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