]> granicus.if.org Git - sysstat/blob - svg_stats.c
Merge branch 'lto-support'
[sysstat] / svg_stats.c
1 /*
2  * svg_stats.c: Funtions used by sadf to display statistics in SVG format.
3  * (C) 2016-2020 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
5  ***************************************************************************
6  * This program is free software; you can redistribute it and/or modify it *
7  * under the terms of the GNU General Public License as published  by  the *
8  * Free Software Foundation; either version 2 of the License, or (at  your *
9  * option) any later version.                                              *
10  *                                                                         *
11  * This program is distributed in the hope that it  will  be  useful,  but *
12  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
14  * for more details.                                                       *
15  *                                                                         *
16  * You should have received a copy of the GNU General Public License along *
17  * with this program; if not, write to the Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
19  ***************************************************************************
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <float.h>
27
28 #include "sa.h"
29 #include "ioconf.h"
30 #include "svg_stats.h"
31
32 #ifdef USE_NLS
33 #include <locale.h>
34 #include <libintl.h>
35 #define _(string) gettext(string)
36 #else
37 #define _(string) (string)
38 #endif
39
40 extern uint64_t flags;
41 extern int palette;
42
43 unsigned int svg_colors[SVG_COL_PALETTE_NR][SVG_COL_PALETTE_SIZE] =
44         {{0x00cc00, 0xff00bf, 0x00ffff, 0xff0000,       /* Default palette */
45           0xe85f00, 0x0000ff, 0x006020, 0x7030a0,
46           0xffff00, 0x666635, 0xd60093, 0x00bfbf,
47           0xcc3300, 0x50040f, 0xffffbf, 0x193d55,
48           0x000000, 0xffffff, 0x202020, 0xffff00,
49           0xffff00, 0x808080, 0xa52a2a, 0xff0000},
50
51          {0x000000, 0x1a1aff, 0x1affb2, 0xb21aff,       /* Custom color palette */
52           0x1ab2ff, 0xff1a1a, 0xffb31a, 0xb2ff1a,
53           0xefefef, 0x000000, 0x1a1aff, 0x1affb2,
54           0xb21aff, 0x1ab2ff, 0xff1a1a, 0xffb31a,
55           0xffffff, 0x000000, 0xbebebe, 0x000000,
56           0x000000, 0x000000, 0x000000, 0x000000},
57
58          {0x696969, 0xbebebe, 0x000000, 0xa9a9a9,       /* Black & white palette */
59           0x708090, 0xc0c0c0, 0x808080, 0xd3d3d3,
60           0x909090, 0x696969, 0xbebebe, 0x000000,
61           0x000000, 0xa9a9a9, 0xc0c0c0, 0x808080,
62           0xffffff, 0x000000, 0xbebebe, 0x000000,
63           0x000000, 0x000000, 0x000000, 0x000000}};
64
65 /*
66  ***************************************************************************
67  * Compare the values of a statistics sample with the max and min values
68  * already found in previous samples for this same activity. If some new
69  * min or max values are found, then save them.
70  * Assume values cannot be negative.
71  * The structure containing the statistics sample is composed of @llu_nr
72  * unsigned long long fields, followed by @lu_nr unsigned long fields, then
73  * followed by @u_nr unsigned int fields.
74  *
75  * IN:
76  * @types_nr    Number of fields whose type is "long long", "long" and "int"
77  *              composing the structure.
78  * @cs          Pointer on current sample statistics structure.
79  * @ps          Pointer on previous sample statistics structure (may be NULL).
80  * @itv         Interval of time in 1/100th of a second.
81  * @spmin       Array containing min values already found for this activity.
82  * @spmax       Array containing max values already found for this activity.
83  * @g_fields    Index in spmin/spmax arrays where extrema values for each
84  *              activity metric will be saved. As a consequence spmin/spmax
85  *              arrays may contain values in a different order than that of
86  *              the fields in the statistics structure.
87  *
88  * OUT:
89  * @spmin       Array containg the possible new min values for current activity.
90  * @spmax       Array containg the possible new max values for current activity.
91  ***************************************************************************
92  */
93 void save_extrema(unsigned int types_nr[], void *cs, void *ps, unsigned long long itv,
94                   double *spmin, double *spmax, int g_fields[])
95 {
96         unsigned long long *lluc, *llup;
97         unsigned long *luc, *lup;
98         unsigned int *uc, *up;
99         double val;
100         int i, m = 0;
101
102         /* Compare unsigned long long fields */
103         lluc = (unsigned long long *) cs;
104         llup = (unsigned long long *) ps;
105         for (i = 0; i < types_nr[0]; i++, m++) {
106                 if (ps) {
107                         val = *lluc < *llup ? 0.0 : S_VALUE(*llup, *lluc, itv);
108                 }
109                 else {
110                         /*
111                          * If no pointer on previous sample has been given
112                          * then the value is not a per-second one.
113                          */
114                         val = (double) *lluc;
115                 }
116                 if (val < *(spmin + g_fields[m])) {
117                         *(spmin + g_fields[m]) = val;
118                 }
119                 if (val > *(spmax + g_fields[m])) {
120                         *(spmax + g_fields[m]) = val;
121                 }
122                 lluc = (unsigned long long *) ((char *) lluc + ULL_ALIGNMENT_WIDTH);
123                 if (ps) {
124                         llup = (unsigned long long *) ((char *) llup + ULL_ALIGNMENT_WIDTH);
125                 }
126         }
127
128         /* Compare unsigned long fields */
129         luc = (unsigned long *) lluc;
130         lup = (unsigned long *) llup;
131         for (i = 0; i < types_nr[1]; i++, m++) {
132                 if (ps) {
133                         val = *luc < *lup ? 0.0 : S_VALUE(*lup, *luc, itv);
134                 }
135                 else {
136                         val = (double) *luc;
137                 }
138                 if (val < *(spmin + g_fields[m])) {
139                         *(spmin + g_fields[m]) = val;
140                 }
141                 if (val > *(spmax + g_fields[m])) {
142                         *(spmax + g_fields[m]) = val;
143                 }
144                 luc = (unsigned long *) ((char *) luc + UL_ALIGNMENT_WIDTH);
145                 if (ps) {
146                         lup = (unsigned long *) ((char *) lup + UL_ALIGNMENT_WIDTH);
147                 }
148         }
149
150         /* Compare unsigned int fields */
151         uc = (unsigned int *) luc;
152         up = (unsigned int *) lup;
153         for (i = 0; i < types_nr[2]; i++, m++) {
154                 if (ps) {
155                         val = *uc < *up ? 0.0 : S_VALUE(*up, *uc, itv);
156                 }
157                 else {
158                         val = (double) *uc;
159                 }
160                 if (val < *(spmin + g_fields[m])) {
161                         *(spmin + g_fields[m]) = val;
162                 }
163                 if (val > *(spmax + g_fields[m])) {
164                         *(spmax + g_fields[m]) = val;
165                 }
166                 uc = (unsigned int *) ((char *) uc + U_ALIGNMENT_WIDTH);
167                 if (ps) {
168                         up = (unsigned int *) ((char *) up + U_ALIGNMENT_WIDTH);
169                 }
170         }
171 }
172
173 /*
174  ***************************************************************************
175  * Find the min and max values of all the graphs that will be drawn in the
176  * same view. The graphs have their own min and max values in
177  * spmin[pos...pos+n-1] and spmax[pos...pos+n-1]. 
178  *
179  * IN:
180  * @pos         Position in array for the first graph extrema value.
181  * @n           Number of graphs to scan.
182  * @spmin       Array containing min values for graphs.
183  * @spmax       Array containing max values for graphs.
184  *
185  * OUT:
186  * @gmin        Global min value found.
187  * @gmax        Global max value found.
188  ***************************************************************************
189  */
190 void get_global_extrema(int pos, int n, double *spmin, double *spmax,
191                         double *gmin, double *gmax)
192 {
193         int i;
194
195         *gmin = *(spmin + pos);
196         *gmax = *(spmax + pos);
197
198         for (i = 1; i < n; i++) {
199                 if (*(spmin + pos + i) < *gmin) {
200                         *gmin = *(spmin + pos + i);
201                 }
202                 if (*(spmax + pos + i) > *gmax) {
203                         *gmax = *(spmax + pos + i);
204                 }
205         }
206 }
207
208 /*
209  ***************************************************************************
210  * Allocate arrays used to save graphs data, min and max values.
211  * @n arrays of chars are allocated for @n graphs to draw. A pointer on this
212  * array is returned. This is equivalent to "char data[][n]" where each
213  * element is of indeterminate size and will contain the graph data (eg.
214  * << path d="M12,14 L13,16..." ... >>.
215  * The size of element data[i] is given by outsize[i].
216  * Also allocate an array to save min values (equivalent to "double spmin[n]")
217  * and an array for max values (equivalent to "double spmax[n]").
218  *
219  * IN:
220  * @n           Number of graphs to draw for current activity.
221  *
222  * OUT:
223  * @outsize     Array that will contain the sizes of each element in array
224  *              of chars. Equivalent to "int outsize[n]" with
225  *              outsize[n] = sizeof(data[][n]).
226  * @spmin       Array that will contain min values for current activity.
227  * @spmax       Array that will contain max values for current activity.
228  *
229  * RETURNS:
230  * Pointer on array of arrays of chars that will contain the graphs data.
231  *
232  * NB: @min and @max arrays contain values in the same order as the fields
233  * in the statistics structure.
234  ***************************************************************************
235  */
236 char **allocate_graph_lines(int n, int **outsize, double **spmin, double **spmax)
237 {
238         char **out;
239         char *out_p;
240         int i;
241
242         /*
243          * Allocate an array of pointers. Each of these pointers will
244          * be an array of chars.
245          */
246         if ((out = (char **) malloc(n * sizeof(char *))) == NULL) {
247                 perror("malloc");
248                 exit(4);
249         }
250         /* Allocate array that will contain the size of each array of chars */
251         if ((*outsize = (int *) malloc(n * sizeof(int))) == NULL) {
252                 perror("malloc");
253                 exit(4);
254         }
255         /* Allocate array that will contain the min value of each graph */
256         if ((*spmin = (double *) malloc(n * sizeof(double))) == NULL) {
257                 perror("malloc");
258                 exit(4);
259         }
260         /* Allocate array that will contain the max value of each graph */
261         if ((*spmax = (double *) malloc(n * sizeof(double))) == NULL) {
262                 perror("malloc");
263                 exit(4);
264         }
265         /* Allocate arrays of chars that will contain graphs data */
266         for (i = 0; i < n; i++) {
267                 if ((out_p = (char *) malloc(CHUNKSIZE * sizeof(char))) == NULL) {
268                         perror("malloc");
269                         exit(4);
270                 }
271                 *(out + i) = out_p;
272                 *out_p = '\0';                  /* Reset string so that it can be safely strncat()'d later */
273                 *(*outsize + i) = CHUNKSIZE;    /* Each array of chars has a default size of CHUNKSIZE */
274                 *(*spmin + i) = DBL_MAX;        /* Init min and max values */
275                 *(*spmax + i) = -DBL_MAX;
276         }
277
278         return out;
279 }
280
281 /*
282  ***************************************************************************
283  * Save SVG code for current graph.
284  *
285  * IN:
286  * @data        SVG code to append to current graph definition.
287  * @out         Pointer on array of chars for current graph definition.
288  * @outsize     Size of array of chars for current graph definition.
289  *
290  * OUT:
291  * @out         Pointer on array of chars for current graph definition that
292  *              has been updated with the addition of current sample data.
293  * @outsize     Array that containing the (possibly new) sizes of each
294  *              element in array of chars.
295  ***************************************************************************
296  */
297 void save_svg_data(char *data, char **out, int *outsize)
298 {
299         char *out_p;
300         int len;
301
302         out_p = *out;
303         /* Determine space left in array */
304         len = *outsize - strlen(out_p) - 1;
305         if (strlen(data) >= len) {
306                 /*
307                  * If current array of chars doesn't have enough space left
308                  * then reallocate it with CHUNKSIZE more bytes.
309                  */
310                 SREALLOC(out_p, char, *outsize + CHUNKSIZE);
311                 *out = out_p;
312                 *outsize += CHUNKSIZE;
313                 len += CHUNKSIZE;
314         }
315         strncat(out_p, data, len);
316 }
317
318 /*
319  ***************************************************************************
320  * Update line graph definition by appending current X,Y coordinates.
321  *
322  * IN:
323  * @timetag     Timestamp in seconds since the epoch for current sample
324  *              stats. Will be used as X coordinate.
325  * @value       Value of current sample metric. Will be used as Y coordinate.
326  * @out         Pointer on array of chars for current graph definition.
327  * @outsize     Size of array of chars for current graph definition.
328  * @restart     Set to TRUE if a RESTART record has been read since the last
329  *              statistics sample.
330  *
331  * OUT:
332  * @out         Pointer on array of chars for current graph definition that
333  *              has been updated with the addition of current sample data.
334  * @outsize     Array that containing the (possibly new) sizes of each
335  *              element in array of chars.
336  ***************************************************************************
337  */
338 void lnappend(unsigned long long timetag, double value, char **out, int *outsize,
339               int restart)
340 {
341         char data[128];
342
343         /* Prepare additional graph definition data */
344         snprintf(data, 128, " %c%llu,%.2f", restart ? 'M' : 'L', timetag, value);
345         data[127] = '\0';
346
347         save_svg_data(data, out, outsize);
348 }
349
350 /*
351  ***************************************************************************
352  * Update line graph definition by appending current X,Y coordinates. Use
353  * (unsigned long) integer values here.
354  *
355  * IN:
356  * @timetag     Timestamp in seconds since the epoch for current sample
357  *              stats. Will be used as X coordinate.
358  * @value       Value of current sample metric. Will be used as Y coordinate.
359  * @out         Pointer on array of chars for current graph definition.
360  * @outsize     Size of array of chars for current graph definition.
361  * @restart     Set to TRUE if a RESTART record has been read since the last
362  *              statistics sample.
363  *
364  * OUT:
365  * @out         Pointer on array of chars for current graph definition that
366  *              has been updated with the addition of current sample data.
367  * @outsize     Array that containing the (possibly new) sizes of each
368  *              element in array of chars.
369  ***************************************************************************
370  */
371 void lniappend(unsigned long long timetag, unsigned long long value, char **out,
372                int *outsize, int restart)
373 {
374         char data[128];
375
376         /* Prepare additional graph definition data */
377         snprintf(data, 128, " %c%llu,%llu", restart ? 'M' : 'L', timetag, value);
378         data[127] = '\0';
379
380         save_svg_data(data, out, outsize);
381 }
382
383 /*
384  ***************************************************************************
385  * Update bar graph definition by adding a new rectangle.
386  *
387  * IN:
388  * @timetag     Timestamp in seconds since the epoch for current sample
389  *              stats. Will be used as X coordinate.
390  * @value       Value of current sample metric. Will be used as rectangle
391  *              height.
392  * @offset      Offset for Y coordinate.
393  * @out         Pointer on array of chars for current graph definition.
394  * @outsize     Size of array of chars for current graph definition.
395  * @dt          Interval of time in seconds between current and previous
396  *              sample.
397  *
398  * OUT:
399  * @out         Pointer on array of chars for current graph definition that
400  *              has been updated with the addition of current sample data.
401  * @outsize     Array that containing the (possibly new) sizes of each
402  *              element in array of chars.
403  ***************************************************************************
404  */
405 void brappend(unsigned long long timetag, double offset, double value, char **out,
406               int *outsize, unsigned long long dt)
407 {
408         char data[128];
409         unsigned long long t = 0;
410
411         /* Prepare additional graph definition data */
412         if ((value == 0.0) || (dt == 0))
413                 /* Don't draw a flat rectangle! */
414                 return;
415         if (dt < timetag) {
416                 t = timetag -dt;
417         }
418
419         snprintf(data, 128, "<rect x=\"%llu\" y=\"%.2f\" height=\"%.2f\" width=\"%llu\"/>",
420                  t, MINIMUM(offset, 100.0), MINIMUM(value, (100.0 - offset)), dt);
421         data[127] = '\0';
422
423         save_svg_data(data, out, outsize);
424
425 }
426
427 /*
428  ***************************************************************************
429  * Update CPU graph and min/max values for each metric.
430  *
431  * IN:
432  * @timetag     Timestamp in seconds since the epoch for current sample
433  *              stats. Will be used as X coordinate.
434  * @offset      Offset for Y coordinate.
435  * @value       Value of current CPU metric. Will be used as rectangle
436  *              height.
437  * @out         Pointer on array of chars for current graph definition.
438  * @outsize     Size of array of chars for current graph definition.
439  * @dt          Interval of time in seconds between current and previous
440  *              sample.
441  * @spmin       Min value already found for this CPU metric.
442  * @spmax       Max value already found for this CPU metric.
443  *
444  * OUT:
445  * @offset      New offset value, to use to draw next rectangle
446  * @out         Pointer on array of chars for current graph definition that
447  *              has been updated with the addition of current sample data.
448  * @outsize     Array that containing the (possibly new) sizes of each
449  *              element in array of chars.
450  ***************************************************************************
451  */
452 void cpuappend(unsigned long long timetag, double *offset, double value, char **out,
453                int *outsize, unsigned long long dt, double *spmin, double *spmax)
454 {
455         /* Save min and max values */
456         if (value < *spmin) {
457                 *spmin = value;
458         }
459         if (value > *spmax) {
460                 *spmax = value;
461         }
462         /* Prepare additional graph definition data */
463         brappend(timetag, *offset, value, out, outsize, dt);
464
465         *offset += value;
466 }
467
468 /*
469  ***************************************************************************
470  * Update rectangular graph and min/max values.
471  *
472  * IN:
473  * @timetag     Timestamp in seconds since the epoch for current sample
474  *              stats. Will be used as X coordinate.
475  * @p_value     Metric value for previous sample
476  * @value       Metric value for current sample.
477  * @out         Pointer on array of chars for current graph definition.
478  * @outsize     Size of array of chars for current graph definition.
479  * @restart     Set to TRUE if a RESTART record has been read since the last
480  *              statistics sample.
481  * @dt          Interval of time in seconds between current and previous
482  *              sample.
483  * @spmin       Min value already found for this metric.
484  * @spmax       Max value already found for this metric.
485  *
486  * OUT:
487  * @out         Pointer on array of chars for current graph definition that
488  *              has been updated with the addition of current sample data.
489  * @outsize     Array that containing the (possibly new) sizes of each
490  *              element in array of chars.
491  * @spmin       Min value for this metric.
492  * @spmax       Max value for this metric.
493  ***************************************************************************
494  */
495 void recappend(unsigned long long timetag, double p_value, double value, char **out,
496                int *outsize, int restart, unsigned long long dt,
497                double *spmin, double *spmax)
498 {
499         char data[512], data1[128], data2[128];
500         unsigned long long t = 0;
501
502         /* Save min and max values */
503         if (value < *spmin) {
504                 *spmin = value;
505         }
506         if (value > *spmax) {
507                 *spmax = value;
508         }
509         if (dt < timetag) {
510                 t = timetag -dt;
511         }
512         /* Prepare additional graph definition data */
513         if (restart) {
514                 snprintf(data1, sizeof(data1), " M%llu,%.2f", t, p_value);
515                 data1[sizeof(data1) - 1] = '\0';
516         }
517         if (p_value != value) {
518                 snprintf(data2, sizeof(data2), " L%llu,%.2f", timetag, value);
519                 data2[sizeof(data2) - 1] = '\0';
520         }
521         snprintf(data, sizeof(data), "%s L%llu,%.2f%s", restart ? data1 : "", timetag, p_value,
522                  p_value != value ? data2 : "");
523         data[sizeof(data) - 1] = '\0';
524
525         save_svg_data(data, out, outsize);
526 }
527
528 /*
529  ***************************************************************************
530  * Calculate 10 raised to the power of n.
531  *
532  * IN:
533  * @n   Power number to use.
534  *
535  * RETURNS:
536  * 10 raised to the power of n.
537  ***************************************************************************
538  */
539 unsigned int pwr10(int n)
540 {
541         int i;
542         unsigned int e = 1;
543
544         for (i = 0; i < n; i++) {
545                 e = e * 10;
546         }
547
548         return e;
549 }
550
551 /*
552  ***************************************************************************
553  * Autoscale graphs of a given view.
554  *
555  * IN:
556  * @asf_nr      (Maximum) number of autoscale factors.
557  * @group       Number of graphs in current view.
558  * @g_type      Type of graph (SVG_LINE_GRAPH, SVG_BAR_GRAPH).
559  * @pos         Position in array for the first graph in view.
560  * @gmax        Global max value for all graphs in view.
561  * @spmax       Array containing max values for graphs.
562  *
563  * OUT:
564  * @asfactor    Autoscale factors (one for each graph).
565  ***************************************************************************
566  */
567 void gr_autoscaling(unsigned int asfactor[], int asf_nr, int group, int g_type, int pos,
568                     double gmax, double *spmax)
569 {
570         int j;
571         char val[32];
572
573         for (j = 0; j < asf_nr; j++) {
574                 /* Init autoscale factors */
575                 asfactor[j] = 1;
576         }
577
578         if (AUTOSCALE_ON(flags) && (group > 1) && gmax && (g_type == SVG_LINE_GRAPH)) {
579                 /* Autoscaling... */
580                 for (j = 0; (j < group) && (j < asf_nr); j++) {
581                         if (!*(spmax + pos + j) || (*(spmax + pos + j) == gmax))
582                                 continue;
583
584                         snprintf(val, 32, "%u", (unsigned int) (gmax / *(spmax + pos + j)));
585                         if (strlen(val) > 0) {
586                                 asfactor[j] = pwr10(strlen(val) - 1);
587                         }
588                 }
589         }
590 }
591
592 /*
593  ***************************************************************************
594  * Display background grid (horizontal lines) and corresponding graduations.
595  *
596  * IN:
597  * @ypos        Gap between two horizontal lines.
598  * @yfactor     Scaling factor on Y axis.
599  * @lmax        Max value for current view.
600  * @dp          Number of decimal places for graduations.
601  ***************************************************************************
602  */
603 void display_hgrid(double ypos, double yfactor, double lmax, int dp)
604 {
605         int j = 0;
606         char stmp[32];
607
608         /* Print marker in debug mode */
609         if (DISPLAY_DEBUG_MODE(flags)) {
610                 printf("<!-- Hgrid -->\n");
611         }
612
613         do {
614                 /* Display horizontal lines (except on X axis) */
615                 if (j > 0) {
616                         printf("<polyline points=\"0,%.2f %d,%.2f\" style=\"vector-effect: non-scaling-stroke; "
617                                "stroke: #%06x\" transform=\"scale(1,%f)\"/>\n",
618                                ypos * j, SVG_G_XSIZE, ypos * j,
619                                svg_colors[palette][SVG_COL_GRID_IDX],
620                                yfactor);
621                 }
622
623                 /*
624                  * Display graduations.
625                  * Use same rounded value for graduation numbers as for grid lines
626                  * to make sure they are properly aligned.
627                  */
628                 sprintf(stmp, "%.2f", ypos * j);
629                 printf("<text x=\"0\" y=\"%ld\" style=\"fill: #%06x; stroke: none; font-size: 12px; "
630                        "text-anchor: end\">%.*f.</text>\n",
631                        (long) (atof(stmp) * yfactor),
632                        svg_colors[palette][SVG_COL_AXIS_IDX],
633                        dp, ypos * j);
634                 j++;
635         }
636         while ((ypos * j <= lmax) && (j < MAX_HLINES_NR));
637 }
638
639 /*
640  ***************************************************************************
641  * Display background grid (vertical lines) and corresponding graduations.
642  *
643  * IN:
644  * @xpos        Gap between two vertical lines.
645  * @xfactor     Scaling factor on X axis.
646  * @v_gridnr    Default number of vertical lines to display. The actual
647  *              number may vary between this value and 2 times this value.
648  * @svg_p       SVG specific parameters (see draw_activity_graphs() function).
649  ***************************************************************************
650  */
651 void display_vgrid(long int xpos, double xfactor, int v_gridnr, struct svg_parm *svg_p)
652 {
653         struct record_header stamp;
654         struct tm rectime;
655         char cur_time[TIMESTAMP_LEN];
656         int j;
657
658         stamp.ust_time = svg_p->ust_time_ref; /* Only ust_time field needs to be set. TRUE_TIME not allowed */
659
660         /* Print marker in debug mode */
661         if (DISPLAY_DEBUG_MODE(flags)) {
662                 printf("<!-- Vgrid -->\n");
663         }
664
665         /*
666          * What really matters to know when we should stop drawing vertical lines
667          * is the time end. v_gridnr is only informative and used to calculate
668          * the gap between two lines.
669          */
670         for (j = 0; (j <= (2 * v_gridnr)) && (stamp.ust_time <= svg_p->ust_time_end); j++) {
671
672                 /* Display vertical lines */
673                 sa_get_record_timestamp_struct(flags, &stamp, &rectime);
674                 set_record_timestamp_string(flags, &stamp, NULL, cur_time, TIMESTAMP_LEN, &rectime);
675                 printf("<polyline points=\"%ld,0 %ld,%d\" style=\"vector-effect: non-scaling-stroke; "
676                        "stroke: #%06x\" transform=\"scale(%f,1)\"/>\n",
677                        xpos * j, xpos * j, -SVG_G_YSIZE,
678                        svg_colors[palette][SVG_COL_GRID_IDX],
679                        xfactor);
680                 /*
681                  * Display graduations.
682                  * NB: We may have tm_min != 0 if we have more than 24H worth of data in one datafile.
683                  * In this case, we should rather display the exact time instead of only the hour.
684                  */
685                 if (DISPLAY_ONE_DAY(flags) && (rectime.tm_min == 0)) {
686                         printf("<text x=\"%ld\" y=\"15\" style=\"fill: #%06x; stroke: none; font-size: 14px; "
687                                "text-anchor: start\">%2d:00</text>\n",
688                                (long) (xpos * j * xfactor) - 15,
689                                svg_colors[palette][SVG_COL_AXIS_IDX],
690                                rectime.tm_hour);
691                 }
692                 else {
693                         printf("<text x=\"%ld\" y=\"10\" style=\"fill: #%06x; stroke: none; font-size: 12px; "
694                                "text-anchor: start\" transform=\"rotate(45,%ld,0)\">%s</text>\n",
695                                (long) (xpos * j * xfactor),
696                                svg_colors[palette][SVG_COL_AXIS_IDX],
697                                (long) (xpos * j * xfactor), cur_time);
698                 }
699                 stamp.ust_time += xpos;
700         }
701
702         if (!PRINT_LOCAL_TIME(flags)) {
703                 printf("<text x=\"-10\" y=\"30\" style=\"fill: #%06x; stroke: none; font-size: 12px; "
704                        "text-anchor: end\">UTC</text>\n",
705                        svg_colors[palette][SVG_COL_INFO_IDX]);
706         }
707 }
708
709 /*
710  ***************************************************************************
711  * Calculate the value on the Y axis between two horizontal lines that will
712  * make the graph background grid.
713  *
714  * IN:
715  * @lmax        Max value reached for this graph.
716  *
717  * OUT:
718  * @dp          Number of decimal places for Y graduations.
719  *
720  * RETURNS:
721  * Value between two horizontal lines.
722  ***************************************************************************
723  */
724 double ygrid(double lmax, int *dp)
725 {
726         char val[32];
727         int l;
728         unsigned int e;
729         long n = 0;
730
731         *dp = 0;
732         if (lmax == 0) {
733                 lmax = 1;
734         }
735         n = (long) (lmax / SVG_H_GRIDNR);
736         if (!n) {
737                 *dp = 2;
738                 return (lmax / SVG_H_GRIDNR);
739         }
740         snprintf(val, 32, "%ld", n);
741         val[31] = '\0';
742         l = strlen(val);
743         if (l < 2)
744                 return n;
745         e = pwr10(l - 1);
746
747         return ((double) (((long) (n / e)) * e));
748 }
749
750 /*
751  ***************************************************************************
752  * Calculate the value on the X axis between two vertical lines that will
753  * make the graph background grid.
754  *
755  * IN:
756  * @timestart   First data timestamp (X coordinate of the first data point).
757  * @timeend     Last data timestamp (X coordinate of the last data point).
758  * @v_gridnr    Number of vertical lines to display. Its value is normally
759  *              SVG_V_GRIDNR, except when option "oneday" is used, in which
760  *              case it is set to 12.
761  *
762  * RETURNS:
763  * Value between two vertical lines.
764  ***************************************************************************
765  */
766 long int xgrid(unsigned long timestart, unsigned long timeend, int v_gridnr)
767 {
768         if ((timeend - timestart) <= v_gridnr)
769                 return 1;
770         else
771                 return ((timeend - timestart) / v_gridnr);
772 }
773
774 /*
775  ***************************************************************************
776  * Free global graphs structures.
777  *
778  * IN:
779  * @out         Pointer on array of chars for each graph definition.
780  * @outsize     Size of array of chars for each graph definition.
781  * @spmin       Array containing min values for graphs.
782  * @spmax       Array containing max values for graphs.
783  ***************************************************************************
784  */
785 void free_graphs(char **out, int *outsize, double *spmin, double *spmax)
786 {
787         if (out) {
788                 free(out);
789         }
790         if (outsize) {
791                 free(outsize);
792         }
793         if (spmin) {
794                 free(spmin);
795         }
796         if (spmax) {
797                 free(spmax);
798         }
799 }
800
801 /*
802  ***************************************************************************
803  * Skip current view where all graphs have only zero values. This function
804  * is called when option "skipempty" has been used, or when "No data" have
805  * been found for current view.
806  *
807  * IN:
808  * @out         Pointer on array of chars for each graph definition.
809  * @pos         Position of current view in the array of graphs definitions.
810  * @group       Number of graphs in current view.
811  *
812  * OUT:
813  * @pos         Position of next view in the array of graphs definitions.
814  ***************************************************************************
815  */
816 void skip_current_view(char **out, int *pos, int group)
817 {
818         int j;
819         char *out_p;
820
821         for (j = 0; j < group; j++) {
822                 out_p = *(out + *pos + j);
823                 if (out_p) {
824                         /* Even if not displayed, current graph data have to be freed */
825                         free(out_p);
826                 }
827         }
828         *pos += group;
829 }
830
831 /*
832  ***************************************************************************
833  * Display all graphs for current activity.
834  *
835  * IN:
836  * @g_nr        Number of views to display.
837  * @g_type      Type of graph (SVG_LINE_GRAPH, SVG_BAR_GRAPH) for each view.
838  * @title       Titles for each set of graphs.
839  * @g_title     Titles for each graph.
840  * @item_name   Item (network interface, etc.) name.
841  * @group       Indicate how graphs are grouped together to make sets.
842  * @spmin       Array containing min values for graphs.
843  * @spmax       Array containing max values for graphs.
844  * @out         Pointer on array of chars for each graph definition.
845  * @outsize     Size of array of chars for each graph definition.
846  * @svg_p       SVG specific parameters: Current views row number (.@graph_no),
847  *              time for the first sample of stats (.@ust_time_first), and
848  *              times used as start and end values on the X axis
849  *              (.@ust_time_ref and .@ust_time_end).
850  * @record_hdr  Pointer on record header of current stats sample.
851  * @skip_void   Set to <> 0 if graphs with no data should be skipped.
852  *              This is typicallly used to not display CPU offline on the
853  *              whole period.
854  * @a           Current activity structure.
855  * @xid         Current activity extra id number.
856  *
857  * RETURNS:
858  * TRUE if at least one graph has been displayed.
859  ***************************************************************************
860  */
861 int draw_activity_graphs(int g_nr, int g_type[], char *title[], char *g_title[], char *item_name,
862                          int group[], double *spmin, double *spmax, char **out, int *outsize,
863                          struct svg_parm *svg_p, struct record_header *record_hdr, int skip_void,
864                          struct activity *a, unsigned int xid)
865 {
866         char *out_p;
867         int i, j, dp, pos = 0, views_nr = 0, displayed = FALSE, palpos;
868         int v_gridnr, xv, yv;
869         unsigned int asfactor[16];
870         long int xpos;
871         double lmax, xfactor, yfactor, ypos, gmin, gmax;
872         char val[32], cur_date[TIMESTAMP_LEN];
873         struct tm rectime;
874
875         /* Print activity name in debug mode */
876         if (DISPLAY_DEBUG_MODE(flags)) {
877                 printf("<!-- Name: %s -->\n", a->name);
878         }
879
880         /* For each view which is part of current activity */
881         for (i = 0; i < g_nr; i++) {
882
883                 /* Print view number in debug mode */
884                 if (DISPLAY_DEBUG_MODE(flags)) {
885                         printf("<!-- View %d -->\n", i + 1);
886                 }
887
888                 /* Used as index in color palette */
889                 palpos = (palette == SVG_BW_COL_PALETTE ? 0 : pos);
890
891                 /* Get global min and max value for current view */
892                 get_global_extrema(pos, group[i], spmin, spmax, &gmin, &gmax);
893
894                 /* Don't display empty views if requested */
895                 if (SKIP_EMPTY_VIEWS(flags) && (gmax < 0.005)) {
896                         skip_current_view(out, &pos, group[i]);
897                         continue;
898                 }
899                 /* Skip void graphs */
900                 if (skip_void && ((*(spmin + pos) == DBL_MAX) || (*(spmax + pos) == -DBL_MIN)))
901                         continue;
902
903                 if (!displayed) {
904                         /* Translate to proper position for current activity */
905                         printf("<g id=\"g%d-%d\" transform=\"translate(0,%d)\">\n",
906                                a->id, xid,
907                                SVG_H_YSIZE +
908                                SVG_C_YSIZE * (DISPLAY_TOC(flags) ? svg_p->nr_act_dispd : 0) +
909                                SVG_T_YSIZE * svg_p->graph_no);
910                         displayed = TRUE;
911                 }
912
913                 /* Increment number of views actually displayed */
914                 views_nr++;
915
916                 /* Compute top left position of view */
917                 if (PACK_VIEWS(flags)) {
918                         xv = (views_nr - 1) * SVG_T_XSIZE;
919                         yv = 0;
920                 }
921                 else {
922                         xv = 0;
923                         yv = (views_nr - 1) * SVG_T_YSIZE;
924                 }
925
926                 /* Graph background */
927                 printf("<rect x=\"%d\" y=\"%d\" height=\"%d\" width=\"%d\" fill=\"#%06x\"/>\n",
928                        xv, yv, SVG_V_YSIZE, SVG_V_XSIZE,
929                        svg_colors[palette][SVG_COL_BCKGRD_IDX]);
930
931                 /* Graph title */
932                 printf("<text x=\"%d\" y=\"%d\" style=\"fill: #%06x; stroke: none\">%s",
933                        xv, 20 + yv,
934                        svg_colors[palette][SVG_COL_TITLE_IDX],
935                        title[i]);
936                 if (item_name) {
937                         printf(" [%s]", item_name);
938                 }
939                 printf("\n");
940                 printf("<tspan x=\"%d\" y=\"%d\" style=\"fill: #%06x; stroke: none; font-size: 12px\">"
941                        "(Min, Max values)</tspan>\n</text>\n",
942                        xv + 5 + SVG_M_XSIZE + SVG_G_XSIZE, yv + 25,
943                        svg_colors[palette][SVG_COL_INFO_IDX]);
944
945                 /*
946                  * At least two samples are needed.
947                  * And a min and max value should have been found.
948                  */
949                 if ((record_hdr->ust_time == svg_p->ust_time_first) ||
950                     (*(spmin + pos) == DBL_MAX) || (*(spmax + pos) == -DBL_MIN)) {
951                         /* No data found */
952                         printf("<text x=\"%d\" y=\"%d\" style=\"fill: #%06x; stroke: none\">No data</text>\n",
953                                xv, yv + SVG_M_YSIZE,
954                                svg_colors[palette][SVG_COL_ERROR_IDX]);
955                         skip_current_view(out, &pos, group[i]);
956                         continue;
957                 }
958
959                 /* X and Y axis */
960                 printf("<polyline points=\"%d,%d %d,%d %d,%d\" style=\"fill: #%06x; stroke: #%06x; stroke-width: 2\"/>\n",
961                        xv + SVG_M_XSIZE, yv + SVG_M_YSIZE,
962                        xv + SVG_M_XSIZE, yv + SVG_M_YSIZE + SVG_G_YSIZE,
963                        xv + SVG_M_XSIZE + SVG_G_XSIZE, yv + SVG_M_YSIZE + SVG_G_YSIZE,
964                        svg_colors[palette][SVG_COL_BCKGRD_IDX],
965                        svg_colors[palette][SVG_COL_AXIS_IDX]);
966
967                 /* Autoscaling graphs if needed */
968                 gr_autoscaling(asfactor, 16, group[i], g_type[i], pos, gmax, spmax);
969
970                 /* Caption */
971                 for (j = 0; j < group[i]; j++) {
972                         /* Set dp to TRUE (1) if current metric is based on integer values */
973                         dp = (g_title[pos + j][0] == '~');
974                         snprintf(val, 32, "x%u ", asfactor[j]);
975                         printf("<text x=\"%d\" y=\"%d\" style=\"fill: #%06x; stroke: none; font-size: 12px\">"
976                                "%s %s(%.*f, %.*f)</text>\n",
977                                xv + 5 + SVG_M_XSIZE + SVG_G_XSIZE, yv + SVG_M_YSIZE + j * 15,
978                                svg_colors[palette][(palpos + j) & SVG_COLORS_IDX_MASK], g_title[pos + j] + dp,
979                                asfactor[j] == 1 ? "" : val,
980                                !dp * 2, *(spmin + pos + j) * asfactor[j],
981                                !dp * 2, *(spmax + pos + j) * asfactor[j]);
982                 }
983
984                 if (DISPLAY_INFO(flags)) {
985                         /* Display additional info (hostname, date) */
986                         printf("<text x=\"%d\" y=\"%d\" "
987                                "style=\"fill: #%06x; text-anchor: end; stroke: none; font-size: 14px\">"
988                                "%s\n",
989                                xv + SVG_V_XSIZE - 5, yv + SVG_M_YSIZE + SVG_G_YSIZE,
990                                svg_colors[palette][SVG_COL_INFO_IDX],
991                                svg_p->file_hdr->sa_nodename);
992
993                         /* Get report date */
994                         set_report_date(localtime_r((const time_t *) &(svg_p->file_hdr->sa_ust_time), &rectime),
995                                         cur_date, sizeof(cur_date));
996                         printf("<tspan x=\"%d\" y=\"%d\" "
997                                "style=\"fill: #%06x; text-anchor: end; stroke: none; font-size: 14px\">"
998                                "%s</tspan>\n</text>\n",
999                                xv + SVG_V_XSIZE - 5, yv + SVG_M_YSIZE + SVG_G_YSIZE + 14,
1000                                svg_colors[palette][SVG_COL_INFO_IDX],
1001                                cur_date);
1002                 }
1003
1004                 /* Translate to proper position for current graph within current activity */
1005                 printf("<g transform=\"translate(%d,%d)\">\n",
1006                        xv + SVG_M_XSIZE, yv + SVG_M_YSIZE + SVG_G_YSIZE);
1007
1008                 /* Grid */
1009                 if (g_type[i] == SVG_LINE_GRAPH) {
1010                         /* For line graphs */
1011                         if (!gmax) {
1012                                 /* If all values are zero then set current max value to 1 */
1013                                 lmax = 1.0;
1014                         }
1015                         else {
1016                                 lmax = gmax;
1017                         }
1018                         /* Max value cannot be too small, else Y graduations will be meaningless */
1019                         if (lmax < SVG_H_GRIDNR * 0.01) {
1020                                 lmax = SVG_H_GRIDNR * 0.01;
1021                         }
1022                         ypos = ygrid(lmax, &dp);
1023                 }
1024                 else {
1025                         /* For bar graphs (used for %values) */
1026                         ypos = 25.0;    /* Draw lines at 25%, 50%, 75% and 100% */
1027                         dp = 0;         /* No decimals */
1028
1029                         /* Max should be always 100% except for percentage values greater than 100% */
1030                         if (gmax > 100.0) {
1031                                 lmax = gmax;
1032                         }
1033                         else {
1034                                 lmax = 100.0;
1035                         }
1036                 }
1037                 yfactor = (double) -SVG_G_YSIZE / lmax;
1038
1039                 /* Display horizontal lines and graduations */
1040                 display_hgrid(ypos, yfactor, lmax, dp);
1041
1042                 /* Set number of vertical lines to 12 when option "oneday" is used */
1043                 v_gridnr = DISPLAY_ONE_DAY(flags) ? 12 : SVG_V_GRIDNR;
1044
1045                 xpos = xgrid(svg_p->ust_time_ref, svg_p->ust_time_end, v_gridnr);
1046                 xfactor = (double) SVG_G_XSIZE / (svg_p->ust_time_end - svg_p->ust_time_ref);
1047
1048                 /* Display vertical lines and graduations */
1049                 display_vgrid(xpos, xfactor, v_gridnr, svg_p);
1050
1051                 /* Print marker in debug mode */
1052                 if (DISPLAY_DEBUG_MODE(flags)) {
1053                         printf("<!-- Graphs -->\n");
1054                 }
1055
1056                 /* Draw current graphs set */
1057                 for (j = 0; j < group[i]; j++) {
1058                         out_p = *(out + pos + j);
1059                         if (g_type[i] == SVG_LINE_GRAPH) {
1060                                 /* Line graphs */
1061                                 printf("<path d=\"%s\" "
1062                                        "style=\"vector-effect: non-scaling-stroke; "
1063                                        "stroke: #%06x; stroke-width: 1; fill-opacity: 0\" "
1064                                        "transform=\"scale(%f,%f)\"/>\n",
1065                                        out_p,
1066                                        svg_colors[palette][(palpos + j) & SVG_COLORS_IDX_MASK],
1067                                        xfactor,
1068                                        yfactor * asfactor[j]);
1069                         }
1070                         else if (*out_p) {      /* Ignore flat bars */
1071                                 /* Bar graphs */
1072                                 printf("<g style=\"fill: #%06x; stroke: none\" transform=\"scale(%f,%f)\">\n",
1073                                        svg_colors[palette][(palpos + j) & SVG_COLORS_IDX_MASK], xfactor, yfactor);
1074                                 printf("%s\n", out_p);
1075                                 printf("</g>\n");
1076                         }
1077                         free(out_p);
1078                 }
1079                 printf("</g>\n");
1080                 pos += group[i];
1081         }
1082         if (displayed) {
1083                 printf("</g>\n");
1084
1085                 /* For next row of views */
1086                 (svg_p->graph_no) += PACK_VIEWS(flags) ? 1 : views_nr;
1087         }
1088
1089         return displayed;
1090 }
1091
1092 /*
1093  ***************************************************************************
1094  * Display CPU statistics in SVG.
1095  *
1096  * IN:
1097  * @a           Activity structure with statistics.
1098  * @curr        Index in array for current sample statistics.
1099  * @action      Action expected from current function.
1100  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1101  *              flag indicating that a restart record has been previously
1102  *              found (.@restart), and time used for the X axis origin
1103  *              (@ust_time_ref).
1104  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1105  *              Unused here.
1106  * @record_hdr  Pointer on record header of current stats sample.
1107  ***************************************************************************
1108  */
1109 #define CPU_ARRAY_SZ    10
1110 __print_funct_t svg_print_cpu_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1111                                     unsigned long long itv, struct record_header *record_hdr)
1112 {
1113         struct stats_cpu *scc, *scp;
1114         unsigned long long deltot_jiffies = 1;
1115         unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
1116         int group1[] = {5};
1117         int group2[] = {9};
1118         int g_type[] = {SVG_BAR_GRAPH};
1119         char *title[] = {"CPU utilization"};
1120         char *g_title1[] = {"%user", "%nice", "%system", "%iowait", "%steal", "%idle"};
1121         char *g_title2[] = {"%usr", "%nice", "%sys", "%iowait", "%steal", "%irq", "%soft", "%guest", "%gnice", "%idle"};
1122         static double *spmin, *spmax;
1123         static char **out;
1124         static int *outsize;
1125         char item_name[16];
1126         double offset, val;
1127         int i, j, k, pos;
1128
1129         if (action & F_BEGIN) {
1130                 /*
1131                  * Allocate arrays that will contain the graphs data
1132                  * and the min/max values.
1133                  */
1134                 out = allocate_graph_lines(CPU_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
1135         }
1136
1137         if (action & F_MAIN) {
1138
1139                 /* @nr[curr] cannot normally be greater than @nr_ini */
1140                 if (a->nr[curr] > a->nr_ini) {
1141                         a->nr_ini = a->nr[curr];
1142                 }
1143
1144                 /*
1145                  * Compute CPU "all" as sum of all individual CPU (on SMP machines)
1146                  * and look for offline CPU.
1147                  */
1148                 if (a->nr_ini > 1) {
1149                         deltot_jiffies = get_global_cpu_statistics(a, !curr, curr,
1150                                                                    flags, offline_cpu_bitmap);
1151                 }
1152
1153                 /* For each CPU */
1154                 for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
1155
1156                         /* Should current CPU (including CPU "all") be displayed? */
1157                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) ||
1158                             offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
1159                                 /* Don't display CPU */
1160                                 continue;
1161
1162                         scc = (struct stats_cpu *) ((char *) a->buf[curr]  + i * a->msize);
1163                         scp = (struct stats_cpu *) ((char *) a->buf[!curr] + i * a->msize);
1164
1165                         pos = i * CPU_ARRAY_SZ;
1166                         offset = 0.0;
1167
1168                         if (i == 0) {
1169                                 /* This is CPU "all" */
1170                                 if (a->nr_ini == 1) {
1171                                         /*
1172                                          * This is a UP machine. In this case
1173                                          * interval has still not been calculated.
1174                                          */
1175                                         deltot_jiffies = get_per_cpu_interval(scc, scp);
1176                                 }
1177                                 if (!deltot_jiffies) {
1178                                         /* CPU "all" cannot be tickless */
1179                                         deltot_jiffies = 1;
1180                                 }
1181                         }
1182                         else {
1183                                 /*
1184                                  * Recalculate interval for current proc.
1185                                  * If result is 0 then current CPU is a tickless one.
1186                                  */
1187                                 deltot_jiffies = get_per_cpu_interval(scc, scp);
1188
1189                                 if (!deltot_jiffies) {  /* Current CPU is tickless */
1190
1191                                         val = 100.0;    /* Tickless CPU: %idle = 100% */
1192
1193                                         if (DISPLAY_CPU_DEF(a->opt_flags)) {
1194                                                 j  = 5; /* -u */
1195                                         }
1196                                         else {  /* DISPLAY_CPU_ALL(a->opt_flags) */
1197                                                 j = 9;  /* -u ALL */
1198                                         }
1199
1200                                         /* Check min/max values for %user, etc. */
1201                                         for (k = 0; k < j; k++) {
1202                                                 if (0.0 < *(spmin + pos + k)) {
1203                                                         *(spmin + pos + k) = 0.0;
1204                                                 }
1205                                                 if (0.0 > *(spmax + pos + k)) {
1206                                                         *(spmax + pos + k) = 0.0;
1207                                                 }
1208                                         }
1209
1210                                         /* %idle */
1211                                         cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1212                                                   &offset, val,
1213                                                   out + pos + j, outsize + pos + j, svg_p->dt,
1214                                                   spmin + pos + j, spmax + pos + j);
1215                                         continue;
1216                                 }
1217                         }
1218
1219                         if (DISPLAY_CPU_DEF(a->opt_flags)) {
1220                                 /* %user */
1221                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1222                                           &offset, ll_sp_value(scp->cpu_user, scc->cpu_user, deltot_jiffies),
1223                                           out + pos, outsize + pos, svg_p->dt,
1224                                           spmin + pos, spmax + pos);
1225                         }
1226                         else {
1227                                 /* %usr */
1228                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1229                                           &offset,
1230                                           (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
1231                                            0.0 :
1232                                            ll_sp_value(scp->cpu_user - scp->cpu_guest,
1233                                                        scc->cpu_user - scc->cpu_guest, deltot_jiffies),
1234                                           out + pos, outsize + pos, svg_p->dt,
1235                                           spmin + pos, spmax + pos);
1236                         }
1237
1238                         if (DISPLAY_CPU_DEF(a->opt_flags)) {
1239                                 /* %nice */
1240                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1241                                           &offset, ll_sp_value(scp->cpu_nice, scc->cpu_nice, deltot_jiffies),
1242                                           out + pos + 1, outsize + pos + 1, svg_p->dt,
1243                                           spmin + pos + 1, spmax + pos + 1);
1244                         }
1245                         else {
1246                                 /* %nice */
1247                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1248                                           &offset,
1249                                           (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
1250                                            0.0 :
1251                                            ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
1252                                                        scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
1253                                           out + pos + 1, outsize + pos + 1, svg_p->dt,
1254                                           spmin + pos + 1, spmax + pos + 1);
1255                         }
1256
1257                         if (DISPLAY_CPU_DEF(a->opt_flags)) {
1258                                 /* %system */
1259                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1260                                           &offset,
1261                                           ll_sp_value(scp->cpu_sys + scp->cpu_hardirq + scp->cpu_softirq,
1262                                                       scc->cpu_sys + scc->cpu_hardirq + scc->cpu_softirq,
1263                                                       deltot_jiffies),
1264                                           out + pos + 2, outsize + pos + 2, svg_p->dt,
1265                                           spmin + pos + 2, spmax + pos + 2);
1266                         }
1267                         else {
1268                                 /* %sys */
1269                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1270                                           &offset, ll_sp_value(scp->cpu_sys, scc->cpu_sys, deltot_jiffies),
1271                                           out + pos + 2, outsize + pos + 2, svg_p->dt,
1272                                           spmin + pos + 2, spmax + pos + 2);
1273                         }
1274
1275                         /* %iowait */
1276                         cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1277                                   &offset, ll_sp_value(scp->cpu_iowait, scc->cpu_iowait, deltot_jiffies),
1278                                   out + pos + 3, outsize + pos + 3, svg_p->dt,
1279                                   spmin + pos + 3, spmax + pos + 3);
1280                         /* %steal */
1281                         cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1282                                   &offset, ll_sp_value(scp->cpu_steal, scc->cpu_steal, deltot_jiffies),
1283                                   out + pos + 4, outsize + pos + 4, svg_p->dt,
1284                                   spmin + pos + 4, spmax + pos + 4);
1285
1286                         if (DISPLAY_CPU_ALL(a->opt_flags)) {
1287                                 /* %irq */
1288                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1289                                           &offset, ll_sp_value(scp->cpu_hardirq, scc->cpu_hardirq, deltot_jiffies),
1290                                           out + pos + 5, outsize + pos + 5, svg_p->dt,
1291                                           spmin + pos + 5, spmax + pos + 5);
1292                                 /* %soft */
1293                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1294                                           &offset, ll_sp_value(scp->cpu_softirq, scc->cpu_softirq, deltot_jiffies),
1295                                           out + pos + 6, outsize + pos + 6, svg_p->dt,
1296                                           spmin + pos + 6, spmax + pos + 6);
1297                                 /* %guest */
1298                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1299                                           &offset, ll_sp_value(scp->cpu_guest, scc->cpu_guest, deltot_jiffies),
1300                                           out + pos + 7, outsize + pos + 7, svg_p->dt,
1301                                           spmin + pos + 7, spmax + pos + 7);
1302                                 /* %gnice */
1303                                 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1304                                           &offset, ll_sp_value(scp->cpu_guest_nice, scc->cpu_guest_nice, deltot_jiffies),
1305                                           out + pos + 8, outsize + pos + 8, svg_p->dt,
1306                                           spmin + pos + 8, spmax + pos + 8);
1307
1308                                 j = 9;
1309                         }
1310                         else {
1311                                 j = 5;
1312                         }
1313
1314                         /* %idle */
1315                         cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1316                                   &offset,
1317                                   (scc->cpu_idle < scp->cpu_idle ? 0.0 :
1318                                    ll_sp_value(scp->cpu_idle, scc->cpu_idle, deltot_jiffies)),
1319                                   out + pos + j, outsize + pos + j, svg_p->dt,
1320                                   spmin + pos + j, spmax + pos + j);
1321                 }
1322         }
1323
1324         if (action & F_END) {
1325                 int xid = 0, displayed;
1326
1327                 if (DISPLAY_IDLE(flags)) {
1328                         /* Include additional %idle field */
1329                         group1[0]++;
1330                         group2[0]++;
1331                 }
1332
1333                 for (i = 0; (i < a->item_list_sz) && (i < a->bitmap->b_size + 1); i++) {
1334
1335                         /* Should current CPU (including CPU "all") be displayed? */
1336                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
1337                                 /* No */
1338                                 continue;
1339
1340                         pos = i * CPU_ARRAY_SZ;
1341                         if (!i) {
1342                                 /* This is CPU "all" */
1343                                 strcpy(item_name, "all");
1344                         }
1345                         else {
1346                                 sprintf(item_name, "%d", i - 1);
1347                         }
1348
1349                         if (DISPLAY_CPU_DEF(a->opt_flags)) {
1350                                 displayed = draw_activity_graphs(a->g_nr, g_type,
1351                                                                  title, g_title1, item_name, group1,
1352                                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
1353                                                                  svg_p, record_hdr, i, a, xid);
1354                         }
1355                         else {
1356                                 displayed = draw_activity_graphs(a->g_nr, g_type,
1357                                                                  title, g_title2, item_name, group2,
1358                                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
1359                                                                  svg_p, record_hdr, i, a, xid);
1360                         }
1361                         if (displayed) {
1362                                 xid++;
1363                         }
1364                 }
1365
1366                 /* Free remaining structures */
1367                 free_graphs(out, outsize, spmin, spmax);
1368         }
1369 }
1370
1371 /*
1372  ***************************************************************************
1373  * Display task creation and context switch statistics in SVG.
1374  *
1375  * IN:
1376  * @a           Activity structure with statistics.
1377  * @curr        Index in array for current sample statistics.
1378  * @action      Action expected from current function.
1379  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1380  *              flag indicating that a restart record has been previously
1381  *              found (.@restart) and time used for the X axis origin
1382  *              (@ust_time_ref).
1383  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1384  * @record_hdr  Pointer on record header of current stats sample.
1385  ***************************************************************************
1386  */
1387 __print_funct_t svg_print_pcsw_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1388                                      unsigned long long itv, struct record_header *record_hdr)
1389 {
1390         struct stats_pcsw
1391                 *spc = (struct stats_pcsw *) a->buf[curr],
1392                 *spp = (struct stats_pcsw *) a->buf[!curr];
1393         int group[] = {1, 1};
1394         int g_fields[] = {1, 0};
1395         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
1396         char *title[] = {"Task creation", "Switching activity"};
1397         char *g_title[] = {"proc/s",
1398                            "cswch/s"};
1399         static double *spmin, *spmax;
1400         static char **out;
1401         static int *outsize;
1402
1403         if (action & F_BEGIN) {
1404                 /*
1405                  * Allocate arrays that will contain the graphs data
1406                  * and the min/max values.
1407                  */
1408                 out = allocate_graph_lines(2, &outsize, &spmin, &spmax);
1409         }
1410
1411         if (action & F_MAIN) {
1412                 /* Check for min/max values */
1413                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
1414                              itv, spmin, spmax, g_fields);
1415                 /* proc/s */
1416                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1417                          S_VALUE(spp->processes, spc->processes, itv),
1418                          out, outsize, svg_p->restart);
1419                 /* cswch/s */
1420                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1421                          S_VALUE(spp->context_switch, spc->context_switch, itv),
1422                          out + 1, outsize + 1, svg_p->restart);
1423         }
1424
1425         if (action & F_END) {
1426                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
1427                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
1428
1429                 /* Free remaining structures */
1430                 free_graphs(out, outsize, spmin, spmax);
1431         }
1432 }
1433
1434 /*
1435  ***************************************************************************
1436  * Display swap statistics in SVG.
1437  *
1438  * IN:
1439  * @a           Activity structure with statistics.
1440  * @curr        Index in array for current sample statistics.
1441  * @action      Action expected from current function.
1442  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1443  *              flag indicating that a restart record has been previously
1444  *              found (.@restart) and time used for the X axis origin
1445  *              (@ust_time_ref).
1446  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1447  * @record_hdr  Pointer on record header of current stats sample.
1448  ***************************************************************************
1449  */
1450 __print_funct_t svg_print_swap_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1451                                      unsigned long long itv, struct record_header *record_hdr)
1452 {
1453         struct stats_swap
1454                 *ssc = (struct stats_swap *) a->buf[curr],
1455                 *ssp = (struct stats_swap *) a->buf[!curr];
1456         int group[] = {2};
1457         int g_type[] = {SVG_LINE_GRAPH};
1458         char *title[] = {"Swap activity"};
1459         char *g_title[] = {"pswpin/s", "pswpout/s" };
1460         int g_fields[] = {0, 1};
1461         static double *spmin, *spmax;
1462         static char **out;
1463         static int *outsize;
1464
1465         if (action & F_BEGIN) {
1466                 /*
1467                  * Allocate arrays that will contain the graphs data
1468                  * and the min/max values.
1469                  */
1470                 out = allocate_graph_lines(2, &outsize, &spmin, &spmax);
1471         }
1472
1473         if (action & F_MAIN) {
1474                 /* Check for min/max values */
1475                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
1476                              itv, spmin, spmax, g_fields);
1477                 /* pswpin/s */
1478                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1479                          S_VALUE(ssp->pswpin, ssc->pswpin, itv),
1480                          out, outsize, svg_p->restart);
1481                 /* pswpout/s */
1482                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1483                          S_VALUE(ssp->pswpout, ssc->pswpout, itv),
1484                          out + 1, outsize + 1, svg_p->restart);
1485         }
1486
1487         if (action & F_END) {
1488                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
1489                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
1490
1491                 /* Free remaining structures */
1492                 free_graphs(out, outsize, spmin, spmax);
1493         }
1494 }
1495
1496 /*
1497  ***************************************************************************
1498  * Display paging statistics in SVG.
1499  *
1500  * IN:
1501  * @a           Activity structure with statistics.
1502  * @curr        Index in array for current sample statistics.
1503  * @action      Action expected from current function.
1504  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1505  *              flag indicating that a restart record has been previously
1506  *              found (.@restart) and time used for the X axis origin
1507  *              (@ust_time_ref).
1508  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1509  * @record_hdr  Pointer on record header of current stats sample.
1510  ***************************************************************************
1511  */
1512 __print_funct_t svg_print_paging_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1513                                        unsigned long long itv, struct record_header *record_hdr)
1514 {
1515         struct stats_paging
1516                 *spc = (struct stats_paging *) a->buf[curr],
1517                 *spp = (struct stats_paging *) a->buf[!curr];
1518         int group[] = {2, 2, 4};
1519         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
1520         char *title[] = {"Paging activity (1)", "Paging activity (2)", "Paging activity (3)"};
1521         char *g_title[] = {"pgpgin/s", "pgpgout/s",
1522                            "fault/s", "majflt/s",
1523                            "pgfree/s", "pgscank/s", "pgscand/s", "pgsteal/s"};
1524         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7};
1525         static double *spmin, *spmax;
1526         static char **out;
1527         static int *outsize;
1528
1529         if (action & F_BEGIN) {
1530                 /*
1531                  * Allocate arrays that will contain the graphs data
1532                  * and the min/max values.
1533                  */
1534                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
1535         }
1536
1537         if (action & F_MAIN) {
1538                 /* Check for min/max values */
1539                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
1540                              itv, spmin, spmax, g_fields);
1541                 /* pgpgin/s */
1542                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1543                          S_VALUE(spp->pgpgin, spc->pgpgin, itv),
1544                          out, outsize, svg_p->restart);
1545                 /* pgpgout/s */
1546                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1547                          S_VALUE(spp->pgpgout, spc->pgpgout, itv),
1548                          out + 1, outsize + 1, svg_p->restart);
1549                 /* fault/s */
1550                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1551                          S_VALUE(spp->pgfault, spc->pgfault, itv),
1552                          out + 2, outsize + 2, svg_p->restart);
1553                 /* majflt/s */
1554                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1555                          S_VALUE(spp->pgmajfault, spc->pgmajfault, itv),
1556                          out + 3, outsize + 3, svg_p->restart);
1557                 /* pgfree/s */
1558                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1559                          S_VALUE(spp->pgfree, spc->pgfree, itv),
1560                          out + 4, outsize + 4, svg_p->restart);
1561                 /* pgscank/s */
1562                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1563                          S_VALUE(spp->pgscan_kswapd, spc->pgscan_kswapd, itv),
1564                          out + 5, outsize + 5, svg_p->restart);
1565                 /* pgscand/s */
1566                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1567                          S_VALUE(spp->pgscan_direct, spc->pgscan_direct, itv),
1568                          out + 6, outsize + 6, svg_p->restart);
1569                 /* pgsteal/s */
1570                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1571                          S_VALUE(spp->pgsteal, spc->pgsteal, itv),
1572                          out + 7, outsize + 7, svg_p->restart);
1573         }
1574
1575         if (action & F_END) {
1576                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
1577                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
1578
1579                 /* Free remaining structures */
1580                 free_graphs(out, outsize, spmin, spmax);
1581         }
1582 }
1583
1584 /*
1585  ***************************************************************************
1586  * Display I/O and transfer rate statistics in SVG.
1587  *
1588  * IN:
1589  * @a           Activity structure with statistics.
1590  * @curr        Index in array for current sample statistics.
1591  * @action      Action expected from current function.
1592  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1593  *              flag indicating that a restart record has been previously
1594  *              found (.@restart) and time used for the X axis origin
1595  *              (@ust_time_ref).
1596  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1597  * @record_hdr  Pointer on record header of current stats sample.
1598  ***************************************************************************
1599  */
1600 __print_funct_t svg_print_io_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1601                                    unsigned long long itv, struct record_header *record_hdr)
1602 {
1603         struct stats_io
1604                 *sic = (struct stats_io *) a->buf[curr],
1605                 *sip = (struct stats_io *) a->buf[!curr];
1606         int group[] = {4, 3};
1607         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
1608         char *title[] = {"I/O and transfer rate statistics (1)", "I/O and transfer rate statistics (2)"};
1609         char *g_title[] = {"tps", "rtps", "wtps", "dtps",
1610                            "bread/s", "bwrtn/s", "bdscd/s"};
1611         /*
1612          * tps:0, rtps:1, wtps:2, dtps:3, bread/s:4, bwrtn/s:5, bdscd/s:6
1613          * g_fields[]:
1614          *      dk_drive=0
1615          *      dk_drive_rio:1
1616          *      dk_drive_wio:2
1617          *      dk_drive_rblk:4
1618          *      dk_drive_wblk:5
1619          *      dk_drive_dio:3
1620          *      dk_drive_dblk:6
1621          */
1622         int g_fields[] = {0, 1, 2, 4, 5, 3, 6};
1623         static double *spmin, *spmax;
1624         static char **out;
1625         static int *outsize;
1626
1627         if (action & F_BEGIN) {
1628                 /*
1629                  * Allocate arrays that will contain the graphs data
1630                  * and the min/max values.
1631                  */
1632                 out = allocate_graph_lines(7, &outsize, &spmin, &spmax);
1633         }
1634
1635         if (action & F_MAIN) {
1636                 /* Check for min/max values */
1637                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
1638                              itv, spmin, spmax, g_fields);
1639
1640                 /*
1641                  * If we get negative values, this is probably because
1642                  * one or more devices/filesystems have been unmounted.
1643                  * We display 0.0 in this case though we should rather tell
1644                  * the user that the value cannot be calculated here.
1645                  */
1646                 /* tps */
1647                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1648                          sic->dk_drive < sip->dk_drive ? 0.0 :
1649                          S_VALUE(sip->dk_drive, sic->dk_drive, itv),
1650                          out, outsize, svg_p->restart);
1651                 /* rtps */
1652                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1653                          sic->dk_drive_rio < sip->dk_drive_rio ? 0.0 :
1654                          S_VALUE(sip->dk_drive_rio, sic->dk_drive_rio, itv),
1655                          out + 1, outsize + 1, svg_p->restart);
1656                 /* wtps */
1657                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1658                          sic->dk_drive_wio < sip->dk_drive_wio ? 0.0 :
1659                          S_VALUE(sip->dk_drive_wio, sic->dk_drive_wio, itv),
1660                          out + 2, outsize + 2, svg_p->restart);
1661                 /* dtps */
1662                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1663                          sic->dk_drive_dio < sip->dk_drive_dio ? 0.0 :
1664                          S_VALUE(sip->dk_drive_dio, sic->dk_drive_dio, itv),
1665                          out + 3, outsize + 3, svg_p->restart);
1666                 /* bread/s */
1667                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1668                          sic->dk_drive_rblk < sip->dk_drive_rblk ? 0.0 :
1669                          S_VALUE(sip->dk_drive_rblk, sic->dk_drive_rblk, itv),
1670                          out + 4, outsize + 4, svg_p->restart);
1671                 /* bwrtn/s */
1672                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1673                          sic->dk_drive_wblk < sip->dk_drive_wblk ? 0.0 :
1674                          S_VALUE(sip->dk_drive_wblk, sic->dk_drive_wblk, itv),
1675                          out + 5, outsize + 5, svg_p->restart);
1676                 /* bdscd/s */
1677                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1678                          sic->dk_drive_dblk < sip->dk_drive_dblk ? 0.0 :
1679                          S_VALUE(sip->dk_drive_dblk, sic->dk_drive_dblk, itv),
1680                          out + 6, outsize + 6, svg_p->restart);
1681         }
1682
1683         if (action & F_END) {
1684                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
1685                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
1686
1687                 /* Free remaining structures */
1688                 free_graphs(out, outsize, spmin, spmax);
1689         }
1690 }
1691
1692 /*
1693  ***************************************************************************
1694  * Display memory statistics in SVG.
1695  *
1696  * IN:
1697  * @a           Activity structure with statistics.
1698  * @curr        Index in array for current sample statistics.
1699  * @action      Action expected from current function.
1700  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1701  *              flag indicating that a restart record has been previously
1702  *              found (.@restart) and time used for the X axis origin
1703  *              (@ust_time_ref).
1704  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1705  * @record_hdr  Pointer on record header of current stats sample.
1706  ***************************************************************************
1707  */
1708 __print_funct_t svg_print_memory_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1709                                        unsigned long long itv, struct record_header *record_hdr)
1710 {
1711         struct stats_memory
1712                 *smc = (struct stats_memory *) a->buf[curr];
1713         int group1[] = {3, 1, 3, 1, 3, 5};
1714         int g_type1[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH, SVG_LINE_GRAPH,
1715                          SVG_BAR_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
1716         int group2[] = {3, 1, 1};
1717         int g_type2[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH, SVG_BAR_GRAPH};
1718         char *title1[] = {"Memory utilization (1)", "Memory utilization (2)",
1719                           "Memory utilization (3)", "Memory utilization (4)",
1720                           "Memory utilization (5)", "Memory utilization (6)"};
1721         char *title2[] = {"Swap utilization (1)", "Swap utilization (2)",
1722                           "Swap utilization (3)"};
1723         char *g_title1[] = {"MBmemfree", "MBavail", "MBmemused", "%memused", "MBbuffers",
1724                             "MBcached", "MBcommit", "%commit", "MBactive", "MBinact",
1725                             "MBdirty", "MBanonpg", "MBslab", "MBkstack", "MBpgtbl",
1726                             "MBvmused"};
1727         char *g_title2[] = {"MBswpfree", "MBswpused", "MBswpcad", "%swpused",
1728                             "%swpcad"};
1729         int g_fields[] = {0, 4, 5, 21, 16, 22, 18, 6, 8, 9, 10, 11, 12, 13, 14, 15, 1};
1730         static double *spmin, *spmax;
1731         static char **out;
1732         static int *outsize;
1733         static int xid = 0;
1734         double tval;
1735         int i;
1736         unsigned long long nousedmem;
1737
1738         if (action & F_BEGIN) {
1739                 /*
1740                  * Allocate arrays that will contain the graphs data
1741                  * and the min/max values.
1742                  */
1743                 out = allocate_graph_lines(23, &outsize, &spmin, &spmax);
1744         }
1745
1746         if (action & F_MAIN) {
1747                 /* Check for min/max values */
1748                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
1749                              itv, spmin, spmax, g_fields);
1750                 /* Compute %memused min/max values */
1751                 nousedmem = smc->frmkb + smc->bufkb + smc->camkb + smc->slabkb;
1752                 if (nousedmem > smc->tlmkb) {
1753                         nousedmem = smc->tlmkb;
1754                 }
1755                 tval = smc->tlmkb ? SP_VALUE(nousedmem, smc->tlmkb, smc->tlmkb) : 0.0;
1756                 if (tval > *(spmax + 3)) {
1757                         *(spmax + 3) = tval;
1758                 }
1759                 if (tval < *(spmin + 3)) {
1760                         *(spmin + 3) = tval;
1761                 }
1762                 /* Compute %commit min/max values */
1763                 tval = (smc->tlmkb + smc->tlskb) ?
1764                        SP_VALUE(0, smc->comkb, smc->tlmkb + smc->tlskb) : 0.0;
1765                 if (tval > *(spmax + 7)) {
1766                         *(spmax + 7) = tval;
1767                 }
1768                 if (tval < *(spmin + 7)) {
1769                         *(spmin + 7) = tval;
1770                 }
1771                 /* Compute %swpused min/max values */
1772                 tval = smc->tlskb ?
1773                        SP_VALUE(smc->frskb, smc->tlskb, smc->tlskb) : 0.0;
1774                 if (tval > *(spmax + 19)) {
1775                         *(spmax + 19) = tval;
1776                 }
1777                 if (tval < *(spmin + 19)) {
1778                         *(spmin + 19) = tval;
1779                 }
1780                 /* Compute %swpcad min/max values */
1781                 tval = (smc->tlskb - smc->frskb) ?
1782                        SP_VALUE(0, smc->caskb, smc->tlskb - smc->frskb) : 0.0;
1783                 if (tval > *(spmax + 20)) {
1784                         *(spmax + 20) = tval;
1785                 }
1786                 if (tval < *(spmin + 20)) {
1787                         *(spmin + 20) = tval;
1788                 }
1789                 /* Compute memused min/max values in MB */
1790                 tval = ((double) (smc->tlmkb - nousedmem)) / 1024;
1791                 if (tval > *(spmax + 2)) {
1792                         *(spmax + 2) = tval;
1793                 }
1794                 if (tval < *(spmin + 2)) {
1795                         *(spmin + 2) = tval;
1796                 }
1797                 /* Compute swpused min/max values in MB */
1798                 tval = ((double) (smc->tlskb - smc->frskb)) / 1024;
1799                 if (tval > *(spmax + 17)) {
1800                         *(spmax + 17) = tval;
1801                 }
1802                 if (tval < *(spmin + 17)) {
1803                         *(spmin + 17) = tval;
1804                 }
1805
1806                 /* MBmemfree */
1807                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1808                          ((double) smc->frmkb) / 1024,
1809                          out, outsize, svg_p->restart);
1810                 /* MBmemused */
1811                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1812                          ((double) (smc->tlmkb - nousedmem)) / 1024,
1813                          out + 2, outsize + 2, svg_p->restart);
1814                 /* MBavail */
1815                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1816                          ((double) smc->availablekb) / 1024,
1817                          out + 1, outsize + 1, svg_p->restart);
1818                 /* MBbuffers */
1819                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1820                          ((double) smc->bufkb) / 1024,
1821                          out + 4, outsize + 4, svg_p->restart);
1822                 /* MBcached */
1823                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1824                          ((double) smc->camkb) / 1024,
1825                           out + 5, outsize + 5, svg_p->restart);
1826                 /* MBswpfree */
1827                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1828                          ((double) smc->frskb) / 1024,
1829                          out + 16, outsize + 16, svg_p->restart);
1830                 /* MBswpused */
1831                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1832                          ((double) (smc->tlskb - smc->frskb)) / 1024,
1833                          out + 17, outsize + 17, svg_p->restart);
1834                 /* MBswpcad */
1835                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1836                          ((double) smc->caskb) / 1024,
1837                          out + 18, outsize + 18, svg_p->restart);
1838                 /* MBcommit */
1839                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1840                          ((double) smc->comkb) / 1024,
1841                          out + 6, outsize + 6, svg_p->restart);
1842                 /* MBactive */
1843                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1844                          ((double) smc->activekb) / 1024,
1845                          out + 8, outsize + 8, svg_p->restart);
1846                 /* MBinact */
1847                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1848                          ((double) smc->inactkb) / 1024,
1849                          out + 9, outsize + 9, svg_p->restart);
1850                 /* MBdirty */
1851                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1852                          ((double) smc->dirtykb) / 1024,
1853                          out + 10, outsize + 10, svg_p->restart);
1854                 /* MBanonpg */
1855                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1856                          ((double) smc->anonpgkb) / 1024,
1857                          out + 11, outsize + 11, svg_p->restart);
1858                 /* MBslab */
1859                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1860                          ((double) smc->slabkb) / 1024,
1861                          out + 12, outsize + 12, svg_p->restart);
1862                 /* MBkstack */
1863                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1864                          ((double) smc->kstackkb) / 1024,
1865                          out + 13, outsize + 13, svg_p->restart);
1866                 /* MBpgtbl */
1867                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1868                          ((double) smc->pgtblkb) / 1024,
1869                          out + 14, outsize + 14, svg_p->restart);
1870                 /* MBvmused */
1871                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1872                          ((double) smc->vmusedkb) / 1024,
1873                          out + 15, outsize + 15, svg_p->restart);
1874                 /* %memused */
1875                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1876                          0.0,
1877                          smc->tlmkb ?
1878                          SP_VALUE(nousedmem, smc->tlmkb, smc->tlmkb) : 0.0,
1879                          out + 3, outsize + 3, svg_p->dt);
1880                 /* %commit */
1881                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1882                          0.0,
1883                          (smc->tlmkb + smc->tlskb) ?
1884                          SP_VALUE(0, smc->comkb, smc->tlmkb + smc->tlskb) : 0.0,
1885                          out + 7, outsize + 7, svg_p->dt);
1886                 /* %swpused */
1887                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1888                          0.0,
1889                          smc->tlskb ?
1890                          SP_VALUE(smc->frskb, smc->tlskb, smc->tlskb) : 0.0,
1891                          out + 19, outsize + 19, svg_p->dt);
1892                 /* %swpcad */
1893                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1894                          0.0,
1895                          (smc->tlskb - smc->frskb) ?
1896                          SP_VALUE(0, smc->caskb, smc->tlskb - smc->frskb) : 0.0,
1897                          out + 20, outsize + 20, svg_p->dt);
1898         }
1899
1900         if (action & F_END) {
1901
1902                 /* Conversion kB -> MB */
1903                 for (i = 0; i < 17; i++) {
1904                         *(spmin + g_fields[i]) /= 1024;
1905                         *(spmax + g_fields[i]) /= 1024;
1906                 }
1907
1908                 if (DISPLAY_MEMORY(a->opt_flags)) {
1909                         if (draw_activity_graphs(DISPLAY_MEM_ALL(a->opt_flags) ? 6 : 5,
1910                                                  g_type1, title1, g_title1, NULL, group1,
1911                                                  spmin, spmax, out, outsize, svg_p, record_hdr,
1912                                                  FALSE, a, xid)) {
1913                                 xid++;
1914                         }
1915                 }
1916
1917                 if (DISPLAY_SWAP(a->opt_flags)) {
1918                         draw_activity_graphs(3, g_type2, title2, g_title2, NULL, group2,
1919                                              spmin + 16, spmax + 16, out + 16, outsize + 16,
1920                                              svg_p, record_hdr, FALSE, a, xid);
1921                 }
1922
1923                 /* Free remaining structures */
1924                 free_graphs(out, outsize, spmin, spmax);
1925         }
1926 }
1927
1928 /*
1929  ***************************************************************************
1930  * Display kernel tables statistics in SVG.
1931  *
1932  * IN:
1933  * @a           Activity structure with statistics.
1934  * @curr        Index in array for current sample statistics.
1935  * @action      Action expected from current function.
1936  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1937  *              flag indicating that a restart record has been previously
1938  *              found (.@restart) and time used for the X axis origin
1939  *              (@ust_time_ref).
1940  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1941  * @record_hdr  Pointer on record header of current stats sample.
1942  ***************************************************************************
1943  */
1944 __print_funct_t svg_print_ktables_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1945                                         unsigned long long itv, struct record_header *record_hdr)
1946 {
1947         struct stats_ktables
1948                 *skc = (struct stats_ktables *) a->buf[curr];
1949         int group[] = {3, 1};
1950         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
1951         char *title[] = {"Kernel tables statistics (1)", "Kernel tables statistics (2)"};
1952         char *g_title[] = {"~dentunusd", "~file-nr", "~inode-nr",
1953                            "~pty-nr"};
1954         int g_fields[] = {1, 2, 0, 3};
1955         static double *spmin, *spmax;
1956         static char **out;
1957         static int *outsize;
1958
1959         if (action & F_BEGIN) {
1960                 /*
1961                  * Allocate arrays that will contain the graphs data
1962                  * and the min/max values.
1963                  */
1964                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
1965         }
1966
1967         if (action & F_MAIN) {
1968                 /* Check for min/max values */
1969                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
1970                              itv, spmin, spmax, g_fields);
1971                 /* dentunusd */
1972                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1973                           (unsigned long long) skc->dentry_stat,
1974                           out, outsize, svg_p->restart);
1975                 /* file-nr */
1976                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1977                           (unsigned long long) skc->file_used,
1978                           out + 1, outsize + 1, svg_p->restart);
1979                 /* inode-nr */
1980                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1981                           (unsigned long long) skc->inode_used,
1982                           out + 2, outsize + 2, svg_p->restart);
1983                 /* pty-nr */
1984                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1985                           (unsigned long long) skc->pty_nr,
1986                           out + 3, outsize + 3, svg_p->restart);
1987         }
1988
1989         if (action & F_END) {
1990                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
1991                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
1992
1993                 /* Free remaining structures */
1994                 free_graphs(out, outsize, spmin, spmax);
1995         }
1996 }
1997
1998 /*
1999  ***************************************************************************
2000  * Display queue and load statistics in SVG.
2001  *
2002  * IN:
2003  * @a           Activity structure with statistics.
2004  * @curr        Index in array for current sample statistics.
2005  * @action      Action expected from current function.
2006  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2007  *              flag indicating that a restart record has been previously
2008  *              found (.@restart) and time used for the X axis origin
2009  *              (@ust_time_ref).
2010  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2011  * @record_hdr  Pointer on record header of current stats sample.
2012  ***************************************************************************
2013  */
2014 __print_funct_t svg_print_queue_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2015                                       unsigned long long itv, struct record_header *record_hdr)
2016 {
2017         struct stats_queue
2018                 *sqc = (struct stats_queue *) a->buf[curr];
2019         int group[] = {2, 1, 3};
2020         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2021         char *title[] = {"Queue length", "Task list statistics", "Load average statistics"};
2022         char *g_title[] = {"~runq-sz", "~blocked",
2023                            "~plist-sz",
2024                            "ldavg-1", "ldavg-5", "ldavg-15"};
2025         int g_fields[] = {0, 1, 2, 3, 4, 5};
2026         static double *spmin, *spmax;
2027         static char **out;
2028         static int *outsize;
2029
2030         if (action & F_BEGIN) {
2031                 /*
2032                  * Allocate arrays that will contain the graphs data
2033                  * and the min/max values.
2034                  */
2035                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
2036         }
2037
2038         if (action & F_MAIN) {
2039                 /* Check for min/max values */
2040                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
2041                              itv, spmin, spmax, g_fields);
2042                 /* runq-sz */
2043                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2044                           (unsigned long long) sqc->nr_running,
2045                           out, outsize, svg_p->restart);
2046                 /* blocked */
2047                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2048                           (unsigned long long) sqc->procs_blocked,
2049                           out + 1, outsize + 1, svg_p->restart);
2050                 /* plist-sz */
2051                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2052                           (unsigned long long) sqc->nr_threads,
2053                           out + 2, outsize + 2, svg_p->restart);
2054                 /* ldavg-1 */
2055                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2056                          (double) sqc->load_avg_1 / 100,
2057                          out + 3, outsize + 3, svg_p->restart);
2058                 /* ldavg-5 */
2059                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2060                          (double) sqc->load_avg_5 / 100,
2061                          out + 4, outsize + 4, svg_p->restart);
2062                 /* ldavg-15 */
2063                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2064                          (double) sqc->load_avg_15 / 100,
2065                          out + 5, outsize + 5, svg_p->restart);
2066         }
2067
2068         if (action & F_END) {
2069                 /* Fix min/max values for load average */
2070                 *(spmin + 3) /= 100; *(spmax + 3) /= 100;
2071                 *(spmin + 4) /= 100; *(spmax + 4) /= 100;
2072                 *(spmin + 5) /= 100; *(spmax + 5) /= 100;
2073
2074                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2075                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
2076
2077                 /* Free remaining structures */
2078                 free_graphs(out, outsize, spmin, spmax);
2079         }
2080 }
2081
2082 /*
2083  ***************************************************************************
2084  * Display disk statistics in SVG.
2085  *
2086  * IN:
2087  * @a           Activity structure with statistics.
2088  * @curr        Index in array for current sample statistics.
2089  * @action      Action expected from current function.
2090  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2091  *              flag indicating that a restart record has been previously
2092  *              found (.@restart) and time used for the X axis origin
2093  *              (@ust_time_ref).
2094  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2095  * @record_hdr  Pointer on record header of current stats sample.
2096  ***************************************************************************
2097  */
2098 #define DISK_ARRAY_SZ   9
2099 __print_funct_t svg_print_disk_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2100                                      unsigned long long itv, struct record_header *record_hdr)
2101 {
2102         struct stats_disk *sdc, *sdp, sdpzero;
2103         struct ext_disk_stats xds;
2104         int group[] = {1, 3, 2, 1, 1};
2105         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2106                         SVG_LINE_GRAPH, SVG_BAR_GRAPH};
2107         char *title[] = {"Block devices statistics (1)", "Block devices statistics (2)",
2108                          "Block devices statistics (3)", "Block devices statistics (4)",
2109                          "Block devices statistics (5)"};
2110         char *g_title[] = {"tps",
2111                            "rkB/s", "wkB/s", "dkB/s",
2112                            "areq-sz", "aqu-sz",
2113                            "await",
2114                            "%util"};
2115         int g_fields[] = {0, 1, 2};
2116         unsigned int local_types_nr[] = {1, 0, 0};
2117         static double *spmin, *spmax;
2118         static char **out;
2119         static int *outsize;
2120         char *dev_name, *item_name;
2121         double rkB, wkB, dkB, aqusz;
2122         int i, j, k, pos, restart, *unregistered;
2123
2124         if (action & F_BEGIN) {
2125                 /*
2126                  * Allocate arrays (#0..7) that will contain the graphs data
2127                  * and the min/max values.
2128                  * Also allocate one additional array (#8) for each disk device:
2129                  * out + 8 will contain the device name (WWN id, pretty name or devm-n),
2130                  * outsize + 8 will contain a positive value (TRUE) if the device
2131                  * has either still not been registered, or has been unregistered.
2132                  */
2133                 out = allocate_graph_lines(DISK_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
2134         }
2135
2136         if (action & F_MAIN) {
2137                 memset(&sdpzero, 0, STATS_DISK_SIZE);
2138                 /*
2139                  * Mark previously registered devices as now
2140                  * possibly unregistered for all graphs.
2141                  */
2142                 for (k = 0; k < a->item_list_sz; k++) {
2143                         unregistered = outsize + k * DISK_ARRAY_SZ + 8;
2144                         if (*unregistered == FALSE) {
2145                                 *unregistered = MAYBE;
2146                         }
2147                 }
2148
2149                 /* For each device structure */
2150                 for (i = 0; i < a->nr[curr]; i++) {
2151                         sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
2152                         restart = svg_p->restart;
2153
2154                         /* Get device name  */
2155                         dev_name = get_device_name(sdc->major, sdc->minor, sdc->wwn, sdc->part_nr,
2156                                                    DISPLAY_PRETTY(flags), DISPLAY_PERSIST_NAME_S(flags),
2157                                                    USE_STABLE_ID(flags), NULL);
2158
2159                         if (a->item_list != NULL) {
2160                                 /* A list of devices has been entered on the command line */
2161                                 if (!search_list_item(a->item_list, dev_name))
2162                                         /* Device not found */
2163                                         continue;
2164                         }
2165
2166                         /* Look for corresponding graph */
2167                         for (k = 0; k < a->item_list_sz; k++) {
2168                                 item_name = *(out + k * DISK_ARRAY_SZ + 8);
2169                                 if (!strcmp(dev_name, item_name))
2170                                         /* Graph found! */
2171                                         break;
2172                         }
2173                         if (k == a->item_list_sz) {
2174                                 /* Graph not found: Look for first free entry */
2175                                 for (k = 0; k < a->item_list_sz; k++) {
2176                                         item_name = *(out + k * DISK_ARRAY_SZ + 8);
2177                                         if (!strcmp(item_name, ""))
2178                                                 break;
2179                                 }
2180                                 if (k == a->item_list_sz) {
2181                                         /* No free graph entry: Ignore it (should never happen) */
2182 #ifdef DEBUG
2183                                         fprintf(stderr, "%s: Name=%s major=%d minor=%d\n",
2184                                                 __FUNCTION__, dev_name, sdc->major, sdc->minor);
2185 #endif
2186                                         continue;
2187                                 }
2188                         }
2189                         pos = k * DISK_ARRAY_SZ;
2190                         unregistered = outsize + pos + 8;
2191
2192                         /*
2193                          * If current device was marked as previously unregistered,
2194                          * then set restart variable to TRUE so that the graph will be
2195                          * discontinuous, and mark it as now registered.
2196                          */
2197                         if (*unregistered == TRUE) {
2198                                 restart = TRUE;
2199                         }
2200                         *unregistered = FALSE;
2201
2202                         item_name = *(out + pos + 8);
2203                         if (!item_name[0]) {
2204                                 /* Save device name (WWN id or pretty name) if not already done */
2205                                 strncpy(item_name, dev_name, CHUNKSIZE);
2206                                 item_name[CHUNKSIZE - 1] = '\0';
2207                         }
2208
2209                         j = check_disk_reg(a, curr, !curr, i);
2210                         if (j < 0) {
2211                                 /* This is a newly registered interface. Previous stats are zero */
2212                                 sdp = &sdpzero;
2213                                 restart = TRUE;
2214                         }
2215                         else {
2216                                 sdp = (struct stats_disk *) ((char *) a->buf[!curr] + j * a->msize);
2217                         }
2218
2219                         /* Check for min/max values */
2220                         save_extrema(local_types_nr, (void *) sdc, (void *) sdp,
2221                                      itv, spmin + pos, spmax + pos, g_fields);
2222
2223                         rkB = S_VALUE(sdp->rd_sect, sdc->rd_sect, itv) / 2;
2224                         wkB = S_VALUE(sdp->wr_sect, sdc->wr_sect, itv) / 2;
2225                         dkB = S_VALUE(sdp->dc_sect, sdc->dc_sect, itv) / 2;
2226                         if (rkB < *(spmin + pos + 1)) {
2227                                 *(spmin + pos + 1) = rkB;
2228                         }
2229                         if (rkB > *(spmax + pos + 1)) {
2230                                 *(spmax + pos + 1) = rkB;
2231                         }
2232                         if (wkB < *(spmin + pos + 2)) {
2233                                 *(spmin + pos + 2) = wkB;
2234                         }
2235                         if (wkB > *(spmax + pos + 2)) {
2236                                 *(spmax + pos + 2) = wkB;
2237                         }
2238                         if (dkB < *(spmin + pos + 3)) {
2239                                 *(spmin + pos + 3) = dkB;
2240                         }
2241                         if (dkB > *(spmax + pos + 3)) {
2242                                 *(spmax + pos + 3) = dkB;
2243                         }
2244
2245                         compute_ext_disk_stats(sdc, sdp, itv, &xds);
2246                         if ((xds.arqsz / 2) < *(spmin + pos + 4)) {
2247                                 *(spmin + pos + 4) = xds.arqsz / 2;
2248                         }
2249                         if ((xds.arqsz / 2) > *(spmax + pos + 4)) {
2250                                 *(spmax + pos + 4) = xds.arqsz / 2;
2251                         }
2252                         aqusz = S_VALUE(sdp->rq_ticks, sdc->rq_ticks, itv) / 1000.0;
2253                         if (aqusz < *(spmin + pos + 5)) {
2254                                 *(spmin + pos + 5) = aqusz;
2255                         }
2256                         if (aqusz > *(spmax + pos + 5)) {
2257                                 *(spmax + pos + 5) = aqusz;
2258                         }
2259                         if (xds.await < *(spmin + pos + 6)) {
2260                                 *(spmin + pos + 6) = xds.await;
2261                         }
2262                         if (xds.await > *(spmax + pos + 6)) {
2263                                 *(spmax + pos + 6) = xds.await;
2264                         }
2265                         if ((xds.util / 10.0) < *(spmin + pos + 7)) {
2266                                 *(spmin + pos + 7) = xds.util / 10.0;
2267                         }
2268                         if ((xds.util / 10.0) > *(spmax + pos + 7)) {
2269                                 *(spmax + pos + 7) = xds.util / 10.0;
2270                         }
2271
2272                         /* tps */
2273                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2274                                  S_VALUE(sdp->nr_ios, sdc->nr_ios, itv),
2275                                  out + pos, outsize + pos, restart);
2276                         /* rkB/s */
2277                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2278                                  S_VALUE(sdp->rd_sect, sdc->rd_sect, itv) / 2,
2279                                  out + pos + 1, outsize + pos + 1, restart);
2280                         /* wkB/s */
2281                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2282                                  S_VALUE(sdp->wr_sect, sdc->wr_sect, itv) / 2,
2283                                  out + pos + 2, outsize + pos + 2, restart);
2284                         /* dkB/s */
2285                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2286                                  S_VALUE(sdp->dc_sect, sdc->dc_sect, itv) / 2,
2287                                  out + pos + 3, outsize + pos + 3, restart);
2288                         /* areq-sz */
2289                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2290                                  xds.arqsz / 2,
2291                                  out + pos + 4, outsize + pos + 4, restart);
2292                         /* aqu-sz */
2293                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2294                                  aqusz,
2295                                  out + pos + 5, outsize + pos + 5, restart);
2296                         /* await */
2297                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2298                                  xds.await,
2299                                  out + pos + 6, outsize + pos + 6, restart);
2300                         /* %util */
2301                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
2302                                  0.0, xds.util / 10.0,
2303                                  out + pos + 7, outsize + pos + 7, svg_p->dt);
2304                 }
2305
2306                 /* Mark devices not seen here as now unregistered */
2307                 for (k = 0; k < a->item_list_sz; k++) {
2308                         unregistered = outsize + k * DISK_ARRAY_SZ + 8;
2309                         if (*unregistered != FALSE) {
2310                                 *unregistered = TRUE;
2311                         }
2312                 }
2313         }
2314
2315         if (action & F_END) {
2316                 int xid = 0;
2317
2318                 for (i = 0; i < a->item_list_sz; i++) {
2319                         /* Check if there is something to display */
2320                         pos = i * DISK_ARRAY_SZ;
2321                         if (!**(out + pos))
2322                                 continue;
2323
2324                         item_name = *(out + pos + 8);
2325                         if (draw_activity_graphs(a->g_nr, g_type,
2326                                                  title, g_title, item_name, group,
2327                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2328                                                  svg_p, record_hdr, FALSE, a, xid)) {
2329                                 xid++;
2330                         }
2331                 }
2332
2333                 /* Free remaining structures */
2334                 free_graphs(out, outsize, spmin, spmax);
2335         }
2336 }
2337
2338 /*
2339  ***************************************************************************
2340  * Display network interfaces statistics in SVG.
2341  *
2342  * IN:
2343  * @a           Activity structure with statistics.
2344  * @curr        Index in array for current sample statistics.
2345  * @action      Action expected from current function.
2346  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2347  *              flag indicating that a restart record has been previously
2348  *              found (.@restart) and time used for the X axis origin
2349  *              (@ust_time_ref).
2350  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2351  * @record_hdr  Pointer on record header of current stats sample.
2352  ***************************************************************************
2353  */
2354 #define NET_DEV_ARRAY_SZ        9
2355 __print_funct_t svg_print_net_dev_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2356                                         unsigned long long itv, struct record_header *record_hdr)
2357 {
2358         struct stats_net_dev *sndc, *sndp, sndzero;
2359         int group[] = {2, 2, 3, 1};
2360         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2361                         SVG_BAR_GRAPH};
2362         char *title[] = {"Network interfaces statistics (1)", "Network interfaces statistics (2)",
2363                          "Network interfaces statistics (3)", "Network interfaces statistics (4)"};
2364         char *g_title[] = {"rxpck/s", "txpck/s",
2365                            "rxkB/s", "txkB/s",
2366                            "rxcmp/s", "txcmp/s", "rxmcst/s",
2367                            "%ifutil"};
2368         int g_fields[] = {0, 1, 2, 3, 4, 5, 6};
2369         unsigned int local_types_nr[] = {7, 0, 0};
2370         static double *spmin, *spmax;
2371         static char **out;
2372         static int *outsize;
2373         char *item_name;
2374         double rxkb, txkb, ifutil;
2375         int i, j, k, pos, restart, *unregistered;
2376
2377         if (action & F_BEGIN) {
2378                 /*
2379                  * Allocate arrays (#0..7) that will contain the graphs data
2380                  * and the min/max values.
2381                  * Also allocate one additional array (#8) for each interface:
2382                  * out + 8 will contain the interface name,
2383                  * outsize + 8 will contain a positive value (TRUE) if the interface
2384                  * has either still not been registered, or has been unregistered.
2385                  */
2386                 out = allocate_graph_lines(NET_DEV_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
2387         }
2388
2389         if (action & F_MAIN) {
2390                 memset(&sndzero, 0, STATS_NET_DEV_SIZE);
2391                 /*
2392                  * Mark previously registered interfaces as now
2393                  * possibly unregistered for all graphs.
2394                  */
2395                 for (k = 0; k < a->item_list_sz; k++) {
2396                         unregistered = outsize + k * NET_DEV_ARRAY_SZ + 8;
2397                         if (*unregistered == FALSE) {
2398                                 *unregistered = MAYBE;
2399                         }
2400                 }
2401
2402                 /* For each network interfaces structure */
2403                 for (i = 0; i < a->nr[curr]; i++) {
2404                         sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
2405                         restart = svg_p->restart;
2406
2407                         if (a->item_list != NULL) {
2408                                 /* A list of devices has been entered on the command line */
2409                                 if (!search_list_item(a->item_list, sndc->interface))
2410                                         /* Device not found */
2411                                         continue;
2412                         }
2413
2414                         /* Look for corresponding graph */
2415                         for (k = 0; k < a->item_list_sz; k++) {
2416                                 item_name = *(out + k * NET_DEV_ARRAY_SZ + 8);
2417                                 if (!strcmp(sndc->interface, item_name))
2418                                         /* Graph found! */
2419                                         break;
2420                         }
2421                         if (k == a->item_list_sz) {
2422                                 /* Graph not found: Look for first free entry */
2423                                 for (k = 0; k < a->item_list_sz; k++) {
2424                                         item_name = *(out + k * NET_DEV_ARRAY_SZ + 8);
2425                                         if (!strcmp(item_name, ""))
2426                                                 break;
2427                                 }
2428                                 if (k == a->item_list_sz) {
2429                                         /* No free graph entry: Ignore it (should never happen) */
2430 #ifdef DEBUG
2431                                         fprintf(stderr, "%s: Name=%s\n",
2432                                                 __FUNCTION__, sndc->interface);
2433 #endif
2434                                         continue;
2435                                 }
2436                         }
2437                         pos = k * NET_DEV_ARRAY_SZ;
2438                         unregistered = outsize + pos + 8;
2439
2440                         j = check_net_dev_reg(a, curr, !curr, i);
2441                         if (j < 0) {
2442                                 /* This is a newly registered interface. Previous stats are zero */
2443                                 sndp = &sndzero;
2444                                 restart = TRUE;
2445                         }
2446                         else {
2447                                 sndp = (struct stats_net_dev *) ((char *) a->buf[!curr] + j * a->msize);
2448                         }
2449
2450                         /*
2451                          * If current interface was marked as previously unregistered,
2452                          * then set restart variable to TRUE so that the graph will be
2453                          * discontinuous, and mark it as now registered.
2454                          */
2455                         if (*unregistered == TRUE) {
2456                                 restart = TRUE;
2457                         }
2458                         *unregistered = FALSE;
2459
2460                         item_name = *(out + pos + 8);
2461                         if (!item_name[0]) {
2462                                 /* Save network interface name (if not already done) */
2463                                 strncpy(item_name, sndc->interface, CHUNKSIZE);
2464                                 item_name[CHUNKSIZE - 1] = '\0';
2465                         }
2466
2467                         /* Check for min/max values */
2468                         save_extrema(local_types_nr, (void *) sndc, (void *) sndp,
2469                                      itv, spmin + pos, spmax + pos, g_fields);
2470
2471                         rxkb = S_VALUE(sndp->rx_bytes, sndc->rx_bytes, itv);
2472                         txkb = S_VALUE(sndp->tx_bytes, sndc->tx_bytes, itv);
2473                         ifutil = compute_ifutil(sndc, rxkb, txkb);
2474                         if (ifutil < *(spmin + pos + 7)) {
2475                                 *(spmin + pos + 7) = ifutil;
2476                         }
2477                         if (ifutil > *(spmax + pos + 7)) {
2478                                 *(spmax + pos + 7) = ifutil;
2479                         }
2480
2481                         /* rxpck/s */
2482                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2483                                  S_VALUE(sndp->rx_packets, sndc->rx_packets, itv),
2484                                  out + pos, outsize + pos, restart);
2485                         /* txpck/s */
2486                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2487                                  S_VALUE(sndp->tx_packets, sndc->tx_packets, itv),
2488                                  out + pos + 1, outsize + pos + 1, restart);
2489                         /* rxkB/s */
2490                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2491                                  rxkb / 1024,
2492                                  out + pos + 2, outsize + pos + 2, restart);
2493                         /* txkB/s */
2494                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2495                                  txkb / 1024,
2496                                  out + pos + 3, outsize + pos + 3, restart);
2497                         /* rxcmp/s */
2498                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2499                                  S_VALUE(sndp->rx_compressed, sndc->rx_compressed, itv),
2500                                  out + pos + 4, outsize + pos + 4, restart);
2501                         /* txcmp/s */
2502                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2503                                  S_VALUE(sndp->tx_compressed, sndc->tx_compressed, itv),
2504                                  out + pos + 5, outsize + pos + 5, restart);
2505                         /* rxmcst/s */
2506                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2507                                  S_VALUE(sndp->multicast, sndc->multicast, itv),
2508                                  out + pos + 6, outsize + pos + 6, restart);
2509                         /* %ifutil */
2510                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
2511                                  0.0, ifutil,
2512                                  out + pos + 7, outsize + pos + 7, svg_p->dt);
2513                 }
2514
2515                 /* Mark interfaces not seen here as now unregistered */
2516                 for (k = 0; k < a->item_list_sz; k++) {
2517                         unregistered = outsize + k * NET_DEV_ARRAY_SZ + 8;
2518                         if (*unregistered != FALSE) {
2519                                 *unregistered = TRUE;
2520                         }
2521                 }
2522         }
2523
2524         if (action & F_END) {
2525                 int xid = 0;
2526
2527                 for (i = 0; i < a->item_list_sz; i++) {
2528                         /*
2529                          * Check if there is something to display.
2530                          * Don't test sndc->interface because maybe the network
2531                          * interface has been registered later.
2532                          */
2533                         pos = i * NET_DEV_ARRAY_SZ;
2534                         if (!**(out + pos))
2535                                 continue;
2536
2537                         /* Recalculate min and max values in kB, not in B */
2538                         *(spmin + pos + 2) /= 1024;
2539                         *(spmax + pos + 2) /= 1024;
2540                         *(spmin + pos + 3) /= 1024;
2541                         *(spmax + pos + 3) /= 1024;
2542
2543                         item_name = *(out + pos + 8);
2544                         if (draw_activity_graphs(a->g_nr, g_type,
2545                                                  title, g_title, item_name, group,
2546                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2547                                                  svg_p, record_hdr, FALSE, a, xid)) {
2548                                 xid++;
2549                         }
2550                 }
2551
2552                 /* Free remaining structures */
2553                 free_graphs(out, outsize, spmin, spmax);
2554         }
2555 }
2556
2557 /*
2558  ***************************************************************************
2559  * Display network interfaces errors statistics in SVG.
2560  *
2561  * IN:
2562  * @a           Activity structure with statistics.
2563  * @curr        Index in array for current sample statistics.
2564  * @action      Action expected from current function.
2565  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2566  *              flag indicating that a restart record has been previously
2567  *              found (.@restart) and time used for the X axis origin
2568  *              (@ust_time_ref).
2569  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2570  * @record_hdr  Pointer on record header of current stats sample.
2571  ***************************************************************************
2572  */
2573 #define NET_EDEV_ARRAY_SZ       10
2574 __print_funct_t svg_print_net_edev_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2575                                          unsigned long long itv, struct record_header *record_hdr)
2576 {
2577         struct stats_net_edev *snedc, *snedp, snedzero;
2578         int group[] = {2, 2, 2, 3};
2579         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2580                         SVG_LINE_GRAPH};
2581         char *title[] = {"Network interfaces errors statistics (1)", "Network interfaces errors statistics (2)",
2582                          "Network interfaces errors statistics (3)", "Network interfaces errors statistics (4)"};
2583         char *g_title[] = {"rxerr/s", "txerr/s",
2584                             "rxdrop/s", "txdrop/s",
2585                             "rxfifo/s", "txfifo/s",
2586                             "coll/s", "txcarr/s", "rxfram/s"};
2587         int g_fields[] = {6, 0, 1, 2, 3, 4, 5, 8, 7};
2588         static double *spmin, *spmax;
2589         static char **out;
2590         static int *outsize;
2591         char *item_name;
2592         int i, j, k, pos, restart, *unregistered;
2593
2594         if (action & F_BEGIN) {
2595                 /*
2596                  * Allocate arrays (#0..8) that will contain the graphs data
2597                  * and the min/max values.
2598                  * Also allocate one additional array (#9) for each interface:
2599                  * out + 9 will contain the interface name,
2600                  * outsize + 9 will contain a positive value (TRUE) if the interface
2601                  * has either still not been registered, or has been unregistered.
2602                  */
2603                 out = allocate_graph_lines(NET_EDEV_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
2604         }
2605
2606         if (action & F_MAIN) {
2607                 memset(&snedzero, 0, STATS_NET_EDEV_SIZE);
2608                 /*
2609                  * Mark previously registered interfaces as now
2610                  * possibly unregistered for all graphs.
2611                  */
2612                 for (k = 0; k < a->item_list_sz; k++) {
2613                         unregistered = outsize + k * NET_EDEV_ARRAY_SZ + 9;
2614                         if (*unregistered == FALSE) {
2615                                 *unregistered = MAYBE;
2616                         }
2617                 }
2618
2619                 /* For each network interfaces structure */
2620                 for (i = 0; i < a->nr[curr]; i++) {
2621                         snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + i * a->msize);
2622                         restart = svg_p->restart;
2623
2624                         if (a->item_list != NULL) {
2625                                 /* A list of devices has been entered on the command line */
2626                                 if (!search_list_item(a->item_list, snedc->interface))
2627                                         /* Device not found */
2628                                         continue;
2629                         }
2630
2631                         /* Look for corresponding graph */
2632                         for (k = 0; k < a->item_list_sz; k++) {
2633                                 item_name = *(out + k * NET_EDEV_ARRAY_SZ + 9);
2634                                 if (!strcmp(snedc->interface, item_name))
2635                                         /* Graph found! */
2636                                         break;
2637                         }
2638                         if (k == a->item_list_sz) {
2639                                 /* Graph not found: Look for first free entry */
2640                                 for (k = 0; k < a->item_list_sz; k++) {
2641                                         item_name = *(out + k * NET_EDEV_ARRAY_SZ + 9);
2642                                         if (!strcmp(item_name, ""))
2643                                                 break;
2644                                 }
2645                                 if (k == a->item_list_sz) {
2646                                         /* No free graph entry: Ignore it (should never happen) */
2647 #ifdef DEBUG
2648                                         fprintf(stderr, "%s: Name=%s\n",
2649                                                 __FUNCTION__, snedc->interface);
2650 #endif
2651                                         continue;
2652                                 }
2653                         }
2654
2655                         pos = k * NET_EDEV_ARRAY_SZ;
2656                         unregistered = outsize + pos + 9;
2657
2658                         j = check_net_edev_reg(a, curr, !curr, i);
2659                         if (j < 0) {
2660                                 /* This is a newly registered interface. Previous stats are zero */
2661                                 snedp = &snedzero;
2662                                 restart = TRUE;
2663                         }
2664                         else {
2665                                 snedp = (struct stats_net_edev *) ((char *) a->buf[!curr] + j * a->msize);
2666                         }
2667
2668                         /*
2669                          * If current interface was marked as previously unregistered,
2670                          * then set restart variable to TRUE so that the graph will be
2671                          * discontinuous, and mark it as now registered.
2672                          */
2673                         if (*unregistered == TRUE) {
2674                                 restart = TRUE;
2675                         }
2676                         *unregistered = FALSE;
2677
2678                         item_name = *(out + pos + 9);
2679                         if (!item_name[0]) {
2680                                 /* Save network interface name (if not already done) */
2681                                 strncpy(item_name, snedc->interface, CHUNKSIZE);
2682                                 item_name[CHUNKSIZE - 1] = '\0';
2683                         }
2684
2685                         /* Check for min/max values */
2686                         save_extrema(a->gtypes_nr, (void *) snedc, (void *) snedp,
2687                                      itv, spmin + pos, spmax + pos, g_fields);
2688
2689                         /* rxerr/s */
2690                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2691                                  S_VALUE(snedp->rx_errors, snedc->rx_errors, itv),
2692                                  out + pos, outsize + pos, restart);
2693                         /* txerr/s */
2694                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2695                                  S_VALUE(snedp->tx_errors, snedc->tx_errors, itv),
2696                                  out + pos + 1, outsize + pos + 1, restart);
2697                         /* rxdrop/s */
2698                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2699                                  S_VALUE(snedp->rx_dropped, snedc->rx_dropped, itv),
2700                                  out + pos + 2, outsize + pos + 2, restart);
2701                         /* txdrop/s */
2702                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2703                                  S_VALUE(snedp->tx_dropped, snedc->tx_dropped, itv),
2704                                  out + pos + 3, outsize + pos + 3, restart);
2705                         /* rxfifo/s */
2706                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2707                                  S_VALUE(snedp->rx_fifo_errors, snedc->rx_fifo_errors, itv),
2708                                  out + pos + 4, outsize + pos + 4, restart);
2709                         /* txfifo/s */
2710                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2711                                  S_VALUE(snedp->tx_fifo_errors, snedc->tx_fifo_errors, itv),
2712                                  out + pos + 5, outsize + pos + 5, restart);
2713                         /* coll/s */
2714                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2715                                  S_VALUE(snedp->collisions, snedc->collisions, itv),
2716                                  out + pos + 6, outsize + pos + 6, restart);
2717                         /* txcarr/s */
2718                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2719                                  S_VALUE(snedp->tx_carrier_errors, snedc->tx_carrier_errors, itv),
2720                                  out + pos + 7, outsize + pos + 7, restart);
2721                         /* rxfram/s */
2722                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2723                                  S_VALUE(snedp->rx_frame_errors, snedc->rx_frame_errors, itv),
2724                                  out + pos + 8, outsize + pos + 8, restart);
2725                 }
2726
2727                 /* Mark interfaces not seen here as now unregistered */
2728                 for (k = 0; k < a->item_list_sz; k++) {
2729                         unregistered = outsize + k * NET_EDEV_ARRAY_SZ + 9;
2730                         if (*unregistered != FALSE) {
2731                                 *unregistered = TRUE;
2732                         }
2733                 }
2734         }
2735
2736         if (action & F_END) {
2737                 int xid = 0;
2738
2739                 for (i = 0; i < a->item_list_sz; i++) {
2740                         /*
2741                          * Check if there is something to display.
2742                          * Don't test snedc->interface because maybe the network
2743                          * interface has been registered later.
2744                          */
2745                         pos = i * NET_EDEV_ARRAY_SZ;
2746                         if (!**(out + pos))
2747                                 continue;
2748
2749                         item_name = *(out + pos + 9);
2750                         if (draw_activity_graphs(a->g_nr, g_type,
2751                                                  title, g_title, item_name, group,
2752                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2753                                                  svg_p, record_hdr, FALSE, a, xid)) {
2754                                 xid++;
2755                         }
2756                 }
2757
2758                 /* Free remaining structures */
2759                 free_graphs(out, outsize, spmin, spmax);
2760         }
2761 }
2762
2763 /*
2764  ***************************************************************************
2765  * Display NFS client statistics in SVG.
2766  *
2767  * IN:
2768  * @a           Activity structure with statistics.
2769  * @curr        Index in array for current sample statistics.
2770  * @action      Action expected from current function.
2771  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2772  *              flag indicating that a restart record has been previously
2773  *              found (.@restart) and time used for the X axis origin
2774  *              (@ust_time_ref).
2775  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2776  * @record_hdr  Pointer on record header of current stats sample.
2777  ***************************************************************************
2778  */
2779 __print_funct_t svg_print_net_nfs_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2780                                         unsigned long long itv, struct record_header *record_hdr)
2781 {
2782         struct stats_net_nfs
2783                 *snnc = (struct stats_net_nfs *) a->buf[curr],
2784                 *snnp = (struct stats_net_nfs *) a->buf[!curr];
2785         int group[] = {2, 2, 2};
2786         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2787         char *title[] = {"NFS client statistics (1)", "NFS client statistics (2)",
2788                          "NFS client statistics (3)"};
2789         char *g_title[] = {"call/s", "retrans/s",
2790                            "read/s", "write/s",
2791                            "access/s", "getatt/s"};
2792         int g_fields[] = {0, 1, 2, 3, 4, 5};
2793         static double *spmin, *spmax;
2794         static char **out;
2795         static int *outsize;
2796
2797         if (action & F_BEGIN) {
2798                 /*
2799                  * Allocate arrays that will contain the graphs data
2800                  * and the min/max values.
2801                  */
2802                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
2803         }
2804
2805         if (action & F_MAIN) {
2806                 /* Check for min/max values */
2807                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
2808                              itv, spmin, spmax, g_fields);
2809
2810                 /* call/s */
2811                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2812                          S_VALUE(snnp->nfs_rpccnt, snnc->nfs_rpccnt, itv),
2813                          out, outsize, svg_p->restart);
2814                 /* retrans/s */
2815                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2816                          S_VALUE(snnp->nfs_rpcretrans, snnc->nfs_rpcretrans, itv),
2817                          out + 1, outsize + 1, svg_p->restart);
2818                 /* read/s */
2819                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2820                          S_VALUE(snnp->nfs_readcnt, snnc->nfs_readcnt, itv),
2821                          out + 2, outsize + 2, svg_p->restart);
2822                 /* write/s */
2823                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2824                          S_VALUE(snnp->nfs_writecnt, snnc->nfs_writecnt, itv),
2825                          out + 3, outsize + 3, svg_p->restart);
2826                 /* access/s */
2827                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2828                          S_VALUE(snnp->nfs_accesscnt, snnc->nfs_accesscnt, itv),
2829                          out + 4, outsize + 4, svg_p->restart);
2830                 /* getatt/s */
2831                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2832                          S_VALUE(snnp->nfs_getattcnt, snnc->nfs_getattcnt, itv),
2833                          out + 5, outsize + 5, svg_p->restart);
2834         }
2835
2836         if (action & F_END) {
2837                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2838                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
2839
2840                 /* Free remaining structures */
2841                 free_graphs(out, outsize, spmin, spmax);
2842         }
2843 }
2844
2845 /*
2846  ***************************************************************************
2847  * Display NFS server statistics in SVG.
2848  *
2849  * IN:
2850  * @a           Activity structure with statistics.
2851  * @curr        Index in array for current sample statistics.
2852  * @action      Action expected from current function.
2853  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2854  *              flag indicating that a restart record has been previously
2855  *              found (.@restart) and time used for the X axis origin
2856  *              (@ust_time_ref).
2857  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2858  * @record_hdr  Pointer on record header of current stats sample.
2859  ***************************************************************************
2860  */
2861 __print_funct_t svg_print_net_nfsd_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2862                                          unsigned long long itv, struct record_header *record_hdr)
2863 {
2864         struct stats_net_nfsd
2865                 *snndc = (struct stats_net_nfsd *) a->buf[curr],
2866                 *snndp = (struct stats_net_nfsd *) a->buf[!curr];
2867         int group[] = {2, 3, 2, 2, 2};
2868         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2869                         SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2870         char *title[] = {"NFS server statistics (1)", "NFS server statistics (2)",
2871                          "NFS server statistics (3)", "NFS server statistics (4)",
2872                          "NFS server statistics (5)"};
2873         char *g_title[] = {"scall/s", "badcall/s",
2874                            "packet/s", "udp/s", "tcp/s",
2875                            "hit/s", "miss/s",
2876                            "sread/s", "swrite/s",
2877                            "saccess/s", "sgetatt/s"};
2878         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
2879         static double *spmin, *spmax;
2880         static char **out;
2881         static int *outsize;
2882
2883         if (action & F_BEGIN) {
2884                 /*
2885                  * Allocate arrays that will contain the graphs data
2886                  * and the min/max values.
2887                  */
2888                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
2889         }
2890
2891         if (action & F_MAIN) {
2892                 /* Check for min/max values */
2893                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
2894                              itv, spmin, spmax, g_fields);
2895
2896                 /* scall/s */
2897                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2898                          S_VALUE(snndp->nfsd_rpccnt, snndc->nfsd_rpccnt, itv),
2899                          out, outsize, svg_p->restart);
2900                 /* badcall/s */
2901                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2902                          S_VALUE(snndp->nfsd_rpcbad, snndc->nfsd_rpcbad, itv),
2903                          out + 1, outsize + 1, svg_p->restart);
2904                 /* packet/s */
2905                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2906                          S_VALUE(snndp->nfsd_netcnt, snndc->nfsd_netcnt, itv),
2907                          out + 2, outsize + 2, svg_p->restart);
2908                 /* udp/s */
2909                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2910                          S_VALUE(snndp->nfsd_netudpcnt, snndc->nfsd_netudpcnt, itv),
2911                          out + 3, outsize + 3, svg_p->restart);
2912                 /* tcp/s */
2913                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2914                          S_VALUE(snndp->nfsd_nettcpcnt, snndc->nfsd_nettcpcnt, itv),
2915                          out + 4, outsize + 4, svg_p->restart);
2916                 /* hit/s */
2917                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2918                          S_VALUE(snndp->nfsd_rchits, snndc->nfsd_rchits, itv),
2919                          out + 5, outsize + 5, svg_p->restart);
2920                 /* miss/s */
2921                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2922                          S_VALUE(snndp->nfsd_rcmisses, snndc->nfsd_rcmisses, itv),
2923                          out + 6, outsize + 6, svg_p->restart);
2924                 /* sread/s */
2925                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2926                          S_VALUE(snndp->nfsd_readcnt, snndc->nfsd_readcnt, itv),
2927                          out + 7, outsize + 7, svg_p->restart);
2928                 /* swrite/s */
2929                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2930                          S_VALUE(snndp->nfsd_writecnt, snndc->nfsd_writecnt, itv),
2931                          out + 8, outsize + 8, svg_p->restart);
2932                 /* saccess/s */
2933                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2934                          S_VALUE(snndp->nfsd_accesscnt, snndc->nfsd_accesscnt, itv),
2935                          out + 9, outsize + 9, svg_p->restart);
2936                 /* sgetatt/s */
2937                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2938                          S_VALUE(snndp->nfsd_getattcnt, snndc->nfsd_getattcnt, itv),
2939                          out + 10, outsize + 10, svg_p->restart);
2940         }
2941
2942         if (action & F_END) {
2943                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2944                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
2945
2946                 /* Free remaining structures */
2947                 free_graphs(out, outsize, spmin, spmax);
2948         }
2949 }
2950
2951 /*
2952  ***************************************************************************
2953  * Display socket statistics in SVG.
2954  *
2955  * IN:
2956  * @a           Activity structure with statistics.
2957  * @curr        Index in array for current sample statistics.
2958  * @action      Action expected from current function.
2959  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2960  *              flag indicating that a restart record has been previously
2961  *              found (.@restart) and time used for the X axis origin
2962  *              (@ust_time_ref).
2963  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2964  * @record_hdr  Pointer on record header of current stats sample.
2965  ***************************************************************************
2966  */
2967 __print_funct_t svg_print_net_sock_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2968                                          unsigned long long itv, struct record_header *record_hdr)
2969 {
2970         struct stats_net_sock
2971                 *snsc = (struct stats_net_sock *) a->buf[curr];
2972         int group[] = {1, 5};
2973         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2974         char *title[] = {"IPv4 sockets statistics (1)", "IPv4 sockets statistics (2)"};
2975         char *g_title[] = {"~totsck",
2976                            "~tcpsck", "~udpsck", "~rawsck", "~ip-frag", "~tcp-tw"};
2977         int g_fields[] = {0, 1, 5, 2, 3, 4};
2978         static double *spmin, *spmax;
2979         static char **out;
2980         static int *outsize;
2981
2982         if (action & F_BEGIN) {
2983                 /*
2984                  * Allocate arrays that will contain the graphs data
2985                  * and the min/max values.
2986                  */
2987                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
2988         }
2989
2990         if (action & F_MAIN) {
2991                 /* Check for min/max values */
2992                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
2993                              itv, spmin, spmax, g_fields);
2994                 /* totsck */
2995                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2996                           (unsigned long long) snsc->sock_inuse,
2997                           out, outsize, svg_p->restart);
2998                 /* tcpsck */
2999                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3000                           (unsigned long long) snsc->tcp_inuse,
3001                           out + 1, outsize + 1, svg_p->restart);
3002                 /* udpsck */
3003                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3004                           (unsigned long long) snsc->udp_inuse,
3005                           out + 2, outsize + 2, svg_p->restart);
3006                 /* rawsck */
3007                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3008                           (unsigned long long) snsc->raw_inuse,
3009                           out + 3, outsize + 3, svg_p->restart);
3010                 /* ip-frag */
3011                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3012                           (unsigned long long) snsc->frag_inuse,
3013                           out + 4, outsize + 4, svg_p->restart);
3014                 /* tcp-tw */
3015                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3016                           (unsigned long long) snsc->tcp_tw,
3017                           out + 5, outsize + 5, svg_p->restart);
3018         }
3019
3020         if (action & F_END) {
3021                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3022                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3023
3024                 /* Free remaining structures */
3025                 free_graphs(out, outsize, spmin, spmax);
3026         }
3027 }
3028
3029 /*
3030  ***************************************************************************
3031  * Display IPv4 traffic statistics in SVG.
3032  *
3033  * IN:
3034  * @a           Activity structure with statistics.
3035  * @curr        Index in array for current sample statistics.
3036  * @action      Action expected from current function.
3037  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3038  *              flag indicating that a restart record has been previously
3039  *              found (.@restart) and time used for the X axis origin
3040  *              (@ust_time_ref).
3041  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3042  * @record_hdr  Pointer on record header of current stats sample.
3043  ***************************************************************************
3044  */
3045 __print_funct_t svg_print_net_ip_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3046                                        unsigned long long itv, struct record_header *record_hdr)
3047 {
3048         struct stats_net_ip
3049                 *snic = (struct stats_net_ip *) a->buf[curr],
3050                 *snip = (struct stats_net_ip *) a->buf[!curr];
3051         int group[] = {4, 2, 2};
3052         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3053         char *title[] = {"IPv4 traffic statistics (1)", "IPv4 traffic statistics (2)", "IPv4 traffic statistics (3)"};
3054         char *g_title[] = {"irec/s", "fwddgm/s", "idel/s", "orq/s",
3055                            "asmrq/s", "asmok/s",
3056                            "fragok/s", "fragcrt/s"};
3057         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7};
3058         static double *spmin, *spmax;
3059         static char **out;
3060         static int *outsize;
3061
3062         if (action & F_BEGIN) {
3063                 /*
3064                  * Allocate arrays that will contain the graphs data
3065                  * and the min/max values.
3066                  */
3067                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
3068         }
3069
3070         if (action & F_MAIN) {
3071                 /* Check for min/max values */
3072                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3073                              itv, spmin, spmax, g_fields);
3074
3075                 /* irec/s */
3076                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3077                          S_VALUE(snip->InReceives, snic->InReceives, itv),
3078                          out, outsize, svg_p->restart);
3079                 /* fwddgm/s */
3080                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3081                          S_VALUE(snip->ForwDatagrams, snic->ForwDatagrams, itv),
3082                          out + 1, outsize + 1, svg_p->restart);
3083                 /* idel/s */
3084                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3085                          S_VALUE(snip->InDelivers, snic->InDelivers, itv),
3086                          out + 2, outsize + 2, svg_p->restart);
3087                 /* orq/s */
3088                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3089                          S_VALUE(snip->OutRequests, snic->OutRequests, itv),
3090                          out + 3, outsize + 3, svg_p->restart);
3091                 /* asmrq/s */
3092                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3093                          S_VALUE(snip->ReasmReqds, snic->ReasmReqds, itv),
3094                          out + 4, outsize + 4, svg_p->restart);
3095                 /* asmok/s */
3096                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3097                          S_VALUE(snip->ReasmOKs, snic->ReasmOKs, itv),
3098                          out + 5, outsize + 5, svg_p->restart);
3099                 /* fragok/s */
3100                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3101                          S_VALUE(snip->FragOKs, snic->FragOKs, itv),
3102                          out + 6, outsize + 6, svg_p->restart);
3103                 /* fragcrt/s */
3104                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3105                          S_VALUE(snip->FragCreates, snic->FragCreates, itv),
3106                          out + 7, outsize + 7, svg_p->restart);
3107         }
3108
3109         if (action & F_END) {
3110                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3111                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3112
3113                 /* Free remaining structures */
3114                 free_graphs(out, outsize, spmin, spmax);
3115         }
3116 }
3117
3118 /*
3119  ***************************************************************************
3120  * Display IPv4 traffic errors statistics in SVG.
3121  *
3122  * IN:
3123  * @a           Activity structure with statistics.
3124  * @curr        Index in array for current sample statistics.
3125  * @action      Action expected from current function.
3126  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3127  *              flag indicating that a restart record has been previously
3128  *              found (.@restart) and time used for the X axis origin
3129  *              (@ust_time_ref).
3130  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3131  * @record_hdr  Pointer on record header of current stats sample.
3132  ***************************************************************************
3133  */
3134 __print_funct_t svg_print_net_eip_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3135                                         unsigned long long itv, struct record_header *record_hdr)
3136 {
3137         struct stats_net_eip
3138                 *sneic = (struct stats_net_eip *) a->buf[curr],
3139                 *sneip = (struct stats_net_eip *) a->buf[!curr];
3140         int group[] = {3, 2, 3};
3141         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3142         char *title[] = {"IPv4 traffic errors statistics (1)", "IPv4 traffic errors statistics (2)",
3143                          "IPv4 traffic errors statistics (3)"};
3144         char *g_title[] = {"ihdrerr/s", "iadrerr/s", "iukwnpr/s",
3145                            "idisc/s", "odisc/s",
3146                            "onort/s", "asmf/s", "fragf/s"};
3147         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7};
3148         static double *spmin, *spmax;
3149         static char **out;
3150         static int *outsize;
3151
3152         if (action & F_BEGIN) {
3153                 /*
3154                  * Allocate arrays that will contain the graphs data
3155                  * and the min/max values.
3156                  */
3157                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
3158         }
3159
3160         if (action & F_MAIN) {
3161                 /* Check for min/max values */
3162                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3163                              itv, spmin, spmax, g_fields);
3164
3165                 /* ihdrerr/s */
3166                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3167                          S_VALUE(sneip->InHdrErrors, sneic->InHdrErrors, itv),
3168                          out, outsize, svg_p->restart);
3169                 /* iadrerr/s */
3170                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3171                          S_VALUE(sneip->InAddrErrors, sneic->InAddrErrors, itv),
3172                          out + 1, outsize + 1, svg_p->restart);
3173                 /* iukwnpr/s */
3174                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3175                          S_VALUE(sneip->InUnknownProtos, sneic->InUnknownProtos, itv),
3176                          out + 2, outsize + 2, svg_p->restart);
3177                 /* idisc/s */
3178                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3179                          S_VALUE(sneip->InDiscards, sneic->InDiscards, itv),
3180                          out + 3, outsize + 3, svg_p->restart);
3181                 /* odisc/s */
3182                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3183                          S_VALUE(sneip->OutDiscards, sneic->OutDiscards, itv),
3184                          out + 4, outsize + 4, svg_p->restart);
3185                 /* onort/s */
3186                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3187                          S_VALUE(sneip->OutNoRoutes, sneic->OutNoRoutes, itv),
3188                          out + 5, outsize + 5, svg_p->restart);
3189                 /* asmf/s */
3190                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3191                          S_VALUE(sneip->ReasmFails, sneic->ReasmFails, itv),
3192                          out + 6, outsize + 6, svg_p->restart);
3193                 /* fragf/s */
3194                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3195                          S_VALUE(sneip->FragFails, sneic->FragFails, itv),
3196                          out + 7, outsize + 7, svg_p->restart);
3197         }
3198
3199         if (action & F_END) {
3200                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3201                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3202
3203                 /* Free remaining structures */
3204                 free_graphs(out, outsize, spmin, spmax);
3205         }
3206 }
3207
3208 /*
3209  ***************************************************************************
3210  * Display ICMPv4 traffic statistics in SVG.
3211  *
3212  * IN:
3213  * @a           Activity structure with statistics.
3214  * @curr        Index in array for current sample statistics.
3215  * @action      Action expected from current function.
3216  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3217  *              flag indicating that a restart record has been previously
3218  *              found (.@restart) and time used for the X axis origin
3219  *              (@ust_time_ref).
3220  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3221  * @record_hdr  Pointer on record header of current stats sample.
3222  ***************************************************************************
3223  */
3224 __print_funct_t svg_print_net_icmp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3225                                          unsigned long long itv, struct record_header *record_hdr)
3226 {
3227         struct stats_net_icmp
3228                 *snic = (struct stats_net_icmp *) a->buf[curr],
3229                 *snip = (struct stats_net_icmp *) a->buf[!curr];
3230         int group[] = {2, 4, 4, 4};
3231         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3232                         SVG_LINE_GRAPH};
3233         char *title[] = {"ICMPv4 traffic statistics (1)", "ICMPv4 traffic statistics (2)",
3234                          "ICMPv4 traffic statistics (3)", "ICMPv4 traffic statistics (4)"};
3235         char *g_title[] = {"imsg/s", "omsg/s",
3236                            "iech/s", "iechr/s", "oech/s", "oechr/s",
3237                            "itm/s", "itmr/s", "otm/s", "otmr/s",
3238                            "iadrmk/s", "iadrmkr/s", "oadrmk/s", "oadrmkr/s"};
3239         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
3240         static double *spmin, *spmax;
3241         static char **out;
3242         static int *outsize;
3243
3244         if (action & F_BEGIN) {
3245                 /*
3246                  * Allocate arrays that will contain the graphs data
3247                  * and the min/max values.
3248                  */
3249                 out = allocate_graph_lines(14, &outsize, &spmin, &spmax);
3250         }
3251
3252         if (action & F_MAIN) {
3253                 /* Check for min/max values */
3254                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3255                              itv, spmin, spmax, g_fields);
3256
3257                 /* imsg/s */
3258                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3259                          S_VALUE(snip->InMsgs, snic->InMsgs, itv),
3260                          out, outsize, svg_p->restart);
3261                 /* omsg/s */
3262                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3263                          S_VALUE(snip->OutMsgs, snic->OutMsgs, itv),
3264                          out + 1, outsize + 1, svg_p->restart);
3265                 /* iech/s */
3266                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3267                          S_VALUE(snip->InEchos, snic->InEchos, itv),
3268                          out + 2, outsize + 2, svg_p->restart);
3269                 /* iechr/s */
3270                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3271                          S_VALUE(snip->InEchoReps, snic->InEchoReps, itv),
3272                          out + 3, outsize + 3, svg_p->restart);
3273                 /* oech/s */
3274                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3275                          S_VALUE(snip->OutEchos, snic->OutEchos, itv),
3276                          out + 4, outsize + 4, svg_p->restart);
3277                 /* oechr/s */
3278                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3279                          S_VALUE(snip->OutEchoReps, snic->OutEchoReps, itv),
3280                          out + 5, outsize + 5, svg_p->restart);
3281                 /* itm/s */
3282                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3283                          S_VALUE(snip->InTimestamps, snic->InTimestamps, itv),
3284                          out + 6, outsize + 6, svg_p->restart);
3285                 /* itmr/s */
3286                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3287                          S_VALUE(snip->InTimestampReps, snic->InTimestampReps, itv),
3288                          out + 7, outsize + 7, svg_p->restart);
3289                 /* otm/s */
3290                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3291                          S_VALUE(snip->OutTimestamps, snic->OutTimestamps, itv),
3292                          out + 8, outsize + 8, svg_p->restart);
3293                 /* otmr/s */
3294                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3295                          S_VALUE(snip->OutTimestampReps, snic->OutTimestampReps, itv),
3296                          out + 9, outsize + 9, svg_p->restart);
3297                 /* iadrmk/s */
3298                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3299                          S_VALUE(snip->InAddrMasks, snic->InAddrMasks, itv),
3300                          out + 10, outsize + 10, svg_p->restart);
3301                 /* iadrmkr/s */
3302                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3303                          S_VALUE(snip->InAddrMaskReps, snic->InAddrMaskReps, itv),
3304                          out + 11, outsize + 11, svg_p->restart);
3305                 /* oadrmk/s */
3306                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3307                          S_VALUE(snip->OutAddrMasks, snic->OutAddrMasks, itv),
3308                          out + 12, outsize + 12, svg_p->restart);
3309                 /* oadrmkr/s */
3310                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3311                          S_VALUE(snip->OutAddrMaskReps, snic->OutAddrMaskReps, itv),
3312                          out + 13, outsize + 13, svg_p->restart);
3313         }
3314
3315         if (action & F_END) {
3316                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3317                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3318
3319                 /* Free remaining structures */
3320                 free_graphs(out, outsize, spmin, spmax);
3321         }
3322 }
3323
3324 /*
3325  ***************************************************************************
3326  * Display ICMPv4 traffic errors statistics in SVG.
3327  *
3328  * IN:
3329  * @a           Activity structure with statistics.
3330  * @curr        Index in array for current sample statistics.
3331  * @action      Action expected from current function.
3332  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3333  *              flag indicating that a restart record has been previously
3334  *              found (.@restart) and time used for the X axis origin
3335  *              (@ust_time_ref).
3336  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3337  * @record_hdr  Pointer on record header of current stats sample.
3338  ***************************************************************************
3339  */
3340 __print_funct_t svg_print_net_eicmp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3341                                           unsigned long long itv, struct record_header *record_hdr)
3342 {
3343         struct stats_net_eicmp
3344                 *sneic = (struct stats_net_eicmp *) a->buf[curr],
3345                 *sneip = (struct stats_net_eicmp *) a->buf[!curr];
3346         int group[] = {2, 2, 2, 2, 2, 2};
3347         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3348                         SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3349         char *title[] = {"ICMPv4 traffic errors statistics (1)", "ICMPv4 traffic errors statistics (2)",
3350                          "ICMPv4 traffic errors statistics (3)", "ICMPv4 traffic errors statistics (4)",
3351                          "ICMPv4 traffic errors statistics (5)", "ICMPv4 traffic errors statistics (6)"};
3352         char *g_title[] = {"ierr/s", "oerr/s",
3353                            "idstunr/s", "odstunr/s",
3354                            "itmex/s", "otmex/s",
3355                            "iparmpb/s", "oparmpb/s",
3356                            "isrcq/s", "osrcq/s",
3357                            "iredir/s", "oredir/s"};
3358         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
3359         static double *spmin, *spmax;
3360         static char **out;
3361         static int *outsize;
3362
3363         if (action & F_BEGIN) {
3364                 /*
3365                  * Allocate arrays that will contain the graphs data
3366                  * and the min/max values.
3367                  */
3368                 out = allocate_graph_lines(12, &outsize, &spmin, &spmax);
3369         }
3370
3371         if (action & F_MAIN) {
3372                 /* Check for min/max values */
3373                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3374                              itv, spmin, spmax, g_fields);
3375
3376                 /* ierr/s */
3377                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3378                          S_VALUE(sneip->InErrors, sneic->InErrors, itv),
3379                          out, outsize, svg_p->restart);
3380                 /* oerr/s */
3381                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3382                          S_VALUE(sneip->OutErrors, sneic->OutErrors, itv),
3383                          out + 1, outsize + 1, svg_p->restart);
3384                 /* idstunr/s */
3385                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3386                          S_VALUE(sneip->InDestUnreachs, sneic->InDestUnreachs, itv),
3387                          out + 2, outsize + 2, svg_p->restart);
3388                 /* odstunr/s */
3389                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3390                          S_VALUE(sneip->OutDestUnreachs, sneic->OutDestUnreachs, itv),
3391                          out + 3, outsize + 3, svg_p->restart);
3392                 /* itmex/s */
3393                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3394                          S_VALUE(sneip->InTimeExcds, sneic->InTimeExcds, itv),
3395                          out + 4, outsize + 4, svg_p->restart);
3396                 /* otmex/s */
3397                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3398                          S_VALUE(sneip->OutTimeExcds, sneic->OutTimeExcds, itv),
3399                          out + 5, outsize + 5, svg_p->restart);
3400                 /* iparmpb/s */
3401                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3402                          S_VALUE(sneip->InParmProbs, sneic->InParmProbs, itv),
3403                          out + 6, outsize + 6, svg_p->restart);
3404                 /* oparmpb/s */
3405                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3406                          S_VALUE(sneip->OutParmProbs, sneic->OutParmProbs, itv),
3407                          out + 7, outsize + 7, svg_p->restart);
3408                 /* isrcq/s */
3409                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3410                          S_VALUE(sneip->InSrcQuenchs, sneic->InSrcQuenchs, itv),
3411                          out + 8, outsize + 8, svg_p->restart);
3412                 /* osrcq/s */
3413                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3414                          S_VALUE(sneip->OutSrcQuenchs, sneic->OutSrcQuenchs, itv),
3415                          out + 9, outsize + 9, svg_p->restart);
3416                 /* iredir/s */
3417                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3418                          S_VALUE(sneip->InRedirects, sneic->InRedirects, itv),
3419                          out + 10, outsize + 10, svg_p->restart);
3420                 /* oredir/s */
3421                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3422                          S_VALUE(sneip->OutRedirects, sneic->OutRedirects, itv),
3423                          out + 11, outsize + 11, svg_p->restart);
3424         }
3425
3426         if (action & F_END) {
3427                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3428                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3429
3430                 /* Free remaining structures */
3431                 free_graphs(out, outsize, spmin, spmax);
3432         }
3433 }
3434
3435 /*
3436  ***************************************************************************
3437  * Display TCPv4 traffic statistics in SVG.
3438  *
3439  * IN:
3440  * @a           Activity structure with statistics.
3441  * @curr        Index in array for current sample statistics.
3442  * @action      Action expected from current function.
3443  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3444  *              flag indicating that a restart record has been previously
3445  *              found (.@restart) and time used for the X axis origin
3446  *              (@ust_time_ref).
3447  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3448  * @record_hdr  Pointer on record header of current stats sample.
3449  ***************************************************************************
3450  */
3451 __print_funct_t svg_print_net_tcp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3452                                         unsigned long long itv, struct record_header *record_hdr)
3453 {
3454         struct stats_net_tcp
3455                 *sntc = (struct stats_net_tcp *) a->buf[curr],
3456                 *sntp = (struct stats_net_tcp *) a->buf[!curr];
3457         int group[] = {2, 2};
3458         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3459         char *title[] = {"TCPv4 traffic statistics (1)", "TCPv4 traffic statistics (2)"};
3460         char *g_title[] = {"active/s", "passive/s",
3461                            "iseg/s", "oseg/s"};
3462         int g_fields[] = {0, 1, 2, 3};
3463         static double *spmin, *spmax;
3464         static char **out;
3465         static int *outsize;
3466
3467         if (action & F_BEGIN) {
3468                 /*
3469                  * Allocate arrays that will contain the graphs data
3470                  * and the min/max values.
3471                  */
3472                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3473         }
3474
3475         if (action & F_MAIN) {
3476                 /* Check for min/max values */
3477                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3478                              itv, spmin, spmax, g_fields);
3479
3480                 /* active/s */
3481                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3482                          S_VALUE(sntp->ActiveOpens, sntc->ActiveOpens, itv),
3483                          out, outsize, svg_p->restart);
3484                 /* passive/s */
3485                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3486                          S_VALUE(sntp->PassiveOpens, sntc->PassiveOpens, itv),
3487                          out + 1, outsize + 1, svg_p->restart);
3488                 /* iseg/s */
3489                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3490                          S_VALUE(sntp->InSegs, sntc->InSegs, itv),
3491                          out + 2, outsize + 2, svg_p->restart);
3492                 /* oseg/s */
3493                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3494                          S_VALUE(sntp->OutSegs, sntc->OutSegs, itv),
3495                          out + 3, outsize + 3, svg_p->restart);
3496         }
3497
3498         if (action & F_END) {
3499                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3500                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3501
3502                 /* Free remaining structures */
3503                 free_graphs(out, outsize, spmin, spmax);
3504         }
3505 }
3506
3507 /*
3508  ***************************************************************************
3509  * Display TCPv4 traffic errors statistics in SVG.
3510  *
3511  * IN:
3512  * @a           Activity structure with statistics.
3513  * @curr        Index in array for current sample statistics.
3514  * @action      Action expected from current function.
3515  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3516  *              flag indicating that a restart record has been previously
3517  *              found (.@restart) and time used for the X axis origin
3518  *              (@ust_time_ref).
3519  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3520  * @record_hdr  Pointer on record header of current stats sample.
3521  ***************************************************************************
3522  */
3523 __print_funct_t svg_print_net_etcp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3524                                          unsigned long long itv, struct record_header *record_hdr)
3525 {
3526         struct stats_net_etcp
3527                 *snetc = (struct stats_net_etcp *) a->buf[curr],
3528                 *snetp = (struct stats_net_etcp *) a->buf[!curr];
3529         int group[] = {2, 3};
3530         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3531         char *title[] = {"TCPv4 traffic errors statistics (1)", "TCPv4 traffic errors statistics (2)"};
3532         char *g_title[] = {"atmptf/s", "estres/s",
3533                            "retrans/s", "isegerr/s", "orsts/s"};
3534         int g_fields[] = {0, 1, 2, 3, 4};
3535         static double *spmin, *spmax;
3536         static char **out;
3537         static int *outsize;
3538
3539         if (action & F_BEGIN) {
3540                 /*
3541                  * Allocate arrays that will contain the graphs data
3542                  * and the min/max values.
3543                  */
3544                 out = allocate_graph_lines(5, &outsize, &spmin, &spmax);
3545         }
3546
3547         if (action & F_MAIN) {
3548                 /* Check for min/max values */
3549                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3550                              itv, spmin, spmax, g_fields);
3551
3552                 /* atmptf/s */
3553                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3554                          S_VALUE(snetp->AttemptFails, snetc->AttemptFails, itv),
3555                          out, outsize, svg_p->restart);
3556                 /* estres/s */
3557                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3558                          S_VALUE(snetp->EstabResets, snetc->EstabResets, itv),
3559                          out + 1, outsize + 1, svg_p->restart);
3560                 /* retrans/s */
3561                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3562                          S_VALUE(snetp->RetransSegs, snetc->RetransSegs, itv),
3563                          out + 2, outsize + 2, svg_p->restart);
3564                 /* isegerr/s */
3565                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3566                          S_VALUE(snetp->InErrs, snetc->InErrs, itv),
3567                          out + 3, outsize + 3, svg_p->restart);
3568                 /* orsts/s */
3569                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3570                          S_VALUE(snetp->OutRsts, snetc->OutRsts, itv),
3571                          out + 4, outsize + 4, svg_p->restart);
3572         }
3573
3574         if (action & F_END) {
3575                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3576                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3577
3578                 /* Free remaining structures */
3579                 free_graphs(out, outsize, spmin, spmax);
3580         }
3581 }
3582
3583 /*
3584  ***************************************************************************
3585  * Display UDPv4 traffic statistics in SVG.
3586  *
3587  * IN:
3588  * @a           Activity structure with statistics.
3589  * @curr        Index in array for current sample statistics.
3590  * @action      Action expected from current function.
3591  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3592  *              flag indicating that a restart record has been previously
3593  *              found (.@restart) and time used for the X axis origin
3594  *              (@ust_time_ref).
3595  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3596  * @record_hdr  Pointer on record header of current stats sample.
3597  ***************************************************************************
3598  */
3599 __print_funct_t svg_print_net_udp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3600                                         unsigned long long itv, struct record_header *record_hdr)
3601 {
3602         struct stats_net_udp
3603                 *snuc = (struct stats_net_udp *) a->buf[curr],
3604                 *snup = (struct stats_net_udp *) a->buf[!curr];
3605         int group[] = {2, 2};
3606         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3607         char *title[] = {"UDPv4 traffic statistics (1)", "UDPv4 traffic statistics (2)"};
3608         char *g_title[] = {"idgm/s", "odgm/s",
3609                            "noport/s", "idgmerr/s"};
3610         int g_fields[] = {0, 1, 2, 3};
3611         static double *spmin, *spmax;
3612         static char **out;
3613         static int *outsize;
3614
3615         if (action & F_BEGIN) {
3616                 /*
3617                  * Allocate arrays that will contain the graphs data
3618                  * and the min/max values.
3619                  */
3620                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3621         }
3622
3623         if (action & F_MAIN) {
3624                 /* Check for min/max values */
3625                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3626                              itv, spmin, spmax, g_fields);
3627
3628                 /* idgm/s */
3629                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3630                          S_VALUE(snup->InDatagrams, snuc->InDatagrams, itv),
3631                          out, outsize, svg_p->restart);
3632                 /* odgm/s */
3633                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3634                          S_VALUE(snup->OutDatagrams, snuc->OutDatagrams, itv),
3635                          out + 1, outsize + 1, svg_p->restart);
3636                 /* noport/s */
3637                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3638                          S_VALUE(snup->NoPorts, snuc->NoPorts, itv),
3639                          out + 2, outsize + 2, svg_p->restart);
3640                 /* idgmerr/s */
3641                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3642                          S_VALUE(snup->InErrors, snuc->InErrors, itv),
3643                          out + 3, outsize + 3, svg_p->restart);
3644         }
3645
3646         if (action & F_END) {
3647                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3648                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3649
3650                 /* Free remaining structures */
3651                 free_graphs(out, outsize, spmin, spmax);
3652         }
3653 }
3654
3655 /*
3656  ***************************************************************************
3657  * Display IPV6 socket statistics in SVG.
3658  *
3659  * IN:
3660  * @a           Activity structure with statistics.
3661  * @curr        Index in array for current sample statistics.
3662  * @action      Action expected from current function.
3663  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3664  *              flag indicating that a restart record has been previously
3665  *              found (.@restart) and time used for the X axis origin
3666  *              (@ust_time_ref).
3667  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3668  * @record_hdr  Pointer on record header of current stats sample.
3669  ***************************************************************************
3670  */
3671 __print_funct_t svg_print_net_sock6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3672                                           unsigned long long itv, struct record_header *record_hdr)
3673 {
3674         struct stats_net_sock6
3675                 *snsc = (struct stats_net_sock6 *) a->buf[curr];
3676         int group[] = {4};
3677         int g_type[] = {SVG_LINE_GRAPH};
3678         char *title[] = {"IPv6 sockets statistics"};
3679         char *g_title[] = {"~tcp6sck", "~udp6sck", "~raw6sck", "~ip6-frag"};
3680         int g_fields[] = {0, 1, 2, 3};
3681         static double *spmin, *spmax;
3682         static char **out;
3683         static int *outsize;
3684
3685         if (action & F_BEGIN) {
3686                 /*
3687                  * Allocate arrays that will contain the graphs data
3688                  * and the min/max values.
3689                  */
3690                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3691         }
3692
3693         if (action & F_MAIN) {
3694                 /* Check for min/max values */
3695                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
3696                              itv, spmin, spmax, g_fields);
3697                 /* tcp6sck */
3698                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3699                           (unsigned long long) snsc->tcp6_inuse,
3700                           out, outsize, svg_p->restart);
3701                 /* udp6sck */
3702                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3703                           (unsigned long long) snsc->udp6_inuse,
3704                           out + 1, outsize + 1, svg_p->restart);
3705                 /* raw6sck */
3706                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3707                           (unsigned long long) snsc->raw6_inuse,
3708                           out + 2, outsize + 2, svg_p->restart);
3709                 /* ip6-frag */
3710                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3711                           (unsigned long long) snsc->frag6_inuse,
3712                           out + 3, outsize + 3, svg_p->restart);
3713         }
3714
3715         if (action & F_END) {
3716                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3717                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3718
3719                 /* Free remaining structures */
3720                 free_graphs(out, outsize, spmin, spmax);
3721         }
3722 }
3723
3724 /*
3725  ***************************************************************************
3726  * Display IPv6 traffic statistics in SVG.
3727  *
3728  * IN:
3729  * @a           Activity structure with statistics.
3730  * @curr        Index in array for current sample statistics.
3731  * @action      Action expected from current function.
3732  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3733  *              flag indicating that a restart record has been previously
3734  *              found (.@restart) and time used for the X axis origin
3735  *              (@ust_time_ref).
3736  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3737  * @record_hdr  Pointer on record header of current stats sample.
3738  ***************************************************************************
3739  */
3740 __print_funct_t svg_print_net_ip6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3741                                         unsigned long long itv, struct record_header *record_hdr)
3742 {
3743         struct stats_net_ip6
3744                 *snic = (struct stats_net_ip6 *) a->buf[curr],
3745                 *snip = (struct stats_net_ip6 *) a->buf[!curr];
3746         int group[] = {4, 2, 2, 2};
3747         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3748                         SVG_LINE_GRAPH};
3749         char *title[] = {"IPv6 traffic statistics (1)", "IPv6 traffic statistics (2)",
3750                          "IPv6 traffic statistics (3)", "IPv6 traffic statistics (4)"};
3751         char *g_title[] = {"irec6/s", "fwddgm6/s", "idel6/s", "orq6/s",
3752                            "asmrq6/s", "asmok6/s",
3753                            "imcpck6/s", "omcpck6/s",
3754                            "fragok6/s", "fragcr6/s"};
3755         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
3756         static double *spmin, *spmax;
3757         static char **out;
3758         static int *outsize;
3759
3760         if (action & F_BEGIN) {
3761                 /*
3762                  * Allocate arrays that will contain the graphs data
3763                  * and the min/max values.
3764                  */
3765                 out = allocate_graph_lines(10, &outsize, &spmin, &spmax);
3766         }
3767
3768         if (action & F_MAIN) {
3769                 /* Check for min/max values */
3770                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3771                              itv, spmin, spmax, g_fields);
3772
3773                 /* irec6/s */
3774                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3775                          S_VALUE(snip->InReceives6, snic->InReceives6, itv),
3776                          out, outsize, svg_p->restart);
3777                 /* fwddgm6/s */
3778                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3779                          S_VALUE(snip->OutForwDatagrams6, snic->OutForwDatagrams6, itv),
3780                          out + 1, outsize + 1, svg_p->restart);
3781                 /* idel6/s */
3782                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3783                          S_VALUE(snip->InDelivers6, snic->InDelivers6, itv),
3784                          out + 2, outsize + 2, svg_p->restart);
3785                 /* orq6/s */
3786                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3787                          S_VALUE(snip->OutRequests6, snic->OutRequests6, itv),
3788                          out + 3, outsize + 3, svg_p->restart);
3789                 /* asmrq6/s */
3790                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3791                          S_VALUE(snip->ReasmReqds6, snic->ReasmReqds6, itv),
3792                          out + 4, outsize + 4, svg_p->restart);
3793                 /* asmok6/s */
3794                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3795                          S_VALUE(snip->ReasmOKs6, snic->ReasmOKs6, itv),
3796                          out + 5, outsize + 5, svg_p->restart);
3797                 /* imcpck6/s */
3798                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3799                          S_VALUE(snip->InMcastPkts6, snic->InMcastPkts6, itv),
3800                          out + 6, outsize + 6, svg_p->restart);
3801                 /* omcpck6/s */
3802                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3803                          S_VALUE(snip->OutMcastPkts6, snic->OutMcastPkts6, itv),
3804                          out + 7, outsize + 7, svg_p->restart);
3805                 /* fragok6/s */
3806                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3807                          S_VALUE(snip->FragOKs6, snic->FragOKs6, itv),
3808                          out + 8, outsize + 8, svg_p->restart);
3809                 /* fragcr6/s */
3810                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3811                          S_VALUE(snip->FragCreates6, snic->FragCreates6, itv),
3812                          out + 9, outsize + 9, svg_p->restart);
3813         }
3814
3815         if (action & F_END) {
3816                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3817                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3818
3819                 /* Free remaining structures */
3820                 free_graphs(out, outsize, spmin, spmax);
3821         }
3822 }
3823
3824 /*
3825  ***************************************************************************
3826  * Display IPv6 traffic errors statistics in SVG.
3827  *
3828  * IN:
3829  * @a           Activity structure with statistics.
3830  * @curr        Index in array for current sample statistics.
3831  * @action      Action expected from current function.
3832  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3833  *              flag indicating that a restart record has been previously
3834  *              found (.@restart) and time used for the X axis origin
3835  *              (@ust_time_ref).
3836  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3837  * @record_hdr  Pointer on record header of current stats sample.
3838  ***************************************************************************
3839  */
3840 __print_funct_t svg_print_net_eip6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3841                                          unsigned long long itv, struct record_header *record_hdr)
3842 {
3843         struct stats_net_eip6
3844                 *sneic = (struct stats_net_eip6 *) a->buf[curr],
3845                 *sneip = (struct stats_net_eip6 *) a->buf[!curr];
3846         int group[] = {4, 2, 2, 3};
3847         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3848                         SVG_LINE_GRAPH};
3849         char *title[] = {"IPv6 traffic errors statistics (1)", "IPv6 traffic errors statistics (2)",
3850                          "IPv6 traffic errors statistics (3)", "IPv6 traffic errors statistics (4)",
3851                          "IPv6 traffic errors statistics (5)"};
3852         char *g_title[] = {"ihdrer6/s", "iadrer6/s", "iukwnp6/s", "i2big6/s",
3853                            "idisc6/s", "odisc6/s",
3854                            "inort6/s", "onort6/s",
3855                            "asmf6/s", "fragf6/s", "itrpck6/s"};
3856         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
3857         static double *spmin, *spmax;
3858         static char **out;
3859         static int *outsize;
3860
3861         if (action & F_BEGIN) {
3862                 /*
3863                  * Allocate arrays that will contain the graphs data
3864                  * and the min/max values.
3865                  */
3866                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
3867         }
3868
3869         if (action & F_MAIN) {
3870                 /* Check for min/max values */
3871                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3872                              itv, spmin, spmax, g_fields);
3873
3874                 /* ihdrer6/s */
3875                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3876                          S_VALUE(sneip->InHdrErrors6, sneic->InHdrErrors6, itv),
3877                          out, outsize, svg_p->restart);
3878                 /* iadrer6/s */
3879                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3880                          S_VALUE(sneip->InAddrErrors6, sneic->InAddrErrors6, itv),
3881                          out + 1, outsize + 1, svg_p->restart);
3882                 /* iukwnp6/s */
3883                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3884                          S_VALUE(sneip->InUnknownProtos6, sneic->InUnknownProtos6, itv),
3885                          out + 2, outsize + 2, svg_p->restart);
3886                 /* i2big6/s */
3887                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3888                          S_VALUE(sneip->InTooBigErrors6, sneic->InTooBigErrors6, itv),
3889                          out + 3, outsize + 3, svg_p->restart);
3890                 /* idisc6/s */
3891                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3892                          S_VALUE(sneip->InDiscards6, sneic->InDiscards6, itv),
3893                          out + 4, outsize + 4, svg_p->restart);
3894                 /* odisc6/s */
3895                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3896                          S_VALUE(sneip->OutDiscards6, sneic->OutDiscards6, itv),
3897                          out + 5, outsize + 5, svg_p->restart);
3898                 /* inort6/s */
3899                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3900                          S_VALUE(sneip->InNoRoutes6, sneic->InNoRoutes6, itv),
3901                          out + 6, outsize + 6, svg_p->restart);
3902                 /* onort6/s */
3903                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3904                          S_VALUE(sneip->OutNoRoutes6, sneic->OutNoRoutes6, itv),
3905                          out + 7, outsize + 7, svg_p->restart);
3906                 /* asmf6/s */
3907                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3908                          S_VALUE(sneip->ReasmFails6, sneic->ReasmFails6, itv),
3909                          out + 8, outsize + 8, svg_p->restart);
3910                 /* fragf6/s */
3911                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3912                          S_VALUE(sneip->FragFails6, sneic->FragFails6, itv),
3913                          out + 9, outsize + 9, svg_p->restart);
3914                 /* itrpck6/s */
3915                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3916                          S_VALUE(sneip->InTruncatedPkts6, sneic->InTruncatedPkts6, itv),
3917                          out + 10, outsize + 10, svg_p->restart);
3918         }
3919
3920         if (action & F_END) {
3921                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3922                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
3923
3924                 /* Free remaining structures */
3925                 free_graphs(out, outsize, spmin, spmax);
3926         }
3927 }
3928
3929 /*
3930  ***************************************************************************
3931  * Display ICMPv6 traffic statistics in SVG.
3932  *
3933  * IN:
3934  * @a           Activity structure with statistics.
3935  * @curr        Index in array for current sample statistics.
3936  * @action      Action expected from current function.
3937  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3938  *              flag indicating that a restart record has been previously
3939  *              found (.@restart) and time used for the X axis origin
3940  *              (@ust_time_ref).
3941  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3942  * @record_hdr  Pointer on record header of current stats sample.
3943  ***************************************************************************
3944  */
3945 __print_funct_t svg_print_net_icmp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3946                                           unsigned long long itv, struct record_header *record_hdr)
3947 {
3948         struct stats_net_icmp6
3949                 *snic = (struct stats_net_icmp6 *) a->buf[curr],
3950                 *snip = (struct stats_net_icmp6 *) a->buf[!curr];
3951         int group[] = {2, 3, 5, 3, 4};
3952         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3953                         SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3954         char *title[] = {"ICMPv6 traffic statistics (1)", "ICMPv6 traffic statistics (2)",
3955                          "ICMPv6 traffic statistics (3)", "ICMPv6 traffic statistics (4)",
3956                          "ICMPv6 traffic statistics (5)"};
3957         char *g_title[] = {"imsg6/s", "omsg6/s",
3958                            "iech6/s", "iechr6/s", "oechr6/s",
3959                            "igmbq6/s", "igmbr6/s", "ogmbr6/s", "igmbrd6/s", "ogmbrd6/s",
3960                            "irtsol6/s", "ortsol6/s", "irtad6/s",
3961                            "inbsol6/s", "onbsol6/s", "inbad6/s", "onbad6/s"};
3962         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
3963         static double *spmin, *spmax;
3964         static char **out;
3965         static int *outsize;
3966
3967         if (action & F_BEGIN) {
3968                 /*
3969                  * Allocate arrays that will contain the graphs data
3970                  * and the min/max values.
3971                  */
3972                 out = allocate_graph_lines(17, &outsize, &spmin, &spmax);
3973         }
3974
3975         if (action & F_MAIN) {
3976                 /* Check for min/max values */
3977                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3978                              itv, spmin, spmax, g_fields);
3979
3980                 /* imsg6/s */
3981                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3982                          S_VALUE(snip->InMsgs6, snic->InMsgs6, itv),
3983                          out, outsize, svg_p->restart);
3984                 /* omsg6/s */
3985                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3986                          S_VALUE(snip->OutMsgs6, snic->OutMsgs6, itv),
3987                          out + 1, outsize + 1, svg_p->restart);
3988                 /* iech6/s */
3989                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3990                          S_VALUE(snip->InEchos6, snic->InEchos6, itv),
3991                          out + 2, outsize + 2, svg_p->restart);
3992                 /* iechr6/s */
3993                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3994                          S_VALUE(snip->InEchoReplies6, snic->InEchoReplies6, itv),
3995                          out + 3, outsize + 3, svg_p->restart);
3996                 /* oechr6/s */
3997                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3998                          S_VALUE(snip->OutEchoReplies6, snic->OutEchoReplies6, itv),
3999                          out + 4, outsize + 4, svg_p->restart);
4000                 /* igmbq6/s */
4001                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4002                          S_VALUE(snip->InGroupMembQueries6, snic->InGroupMembQueries6, itv),
4003                          out + 5, outsize + 5, svg_p->restart);
4004                 /* igmbr6/s */
4005                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4006                          S_VALUE(snip->InGroupMembResponses6, snic->InGroupMembResponses6, itv),
4007                          out + 6, outsize + 6, svg_p->restart);
4008                 /* ogmbr6/s */
4009                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4010                          S_VALUE(snip->OutGroupMembResponses6, snic->OutGroupMembResponses6, itv),
4011                          out + 7, outsize + 7, svg_p->restart);
4012                 /* igmbrd6/s */
4013                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4014                          S_VALUE(snip->InGroupMembReductions6, snic->InGroupMembReductions6, itv),
4015                          out + 8, outsize + 8, svg_p->restart);
4016                 /* ogmbrd6/s */
4017                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4018                          S_VALUE(snip->OutGroupMembReductions6, snic->OutGroupMembReductions6, itv),
4019                          out + 9, outsize + 9, svg_p->restart);
4020                 /* irtsol6/s */
4021                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4022                          S_VALUE(snip->InRouterSolicits6, snic->InRouterSolicits6, itv),
4023                          out + 10, outsize + 10, svg_p->restart);
4024                 /* ortsol6/s */
4025                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4026                          S_VALUE(snip->OutRouterSolicits6, snic->OutRouterSolicits6, itv),
4027                          out + 11, outsize + 11, svg_p->restart);
4028                 /* irtad6/s */
4029                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4030                          S_VALUE(snip->InRouterAdvertisements6, snic->InRouterAdvertisements6, itv),
4031                          out + 12, outsize + 12, svg_p->restart);
4032                 /* inbsol6/s */
4033                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4034                          S_VALUE(snip->InNeighborSolicits6, snic->InNeighborSolicits6, itv),
4035                          out + 13, outsize + 13, svg_p->restart);
4036                 /* onbsol6/s */
4037                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4038                          S_VALUE(snip->OutNeighborSolicits6, snic->OutNeighborSolicits6, itv),
4039                          out + 14, outsize + 14, svg_p->restart);
4040                 /* inbad6/s */
4041                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4042                          S_VALUE(snip->InNeighborAdvertisements6, snic->InNeighborAdvertisements6, itv),
4043                          out + 15, outsize + 15, svg_p->restart);
4044                 /* onbad6/s */
4045                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4046                          S_VALUE(snip->OutNeighborAdvertisements6, snic->OutNeighborAdvertisements6, itv),
4047                          out + 16, outsize + 16, svg_p->restart);
4048         }
4049
4050         if (action & F_END) {
4051                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
4052                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
4053
4054                 /* Free remaining structures */
4055                 free_graphs(out, outsize, spmin, spmax);
4056         }
4057 }
4058
4059 /*
4060  ***************************************************************************
4061  * Display ICMPv6 traffic errors statistics in SVG.
4062  *
4063  * IN:
4064  * @a           Activity structure with statistics.
4065  * @curr        Index in array for current sample statistics.
4066  * @action      Action expected from current function.
4067  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4068  *              flag indicating that a restart record has been previously
4069  *              found (.@restart) and time used for the X axis origin
4070  *              (@ust_time_ref).
4071  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4072  * @record_hdr  Pointer on record header of current stats sample.
4073  ***************************************************************************
4074  */
4075 __print_funct_t svg_print_net_eicmp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4076                                            unsigned long long itv, struct record_header *record_hdr)
4077 {
4078         struct stats_net_eicmp6
4079                 *sneic = (struct stats_net_eicmp6 *) a->buf[curr],
4080                 *sneip = (struct stats_net_eicmp6 *) a->buf[!curr];
4081         int group[] = {1, 2, 2, 2, 2, 2};
4082         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
4083                         SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4084         char *title[] = {"ICMPv6 traffic errors statistics (1)", "ICMPv6 traffic errors statistics (2)",
4085                          "ICMPv6 traffic errors statistics (3)", "ICMPv6 traffic errors statistics (4)",
4086                          "ICMPv6 traffic errors statistics (5)", "ICMPv6 traffic errors statistics (6)"};
4087         char *g_title[] = {"ierr6/s",
4088                            "idtunr6/s", "odtunr6/s",
4089                            "itmex6/s", "otmex6/s",
4090                            "iprmpb6/s", "oprmpb6/s",
4091                            "iredir6/s", "oredir6/s",
4092                            "ipck2b6/s", "opck2b6/s"};
4093         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
4094         static double *spmin, *spmax;
4095         static char **out;
4096         static int *outsize;
4097
4098         if (action & F_BEGIN) {
4099                 /*
4100                  * Allocate arrays that will contain the graphs data
4101                  * and the min/max values.
4102                  */
4103                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
4104         }
4105
4106         if (action & F_MAIN) {
4107                 /* Check for min/max values */
4108                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
4109                              itv, spmin, spmax, g_fields);
4110
4111                 /* ierr6/s */
4112                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4113                          S_VALUE(sneip->InErrors6, sneic->InErrors6, itv),
4114                          out, outsize, svg_p->restart);
4115                 /* idtunr6/s */
4116                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4117                          S_VALUE(sneip->InDestUnreachs6, sneic->InDestUnreachs6, itv),
4118                          out + 1, outsize + 1, svg_p->restart);
4119                 /* odtunr6/s */
4120                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4121                          S_VALUE(sneip->OutDestUnreachs6, sneic->OutDestUnreachs6, itv),
4122                          out + 2, outsize + 2, svg_p->restart);
4123                 /* itmex6/s */
4124                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4125                          S_VALUE(sneip->InTimeExcds6, sneic->InTimeExcds6, itv),
4126                          out + 3, outsize + 3, svg_p->restart);
4127                 /* otmex6/s */
4128                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4129                          S_VALUE(sneip->OutTimeExcds6, sneic->OutTimeExcds6, itv),
4130                          out + 4, outsize + 4, svg_p->restart);
4131                 /* iprmpb6/s */
4132                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4133                          S_VALUE(sneip->InParmProblems6, sneic->InParmProblems6, itv),
4134                          out + 5, outsize + 5, svg_p->restart);
4135                 /* oprmpb6/s */
4136                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4137                          S_VALUE(sneip->OutParmProblems6, sneic->OutParmProblems6, itv),
4138                          out + 6, outsize + 6, svg_p->restart);
4139                 /* iredir6/s */
4140                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4141                          S_VALUE(sneip->InRedirects6, sneic->InRedirects6, itv),
4142                          out + 7, outsize + 7, svg_p->restart);
4143                 /* oredir6/s */
4144                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4145                          S_VALUE(sneip->OutRedirects6, sneic->OutRedirects6, itv),
4146                          out + 8, outsize + 8, svg_p->restart);
4147                 /* ipck2b6/s */
4148                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4149                          S_VALUE(sneip->InPktTooBigs6, sneic->InPktTooBigs6, itv),
4150                          out + 9, outsize + 9, svg_p->restart);
4151                 /* opck2b6/s */
4152                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4153                          S_VALUE(sneip->OutPktTooBigs6, sneic->OutPktTooBigs6, itv),
4154                          out + 10, outsize + 10, svg_p->restart);
4155         }
4156
4157         if (action & F_END) {
4158                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
4159                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
4160
4161                 /* Free remaining structures */
4162                 free_graphs(out, outsize, spmin, spmax);
4163         }
4164 }
4165
4166 /*
4167  ***************************************************************************
4168  * Display UDPv6 traffic statistics in SVG.
4169  *
4170  * IN:
4171  * @a           Activity structure with statistics.
4172  * @curr        Index in array for current sample statistics.
4173  * @action      Action expected from current function.
4174  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4175  *              flag indicating that a restart record has been previously
4176  *              found (.@restart) and time used for the X axis origin
4177  *              (@ust_time_ref).
4178  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4179  * @record_hdr  Pointer on record header of current stats sample.
4180  ***************************************************************************
4181  */
4182 __print_funct_t svg_print_net_udp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4183                                          unsigned long long itv, struct record_header *record_hdr)
4184 {
4185         struct stats_net_udp6
4186                 *snuc = (struct stats_net_udp6 *) a->buf[curr],
4187                 *snup = (struct stats_net_udp6 *) a->buf[!curr];
4188         int group[] = {2, 2};
4189         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4190         char *title[] = {"UDPv6 traffic statistics (1)", "UDPv6 traffic statistics (2)"};
4191         char *g_title[] = {"idgm6/s", "odgm6/s",
4192                            "noport6/s", "idgmer6/s"};
4193         int g_fields[] = {0, 1, 2, 3};
4194         static double *spmin, *spmax;
4195         static char **out;
4196         static int *outsize;
4197
4198         if (action & F_BEGIN) {
4199                 /*
4200                  * Allocate arrays that will contain the graphs data
4201                  * and the min/max values.
4202                  */
4203                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
4204         }
4205
4206         if (action & F_MAIN) {
4207                 /* Check for min/max values */
4208                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
4209                              itv, spmin, spmax, g_fields);
4210
4211                 /* idgm6/s */
4212                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4213                          S_VALUE(snup->InDatagrams6, snuc->InDatagrams6, itv),
4214                          out, outsize, svg_p->restart);
4215                 /* odgm6/s */
4216                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4217                          S_VALUE(snup->OutDatagrams6, snuc->OutDatagrams6, itv),
4218                          out + 1, outsize + 1, svg_p->restart);
4219                 /* noport6/s */
4220                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4221                          S_VALUE(snup->NoPorts6, snuc->NoPorts6, itv),
4222                          out + 2, outsize + 2, svg_p->restart);
4223                 /* idgmer6/s */
4224                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4225                          S_VALUE(snup->InErrors6, snuc->InErrors6, itv),
4226                          out + 3, outsize + 3, svg_p->restart);
4227         }
4228
4229         if (action & F_END) {
4230                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
4231                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
4232
4233                 /* Free remaining structures */
4234                 free_graphs(out, outsize, spmin, spmax);
4235         }
4236 }
4237
4238 /*
4239  ***************************************************************************
4240  * Display CPU frequency statistics in SVG.
4241  *
4242  * IN:
4243  * @a           Activity structure with statistics.
4244  * @curr        Index in array for current sample statistics.
4245  * @action      Action expected from current function.
4246  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4247  *              flag indicating that a restart record has been previously
4248  *              found (.@restart) and time used for the X axis origin
4249  *              (@ust_time_ref).
4250  * @itv         Interval of time in 1/100th of a second (unused here).
4251  * @record_hdr  Pointer on record header of current stats sample.
4252  ***************************************************************************
4253  */
4254 __print_funct_t svg_print_pwr_cpufreq_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4255                                             unsigned long long itv, struct record_header *record_hdr)
4256 {
4257         struct stats_pwr_cpufreq *spc, *spp;
4258         int group[] = {1};
4259         int g_type[] = {SVG_LINE_GRAPH};
4260         char *title[] = {"CPU clock frequency"};
4261         char *g_title[] = {"MHz"};
4262         static double *spmin, *spmax;
4263         static char **out;
4264         static int *outsize;
4265         char item_name[16];
4266         int i;
4267
4268         if (action & F_BEGIN) {
4269                 /*
4270                  * Allocate arrays that will contain the graphs data
4271                  * and the min/max values.
4272                  */
4273                 out = allocate_graph_lines(a->item_list_sz, &outsize, &spmin, &spmax);
4274         }
4275
4276         if (action & F_MAIN) {
4277                 /* For each CPU */
4278                 for (i = 0; (i < a->nr[curr]) && (i < a->bitmap->b_size + 1); i++) {
4279
4280                         spc = (struct stats_pwr_cpufreq *) ((char *) a->buf[curr]  + i * a->msize);
4281                         spp = (struct stats_pwr_cpufreq *) ((char *) a->buf[!curr] + i * a->msize);
4282
4283                         /* Should current CPU (including CPU "all") be displayed? */
4284                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
4285                                 /* No */
4286                                 continue;
4287
4288                         /*
4289                          * Note: Don't skip offline CPU here as it is needed
4290                          * to make the graph go though 0.
4291                          */
4292
4293                         /* MHz */
4294                         recappend(record_hdr->ust_time - svg_p->ust_time_ref,
4295                                   ((double) spp->cpufreq) / 100,
4296                                   ((double) spc->cpufreq) / 100,
4297                                   out + i, outsize + i, svg_p->restart, svg_p->dt,
4298                                   spmin + i, spmax + i);
4299                 }
4300         }
4301
4302         if (action & F_END) {
4303                 int xid = 0;
4304
4305                 for (i = 0; (i < a->item_list_sz) && (i < a->bitmap->b_size + 1); i++) {
4306
4307                         /* Should current CPU (including CPU "all") be displayed? */
4308                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
4309                                 /* No */
4310                                 continue;
4311
4312                         if (!i) {
4313                                 /* This is CPU "all" */
4314                                 strcpy(item_name, "all");
4315                         }
4316                         else {
4317                                 /*
4318                                  * If the maximum frequency reached by the CPU is 0, then
4319                                  * the CPU has been offline on the whole period.
4320                                  * => Don't display it.
4321                                  */
4322                                 if (*(spmax + i) == 0)
4323                                         continue;
4324
4325                                 sprintf(item_name, "%d", i - 1);
4326                         }
4327
4328                         if (draw_activity_graphs(a->g_nr, g_type,
4329                                                  title, g_title, item_name, group,
4330                                                  spmin + i, spmax + i, out + i, outsize + i,
4331                                                  svg_p, record_hdr, i, a, xid)) {
4332                                 xid++;
4333                         }
4334                 }
4335
4336                 /* Free remaining structures */
4337                 free_graphs(out, outsize, spmin, spmax);
4338         }
4339 }
4340
4341 /*
4342  ***************************************************************************
4343  * Display fan statistics in SVG.
4344  *
4345  * IN:
4346  * @a           Activity structure with statistics.
4347  * @curr        Index in array for current sample statistics.
4348  * @action      Action expected from current function.
4349  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4350  *              flag indicating that a restart record has been previously
4351  *              found (.@restart) and time used for the X axis origin
4352  *              (@ust_time_ref).
4353  * @itv         Interval of time in 1/100th of a second (unused here).
4354  * @record_hdr  Pointer on record header of current stats sample.
4355  ***************************************************************************
4356  */
4357 __print_funct_t svg_print_pwr_fan_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4358                                         unsigned long long itv, struct record_header *record_hdr)
4359 {
4360         struct stats_pwr_fan *spc, *spp;
4361         int group[] = {1};
4362         int g_type[] = {SVG_LINE_GRAPH};
4363         char *title[] = {"Fans speed"};
4364         char *g_title[] = {"~rpm"};
4365         static double *spmin, *spmax;
4366         static char **out;
4367         static int *outsize;
4368         char item_name[MAX_SENSORS_DEV_LEN + 16];
4369         int i;
4370
4371         if (action & F_BEGIN) {
4372                 /*
4373                  * Allocate arrays that will contain the graphs data
4374                  * and the min/max values.
4375                  */
4376                 out = allocate_graph_lines(a->item_list_sz, &outsize, &spmin, &spmax);
4377         }
4378
4379         if (action & F_MAIN) {
4380                 /* For each fan */
4381                 for (i = 0; i < a->nr[curr]; i++) {
4382
4383                         spc = (struct stats_pwr_fan *) ((char *) a->buf[curr]  + i * a->msize);
4384                         spp = (struct stats_pwr_fan *) ((char *) a->buf[!curr] + i * a->msize);
4385
4386                         /* rpm */
4387                         recappend(record_hdr->ust_time - svg_p->ust_time_ref,
4388                                   (double) spp->rpm,
4389                                   (double) spc->rpm,
4390                                   out + i, outsize + i, svg_p->restart, svg_p->dt,
4391                                   spmin + i, spmax + i);
4392                 }
4393         }
4394
4395         if (action & F_END) {
4396                 int xid = 0;
4397
4398                 for (i = 0; i < a->item_list_sz; i++) {
4399
4400                         spc = (struct stats_pwr_fan *) ((char *) a->buf[curr] + i * a->msize);
4401
4402                         snprintf(item_name, sizeof(item_name), "%d: %s", i + 1, spc->device);
4403                         item_name[sizeof(item_name) - 1] = '\0';
4404
4405                         if (draw_activity_graphs(a->g_nr, g_type,
4406                                                  title, g_title, item_name, group,
4407                                                  spmin + i, spmax + i, out + i, outsize + i,
4408                                                  svg_p, record_hdr, FALSE, a, xid)) {
4409                                 xid++;
4410                         }
4411                 }
4412
4413                 /* Free remaining structures */
4414                 free_graphs(out, outsize, spmin, spmax);
4415         }
4416 }
4417
4418 /*
4419  ***************************************************************************
4420  * Display temperature statistics in SVG.
4421  *
4422  * IN:
4423  * @a           Activity structure with statistics.
4424  * @curr        Index in array for current sample statistics.
4425  * @action      Action expected from current function.
4426  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4427  *              flag indicating that a restart record has been previously
4428  *              found (.@restart) and time used for the X axis origin
4429  *              (@ust_time_ref).
4430  * @itv         Interval of time in 1/100th of a second (unused here).
4431  * @record_hdr  Pointer on record header of current stats sample.
4432  ***************************************************************************
4433  */
4434 #define TEMP_ARRAY_SZ   2
4435 __print_funct_t svg_print_pwr_temp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4436                                          unsigned long long itv, struct record_header *record_hdr)
4437 {
4438         struct stats_pwr_temp *spc;
4439         int group[] = {1, 1};
4440         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4441         char *title[] = {"Devices temperature (1)",
4442                          "Devices temperature (2)"};
4443         char *g_title[] = {"~degC",
4444                            "%temp"};
4445         static double *spmin, *spmax;
4446         static char **out;
4447         static int *outsize;
4448         char item_name[MAX_SENSORS_DEV_LEN + 16];
4449         int i;
4450         double tval;
4451
4452         if (action & F_BEGIN) {
4453                 /*
4454                  * Allocate arrays that will contain the graphs data
4455                  * and the min/max values.
4456                  */
4457                 out = allocate_graph_lines(TEMP_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
4458         }
4459
4460         if (action & F_MAIN) {
4461                 /* For each temperature sensor */
4462                 for (i = 0; i < a->nr[curr]; i++) {
4463
4464                         spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
4465
4466                         /* Look for min/max values */
4467                         if (spc->temp < *(spmin + TEMP_ARRAY_SZ * i)) {
4468                                 *(spmin + TEMP_ARRAY_SZ * i) = spc->temp;
4469                         }
4470                         if (spc->temp > *(spmax + TEMP_ARRAY_SZ * i)) {
4471                                 *(spmax + TEMP_ARRAY_SZ * i) = spc->temp;
4472                         }
4473                         tval = (spc->temp_max - spc->temp_min) ?
4474                                (spc->temp - spc->temp_min) / (spc->temp_max - spc->temp_min) * 100 :
4475                                0.0;
4476                         if (tval < *(spmin + TEMP_ARRAY_SZ * i + 1)) {
4477                                 *(spmin + TEMP_ARRAY_SZ * i + 1) = tval;
4478                         }
4479                         if (tval > *(spmax + TEMP_ARRAY_SZ * i + 1)) {
4480                                 *(spmax + TEMP_ARRAY_SZ * i + 1) = tval;
4481                         }
4482
4483                         /* degC */
4484                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4485                                  (double) spc->temp,
4486                                  out + TEMP_ARRAY_SZ * i, outsize + TEMP_ARRAY_SZ * i, svg_p->restart);
4487                         /* %temp */
4488                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4489                                  0.0, tval,
4490                                  out + TEMP_ARRAY_SZ * i + 1, outsize + TEMP_ARRAY_SZ * i + 1, svg_p->dt);
4491                 }
4492         }
4493
4494         if (action & F_END) {
4495                 int xid = 0;
4496
4497                 for (i = 0; i < a->item_list_sz; i++) {
4498
4499                         spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
4500
4501                         snprintf(item_name, sizeof(item_name), "%d: %s", i + 1, spc->device);
4502                         item_name[sizeof(item_name) - 1] = '\0';
4503
4504                         if (draw_activity_graphs(a->g_nr, g_type,
4505                                                  title, g_title, item_name, group,
4506                                                  spmin + TEMP_ARRAY_SZ * i, spmax + TEMP_ARRAY_SZ * i,
4507                                                  out + TEMP_ARRAY_SZ * i, outsize + TEMP_ARRAY_SZ * i,
4508                                                  svg_p, record_hdr, FALSE, a, xid)) {
4509                                 xid++;
4510                         }
4511                 }
4512
4513                 /* Free remaining structures */
4514                 free_graphs(out, outsize, spmin, spmax);
4515         }
4516 }
4517
4518 /*
4519  ***************************************************************************
4520  * Display voltage inputs statistics in SVG.
4521  *
4522  * IN:
4523  * @a           Activity structure with statistics.
4524  * @curr        Index in array for current sample statistics.
4525  * @action      Action expected from current function.
4526  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4527  *              flag indicating that a restart record has been previously
4528  *              found (.@restart) and time used for the X axis origin
4529  *              (@ust_time_ref).
4530  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4531  * @record_hdr  Pointer on record header of current stats sample.
4532  ***************************************************************************
4533  */
4534 #define IN_ARRAY_SZ     2
4535 __print_funct_t svg_print_pwr_in_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4536                                        unsigned long long itv, struct record_header *record_hdr)
4537 {
4538         struct stats_pwr_in *spc;
4539         int group[] = {1, 1};
4540         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4541         char *title[] = {"Voltage inputs statistics (1)",
4542                          "Voltage inputs statistics (2)"};
4543         char *g_title[] = {"inV",
4544                            "%in"};
4545         static double *spmin, *spmax;
4546         static char **out;
4547         static int *outsize;
4548         char item_name[MAX_SENSORS_DEV_LEN + 16];
4549         int i;
4550         double tval;
4551
4552         if (action & F_BEGIN) {
4553                 /*
4554                  * Allocate arrays that will contain the graphs data
4555                  * and the min/max values.
4556                  */
4557                 out = allocate_graph_lines(IN_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
4558         }
4559
4560         if (action & F_MAIN) {
4561                 /* For each voltage input sensor */
4562                 for (i = 0; i < a->nr[curr]; i++) {
4563
4564                         spc = (struct stats_pwr_in *) ((char *) a->buf[curr] + i * a->msize);
4565
4566                         /* Look for min/max values */
4567                         if (spc->in < *(spmin + IN_ARRAY_SZ * i)) {
4568                                 *(spmin + IN_ARRAY_SZ * i) = spc->in;
4569                         }
4570                         if (spc->in > *(spmax + IN_ARRAY_SZ * i)) {
4571                                 *(spmax + IN_ARRAY_SZ * i) = spc->in;
4572                         }
4573                         tval = (spc->in_max - spc->in_min) ?
4574                                (spc->in - spc->in_min) / (spc->in_max - spc->in_min) * 100 :
4575                                0.0;
4576                         if (tval < *(spmin + IN_ARRAY_SZ * i + 1)) {
4577                                 *(spmin + IN_ARRAY_SZ * i + 1) = tval;
4578                         }
4579                         if (tval > *(spmax + IN_ARRAY_SZ * i + 1)) {
4580                                 *(spmax + IN_ARRAY_SZ * i + 1) = tval;
4581                         }
4582
4583                         /* inV */
4584                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4585                                  (double) spc->in,
4586                                  out + IN_ARRAY_SZ * i, outsize + IN_ARRAY_SZ * i, svg_p->restart);
4587                         /* %in */
4588                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4589                                  0.0, tval,
4590                                  out + IN_ARRAY_SZ * i + 1, outsize + IN_ARRAY_SZ * i + 1, svg_p->dt);
4591                 }
4592         }
4593
4594         if (action & F_END) {
4595                 int xid = 0;
4596
4597                 for (i = 0; i < a->item_list_sz; i++) {
4598
4599                         spc = (struct stats_pwr_in *) ((char *) a->buf[curr]  + i * a->msize);
4600
4601                         snprintf(item_name, sizeof(item_name), "%d: %s", i + 1, spc->device);
4602                         item_name[sizeof(item_name) - 1] = '\0';
4603
4604                         if (draw_activity_graphs(a->g_nr, g_type,
4605                                                  title, g_title, item_name, group,
4606                                                  spmin + IN_ARRAY_SZ * i, spmax + IN_ARRAY_SZ * i,
4607                                                  out + IN_ARRAY_SZ * i, outsize + IN_ARRAY_SZ * i,
4608                                                  svg_p, record_hdr, FALSE, a, xid)) {
4609                                 xid++;
4610                         }
4611                 }
4612
4613                 /* Free remaining structures */
4614                 free_graphs(out, outsize, spmin, spmax);
4615         }
4616 }
4617
4618 /*
4619  ***************************************************************************
4620  * Display huge pages statistics in SVG.
4621  *
4622  * IN:
4623  * @a           Activity structure with statistics.
4624  * @curr        Index in array for current sample statistics.
4625  * @action      Action expected from current function.
4626  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4627  *              flag indicating that a restart record has been previously
4628  *              found (.@restart) and time used for the X axis origin
4629  *              (@ust_time_ref).
4630  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4631  * @record_hdr  Pointer on record header of current stats sample.
4632  ***************************************************************************
4633  */
4634 __print_funct_t svg_print_huge_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4635                                      unsigned long long itv, struct record_header *record_hdr)
4636 {
4637         struct stats_huge
4638                 *smc = (struct stats_huge *) a->buf[curr];
4639         int group[] = {4, 1};
4640         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4641         char *title[] = {"Huge pages utilization (1)",
4642                          "Huge pages utilization (2)"};
4643         char *g_title[] = {"~kbhugfree", "~kbhugused", "~kbhugrsvd", "~kbhugsurp",
4644                            "%hugused"};
4645         int g_fields[] = {0, 5, 2, 3};
4646         static double *spmin, *spmax;
4647         static char **out;
4648         static int *outsize;
4649         double tval;
4650
4651         if (action & F_BEGIN) {
4652                 /*
4653                  * Allocate arrays that will contain the graphs data
4654                  * and the min/max values.
4655                  * Allocate one additional array (#5) to save min/max
4656                  * values for tlhkb (unused).
4657                  */
4658                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
4659         }
4660
4661         if (action & F_MAIN) {
4662                 /* Check for min/max values */
4663                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
4664                              itv, spmin, spmax, g_fields);
4665
4666                 if (smc->tlhkb - smc->frhkb < *(spmin + 1)) {
4667                         *(spmin + 1) = smc->tlhkb - smc->frhkb;
4668                 }
4669                 if (smc->tlhkb - smc->frhkb > *(spmax + 1)) {
4670                         *(spmax + 1) = smc->tlhkb - smc->frhkb;
4671                 }
4672                 tval = smc->tlhkb ? SP_VALUE(smc->frhkb, smc->tlhkb, smc->tlhkb) : 0.0;
4673                 if (tval < *(spmin + 4)) {
4674                         *(spmin + 4) = tval;
4675                 }
4676                 if (tval > *(spmax + 4)) {
4677                         *(spmax + 4) = tval;
4678                 }
4679
4680                 /* kbhugfree */
4681                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4682                           (unsigned long long) smc->frhkb,
4683                           out, outsize, svg_p->restart);
4684                 /* hugused */
4685                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4686                           (unsigned long long) smc->tlhkb - smc->frhkb,
4687                           out + 1, outsize + 1, svg_p->restart);
4688                 /* kbhugrsvd */
4689                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4690                           (unsigned long long) smc->rsvdhkb,
4691                           out + 2, outsize + 2, svg_p->restart);
4692                 /* kbhugsurp */
4693                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4694                           (unsigned long long) smc->surphkb,
4695                           out + 3, outsize + 3, svg_p->restart);
4696                 /* %hugused */
4697                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4698                          0.0, tval,
4699                          out + 4, outsize + 4, svg_p->dt);
4700         }
4701
4702         if (action & F_END) {
4703                 draw_activity_graphs(a->g_nr, g_type,
4704                                      title, g_title, NULL, group,
4705                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
4706
4707                 /* Free remaining structures */
4708                 free_graphs(out, outsize, spmin, spmax);
4709         }
4710 }
4711
4712 /*
4713  ***************************************************************************
4714  * Display filesystem statistics in SVG.
4715  *
4716  * IN:
4717  * @a           Activity structure with statistics.
4718  * @curr        Index in array for current sample statistics.
4719  * @action      Action expected from current function.
4720  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4721  *              flag indicating that a restart record has been previously
4722  *              found (.@restart) and time used for the X axis origin
4723  *              (@ust_time_ref).
4724  * @itv         Interval of time in 1/100th of a second (unused here).
4725  * @record_hdr  Pointer on record header of current stats sample.
4726  ***************************************************************************
4727  */
4728 #define FS_ARRAY_SZ     8
4729 __print_funct_t svg_print_filesystem_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4730                                            unsigned long long itv, struct record_header *record_hdr)
4731 {
4732         struct stats_filesystem *sfc, *sfp;
4733         int group[] = {2, 2, 2, 1};
4734         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH,
4735                         SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4736         char *title[] = {"Filesystems statistics (1)", "Filesystems statistics (2)",
4737                          "Filesystems statistics (3)", "Filesystems statistics (4)"};
4738         char *g_title[] = {"~MBfsfree", "~MBfsused",
4739                            "%ufsused", "%fsused",
4740                            "Ifree/1000", "Iused/1000",
4741                            "%Iused"};
4742         static double *spmin, *spmax;
4743         static char **out;
4744         static int *outsize;
4745         char *dev_name, *item_name;
4746         double tval;
4747         int i, k, pos, restart;
4748
4749         if (action & F_BEGIN) {
4750                 /*
4751                  * Allocate arrays (#0..6) that will contain the graphs data
4752                  * and the min/max values.
4753                  * Also allocate an additional arrays (#7) for each filesystem:
4754                  * out + 7 will contain the persistent or standard fs name, or mount point.
4755                  */
4756                 out = allocate_graph_lines(FS_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
4757         }
4758
4759         if (action & F_MAIN) {
4760                 /* For each filesystem structure */
4761                 for (i = 0; i < a->nr[curr]; i++) {
4762                         sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize);
4763
4764                         /* Get name to display (persistent or standard fs name, or mount point) */
4765                         dev_name = get_fs_name_to_display(a, flags, sfc);
4766
4767                         if (a->item_list != NULL) {
4768                                 /* A list of devices has been entered on the command line */
4769                                 if (!search_list_item(a->item_list, dev_name))
4770                                         /* Device not found */
4771                                         continue;
4772                         }
4773
4774                         /* Look for corresponding graph */
4775                         for (k = 0; k < a->item_list_sz; k++) {
4776                                 item_name = *(out + k * FS_ARRAY_SZ + 7);
4777                                 if (!strcmp(dev_name, item_name))
4778                                         /* Graph found! */
4779                                         break;
4780                         }
4781
4782                         if (k == a->item_list_sz) {
4783                                 /* Graph not found: Look for first free entry */
4784                                 for (k = 0; k < a->item_list_sz; k++) {
4785                                         item_name = *(out + k * FS_ARRAY_SZ + 7);
4786                                         if (!strcmp(item_name, ""))
4787                                                 break;
4788                                 }
4789                                 if (k == a->item_list_sz) {
4790                                         /* No free graph entry: Ignore it (should never happen) */
4791 #ifdef DEBUG
4792                                         fprintf(stderr, "%s: Name=%s\n",
4793                                                 __FUNCTION__, sfc->fs_name);
4794 #endif
4795                                         continue;
4796                                 }
4797                         }
4798
4799                         pos = k * FS_ARRAY_SZ;
4800
4801                         item_name = *(out + pos + 7);
4802                         if (!item_name[0]) {
4803                                 /* Save filesystem name and mount point (if not already done) */
4804                                 strncpy(item_name, dev_name, CHUNKSIZE);
4805                                 item_name[CHUNKSIZE - 1] = '\0';
4806                         }
4807
4808                         restart = TRUE;
4809                         for (k = 0; k < a->nr[!curr]; k++) {
4810                                 sfp = (struct stats_filesystem *) ((char *) a->buf[!curr] + k * a->msize);
4811                                 if (!strcmp(sfc->fs_name, sfp->fs_name)) {
4812                                         /* Filesystem found in previous sample */
4813                                         restart = svg_p->restart;
4814                                 }
4815                         }
4816
4817                         /* Check for min/max values */
4818
4819                         /* Compute fsfree min/max values */
4820                         tval = (double) sfc->f_bfree;
4821                         if (tval > *(spmax + pos)) {
4822                                 *(spmax + pos) = tval;
4823                         }
4824                         if (tval < *(spmin + pos)) {
4825                                 *(spmin + pos) = tval;
4826                         }
4827                         /* Compute fsused min/max values */
4828                         tval = (double) (sfc->f_blocks - sfc->f_bfree);
4829                         if (tval > *(spmax + pos + 1)) {
4830                                 *(spmax + pos + 1) = tval;
4831                         }
4832                         if (tval < *(spmin + pos + 1)) {
4833                                 *(spmin + pos + 1) = tval;
4834                         }
4835                         /* Compute %ufsused min/max values */
4836                         tval = sfc->f_blocks ?
4837                                SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks) : 0.0;
4838                         if (tval > *(spmax + pos + 2)) {
4839                                 *(spmax + pos + 2) = tval;
4840                         }
4841                         if (tval < *(spmin + pos + 2)) {
4842                                 *(spmin + pos + 2) = tval;
4843                         }
4844                         /* Compute %fsused min/max values */
4845                         tval = sfc->f_blocks ?
4846                                SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks) : 0.0;
4847                         if (tval > *(spmax + pos + 3)) {
4848                                 *(spmax + pos + 3) = tval;
4849                         }
4850                         if (tval < *(spmin + pos + 3)) {
4851                                 *(spmin + pos + 3) = tval;
4852                         }
4853                         /* Compute Ifree min/max values */
4854                         tval = (double) sfc->f_ffree;
4855                         if (tval > *(spmax + pos + 4)) {
4856                                 *(spmax + pos + 4) = tval;
4857                         }
4858                         if (tval < *(spmin + pos + 4)) {
4859                                 *(spmin + pos + 4) = tval;
4860                         }
4861                         /* Compute Iused min/max values */
4862                         tval = (double) (sfc->f_files - sfc->f_ffree);
4863                         if (tval > *(spmax + pos + 5)) {
4864                                 *(spmax + pos + 5) = tval;
4865                         }
4866                         if (tval < *(spmin + pos + 5)) {
4867                                 *(spmin + pos + 5) = tval;
4868                         }
4869                         /* Compute %Iused min/max values */
4870                         tval = sfc->f_files ?
4871                                SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) : 0.0;
4872                         if (tval > *(spmax + pos + 6)) {
4873                                 *(spmax + pos + 6) = tval;
4874                         }
4875                         if (tval < *(spmin + pos + 6)) {
4876                                 *(spmin + pos + 6) = tval;
4877                         }
4878
4879                         /* MBfsfree */
4880                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4881                                  (double) sfc->f_bfree / 1024 / 1024,
4882                                  out + pos, outsize + pos, restart);
4883                         /* MBfsused */
4884                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4885                                  (double) (sfc->f_blocks - sfc->f_bfree) / 1024 / 1024,
4886                                  out + pos + 1, outsize + pos + 1, restart);
4887                         /* %ufsused */
4888                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4889                                  0.0,
4890                                  sfc->f_blocks ?
4891                                  SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks) : 0.0,
4892                                  out + pos + 2, outsize + pos + 2, svg_p->dt);
4893                         /* %fsused */
4894                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4895                                  0.0,
4896                                  sfc->f_blocks ?
4897                                  SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks) : 0.0,
4898                                  out + pos + 3, outsize + pos + 3, svg_p->dt);
4899                         /* Ifree */
4900                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4901                                  ((double) sfc->f_ffree) / 1000,
4902                                  out + pos + 4, outsize + pos + 4, restart);
4903                         /* Iused */
4904                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4905                                  ((double) (sfc->f_files - sfc->f_ffree)) / 1000,
4906                                  out + pos + 5, outsize + pos + 5, restart);
4907                         /* %Iused */
4908                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4909                                  0.0,
4910                                  sfc->f_files ?
4911                                  SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) : 0.0,
4912                                  out + pos + 6, outsize + pos + 6, svg_p->dt);
4913                 }
4914         }
4915
4916         if (action & F_END) {
4917                 int xid = 0;
4918
4919                 for (i = 0; i < a->item_list_sz; i++) {
4920
4921                         /* Check if there is something to display */
4922                         pos = i * FS_ARRAY_SZ;
4923                         if (!**(out + pos))
4924                                 continue;
4925
4926                         /* Conversion B -> MiB and inodes/1000 */
4927                         for (k = 0; k < 2; k++) {
4928                                 *(spmin + pos + k) /= (1024 * 1024);
4929                                 *(spmax + pos + k) /= (1024 * 1024);
4930                                 *(spmin + pos + 4 + k) /= 1000;
4931                                 *(spmax + pos + 4 + k) /= 1000;
4932                         }
4933
4934                         item_name = *(out + pos + 7);
4935
4936                         if (draw_activity_graphs(a->g_nr, g_type, title, g_title, item_name, group,
4937                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
4938                                                  svg_p, record_hdr, FALSE, a, xid)) {
4939                                 xid++;
4940                         }
4941                 }
4942
4943                 /* Free remaining structures */
4944                 free_graphs(out, outsize, spmin, spmax);
4945         }
4946 }
4947
4948 /*
4949  ***************************************************************************
4950  * Display Fibre Channel HBA statistics in SVG.
4951  *
4952  * IN:
4953  * @a           Activity structure with statistics.
4954  * @curr        Index in array for current sample statistics.
4955  * @action      Action expected from current function.
4956  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4957  *              flag indicating that a restart record has been previously
4958  *              found (.@restart) and time used for the X axis origin
4959  *              (@ust_time_ref).
4960  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4961  * @record_hdr  Pointer on record header of current stats sample.
4962  ***************************************************************************
4963  */
4964 #define FC_ARRAY_SZ     5
4965 __print_funct_t svg_print_fchost_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4966                                        unsigned long long itv, struct record_header *record_hdr)
4967 {
4968         struct stats_fchost *sfcc, *sfcp, sfczero;
4969         int group[] = {2, 2};
4970         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4971         char *title[] = {"Fibre Channel HBA statistics (1)", "Fibre Channel HBA statistics (2)"};
4972         char *g_title[] = {"fch_rxf/s", "fch_txf/s",
4973                            "fch_rxw/s", "fch_txw/s"};
4974         int g_fields[] = {0, 1, 2, 3};
4975         static double *spmin, *spmax;
4976         static char **out;
4977         static int *outsize;
4978         char *item_name;
4979         int i, j, j0, k, found, pos, restart, *unregistered;
4980
4981         if (action & F_BEGIN) {
4982                 /*
4983                  * Allocate arrays (#0..3) that will contain the graphs data
4984                  * and the min/max values.
4985                  * Also allocate one additional array (#4) that will contain
4986                  * FC HBA name (out + 4) and a positive value (TRUE) if the interface
4987                  * has either still not been registered, or has been unregistered
4988                  * (outsize + 4).
4989                  */
4990                 out = allocate_graph_lines(FC_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
4991         }
4992
4993         if (action & F_MAIN) {
4994                 memset(&sfczero, 0, sizeof(struct stats_fchost));
4995                 /*
4996                  * Mark previously registered interfaces as now
4997                  * possibly unregistered for all graphs.
4998                  */
4999                 for (k = 0; k < a->item_list_sz; k++) {
5000                         unregistered = outsize + k * FC_ARRAY_SZ + 4;
5001                         if (*unregistered == FALSE) {
5002                                 *unregistered = MAYBE;
5003                         }
5004                 }
5005
5006                 /* For each FC HBA */
5007                 for (i = 0; i < a->nr[curr]; i++) {
5008
5009                         found = FALSE;
5010                         sfcc = (struct stats_fchost *) ((char *) a->buf[curr] + i * a->msize);
5011                         restart = svg_p->restart;
5012
5013                         /* Look for corresponding graph */
5014                         for (k = 0; k < a->item_list_sz; k++) {
5015                                 item_name = *(out + k * FC_ARRAY_SZ + 4);
5016                                 if (!strcmp(sfcc->fchost_name, item_name))
5017                                         /* Graph found! */
5018                                         break;
5019                         }
5020                         if (k == a->item_list_sz) {
5021                                 /* Graph not found: Look for first free entry */
5022                                 for (k = 0; k < a->item_list_sz; k++) {
5023                                         item_name = *(out + k * FC_ARRAY_SZ + 4);
5024                                         if (!strcmp(item_name, ""))
5025                                                 break;
5026                                 }
5027                                 if (k == a->item_list_sz) {
5028                                         /* No free graph entry: Ignore it (should never happen) */
5029 #ifdef DEBUG
5030                                         fprintf(stderr, "%s: Name=%s\n",
5031                                                 __FUNCTION__, sfcc->fchost_name);
5032 #endif
5033                                         continue;
5034                                 }
5035                         }
5036
5037                         pos = k * FC_ARRAY_SZ;
5038                         unregistered = outsize + pos + 4;
5039
5040                         if (a->nr[!curr] > 0) {
5041                                 /* Look for corresponding structure in previous iteration */
5042                                 j = i;
5043
5044                                 if (j >= a->nr[!curr]) {
5045                                         j = a->nr[!curr] - 1;
5046                                 }
5047
5048                                 j0 = j;
5049
5050                                 do {
5051                                         sfcp = (struct stats_fchost *) ((char *) a->buf[!curr] + j * a->msize);
5052                                         if (!strcmp(sfcc->fchost_name, sfcp->fchost_name)) {
5053                                                 found = TRUE;
5054                                                 break;
5055                                         }
5056                                         if (++j >= a->nr[!curr]) {
5057                                                 j = 0;
5058                                         }
5059                                 }
5060                                 while (j != j0);
5061                         }
5062
5063                         if (!found) {
5064                                 /* This is a newly registered host */
5065                                 sfcp = &sfczero;
5066                                 restart = TRUE;
5067                         }
5068
5069                         /*
5070                          * If current interface was marked as previously unregistered,
5071                          * then set restart variable to TRUE so that the graph will be
5072                          * discontinuous, and mark it as now registered.
5073                          */
5074                         if (*unregistered == TRUE) {
5075                                 restart = TRUE;
5076                         }
5077                         *unregistered = FALSE;
5078
5079                         item_name = *(out + pos + 4);
5080                         if (!item_name[0]) {
5081                                 /* Save FC HBA name */
5082                                 strncpy(item_name, sfcc->fchost_name, CHUNKSIZE);
5083                                 item_name[CHUNKSIZE - 1] = '\0';
5084                         }
5085
5086                         /* Look for min/max values */
5087                         save_extrema(a->gtypes_nr, (void *) sfcc, (void *) sfcp,
5088                                 itv, spmin + pos, spmax + pos, g_fields);
5089
5090                         /* fch_rxf/s */
5091                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5092                                  S_VALUE(sfcp->f_rxframes, sfcc->f_rxframes, itv),
5093                                  out + pos, outsize + pos, restart);
5094                         /* fch_txf/s */
5095                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5096                                  S_VALUE(sfcp->f_txframes, sfcc->f_txframes, itv),
5097                                  out + pos + 1, outsize + pos + 1, restart);
5098                         /* fch_rxw/s */
5099                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5100                                  S_VALUE(sfcp->f_rxwords, sfcc->f_rxwords, itv),
5101                                  out + pos + 2, outsize + pos + 2, restart);
5102                         /* fch_txw/s */
5103                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5104                                  S_VALUE(sfcp->f_txwords, sfcc->f_txwords, itv),
5105                                  out + pos + 3, outsize + pos + 3, restart);
5106                 }
5107
5108                 /* Mark interfaces not seen here as now unregistered */
5109                 for (k = 0; k < a->item_list_sz; k++) {
5110                         unregistered = outsize + k * FC_ARRAY_SZ + 4;
5111                         if (*unregistered != FALSE) {
5112                                 *unregistered = TRUE;
5113                         }
5114                 }
5115         }
5116
5117         if (action & F_END) {
5118                 for (i = 0; i < a->item_list_sz; i++) {
5119
5120                         /* Check if there is something to display */
5121                         pos = i * FC_ARRAY_SZ;
5122                         if (!**(out + pos))
5123                                 continue;
5124
5125                         item_name = *(out + pos + 4);
5126                         draw_activity_graphs(a->g_nr, g_type,
5127                                              title, g_title, item_name, group,
5128                                              spmin + pos, spmax + pos, out + pos, outsize + pos,
5129                                              svg_p, record_hdr, FALSE, a, i);
5130                 }
5131
5132                 /* Free remaining structures */
5133                 free_graphs(out, outsize, spmin, spmax);
5134         }
5135 }
5136
5137 /*
5138  ***************************************************************************
5139  * Display softnet statistics in SVG.
5140  *
5141  * IN:
5142  * @a           Activity structure with statistics.
5143  * @curr        Index in array for current sample statistics.
5144  * @action      Action expected from current function.
5145  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5146  *              flag indicating that a restart record has been previously
5147  *              found (.@restart) and time used for the X axis origin
5148  *              (@ust_time_ref).
5149  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5150  * @record_hdr  Pointer on record header of current stats sample.
5151  ***************************************************************************
5152  */
5153 #define SOFT_ARRAY_SZ   5
5154 __print_funct_t svg_print_softnet_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5155                                         unsigned long long itv, struct record_header *record_hdr)
5156 {
5157         struct stats_softnet *ssnc, *ssnp, ssnczero;
5158         int group[] = {2, 3};
5159         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
5160         char *title[] = {"Software-based network processing statistics (1)",
5161                          "Software-based network processing statistics (2)"};
5162         char *g_title[] = {"total/s", "dropd/s",
5163                            "squeezd/s", "rx_rps/s", "flw_lim/s"};
5164         int g_fields[] = {0, 1, 2, 3, 4};
5165         static double *spmin, *spmax;
5166         static char **out;
5167         static int *outsize;
5168         char item_name[16];
5169         unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
5170         int i, pos, restart;
5171
5172         if (action & F_BEGIN) {
5173                 /*
5174                  * Allocate arrays that will contain the graphs data
5175                  * and the min/max values.
5176                  */
5177                 out = allocate_graph_lines(SOFT_ARRAY_SZ * a->item_list_sz, &outsize, &spmin, &spmax);
5178         }
5179
5180         if (action & F_MAIN) {
5181                 memset(&ssnczero, 0, STATS_SOFTNET_SIZE);
5182
5183                 /* @nr[curr] cannot normally be greater than @nr_ini */
5184                 if (a->nr[curr] > a->nr_ini) {
5185                         a->nr_ini = a->nr[curr];
5186                 }
5187
5188                 /* Compute statistics for CPU "all" */
5189                 get_global_soft_statistics(a, !curr, curr, flags, offline_cpu_bitmap);
5190
5191                 /* For each CPU */
5192                 for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
5193                         restart = svg_p->restart;
5194
5195                         /* Should current CPU (including CPU "all") be displayed? */
5196                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
5197                                 /* No */
5198                                 continue;
5199
5200                         ssnc = (struct stats_softnet *) ((char *) a->buf[curr]  + i * a->msize);
5201                         ssnp = (struct stats_softnet *) ((char *) a->buf[!curr] + i * a->msize);
5202
5203                         /* Is current CPU marked offline? */
5204                         if (offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07))) {
5205                                 /*
5206                                  * Yes and it doesn't follow a RESTART record.
5207                                  * To add a discontinuity in graph, we simulate
5208                                  * a RESTART mark.
5209                                  */
5210                                 restart = TRUE;
5211                                 if (svg_p->restart) {
5212                                         /*
5213                                          * CPU is offline and it follows a real
5214                                          * RESTART record. Ignore its current value
5215                                          * (no previous sample).
5216                                          */
5217                                         ssnc = &ssnczero;
5218                                 }
5219                         }
5220                         pos = i * SOFT_ARRAY_SZ;
5221
5222                         /* Check for min/max values */
5223                         save_extrema(a->gtypes_nr, (void *) ssnc, (void *) ssnp,
5224                                      itv, spmin + pos, spmax + pos, g_fields);
5225
5226                         /* total/s */
5227                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5228                                  S_VALUE(ssnp->processed, ssnc->processed, itv),
5229                                  out + pos, outsize + pos, restart);
5230                         /* dropd/s */
5231                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5232                                  S_VALUE(ssnp->dropped, ssnc->dropped, itv),
5233                                  out + pos + 1, outsize + pos + 1, restart);
5234                         /* squeezd/s */
5235                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5236                                  S_VALUE(ssnp->time_squeeze, ssnc->time_squeeze, itv),
5237                                  out + pos + 2, outsize + pos + 2, restart);
5238                         /* rx_rps/s */
5239                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5240                                  S_VALUE(ssnp->received_rps, ssnc->received_rps, itv),
5241                                  out + pos + 3, outsize + pos + 3, restart);
5242                         /* flw_lim/s */
5243                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5244                                  S_VALUE(ssnp->flow_limit, ssnc->flow_limit, itv),
5245                                  out + pos + 4, outsize + pos + 4, restart);
5246                 }
5247         }
5248
5249         if (action & F_END) {
5250                 for (i = 0; (i < a->item_list_sz) && (i < a->bitmap->b_size + 1); i++) {
5251
5252                         /* Should current CPU (including CPU "all") be displayed? */
5253                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
5254                                 /* No */
5255                                 continue;
5256
5257                         pos = i * SOFT_ARRAY_SZ;
5258
5259                         if (!i) {
5260                                 /* This is CPU "all" */
5261                                 strcpy(item_name, "all");
5262                         }
5263                         else {
5264                                 sprintf(item_name, "%d", i - 1);
5265                         }
5266
5267                         draw_activity_graphs(a->g_nr, g_type,
5268                                              title, g_title, item_name, group,
5269                                              spmin + pos, spmax + pos, out + pos, outsize + pos,
5270                                              svg_p, record_hdr, FALSE, a, i);
5271                 }
5272
5273                 /* Free remaining structures */
5274                 free_graphs(out, outsize, spmin, spmax);
5275         }
5276 }
5277
5278 /*
5279  ***************************************************************************
5280  * Display pressure-stall CPU statistics in SVG.
5281  *
5282  * IN:
5283  * @a           Activity structure with statistics.
5284  * @curr        Index in array for current sample statistics.
5285  * @action      Action expected from current function.
5286  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5287  *              flag indicating that a restart record has been previously
5288  *              found (.@restart) and time used for the X axis origin
5289  *              (@ust_time_ref).
5290  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5291  * @record_hdr  Pointer on record header of current stats sample.
5292  ***************************************************************************
5293  */
5294 __print_funct_t svg_print_psicpu_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5295                                        unsigned long long itv, struct record_header *record_hdr)
5296 {
5297         struct stats_psi_cpu
5298                 *psic = (struct stats_psi_cpu *) a->buf[curr],
5299                 *psip = (struct stats_psi_cpu *) a->buf[!curr];
5300         int group[] = {3, 1};
5301         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
5302         char *title[] = {"CPU pressure trends (some tasks)", "CPU stall time (some tasks)"};
5303         char *g_title[] = {"%scpu-10", "%scpu-60", "%scpu-300",
5304                            "%scpu"};
5305         static double *spmin, *spmax;
5306         static char **out;
5307         static int *outsize;
5308         double tval;
5309
5310         if (action & F_BEGIN) {
5311                 /*
5312                  * Allocate arrays that will contain the graphs data
5313                  * and the min/max values.
5314                  */
5315                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
5316         }
5317
5318         if (action & F_MAIN) {
5319                 /* Check for min/max values */
5320                 if (psic->some_acpu_10 > *spmax) {
5321                         *spmax = psic->some_acpu_10;
5322                 }
5323                 if (psic->some_acpu_10 < *spmin) {
5324                         *spmin = psic->some_acpu_10;
5325                 }
5326                 if (psic->some_acpu_60 > *(spmax + 1)) {
5327                         *(spmax + 1) = psic->some_acpu_60;
5328                 }
5329                 if (psic->some_acpu_60 < *(spmin + 1)) {
5330                         *(spmin + 1) = psic->some_acpu_60;
5331                 }
5332                 if (psic->some_acpu_300 > *(spmax + 2)) {
5333                         *(spmax + 2) = psic->some_acpu_300;
5334                 }
5335                 if (psic->some_acpu_300 < *(spmin + 2)) {
5336                         *(spmin + 2) = psic->some_acpu_300;
5337                 }
5338                 tval = ((double) psic->some_cpu_total - psip->some_cpu_total) / (100 * itv);
5339                 if (tval > *(spmax + 3)) {
5340                         *(spmax + 3) = tval;
5341                 }
5342                 if (tval < *(spmin + 3)) {
5343                         *(spmin + 3) = tval;
5344                 }
5345
5346                 /* %scpu-10 */
5347                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5348                          (double) psic->some_acpu_10 / 100,
5349                          out, outsize, svg_p->restart);
5350                 /* %scpu-60 */
5351                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5352                          (double) psic->some_acpu_60 / 100,
5353                          out + 1, outsize + 1, svg_p->restart);
5354                 /* %scpu-300 */
5355                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5356                          (double) psic->some_acpu_300 / 100,
5357                          out + 2, outsize + 2, svg_p->restart);
5358                 /* %scpu */
5359                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5360                          0.0,
5361                          ((double) psic->some_cpu_total - psip->some_cpu_total) / (100 * itv),
5362                          out + 3, outsize + 3, svg_p->dt);
5363         }
5364
5365         if (action & F_END) {
5366                 /* Fix min/max values for pressure ratios */
5367                 *spmin /= 100; *spmax /= 100;
5368                 *(spmin + 1) /= 100; *(spmax + 1) /= 100;
5369                 *(spmin + 2) /= 100; *(spmax + 2) /= 100;
5370
5371                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
5372                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
5373
5374                 /* Free remaining structures */
5375                 free_graphs(out, outsize, spmin, spmax);
5376         }
5377 }
5378
5379 /*
5380  ***************************************************************************
5381  * Display pressure-stall I/O statistics in SVG.
5382  *
5383  * IN:
5384  * @a           Activity structure with statistics.
5385  * @curr        Index in array for current sample statistics.
5386  * @action      Action expected from current function.
5387  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5388  *              flag indicating that a restart record has been previously
5389  *              found (.@restart) and time used for the X axis origin
5390  *              (@ust_time_ref).
5391  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5392  * @record_hdr  Pointer on record header of current stats sample.
5393  ***************************************************************************
5394  */
5395 __print_funct_t svg_print_psiio_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5396                                       unsigned long long itv, struct record_header *record_hdr)
5397 {
5398         struct stats_psi_io
5399                 *psic = (struct stats_psi_io *) a->buf[curr],
5400                 *psip = (struct stats_psi_io *) a->buf[!curr];
5401         int group[] = {3, 1, 3, 1};
5402         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH, SVG_LINE_GRAPH, SVG_BAR_GRAPH};
5403         char *title[] = {"I/O pressure trends (some tasks)", "I/O stall time (some tasks)",
5404                          "I/O pressure trends (full)", "I/O stall time (full)"};
5405         char *g_title[] = {"%sio-10", "%sio-60", "%sio-300",
5406                            "%sio",
5407                            "%fio-10", "%fio-60", "%fio-300",
5408                            "%fio"};
5409         static double *spmin, *spmax;
5410         static char **out;
5411         static int *outsize;
5412         double tval;
5413
5414         if (action & F_BEGIN) {
5415                 /*
5416                  * Allocate arrays that will contain the graphs data
5417                  * and the min/max values.
5418                  */
5419                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
5420         }
5421
5422         if (action & F_MAIN) {
5423                 /* Check for min/max values */
5424                 if (psic->some_aio_10 > *spmax) {
5425                         *spmax = psic->some_aio_10;
5426                 }
5427                 if (psic->some_aio_10 < *spmin) {
5428                         *spmin = psic->some_aio_10;
5429                 }
5430                 if (psic->some_aio_60 > *(spmax + 1)) {
5431                         *(spmax + 1) = psic->some_aio_60;
5432                 }
5433                 if (psic->some_aio_60 < *(spmin + 1)) {
5434                         *(spmin + 1) = psic->some_aio_60;
5435                 }
5436                 if (psic->some_aio_300 > *(spmax + 2)) {
5437                         *(spmax + 2) = psic->some_aio_300;
5438                 }
5439                 if (psic->some_aio_300 < *(spmin + 2)) {
5440                         *(spmin + 2) = psic->some_aio_300;
5441                 }
5442                 tval = ((double) psic->some_io_total - psip->some_io_total) / (100 * itv);
5443                 if (tval > *(spmax + 3)) {
5444                         *(spmax + 3) = tval;
5445                 }
5446                 if (tval < *(spmin + 3)) {
5447                         *(spmin + 3) = tval;
5448                 }
5449
5450                 if (psic->full_aio_10 > *(spmax + 4)) {
5451                         *(spmax + 4) = psic->full_aio_10;
5452                 }
5453                 if (psic->full_aio_10 < *(spmin + 4)) {
5454                         *(spmin + 4) = psic->full_aio_10;
5455                 }
5456                 if (psic->full_aio_60 > *(spmax + 5)) {
5457                         *(spmax + 5) = psic->full_aio_60;
5458                 }
5459                 if (psic->full_aio_60 < *(spmin + 5)) {
5460                         *(spmin + 5) = psic->full_aio_60;
5461                 }
5462                 if (psic->full_aio_300 > *(spmax + 6)) {
5463                         *(spmax + 6) = psic->full_aio_300;
5464                 }
5465                 if (psic->full_aio_300 < *(spmin + 6)) {
5466                         *(spmin + 6) = psic->full_aio_300;
5467                 }
5468                 tval = ((double) psic->full_io_total - psip->full_io_total) / (100 * itv);
5469                 if (tval > *(spmax + 7)) {
5470                         *(spmax + 7) = tval;
5471                 }
5472                 if (tval < *(spmin + 7)) {
5473                         *(spmin + 7) = tval;
5474                 }
5475
5476                 /* %sio-10 */
5477                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5478                          (double) psic->some_aio_10 / 100,
5479                          out, outsize, svg_p->restart);
5480                 /* %sio-60 */
5481                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5482                          (double) psic->some_aio_60 / 100,
5483                          out + 1, outsize + 1, svg_p->restart);
5484                 /* %sio-300 */
5485                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5486                          (double) psic->some_aio_300 / 100,
5487                          out + 2, outsize + 2, svg_p->restart);
5488                 /* %sio */
5489                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5490                          0.0,
5491                          ((double) psic->some_io_total - psip->some_io_total) / (100 * itv),
5492                          out + 3, outsize + 3, svg_p->dt);
5493
5494                 /* %fio-10 */
5495                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5496                          (double) psic->full_aio_10 / 100,
5497                          out + 4, outsize + 4, svg_p->restart);
5498                 /* %fio-60 */
5499                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5500                          (double) psic->full_aio_60 / 100,
5501                          out + 5, outsize + 5, svg_p->restart);
5502                 /* %fio-300 */
5503                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5504                          (double) psic->full_aio_300 / 100,
5505                          out + 6, outsize + 6, svg_p->restart);
5506                 /* %fio */
5507                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5508                          0.0,
5509                          ((double) psic->full_io_total - psip->full_io_total) / (100 * itv),
5510                          out + 7, outsize + 7, svg_p->dt);
5511         }
5512
5513         if (action & F_END) {
5514                 /* Fix min/max values for pressure ratios */
5515                 *spmin /= 100; *spmax /= 100;
5516                 *(spmin + 1) /= 100; *(spmax + 1) /= 100;
5517                 *(spmin + 2) /= 100; *(spmax + 2) /= 100;
5518
5519                 *(spmin + 4) /= 100; *(spmax + 4) /= 100;
5520                 *(spmin + 5) /= 100; *(spmax + 5) /= 100;
5521                 *(spmin + 6) /= 100; *(spmax + 6) /= 100;
5522
5523                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
5524                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
5525
5526                 /* Free remaining structures */
5527                 free_graphs(out, outsize, spmin, spmax);
5528         }
5529 }
5530
5531 /*
5532  ***************************************************************************
5533  * Display pressure-stall memory statistics in SVG.
5534  *
5535  * IN:
5536  * @a           Activity structure with statistics.
5537  * @curr        Index in array for current sample statistics.
5538  * @action      Action expected from current function.
5539  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5540  *              flag indicating that a restart record has been previously
5541  *              found (.@restart) and time used for the X axis origin
5542  *              (@ust_time_ref).
5543  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5544  * @record_hdr  Pointer on record header of current stats sample.
5545  ***************************************************************************
5546  */
5547 __print_funct_t svg_print_psimem_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5548                                        unsigned long long itv, struct record_header *record_hdr)
5549 {
5550         struct stats_psi_mem
5551                 *psic = (struct stats_psi_mem *) a->buf[curr],
5552                 *psip = (struct stats_psi_mem *) a->buf[!curr];
5553         int group[] = {3, 1, 3, 1};
5554         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH, SVG_LINE_GRAPH, SVG_BAR_GRAPH};
5555         char *title[] = {"Memory pressure trends (some tasks)", "Memory stall time (some tasks)",
5556                          "Memory pressure trends (full)", "Memory stall time (full)"};
5557         char *g_title[] = {"%smem-10", "%smem-60", "%smem-300",
5558                            "%smem",
5559                            "%fmem-10", "%fmem-60", "%fmem-300",
5560                            "%fmem"};
5561         static double *spmin, *spmax;
5562         static char **out;
5563         static int *outsize;
5564         double tval;
5565
5566         if (action & F_BEGIN) {
5567                 /*
5568                  * Allocate arrays that will contain the graphs data
5569                  * and the min/max values.
5570                  */
5571                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
5572         }
5573
5574         if (action & F_MAIN) {
5575                 /* Check for min/max values */
5576                 if (psic->some_amem_10 > *spmax) {
5577                         *spmax = psic->some_amem_10;
5578                 }
5579                 if (psic->some_amem_10 < *spmin) {
5580                         *spmin = psic->some_amem_10;
5581                 }
5582                 if (psic->some_amem_60 > *(spmax + 1)) {
5583                         *(spmax + 1) = psic->some_amem_60;
5584                 }
5585                 if (psic->some_amem_60 < *(spmin + 1)) {
5586                         *(spmin + 1) = psic->some_amem_60;
5587                 }
5588                 if (psic->some_amem_300 > *(spmax + 2)) {
5589                         *(spmax + 2) = psic->some_amem_300;
5590                 }
5591                 if (psic->some_amem_300 < *(spmin + 2)) {
5592                         *(spmin + 2) = psic->some_amem_300;
5593                 }
5594                 tval = ((double) psic->some_mem_total - psip->some_mem_total) / (100 * itv);
5595                 if (tval > *(spmax + 3)) {
5596                         *(spmax + 3) = tval;
5597                 }
5598                 if (tval < *(spmin + 3)) {
5599                         *(spmin + 3) = tval;
5600                 }
5601
5602                 if (psic->full_amem_10 > *(spmax + 4)) {
5603                         *(spmax + 4) = psic->full_amem_10;
5604                 }
5605                 if (psic->full_amem_10 < *(spmin + 4)) {
5606                         *(spmin + 4) = psic->full_amem_10;
5607                 }
5608                 if (psic->full_amem_60 > *(spmax + 5)) {
5609                         *(spmax + 5) = psic->full_amem_60;
5610                 }
5611                 if (psic->full_amem_60 < *(spmin + 5)) {
5612                         *(spmin + 5) = psic->full_amem_60;
5613                 }
5614                 if (psic->full_amem_300 > *(spmax + 6)) {
5615                         *(spmax + 6) = psic->full_amem_300;
5616                 }
5617                 if (psic->full_amem_300 < *(spmin + 6)) {
5618                         *(spmin + 6) = psic->full_amem_300;
5619                 }
5620                 tval = ((double) psic->full_mem_total - psip->full_mem_total) / (100 * itv);
5621                 if (tval > *(spmax + 7)) {
5622                         *(spmax + 7) = tval;
5623                 }
5624                 if (tval < *(spmin + 7)) {
5625                         *(spmin + 7) = tval;
5626                 }
5627
5628                 /* %smem-10 */
5629                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5630                          (double) psic->some_amem_10 / 100,
5631                          out, outsize, svg_p->restart);
5632                 /* %smem-60 */
5633                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5634                          (double) psic->some_amem_60 / 100,
5635                          out + 1, outsize + 1, svg_p->restart);
5636                 /* %smem-300 */
5637                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5638                          (double) psic->some_amem_300 / 100,
5639                          out + 2, outsize + 2, svg_p->restart);
5640                 /* %smem */
5641                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5642                          0.0,
5643                          ((double) psic->some_mem_total - psip->some_mem_total) / (100 * itv),
5644                          out + 3, outsize + 3, svg_p->dt);
5645
5646                 /* %fmem-10 */
5647                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5648                          (double) psic->full_amem_10 / 100,
5649                          out + 4, outsize + 4, svg_p->restart);
5650                 /* %fmem-60 */
5651                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5652                          (double) psic->full_amem_60 / 100,
5653                          out + 5, outsize + 5, svg_p->restart);
5654                 /* %fmem-300 */
5655                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5656                          (double) psic->full_amem_300 / 100,
5657                          out + 6, outsize + 6, svg_p->restart);
5658                 /* %fmem */
5659                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5660                          0.0,
5661                          ((double) psic->full_mem_total - psip->full_mem_total) / (100 * itv),
5662                          out + 7, outsize + 7, svg_p->dt);
5663         }
5664
5665         if (action & F_END) {
5666                 /* Fix min/max values for pressure ratios */
5667                 *spmin /= 100; *spmax /= 100;
5668                 *(spmin + 1) /= 100; *(spmax + 1) /= 100;
5669                 *(spmin + 2) /= 100; *(spmax + 2) /= 100;
5670
5671                 *(spmin + 4) /= 100; *(spmax + 4) /= 100;
5672                 *(spmin + 5) /= 100; *(spmax + 5) /= 100;
5673                 *(spmin + 6) /= 100; *(spmax + 6) /= 100;
5674
5675                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
5676                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a, 0);
5677
5678                 /* Free remaining structures */
5679                 free_graphs(out, outsize, spmin, spmax);
5680         }
5681 }