FIX #2164: check for ThreadRelocated in isAlive()
[ghc.git] / rts / FrontPanel.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team 2000
4 *
5 * RTS GTK Front Panel
6 *
7 * ---------------------------------------------------------------------------*/
8
9 #ifdef RTS_GTK_FRONTPANEL
10
11 /* Alas, not Posix. */
12 /* #include "PosixSource.h" */
13
14 #include "Rts.h"
15 #include "RtsUtils.h"
16 #include "MBlock.h"
17 #include "FrontPanel.h"
18 #include "Stats.h"
19 #include "RtsFlags.h"
20 #include "Schedule.h"
21
22 #include <gtk/gtk.h>
23 #include <unistd.h>
24 #include <string.h>
25
26 #include "VisSupport.h"
27 #include "VisWindow.h"
28
29 static GtkWidget *window, *map_drawing_area, *gen_drawing_area;
30 static GtkWidget *res_drawing_area;
31 static GtkWidget *continue_but, *stop_but, *quit_but;
32 static GtkWidget *statusbar;
33 static GtkWidget *live_label, *allocated_label;
34 static GtkWidget *footprint_label, *alloc_rate_label;
35 static GtkWidget *map_ruler, *gen_ruler;
36 static GtkWidget *res_vruler, *res_hruler;
37 static GtkWidget *running_label, *b_read_label, *b_write_label, *total_label;
38 static GtkWidget *b_mvar_label, *b_bh_label, *b_throwto_label, *sleeping_label;
39
40 static guint status_context_id;
41
42 gboolean continue_now = FALSE, stop_now = FALSE, quit = FALSE;
43 UpdateMode update_mode = Continuous;
44
45 static GdkPixmap *map_pixmap = NULL;
46 static GdkPixmap *gen_pixmap = NULL;
47 static GdkPixmap *res_pixmap = NULL;
48
49 #define N_GENS 10
50
51 static GdkColor
52 bdescr_color = { 0, 0xffff, 0, 0 }, /* red */
53 free_color = { 0, 0, 0, 0xffff }, /* blue */
54 gen_colors[N_GENS] = {
55 { 0, 0, 0xffff, 0 },
56 { 0, 0, 0xf000, 0 },
57 { 0, 0, 0xe000, 0 },
58 { 0, 0, 0xd000, 0 },
59 { 0, 0, 0xc000, 0 },
60 { 0, 0, 0xb000, 0 },
61 { 0, 0, 0xa000, 0 },
62 { 0, 0, 0x9000, 0 },
63 { 0, 0, 0x8000, 0 },
64 { 0, 0, 0x7000, 0 }
65 };
66
67 GdkGC *my_gc = NULL;
68
69 static void *mem_start = (void *) 0x50000000;
70
71 static void colorBlock( void *addr, GdkColor *color,
72 nat block_width, nat block_height,
73 nat blocks_per_line );
74
75 static void residencyCensus( void );
76 static void updateResidencyGraph( void );
77 static void updateThreadsPanel( void );
78
79 /* Some code pinched from examples/scribble-simple in the GTK+
80 * distribution.
81 */
82
83 /* Create a new backing pixmap of the appropriate size */
84 static gint
85 configure_event( GtkWidget *widget, GdkEventConfigure *event STG_UNUSED,
86 GdkPixmap **pixmap )
87 {
88 if (*pixmap)
89 gdk_pixmap_unref(*pixmap);
90
91 *pixmap = gdk_pixmap_new(widget->window,
92 widget->allocation.width,
93 widget->allocation.height,
94 -1);
95
96 gdk_draw_rectangle (*pixmap,
97 widget->style->white_gc,
98 TRUE,
99 0, 0,
100 widget->allocation.width,
101 widget->allocation.height);
102
103 debugBelch("configure!\n");
104 updateFrontPanel();
105 return TRUE;
106 }
107
108 /* Redraw the screen from the backing pixmap */
109 static gint
110 expose_event( GtkWidget *widget, GdkEventExpose *event, GdkPixmap **pixmap )
111 {
112 gdk_draw_pixmap(widget->window,
113 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
114 *pixmap,
115 event->area.x, event->area.y,
116 event->area.x, event->area.y,
117 event->area.width, event->area.height);
118
119 return FALSE;
120 }
121
122 void
123 initFrontPanel( void )
124 {
125 GdkColormap *colormap;
126 GtkWidget *gen_hbox;
127
128 gtk_init( &prog_argc, &prog_argv );
129
130 window = create_GHC_Front_Panel();
131 map_drawing_area = lookup_widget(window, "memmap");
132 gen_drawing_area = lookup_widget(window, "generations");
133 res_drawing_area = lookup_widget(window, "res_drawingarea");
134 stop_but = lookup_widget(window, "stop_but");
135 continue_but = lookup_widget(window, "continue_but");
136 quit_but = lookup_widget(window, "quit_but");
137 statusbar = lookup_widget(window, "statusbar");
138 live_label = lookup_widget(window, "live_label");
139 footprint_label = lookup_widget(window, "footprint_label");
140 allocated_label = lookup_widget(window, "allocated_label");
141 alloc_rate_label = lookup_widget(window, "alloc_rate_label");
142 gen_hbox = lookup_widget(window, "gen_hbox");
143 gen_ruler = lookup_widget(window, "gen_ruler");
144 map_ruler = lookup_widget(window, "map_ruler");
145 res_vruler = lookup_widget(window, "res_vruler");
146 res_hruler = lookup_widget(window, "res_hruler");
147 running_label = lookup_widget(window, "running_label");
148 b_read_label = lookup_widget(window, "blockread_label");
149 b_write_label = lookup_widget(window, "blockwrite_label");
150 b_mvar_label = lookup_widget(window, "blockmvar_label");
151 b_bh_label = lookup_widget(window, "blockbh_label");
152 b_throwto_label = lookup_widget(window, "blockthrowto_label");
153 sleeping_label = lookup_widget(window, "sleeping_label");
154 total_label = lookup_widget(window, "total_label");
155
156 status_context_id =
157 gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "context" );
158
159 /* hook up some signals for the mem map drawing area */
160 gtk_signal_connect (GTK_OBJECT(map_drawing_area), "expose_event",
161 (GtkSignalFunc)expose_event, &map_pixmap);
162 gtk_signal_connect (GTK_OBJECT(map_drawing_area), "configure_event",
163 (GtkSignalFunc)configure_event, &map_pixmap);
164
165 gtk_widget_set_events(map_drawing_area, GDK_EXPOSURE_MASK);
166
167 /* hook up some signals for the gen drawing area */
168 gtk_signal_connect (GTK_OBJECT(gen_drawing_area), "expose_event",
169 (GtkSignalFunc)expose_event, &gen_pixmap);
170 gtk_signal_connect (GTK_OBJECT(gen_drawing_area), "configure_event",
171 (GtkSignalFunc)configure_event, &gen_pixmap);
172
173 gtk_widget_set_events(gen_drawing_area, GDK_EXPOSURE_MASK);
174
175 /* hook up some signals for the res drawing area */
176 gtk_signal_connect (GTK_OBJECT(res_drawing_area), "expose_event",
177 (GtkSignalFunc)expose_event, &res_pixmap);
178 gtk_signal_connect (GTK_OBJECT(res_drawing_area), "configure_event",
179 (GtkSignalFunc)configure_event, &res_pixmap);
180
181 gtk_widget_set_events(res_drawing_area, GDK_EXPOSURE_MASK);
182
183 /* allocate our colors */
184 colormap = gdk_colormap_get_system();
185 gdk_colormap_alloc_color(colormap, &bdescr_color, TRUE, TRUE);
186 gdk_colormap_alloc_color(colormap, &free_color, TRUE, TRUE);
187
188 {
189 gboolean success[N_GENS];
190 gdk_colormap_alloc_colors(colormap, gen_colors, N_GENS, TRUE,
191 TRUE, success);
192 if (!success) { barf("can't allocate colors"); }
193 }
194
195 /* set the labels on the generation histogram */
196 {
197 char buf[64];
198 nat g, s;
199 GtkWidget *label;
200
201 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
202 for(s = 0; s < generations[g].n_steps; s++) {
203 g_snprintf( buf, 64, "%d.%d", g, s );
204 label = gtk_label_new( buf );
205 gtk_box_pack_start( GTK_BOX(gen_hbox), label,
206 TRUE, TRUE, 5 );
207 gtk_widget_show(label);
208 }
209 }
210 }
211
212 gtk_widget_show(window);
213
214 /* wait for the user to press "Continue" before getting going... */
215 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
216 "Program start");
217 gtk_widget_set_sensitive( stop_but, FALSE );
218 continue_now = FALSE;
219 while (continue_now == FALSE) {
220 gtk_main_iteration();
221 }
222 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
223 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
224 "Running");
225
226 gtk_widget_set_sensitive( continue_but, FALSE );
227 gtk_widget_set_sensitive( stop_but, TRUE );
228 gtk_widget_set_sensitive( quit_but, FALSE );
229
230 while (gtk_events_pending()) {
231 gtk_main_iteration();
232 }
233 }
234
235 void
236 stopFrontPanel( void )
237 {
238 gtk_widget_set_sensitive( quit_but, TRUE );
239 gtk_widget_set_sensitive( continue_but, FALSE );
240 gtk_widget_set_sensitive( stop_but, FALSE );
241
242 updateFrontPanel();
243
244 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
245 "Program finished");
246
247 quit = FALSE;
248 while (quit == FALSE) {
249 gtk_main_iteration();
250 }
251 }
252
253 static void
254 waitForContinue( void )
255 {
256 gtk_widget_set_sensitive( continue_but, TRUE );
257 gtk_widget_set_sensitive( stop_but, FALSE );
258 stop_now = FALSE;
259 continue_now = FALSE;
260 while (continue_now == FALSE) {
261 gtk_main_iteration();
262 }
263 gtk_widget_set_sensitive( continue_but, FALSE );
264 gtk_widget_set_sensitive( stop_but, TRUE );
265 }
266
267 void
268 updateFrontPanelBeforeGC( nat N )
269 {
270 char buf[1000];
271
272 updateFrontPanel();
273
274 if (update_mode == BeforeGC
275 || update_mode == BeforeAfterGC
276 || stop_now == TRUE) {
277 g_snprintf( buf, 1000, "Stopped (before GC, generation %d)", N );
278 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf );
279 waitForContinue();
280 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
281 }
282
283 g_snprintf( buf, 1000, "Garbage collecting (generation %d)", N );
284 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf);
285
286 while (gtk_events_pending()) {
287 gtk_main_iteration();
288 }
289 }
290
291 static void
292 numLabel( GtkWidget *lbl, nat n )
293 {
294 char buf[64];
295 g_snprintf(buf, 64, "%d", n);
296 gtk_label_set_text( GTK_LABEL(lbl), buf );
297 }
298
299 void
300 updateFrontPanelAfterGC( nat N, lnat live )
301 {
302 char buf[1000];
303
304 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
305
306 /* is a major GC? */
307 if (N == RtsFlags.GcFlags.generations-1) {
308 residencyCensus();
309 }
310
311 updateFrontPanel();
312
313 if (update_mode == AfterGC
314 || update_mode == BeforeAfterGC
315 || stop_now == TRUE) {
316 snprintf( buf, 1000, "Stopped (after GC, generation %d)", N );
317 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf );
318 waitForContinue();
319 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
320 }
321
322 {
323 double words_to_megs = (1024 * 1024) / sizeof(W_);
324 double time = mut_user_time();
325
326 snprintf( buf, 1000, "%.2f", (double)live / words_to_megs );
327 gtk_label_set_text( GTK_LABEL(live_label), buf );
328
329 snprintf( buf, 1000, "%.2f", (double)total_allocated / words_to_megs );
330 gtk_label_set_text( GTK_LABEL(allocated_label), buf );
331
332 snprintf( buf, 1000, "%.2f",
333 (double)(mblocks_allocated * MBLOCK_SIZE_W) / words_to_megs );
334 gtk_label_set_text( GTK_LABEL(footprint_label), buf );
335
336 if ( time == 0.0 )
337 snprintf( buf, 1000, "%.2f", time );
338 else
339 snprintf( buf, 1000, "%.2f",
340 (double)(total_allocated / words_to_megs) / time );
341 gtk_label_set_text( GTK_LABEL(alloc_rate_label), buf );
342 }
343
344 while (gtk_events_pending()) {
345 gtk_main_iteration();
346 }
347 }
348
349 void
350 updateFrontPanel( void )
351 {
352 void *m, *a;
353 bdescr *bd;
354
355 updateThreadsPanel();
356
357 if (my_gc == NULL) {
358 my_gc = gdk_gc_new( window->window );
359 }
360
361 if (map_pixmap != NULL) {
362 nat height, width, blocks_per_line,
363 block_height, block_width, mblock_height;
364
365 height = map_drawing_area->allocation.height;
366 width = map_drawing_area->allocation.width;
367
368 mblock_height = height / mblocks_allocated;
369 blocks_per_line = 16;
370 block_height = mblock_height /
371 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
372 while (block_height == 0) {
373 blocks_per_line *= 2;
374 block_height = mblock_height /
375 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
376 }
377 block_width = width / blocks_per_line;
378
379 gdk_draw_rectangle (map_pixmap,
380 map_drawing_area->style->bg_gc[GTK_STATE_NORMAL],
381 TRUE,
382 0, 0,
383 map_drawing_area->allocation.width,
384 map_drawing_area->allocation.height);
385
386 for ( m = mem_start;
387 (char *)m < (char *)mem_start +
388 (mblocks_allocated * MBLOCK_SIZE);
389 (char *)m += MBLOCK_SIZE ) {
390
391 /* color the bdescr area first */
392 for (a = m; a < FIRST_BLOCK(m); (char *)a += BLOCK_SIZE) {
393 colorBlock( a, &bdescr_color,
394 block_width, block_height, blocks_per_line );
395 }
396
397 #if 0 /* Segfaults because bd appears to be bogus but != NULL. stolz, 2003-06-24 */
398 /* color each block */
399 for (; a <= LAST_BLOCK(m); (char *)a += BLOCK_SIZE) {
400 bd = Bdescr((P_)a);
401 ASSERT(bd->start == a);
402 if (bd->flags & BF_FREE) {
403 colorBlock( a, &free_color,
404 block_width, block_height, blocks_per_line );
405 } else {
406 colorBlock( a, &gen_colors[bd->gen_no],
407 block_width, block_height, blocks_per_line );
408 }
409 }
410 #endif
411 }
412
413
414 {
415 nat height = map_drawing_area->allocation.height,
416 block_height, mblock_height;
417
418 block_height = (height / mblocks_allocated) /
419 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
420 if (block_height < 1) block_height = 1;
421 mblock_height = block_height *
422 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
423
424 gtk_ruler_set_range( GTK_RULER(map_ruler), 0,
425 (double)(height * mblocks_allocated) /
426 (double)((mblock_height * mblocks_allocated)),
427 0,
428 (double)(height * mblocks_allocated) /
429 (double)((mblock_height * mblocks_allocated))
430 );
431 }
432
433 gtk_widget_draw( map_drawing_area, NULL );
434 }
435
436 if (gen_pixmap != NULL) {
437
438 GdkRectangle rect;
439 nat g, s, columns, column, max_blocks, height_blocks,
440 width, height;
441
442 gdk_draw_rectangle (gen_pixmap,
443 gen_drawing_area->style->white_gc,
444 TRUE,
445 0, 0,
446 gen_drawing_area->allocation.width,
447 gen_drawing_area->allocation.height);
448
449 height = gen_drawing_area->allocation.height;
450 width = gen_drawing_area->allocation.width;
451
452 columns = 0; max_blocks = 0;
453 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
454 columns += generations[g].n_steps;
455 for(s = 0; s < generations[g].n_steps; s++) {
456 if (generations[g].steps[s].n_blocks > max_blocks) {
457 max_blocks = generations[g].steps[s].n_blocks;
458 }
459 }
460 }
461
462 /* find a reasonable height value larger than max_blocks */
463 {
464 nat n = 0;
465 while (max_blocks != 0) {
466 max_blocks >>= 1; n++;
467 }
468 height_blocks = 1 << n;
469 }
470
471 column = 0;
472 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
473 for(s = 0; s < generations[g].n_steps; s++, column++) {
474 gdk_gc_set_foreground(my_gc, &gen_colors[g]);
475
476 rect.x = column * (width / columns);
477
478 if (generations[g].steps[s].n_blocks == 0)
479 rect.y = height;
480 else
481 rect.y = height -
482 (height * generations[g].steps[s].n_blocks
483 / height_blocks);
484
485 rect.width = (width / columns);
486 rect.height = height - rect.y;
487
488 gdk_draw_rectangle( gen_pixmap, my_gc, TRUE/*filled*/,
489 rect.x, rect.y, rect.width,
490 rect.height );
491 }
492 }
493
494 gtk_ruler_set_range( GTK_RULER(gen_ruler),
495 height_blocks * BLOCK_SIZE / (1024 * 1024),
496 0, 0,
497 height_blocks * BLOCK_SIZE / (1024 * 1024)
498 );
499
500 gtk_widget_draw( gen_drawing_area, NULL );
501 }
502
503 if (res_pixmap != NULL) {
504 updateResidencyGraph();
505 }
506
507 while (gtk_events_pending()) {
508 gtk_main_iteration_do(FALSE/*don't block*/);
509 }
510 }
511
512 static void
513 colorBlock( void *addr, GdkColor *color,
514 nat block_width, nat block_height, nat blocks_per_line )
515 {
516 GdkRectangle rect;
517 nat block_no;
518
519 gdk_gc_set_foreground(my_gc, color);
520
521 block_no = ((char *)addr - (char *)mem_start) / BLOCK_SIZE;
522
523 rect.x = (block_no % blocks_per_line) * block_width;
524 rect.y = block_no / blocks_per_line * block_height;
525 rect.width = block_width;
526 rect.height = block_height;
527 gdk_draw_rectangle( map_pixmap, my_gc, TRUE/*filled*/,
528 rect.x, rect.y, rect.width, rect.height );
529 }
530
531 static void
532 updateThreadsPanel( void )
533 {
534 nat running = 0,
535 b_read = 0,
536 b_write = 0,
537 b_mvar = 0,
538 b_throwto = 0,
539 b_bh = 0,
540 sleeping = 0,
541 total = 0;
542
543 StgTSO *t;
544
545 for (t = all_threads; t != END_TSO_QUEUE; t = t->global_link) {
546 switch (t->what_next) {
547 case ThreadKilled: break;
548 case ThreadComplete: break;
549 default:
550 switch (t->why_blocked) {
551 case BlockedOnRead: b_read++; break;
552 case BlockedOnWrite: b_write++; break;
553 case BlockedOnDelay: sleeping++; break;
554 case BlockedOnMVar: b_mvar++; break;
555 case BlockedOnException: b_throwto++; break;
556 case BlockedOnBlackHole: b_bh++; break;
557 case NotBlocked: running++; break;
558 }
559 }
560 }
561 total = running + b_read + b_write + b_mvar + b_throwto + b_bh + sleeping;
562 numLabel(running_label, running);
563 numLabel(b_read_label, b_read);
564 numLabel(b_write_label, b_write);
565 numLabel(b_mvar_label, b_mvar);
566 numLabel(b_bh_label, b_bh);
567 numLabel(b_throwto_label, b_throwto);
568 numLabel(sleeping_label, sleeping);
569 numLabel(total_label, total);
570 }
571
572 typedef enum { Thunk, Fun, Constr, BlackHole,
573 Array, Thread, Other, N_Cats } ClosureCategory;
574
575 #define N_SLICES 100
576
577 static nat *res_prof[N_SLICES];
578 static double res_time[N_SLICES];
579 static nat next_slice = 0;
580
581 static void
582 residencyCensus( void )
583 {
584 nat slice = next_slice++, *prof;
585 bdescr *bd;
586 nat g, s, size, type;
587 StgPtr p;
588 StgInfoTable *info;
589
590 if (slice >= N_SLICES) {
591 barf("too many slices");
592 }
593 res_prof[slice] = stgMallocBytes(N_Cats * sizeof(nat), "residencyCensus");
594 prof = res_prof[slice];
595 memset(prof, 0, N_Cats * sizeof(nat));
596
597 res_time[slice] = mut_user_time();
598
599 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
600 for(s = 0; s < generations[g].n_steps; s++) {
601
602 /* skip over g0s0 if multi-generational */
603 if (RtsFlags.GcFlags.generations > 1 &&
604 g == 0 && s == 0) continue;
605
606 if (RtsFlags.GcFlags.generations == 1) {
607 /* bd = generations[g].steps[s].to_blocks; FIXME to_blocks does not exist */
608 } else {
609 bd = generations[g].steps[s].blocks;
610 }
611
612 for (; bd != NULL; bd = bd->link) {
613
614 p = bd->start;
615
616 while (p < bd->free) {
617 info = get_itbl((StgClosure *)p);
618 type = Other;
619
620 switch (info->type) {
621
622 case CONSTR:
623 case BCO:
624 if (((StgClosure *)p)->header.info == &stg_DEAD_WEAK_info) {
625 size = sizeofW(StgWeak);
626 type = Other;
627 break;
628 }
629 /* else, fall through... */
630 case CONSTR_1_0:
631 case CONSTR_0_1:
632 case CONSTR_1_1:
633 case CONSTR_0_2:
634 case CONSTR_2_0:
635 size = sizeW_fromITBL(info);
636 type = Constr;
637 break;
638
639 case FUN_1_0:
640 case FUN_0_1:
641 size = sizeofW(StgHeader) + 1;
642 goto fun;
643 case FUN_1_1:
644 case FUN_0_2:
645 case FUN_2_0:
646 case FUN:
647 size = sizeW_fromITBL(info);
648 fun:
649 type = Fun;
650 break;
651
652 case THUNK_1_0:
653 case THUNK_0_1:
654 case THUNK_SELECTOR:
655 size = sizeofW(StgHeader) + 2;
656 goto thunk;
657 case THUNK_1_1:
658 case THUNK_0_2:
659 case THUNK_2_0:
660 case THUNK:
661 size = sizeW_fromITBL(info);
662 thunk:
663 type = Thunk;
664 break;
665
666 case CAF_BLACKHOLE:
667 case SE_CAF_BLACKHOLE:
668 case SE_BLACKHOLE:
669 case BLACKHOLE:
670 /* case BLACKHOLE_BQ: FIXME: case does not exist */
671 size = sizeW_fromITBL(info);
672 type = BlackHole;
673 break;
674
675 case AP:
676 size = pap_sizeW((StgPAP *)p);
677 type = Thunk;
678 break;
679
680 case PAP:
681 size = pap_sizeW((StgPAP *)p);
682 type = Fun;
683 break;
684
685 case ARR_WORDS:
686 size = arr_words_sizeW(stgCast(StgArrWords*,p));
687 type = Array;
688 break;
689
690 case MUT_ARR_PTRS:
691 case MUT_ARR_PTRS_FROZEN:
692 size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
693 type = Array;
694 break;
695
696 case TSO:
697 size = tso_sizeW((StgTSO *)p);
698 type = Thread;
699 break;
700
701 case WEAK:
702 case STABLE_NAME:
703 case MVAR:
704 case MUT_VAR:
705 /* case MUT_CONS: FIXME: case does not exist */
706 case IND_PERM:
707 case IND_OLDGEN_PERM:
708 size = sizeW_fromITBL(info);
709 type = Other;
710 break;
711
712 default:
713 barf("updateResidencyGraph: strange closure "
714 "%d", info->type );
715 }
716
717 prof[type] += size;
718 p += size;
719 }
720 }
721 }
722 }
723
724 }
725
726 static void
727 updateResidencyGraph( void )
728 {
729 nat total, prev_total, i, max_res;
730 double time;
731 double time_scale = 1;
732 nat last_slice = next_slice-1;
733 double res_scale = 1; /* in megabytes, doubles */
734 nat *prof;
735 nat width, height;
736 GdkPoint points[4];
737
738 gdk_draw_rectangle (res_pixmap,
739 res_drawing_area->style->bg_gc[GTK_STATE_NORMAL],
740 TRUE,
741 0, 0,
742 res_drawing_area->allocation.width,
743 res_drawing_area->allocation.height);
744
745 if (next_slice == 0) return;
746
747 time = res_time[last_slice];
748 while (time > time_scale) {
749 time_scale *= 2;
750 }
751
752 max_res = 0;
753 for (i = 0; i < next_slice; i++) {
754 prof = res_prof[i];
755 total = prof[Thunk] + prof[Fun] + prof[Constr] +
756 prof[BlackHole] + prof[Array] + prof[Other];
757 if (total > max_res) {
758 max_res = total;
759 }
760 }
761 while (max_res > res_scale) {
762 res_scale *= 2;
763 }
764
765 height = res_drawing_area->allocation.height;
766 width = res_drawing_area->allocation.width;
767
768 points[0].x = 0;
769 points[0].y = height;
770 points[1].y = height;
771 points[3].x = 0;
772 points[3].y = height;
773
774 gdk_gc_set_foreground(my_gc, &free_color);
775
776 prev_total = 0;
777 for (i = 0; i < next_slice; i++) {
778 prof = res_prof[i];
779 total = prof[Thunk] + prof[Fun] + prof[Constr] +
780 prof[BlackHole] + prof[Array] + prof[Other];
781 points[1].x = width * res_time[i] / time_scale;
782 points[2].x = points[1].x;
783 points[2].y = height - ((height * total) / res_scale);
784 gdk_draw_polygon(res_pixmap, my_gc, TRUE/*filled*/, points, 4);
785 points[3] = points[2];
786 points[0] = points[1];
787 }
788
789 gtk_ruler_set_range( GTK_RULER(res_vruler),
790 res_scale / ((1024*1024)/sizeof(W_)),
791 0, 0,
792 res_scale / ((1024*1024)/sizeof(W_)) );
793
794 gtk_ruler_set_range( GTK_RULER(res_hruler),
795 0, time_scale, 0, time_scale );
796
797
798 gtk_widget_draw( res_drawing_area, NULL );
799 }
800
801 #endif /* RTS_GTK_FRONTPANEL */