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