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