Bug 698328 - Add a new cubeb backend based on AudioTrack.cpp. r=kinetik
[gecko.git] / tools / footprint / thrashview.cpp
blob6ee186f48988bf87a2b8aaf21c629f8775e90d21
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6 * ``thrashview'' is a program that reads a binary stream of addresses
7 * from stdin and displays the pattern graphically in a window.
8 */
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/time.h>
16 #include <unistd.h>
17 #include <X11/Xlib.h>
18 #include <fstream>
19 #include <getopt.h>
21 #define GET_DISPLAY_FD(display_) ConnectionNumber(display_)
23 static bool opt_working_set = false;
24 static bool opt_fixed = false;
26 static Display *display;
27 static Window window;
28 static GC gc;
29 static XColor colors[256];
30 const unsigned int cellsize = 4;
31 static unsigned int width = 64 * cellsize;
32 static unsigned int height = 64 * cellsize;
34 #define PAGESIZE 4096
35 #define MAXPAGES 4096 // should hold 16MB worth of code
36 static unsigned int minpage = static_cast<unsigned int>(-1);
37 static unsigned int maxpage = 0;
38 static unsigned char pages[MAXPAGES];
41 /**
42 * Create a simple window and the X objects we'll need to talk with it.
44 static int
45 init()
47 display = XOpenDisplay(0);
48 if (! display)
49 return 0;
51 window =
52 XCreateSimpleWindow(display,
53 RootWindow(display, 0),
54 1, 1, width, height,
56 BlackPixel(display, 0),
57 BlackPixel(display, 0));
59 if (! window)
60 return 0;
62 gc = XCreateGC(display, window, 0, 0);
63 if (! gc)
64 return 0;
66 // Set up a grayscale
67 const unsigned int ncolors = sizeof colors / sizeof colors[0];
68 const unsigned short step = 65536 / ncolors;
69 unsigned short brightness = 0;
71 XColor *color = colors;
72 XColor *limit = colors + ncolors;
73 for (; color < limit; ++color, brightness += step) {
74 color->red = brightness;
75 color->green = brightness;
76 color->blue = brightness;
77 XAllocColor(display, DefaultColormap(display, 0), color);
80 // We want exposes and resizes.
81 XSelectInput(display, window, ExposureMask | StructureNotifyMask);
83 XMapWindow(display, window);
84 XFlush(display);
86 return 1;
89 /**
90 * Age pages that haven't been recently touched.
92 static void
93 decay()
95 int ws_immediate = 0, ws_longterm = 0;
97 unsigned char *page = pages;
98 unsigned char *limit = pages + (maxpage - minpage) + 1;
99 for (; page < limit; ++page) {
100 if (opt_working_set) {
101 if (*page == 255)
102 ++ws_immediate;
103 if (*page)
104 ++ws_longterm;
107 if (*page) {
108 *page /= 8;
109 *page *= 7;
113 if (opt_working_set) {
114 dec(cout);
115 cout << "immediate: " << ws_immediate << " pages, ";
116 cout << "longterm: " << ws_longterm << " pages, ";
117 cout << "mapped: " << ((maxpage - minpage) + 1) << " pages";
118 cout << endl;
123 * Blast the state of our pages to the screen.
125 static int
126 handle_expose(const XExposeEvent& event)
128 //printf("handle_expose(%d, %d, %d, %d)\n", event.x, event.y, event.width, event.height);
130 int i = event.x / cellsize;
131 int imost = i + event.width / cellsize + 1;
133 int j = event.y / cellsize;
134 int jmost = j + event.height / cellsize + 1;
136 unsigned char *last_cell = pages + maxpage - minpage;
137 unsigned char *row = pages + j;
138 for (int y = j * cellsize, ymost = jmost * cellsize;
139 y < ymost;
140 y += cellsize, row += width / cellsize) {
141 unsigned char *cell = row + i;
142 for (int x = i * cellsize, xmost = imost * cellsize;
143 x < xmost;
144 x += cellsize, ++cell) {
145 unsigned int pixel = (cell <= last_cell) ? colors[*cell].pixel : colors[0].pixel;
146 XSetForeground(display, gc, pixel);
147 XFillRectangle(display, window, gc, x, y, cellsize - 1, cellsize - 1);
151 XFlush(display);
153 return 1;
157 * Invalidate the entire window.
159 static void
160 invalidate_window()
162 XExposeEvent event;
163 event.x = event.y = 0;
164 event.width = width;
165 event.height = height;
167 handle_expose(event);
171 * Handle a configure event.
173 static int
174 handle_configure(const XConfigureEvent& event)
176 //printf("handle_resize(%d, %d)\n", event.width, event.height);
177 width = event.width - event.width % cellsize;
178 height = event.height;
179 return 1;
183 * Filter to select any message.
185 static Bool
186 any_event(Display *display, XEvent *event, XPointer arg)
188 return 1;
192 * An X event occurred. Process it and flush the queue.
194 static int
195 handle_xevents()
197 int ok;
199 XEvent event;
200 XNextEvent(display, &event);
201 do {
202 switch (event.type) {
203 case Expose:
204 ok = handle_expose(reinterpret_cast<const XExposeEvent&>(event));
205 break;
207 case ConfigureNotify:
208 ok = handle_configure(reinterpret_cast<const XConfigureEvent&>(event));
209 break;
211 default:
212 ok = 1;
214 } while (ok && XCheckIfEvent(display, &event, any_event, 0));
216 return ok;
220 * Read address data from stdin.
222 static int
223 read_addrs()
225 unsigned int buf[1024];
226 ssize_t count;
227 while ((count = read(0, buf, sizeof buf)) > 0) {
228 if (count % sizeof(unsigned int))
229 cerr << "truncating unaligned read" << endl;
231 count /= sizeof buf[0];
233 unsigned int *addr = reinterpret_cast<unsigned int *>(buf);
234 unsigned int *limit = addr + count;
236 for (; addr < limit; ++addr) {
237 // map the address to a page
238 unsigned int page = *addr / PAGESIZE;
240 // XXX Don't let stray addresses bring us down. Should
241 // really fix this by knowing what the ranges of addresses
242 // we ought to expect are (e.g., by reading the symtab)
243 if (maxpage && page > maxpage && page - maxpage > MAXPAGES)
244 continue;
246 if (! opt_fixed) {
247 // Potentially adjust minpage and maxpage to
248 // accomodate an out-of-bounds address.
249 if (page < minpage) {
250 if (maxpage) {
251 // everything needs to shift.
252 unsigned int shift = minpage - page;
253 memmove(pages + shift, pages, maxpage - minpage);
254 memset(pages, 0, shift);
256 minpage = page;
259 if (page > maxpage)
260 maxpage = page;
263 page -= minpage;
264 pages[page] = 255;
268 if (count < 0 && errno != EWOULDBLOCK) {
269 perror("read");
270 return 0;
273 return 1;
277 * Run the program
279 static void
280 run()
282 // We want non-blocking I/O on stdin so we can select on it.
283 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
285 // The last time we refreshed the window.
286 struct timeval last;
287 gettimeofday(&last, 0);
289 int ok;
291 do {
292 // Select on stdin and the connection to the X server.
293 fd_set fds;
294 FD_ZERO(&fds);
295 FD_SET(STDIN_FILENO, &fds);
296 FD_SET(GET_DISPLAY_FD(display), &fds);
298 struct timeval tv;
299 tv.tv_sec = 1;
300 tv.tv_usec = 0;
302 ok = select(GET_DISPLAY_FD(display) + 1, &fds, 0, 0, &tv);
303 if (ok < 0)
304 break;
306 if (maxpage) {
307 // See if we've waited long enough to refresh the window.
308 struct timeval now;
309 gettimeofday(&now, 0);
311 if (now.tv_sec != last.tv_sec) {
312 // At least a second has gone by. Decay and refresh.
313 last = now;
314 decay();
315 invalidate_window();
317 else if (now.tv_usec - last.tv_usec > 100000) {
318 // At least 100msec have gone by. Refresh.
319 last.tv_usec = now.tv_usec;
320 invalidate_window();
324 // Now check for X events and input.
325 ok = 1;
327 if (FD_ISSET(GET_DISPLAY_FD(display), &fds))
328 ok = handle_xevents();
330 if (FD_ISSET(STDIN_FILENO, &fds))
331 ok = read_addrs();
332 } while (ok);
336 * Tear down our window and stuff.
338 static void
339 finish()
341 if (window) {
342 XUnmapWindow(display, window);
343 XDestroyWindow(display, window);
346 if (display)
347 XCloseDisplay(display);
350 static struct option opts[] = {
351 { "working-set", no_argument, 0, 'w' },
352 { "min", required_argument, 0, 'm' },
353 { "size", required_argument, 0, 's' },
354 { "max", required_argument, 0, 'x' },
355 { 0, 0, 0, 0 }
358 static void
359 usage()
361 cerr << "thrashview [--working-set] [--min=<min>] [--max=<max>] [--size=<size>]" << endl;
365 * Program starts here.
368 main(int argc, char *argv[])
370 int size = 0;
372 while (1) {
373 int option_index = 0;
374 int c = getopt_long(argc, argv, "wm:x:s:", opts, &option_index);
376 if (c < 0)
377 break;
379 switch (c) {
380 case 'w':
381 opt_working_set = true;
382 break;
384 case 'm':
385 minpage = strtol(optarg, 0, 0) / PAGESIZE;
386 opt_fixed = true;
387 break;
389 case 's':
390 size = strtol(optarg, 0, 0) / PAGESIZE;
391 break;
393 case 'x':
394 maxpage = strtol(optarg, 0, 0) / PAGESIZE;
395 opt_fixed = true;
396 break;
398 default:
399 usage();
400 return 1;
404 if (minpage && !maxpage) {
405 if (!size) {
406 cerr << argv[0] << ": minpage specified without maxpage or size" << endl;
407 return 1;
410 maxpage = minpage + size;
413 if (opt_fixed && minpage > maxpage) {
414 cerr << argv[0] << ": invalid page range" << endl;
415 return 1;
418 if (init())
419 run();
421 finish();
423 return 0;