]> granicus.if.org Git - sysstat/commitdiff
Close #138: SVG: Allow multiple charts on a row
authorSebastien GODARD <sysstat@users.noreply.github.com>
Sun, 5 Feb 2017 09:07:10 +0000 (10:07 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Sun, 5 Feb 2017 09:07:10 +0000 (10:07 +0100)
Add a new option ("packed") to tell sadf to put multiple charts on a row
when generating SVG graphs.
In fact, with this option, all charts from the same activity (and for
the same device) will appear on the same row.

E.g.: sadf -g -O packed sa01 -- -A > sa01.svg

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

diff --git a/sa.h b/sa.h
index 4b0224f682fa7e7c0559897de65d73b2f995f271..ddac09acd0af5d2294e405bdd0123163f159fe8c 100644 (file)
--- a/sa.h
+++ b/sa.h
 #define S_F_SVG_SHOW_IDLE      0x00080000
 #define S_F_UNIT               0x00100000
 #define S_F_SVG_HEIGHT         0x00200000
+#define S_F_SVG_PACKED         0x00400000
 
 #define WANT_SINCE_BOOT(m)             (((m) & S_F_SINCE_BOOT)   == S_F_SINCE_BOOT)
 #define WANT_SA_ROTAT(m)               (((m) & S_F_SA_ROTAT)     == S_F_SA_ROTAT)
 #define DISPLAY_IDLE(m)                        (((m) & S_F_SVG_SHOW_IDLE) == S_F_SVG_SHOW_IDLE)
 #define DISPLAY_UNIT(m)                        (((m) & S_F_UNIT) == S_F_UNIT)
 #define SET_CANVAS_HEIGHT(m)           (((m) & S_F_SVG_HEIGHT) == S_F_SVG_HEIGHT)
+#define PACK_VIEWS(m)                  (((m) & S_F_SVG_PACKED) == S_F_SVG_PACKED)
 
 #define AO_F_NULL              0x00000000
 
 #define K_SHOWIDLE     "showidle"
 #define K_SHOWHINTS    "showhints"
 #define K_HEIGHT       "height="
+#define K_PACKED       "packed"
 
 /* Groups of activities */
 #define G_DEFAULT      0x00
@@ -300,6 +303,11 @@ struct svg_parm {
        int restart;                    /* TRUE if we have just met a RESTART record */
 };
 
+/* Structure used when displaying SVG header */
+struct svg_hdr_parm {
+       int graph_nr;      /* Number of rows of views to display or canvas height entered on the command line */
+       int views_per_row; /* Maximum number of views on a single row */
+};
 
 /*
  ***************************************************************************
@@ -898,8 +906,10 @@ struct report_format {
  *   |   v   <---><------------------------------>
  *   |         6                8
  *   | Gap
- *   v<--------------------------------------------------------------->
+ *   v<---------------------------------------------------------------> Gap
  *                                    7
+ *    <--------------------------------------------------------------------->
+ *                                      8
  */
 
 /* #8 */
@@ -908,6 +918,8 @@ struct report_format {
 #define SVG_M_XSIZE    70
 /* #7 */
 #define SVG_V_XSIZE    1050
+/* #8 */
+#define SVG_T_XSIZE    1060
 
 /* #5 */
 #define SVG_G_YSIZE    200
@@ -928,6 +940,9 @@ struct report_format {
 /* Block size used to allocate arrays for graphs data */
 #define CHUNKSIZE      4096
 
+/* Maximum number of views on a single row */
+#define MAX_VIEWS_ON_A_ROW     6
+
 #define SVG_LINE_GRAPH 1
 #define SVG_BAR_GRAPH  2
 
diff --git a/sadf.c b/sadf.c
index 66ff30c81c81584a8548ec2763ae8315bcbdac9b..ff9fec3153adc92924bbbe153dc3748a38f2b3f1 100644 (file)
--- a/sadf.c
+++ b/sadf.c
@@ -418,32 +418,37 @@ time_t get_time_ref(void)
 
 /*
  ***************************************************************************
- * Compute the number of SVG graphs to display. Each activity selected may
- * have several graphs. Moreover we have to take into account volatile
- * activities (eg. CPU) for which the number of graphs will depend on the
- * highest number of items (eg. maximum number of CPU) saved in the file.
- * This number may be higher than the real number of graphs that will be
- * displayed since some items have a preallocation constant.
+ * Compute the number of rows that will contain SVG views. Usually only one
+ * view is displayed on a row, unless the "packed" option has been entered.
+ * Each activity selected may have several views. Moreover we have to take
+ * into account volatile activities (eg. CPU) for which the number of views
+ * will depend on the highest number of items (eg. maximum number of CPU)
+ * saved in the file. This number may be higher than the real number of views
+ * that will be displayed since some items have a preallocation constant.
  *
  * IN:
- * @ifd                File descriptor of input file.
- * @file       Name of file being read.
- * @file_magic file_magic structure filled with file magic header data.
- * @file_actlst        List of (known or unknown) activities in file.
- * @rectime    Structure where timestamp (expressed in local time or in UTC
- *             depending on whether options -T/-t have been used or not) can
- *             be saved for current record.
- * @loctime    Structure where timestamp (expressed in local time) can be
- *             saved for current record.
+ * @ifd                        File descriptor of input file.
+ * @file               Name of file being read.
+ * @file_magic         file_magic structure filled with file magic header data.
+ * @file_actlst                List of (known or unknown) activities in file.
+ * @rectime            Structure where timestamp (expressed in local time or
+ *                     in UTC depending on whether options -T/-t have been
+ *                     used or not) can be saved for current record.
+ * @loctime            Structure where timestamp (expressed in local time)
+ *                     can be saved for current record.
+ *
+ * OUT:
+ * @views_per_row      Maximum number of views that will be displayed on a
+ *                     single row (useful only if "packed" option entered).
  *
  * RETURNS:
- * Total number of graphs to display, taking into account only activities
+ * Number of rows containing views, taking into account only activities
  * to be displayed, and selected period of time (options -s/-e).
  ***************************************************************************
  */
 int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic,
                     struct file_activity *file_actlst, struct tm *rectime,
-                    struct tm *loctime)
+                    struct tm *loctime, int *views_per_row)
 {
        int i, n, p, eosaf;
        int rtype, new_tot_g_nr, tot_g_nr = 0;
@@ -457,7 +462,7 @@ int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic,
        }
        sr_act_nr(save_act_nr, DO_SAVE);
 
-       /* Init total number of graphs for each activity */
+       /* Init total number of views for each activity */
        for (i = 0; i < NR_ACT; i++) {
                id_g_nr[i] = 0;
        }
@@ -485,12 +490,20 @@ int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic,
                        if (!IS_SELECTED(act[p]->options))
                                continue;
 
-                       if (ONE_GRAPH_PER_ITEM(act[p]->options)) {
-                                n = act[p]->g_nr * act[p]->nr;
+                       if (PACK_VIEWS(flags)) {
+                               /* One activity = one row with multiple views */
+                               n = 1;
                        }
                        else {
+                               /* One activity = multiple rows with only one view */
                                n = act[p]->g_nr;
                        }
+                       if (ONE_GRAPH_PER_ITEM(act[p]->options)) {
+                                n = n * act[p]->nr;
+                       }
+                       if (act[p]->g_nr > *views_per_row) {
+                               *views_per_row = act[p]->g_nr;
+                       }
 
                        if (n > id_g_nr[i]) {
                                 id_g_nr[i] = n;
@@ -537,6 +550,10 @@ int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic,
        }
        sr_act_nr(save_act_nr, DO_RESTORE);
 
+       if (*views_per_row > MAX_VIEWS_ON_A_ROW) {
+               *views_per_row = MAX_VIEWS_ON_A_ROW;
+       }
+
        return tot_g_nr;
 }
 /*
@@ -1264,8 +1281,9 @@ void logic3_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_
                         struct tm *rectime, struct tm *loctime, char *file,
                         struct file_magic *file_magic)
 {
+       struct svg_hdr_parm parm;
        int i, p;
-       int curr = 1, rtype, g_nr = 0;
+       int curr = 1, rtype, g_nr = 0, views_per_row = 1;
        int eosaf = TRUE, reset = TRUE;
        long cnt = 1;
        off_t fpos;
@@ -1275,6 +1293,10 @@ void logic3_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_
        /* Use a decimal point to make SVG code locale independent */
        setlocale(LC_NUMERIC, "C");
 
+       /* Calculate the number of rows and the max number of views per row to display */
+       graph_nr = get_svg_graph_nr(ifd, file, file_magic,
+                                   file_actlst, rectime, loctime, &views_per_row);
+
        if (SET_CANVAS_HEIGHT(flags)) {
                /*
                 * Option "-O height=..." used: This is not a number
@@ -1282,19 +1304,17 @@ void logic3_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_
                 */
                graph_nr = canvas_height;
        }
-       else {
-               /* Calculate the number of graphs to display */
-               graph_nr = get_svg_graph_nr(ifd, file, file_magic,
-                                           file_actlst, rectime, loctime);
-       }
 
        if (!graph_nr)
                /* No graph to display */
                return;
 
+       parm.graph_nr = graph_nr;
+       parm.views_per_row = PACK_VIEWS(flags) ? views_per_row : 1;
+
        /* Print SVG header */
        if (*fmt[f_position]->f_header) {
-               (*fmt[f_position]->f_header)(&graph_nr, F_BEGIN + F_MAIN, file, file_magic,
+               (*fmt[f_position]->f_header)(&parm, F_BEGIN + F_MAIN, file, file_magic,
                                             &file_hdr, cpu_nr, act, id_seq);
        }
 
@@ -1523,6 +1543,9 @@ int main(int argc, char **argv)
                                        canvas_height = atoi(v);
                                        flags |= S_F_SVG_HEIGHT;
                                }
+                               else if (!strcmp(t, K_PACKED)) {
+                                       flags |= S_F_SVG_PACKED;
+                               }
                                else {
                                        usage(argv[0]);
                                }
index 4e9784143a3f236cb8700b828a8e45cb86fa7765..12e27d49ab66e5b6c40306c7bd70a235844937e5 100644 (file)
@@ -896,8 +896,9 @@ __printf_funct_t print_hdr_header(void *parm, int action, char *dfile,
  * Display the header of the report (SVG format).
  *
  * IN:
- * @parm       Specific parameter. Here: number of graphs to display or
- *             canvas height entered on the command line.
+ * @parm       Specific parameters. Here: number of rows of views to display
+ *             or canvas height entered on the command line (@graph_nr), and
+ *             max number of views on a single row (@views_per_row).
  * @action     Action expected from current function.
  * @dfile      Name of system activity data file (unused here).
  * @file_magic System activity file magic header (unused here).
@@ -912,7 +913,7 @@ __printf_funct_t print_svg_header(void *parm, int action, char *dfile,
                                  struct file_header *file_hdr, __nr_t cpu_nr,
                                  struct activity *act[], unsigned int id_seq[])
 {
-       int *graph_nr = (int *) parm;
+       struct svg_hdr_parm *hdr_parm = (struct svg_hdr_parm *) parm;
 
        if (action & F_BEGIN) {
                printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
@@ -927,9 +928,9 @@ __printf_funct_t print_svg_header(void *parm, int action, char *dfile,
        if (action & F_MAIN) {
                printf(" width=\"%d\" height=\"%d\""
                       " fill=\"black\" stroke=\"gray\" stroke-width=\"1\">\n",
-                      SVG_V_XSIZE,
-                      SET_CANVAS_HEIGHT(flags) ? *graph_nr
-                                               : SVG_H_YSIZE + SVG_T_YSIZE * (*graph_nr));
+                      SVG_T_XSIZE * (hdr_parm->views_per_row),
+                      SET_CANVAS_HEIGHT(flags) ? hdr_parm->graph_nr
+                                               : SVG_H_YSIZE + SVG_T_YSIZE * (hdr_parm->graph_nr));
                printf("<text x= \"0\" y=\"30\" text-anchor=\"start\" stroke=\"brown\">");
                print_gal_header(localtime((const time_t *) &(file_hdr->sa_ust_time)),
                                 file_hdr->sa_sysname, file_hdr->sa_release,
@@ -943,7 +944,7 @@ __printf_funct_t print_svg_header(void *parm, int action, char *dfile,
                if (!(action & F_BEGIN)) {
                        /* Give actual SVG height */
                        printf("<!-- Actual canvas height: %d -->\n",
-                              SVG_H_YSIZE + SVG_T_YSIZE * (*graph_nr));
+                              SVG_H_YSIZE + SVG_T_YSIZE * (hdr_parm->graph_nr));
                }
                printf("</svg>\n");
        }
index a0fac7560db8b540fc3b33684231bb827ce953b4..d0d941c028bad4d221ef319118a2ec29b61e3e98 100644 (file)
@@ -782,7 +782,7 @@ void skip_current_view(char **out, int *pos, int group)
  * Display all graphs for current activity.
  *
  * IN:
- * @g_nr       Number of sets of graphs (views) to display.
+ * @g_nr       Number of views to display.
  * @g_type     Type of graph (SVG_LINE_GRAPH, SVG_BAR_GRAPH) for each view.
  * @title      Titles for each set of graphs.
  * @g_title    Titles for each graph.
@@ -792,7 +792,7 @@ void skip_current_view(char **out, int *pos, int group)
  * @spmax      Array containing max values for graphs.
  * @out                Pointer on array of chars for each graph definition.
  * @outsize    Size of array of chars for each graph definition.
- * @svg_p      SVG specific parameters: Current graph number (.@graph_no),
+ * @svg_p      SVG specific parameters: Current views row number (.@graph_no),
  *             time for the first sample of stats (.@ust_time_first), and
  *             times used as start and end values on the X axis
  *             (.@ust_time_ref and .@ust_time_end).
@@ -805,7 +805,7 @@ void draw_activity_graphs(int g_nr, int g_type[], char *title[], char *g_title[]
 {
        char *out_p;
        int i, j, dp, pos = 0, views_nr = 0;
-       int v_gridnr;
+       int v_gridnr, xv, yv;
        unsigned int asfactor[16];
        long int xpos;
        double lmax, xfactor, yfactor, ypos, gmin, gmax;
@@ -816,10 +816,10 @@ void draw_activity_graphs(int g_nr, int g_type[], char *title[], char *g_title[]
               svg_p->graph_no,
               SVG_H_YSIZE + svg_p->graph_no * SVG_T_YSIZE);
 
-       /* For each set of graphs which are part of current activity */
+       /* For each view which is part of current activity */
        for (i = 0; i < g_nr; i++) {
 
-               /* Get global min and max value for current set of graphs */
+               /* Get global min and max value for current view */
                get_global_extrema(pos, group[i], spmin, spmax, &gmin, &gmax);
 
                /* Don't display empty views if requested */
@@ -830,22 +830,30 @@ void draw_activity_graphs(int g_nr, int g_type[], char *title[], char *g_title[]
                /* Increment number of views actually displayed */
                views_nr++;
 
+               /* Compute top left position of view */
+               if (PACK_VIEWS(flags)) {
+                       xv = (views_nr - 1) * SVG_T_XSIZE;
+                       yv = 0;
+               }
+               else {
+                       xv = 0;
+                       yv = (views_nr - 1) * SVG_T_YSIZE;
+               }
+
                /* Graph background */
-               printf("<rect x=\"0\" y=\"%d\" height=\"%d\" width=\"%d\"/>\n",
-                      (views_nr - 1) * SVG_T_YSIZE,
-                      SVG_V_YSIZE, SVG_V_XSIZE);
+               printf("<rect x=\"%d\" y=\"%d\" height=\"%d\" width=\"%d\"/>\n",
+                      xv, yv, SVG_V_YSIZE, SVG_V_XSIZE);
 
                /* Graph title */
-               printf("<text x=\"0\" y=\"%d\" style=\"fill: yellow; stroke: none\">%s",
-                      20 + (views_nr - 1) * SVG_T_YSIZE, title[i]);
+               printf("<text x=\"%d\" y=\"%d\" style=\"fill: yellow; stroke: none\">%s",
+                      xv, 20 + yv, title[i]);
                if (item_name) {
                        printf(" [%s]", item_name);
                }
                printf("\n");
                printf("<tspan x=\"%d\" y=\"%d\" style=\"fill: yellow; stroke: none; font-size: 12px\">"
                       "(Min, Max values)</tspan>\n</text>\n",
-                      5 + SVG_M_XSIZE + SVG_G_XSIZE,
-                      25 + (views_nr - 1) * SVG_T_YSIZE);
+                      xv + 5 + SVG_M_XSIZE + SVG_G_XSIZE, yv + 25);
 
                /*
                 * At least two samples are needed.
@@ -854,17 +862,17 @@ void draw_activity_graphs(int g_nr, int g_type[], char *title[], char *g_title[]
                if ((record_hdr->ust_time == svg_p->ust_time_first) ||
                    (*(spmin + pos) == DBL_MAX) || (*(spmax + pos) == -DBL_MIN)) {
                        /* No data found */
-                       printf("<text x=\"0\" y=\"%d\" style=\"fill: red; stroke: none\">No data</text>\n",
-                              SVG_M_YSIZE + (views_nr - 1) * SVG_T_YSIZE);
+                       printf("<text x=\"%d\" y=\"%d\" style=\"fill: red; stroke: none\">No data</text>\n",
+                              xv, yv + SVG_M_YSIZE);
                        skip_current_view(out, &pos, group[i]);
                        continue;
                }
 
                /* X and Y axis */
                printf("<polyline points=\"%d,%d %d,%d %d,%d\" stroke=\"white\" stroke-width=\"2\"/>\n",
-                      SVG_M_XSIZE, SVG_M_YSIZE + (views_nr - 1) * SVG_T_YSIZE,
-                      SVG_M_XSIZE, SVG_M_YSIZE + SVG_G_YSIZE + (views_nr - 1) * SVG_T_YSIZE,
-                      SVG_M_XSIZE + SVG_G_XSIZE, SVG_M_YSIZE + SVG_G_YSIZE + (views_nr - 1) * SVG_T_YSIZE);
+                      xv + SVG_M_XSIZE, yv + SVG_M_YSIZE,
+                      xv + SVG_M_XSIZE, yv + SVG_M_YSIZE + SVG_G_YSIZE,
+                      xv + SVG_M_XSIZE + SVG_G_XSIZE, yv + SVG_M_YSIZE + SVG_G_YSIZE);
 
                /* Autoscaling graphs if needed */
                gr_autoscaling(asfactor, 16, group[i], g_type[i], pos, gmax, spmax);
@@ -876,7 +884,7 @@ void draw_activity_graphs(int g_nr, int g_type[], char *title[], char *g_title[]
                        snprintf(val, 32, "x%u ", asfactor[j]);
                        printf("<text x=\"%d\" y=\"%d\" style=\"fill: #%06x; stroke: none; font-size: 12px\">"
                               "%s %s(%.*f, %.*f)</text>\n",
-                              5 + SVG_M_XSIZE + SVG_G_XSIZE, SVG_M_YSIZE + (views_nr - 1) * SVG_T_YSIZE + j * 15,
+                              xv + 5 + SVG_M_XSIZE + SVG_G_XSIZE, yv + SVG_M_YSIZE + j * 15,
                               svg_colors[(pos + j) & SVG_COLORS_IDX_MASK], g_title[pos + j] + dp,
                               asfactor[j] == 1 ? "" : val,
                               !dp * 2, *(spmin + pos + j) * asfactor[j],
@@ -885,7 +893,7 @@ void draw_activity_graphs(int g_nr, int g_type[], char *title[], char *g_title[]
 
                /* Translate to proper position for current graph within current activity */
                printf("<g transform=\"translate(%d,%d)\">\n",
-                      SVG_M_XSIZE, SVG_M_YSIZE + SVG_G_YSIZE + (views_nr - 1) * SVG_T_YSIZE);
+                      xv + SVG_M_XSIZE, yv + SVG_M_YSIZE + SVG_G_YSIZE);
 
                /* Grid */
                if (g_type[i] == SVG_LINE_GRAPH) {
@@ -958,8 +966,8 @@ void draw_activity_graphs(int g_nr, int g_type[], char *title[], char *g_title[]
        }
        printf("</g>\n");
 
-       /* Next graph */
-       (svg_p->graph_no) += views_nr;
+       /* For next row of views */
+       (svg_p->graph_no) += PACK_VIEWS(flags) ? 1 : views_nr;
 }
 
 /*