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