/** * uber_line_graph_get_next_data: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static gboolean uber_line_graph_get_next_data (UberGraph *graph) /* IN */ { UberLineGraphPrivate *priv; LineInfo *line; gdouble val; gboolean ret = FALSE; gint i; g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), FALSE); priv = UBER_LINE_GRAPH(graph)->priv; /* * Retrieve the next data point. */ if (priv->func) { for (i = 0; i < priv->lines->len; i++) { val = 0.; line = &g_array_index(priv->lines, LineInfo, i); if (!(ret = priv->func(UBER_LINE_GRAPH(graph), i + 1, &val, priv->func_data))) { val = -INFINITY; } g_ring_append_val(line->raw_data, val); /* * TODO: Scale value. */ g_ring_append_val(line->scaled_data, val); } } return ret; }
/** * uber_line_graph_set_stride: * @graph: A #UberGraph. * @stride: The number of data points within the graph. * * XXX * * Returns: None. * Side effects: None. */ static void uber_line_graph_set_stride (UberGraph *graph, /* IN */ guint stride) /* IN */ { UberLineGraphPrivate *priv; LineInfo *line; gint i; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); priv = UBER_LINE_GRAPH(graph)->priv; priv->stride = stride; /* * TODO: Support changing stride after lines have been added. */ if (priv->lines->len) { for (i = 0; i < priv->lines->len; i++) { line = &g_array_index(priv->lines, LineInfo, i); g_ring_unref(line->raw_data); g_ring_unref(line->scaled_data); line->raw_data = g_ring_sized_new(sizeof(gdouble), priv->stride, NULL); line->scaled_data = g_ring_sized_new(sizeof(gdouble), priv->stride, NULL); uber_line_graph_init_ring(line->raw_data); uber_line_graph_init_ring(line->scaled_data); } return; } }
/** * uber_line_graph_get_next_data: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static gboolean uber_line_graph_get_next_data (UberGraph *graph) /* IN */ { UberLineGraphPrivate *priv; gboolean scale_changed = FALSE; gboolean ret = FALSE; LineInfo *line; gdouble val; gint i; g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), FALSE); priv = UBER_LINE_GRAPH(graph)->priv; /* * Retrieve the next data point. */ if (priv->func) { for (i = 0; i < priv->lines->len; i++) { val = 0.; line = &g_array_index(priv->lines, LineInfo, i); if (!(ret = priv->func(UBER_LINE_GRAPH(graph), i + 1, &val, priv->func_data))) { val = -INFINITY; } g_ring_append_val(line->raw_data, val); if (priv->autoscale) { if (val < priv->range.begin) { priv->range.begin = val - (val * SCALE_FACTOR); priv->range.range = priv->range.end - priv->range.begin; scale_changed = TRUE; } else if (val > priv->range.end) { priv->range.end = val + (val * SCALE_FACTOR); priv->range.range = priv->range.end - priv->range.begin; scale_changed = TRUE; } } } } if (scale_changed) { uber_graph_scale_changed(graph); } return ret; }
/** * uber_line_graph_render: * @graph: A #UberGraph. * * Render the entire contents of the graph. * * Returns: None. * Side effects: None. */ static void uber_line_graph_render (UberGraph *graph, /* IN */ cairo_t *cr, /* IN */ GdkRectangle *rect) /* IN */ { UberLineGraphPrivate *priv; LineInfo *line; gint i; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); priv = UBER_LINE_GRAPH(graph)->priv; /* * Render each line to the graph. */ for (i = 0; i < priv->lines->len; i++) { line = &g_array_index(priv->lines, LineInfo, i); uber_line_graph_render_line(UBER_LINE_GRAPH(graph), cr, rect, line); } }
/** * uber_line_graph_get_yrange: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static void uber_line_graph_get_yrange (UberGraph *graph, /* IN */ UberRange *range) /* OUT */ { UberLineGraphPrivate *priv; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); g_return_if_fail(range != NULL); priv = UBER_LINE_GRAPH(graph)->priv; *range = priv->range; }
/** * uber_line_graph_finalize: * @object: A #UberLineGraph. * * Finalizer for a #UberLineGraph instance. Frees any resources held by * the instance. * * Returns: None. * Side effects: None. */ static void uber_line_graph_finalize (GObject *object) /* IN */ { UberLineGraphPrivate *priv; LineInfo *line; gint i; priv = UBER_LINE_GRAPH(object)->priv; /* * Clean up after cached values. */ for (i = 0; i < priv->lines->len; i++) { line = &g_array_index(priv->lines, LineInfo, i); g_ring_unref(line->raw_data); g_ring_unref(line->scaled_data); } G_OBJECT_CLASS(uber_line_graph_parent_class)->finalize(object); }
/** * uber_line_graph_set_property: * @object: (in): A #GObject. * @prop_id: (in): The property identifier. * @value: (in): The given property. * @pspec: (in): A #ParamSpec. * * Set a given #GObject property. */ static void uber_line_graph_set_property (GObject *object, /* IN */ guint prop_id, /* IN */ const GValue *value, /* IN */ GParamSpec *pspec) /* IN */ { UberLineGraph *graph = UBER_LINE_GRAPH(object); switch (prop_id) { case PROP_AUTOSCALE: uber_line_graph_set_autoscale(graph, g_value_get_boolean(value)); break; case PROP_RANGE: uber_line_graph_set_range(graph, g_value_get_boxed(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } }
/** * uber_line_graph_downscale: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static gboolean uber_line_graph_downscale (UberGraph *graph) /* IN */ { UberLineGraphPrivate *priv; gboolean ret = FALSE; gdouble val = 0; gdouble cur; LineInfo *line; gint i; gint j; g_return_val_if_fail(UBER_IS_LINE_GRAPH(graph), FALSE); priv = UBER_LINE_GRAPH(graph)->priv; /* * If we are set to autoscale, ignore request. */ if (!priv->autoscale) { return FALSE; } /* * Determine the largest value available. */ for (i = 0; i < priv->lines->len; i++) { line = &g_array_index(priv->lines, LineInfo, i); for (j = 0; j < line->raw_data->len; j++) { cur = g_ring_get_index(line->raw_data, gdouble, j); val = (cur > val) ? cur : val; } } /* * Downscale if we can. */ if (val != priv->range.begin) { if ((val * (1. + SCALE_FACTOR)) < priv->range.end) { priv->range.end = val * (1. + SCALE_FACTOR); priv->range.range = priv->range.end - priv->range.begin; ret = TRUE; } } return ret; }
/** * uber_line_graph_render_fast: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static void uber_line_graph_render_fast (UberGraph *graph, /* IN */ cairo_t *cr, /* IN */ GdkRectangle *rect, /* IN */ guint epoch, /* IN */ gfloat each) /* IN */ { UberLineGraphPrivate *priv; LineInfo *line; gdouble last_y; gdouble y; gint i; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); g_return_if_fail(cr != NULL); g_return_if_fail(rect != NULL); priv = UBER_LINE_GRAPH(graph)->priv; /* * Prepare cairo line styling. */ cairo_set_line_width(cr, 1.0); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT); /* * Render most recent data point for each line. */ for (i = 0; i < priv->lines->len; i++) { line = &g_array_index(priv->lines, LineInfo, i); gdk_cairo_set_source_color(cr, &line->color); /* * Calculate positions. */ y = g_ring_get_index(line->scaled_data, gdouble, 0); last_y = g_ring_get_index(line->scaled_data, gdouble, 1); /* * Don't try to draw before we have real values. */ if ((isnan(y) || isinf(y)) || (isnan(last_y) || isinf(last_y))) { continue; } /* * Translate position from bottom right corner. */ y = RECT_BOTTOM(*rect) - y; last_y = RECT_BOTTOM(*rect) - last_y; /* * Convert relative position to fixed from bottom pixel. */ cairo_new_path(cr); cairo_move_to(cr, epoch, y); cairo_curve_to(cr, epoch - (each / 2.), y, epoch - (each / 2.), last_y, epoch - each, last_y); cairo_stroke(cr); } }
/** * uber_line_graph_render_fast: * @graph: A #UberGraph. * * XXX * * Returns: None. * Side effects: None. */ static void uber_line_graph_render_fast (UberGraph *graph, /* IN */ cairo_t *cr, /* IN */ GdkRectangle *rect, /* IN */ guint epoch, /* IN */ gfloat each) /* IN */ { UberLineGraphPrivate *priv; UberRange pixel_range; LineInfo *line; gdouble last_y; gdouble y; gint i; g_return_if_fail(UBER_IS_LINE_GRAPH(graph)); g_return_if_fail(cr != NULL); g_return_if_fail(rect != NULL); priv = UBER_LINE_GRAPH(graph)->priv; pixel_range.begin = rect->y + 1; pixel_range.end = rect->y + rect->height; pixel_range.range = pixel_range.end - pixel_range.begin; /* * Render most recent data point for each line. */ for (i = 0; i < priv->lines->len; i++) { line = &g_array_index(priv->lines, LineInfo, i); uber_line_graph_stylize_line(UBER_LINE_GRAPH(graph), line, cr); /* * Calculate positions. */ y = g_ring_get_index(line->raw_data, gdouble, 0); last_y = g_ring_get_index(line->raw_data, gdouble, 1); /* * Don't try to draw before we have real values. */ if ((isnan(y) || isinf(y)) || (isnan(last_y) || isinf(last_y))) { continue; } /* * Translate to coordinate scale. */ if (!priv->scale(&priv->range, &pixel_range, &y, priv->scale_data) || !priv->scale(&priv->range, &pixel_range, &last_y, priv->scale_data)) { continue; } /* * Translate position from bottom right corner. */ y = (gint)(RECT_BOTTOM(*rect) - y) - .5; last_y = (gint)(RECT_BOTTOM(*rect) - last_y) - .5; /* * Convert relative position to fixed from bottom pixel. */ cairo_new_path(cr); cairo_move_to(cr, epoch, y); cairo_curve_to(cr, epoch - (each / 2.), y, epoch - (each / 2.), last_y, epoch - each, last_y); 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; }