1 /* -----------------------------------------------------------------------------
2 * $Id: FrontPanel.c,v 1.5 2001/08/14 13:40:09 sewardj Exp $
4 * (c) The GHC Team 2000
8 * ---------------------------------------------------------------------------*/
10 #ifdef RTS_GTK_FRONTPANEL
12 /* Alas, not Posix. */
13 /* #include "PosixSource.h" */
18 #include "FrontPanel.h"
20 #include "StoragePriv.h"
26 #include <gdk/gdktypes.h>
29 #include "VisSupport.h"
30 #include "VisWindow.h"
32 static GtkWidget *window, *map_drawing_area, *gen_drawing_area;
33 static GtkWidget *res_drawing_area;
34 static GtkWidget *continue_but, *stop_but, *quit_but;
35 static GtkWidget *statusbar;
36 static GtkWidget *live_label, *allocated_label;
37 static GtkWidget *footprint_label, *alloc_rate_label;
38 static GtkWidget *map_ruler, *gen_ruler;
39 static GtkWidget *res_vruler, *res_hruler;
40 static GtkWidget *running_label, *b_read_label, *b_write_label, *total_label;
41 static GtkWidget *b_mvar_label, *b_bh_label, *b_throwto_label, *sleeping_label;
43 static guint status_context_id;
45 gboolean continue_now = FALSE, stop_now = FALSE, quit = FALSE;
46 UpdateMode update_mode = Continuous;
48 static GdkPixmap *map_pixmap = NULL;
49 static GdkPixmap *gen_pixmap = NULL;
50 static GdkPixmap *res_pixmap = NULL;
55 bdescr_color = { 0, 0xffff, 0, 0 }, /* red */
56 free_color = { 0, 0, 0, 0xffff }, /* blue */
57 gen_colors[N_GENS] = {
72 static void *mem_start = (void *) 0x50000000;
74 static void colorBlock( void *addr, GdkColor *color,
75 nat block_width, nat block_height,
76 nat blocks_per_line );
78 static void residencyCensus( void );
79 static void updateResidencyGraph( void );
80 static void updateThreadsPanel( void );
82 /* Some code pinched from examples/scribble-simple in the GTK+
86 /* Create a new backing pixmap of the appropriate size */
88 configure_event( GtkWidget *widget, GdkEventConfigure *event STG_UNUSED,
92 gdk_pixmap_unref(*pixmap);
94 *pixmap = gdk_pixmap_new(widget->window,
95 widget->allocation.width,
96 widget->allocation.height,
99 gdk_draw_rectangle (*pixmap,
100 widget->style->white_gc,
103 widget->allocation.width,
104 widget->allocation.height);
106 fprintf(stderr, "configure!\n");
111 /* Redraw the screen from the backing pixmap */
113 expose_event( GtkWidget *widget, GdkEventExpose *event, GdkPixmap **pixmap )
115 gdk_draw_pixmap(widget->window,
116 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
118 event->area.x, event->area.y,
119 event->area.x, event->area.y,
120 event->area.width, event->area.height);
126 initFrontPanel( void )
128 GdkColormap *colormap;
131 gtk_init( &prog_argc, &prog_argv );
133 window = create_GHC_Front_Panel();
134 map_drawing_area = lookup_widget(window, "memmap");
135 gen_drawing_area = lookup_widget(window, "generations");
136 res_drawing_area = lookup_widget(window, "res_drawingarea");
137 stop_but = lookup_widget(window, "stop_but");
138 continue_but = lookup_widget(window, "continue_but");
139 quit_but = lookup_widget(window, "quit_but");
140 statusbar = lookup_widget(window, "statusbar");
141 live_label = lookup_widget(window, "live_label");
142 footprint_label = lookup_widget(window, "footprint_label");
143 allocated_label = lookup_widget(window, "allocated_label");
144 alloc_rate_label = lookup_widget(window, "alloc_rate_label");
145 gen_hbox = lookup_widget(window, "gen_hbox");
146 gen_ruler = lookup_widget(window, "gen_ruler");
147 map_ruler = lookup_widget(window, "map_ruler");
148 res_vruler = lookup_widget(window, "res_vruler");
149 res_hruler = lookup_widget(window, "res_hruler");
150 running_label = lookup_widget(window, "running_label");
151 b_read_label = lookup_widget(window, "blockread_label");
152 b_write_label = lookup_widget(window, "blockwrite_label");
153 b_mvar_label = lookup_widget(window, "blockmvar_label");
154 b_bh_label = lookup_widget(window, "blockbh_label");
155 b_throwto_label = lookup_widget(window, "blockthrowto_label");
156 sleeping_label = lookup_widget(window, "sleeping_label");
157 total_label = lookup_widget(window, "total_label");
160 gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "context" );
162 /* hook up some signals for the mem map drawing area */
163 gtk_signal_connect (GTK_OBJECT(map_drawing_area), "expose_event",
164 (GtkSignalFunc)expose_event, &map_pixmap);
165 gtk_signal_connect (GTK_OBJECT(map_drawing_area), "configure_event",
166 (GtkSignalFunc)configure_event, &map_pixmap);
168 gtk_widget_set_events(map_drawing_area, GDK_EXPOSURE_MASK);
170 /* hook up some signals for the gen drawing area */
171 gtk_signal_connect (GTK_OBJECT(gen_drawing_area), "expose_event",
172 (GtkSignalFunc)expose_event, &gen_pixmap);
173 gtk_signal_connect (GTK_OBJECT(gen_drawing_area), "configure_event",
174 (GtkSignalFunc)configure_event, &gen_pixmap);
176 gtk_widget_set_events(gen_drawing_area, GDK_EXPOSURE_MASK);
178 /* hook up some signals for the res drawing area */
179 gtk_signal_connect (GTK_OBJECT(res_drawing_area), "expose_event",
180 (GtkSignalFunc)expose_event, &res_pixmap);
181 gtk_signal_connect (GTK_OBJECT(res_drawing_area), "configure_event",
182 (GtkSignalFunc)configure_event, &res_pixmap);
184 gtk_widget_set_events(res_drawing_area, GDK_EXPOSURE_MASK);
186 /* allocate our colors */
187 colormap = gdk_colormap_get_system();
188 gdk_colormap_alloc_color(colormap, &bdescr_color, TRUE, TRUE);
189 gdk_colormap_alloc_color(colormap, &free_color, TRUE, TRUE);
192 gboolean success[N_GENS];
193 gdk_colormap_alloc_colors(colormap, gen_colors, N_GENS, TRUE,
195 if (!success) { barf("can't allocate colors"); }
198 /* set the labels on the generation histogram */
204 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
205 for(s = 0; s < generations[g].n_steps; s++) {
206 g_snprintf( buf, 64, "%d.%d", g, s );
207 label = gtk_label_new( buf );
208 gtk_box_pack_start( GTK_BOX(gen_hbox), label,
210 gtk_widget_show(label);
215 gtk_widget_show(window);
217 /* wait for the user to press "Continue" before getting going... */
218 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
220 gtk_widget_set_sensitive( stop_but, FALSE );
221 continue_now = FALSE;
222 while (continue_now == FALSE) {
223 gtk_main_iteration();
225 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
226 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
229 gtk_widget_set_sensitive( continue_but, FALSE );
230 gtk_widget_set_sensitive( stop_but, TRUE );
231 gtk_widget_set_sensitive( quit_but, FALSE );
233 while (gtk_events_pending()) {
234 gtk_main_iteration();
239 stopFrontPanel( void )
241 gtk_widget_set_sensitive( quit_but, TRUE );
242 gtk_widget_set_sensitive( continue_but, FALSE );
243 gtk_widget_set_sensitive( stop_but, FALSE );
247 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id,
251 while (quit == FALSE) {
252 gtk_main_iteration();
257 waitForContinue( void )
259 gtk_widget_set_sensitive( continue_but, TRUE );
260 gtk_widget_set_sensitive( stop_but, FALSE );
262 continue_now = FALSE;
263 while (continue_now == FALSE) {
264 gtk_main_iteration();
266 gtk_widget_set_sensitive( continue_but, FALSE );
267 gtk_widget_set_sensitive( stop_but, TRUE );
271 updateFrontPanelBeforeGC( nat N )
277 if (update_mode == BeforeGC
278 || update_mode == BeforeAfterGC
279 || stop_now == TRUE) {
280 g_snprintf( buf, 1000, "Stopped (before GC, generation %d)", N );
281 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf );
283 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
286 g_snprintf( buf, 1000, "Garbage collecting (generation %d)", N );
287 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf);
289 while (gtk_events_pending()) {
290 gtk_main_iteration();
295 numLabel( GtkWidget *lbl, nat n )
298 g_snprintf(buf, 64, "%d", n);
299 gtk_label_set_text( GTK_LABEL(lbl), buf );
303 updateFrontPanelAfterGC( nat N, lnat live )
307 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
310 if (N == RtsFlags.GcFlags.generations-1) {
316 if (update_mode == AfterGC
317 || update_mode == BeforeAfterGC
318 || stop_now == TRUE) {
319 snprintf( buf, 1000, "Stopped (after GC, generation %d)", N );
320 gtk_statusbar_push( GTK_STATUSBAR(statusbar), status_context_id, buf );
322 gtk_statusbar_pop( GTK_STATUSBAR(statusbar), status_context_id );
326 double words_to_megs = (1024 * 1024) / sizeof(W_);
327 double time = mut_user_time();
329 snprintf( buf, 1000, "%.2f", (double)live / words_to_megs );
330 gtk_label_set_text( GTK_LABEL(live_label), buf );
332 snprintf( buf, 1000, "%.2f", (double)total_allocated / words_to_megs );
333 gtk_label_set_text( GTK_LABEL(allocated_label), buf );
335 snprintf( buf, 1000, "%.2f",
336 (double)(mblocks_allocated * MBLOCK_SIZE_W) / words_to_megs );
337 gtk_label_set_text( GTK_LABEL(footprint_label), buf );
340 snprintf( buf, 1000, "%.2f", time );
342 snprintf( buf, 1000, "%.2f",
343 (double)(total_allocated / words_to_megs) / time );
344 gtk_label_set_text( GTK_LABEL(alloc_rate_label), buf );
347 while (gtk_events_pending()) {
348 gtk_main_iteration();
353 updateFrontPanel( void )
358 updateThreadsPanel();
361 my_gc = gdk_gc_new( window->window );
364 if (map_pixmap != NULL) {
365 nat height, width, blocks_per_line,
366 block_height, block_width, mblock_height;
368 height = map_drawing_area->allocation.height;
369 width = map_drawing_area->allocation.width;
371 mblock_height = height / mblocks_allocated;
372 blocks_per_line = 16;
373 block_height = mblock_height /
374 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
375 while (block_height == 0) {
376 blocks_per_line *= 2;
377 block_height = mblock_height /
378 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
380 block_width = width / blocks_per_line;
382 gdk_draw_rectangle (map_pixmap,
383 map_drawing_area->style->bg_gc[GTK_STATE_NORMAL],
386 map_drawing_area->allocation.width,
387 map_drawing_area->allocation.height);
390 (char *)m < (char *)mem_start +
391 (mblocks_allocated * MBLOCK_SIZE);
392 (char *)m += MBLOCK_SIZE ) {
394 /* color the bdescr area first */
395 for (a = m; a < FIRST_BLOCK(m); (char *)a += BLOCK_SIZE) {
396 colorBlock( a, &bdescr_color,
397 block_width, block_height, blocks_per_line );
400 /* color each block */
401 for (; a <= LAST_BLOCK(m); (char *)a += BLOCK_SIZE) {
403 ASSERT(bd->start == a);
404 if (bd->free == (void *)-1) {
405 colorBlock( a, &free_color,
406 block_width, block_height, blocks_per_line );
407 } else if (bd->gen != NULL) {
408 colorBlock( a, &gen_colors[bd->gen->no],
409 block_width, block_height, blocks_per_line );
410 } else if (bd->link != NULL) {
411 if (bd->link->free == (void *)-1) {
412 colorBlock( a, &free_color,
413 block_width, block_height, blocks_per_line );
415 } else if (bd->link->gen != NULL) {
416 colorBlock( a, &gen_colors[bd->link->gen->no],
417 block_width, block_height, blocks_per_line );
419 belch("block at %p: can't indentify", bd->start);
427 nat height = map_drawing_area->allocation.height,
428 block_height, mblock_height;
430 block_height = (height / mblocks_allocated) /
431 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
432 if (block_height < 1) block_height = 1;
433 mblock_height = block_height *
434 ((MBLOCK_SIZE/BLOCK_SIZE) / blocks_per_line);
436 gtk_ruler_set_range( GTK_RULER(map_ruler), 0,
437 (double)(height * mblocks_allocated) /
438 (double)((mblock_height * mblocks_allocated)),
440 (double)(height * mblocks_allocated) /
441 (double)((mblock_height * mblocks_allocated))
445 gtk_widget_draw( map_drawing_area, NULL );
448 if (gen_pixmap != NULL) {
451 nat g, s, columns, column, max_blocks, height_blocks,
454 gdk_draw_rectangle (gen_pixmap,
455 gen_drawing_area->style->white_gc,
458 gen_drawing_area->allocation.width,
459 gen_drawing_area->allocation.height);
461 height = gen_drawing_area->allocation.height;
462 width = gen_drawing_area->allocation.width;
464 columns = 0; max_blocks = 0;
465 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
466 columns += generations[g].n_steps;
467 for(s = 0; s < generations[g].n_steps; s++) {
468 if (generations[g].steps[s].n_blocks > max_blocks) {
469 max_blocks = generations[g].steps[s].n_blocks;
474 /* find a reasonable height value larger than max_blocks */
477 while (max_blocks != 0) {
478 max_blocks >>= 1; n++;
480 height_blocks = 1 << n;
484 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
485 for(s = 0; s < generations[g].n_steps; s++, column++) {
486 gdk_gc_set_foreground(my_gc, &gen_colors[g]);
488 rect.x = column * (width / columns);
490 if (generations[g].steps[s].n_blocks == 0)
494 (height * generations[g].steps[s].n_blocks
497 rect.width = (width / columns);
498 rect.height = height - rect.y;
500 gdk_draw_rectangle( gen_pixmap, my_gc, TRUE/*filled*/,
501 rect.x, rect.y, rect.width,
506 gtk_ruler_set_range( GTK_RULER(gen_ruler),
507 height_blocks * BLOCK_SIZE / (1024 * 1024),
509 height_blocks * BLOCK_SIZE / (1024 * 1024)
512 gtk_widget_draw( gen_drawing_area, NULL );
515 if (res_pixmap != NULL) {
516 updateResidencyGraph();
519 while (gtk_events_pending()) {
520 gtk_main_iteration_do(FALSE/*don't block*/);
525 colorBlock( void *addr, GdkColor *color,
526 nat block_width, nat block_height, nat blocks_per_line )
531 gdk_gc_set_foreground(my_gc, color);
533 block_no = ((char *)addr - (char *)mem_start) / BLOCK_SIZE;
535 rect.x = (block_no % blocks_per_line) * block_width;
536 rect.y = block_no / blocks_per_line * block_height;
537 rect.width = block_width;
538 rect.height = block_height;
539 gdk_draw_rectangle( map_pixmap, my_gc, TRUE/*filled*/,
540 rect.x, rect.y, rect.width, rect.height );
544 updateThreadsPanel( void )
557 for (t = all_threads; t != END_TSO_QUEUE; t = t->global_link) {
558 switch (t->what_next) {
559 case ThreadKilled: break;
560 case ThreadComplete: break;
562 switch (t->why_blocked) {
563 case BlockedOnRead: b_read++; break;
564 case BlockedOnWrite: b_write++; break;
565 case BlockedOnDelay: sleeping++; break;
566 case BlockedOnMVar: b_mvar++; break;
567 case BlockedOnException: b_throwto++; break;
568 case BlockedOnBlackHole: b_bh++; break;
569 case NotBlocked: running++; break;
573 total = running + b_read + b_write + b_mvar + b_throwto + b_bh + sleeping;
574 numLabel(running_label, running);
575 numLabel(b_read_label, b_read);
576 numLabel(b_write_label, b_write);
577 numLabel(b_mvar_label, b_mvar);
578 numLabel(b_bh_label, b_bh);
579 numLabel(b_throwto_label, b_throwto);
580 numLabel(sleeping_label, sleeping);
581 numLabel(total_label, total);
584 typedef enum { Thunk, Fun, Constr, BlackHole,
585 Array, Thread, Other, N_Cats } ClosureCategory;
589 static nat *res_prof[N_SLICES];
590 static double res_time[N_SLICES];
591 static nat next_slice = 0;
594 residencyCensus( void )
596 nat slice = next_slice++, *prof;
598 nat g, s, size, type;
602 if (slice >= N_SLICES) {
603 barf("too many slices");
605 res_prof[slice] = stgMallocBytes(N_Cats * sizeof(nat), "residencyCensus");
606 prof = res_prof[slice];
607 memset(prof, 0, N_Cats * sizeof(nat));
609 res_time[slice] = mut_user_time();
611 for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
612 for(s = 0; s < generations[g].n_steps; s++) {
614 /* skip over g0s0 if multi-generational */
615 if (RtsFlags.GcFlags.generations > 1 &&
616 g == 0 && s == 0) continue;
618 if (RtsFlags.GcFlags.generations == 1) {
619 bd = generations[g].steps[s].to_space;
621 bd = generations[g].steps[s].blocks;
624 for (; bd != NULL; bd = bd->link) {
628 while (p < bd->free) {
629 info = get_itbl((StgClosure *)p);
632 switch (info->type) {
636 if (((StgClosure *)p)->header.info == &stg_DEAD_WEAK_info) {
637 size = sizeofW(StgWeak);
641 /* else, fall through... */
647 size = sizeW_fromITBL(info);
653 size = sizeofW(StgHeader) + 1;
659 size = sizeW_fromITBL(info);
667 size = sizeofW(StgHeader) + 2;
673 size = sizeW_fromITBL(info);
679 case SE_CAF_BLACKHOLE:
683 size = sizeW_fromITBL(info);
688 size = pap_sizeW((StgPAP *)p);
693 size = pap_sizeW((StgPAP *)p);
698 size = arr_words_sizeW(stgCast(StgArrWords*,p));
703 case MUT_ARR_PTRS_FROZEN:
704 size = mut_arr_ptrs_sizeW((StgMutArrPtrs *)p);
709 size = tso_sizeW((StgTSO *)p);
719 case IND_OLDGEN_PERM:
720 size = sizeW_fromITBL(info);
725 barf("updateResidencyGraph: strange closure "
739 updateResidencyGraph( void )
741 nat total, prev_total, i, max_res;
743 double time_scale = 1;
744 nat last_slice = next_slice-1;
745 double res_scale = 1; /* in megabytes, doubles */
750 gdk_draw_rectangle (res_pixmap,
751 res_drawing_area->style->bg_gc[GTK_STATE_NORMAL],
754 res_drawing_area->allocation.width,
755 res_drawing_area->allocation.height);
757 if (next_slice == 0) return;
759 time = res_time[last_slice];
760 while (time > time_scale) {
765 for (i = 0; i < next_slice; i++) {
767 total = prof[Thunk] + prof[Fun] + prof[Constr] +
768 prof[BlackHole] + prof[Array] + prof[Other];
769 if (total > max_res) {
773 while (max_res > res_scale) {
777 height = res_drawing_area->allocation.height;
778 width = res_drawing_area->allocation.width;
781 points[0].y = height;
782 points[1].y = height;
784 points[3].y = height;
786 gdk_gc_set_foreground(my_gc, &free_color);
789 for (i = 0; i < next_slice; i++) {
791 total = prof[Thunk] + prof[Fun] + prof[Constr] +
792 prof[BlackHole] + prof[Array] + prof[Other];
793 points[1].x = width * res_time[i] / time_scale;
794 points[2].x = points[1].x;
795 points[2].y = height - ((height * total) / res_scale);
796 gdk_draw_polygon(res_pixmap, my_gc, TRUE/*filled*/, points, 4);
797 points[3] = points[2];
798 points[0] = points[1];
801 gtk_ruler_set_range( GTK_RULER(res_vruler),
802 res_scale / ((1024*1024)/sizeof(W_)),
804 res_scale / ((1024*1024)/sizeof(W_)) );
806 gtk_ruler_set_range( GTK_RULER(res_hruler),
807 0, time_scale, 0, time_scale );
810 gtk_widget_draw( res_drawing_area, NULL );
813 #endif /* RTS_GTK_FRONTPANEL */