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/. */
6 * ``thrashview'' is a program that reads a binary stream of addresses
7 * from stdin and displays the pattern graphically in a window.
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
;
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
;
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
];
42 * Create a simple window and the X objects we'll need to talk with it.
47 display
= XOpenDisplay(0);
52 XCreateSimpleWindow(display
,
53 RootWindow(display
, 0),
56 BlackPixel(display
, 0),
57 BlackPixel(display
, 0));
62 gc
= XCreateGC(display
, window
, 0, 0);
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
);
90 * Age pages that haven't been recently touched.
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
) {
113 if (opt_working_set
) {
115 cout
<< "immediate: " << ws_immediate
<< " pages, ";
116 cout
<< "longterm: " << ws_longterm
<< " pages, ";
117 cout
<< "mapped: " << ((maxpage
- minpage
) + 1) << " pages";
123 * Blast the state of our pages to the screen.
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
;
140 y
+= cellsize
, row
+= width
/ cellsize
) {
141 unsigned char *cell
= row
+ i
;
142 for (int x
= i
* cellsize
, xmost
= imost
* cellsize
;
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);
157 * Invalidate the entire window.
163 event
.x
= event
.y
= 0;
165 event
.height
= height
;
167 handle_expose(event
);
171 * Handle a configure event.
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
;
183 * Filter to select any message.
186 any_event(Display
*display
, XEvent
*event
, XPointer arg
)
192 * An X event occurred. Process it and flush the queue.
200 XNextEvent(display
, &event
);
202 switch (event
.type
) {
204 ok
= handle_expose(reinterpret_cast<const XExposeEvent
&>(event
));
207 case ConfigureNotify
:
208 ok
= handle_configure(reinterpret_cast<const XConfigureEvent
&>(event
));
214 } while (ok
&& XCheckIfEvent(display
, &event
, any_event
, 0));
220 * Read address data from stdin.
225 unsigned int buf
[1024];
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
)
247 // Potentially adjust minpage and maxpage to
248 // accomodate an out-of-bounds address.
249 if (page
< minpage
) {
251 // everything needs to shift.
252 unsigned int shift
= minpage
- page
;
253 memmove(pages
+ shift
, pages
, maxpage
- minpage
);
254 memset(pages
, 0, shift
);
268 if (count
< 0 && errno
!= EWOULDBLOCK
) {
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.
287 gettimeofday(&last
, 0);
292 // Select on stdin and the connection to the X server.
295 FD_SET(STDIN_FILENO
, &fds
);
296 FD_SET(GET_DISPLAY_FD(display
), &fds
);
302 ok
= select(GET_DISPLAY_FD(display
) + 1, &fds
, 0, 0, &tv
);
307 // See if we've waited long enough to refresh the window.
309 gettimeofday(&now
, 0);
311 if (now
.tv_sec
!= last
.tv_sec
) {
312 // At least a second has gone by. Decay and refresh.
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
;
324 // Now check for X events and input.
327 if (FD_ISSET(GET_DISPLAY_FD(display
), &fds
))
328 ok
= handle_xevents();
330 if (FD_ISSET(STDIN_FILENO
, &fds
))
336 * Tear down our window and stuff.
342 XUnmapWindow(display
, window
);
343 XDestroyWindow(display
, window
);
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' },
361 cerr
<< "thrashview [--working-set] [--min=<min>] [--max=<max>] [--size=<size>]" << endl
;
365 * Program starts here.
368 main(int argc
, char *argv
[])
373 int option_index
= 0;
374 int c
= getopt_long(argc
, argv
, "wm:x:s:", opts
, &option_index
);
381 opt_working_set
= true;
385 minpage
= strtol(optarg
, 0, 0) / PAGESIZE
;
390 size
= strtol(optarg
, 0, 0) / PAGESIZE
;
394 maxpage
= strtol(optarg
, 0, 0) / PAGESIZE
;
404 if (minpage
&& !maxpage
) {
406 cerr
<< argv
[0] << ": minpage specified without maxpage or size" << endl
;
410 maxpage
= minpage
+ size
;
413 if (opt_fixed
&& minpage
> maxpage
) {
414 cerr
<< argv
[0] << ": invalid page range" << endl
;