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