]> granicus.if.org Git - sysstat/commitdiff
SVG: Add SVG output for CPU frequency statistics
authorSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 25 Mar 2016 13:33:59 +0000 (14:33 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 25 Mar 2016 13:33:59 +0000 (14:33 +0100)
This graph corresponds to the output of "sar -m CPU".
This is a new kind of graph ("rectangular").

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
activity.c
svg_stats.c
svg_stats.h

index b346b3ec241a60bbc228ad1b85e150d78546d577..df5f9d8f0d46af3c05c1e7ea72c6ce986b4ce6d1 100644 (file)
@@ -1046,7 +1046,7 @@ struct activity net_udp6_act = {
 /* CPU frequency */
 struct activity pwr_cpufreq_act = {
        .id             = A_PWR_CPUFREQ,
-       .options        = AO_VOLATILE,
+       .options        = AO_VOLATILE + AO_GRAPH_PER_ITEM,
        .magic          = ACTIVITY_MAGIC_BASE,
        .group          = G_POWER,
 #ifdef SOURCE_SADC
@@ -1062,9 +1062,10 @@ struct activity pwr_cpufreq_act = {
        .f_render       = render_pwr_cpufreq_stats,
        .f_xml_print    = xml_print_pwr_cpufreq_stats,
        .f_json_print   = json_print_pwr_cpufreq_stats,
+       .f_svg_print    = svg_print_pwr_cpufreq_stats,
        .hdr_line       = "CPU;MHz",
        .name           = "A_PWR_CPUFREQ",
-       .g_nr           = 0,
+       .g_nr           = 1,
 #endif
        .nr             = -1,
        .nr2            = 1,
index 3a7337718deb844b9a17952d632bcdb7fb1963c4..53d76a08b28de525816f8bc96958a49ae60a5cf0 100644 (file)
@@ -385,6 +385,61 @@ void cpuappend(unsigned long timetag, double *offset, double value, char **out,
        *offset += value;
 }
 
+/*
+ ***************************************************************************
+ * Update rectangular graph and min/max values.
+ *
+ * IN:
+ * @timetag    Timestamp in seconds since the epoch for current sample
+ *             stats. Will be used as X coordinate.
+ * @p_value    Metric value for previous sample
+ * @value      Metric value for current sample.
+ * @out                Pointer on array of chars for current graph definition.
+ * @outsize    Size of array of chars for current graph definition.
+ * @restart    Set to TRUE if a RESTART record has been read since the last
+ *             statistics sample.
+ * @dt         Interval of time in seconds between current and previous
+ *             sample.
+ * @spmin      Min value already found for this metric.
+ * @spmax      Max value already found for this metric.
+ *
+ * OUT:
+ * @out                Pointer on array of chars for current graph definition that
+ *             has been updated with the addition of current sample data.
+ * @outsize    Array that containing the (possibly new) sizes of each
+ *             element in array of chars.
+ * @spmin      Min value for this metric.
+ * @spmax      Max value for this metric.
+ ***************************************************************************
+ */
+void recappend(unsigned long timetag, double p_value, double value, char **out, int *outsize,
+              int restart, unsigned long dt, double *spmin, double *spmax)
+{
+       char data[128], data1[128], data2[128];
+
+       /* Save min and max values */
+       if (value < *spmin) {
+               *spmin = value;
+       }
+       if (value > *spmax) {
+               *spmax = value;
+       }
+       /* Prepare additional graph definition data */
+       if (restart) {
+               snprintf(data1, 128, " M%lu,%.2f", timetag - dt, p_value);
+               data1[127] = '\0';
+       }
+       if (p_value != value) {
+               snprintf(data2, 128, " L%lu,%.2f", timetag, value);
+               data2[127] = '\0';
+       }
+       snprintf(data, 128, "%s L%lu,%.2f%s", restart ? data1 : "", timetag, p_value,
+                p_value != value ? data2 : "");
+       data[127] = '\0';
+
+       save_svg_data(data, out, outsize);
+}
+
 /*
  ***************************************************************************
  * Calculate the value on the Y axis between two horizontal lines that will
@@ -1328,3 +1383,88 @@ __print_funct_t svg_print_net_dev_stats(struct activity *a, int curr, int action
                free_graphs(out, outsize, spmin, spmax);
        }
 }
+
+/*
+ ***************************************************************************
+ * Display CPU frequency statistics in SVG.
+ *
+ * IN:
+ * @a          Activity structure with statistics.
+ * @curr       Index in array for current sample statistics.
+ * @action     Action expected from current function.
+ * @svg_p      SVG specific parameters: Current graph number (.@graph_no),
+ *             flag indicating that a restart record has been previously
+ *             found (.@restart) and a pointer on a record header structure
+ *             (.@record_hdr) containing the first stats sample.
+ * @itv                Interval of time in jiffies (only with F_MAIN action).
+ * @record_hdr Pointer on record header of current stats sample.
+ ***************************************************************************
+ */
+__print_funct_t svg_print_pwr_cpufreq_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
+                                           unsigned long long g_itv, struct record_header *record_hdr)
+{
+       struct stats_pwr_cpufreq *spc, *spp;
+       int group[] = {1};
+       char *title[] = {"CPU frequency"};
+       char *g_title[] = {"MHz"};
+       static double *spmin, *spmax;
+       static char **out;
+       static int *outsize;
+       char item_name[8];
+       int i;
+
+       if (action & F_BEGIN) {
+               /*
+                * Allocate arrays that will contain the graphs data
+                * and the min/max values.
+                */
+               out = allocate_graph_lines(a->nr, &outsize, &spmin, &spmax);
+       }
+
+       if (action & F_MAIN) {
+               /* For each CPU */
+               for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+
+                       spc = (struct stats_pwr_cpufreq *) ((char *) a->buf[curr]  + i * a->msize);
+                       spp = (struct stats_pwr_cpufreq *) ((char *) a->buf[!curr]  + i * a->msize);
+
+                       /* Should current CPU (including CPU "all") be displayed? */
+                       if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
+                               /* No */
+                               continue;
+
+                       /* MHz */
+                       recappend(record_hdr->ust_time - svg_p->record_hdr->ust_time,
+                                 ((double) spp->cpufreq) / 100,
+                                 ((double) spc->cpufreq) / 100,
+                                 out + i, outsize + i, svg_p->restart, svg_p->dt,
+                                 spmin + i, spmax + i);
+               }
+       }
+
+       if (action & F_END) {
+               for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+
+                       /* Should current CPU (including CPU "all") be displayed? */
+                       if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
+                               /* No */
+                               continue;
+
+                       if (!i) {
+                               /* This is CPU "all" */
+                               strcpy(item_name, "all");
+                       }
+                       else {
+                               sprintf(item_name, "%d", i - 1);
+                       }
+
+                       draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH,
+                                            title, g_title, item_name, group,
+                                            spmin + i, spmax + i, out + i, outsize + i,
+                                            svg_p, record_hdr);
+               }
+
+               /* Free remaining structures */
+               free_graphs(out, outsize, spmin, spmax);
+       }
+}
index b0e84b267586cd3e51373c57a21f4adb1d15c88b..df19378130691aac0e4cb8a464c8e6315e8b5cbb 100644 (file)
@@ -29,5 +29,8 @@ __print_funct_t svg_print_paging_stats
 __print_funct_t svg_print_net_dev_stats
        (struct activity *, int, int, struct svg_parm *, unsigned long long,
         struct record_header *);
+__print_funct_t svg_print_pwr_cpufreq_stats
+       (struct activity *, int, int, struct svg_parm *, unsigned long long,
+        struct record_header *);
        
 #endif /* _SVG_STATS_H */