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