/** * uber_line_graph_add_line: * @graph: A #UberLineGraph. * @color: A #GdkColor for the line or %NULL. * * Adds a new line to the graph. If color is %NULL, the next value * in the default color list will be used. * * See uber_line_graph_remove_line(). * * Returns: The line identifier. * Side effects: None. */ gint uber_line_graph_add_line (UberLineGraph *graph, /* IN */ const GdkColor *color, /* IN */ UberLabel *label) /* IN */ { UberLineGraphPrivate *priv; LineInfo info = { 0 }; g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), 0); priv = graph->priv; info.alpha = 1.0; info.width = 1.0; /* * Retrieve the lines color. */ if (color) { info.color = *color; } else { gdk_color_parse("#729fcf", &info.color); } /* * Allocate buffers for data points. */ info.raw_data = g_ring_sized_new(sizeof(gdouble), priv->stride, NULL); uber_line_graph_init_ring(info.raw_data); /* * Store the newly crated line. */ g_array_append_val(priv->lines, info); /* * Mark the graph for full redraw. */ uber_graph_redraw(UBER_GRAPH(graph)); /* * Attach label. */ if (label) { uber_line_graph_bind_label(graph, priv->lines->len, label); uber_graph_add_label(UBER_GRAPH(graph), label); uber_label_set_color(label, &info.color); } /* * Line indexes start from 1. */ return priv->lines->len; }
/** * uber_window_show_labels: * @window: A #UberWindow. * * XXX * * Returns: None. * Side effects: None. */ void uber_window_show_labels (UberWindow *window, /* IN */ UberGraph *graph) /* IN */ { UberWindowPrivate *priv; GtkWidget *labels; GtkWidget *align; GList *list; gboolean show; g_return_if_fail(UBER_IS_WINDOW(window)); g_return_if_fail(UBER_IS_GRAPH(graph)); priv = window->priv; /* * Get the widgets labels. */ labels = uber_graph_get_labels(graph); /* * Show/hide ticks and labels. */ show = !!labels; if (labels) { align = gtk_bin_get_child(GTK_BIN(labels)); list = gtk_container_get_children(GTK_CONTAINER(align)); if (list) { gtk_widget_show(labels); } else { gtk_widget_hide(labels); show = FALSE; } g_list_free(list); } if (graph == (gpointer)g_list_last(priv->graphs)) { show = TRUE; } uber_graph_set_show_xlabels(graph, show); /* * Hide labels/xlabels for other graphs. */ for (list = priv->graphs; list && list->next; list = list->next) { if (list->data != graph) { uber_graph_set_show_xlabels(list->data, FALSE); labels = uber_graph_get_labels(list->data); if (labels) { gtk_widget_hide(labels); } } } /* * Ensure the last graph always has labels. */ if (list) { uber_graph_set_show_xlabels(UBER_GRAPH(list->data), TRUE); } }
/** * uber_line_graph_set_antialias: * @graph: A #UberLineGraph. * * XXX * * Returns: None. * Side effects: None. */ void uber_line_graph_set_antialias (UberLineGraph *graph, /* IN */ cairo_antialias_t antialias) /* IN */ { UberLineGraphPrivate *priv; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); priv = graph->priv; priv->antialias = antialias; uber_graph_redraw(UBER_GRAPH(graph)); }
static gboolean uber_window_graph_button_press_event (GtkWidget *widget, /* IN */ GdkEventButton *button, /* IN */ UberWindow *window) /* IN */ { GtkWidget *labels; g_return_val_if_fail(UBER_IS_WINDOW(window), FALSE); g_return_val_if_fail(UBER_IS_GRAPH(widget), FALSE); switch (button->button) { case 1: /* Left click */ labels = uber_graph_get_labels(UBER_GRAPH(widget)); if (gtk_widget_get_visible(labels)) { uber_window_hide_labels(window, UBER_GRAPH(widget)); } else { uber_window_show_labels(window, UBER_GRAPH(widget)); } break; default: break; } return FALSE; }
/** * uber_line_graph_set_line_width: * @graph: A #UberLineGraph. * * XXX * * Returns: None. * Side effects: None. */ void uber_line_graph_set_line_width (UberLineGraph *graph, /* IN */ gint line, /* IN */ gdouble width) /* IN */ { UberLineGraphPrivate *priv; LineInfo *info; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); g_return_if_fail(line > 0); g_return_if_fail(line <= graph->priv->lines->len); priv = graph->priv; info = &g_array_index(graph->priv->lines, LineInfo, line - 1); info->width = width; uber_graph_redraw(UBER_GRAPH(graph)); }
/** * uber_line_graph_color: * @graph: A #UberLineGraph. * * XXX * * Returns: None. * Side effects: None. */ static void uber_line_graph_color_changed (UberLabel *label, /* IN */ GdkColor *color, /* IN */ UberLineGraph *graph) /* IN */ { UberLineGraphPrivate *priv; LineInfo *info; gint i; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); g_return_if_fail(color != NULL); priv = graph->priv; for (i = 0; i < priv->lines->len; i++) { info = &g_array_index(priv->lines, LineInfo, i); if (info->label == label) { info->color = *color; } } uber_graph_redraw(UBER_GRAPH(graph)); }
/** * uber_line_graph_render: * @graph: A #UberGraph. * @cr: A #cairo_t context. * @area: Full area to render contents within. * @line: The line to render. * * Render a particular line to the graph. * * Returns: None. * Side effects: None. */ static void uber_line_graph_render_line (UberLineGraph *graph, /* IN */ cairo_t *cr, /* IN */ GdkRectangle *area, /* IN */ LineInfo *line, /* IN */ guint epoch, /* IN */ gfloat each) /* IN */ { UberLineGraphPrivate *priv; UberRange pixel_range; GdkRectangle vis; guint x; guint last_x; gdouble y; gdouble last_y; gdouble val; gint i; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); priv = graph->priv; uber_graph_get_content_area(UBER_GRAPH(graph), &vis); pixel_range.begin = area->y + 1; pixel_range.end = area->y + area->height; pixel_range.range = pixel_range.end - pixel_range.begin; /* * Prepare cairo settings. */ uber_line_graph_stylize_line(graph, line, cr); /* * Force a new path. */ cairo_new_path(cr); /* * Draw the line contents as bezier curves. */ for (i = 0; i < line->raw_data->len; i++) { /* * Retrieve data point. */ val = g_ring_get_index(line->raw_data, gdouble, i); /* * Once we get to -INFINITY, we must be at the end of the data * sequence. This may not always be true in the future. */ if (val == -INFINITY) { break; } /* * Translate value to coordinate system. */ if (!priv->scale(&priv->range, &pixel_range, &val, priv->scale_data)) { break; } /* * Calculate X/Y coordinate. */ y = (gint)(RECT_BOTTOM(*area) - val) - .5; x = epoch - (each * i); if (i == 0) { /* * Just move to the right position on first entry. */ cairo_move_to(cr, x, y); goto next; } else { /* * Draw curve to data point using the last X/Y positions as * control points. */ cairo_curve_to(cr, last_x - (each / 2.), last_y, last_x - (each / 2.), y, x, y); } next: last_y = y; last_x = x; } /* * Stroke the line content. */ cairo_stroke(cr); }
gint main (gint argc, /* IN */ gchar *argv[]) /* IN */ { gdouble dashes[] = { 1.0, 4.0 }; UberRange cpu_range = { 0., 100., 100. }; UberRange net_range = { 0., 512., 512. }; UberRange ui_range = { 0., 10., 10. }; GtkWidget *window; GtkWidget *cpu; GtkWidget *net; GtkWidget *line; GtkWidget *map; GtkWidget *scatter; GtkWidget *label; GtkAccelGroup *ag; GdkColor color; gint lineno; gint nprocs; gint i; gint mod; g_thread_init(NULL); gtk_init(&argc, &argv); nprocs = get_nprocs(); /* * Check for blktrace hack. */ if (argc > 1 && (g_strcmp0(argv[1], "--i-can-haz-blktrace") == 0)) { want_blktrace = TRUE; } /* * Warm up differential samplers. */ smon_next_cpu_info(); smon_next_cpu_freq_info(); if (want_blktrace) { uber_blktrace_init(); } /* * Install event hook to track how many X events we are doing. */ gdk_event_handler_set(smon_gdk_event_hook, NULL, NULL); /* * Create window and graphs. */ window = uber_window_new(); cpu = uber_line_graph_new(); net = uber_line_graph_new(); line = uber_line_graph_new(); map = uber_heat_map_new(); scatter = uber_scatter_new(); /* * Configure CPU graph. */ uber_line_graph_set_autoscale(UBER_LINE_GRAPH(cpu), FALSE); uber_graph_set_format(UBER_GRAPH(cpu), UBER_GRAPH_FORMAT_PERCENT); uber_line_graph_set_range(UBER_LINE_GRAPH(cpu), &cpu_range); uber_line_graph_set_data_func(UBER_LINE_GRAPH(cpu), smon_get_cpu_info, NULL, NULL); for (i = 0; i < nprocs; i++) { mod = i % G_N_ELEMENTS(default_colors); gdk_color_parse(default_colors[mod], &color); label = uber_label_new(); uber_label_set_color(UBER_LABEL(label), &color); uber_line_graph_add_line(UBER_LINE_GRAPH(cpu), &color, UBER_LABEL(label)); cpu_info.labels[i] = label; /* * XXX: Add the line regardless. Just dont populate it if we don't * have data. */ lineno = uber_line_graph_add_line(UBER_LINE_GRAPH(cpu), &color, NULL); if (smon_cpu_has_freq_scaling(i)) { uber_line_graph_set_line_dash(UBER_LINE_GRAPH(cpu), lineno, dashes, G_N_ELEMENTS(dashes), 0); uber_line_graph_set_line_alpha(UBER_LINE_GRAPH(cpu), lineno, 1.); } } /* * Add lines for GDK/X events. */ uber_line_graph_set_range(UBER_LINE_GRAPH(line), &ui_range); label = uber_label_new(); uber_label_set_text(UBER_LABEL(label), "GDK Events"); gdk_color_parse("#729fcf", &color); uber_line_graph_add_line(UBER_LINE_GRAPH(line), &color, UBER_LABEL(label)); label = uber_label_new(); uber_label_set_text(UBER_LABEL(label), "X Events"); gdk_color_parse("#a40000", &color); uber_line_graph_add_line(UBER_LINE_GRAPH(line), &color, UBER_LABEL(label)); uber_line_graph_set_data_func(UBER_LINE_GRAPH(line), smon_get_xevent_info, NULL, NULL); /* * Add lines for bytes in/out. */ uber_line_graph_set_range(UBER_LINE_GRAPH(net), &net_range); uber_line_graph_set_data_func(UBER_LINE_GRAPH(net), smon_get_net_info, NULL, NULL); uber_graph_set_format(UBER_GRAPH(net), UBER_GRAPH_FORMAT_DIRECT1024); label = uber_label_new(); uber_label_set_text(UBER_LABEL(label), "Bytes In"); gdk_color_parse("#a40000", &color); uber_line_graph_add_line(UBER_LINE_GRAPH(net), &color, UBER_LABEL(label)); label = uber_label_new(); uber_label_set_text(UBER_LABEL(label), "Bytes Out"); gdk_color_parse("#4e9a06", &color); uber_line_graph_add_line(UBER_LINE_GRAPH(net), &color, UBER_LABEL(label)); /* * Configure heat map. */ uber_graph_set_show_ylines(UBER_GRAPH(map), FALSE); gdk_color_parse(default_colors[0], &color); uber_heat_map_set_fg_color(UBER_HEAT_MAP(map), &color); uber_heat_map_set_data_func(UBER_HEAT_MAP(map), (UberHeatMapFunc)dummy_scatter_func, NULL, NULL); uber_window_add_graph(UBER_WINDOW(window), UBER_GRAPH(map), "IO Latency"); uber_graph_set_show_xlabels(UBER_GRAPH(map), FALSE); gtk_widget_show(map); /* * Configure scatter. */ if (want_blktrace) { uber_graph_set_show_ylines(UBER_GRAPH(scatter), FALSE); gdk_color_parse(default_colors[3], &color); uber_scatter_set_fg_color(UBER_SCATTER(scatter), &color); uber_scatter_set_data_func(UBER_SCATTER(scatter), (UberScatterFunc)uber_blktrace_get, NULL, NULL); uber_window_add_graph(UBER_WINDOW(window), UBER_GRAPH(scatter), "IOPS By Size"); uber_graph_set_show_xlabels(UBER_GRAPH(scatter), TRUE); gtk_widget_show(scatter); } /* * Add graphs. */ uber_window_add_graph(UBER_WINDOW(window), UBER_GRAPH(cpu), "CPU"); uber_window_add_graph(UBER_WINDOW(window), UBER_GRAPH(net), "Network"); uber_window_add_graph(UBER_WINDOW(window), UBER_GRAPH(line), "UI Events"); /* * Disable X tick labels by default (except last). */ uber_graph_set_show_xlabels(UBER_GRAPH(cpu), FALSE); uber_graph_set_show_xlabels(UBER_GRAPH(net), FALSE); uber_graph_set_show_xlabels(UBER_GRAPH(line), FALSE); /* * Show widgets. */ gtk_widget_show(net); gtk_widget_show(line); gtk_widget_show(cpu); gtk_widget_show(window); /* * Show cpu labels by default. */ uber_window_show_labels(UBER_WINDOW(window), UBER_GRAPH(cpu)); /* * Setup accelerators. */ ag = gtk_accel_group_new(); gtk_accel_group_connect(ag, GDK_KEY_w, GDK_CONTROL_MASK, GTK_ACCEL_MASK, g_cclosure_new(gtk_main_quit, NULL, NULL)); gtk_window_add_accel_group(GTK_WINDOW(window), ag); /* * Attach signals. */ g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL); /* * Start sampling thread. */ g_thread_create((GThreadFunc)sample_thread, NULL, FALSE, NULL); gtk_main(); /* * Cleanup after blktrace. */ if (want_blktrace) { uber_blktrace_shutdown(); } return EXIT_SUCCESS; }