1 /* -----------------------------------------------------------------------------
2 * $Id: FrontPanel.c,v 1.4 2001/01/19 11:08:05 simonmar Exp $
4 * (c) The GHC Team 2000
8 * ---------------------------------------------------------------------------*/
10 #ifdef RTS_GTK_FRONTPANEL
12 #define NON_POSIX_SOURCE
17 #include "FrontPanel.h"
19 #include "StoragePriv.h"
25 #include <gdk/gdktypes.h>
28 #include "VisSupport.h"
29 #include "VisWindow.h"
31 static GtkWidget *window, *map_drawing_area, *gen_drawing_area;
32 static GtkWidget *res_drawing_area;
33 static GtkWidget *continue_but, *stop_but, *quit_but;
34 static GtkWidget *statusbar;
35 static GtkWidget *live_label, *allocated_label;
36 static GtkWidget *footprint_label, *alloc_rate_label;
37 static GtkWidget *map_ruler, *gen_ruler;
38 static GtkWidget *res_vruler, *res_hruler;
39 static GtkWidget *running_label, *b_read_label, *b_write_label, *total_label;
40 static GtkWidget *b_mvar_label, *b_bh_label, *b_throwto_label, *sleeping_label;
42 static guint status_context_id;
44 gboolean continue_now = FALSE, stop_now = FALSE, quit = FALSE;
45 UpdateMode update_mode = Continuous;
47 static GdkPixmap *map_pixmap = NULL;
48 static GdkPixmap *gen_pixmap = NULL;
49 static GdkPixmap *res_pixmap = NULL;
54 bdescr_color = { 0, 0xffff, 0, 0 }, /* red */
55 free_color = { 0, 0, 0, 0xffff }, /* blue */
56 gen_colors[N_GENS] = {
71 static void *mem_start = (void *) 0x50000000;
73 static void colorBlock( void *addr, GdkColor *color,
74 nat block_width, nat block_height,
75 nat blocks_per_line );
77 static void residencyCensus( void );
78 static void updateResidencyGraph( void );
79 static void updateThreadsPanel( void );
81 /* Some code pinched from examples/scribble-simple in the GTK+
85 /* Create a new backing pixmap of the appropriate size */
87 configure_event( GtkWidget *widget, GdkEventConfigure *event STG_UNUSED,
91 gdk_pixmap_unref(*pixmap);
93 *pixmap = gdk_pixmap_new(widget->window,
94 widget->allocation.width,
95 widget->allocation.height,
98 gdk_draw_rectangle (*pixmap,
99 widget->style->white_gc,
102 widget->allocation.width,
103 widget->allocation.height);
105 fprintf(stderr, "configure!\n");
110 /* Redraw the screen from the backing pixmap */
112 expose_event( GtkWidget *widget, GdkEventExpose *event, GdkPixmap **pixmap )
114 gdk_draw_pixmap(widget->window,
115 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
117 event->area.x, event->area.y,
118 event->area.x, event->area.y,
119 event->area.width, event->area.height);
125 initFrontPanel( void )
127 GdkColormap *colormap;
130 gtk_init( &prog_argc, &prog_argv );
132 window = create_GHC_Front_Panel();
133 map_drawing_area = lookup_widget(window, "memmap");
134 gen_drawing_area = lookup_widget(window, "generations");
135 res_drawing_area = lookup_widget(window, "res_drawingarea");
136 stop_but = lookup_widget(window, "stop_but");
137 continue_but = lookup_widget(window, "continue_but");
138 quit_but = lookup_widget(window, "quit_but");
139 statusbar = lookup_widget(window, "statusbar");
140 live_label = lookup_widget(window, "live_label");
141 footprint_label = lookup_widget(window, "footprint_label");
142 allocated_label = lookup_widget(window, "allocated_label");
143 alloc_rate_label = lookup_widget(window, "alloc_rate_label");
144 gen_hbox = lookup_widget(window, "gen_hbox");
145 gen_ruler = lookup_widget(window, "gen_ruler");
146 map_ruler = lookup_widget(window, "map_ruler");
147 res_vruler = lookup_widget(window, "res_vruler");
148 res_hruler = lookup_widget(window, "res_hruler");
149 running_label = lookup_widget(window, "running_label");
150 b_read_label = lookup_widget(window, "blockread_label");
151 b_write_label = lookup_widget(window, "blockwrite_label");
152 b_mvar_label = lookup_widget(window, "blockmvar_label");
153 b_bh_label = lookup_widget(window, "blockbh_label");
154 b_throwto_label = lookup_widget(window, "blockthrowto_label");
155 sleeping_label = lookup_widget(window, "sleeping_label");
156 total_label = lookup_widget(window, "total_label");
159 gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "context" );
161 /* hook up some signals for the mem map drawing area */
162 gtk_signal_connect (GTK_OBJECT(map_drawing_area), "expose_event",
163 (GtkSignalFunc)expose_event, &map_pixmap);
164 gtk_signal_connect (GTK_OBJECT(map_drawing_area), "configure_event",
165 (GtkSignalFunc)configure_event, &map_pixmap);
167 gtk_widget_set_events(map_drawing_area, GDK_EXPOSURE_MASK);
169 /* hook up some signals for the gen drawing area */
170 gtk_signal_connect (GTK_OBJECT(gen_drawing_area), "expose_event",
171 (GtkSignalFunc)expose_event, &gen_pixmap);
172 gtk_signal_connect (GTK_OBJECT(gen_drawing_area), "configure_event",
173 (GtkSignalFunc)configure_event, &gen_pixmap);
175 gtk_widget_set_events(gen_drawing_area, GDK_EXPOSURE_MASK);
177 /* hook up some signals for the res drawing area */
178 gtk_signal_connect (GTK_OBJECT(res_drawing_area), "expose_event",
179 (GtkSignalFunc)expose_event, &res_pixmap);
180 gtk_signal_connect (GTK_OBJECT(res_drawing_area), "configure_event",
181 (GtkSignalFunc)configure_event, &res_pixmap);
183 gtk_widget_set_events(res_drawing_area, GDK_EXPOSURE_MASK);
185 /* allocate our colors */
186 colormap = gdk_colormap_get_system();
187 gdk_colormap_alloc_color(colormap, &bdescr_color, TRUE, TRUE);
188 gdk_colormap_alloc_color(colormap, &free_color, TRUE, TRUE);
191 gboolean success[N_GENS];
192 gdk_colormap_alloc_colors(colormap, gen_colors, N_GENS, TRUE,
194 if (!success) { barf("can't allocate colors"); }
197 /* set the labels on the generation histogram */
203 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
204 for(s = 0; s < generations[g].n_steps; s++) {
205 g_snprintf( buf, 64, "%d.%d", g, s );
206 label = gtk_label_new( buf );
207 gtk_box_pack_start( GTK_BOX(gen_hbox), label,
209 gtk_widget_show(label);
214 gtk_widget_show(window);
216 /* wait for the user to press "Continue" before getting going... */
217 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
219 gtk_widget_set_sensitive( stop_but, FALSE );
220 continue_now = FALSE;
221 while (continue_now == FALSE) {
222 gtk_main_iteration();
224 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
225 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
228 gtk_widget_set_sensitive( continue_but, FALSE );
229 gtk_widget_set_sensitive( stop_but, TRUE );
230 gtk_widget_set_sensitive( quit_but, FALSE );
232 while (gtk_events_pending()) {
233 gtk_main_iteration();
238 stopFrontPanel( void )
240 gtk_widget_set_sensitive( quit_but, TRUE );
241 gtk_widget_set_sensitive( continue_but, FALSE );
242 gtk_widget_set_sensitive( stop_but, FALSE );
246 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
250 while (quit == FALSE) {
251 gtk_main_iteration();
256 waitForContinue( void )
258 gtk_widget_set_sensitive( continue_but, TRUE );
259 gtk_widget_set_sensitive( stop_but, FALSE );
261 continue_now = FALSE;
262 while (continue_now == FALSE) {
263 gtk_main_iteration();
265 gtk_widget_set_sensitive( continue_but, FALSE );
266 gtk_widget_set_sensitive( stop_but, TRUE );
270 updateFrontPanelBeforeGC( nat N )
276 if (update_mode == BeforeGC
277 || update_mode == BeforeAfterGC
278 || stop_now == TRUE) {
279 g_snprintf( buf, 1000, "Stopped (before GC, generation %d)", N );
280 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf );
282 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
285 g_snprintf( buf, 1000, "Garbage collecting (generation %d)", N );
286 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf);
288 while (gtk_events_pending()) {
289 gtk_main_iteration();
294 numLabel( GtkWidget *lbl, nat n )
297 g_snprintf(buf, 64, "%d", n);
298 gtk_label_set_text( GTK_LABEL(lbl), buf );
302 updateFrontPanelAfterGC( nat N, lnat live )
306 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
309 if (N == RtsFlags.GcFlags.generations-1) {
315 if (update_mode == AfterGC
316 || update_mode == BeforeAfterGC
317 || stop_now == TRUE) {
318 snprintf( buf, 1000, "Stopped (after GC, generation %d)", N );
319 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf );
321 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
325 double words_to_megs = (1024 * 1024) / sizeof(W_);
326 double time = mut_user_time();
328 snprintf( buf, 1000, "%.2f", (double)live / words_to_megs );
329 gtk_label_set_text( GTK_LABEL(live_label), buf );
331 snprintf( buf, 1000, "%.2f", (double)total_allocated / words_to_megs );
332 gtk_label_set_text( GTK_LABEL(allocated_label), buf );
334 snprintf( buf, 1000, "%.2f",
335 (double)(mblocks_allocated * MBLOCK_SIZE_W) / words_to_megs );
336 gtk_label_set_text( GTK_LABEL(footprint_label), buf );
339 snprintf( buf, 1000, "%.2f", time );
341 snprintf( buf, 1000, "%.2f",
342 (double)(total_allocated / words_to_megs) / time );
343 gtk_label_set_text( GTK_LABEL(alloc_rate_label), buf );
346 while (gtk_events_pending()) {
347 gtk_main_iteration();
352 updateFrontPanel( void )
357 updateThreadsPanel();
360 my_gc = gdk_gc_new( window->window );
363 if (map_pixmap != NULL) {
364 nat height, width, blocks_per_line,
365 block_height, block_width, mblock_height;
367 height = map_drawing_area->allocation.height;
368 width = map_drawing_area->allocation.width;
370 mblock_height = height / mblocks_allocated;
371 blocks_per_line = 16;
372 block_height = mblock_height /
373 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
374 while (block_height == 0) {
375 blocks_per_line *= 2;
376 block_height = mblock_height /
377 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
379 block_width = width / blocks_per_line;
381 gdk_draw_rectangle (map_pixmap,
382 map_drawing_area->style->bg_gc[GTK_STATE_NORMAL],
385 map_drawing_area->allocation.width,
386 map_drawing_area->allocation.height);
389 (char *)m < (char *)mem_start +
390 (mblocks_allocated * MBLOCK_SIZE);
391 (char *)m += MBLOCK_SIZE ) {
393 /* color the bdescr area first */
394 for (a = m; a < FIRST_BLOCK(m); (char *)a += BLOCK_SIZE) {
395 colorBlock( a, &bdescr_color,
396 block_width, block_height, blocks_per_line );
399 /* color each block */
400 for (; a <= LAST_BLOCK(m); (char *)a += BLOCK_SIZE) {
402 ASSERT(bd->start == a);
403 if (bd->free == (void *)-1) {
404 colorBlock( a, &free_color,
405 block_width, block_height, blocks_per_line );
406 } else if (bd->gen != NULL) {
407 colorBlock( a, &gen_colors[bd->gen->no],
408 block_width, block_height, blocks_per_line );
409 } else if (bd->link != NULL) {
410 if (bd->link->free == (void *)-1) {
411 colorBlock( a, &free_color,
412 block_width, block_height, blocks_per_line );
414 } else if (bd->link->gen != NULL) {
415 colorBlock( a, &gen_colors[bd->link->gen->no],
416 block_width, block_height, blocks_per_line );
418 belch("block at %p: can't indentify", bd->start);
426 nat height = map_drawing_area->allocation.height,
427 block_height, mblock_height;
429 block_height = (height / mblocks_allocated) /
430 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
431 if (block_height < 1) block_height = 1;
432 mblock_height = block_height *
433 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
435 gtk_ruler_set_range( GTK_RULER(map_ruler), 0,
436 (double)(height * mblocks_allocated) /
437 (double)((mblock_height * mblocks_allocated)),
439 (double)(height * mblocks_allocated) /
440 (double)((mblock_height * mblocks_allocated))
444 gtk_widget_draw( map_drawing_area, NULL );
447 if (gen_pixmap != NULL) {
450 nat g, s, columns, column, max_blocks, height_blocks,
453 gdk_draw_rectangle (gen_pixmap,
454 gen_drawing_area->style->white_gc,
457 gen_drawing_area->allocation.width,
458 gen_drawing_area->allocation.height);
460 height = gen_drawing_area->allocation.height;
461 width = gen_drawing_area->allocation.width;
463 columns = 0; max_blocks = 0;
464 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
465 columns += generations[g].n_steps;
466 for(s = 0; s < generations[g].n_steps; s++) {
467 if (generations[g].steps[s].n_blocks > max_blocks) {
468 max_blocks = generations[g].steps[s].n_blocks;
473 /* find a reasonable height value larger than max_blocks */
476 while (max_blocks != 0) {
477 max_blocks >>= 1; n++;
479 height_blocks = 1 << n;
483 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
484 for(s = 0; s < generations[g].n_steps; s++, column++) {
485 gdk_gc_set_foreground(my_gc, &gen_colors[g]);
487 rect.x = column * (width / columns);
489 if (generations[g].steps[s].n_blocks == 0)
493 (height * generations[g].steps[s].n_blocks
496 rect.width = (width / columns);
497 rect.height = height - rect.y;
499 gdk_draw_rectangle( gen_pixmap, my_gc, TRUE/*filled*/,
500 rect.x, rect.y, rect.width,
505 gtk_ruler_set_range( GTK_RULER(gen_ruler),
506 height_blocks * BLOCK_SIZE / (1024 * 1024),
508 height_blocks * BLOCK_SIZE / (1024 * 1024)
511 gtk_widget_draw( gen_drawing_area, NULL );
514 if (res_pixmap != NULL) {
515 updateResidencyGraph();
518 while (gtk_events_pending()) {
519 gtk_main_iteration_do(FALSE/*don't block*/);
524 colorBlock( void *addr, GdkColor *color,
525 nat block_width, nat block_height, nat blocks_per_line )
530 gdk_gc_set_foreground(my_gc, color);
532 block_no = ((char *)addr - (char *)mem_start) / BLOCK_SIZE;
534 rect.x = (block_no % blocks_per_line) * block_width;
535 rect.y = block_no / blocks_per_line * block_height;
536 rect.width = block_width;
537 rect.height = block_height;
538 gdk_draw_rectangle( map_pixmap, my_gc, TRUE/*filled*/,
539 rect.x, rect.y, rect.width, rect.height );
543 updateThreadsPanel( void )
556 for (t = all_threads; t != END_TSO_QUEUE; t = t->global_link) {
557 switch (t->what_next) {
558 case ThreadKilled: break;
559 case ThreadComplete: break;
561 switch (t->why_blocked) {
562 case BlockedOnRead: b_read++; break;
563 case BlockedOnWrite: b_write++; break;
564 case BlockedOnDelay: sleeping++; break;
565 case BlockedOnMVar: b_mvar++; break;
566 case BlockedOnException: b_throwto++; break;
567 case BlockedOnBlackHole: b_bh++; break;
568 case NotBlocked: running++; break;
572 total = running + b_read + b_write + b_mvar + b_throwto + b_bh + sleeping;
573 numLabel(running_label, running);
574 numLabel(b_read_label, b_read);
575 numLabel(b_write_label, b_write);
576 numLabel(b_mvar_label, b_mvar);
577 numLabel(b_bh_label, b_bh);
578 numLabel(b_throwto_label, b_throwto);
579 numLabel(sleeping_label, sleeping);
580 numLabel(total_label, total);
583 typedef enum { Thunk, Fun, Constr, BlackHole,
584 Array, Thread, Other, N_Cats } ClosureCategory;
588 static nat *res_prof[N_SLICES];
589 static double res_time[N_SLICES];
590 static nat next_slice = 0;
593 residencyCensus( void )
595 nat slice = next_slice++, *prof;
597 nat g, s, size, type;
601 if (slice >= N_SLICES) {
602 barf("too many slices");
604 res_prof[slice] = stgMallocBytes(N_Cats * sizeof(nat), "residencyCensus");
605 prof = res_prof[slice];
606 memset(prof, 0, N_Cats * sizeof(nat));
608 res_time[slice] = mut_user_time();
610 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
611 for(s = 0; s < generations[g].n_steps; s++) {
613 /* skip over g0s0 if multi-generational */
614 if (RtsFlags.GcFlags.generations > 1 &&
615 g == 0 && s == 0) continue;
617 if (RtsFlags.GcFlags.generations == 1) {
618 bd = generations[g].steps[s].to_space;
620 bd = generations[g].steps[s].blocks;
623 for (; bd != NULL; bd = bd->link) {
627 while (p < bd->free) {
628 info = get_itbl((StgClosure *)p);
631 switch (info->type) {
635 if (((StgClosure *)p)->header.info == &stg_DEAD_WEAK_info) {
636 size = sizeofW(StgWeak);
640 /* else, fall through... */
646 size = sizeW_fromITBL(info);
652 size = sizeofW(StgHeader) + 1;
658 size = sizeW_fromITBL(info);
666 size = sizeofW(StgHeader) + 2;
672 size = sizeW_fromITBL(info);
678 case SE_CAF_BLACKHOLE:
682 size = sizeW_fromITBL(info);
687 size = pap_sizeW((StgPAP *)p);
692 size = pap_sizeW((StgPAP *)p);
697 size = arr_words_sizeW(stgCast(StgArrWords*,p));
702 case MUT_ARR_PTRS_FROZEN:
703 size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
708 size = tso_sizeW((StgTSO *)p);
718 case IND_OLDGEN_PERM:
719 size = sizeW_fromITBL(info);
724 barf("updateResidencyGraph: strange closure "
738 updateResidencyGraph( void )
740 nat total, prev_total, i, max_res;
742 double time_scale = 1;
743 nat last_slice = next_slice-1;
744 double res_scale = 1; /* in megabytes, doubles */
749 gdk_draw_rectangle (res_pixmap,
750 res_drawing_area->style->bg_gc[GTK_STATE_NORMAL],
753 res_drawing_area->allocation.width,
754 res_drawing_area->allocation.height);
756 if (next_slice == 0) return;
758 time = res_time[last_slice];
759 while (time > time_scale) {
764 for (i = 0; i < next_slice; i++) {
766 total = prof[Thunk] + prof[Fun] + prof[Constr] +
767 prof[BlackHole] + prof[Array] + prof[Other];
768 if (total > max_res) {
772 while (max_res > res_scale) {
776 height = res_drawing_area->allocation.height;
777 width = res_drawing_area->allocation.width;
780 points[0].y = height;
781 points[1].y = height;
783 points[3].y = height;
785 gdk_gc_set_foreground(my_gc, &free_color);
788 for (i = 0; i < next_slice; i++) {
790 total = prof[Thunk] + prof[Fun] + prof[Constr] +
791 prof[BlackHole] + prof[Array] + prof[Other];
792 points[1].x = width * res_time[i] / time_scale;
793 points[2].x = points[1].x;
794 points[2].y = height - ((height * total) / res_scale);
795 gdk_draw_polygon(res_pixmap, my_gc, TRUE/*filled*/, points, 4);
796 points[3] = points[2];
797 points[0] = points[1];
800 gtk_ruler_set_range( GTK_RULER(res_vruler),
801 res_scale / ((1024*1024)/sizeof(W_)),
803 res_scale / ((1024*1024)/sizeof(W_)) );
805 gtk_ruler_set_range( GTK_RULER(res_hruler),
806 0, time_scale, 0, time_scale );
809 gtk_widget_draw( res_drawing_area, NULL );
812 #endif /* RTS_GTK_FRONTPANEL */