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
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.
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.
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
;
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
;
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
];
74 * Create a simple window and the X objects we'll need to talk with it.
79 display
= XOpenDisplay(0);
84 XCreateSimpleWindow(display
,
85 RootWindow(display
, 0),
88 BlackPixel(display
, 0),
89 BlackPixel(display
, 0));
94 gc
= XCreateGC(display
, window
, 0, 0);
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
);
122 * Age pages that haven't been recently touched.
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
) {
145 if (opt_working_set
) {
147 cout
<< "immediate: " << ws_immediate
<< " pages, ";
148 cout
<< "longterm: " << ws_longterm
<< " pages, ";
149 cout
<< "mapped: " << ((maxpage
- minpage
) + 1) << " pages";
155 * Blast the state of our pages to the screen.
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
;
172 y
+= cellsize
, row
+= width
/ cellsize
) {
173 unsigned char *cell
= row
+ i
;
174 for (int x
= i
* cellsize
, xmost
= imost
* cellsize
;
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);
189 * Invalidate the entire window.
195 event
.x
= event
.y
= 0;
197 event
.height
= height
;
199 handle_expose(event
);
203 * Handle a configure event.
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
;
215 * Filter to select any message.
218 any_event(Display
*display
, XEvent
*event
, XPointer arg
)
224 * An X event occurred. Process it and flush the queue.
232 XNextEvent(display
, &event
);
234 switch (event
.type
) {
236 ok
= handle_expose(reinterpret_cast<const XExposeEvent
&>(event
));
239 case ConfigureNotify
:
240 ok
= handle_configure(reinterpret_cast<const XConfigureEvent
&>(event
));
246 } while (ok
&& XCheckIfEvent(display
, &event
, any_event
, 0));
252 * Read address data from stdin.
257 unsigned int buf
[1024];
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
)
279 // Potentially adjust minpage and maxpage to
280 // accomodate an out-of-bounds address.
281 if (page
< minpage
) {
283 // everything needs to shift.
284 unsigned int shift
= minpage
- page
;
285 memmove(pages
+ shift
, pages
, maxpage
- minpage
);
286 memset(pages
, 0, shift
);
300 if (count
< 0 && errno
!= EWOULDBLOCK
) {
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.
319 gettimeofday(&last
, 0);
324 // Select on stdin and the connection to the X server.
327 FD_SET(STDIN_FILENO
, &fds
);
328 FD_SET(GET_DISPLAY_FD(display
), &fds
);
334 ok
= select(GET_DISPLAY_FD(display
) + 1, &fds
, 0, 0, &tv
);
339 // See if we've waited long enough to refresh the window.
341 gettimeofday(&now
, 0);
343 if (now
.tv_sec
!= last
.tv_sec
) {
344 // At least a second has gone by. Decay and refresh.
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
;
356 // Now check for X events and input.
359 if (FD_ISSET(GET_DISPLAY_FD(display
), &fds
))
360 ok
= handle_xevents();
362 if (FD_ISSET(STDIN_FILENO
, &fds
))
368 * Tear down our window and stuff.
374 XUnmapWindow(display
, window
);
375 XDestroyWindow(display
, window
);
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' },
393 cerr
<< "thrashview [--working-set] [--min=<min>] [--max=<max>] [--size=<size>]" << endl
;
397 * Program starts here.
400 main(int argc
, char *argv
[])
405 int option_index
= 0;
406 int c
= getopt_long(argc
, argv
, "wm:x:s:", opts
, &option_index
);
413 opt_working_set
= true;
417 minpage
= strtol(optarg
, 0, 0) / PAGESIZE
;
422 size
= strtol(optarg
, 0, 0) / PAGESIZE
;
426 maxpage
= strtol(optarg
, 0, 0) / PAGESIZE
;
436 if (minpage
&& !maxpage
) {
438 cerr
<< argv
[0] << ": minpage specified without maxpage or size" << endl
;
442 maxpage
= minpage
+ size
;
445 if (opt_fixed
&& minpage
> maxpage
) {
446 cerr
<< argv
[0] << ": invalid page range" << endl
;