]> granicus.if.org Git - sysstat/commitdiff
SVG: Add SVG output for disk statistics
authorSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 17 Jun 2016 13:13:27 +0000 (15:13 +0200)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 17 Jun 2016 13:13:27 +0000 (15:13 +0200)
These graphs correspond to the output of "sar -d".

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

index 1cc589f6d943093bac77efd9161e4a6b53b37ebf..558cb8d9d94090b1c4c0d30fee800d04c91bf1b8 100644 (file)
@@ -413,7 +413,7 @@ struct activity serial_act = {
 /* Block devices activity */
 struct activity disk_act = {
        .id             = A_DISK,
-       .options        = AO_NULL,
+       .options        = AO_GRAPH_PER_ITEM,
        .magic          = ACTIVITY_MAGIC_BASE + 1,
        .group          = G_DISK,
 #ifdef SOURCE_SADC
@@ -429,9 +429,10 @@ struct activity disk_act = {
        .f_render       = render_disk_stats,
        .f_xml_print    = xml_print_disk_stats,
        .f_json_print   = json_print_disk_stats,
+       .f_svg_print    = svg_print_disk_stats,
        .hdr_line       = "DEV;tps;rd_sec/s;wr_sec/s;avgrq-sz;avgqu-sz;await;svctm;%util",
        .name           = "A_DISK",
-       .g_nr           = 0,
+       .g_nr           = 5,
 #endif
        .nr             = -1,
        .nr2            = 1,
index f873f7389bffe9440ba822117c5ab7c71d797807..cf39a44c77de13c80f45dc7a4f3d31a2413e2309 100644 (file)
@@ -1786,6 +1786,247 @@ __print_funct_t svg_print_queue_stats(struct activity *a, int curr, int action,
        }
 }
 
+/*
+ ***************************************************************************
+ * Display disk 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 time used for the X axis origin
+ *             (@ust_time_ref).
+ * @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_disk_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
+                                    unsigned long long itv, struct record_header *record_hdr)
+{
+       struct stats_disk *sdc, *sdp;
+       struct ext_disk_stats xds;
+       int group1[] = {1, 2, 2, 2};
+       int group2[] = {1};
+       char *title1[] = {"Disk statistics (1)", "Disk statistics (2)",
+                         "Disk statistics (3)", "Disk statistics (4)"};
+       char *title2[] = {"Disk statistics (5)"};
+       char *g_title1[] = {"tps",
+                           "rd_sec/s", "wr_sec/s",
+                           "avgrq-sz", "avgqu-sz",
+                           "await", "svctm"};
+       char *g_title2[] = {"%util"};
+       static double *spmin, *spmax;
+       static char **out;
+       static int *outsize;
+       char *item_name, *persist_dev_name;
+       double aqusz;
+       int i, j, k, pos, restart, *unregistered;
+
+       if (action & F_BEGIN) {
+               /*
+                * Allocate arrays (#0..7) that will contain the graphs data
+                * and the min/max values.
+                * Also allocate one additional array (#8) for each disk device:
+                * spmax + 8 will contain the device major number,
+                * spmin + 8 will contain the device minor number,
+                * outsize + 8 will contain a positive value (TRUE) if the device
+                * has either still not been registered, or has been unregistered.
+                */
+               out = allocate_graph_lines(9 * a->nr, &outsize, &spmin, &spmax);
+       }
+
+       if (action & F_MAIN) {
+               restart = svg_p->restart;
+               /*
+                * Mark previously registered devices as now
+                * possibly unregistered for all graphs.
+                */
+               for (k = 0; k < a->nr; k++) {
+                       unregistered = outsize + k * 9 + 8;
+                       if (*unregistered == FALSE) {
+                               *unregistered = MAYBE;
+                       }
+               }
+
+               /* For each device structure */
+               for (i = 0; i < a->nr; i++) {
+                       sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
+                       if (!(sdc->major + sdc->minor))
+                               /* Empty structure: Ignore it */
+                               continue;
+
+                       /* Look for corresponding graph */
+                       for (k = 0; k < a->nr; k++) {
+                               if ((sdc->major == *(spmax + k * 9 + 8)) &&
+                                   (sdc->minor == *(spmin + k * 9 + 8)))
+                                       /* Graph found! */
+                                       break;
+                       }
+                       if (k == a->nr) {
+                               /* Graph not found: Look for first free entry */
+                               for (k = 0; k < a->nr; k++) {
+                                       if (*(spmax + k * 9 + 8) == -DBL_MAX)
+                                               break;
+                               }
+                               if (k == a->nr)
+                                       /* No free graph entry: Graph for this item won't be drawn */
+                                       continue;
+                       }
+                       pos = k * 9;
+                       unregistered = outsize + pos + 8;
+
+                       j = check_disk_reg(a, curr, !curr, i);
+                       sdp = (struct stats_disk *) ((char *) a->buf[!curr] + j * a->msize);
+
+                       /*
+                        * If current device was marked as previously unregistered,
+                        * then set restart variable to TRUE so that the graph will be
+                        * discontinuous, and mark it as now registered.
+                        */
+                       if (*unregistered == TRUE) {
+                               restart = TRUE;
+                       }
+                       *unregistered = FALSE;
+
+                       if (*(spmax + pos + 8) == -DBL_MAX) {
+                               /* Save device major and minor numbers (if not already done) */
+                               *(spmax + pos + 8) = sdc->major;
+                               *(spmin + pos + 8) = sdc->minor;
+                       }
+
+                       /* Check for min/max values */
+                       save_extrema(1, 2, 0, (void *) sdc, (void *) sdp,
+                                    itv, spmin + pos, spmax + pos);
+
+                       compute_ext_disk_stats(sdc, sdp, itv, &xds);
+                       if (xds.arqsz < *(spmin + pos + 3)) {
+                               *(spmin + pos + 3) = xds.arqsz;
+                       }
+                       if (xds.arqsz > *(spmax + pos + 3)) {
+                               *(spmax + pos + 3) = xds.arqsz;
+                       }
+                       aqusz = S_VALUE(sdp->rq_ticks, sdc->rq_ticks, itv) / 1000.0;
+                       if (aqusz < *(spmin + pos + 4)) {
+                               *(spmin + pos + 4) = aqusz;
+                       }
+                       if (aqusz > *(spmax + pos + 4)) {
+                               *(spmax + pos + 4) = aqusz;
+                       }
+                       if (xds.await < *(spmin + pos + 5)) {
+                               *(spmin + pos + 5) = xds.await;
+                       }
+                       if (xds.await > *(spmax + pos + 5)) {
+                               *(spmax + pos + 5) = xds.await;
+                       }
+                       if (xds.svctm < *(spmin + pos + 6)) {
+                               *(spmin + pos + 6) = xds.svctm;
+                       }
+                       if (xds.svctm > *(spmax + pos + 6)) {
+                               *(spmax + pos + 6) = xds.svctm;
+                       }
+                       if ((xds.util / 10.0) < *(spmin + pos + 7)) {
+                               *(spmin + pos + 7) = xds.util / 10.0;
+                       }
+                       if ((xds.util / 10.0) > *(spmax + pos + 7)) {
+                               *(spmax + pos + 7) = xds.util / 10.0;
+                       }
+
+                       /* tps */
+                       lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
+                                S_VALUE(sdp->nr_ios, sdc->nr_ios, itv),
+                                out + pos, outsize + pos, restart);
+
+                       /* rd_sec/s */
+                       lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
+                                S_VALUE(sdp->rd_sect, sdc->rd_sect, itv),
+                                out + pos + 1, outsize + pos + 1, restart);
+
+                       /* wr_sec/s */
+                       lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
+                                S_VALUE(sdp->wr_sect, sdc->wr_sect, itv),
+                                out + pos + 2, outsize + pos + 2, restart);
+
+                       /* avgrq-sz */
+                       lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
+                                xds.arqsz,
+                                out + pos + 3, outsize + pos + 3, restart);
+
+                       /* avgqu-sz */
+                       lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
+                                aqusz,
+                                out + pos + 4, outsize + pos + 4, restart);
+
+                       /* await */
+                       lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
+                                xds.await,
+                                out + pos + 5, outsize + pos + 5, restart);
+
+                       /* svctm */
+                       lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
+                                xds.svctm,
+                                out + pos + 6, outsize + pos + 6, restart);
+
+                       /* %util */
+                       brappend(record_hdr->ust_time - svg_p->ust_time_ref,
+                                0.0, xds.util / 10.0,
+                                out + pos + 7, outsize + pos + 7, svg_p->dt);
+               }
+
+               /* Mark devices not seen here as now unregistered */
+               for (k = 0; k < a->nr; k++) {
+                       unregistered = outsize + k * 9 + 8;
+                       if (*unregistered != FALSE) {
+                               *unregistered = TRUE;
+                       }
+               }
+       }
+
+       if (action & F_END) {
+               for (i = 0; i < a->nr; i++) {
+                       /* Check if there is something to display */
+                       pos = i * 9;
+                       if (!**(out + pos))
+                               continue;
+
+                       item_name = NULL;
+                       persist_dev_name = NULL;
+
+                       if (DISPLAY_PERSIST_NAME_S(flags)) {
+                               persist_dev_name = get_persistent_name_from_pretty(get_devname(*(spmax + pos + 8),
+                                                                                              *(spmin + pos + 8),
+                                                                                              TRUE));
+                       }
+                       if (persist_dev_name) {
+                               item_name = persist_dev_name;
+                       }
+                       else {
+                               if ((USE_PRETTY_OPTION(flags)) && (*(spmax + pos + 8) == dm_major)) {
+                                       item_name = transform_devmapname(*(spmax + pos + 8), *(spmin + pos + 8));
+                               }
+
+                               if (!item_name) {
+                                       item_name = get_devname(*(spmax + pos + 8), *(spmin + pos + 8),
+                                                               USE_PRETTY_OPTION(flags));
+                               }
+                       }
+
+                       draw_activity_graphs(a->g_nr - 1, SVG_LINE_GRAPH,
+                                            title1, g_title1, item_name, group1,
+                                            spmin + pos, spmax + pos, out + pos, outsize + pos,
+                                            svg_p, record_hdr);
+                       draw_activity_graphs(1, SVG_BAR_GRAPH,
+                                            title2, g_title2, item_name, group2,
+                                            spmin + pos + 7, spmax + pos + 7, out + pos + 7, outsize + pos + 7,
+                                            svg_p, record_hdr);
+               }
+
+               /* Free remaining structures */
+               free_graphs(out, outsize, spmin, spmax);
+       }
+}
+
 /*
  ***************************************************************************
  * Display network interfaces statistics in SVG.
index d9a906668402b14584d7e0a3f6e50f292ee7fe17..cc344a04bc8d6ce30de6c372f342cf84dd750522 100644 (file)
@@ -38,6 +38,9 @@ __print_funct_t svg_print_ktables_stats
 __print_funct_t svg_print_queue_stats
        (struct activity *, int, int, struct svg_parm *, unsigned long long,
         struct record_header *);
+__print_funct_t svg_print_disk_stats
+       (struct activity *, int, int, struct svg_parm *, unsigned long long,
+        struct record_header *);
 __print_funct_t svg_print_net_dev_stats
        (struct activity *, int, int, struct svg_parm *, unsigned long long,
         struct record_header *);