Bug 458256. Use LoadLibraryW instead of LoadLibrary (patch by DougT). r+sr=vlad
[wine-gecko.git] / tools / footprint / thrashview.cpp
blob5d7096457c6110cb0dc6bff346b867d09849830e
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is ``thrashview''
16 * The Initial Developer of the Original Code is Netscape
17 * Communications Corp. Portions created by the Initial Developer are
18 * Copyright (C) 2001 the Initial Developer. All Rights Reserved.
20 * Contributor(s):
21 * Chris Waterson <waterson@netscape.com>
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * ``thrashview'' is a program that reads a binary stream of addresses
39 * from stdin and displays the pattern graphically in a window.
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/time.h>
48 #include <unistd.h>
49 #include <X11/Xlib.h>
50 #include <fstream>
51 #include <getopt.h>
53 #define GET_DISPLAY_FD(display_) ConnectionNumber(display_)
55 static bool opt_working_set = false;
56 static bool opt_fixed = false;
58 static Display *display;
59 static Window window;
60 static GC gc;
61 static XColor colors[256];
62 const unsigned int cellsize = 4;
63 static unsigned int width = 64 * cellsize;
64 static unsigned int height = 64 * cellsize;
66 #define PAGESIZE 4096
67 #define MAXPAGES 4096 // should hold 16MB worth of code
68 static unsigned int minpage = static_cast<unsigned int>(-1);
69 static unsigned int maxpage = 0;
70 static unsigned char pages[MAXPAGES];
73 /**
74 * Create a simple window and the X objects we'll need to talk with it.
76 static int
77 init()
79 display = XOpenDisplay(0);
80 if (! display)
81 return 0;
83 window =
84 XCreateSimpleWindow(display,
85 RootWindow(display, 0),
86 1, 1, width, height,
88 BlackPixel(display, 0),
89 BlackPixel(display, 0));
91 if (! window)
92 return 0;
94 gc = XCreateGC(display, window, 0, 0);
95 if (! gc)
96 return 0;
98 // Set up a grayscale
99 const unsigned int ncolors = sizeof colors / sizeof colors[0];
100 const unsigned short step = 65536 / ncolors;
101 unsigned short brightness = 0;
103 XColor *color = colors;
104 XColor *limit = colors + ncolors;
105 for (; color < limit; ++color, brightness += step) {
106 color->red = brightness;
107 color->green = brightness;
108 color->blue = brightness;
109 XAllocColor(display, DefaultColormap(display, 0), color);
112 // We want exposes and resizes.
113 XSelectInput(display, window, ExposureMask | StructureNotifyMask);
115 XMapWindow(display, window);
116 XFlush(display);
118 return 1;
122 * Age pages that haven't been recently touched.
124 static void
125 decay()
127 int ws_immediate = 0, ws_longterm = 0;
129 unsigned char *page = pages;
130 unsigned char *limit = pages + (maxpage - minpage) + 1;
131 for (; page < limit; ++page) {
132 if (opt_working_set) {
133 if (*page == 255)
134 ++ws_immediate;
135 if (*page)
136 ++ws_longterm;
139 if (*page) {
140 *page /= 8;
141 *page *= 7;
145 if (opt_working_set) {
146 dec(cout);
147 cout << "immediate: " << ws_immediate << " pages, ";
148 cout << "longterm: " << ws_longterm << " pages, ";
149 cout << "mapped: " << ((maxpage - minpage) + 1) << " pages";
150 cout << endl;
155 * Blast the state of our pages to the screen.
157 static int
158 handle_expose(const XExposeEvent& event)
160 //printf("handle_expose(%d, %d, %d, %d)\n", event.x, event.y, event.width, event.height);
162 int i = event.x / cellsize;
163 int imost = i + event.width / cellsize + 1;
165 int j = event.y / cellsize;
166 int jmost = j + event.height / cellsize + 1;
168 unsigned char *last_cell = pages + maxpage - minpage;
169 unsigned char *row = pages + j;
170 for (int y = j * cellsize, ymost = jmost * cellsize;
171 y < ymost;
172 y += cellsize, row += width / cellsize) {
173 unsigned char *cell = row + i;
174 for (int x = i * cellsize, xmost = imost * cellsize;
175 x < xmost;
176 x += cellsize, ++cell) {
177 unsigned int pixel = (cell <= last_cell) ? colors[*cell].pixel : colors[0].pixel;
178 XSetForeground(display, gc, pixel);
179 XFillRectangle(display, window, gc, x, y, cellsize - 1, cellsize - 1);
183 XFlush(display);
185 return 1;
189 * Invalidate the entire window.
191 static void
192 invalidate_window()
194 XExposeEvent event;
195 event.x = event.y = 0;
196 event.width = width;
197 event.height = height;
199 handle_expose(event);
203 * Handle a configure event.
205 static int
206 handle_configure(const XConfigureEvent& event)
208 //printf("handle_resize(%d, %d)\n", event.width, event.height);
209 width = event.width - event.width % cellsize;
210 height = event.height;
211 return 1;
215 * Filter to select any message.
217 static Bool
218 any_event(Display *display, XEvent *event, XPointer arg)
220 return 1;
224 * An X event occurred. Process it and flush the queue.
226 static int
227 handle_xevents()
229 int ok;
231 XEvent event;
232 XNextEvent(display, &event);
233 do {
234 switch (event.type) {
235 case Expose:
236 ok = handle_expose(reinterpret_cast<const XExposeEvent&>(event));
237 break;
239 case ConfigureNotify:
240 ok = handle_configure(reinterpret_cast<const XConfigureEvent&>(event));
241 break;
243 default:
244 ok = 1;
246 } while (ok && XCheckIfEvent(display, &event, any_event, 0));
248 return ok;
252 * Read address data from stdin.
254 static int
255 read_addrs()
257 unsigned int buf[1024];
258 ssize_t count;
259 while ((count = read(0, buf, sizeof buf)) > 0) {
260 if (count % sizeof(unsigned int))
261 cerr << "truncating unaligned read" << endl;
263 count /= sizeof buf[0];
265 unsigned int *addr = reinterpret_cast<unsigned int *>(buf);
266 unsigned int *limit = addr + count;
268 for (; addr < limit; ++addr) {
269 // map the address to a page
270 unsigned int page = *addr / PAGESIZE;
272 // XXX Don't let stray addresses bring us down. Should
273 // really fix this by knowing what the ranges of addresses
274 // we ought to expect are (e.g., by reading the symtab)
275 if (maxpage && page > maxpage && page - maxpage > MAXPAGES)
276 continue;
278 if (! opt_fixed) {
279 // Potentially adjust minpage and maxpage to
280 // accomodate an out-of-bounds address.
281 if (page < minpage) {
282 if (maxpage) {
283 // everything needs to shift.
284 unsigned int shift = minpage - page;
285 memmove(pages + shift, pages, maxpage - minpage);
286 memset(pages, 0, shift);
288 minpage = page;
291 if (page > maxpage)
292 maxpage = page;
295 page -= minpage;
296 pages[page] = 255;
300 if (count < 0 && errno != EWOULDBLOCK) {
301 perror("read");
302 return 0;
305 return 1;
309 * Run the program
311 static void
312 run()
314 // We want non-blocking I/O on stdin so we can select on it.
315 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
317 // The last time we refreshed the window.
318 struct timeval last;
319 gettimeofday(&last, 0);
321 int ok;
323 do {
324 // Select on stdin and the connection to the X server.
325 fd_set fds;
326 FD_ZERO(&fds);
327 FD_SET(STDIN_FILENO, &fds);
328 FD_SET(GET_DISPLAY_FD(display), &fds);
330 struct timeval tv;
331 tv.tv_sec = 1;
332 tv.tv_usec = 0;
334 ok = select(GET_DISPLAY_FD(display) + 1, &fds, 0, 0, &tv);
335 if (ok < 0)
336 break;
338 if (maxpage) {
339 // See if we've waited long enough to refresh the window.
340 struct timeval now;
341 gettimeofday(&now, 0);
343 if (now.tv_sec != last.tv_sec) {
344 // At least a second has gone by. Decay and refresh.
345 last = now;
346 decay();
347 invalidate_window();
349 else if (now.tv_usec - last.tv_usec > 100000) {
350 // At least 100msec have gone by. Refresh.
351 last.tv_usec = now.tv_usec;
352 invalidate_window();
356 // Now check for X events and input.
357 ok = 1;
359 if (FD_ISSET(GET_DISPLAY_FD(display), &fds))
360 ok = handle_xevents();
362 if (FD_ISSET(STDIN_FILENO, &fds))
363 ok = read_addrs();
364 } while (ok);
368 * Tear down our window and stuff.
370 static void
371 finish()
373 if (window) {
374 XUnmapWindow(display, window);
375 XDestroyWindow(display, window);
378 if (display)
379 XCloseDisplay(display);
382 static struct option opts[] = {
383 { "working-set", no_argument, 0, 'w' },
384 { "min", required_argument, 0, 'm' },
385 { "size", required_argument, 0, 's' },
386 { "max", required_argument, 0, 'x' },
387 { 0, 0, 0, 0 }
390 static void
391 usage()
393 cerr << "thrashview [--working-set] [--min=<min>] [--max=<max>] [--size=<size>]" << endl;
397 * Program starts here.
400 main(int argc, char *argv[])
402 int size = 0;
404 while (1) {
405 int option_index = 0;
406 int c = getopt_long(argc, argv, "wm:x:s:", opts, &option_index);
408 if (c < 0)
409 break;
411 switch (c) {
412 case 'w':
413 opt_working_set = true;
414 break;
416 case 'm':
417 minpage = strtol(optarg, 0, 0) / PAGESIZE;
418 opt_fixed = true;
419 break;
421 case 's':
422 size = strtol(optarg, 0, 0) / PAGESIZE;
423 break;
425 case 'x':
426 maxpage = strtol(optarg, 0, 0) / PAGESIZE;
427 opt_fixed = true;
428 break;
430 default:
431 usage();
432 return 1;
436 if (minpage && !maxpage) {
437 if (!size) {
438 cerr << argv[0] << ": minpage specified without maxpage or size" << endl;
439 return 1;
442 maxpage = minpage + size;
445 if (opt_fixed && minpage > maxpage) {
446 cerr << argv[0] << ": invalid page range" << endl;
447 return 1;
450 if (init())
451 run();
453 finish();
455 return 0;