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