]> granicus.if.org Git - sysstat/blob - svg_stats.c
sadf: SVG: Always start id numbers at zero
[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
1065         /* For next row of views */
1066         (svg_p->graph_no) += PACK_VIEWS(flags) ? 1 : views_nr;
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         double tval;
1691         int i;
1692         unsigned long long nousedmem;
1693
1694         if (action & F_BEGIN) {
1695                 /*
1696                  * Allocate arrays that will contain the graphs data
1697                  * and the min/max values.
1698                  */
1699                 out = allocate_graph_lines(23, &outsize, &spmin, &spmax);
1700         }
1701
1702         if (action & F_MAIN) {
1703                 /* Check for min/max values */
1704                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
1705                              itv, spmin, spmax, g_fields);
1706                 /* Compute %memused min/max values */
1707                 nousedmem = smc->frmkb + smc->bufkb + smc->camkb + smc->slabkb;
1708                 if (nousedmem > smc->tlmkb) {
1709                         nousedmem = smc->tlmkb;
1710                 }
1711                 tval = smc->tlmkb ? SP_VALUE(nousedmem, smc->tlmkb, smc->tlmkb) : 0.0;
1712                 if (tval > *(spmax + 3)) {
1713                         *(spmax + 3) = tval;
1714                 }
1715                 if (tval < *(spmin + 3)) {
1716                         *(spmin + 3) = tval;
1717                 }
1718                 /* Compute %commit min/max values */
1719                 tval = (smc->tlmkb + smc->tlskb) ?
1720                        SP_VALUE(0, smc->comkb, smc->tlmkb + smc->tlskb) : 0.0;
1721                 if (tval > *(spmax + 7)) {
1722                         *(spmax + 7) = tval;
1723                 }
1724                 if (tval < *(spmin + 7)) {
1725                         *(spmin + 7) = tval;
1726                 }
1727                 /* Compute %swpused min/max values */
1728                 tval = smc->tlskb ?
1729                        SP_VALUE(smc->frskb, smc->tlskb, smc->tlskb) : 0.0;
1730                 if (tval > *(spmax + 19)) {
1731                         *(spmax + 19) = tval;
1732                 }
1733                 if (tval < *(spmin + 19)) {
1734                         *(spmin + 19) = tval;
1735                 }
1736                 /* Compute %swpcad min/max values */
1737                 tval = (smc->tlskb - smc->frskb) ?
1738                        SP_VALUE(0, smc->caskb, smc->tlskb - smc->frskb) : 0.0;
1739                 if (tval > *(spmax + 20)) {
1740                         *(spmax + 20) = tval;
1741                 }
1742                 if (tval < *(spmin + 20)) {
1743                         *(spmin + 20) = tval;
1744                 }
1745                 /* Compute memused min/max values in MB */
1746                 tval = ((double) (smc->tlmkb - nousedmem)) / 1024;
1747                 if (tval > *(spmax + 2)) {
1748                         *(spmax + 2) = tval;
1749                 }
1750                 if (tval < *(spmin + 2)) {
1751                         *(spmin + 2) = tval;
1752                 }
1753                 /* Compute swpused min/max values in MB */
1754                 tval = ((double) (smc->tlskb - smc->frskb)) / 1024;
1755                 if (tval > *(spmax + 17)) {
1756                         *(spmax + 17) = tval;
1757                 }
1758                 if (tval < *(spmin + 17)) {
1759                         *(spmin + 17) = tval;
1760                 }
1761
1762                 /* MBmemfree */
1763                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1764                          ((double) smc->frmkb) / 1024,
1765                          out, outsize, svg_p->restart);
1766                 /* MBmemused */
1767                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1768                          ((double) (smc->tlmkb - nousedmem)) / 1024,
1769                          out + 2, outsize + 2, svg_p->restart);
1770                 /* MBavail */
1771                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1772                          ((double) smc->availablekb) / 1024,
1773                          out + 1, outsize + 1, svg_p->restart);
1774                 /* MBbuffers */
1775                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1776                          ((double) smc->bufkb) / 1024,
1777                          out + 4, outsize + 4, svg_p->restart);
1778                 /* MBcached */
1779                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1780                          ((double) smc->camkb) / 1024,
1781                           out + 5, outsize + 5, svg_p->restart);
1782                 /* MBswpfree */
1783                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1784                          ((double) smc->frskb) / 1024,
1785                          out + 16, outsize + 16, svg_p->restart);
1786                 /* MBswpused */
1787                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1788                          ((double) (smc->tlskb - smc->frskb)) / 1024,
1789                          out + 17, outsize + 17, svg_p->restart);
1790                 /* MBswpcad */
1791                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1792                          ((double) smc->caskb) / 1024,
1793                          out + 18, outsize + 18, svg_p->restart);
1794                 /* MBcommit */
1795                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1796                          ((double) smc->comkb) / 1024,
1797                          out + 6, outsize + 6, svg_p->restart);
1798                 /* MBactive */
1799                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1800                          ((double) smc->activekb) / 1024,
1801                          out + 8, outsize + 8, svg_p->restart);
1802                 /* MBinact */
1803                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1804                          ((double) smc->inactkb) / 1024,
1805                          out + 9, outsize + 9, svg_p->restart);
1806                 /* MBdirty */
1807                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1808                          ((double) smc->dirtykb) / 1024,
1809                          out + 10, outsize + 10, svg_p->restart);
1810                 /* MBanonpg */
1811                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1812                          ((double) smc->anonpgkb) / 1024,
1813                          out + 11, outsize + 11, svg_p->restart);
1814                 /* MBslab */
1815                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1816                          ((double) smc->slabkb) / 1024,
1817                          out + 12, outsize + 12, svg_p->restart);
1818                 /* MBkstack */
1819                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1820                          ((double) smc->kstackkb) / 1024,
1821                          out + 13, outsize + 13, svg_p->restart);
1822                 /* MBpgtbl */
1823                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1824                          ((double) smc->pgtblkb) / 1024,
1825                          out + 14, outsize + 14, svg_p->restart);
1826                 /* MBvmused */
1827                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1828                          ((double) smc->vmusedkb) / 1024,
1829                          out + 15, outsize + 15, svg_p->restart);
1830                 /* %memused */
1831                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1832                          0.0,
1833                          smc->tlmkb ?
1834                          SP_VALUE(nousedmem, smc->tlmkb, smc->tlmkb) : 0.0,
1835                          out + 3, outsize + 3, svg_p->dt);
1836                 /* %commit */
1837                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1838                          0.0,
1839                          (smc->tlmkb + smc->tlskb) ?
1840                          SP_VALUE(0, smc->comkb, smc->tlmkb + smc->tlskb) : 0.0,
1841                          out + 7, outsize + 7, svg_p->dt);
1842                 /* %swpused */
1843                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1844                          0.0,
1845                          smc->tlskb ?
1846                          SP_VALUE(smc->frskb, smc->tlskb, smc->tlskb) : 0.0,
1847                          out + 19, outsize + 19, svg_p->dt);
1848                 /* %swpcad */
1849                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1850                          0.0,
1851                          (smc->tlskb - smc->frskb) ?
1852                          SP_VALUE(0, smc->caskb, smc->tlskb - smc->frskb) : 0.0,
1853                          out + 20, outsize + 20, svg_p->dt);
1854         }
1855
1856         if (action & F_END) {
1857
1858                 /* Conversion kB -> MB */
1859                 for (i = 0; i < 17; i++) {
1860                         *(spmin + g_fields[i]) /= 1024;
1861                         *(spmax + g_fields[i]) /= 1024;
1862                 }
1863
1864                 if (DISPLAY_MEMORY(a->opt_flags)) {
1865                         draw_activity_graphs(DISPLAY_MEM_ALL(a->opt_flags) ? 6 : 5,
1866                                              g_type1, title1, g_title1, NULL, group1,
1867                                              spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
1868                 }
1869
1870                 if (DISPLAY_SWAP(a->opt_flags)) {
1871                         draw_activity_graphs(3, g_type2, title2, g_title2, NULL, group2,
1872                                              spmin + 16, spmax + 16, out + 16, outsize + 16,
1873                                              svg_p, record_hdr, FALSE, a->id, 1);
1874                 }
1875
1876                 /* Free remaining structures */
1877                 free_graphs(out, outsize, spmin, spmax);
1878         }
1879 }
1880
1881 /*
1882  ***************************************************************************
1883  * Display kernel tables statistics in SVG.
1884  *
1885  * IN:
1886  * @a           Activity structure with statistics.
1887  * @curr        Index in array for current sample statistics.
1888  * @action      Action expected from current function.
1889  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1890  *              flag indicating that a restart record has been previously
1891  *              found (.@restart) and time used for the X axis origin
1892  *              (@ust_time_ref).
1893  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1894  * @record_hdr  Pointer on record header of current stats sample.
1895  ***************************************************************************
1896  */
1897 __print_funct_t svg_print_ktables_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1898                                         unsigned long long itv, struct record_header *record_hdr)
1899 {
1900         struct stats_ktables
1901                 *skc = (struct stats_ktables *) a->buf[curr];
1902         int group[] = {3, 1};
1903         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
1904         char *title[] = {"Kernel tables statistics (1)", "Kernel tables statistics (2)"};
1905         char *g_title[] = {"~dentunusd", "~file-nr", "~inode-nr",
1906                            "~pty-nr"};
1907         int g_fields[] = {1, 2, 0, 3};
1908         static double *spmin, *spmax;
1909         static char **out;
1910         static int *outsize;
1911
1912         if (action & F_BEGIN) {
1913                 /*
1914                  * Allocate arrays that will contain the graphs data
1915                  * and the min/max values.
1916                  */
1917                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
1918         }
1919
1920         if (action & F_MAIN) {
1921                 /* Check for min/max values */
1922                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
1923                              itv, spmin, spmax, g_fields);
1924                 /* dentunusd */
1925                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1926                           (unsigned long long) skc->dentry_stat,
1927                           out, outsize, svg_p->restart);
1928                 /* file-nr */
1929                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1930                           (unsigned long long) skc->file_used,
1931                           out + 1, outsize + 1, svg_p->restart);
1932                 /* inode-nr */
1933                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1934                           (unsigned long long) skc->inode_used,
1935                           out + 2, outsize + 2, svg_p->restart);
1936                 /* pty-nr */
1937                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1938                           (unsigned long long) skc->pty_nr,
1939                           out + 3, outsize + 3, svg_p->restart);
1940         }
1941
1942         if (action & F_END) {
1943                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
1944                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
1945
1946                 /* Free remaining structures */
1947                 free_graphs(out, outsize, spmin, spmax);
1948         }
1949 }
1950
1951 /*
1952  ***************************************************************************
1953  * Display queue and load statistics in SVG.
1954  *
1955  * IN:
1956  * @a           Activity structure with statistics.
1957  * @curr        Index in array for current sample statistics.
1958  * @action      Action expected from current function.
1959  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
1960  *              flag indicating that a restart record has been previously
1961  *              found (.@restart) and time used for the X axis origin
1962  *              (@ust_time_ref).
1963  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
1964  * @record_hdr  Pointer on record header of current stats sample.
1965  ***************************************************************************
1966  */
1967 __print_funct_t svg_print_queue_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1968                                       unsigned long long itv, struct record_header *record_hdr)
1969 {
1970         struct stats_queue
1971                 *sqc = (struct stats_queue *) a->buf[curr];
1972         int group[] = {2, 1, 3};
1973         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
1974         char *title[] = {"Queue length", "Task list statistics", "Load average statistics"};
1975         char *g_title[] = {"~runq-sz", "~blocked",
1976                            "~plist-sz",
1977                            "ldavg-1", "ldavg-5", "ldavg-15"};
1978         int g_fields[] = {0, 1, 2, 3, 4, 5};
1979         static double *spmin, *spmax;
1980         static char **out;
1981         static int *outsize;
1982
1983         if (action & F_BEGIN) {
1984                 /*
1985                  * Allocate arrays that will contain the graphs data
1986                  * and the min/max values.
1987                  */
1988                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
1989         }
1990
1991         if (action & F_MAIN) {
1992                 /* Check for min/max values */
1993                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
1994                              itv, spmin, spmax, g_fields);
1995                 /* runq-sz */
1996                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1997                           (unsigned long long) sqc->nr_running,
1998                           out, outsize, svg_p->restart);
1999                 /* blocked */
2000                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2001                           (unsigned long long) sqc->procs_blocked,
2002                           out + 1, outsize + 1, svg_p->restart);
2003                 /* plist-sz */
2004                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2005                           (unsigned long long) sqc->nr_threads,
2006                           out + 2, outsize + 2, svg_p->restart);
2007                 /* ldavg-1 */
2008                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2009                          (double) sqc->load_avg_1 / 100,
2010                          out + 3, outsize + 3, svg_p->restart);
2011                 /* ldavg-5 */
2012                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2013                          (double) sqc->load_avg_5 / 100,
2014                          out + 4, outsize + 4, svg_p->restart);
2015                 /* ldavg-15 */
2016                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2017                          (double) sqc->load_avg_15 / 100,
2018                          out + 5, outsize + 5, svg_p->restart);
2019         }
2020
2021         if (action & F_END) {
2022                 /* Fix min/max values for load average */
2023                 *(spmin + 3) /= 100; *(spmax + 3) /= 100;
2024                 *(spmin + 4) /= 100; *(spmax + 4) /= 100;
2025                 *(spmin + 5) /= 100; *(spmax + 5) /= 100;
2026
2027                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2028                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
2029
2030                 /* Free remaining structures */
2031                 free_graphs(out, outsize, spmin, spmax);
2032         }
2033 }
2034
2035 /*
2036  ***************************************************************************
2037  * Display disk statistics in SVG.
2038  *
2039  * IN:
2040  * @a           Activity structure with statistics.
2041  * @curr        Index in array for current sample statistics.
2042  * @action      Action expected from current function.
2043  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2044  *              flag indicating that a restart record has been previously
2045  *              found (.@restart) and time used for the X axis origin
2046  *              (@ust_time_ref).
2047  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2048  * @record_hdr  Pointer on record header of current stats sample.
2049  ***************************************************************************
2050  */
2051 __print_funct_t svg_print_disk_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2052                                      unsigned long long itv, struct record_header *record_hdr)
2053 {
2054         struct stats_disk *sdc, *sdp, sdpzero;
2055         struct ext_disk_stats xds;
2056         int group[] = {1, 2, 2, 2, 1};
2057         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2058                         SVG_LINE_GRAPH, SVG_BAR_GRAPH};
2059         char *title[] = {"Block devices statistics (1)", "Block devices statistics (2)",
2060                          "Block devices statistics (3)", "Block devices statistics (4)",
2061                          "Block devices statistics (5)"};
2062         char *g_title[] = {"tps",
2063                            "rkB/s", "wkB/s",
2064                            "areq-sz", "aqu-sz",
2065                            "await", "svctm",
2066                            "%util"};
2067         int g_fields[] = {0, 1, 2};
2068         unsigned int local_types_nr[] = {1, 0, 0};
2069         static double *spmin, *spmax;
2070         static char **out;
2071         static int *outsize;
2072         char *item_name;
2073         double rkB, wkB, aqusz;
2074         int i, j, k, pos, restart, *unregistered;
2075
2076         if (action & F_BEGIN) {
2077                 /*
2078                  * Allocate arrays (#0..7) that will contain the graphs data
2079                  * and the min/max values.
2080                  * Also allocate one additional array (#8) for each disk device:
2081                  * spmax + 8 will contain the device major number,
2082                  * spmin + 8 will contain the device minor number,
2083                  * outsize + 8 will contain a positive value (TRUE) if the device
2084                  * has either still not been registered, or has been unregistered.
2085                  */
2086                 out = allocate_graph_lines(9 * svg_p->nr_max, &outsize, &spmin, &spmax);
2087         }
2088
2089         if (action & F_MAIN) {
2090                 memset(&sdpzero, 0, STATS_DISK_SIZE);
2091                 restart = svg_p->restart;
2092                 /*
2093                  * Mark previously registered devices as now
2094                  * possibly unregistered for all graphs.
2095                  */
2096                 for (k = 0; k < svg_p->nr_max; k++) {
2097                         unregistered = outsize + k * 9 + 8;
2098                         if (*unregistered == FALSE) {
2099                                 *unregistered = MAYBE;
2100                         }
2101                 }
2102
2103                 /* For each device structure */
2104                 for (i = 0; i < a->nr[curr]; i++) {
2105                         sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
2106
2107                         /* Get device name */
2108                         item_name = get_sa_devname(sdc->major, sdc->minor, flags);
2109
2110                         if (dlst_dev_idx) {
2111                                 /* A list of devices has been entered on the command line */
2112                                 if (!search_sa_dlist(st_dev_list, dlst_dev_idx, item_name))
2113                                         /* Device not found */
2114                                         continue;
2115                         }
2116
2117                         /* Look for corresponding graph */
2118                         for (k = 0; k < svg_p->nr_max; k++) {
2119                                 if ((sdc->major == *(spmax + k * 9 + 8)) &&
2120                                     (sdc->minor == *(spmin + k * 9 + 8)))
2121                                         /* Graph found! */
2122                                         break;
2123                         }
2124                         if (k == svg_p->nr_max) {
2125                                 /* Graph not found: Look for first free entry */
2126                                 for (k = 0; k < svg_p->nr_max; k++) {
2127                                         if (*(spmax + k * 9 + 8) == -DBL_MAX)
2128                                                 break;
2129                                 }
2130                                 if (k == svg_p->nr_max) {
2131                                         /* No free graph entry: Extend all buffers */
2132                                         reallocate_all_graph_lines(svg_p->nr_max,
2133                                                                    &out, &outsize, &spmin, &spmax);
2134                                         svg_p->nr_max *= 2;
2135                                 }
2136                         }
2137                         pos = k * 9;
2138                         unregistered = outsize + pos + 8;
2139
2140                         /*
2141                          * If current device was marked as previously unregistered,
2142                          * then set restart variable to TRUE so that the graph will be
2143                          * discontinuous, and mark it as now registered.
2144                          */
2145                         if (*unregistered == TRUE) {
2146                                 restart = TRUE;
2147                         }
2148                         *unregistered = FALSE;
2149
2150                         if (*(spmax + pos + 8) == -DBL_MAX) {
2151                                 /* Save device major and minor numbers (if not already done) */
2152                                 *(spmax + pos + 8) = sdc->major;
2153                                 *(spmin + pos + 8) = sdc->minor;
2154                         }
2155
2156                         j = check_disk_reg(a, curr, !curr, i);
2157                         if (j < 0) {
2158                                 /* This is a newly registered interface. Previous stats are zero */
2159                                 sdp = &sdpzero;
2160                         }
2161                         else {
2162                                 sdp = (struct stats_disk *) ((char *) a->buf[!curr] + j * a->msize);
2163                         }
2164
2165                         /* Check for min/max values */
2166                         save_extrema(local_types_nr, (void *) sdc, (void *) sdp,
2167                                      itv, spmin + pos, spmax + pos, g_fields);
2168
2169                         rkB = S_VALUE(sdp->rd_sect, sdc->rd_sect, itv) / 2;
2170                         wkB = S_VALUE(sdp->wr_sect, sdc->wr_sect, itv) / 2;
2171                         if (rkB < *(spmin + pos + 1)) {
2172                                 *(spmin + pos + 1) = rkB;
2173                         }
2174                         if (rkB > *(spmax + pos + 1)) {
2175                                 *(spmax + pos + 1) = rkB;
2176                         }
2177                         if (wkB < *(spmin + pos + 2)) {
2178                                 *(spmin + pos + 2) = wkB;
2179                         }
2180                         if (wkB > *(spmax + pos + 2)) {
2181                                 *(spmax + pos + 2) = wkB;
2182                         }
2183
2184                         compute_ext_disk_stats(sdc, sdp, itv, &xds);
2185                         if ((xds.arqsz / 2) < *(spmin + pos + 3)) {
2186                                 *(spmin + pos + 3) = xds.arqsz / 2;
2187                         }
2188                         if ((xds.arqsz / 2) > *(spmax + pos + 3)) {
2189                                 *(spmax + pos + 3) = xds.arqsz / 2;
2190                         }
2191                         aqusz = S_VALUE(sdp->rq_ticks, sdc->rq_ticks, itv) / 1000.0;
2192                         if (aqusz < *(spmin + pos + 4)) {
2193                                 *(spmin + pos + 4) = aqusz;
2194                         }
2195                         if (aqusz > *(spmax + pos + 4)) {
2196                                 *(spmax + pos + 4) = aqusz;
2197                         }
2198                         if (xds.await < *(spmin + pos + 5)) {
2199                                 *(spmin + pos + 5) = xds.await;
2200                         }
2201                         if (xds.await > *(spmax + pos + 5)) {
2202                                 *(spmax + pos + 5) = xds.await;
2203                         }
2204                         if (xds.svctm < *(spmin + pos + 6)) {
2205                                 *(spmin + pos + 6) = xds.svctm;
2206                         }
2207                         if (xds.svctm > *(spmax + pos + 6)) {
2208                                 *(spmax + pos + 6) = xds.svctm;
2209                         }
2210                         if ((xds.util / 10.0) < *(spmin + pos + 7)) {
2211                                 *(spmin + pos + 7) = xds.util / 10.0;
2212                         }
2213                         if ((xds.util / 10.0) > *(spmax + pos + 7)) {
2214                                 *(spmax + pos + 7) = xds.util / 10.0;
2215                         }
2216
2217                         /* tps */
2218                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2219                                  S_VALUE(sdp->nr_ios, sdc->nr_ios, itv),
2220                                  out + pos, outsize + pos, restart);
2221                         /* rkB/s */
2222                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2223                                  S_VALUE(sdp->rd_sect, sdc->rd_sect, itv) / 2,
2224                                  out + pos + 1, outsize + pos + 1, restart);
2225                         /* wkB/s */
2226                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2227                                  S_VALUE(sdp->wr_sect, sdc->wr_sect, itv) / 2,
2228                                  out + pos + 2, outsize + pos + 2, restart);
2229                         /* areq-sz */
2230                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2231                                  xds.arqsz / 2,
2232                                  out + pos + 3, outsize + pos + 3, restart);
2233                         /* aqu-sz */
2234                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2235                                  aqusz,
2236                                  out + pos + 4, outsize + pos + 4, restart);
2237                         /* await */
2238                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2239                                  xds.await,
2240                                  out + pos + 5, outsize + pos + 5, restart);
2241                         /* svctm */
2242                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2243                                  xds.svctm,
2244                                  out + pos + 6, outsize + pos + 6, restart);
2245                         /* %util */
2246                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
2247                                  0.0, xds.util / 10.0,
2248                                  out + pos + 7, outsize + pos + 7, svg_p->dt);
2249                 }
2250
2251                 /* Mark devices not seen here as now unregistered */
2252                 for (k = 0; k < svg_p->nr_max; k++) {
2253                         unregistered = outsize + k * 9 + 8;
2254                         if (*unregistered != FALSE) {
2255                                 *unregistered = TRUE;
2256                         }
2257                 }
2258         }
2259
2260         if (action & F_END) {
2261                 int xid = 0;
2262
2263                 for (i = 0; i < svg_p->nr_max; i++) {
2264                         /* Check if there is something to display */
2265                         pos = i * 9;
2266                         if (!**(out + pos))
2267                                 continue;
2268
2269                         /* Get device name */
2270                         item_name = get_sa_devname(*(spmax + pos + 8), *(spmin + pos + 8), flags);
2271
2272                         if (draw_activity_graphs(a->g_nr, g_type,
2273                                                  title, g_title, item_name, group,
2274                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2275                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
2276                                 xid++;
2277                         }
2278                 }
2279
2280                 /* Free remaining structures */
2281                 free_graphs(out, outsize, spmin, spmax);
2282         }
2283 }
2284
2285 /*
2286  ***************************************************************************
2287  * Display network interfaces statistics in SVG.
2288  *
2289  * IN:
2290  * @a           Activity structure with statistics.
2291  * @curr        Index in array for current sample statistics.
2292  * @action      Action expected from current function.
2293  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2294  *              flag indicating that a restart record has been previously
2295  *              found (.@restart) and time used for the X axis origin
2296  *              (@ust_time_ref).
2297  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2298  * @record_hdr  Pointer on record header of current stats sample.
2299  ***************************************************************************
2300  */
2301 __print_funct_t svg_print_net_dev_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2302                                         unsigned long long itv, struct record_header *record_hdr)
2303 {
2304         struct stats_net_dev *sndc, *sndp, sndzero;
2305         int group[] = {2, 2, 3, 1};
2306         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2307                         SVG_BAR_GRAPH};
2308         char *title[] = {"Network interfaces statistics (1)", "Network interfaces statistics (2)",
2309                          "Network interfaces statistics (3)", "Network interfaces statistics (4)"};
2310         char *g_title[] = {"rxpck/s", "txpck/s",
2311                            "rxkB/s", "txkB/s",
2312                            "rxcmp/s", "txcmp/s", "rxmcst/s",
2313                            "%ifutil"};
2314         int g_fields[] = {0, 1, 2, 3, 4, 5, 6};
2315         unsigned int local_types_nr[] = {7, 0, 0};
2316         static double *spmin, *spmax;
2317         static char **out;
2318         static int *outsize;
2319         char *item_name;
2320         double rxkb, txkb, ifutil;
2321         int i, j, k, pos, restart, *unregistered;
2322
2323         if (action & F_BEGIN) {
2324                 /*
2325                  * Allocate arrays (#0..7) that will contain the graphs data
2326                  * and the min/max values.
2327                  * Also allocate one additional array (#8) for each interface:
2328                  * out + 8 will contain the interface name,
2329                  * outsize + 8 will contain a positive value (TRUE) if the interface
2330                  * has either still not been registered, or has been unregistered.
2331                  */
2332                 out = allocate_graph_lines(9 * svg_p->nr_max, &outsize, &spmin, &spmax);
2333         }
2334
2335         if (action & F_MAIN) {
2336                 memset(&sndzero, 0, STATS_NET_DEV_SIZE);
2337                 restart = svg_p->restart;
2338                 /*
2339                  * Mark previously registered interfaces as now
2340                  * possibly unregistered for all graphs.
2341                  */
2342                 for (k = 0; k < svg_p->nr_max; k++) {
2343                         unregistered = outsize + k * 9 + 8;
2344                         if (*unregistered == FALSE) {
2345                                 *unregistered = MAYBE;
2346                         }
2347                 }
2348
2349                 /* For each network interfaces structure */
2350                 for (i = 0; i < a->nr[curr]; i++) {
2351                         sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
2352
2353                         if (dlst_iface_idx) {
2354                                 /* A list of devices has been entered on the command line */
2355                                 if (!search_sa_dlist(st_iface_list, dlst_iface_idx, sndc->interface))
2356                                         /* Device not found */
2357                                         continue;
2358                         }
2359
2360                         /* Look for corresponding graph */
2361                         for (k = 0; k < svg_p->nr_max; k++) {
2362                                 item_name = *(out + k * 9 + 8);
2363                                 if (!strcmp(sndc->interface, item_name))
2364                                         /* Graph found! */
2365                                         break;
2366                         }
2367                         if (k == svg_p->nr_max) {
2368                                 /* Graph not found: Look for first free entry */
2369                                 for (k = 0; k < svg_p->nr_max; k++) {
2370                                         item_name = *(out + k * 9 + 8);
2371                                         if (!strcmp(item_name, ""))
2372                                                 break;
2373                                 }
2374                                 if (k == svg_p->nr_max) {
2375                                         /* No free graph entry: Extend all buffers */
2376                                         reallocate_all_graph_lines(svg_p->nr_max,
2377                                                                    &out, &outsize, &spmin, &spmax);
2378                                         svg_p->nr_max *= 2;
2379                                 }
2380                         }
2381
2382                         pos = k * 9;
2383                         unregistered = outsize + pos + 8;
2384
2385                         j = check_net_dev_reg(a, curr, !curr, i);
2386                         if (j < 0) {
2387                                 /* This is a newly registered interface. Previous stats are zero */
2388                                 sndp = &sndzero;
2389                         }
2390                         else {
2391                                 sndp = (struct stats_net_dev *) ((char *) a->buf[!curr] + j * a->msize);
2392                         }
2393
2394                         /*
2395                          * If current interface was marked as previously unregistered,
2396                          * then set restart variable to TRUE so that the graph will be
2397                          * discontinuous, and mark it as now registered.
2398                          */
2399                         if (*unregistered == TRUE) {
2400                                 restart = TRUE;
2401                         }
2402                         *unregistered = FALSE;
2403
2404                         if (!item_name[0]) {
2405                                 /* Save network interface name (if not already done) */
2406                                 strncpy(item_name, sndc->interface, CHUNKSIZE);
2407                                 item_name[CHUNKSIZE - 1] = '\0';
2408                         }
2409
2410                         /* Check for min/max values */
2411                         save_extrema(local_types_nr, (void *) sndc, (void *) sndp,
2412                                      itv, spmin + pos, spmax + pos, g_fields);
2413
2414                         rxkb = S_VALUE(sndp->rx_bytes, sndc->rx_bytes, itv);
2415                         txkb = S_VALUE(sndp->tx_bytes, sndc->tx_bytes, itv);
2416                         ifutil = compute_ifutil(sndc, rxkb, txkb);
2417                         if (ifutil < *(spmin + pos + 7)) {
2418                                 *(spmin + pos + 7) = ifutil;
2419                         }
2420                         if (ifutil > *(spmax + pos + 7)) {
2421                                 *(spmax + pos + 7) = ifutil;
2422                         }
2423
2424                         /* rxpck/s */
2425                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2426                                  S_VALUE(sndp->rx_packets, sndc->rx_packets, itv),
2427                                  out + pos, outsize + pos, restart);
2428                         /* txpck/s */
2429                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2430                                  S_VALUE(sndp->tx_packets, sndc->tx_packets, itv),
2431                                  out + pos + 1, outsize + pos + 1, restart);
2432                         /* rxkB/s */
2433                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2434                                  rxkb / 1024,
2435                                  out + pos + 2, outsize + pos + 2, restart);
2436                         /* txkB/s */
2437                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2438                                  txkb / 1024,
2439                                  out + pos + 3, outsize + pos + 3, restart);
2440                         /* rxcmp/s */
2441                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2442                                  S_VALUE(sndp->rx_compressed, sndc->rx_compressed, itv),
2443                                  out + pos + 4, outsize + pos + 4, restart);
2444                         /* txcmp/s */
2445                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2446                                  S_VALUE(sndp->tx_compressed, sndc->tx_compressed, itv),
2447                                  out + pos + 5, outsize + pos + 5, restart);
2448                         /* rxmcst/s */
2449                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2450                                  S_VALUE(sndp->multicast, sndc->multicast, itv),
2451                                  out + pos + 6, outsize + pos + 6, restart);
2452                         /* %ifutil */
2453                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
2454                                  0.0, ifutil,
2455                                  out + pos + 7, outsize + pos + 7, svg_p->dt);
2456                 }
2457
2458                 /* Mark interfaces not seen here as now unregistered */
2459                 for (k = 0; k < svg_p->nr_max; k++) {
2460                         unregistered = outsize + k * 9 + 8;
2461                         if (*unregistered != FALSE) {
2462                                 *unregistered = TRUE;
2463                         }
2464                 }
2465         }
2466
2467         if (action & F_END) {
2468                 int xid = 0;
2469
2470                 for (i = 0; i < svg_p->nr_max; i++) {
2471                         /*
2472                          * Check if there is something to display.
2473                          * Don't test sndc->interface because maybe the network
2474                          * interface has been registered later.
2475                          */
2476                         pos = i * 9;
2477                         if (!**(out + pos))
2478                                 continue;
2479
2480                         /* Recalculate min and max values in kB, not in B */
2481                         *(spmin + pos + 2) /= 1024;
2482                         *(spmax + pos + 2) /= 1024;
2483                         *(spmin + pos + 3) /= 1024;
2484                         *(spmax + pos + 3) /= 1024;
2485
2486                         item_name = *(out + pos + 8);
2487                         if (draw_activity_graphs(a->g_nr, g_type,
2488                                                  title, g_title, item_name, group,
2489                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2490                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
2491                                 xid++;
2492                         }
2493                 }
2494
2495                 /* Free remaining structures */
2496                 free_graphs(out, outsize, spmin, spmax);
2497         }
2498 }
2499
2500 /*
2501  ***************************************************************************
2502  * Display network interfaces errors statistics in SVG.
2503  *
2504  * IN:
2505  * @a           Activity structure with statistics.
2506  * @curr        Index in array for current sample statistics.
2507  * @action      Action expected from current function.
2508  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2509  *              flag indicating that a restart record has been previously
2510  *              found (.@restart) and time used for the X axis origin
2511  *              (@ust_time_ref).
2512  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2513  * @record_hdr  Pointer on record header of current stats sample.
2514  ***************************************************************************
2515  */
2516 __print_funct_t svg_print_net_edev_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2517                                          unsigned long long itv, struct record_header *record_hdr)
2518 {
2519         struct stats_net_edev *snedc, *snedp, snedzero;
2520         int group[] = {2, 2, 2, 3};
2521         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2522                         SVG_LINE_GRAPH};
2523         char *title[] = {"Network interfaces errors statistics (1)", "Network interfaces errors statistics (2)",
2524                          "Network interfaces errors statistics (3)", "Network interfaces errors statistics (4)"};
2525         char *g_title[] = {"rxerr/s", "txerr/s",
2526                             "rxdrop/s", "txdrop/s",
2527                             "rxfifo/s", "txfifo/s",
2528                             "coll/s", "txcarr/s", "rxfram/s"};
2529         int g_fields[] = {6, 0, 1, 2, 3, 4, 5, 8, 7};
2530         static double *spmin, *spmax;
2531         static char **out;
2532         static int *outsize;
2533         char *item_name;
2534         int i, j, k, pos, restart, *unregistered;
2535
2536         if (action & F_BEGIN) {
2537                 /*
2538                  * Allocate arrays (#0..8) that will contain the graphs data
2539                  * and the min/max values.
2540                  * Also allocate one additional array (#9) for each interface:
2541                  * out + 9 will contain the interface name,
2542                  * outsize + 9 will contain a positive value (TRUE) if the interface
2543                  * has either still not been registered, or has been unregistered.
2544                  */
2545                 out = allocate_graph_lines(10 * svg_p->nr_max, &outsize, &spmin, &spmax);
2546         }
2547
2548         if (action & F_MAIN) {
2549                 memset(&snedzero, 0, STATS_NET_EDEV_SIZE);
2550                 restart = svg_p->restart;
2551                 /*
2552                  * Mark previously registered interfaces as now
2553                  * possibly unregistered for all graphs.
2554                  */
2555                 for (k = 0; k < svg_p->nr_max; k++) {
2556                         unregistered = outsize + k * 10 + 9;
2557                         if (*unregistered == FALSE) {
2558                                 *unregistered = MAYBE;
2559                         }
2560                 }
2561
2562                 /* For each network interfaces structure */
2563                 for (i = 0; i < a->nr[curr]; i++) {
2564                         snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + i * a->msize);
2565                         if (!strcmp(snedc->interface, ""))
2566                                 /* Empty structure: This is the end of the list */
2567                                 break;
2568
2569                         if (dlst_iface_idx) {
2570                                 /* A list of devices has been entered on the command line */
2571                                 if (!search_sa_dlist(st_iface_list, dlst_iface_idx, snedc->interface))
2572                                         /* Device not found */
2573                                         continue;
2574                         }
2575
2576                         /* Look for corresponding graph */
2577                         for (k = 0; k < svg_p->nr_max; k++) {
2578                                 item_name = *(out + k * 10 + 9);
2579                                 if (!strcmp(snedc->interface, item_name))
2580                                         /* Graph found! */
2581                                         break;
2582                         }
2583                         if (k == svg_p->nr_max) {
2584                                 /* Graph not found: Look for first free entry */
2585                                 for (k = 0; k < svg_p->nr_max; k++) {
2586                                         item_name = *(out + k * 10 + 9);
2587                                         if (!strcmp(item_name, ""))
2588                                                 break;
2589                                 }
2590                                 if (k == svg_p->nr_max) {
2591                                         /* No free graph entry: Extend all buffers */
2592                                         reallocate_all_graph_lines(svg_p->nr_max,
2593                                                                    &out, &outsize, &spmin, &spmax);
2594                                         svg_p->nr_max *= 2;
2595                                 }
2596                         }
2597
2598                         pos = k * 10;
2599                         unregistered = outsize + pos + 9;
2600
2601                         j = check_net_edev_reg(a, curr, !curr, i);
2602                         if (j < 0) {
2603                                 /* This is a newly registered interface. Previous stats are zero */
2604                                 snedp = &snedzero;
2605                         }
2606                         else {
2607                                 snedp = (struct stats_net_edev *) ((char *) a->buf[!curr] + j * a->msize);
2608                         }
2609
2610                         /*
2611                          * If current interface was marked as previously unregistered,
2612                          * then set restart variable to TRUE so that the graph will be
2613                          * discontinuous, and mark it as now registered.
2614                          */
2615                         if (*unregistered == TRUE) {
2616                                 restart = TRUE;
2617                         }
2618                         *unregistered = FALSE;
2619
2620                         if (!item_name[0]) {
2621                                 /* Save network interface name (if not already done) */
2622                                 strncpy(item_name, snedc->interface, CHUNKSIZE);
2623                                 item_name[CHUNKSIZE - 1] = '\0';
2624                         }
2625
2626                         /* Check for min/max values */
2627                         save_extrema(a->gtypes_nr, (void *) snedc, (void *) snedp,
2628                                      itv, spmin + pos, spmax + pos, g_fields);
2629
2630                         /* rxerr/s */
2631                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2632                                  S_VALUE(snedp->rx_errors, snedc->rx_errors, itv),
2633                                  out + pos, outsize + pos, restart);
2634                         /* txerr/s */
2635                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2636                                  S_VALUE(snedp->tx_errors, snedc->tx_errors, itv),
2637                                  out + pos + 1, outsize + pos + 1, restart);
2638                         /* rxdrop/s */
2639                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2640                                  S_VALUE(snedp->rx_dropped, snedc->rx_dropped, itv),
2641                                  out + pos + 2, outsize + pos + 2, restart);
2642                         /* txdrop/s */
2643                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2644                                  S_VALUE(snedp->tx_dropped, snedc->tx_dropped, itv),
2645                                  out + pos + 3, outsize + pos + 3, restart);
2646                         /* rxfifo/s */
2647                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2648                                  S_VALUE(snedp->rx_fifo_errors, snedc->rx_fifo_errors, itv),
2649                                  out + pos + 4, outsize + pos + 4, restart);
2650                         /* txfifo/s */
2651                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2652                                  S_VALUE(snedp->tx_fifo_errors, snedc->tx_fifo_errors, itv),
2653                                  out + pos + 5, outsize + pos + 5, restart);
2654                         /* coll/s */
2655                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2656                                  S_VALUE(snedp->collisions, snedc->collisions, itv),
2657                                  out + pos + 6, outsize + pos + 6, restart);
2658                         /* txcarr/s */
2659                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2660                                  S_VALUE(snedp->tx_carrier_errors, snedc->tx_carrier_errors, itv),
2661                                  out + pos + 7, outsize + pos + 7, restart);
2662                         /* rxfram/s */
2663                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2664                                  S_VALUE(snedp->rx_frame_errors, snedc->rx_frame_errors, itv),
2665                                  out + pos + 8, outsize + pos + 8, restart);
2666                 }
2667
2668                 /* Mark interfaces not seen here as now unregistered */
2669                 for (k = 0; k < svg_p->nr_max; k++) {
2670                         unregistered = outsize + k * 10 + 9;
2671                         if (*unregistered != FALSE) {
2672                                 *unregistered = TRUE;
2673                         }
2674                 }
2675         }
2676
2677         if (action & F_END) {
2678                 int xid = 0;
2679
2680                 for (i = 0; i < svg_p->nr_max; i++) {
2681                         /*
2682                          * Check if there is something to display.
2683                          * Don't test snedc->interface because maybe the network
2684                          * interface has been registered later.
2685                          */
2686                         pos = i * 10;
2687                         if (!**(out + pos))
2688                                 continue;
2689
2690                         item_name = *(out + pos + 9);
2691                         if (draw_activity_graphs(a->g_nr, g_type,
2692                                                  title, g_title, item_name, group,
2693                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2694                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
2695                                 xid++;
2696                         }
2697                 }
2698
2699                 /* Free remaining structures */
2700                 free_graphs(out, outsize, spmin, spmax);
2701         }
2702 }
2703
2704 /*
2705  ***************************************************************************
2706  * Display NFS client statistics in SVG.
2707  *
2708  * IN:
2709  * @a           Activity structure with statistics.
2710  * @curr        Index in array for current sample statistics.
2711  * @action      Action expected from current function.
2712  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2713  *              flag indicating that a restart record has been previously
2714  *              found (.@restart) and time used for the X axis origin
2715  *              (@ust_time_ref).
2716  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2717  * @record_hdr  Pointer on record header of current stats sample.
2718  ***************************************************************************
2719  */
2720 __print_funct_t svg_print_net_nfs_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2721                                         unsigned long long itv, struct record_header *record_hdr)
2722 {
2723         struct stats_net_nfs
2724                 *snnc = (struct stats_net_nfs *) a->buf[curr],
2725                 *snnp = (struct stats_net_nfs *) a->buf[!curr];
2726         int group[] = {2, 2, 2};
2727         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2728         char *title[] = {"NFS client statistics (1)", "NFS client statistics (2)",
2729                          "NFS client statistics (3)"};
2730         char *g_title[] = {"call/s", "retrans/s",
2731                            "read/s", "write/s",
2732                            "access/s", "getatt/s"};
2733         int g_fields[] = {0, 1, 2, 3, 4, 5};
2734         static double *spmin, *spmax;
2735         static char **out;
2736         static int *outsize;
2737
2738         if (action & F_BEGIN) {
2739                 /*
2740                  * Allocate arrays that will contain the graphs data
2741                  * and the min/max values.
2742                  */
2743                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
2744         }
2745
2746         if (action & F_MAIN) {
2747                 /* Check for min/max values */
2748                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
2749                              itv, spmin, spmax, g_fields);
2750
2751                 /* call/s */
2752                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2753                          S_VALUE(snnp->nfs_rpccnt, snnc->nfs_rpccnt, itv),
2754                          out, outsize, svg_p->restart);
2755                 /* retrans/s */
2756                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2757                          S_VALUE(snnp->nfs_rpcretrans, snnc->nfs_rpcretrans, itv),
2758                          out + 1, outsize + 1, svg_p->restart);
2759                 /* read/s */
2760                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2761                          S_VALUE(snnp->nfs_readcnt, snnc->nfs_readcnt, itv),
2762                          out + 2, outsize + 2, svg_p->restart);
2763                 /* write/s */
2764                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2765                          S_VALUE(snnp->nfs_writecnt, snnc->nfs_writecnt, itv),
2766                          out + 3, outsize + 3, svg_p->restart);
2767                 /* access/s */
2768                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2769                          S_VALUE(snnp->nfs_accesscnt, snnc->nfs_accesscnt, itv),
2770                          out + 4, outsize + 4, svg_p->restart);
2771                 /* getatt/s */
2772                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2773                          S_VALUE(snnp->nfs_getattcnt, snnc->nfs_getattcnt, itv),
2774                          out + 5, outsize + 5, svg_p->restart);
2775         }
2776
2777         if (action & F_END) {
2778                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2779                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
2780
2781                 /* Free remaining structures */
2782                 free_graphs(out, outsize, spmin, spmax);
2783         }
2784 }
2785
2786 /*
2787  ***************************************************************************
2788  * Display NFS server statistics in SVG.
2789  *
2790  * IN:
2791  * @a           Activity structure with statistics.
2792  * @curr        Index in array for current sample statistics.
2793  * @action      Action expected from current function.
2794  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2795  *              flag indicating that a restart record has been previously
2796  *              found (.@restart) and time used for the X axis origin
2797  *              (@ust_time_ref).
2798  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2799  * @record_hdr  Pointer on record header of current stats sample.
2800  ***************************************************************************
2801  */
2802 __print_funct_t svg_print_net_nfsd_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2803                                          unsigned long long itv, struct record_header *record_hdr)
2804 {
2805         struct stats_net_nfsd
2806                 *snndc = (struct stats_net_nfsd *) a->buf[curr],
2807                 *snndp = (struct stats_net_nfsd *) a->buf[!curr];
2808         int group[] = {2, 3, 2, 2, 2};
2809         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2810                         SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2811         char *title[] = {"NFS server statistics (1)", "NFS server statistics (2)",
2812                          "NFS server statistics (3)", "NFS server statistics (4)",
2813                          "NFS server statistics (5)"};
2814         char *g_title[] = {"scall/s", "badcall/s",
2815                            "packet/s", "udp/s", "tcp/s",
2816                            "hit/s", "miss/s",
2817                            "sread/s", "swrite/s",
2818                            "saccess/s", "sgetatt/s"};
2819         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
2820         static double *spmin, *spmax;
2821         static char **out;
2822         static int *outsize;
2823
2824         if (action & F_BEGIN) {
2825                 /*
2826                  * Allocate arrays that will contain the graphs data
2827                  * and the min/max values.
2828                  */
2829                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
2830         }
2831
2832         if (action & F_MAIN) {
2833                 /* Check for min/max values */
2834                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
2835                              itv, spmin, spmax, g_fields);
2836
2837                 /* scall/s */
2838                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2839                          S_VALUE(snndp->nfsd_rpccnt, snndc->nfsd_rpccnt, itv),
2840                          out, outsize, svg_p->restart);
2841                 /* badcall/s */
2842                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2843                          S_VALUE(snndp->nfsd_rpcbad, snndc->nfsd_rpcbad, itv),
2844                          out + 1, outsize + 1, svg_p->restart);
2845                 /* packet/s */
2846                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2847                          S_VALUE(snndp->nfsd_netcnt, snndc->nfsd_netcnt, itv),
2848                          out + 2, outsize + 2, svg_p->restart);
2849                 /* udp/s */
2850                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2851                          S_VALUE(snndp->nfsd_netudpcnt, snndc->nfsd_netudpcnt, itv),
2852                          out + 3, outsize + 3, svg_p->restart);
2853                 /* tcp/s */
2854                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2855                          S_VALUE(snndp->nfsd_nettcpcnt, snndc->nfsd_nettcpcnt, itv),
2856                          out + 4, outsize + 4, svg_p->restart);
2857                 /* hit/s */
2858                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2859                          S_VALUE(snndp->nfsd_rchits, snndc->nfsd_rchits, itv),
2860                          out + 5, outsize + 5, svg_p->restart);
2861                 /* miss/s */
2862                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2863                          S_VALUE(snndp->nfsd_rcmisses, snndc->nfsd_rcmisses, itv),
2864                          out + 6, outsize + 6, svg_p->restart);
2865                 /* sread/s */
2866                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2867                          S_VALUE(snndp->nfsd_readcnt, snndc->nfsd_readcnt, itv),
2868                          out + 7, outsize + 7, svg_p->restart);
2869                 /* swrite/s */
2870                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2871                          S_VALUE(snndp->nfsd_writecnt, snndc->nfsd_writecnt, itv),
2872                          out + 8, outsize + 8, svg_p->restart);
2873                 /* saccess/s */
2874                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2875                          S_VALUE(snndp->nfsd_accesscnt, snndc->nfsd_accesscnt, itv),
2876                          out + 9, outsize + 9, svg_p->restart);
2877                 /* sgetatt/s */
2878                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2879                          S_VALUE(snndp->nfsd_getattcnt, snndc->nfsd_getattcnt, itv),
2880                          out + 10, outsize + 10, svg_p->restart);
2881         }
2882
2883         if (action & F_END) {
2884                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2885                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
2886
2887                 /* Free remaining structures */
2888                 free_graphs(out, outsize, spmin, spmax);
2889         }
2890 }
2891
2892 /*
2893  ***************************************************************************
2894  * Display socket statistics in SVG.
2895  *
2896  * IN:
2897  * @a           Activity structure with statistics.
2898  * @curr        Index in array for current sample statistics.
2899  * @action      Action expected from current function.
2900  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2901  *              flag indicating that a restart record has been previously
2902  *              found (.@restart) and time used for the X axis origin
2903  *              (@ust_time_ref).
2904  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2905  * @record_hdr  Pointer on record header of current stats sample.
2906  ***************************************************************************
2907  */
2908 __print_funct_t svg_print_net_sock_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2909                                          unsigned long long itv, struct record_header *record_hdr)
2910 {
2911         struct stats_net_sock
2912                 *snsc = (struct stats_net_sock *) a->buf[curr];
2913         int group[] = {1, 5};
2914         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2915         char *title[] = {"IPv4 sockets statistics (1)", "IPv4 sockets statistics (2)"};
2916         char *g_title[] = {"~totsck",
2917                            "~tcpsck", "~udpsck", "~rawsck", "~ip-frag", "~tcp-tw"};
2918         int g_fields[] = {0, 1, 5, 2, 3, 4};
2919         static double *spmin, *spmax;
2920         static char **out;
2921         static int *outsize;
2922
2923         if (action & F_BEGIN) {
2924                 /*
2925                  * Allocate arrays that will contain the graphs data
2926                  * and the min/max values.
2927                  */
2928                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
2929         }
2930
2931         if (action & F_MAIN) {
2932                 /* Check for min/max values */
2933                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
2934                              itv, spmin, spmax, g_fields);
2935                 /* totsck */
2936                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2937                           (unsigned long long) snsc->sock_inuse,
2938                           out, outsize, svg_p->restart);
2939                 /* tcpsck */
2940                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2941                           (unsigned long long) snsc->tcp_inuse,
2942                           out + 1, outsize + 1, svg_p->restart);
2943                 /* udpsck */
2944                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2945                           (unsigned long long) snsc->udp_inuse,
2946                           out + 2, outsize + 2, svg_p->restart);
2947                 /* rawsck */
2948                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2949                           (unsigned long long) snsc->raw_inuse,
2950                           out + 3, outsize + 3, svg_p->restart);
2951                 /* ip-frag */
2952                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2953                           (unsigned long long) snsc->frag_inuse,
2954                           out + 4, outsize + 4, svg_p->restart);
2955                 /* tcp-tw */
2956                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2957                           (unsigned long long) snsc->tcp_tw,
2958                           out + 5, outsize + 5, svg_p->restart);
2959         }
2960
2961         if (action & F_END) {
2962                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2963                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
2964
2965                 /* Free remaining structures */
2966                 free_graphs(out, outsize, spmin, spmax);
2967         }
2968 }
2969
2970 /*
2971  ***************************************************************************
2972  * Display IPv4 traffic statistics in SVG.
2973  *
2974  * IN:
2975  * @a           Activity structure with statistics.
2976  * @curr        Index in array for current sample statistics.
2977  * @action      Action expected from current function.
2978  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2979  *              flag indicating that a restart record has been previously
2980  *              found (.@restart) and time used for the X axis origin
2981  *              (@ust_time_ref).
2982  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2983  * @record_hdr  Pointer on record header of current stats sample.
2984  ***************************************************************************
2985  */
2986 __print_funct_t svg_print_net_ip_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2987                                        unsigned long long itv, struct record_header *record_hdr)
2988 {
2989         struct stats_net_ip
2990                 *snic = (struct stats_net_ip *) a->buf[curr],
2991                 *snip = (struct stats_net_ip *) a->buf[!curr];
2992         int group[] = {4, 2, 2};
2993         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2994         char *title[] = {"IPv4 traffic statistics (1)", "IPv4 traffic statistics (2)", "IPv4 traffic statistics (3)"};
2995         char *g_title[] = {"irec/s", "fwddgm/s", "idel/s", "orq/s",
2996                            "asmrq/s", "asmok/s",
2997                            "fragok/s", "fragcrt/s"};
2998         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7};
2999         static double *spmin, *spmax;
3000         static char **out;
3001         static int *outsize;
3002
3003         if (action & F_BEGIN) {
3004                 /*
3005                  * Allocate arrays that will contain the graphs data
3006                  * and the min/max values.
3007                  */
3008                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
3009         }
3010
3011         if (action & F_MAIN) {
3012                 /* Check for min/max values */
3013                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3014                              itv, spmin, spmax, g_fields);
3015
3016                 /* irec/s */
3017                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3018                          S_VALUE(snip->InReceives, snic->InReceives, itv),
3019                          out, outsize, svg_p->restart);
3020                 /* fwddgm/s */
3021                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3022                          S_VALUE(snip->ForwDatagrams, snic->ForwDatagrams, itv),
3023                          out + 1, outsize + 1, svg_p->restart);
3024                 /* idel/s */
3025                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3026                          S_VALUE(snip->InDelivers, snic->InDelivers, itv),
3027                          out + 2, outsize + 2, svg_p->restart);
3028                 /* orq/s */
3029                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3030                          S_VALUE(snip->OutRequests, snic->OutRequests, itv),
3031                          out + 3, outsize + 3, svg_p->restart);
3032                 /* asmrq/s */
3033                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3034                          S_VALUE(snip->ReasmReqds, snic->ReasmReqds, itv),
3035                          out + 4, outsize + 4, svg_p->restart);
3036                 /* asmok/s */
3037                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3038                          S_VALUE(snip->ReasmOKs, snic->ReasmOKs, itv),
3039                          out + 5, outsize + 5, svg_p->restart);
3040                 /* fragok/s */
3041                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3042                          S_VALUE(snip->FragOKs, snic->FragOKs, itv),
3043                          out + 6, outsize + 6, svg_p->restart);
3044                 /* fragcrt/s */
3045                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3046                          S_VALUE(snip->FragCreates, snic->FragCreates, itv),
3047                          out + 7, outsize + 7, svg_p->restart);
3048         }
3049
3050         if (action & F_END) {
3051                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3052                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3053
3054                 /* Free remaining structures */
3055                 free_graphs(out, outsize, spmin, spmax);
3056         }
3057 }
3058
3059 /*
3060  ***************************************************************************
3061  * Display IPv4 traffic errors statistics in SVG.
3062  *
3063  * IN:
3064  * @a           Activity structure with statistics.
3065  * @curr        Index in array for current sample statistics.
3066  * @action      Action expected from current function.
3067  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3068  *              flag indicating that a restart record has been previously
3069  *              found (.@restart) and time used for the X axis origin
3070  *              (@ust_time_ref).
3071  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3072  * @record_hdr  Pointer on record header of current stats sample.
3073  ***************************************************************************
3074  */
3075 __print_funct_t svg_print_net_eip_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3076                                         unsigned long long itv, struct record_header *record_hdr)
3077 {
3078         struct stats_net_eip
3079                 *sneic = (struct stats_net_eip *) a->buf[curr],
3080                 *sneip = (struct stats_net_eip *) a->buf[!curr];
3081         int group[] = {3, 2, 3};
3082         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3083         char *title[] = {"IPv4 traffic errors statistics (1)", "IPv4 traffic errors statistics (2)",
3084                          "IPv4 traffic errors statistics (3)"};
3085         char *g_title[] = {"ihdrerr/s", "iadrerr/s", "iukwnpr/s",
3086                            "idisc/s", "odisc/s",
3087                            "onort/s", "asmf/s", "fragf/s"};
3088         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7};
3089         static double *spmin, *spmax;
3090         static char **out;
3091         static int *outsize;
3092
3093         if (action & F_BEGIN) {
3094                 /*
3095                  * Allocate arrays that will contain the graphs data
3096                  * and the min/max values.
3097                  */
3098                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
3099         }
3100
3101         if (action & F_MAIN) {
3102                 /* Check for min/max values */
3103                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3104                              itv, spmin, spmax, g_fields);
3105
3106                 /* ihdrerr/s */
3107                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3108                          S_VALUE(sneip->InHdrErrors, sneic->InHdrErrors, itv),
3109                          out, outsize, svg_p->restart);
3110                 /* iadrerr/s */
3111                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3112                          S_VALUE(sneip->InAddrErrors, sneic->InAddrErrors, itv),
3113                          out + 1, outsize + 1, svg_p->restart);
3114                 /* iukwnpr/s */
3115                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3116                          S_VALUE(sneip->InUnknownProtos, sneic->InUnknownProtos, itv),
3117                          out + 2, outsize + 2, svg_p->restart);
3118                 /* idisc/s */
3119                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3120                          S_VALUE(sneip->InDiscards, sneic->InDiscards, itv),
3121                          out + 3, outsize + 3, svg_p->restart);
3122                 /* odisc/s */
3123                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3124                          S_VALUE(sneip->OutDiscards, sneic->OutDiscards, itv),
3125                          out + 4, outsize + 4, svg_p->restart);
3126                 /* onort/s */
3127                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3128                          S_VALUE(sneip->OutNoRoutes, sneic->OutNoRoutes, itv),
3129                          out + 5, outsize + 5, svg_p->restart);
3130                 /* asmf/s */
3131                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3132                          S_VALUE(sneip->ReasmFails, sneic->ReasmFails, itv),
3133                          out + 6, outsize + 6, svg_p->restart);
3134                 /* fragf/s */
3135                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3136                          S_VALUE(sneip->FragFails, sneic->FragFails, itv),
3137                          out + 7, outsize + 7, svg_p->restart);
3138         }
3139
3140         if (action & F_END) {
3141                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3142                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3143
3144                 /* Free remaining structures */
3145                 free_graphs(out, outsize, spmin, spmax);
3146         }
3147 }
3148
3149 /*
3150  ***************************************************************************
3151  * Display ICMPv4 traffic statistics in SVG.
3152  *
3153  * IN:
3154  * @a           Activity structure with statistics.
3155  * @curr        Index in array for current sample statistics.
3156  * @action      Action expected from current function.
3157  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3158  *              flag indicating that a restart record has been previously
3159  *              found (.@restart) and time used for the X axis origin
3160  *              (@ust_time_ref).
3161  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3162  * @record_hdr  Pointer on record header of current stats sample.
3163  ***************************************************************************
3164  */
3165 __print_funct_t svg_print_net_icmp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3166                                          unsigned long long itv, struct record_header *record_hdr)
3167 {
3168         struct stats_net_icmp
3169                 *snic = (struct stats_net_icmp *) a->buf[curr],
3170                 *snip = (struct stats_net_icmp *) a->buf[!curr];
3171         int group[] = {2, 4, 4, 4};
3172         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3173                         SVG_LINE_GRAPH};
3174         char *title[] = {"ICMPv4 traffic statistics (1)", "ICMPv4 traffic statistics (2)",
3175                          "ICMPv4 traffic statistics (3)", "ICMPv4 traffic statistics (4)"};
3176         char *g_title[] = {"imsg/s", "omsg/s",
3177                            "iech/s", "iechr/s", "oech/s", "oechr/s",
3178                            "itm/s", "itmr/s", "otm/s", "otmr/s",
3179                            "iadrmk/s", "iadrmkr/s", "oadrmk/s", "oadrmkr/s"};
3180         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
3181         static double *spmin, *spmax;
3182         static char **out;
3183         static int *outsize;
3184
3185         if (action & F_BEGIN) {
3186                 /*
3187                  * Allocate arrays that will contain the graphs data
3188                  * and the min/max values.
3189                  */
3190                 out = allocate_graph_lines(14, &outsize, &spmin, &spmax);
3191         }
3192
3193         if (action & F_MAIN) {
3194                 /* Check for min/max values */
3195                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3196                              itv, spmin, spmax, g_fields);
3197
3198                 /* imsg/s */
3199                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3200                          S_VALUE(snip->InMsgs, snic->InMsgs, itv),
3201                          out, outsize, svg_p->restart);
3202                 /* omsg/s */
3203                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3204                          S_VALUE(snip->OutMsgs, snic->OutMsgs, itv),
3205                          out + 1, outsize + 1, svg_p->restart);
3206                 /* iech/s */
3207                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3208                          S_VALUE(snip->InEchos, snic->InEchos, itv),
3209                          out + 2, outsize + 2, svg_p->restart);
3210                 /* iechr/s */
3211                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3212                          S_VALUE(snip->InEchoReps, snic->InEchoReps, itv),
3213                          out + 3, outsize + 3, svg_p->restart);
3214                 /* oech/s */
3215                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3216                          S_VALUE(snip->OutEchos, snic->OutEchos, itv),
3217                          out + 4, outsize + 4, svg_p->restart);
3218                 /* oechr/s */
3219                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3220                          S_VALUE(snip->OutEchoReps, snic->OutEchoReps, itv),
3221                          out + 5, outsize + 5, svg_p->restart);
3222                 /* itm/s */
3223                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3224                          S_VALUE(snip->InTimestamps, snic->InTimestamps, itv),
3225                          out + 6, outsize + 6, svg_p->restart);
3226                 /* itmr/s */
3227                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3228                          S_VALUE(snip->InTimestampReps, snic->InTimestampReps, itv),
3229                          out + 7, outsize + 7, svg_p->restart);
3230                 /* otm/s */
3231                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3232                          S_VALUE(snip->OutTimestamps, snic->OutTimestamps, itv),
3233                          out + 8, outsize + 8, svg_p->restart);
3234                 /* otmr/s */
3235                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3236                          S_VALUE(snip->OutTimestampReps, snic->OutTimestampReps, itv),
3237                          out + 9, outsize + 9, svg_p->restart);
3238                 /* iadrmk/s */
3239                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3240                          S_VALUE(snip->InAddrMasks, snic->InAddrMasks, itv),
3241                          out + 10, outsize + 10, svg_p->restart);
3242                 /* iadrmkr/s */
3243                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3244                          S_VALUE(snip->InAddrMaskReps, snic->InAddrMaskReps, itv),
3245                          out + 11, outsize + 11, svg_p->restart);
3246                 /* oadrmk/s */
3247                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3248                          S_VALUE(snip->OutAddrMasks, snic->OutAddrMasks, itv),
3249                          out + 12, outsize + 12, svg_p->restart);
3250                 /* oadrmkr/s */
3251                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3252                          S_VALUE(snip->OutAddrMaskReps, snic->OutAddrMaskReps, itv),
3253                          out + 13, outsize + 13, svg_p->restart);
3254         }
3255
3256         if (action & F_END) {
3257                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3258                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3259
3260                 /* Free remaining structures */
3261                 free_graphs(out, outsize, spmin, spmax);
3262         }
3263 }
3264
3265 /*
3266  ***************************************************************************
3267  * Display ICMPv4 traffic errors statistics in SVG.
3268  *
3269  * IN:
3270  * @a           Activity structure with statistics.
3271  * @curr        Index in array for current sample statistics.
3272  * @action      Action expected from current function.
3273  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3274  *              flag indicating that a restart record has been previously
3275  *              found (.@restart) and time used for the X axis origin
3276  *              (@ust_time_ref).
3277  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3278  * @record_hdr  Pointer on record header of current stats sample.
3279  ***************************************************************************
3280  */
3281 __print_funct_t svg_print_net_eicmp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3282                                           unsigned long long itv, struct record_header *record_hdr)
3283 {
3284         struct stats_net_eicmp
3285                 *sneic = (struct stats_net_eicmp *) a->buf[curr],
3286                 *sneip = (struct stats_net_eicmp *) a->buf[!curr];
3287         int group[] = {2, 2, 2, 2, 2, 2};
3288         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3289                         SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3290         char *title[] = {"ICMPv4 traffic errors statistics (1)", "ICMPv4 traffic errors statistics (2)",
3291                          "ICMPv4 traffic errors statistics (3)", "ICMPv4 traffic errors statistics (4)",
3292                          "ICMPv4 traffic errors statistics (5)", "ICMPv4 traffic errors statistics (6)"};
3293         char *g_title[] = {"ierr/s", "oerr/s",
3294                            "idstunr/s", "odstunr/s",
3295                            "itmex/s", "otmex/s",
3296                            "iparmpb/s", "oparmpb/s",
3297                            "isrcq/s", "osrcq/s",
3298                            "iredir/s", "oredir/s"};
3299         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
3300         static double *spmin, *spmax;
3301         static char **out;
3302         static int *outsize;
3303
3304         if (action & F_BEGIN) {
3305                 /*
3306                  * Allocate arrays that will contain the graphs data
3307                  * and the min/max values.
3308                  */
3309                 out = allocate_graph_lines(12, &outsize, &spmin, &spmax);
3310         }
3311
3312         if (action & F_MAIN) {
3313                 /* Check for min/max values */
3314                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3315                              itv, spmin, spmax, g_fields);
3316
3317                 /* ierr/s */
3318                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3319                          S_VALUE(sneip->InErrors, sneic->InErrors, itv),
3320                          out, outsize, svg_p->restart);
3321                 /* oerr/s */
3322                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3323                          S_VALUE(sneip->OutErrors, sneic->OutErrors, itv),
3324                          out + 1, outsize + 1, svg_p->restart);
3325                 /* idstunr/s */
3326                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3327                          S_VALUE(sneip->InDestUnreachs, sneic->InDestUnreachs, itv),
3328                          out + 2, outsize + 2, svg_p->restart);
3329                 /* odstunr/s */
3330                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3331                          S_VALUE(sneip->OutDestUnreachs, sneic->OutDestUnreachs, itv),
3332                          out + 3, outsize + 3, svg_p->restart);
3333                 /* itmex/s */
3334                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3335                          S_VALUE(sneip->InTimeExcds, sneic->InTimeExcds, itv),
3336                          out + 4, outsize + 4, svg_p->restart);
3337                 /* otmex/s */
3338                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3339                          S_VALUE(sneip->OutTimeExcds, sneic->OutTimeExcds, itv),
3340                          out + 5, outsize + 5, svg_p->restart);
3341                 /* iparmpb/s */
3342                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3343                          S_VALUE(sneip->InParmProbs, sneic->InParmProbs, itv),
3344                          out + 6, outsize + 6, svg_p->restart);
3345                 /* oparmpb/s */
3346                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3347                          S_VALUE(sneip->OutParmProbs, sneic->OutParmProbs, itv),
3348                          out + 7, outsize + 7, svg_p->restart);
3349                 /* isrcq/s */
3350                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3351                          S_VALUE(sneip->InSrcQuenchs, sneic->InSrcQuenchs, itv),
3352                          out + 8, outsize + 8, svg_p->restart);
3353                 /* osrcq/s */
3354                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3355                          S_VALUE(sneip->OutSrcQuenchs, sneic->OutSrcQuenchs, itv),
3356                          out + 9, outsize + 9, svg_p->restart);
3357                 /* iredir/s */
3358                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3359                          S_VALUE(sneip->InRedirects, sneic->InRedirects, itv),
3360                          out + 10, outsize + 10, svg_p->restart);
3361                 /* oredir/s */
3362                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3363                          S_VALUE(sneip->OutRedirects, sneic->OutRedirects, itv),
3364                          out + 11, outsize + 11, svg_p->restart);
3365         }
3366
3367         if (action & F_END) {
3368                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3369                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3370
3371                 /* Free remaining structures */
3372                 free_graphs(out, outsize, spmin, spmax);
3373         }
3374 }
3375
3376 /*
3377  ***************************************************************************
3378  * Display TCPv4 traffic statistics in SVG.
3379  *
3380  * IN:
3381  * @a           Activity structure with statistics.
3382  * @curr        Index in array for current sample statistics.
3383  * @action      Action expected from current function.
3384  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3385  *              flag indicating that a restart record has been previously
3386  *              found (.@restart) and time used for the X axis origin
3387  *              (@ust_time_ref).
3388  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3389  * @record_hdr  Pointer on record header of current stats sample.
3390  ***************************************************************************
3391  */
3392 __print_funct_t svg_print_net_tcp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3393                                         unsigned long long itv, struct record_header *record_hdr)
3394 {
3395         struct stats_net_tcp
3396                 *sntc = (struct stats_net_tcp *) a->buf[curr],
3397                 *sntp = (struct stats_net_tcp *) a->buf[!curr];
3398         int group[] = {2, 2};
3399         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3400         char *title[] = {"TCPv4 traffic statistics (1)", "TCPv4 traffic statistics (2)"};
3401         char *g_title[] = {"active/s", "passive/s",
3402                            "iseg/s", "oseg/s"};
3403         int g_fields[] = {0, 1, 2, 3};
3404         static double *spmin, *spmax;
3405         static char **out;
3406         static int *outsize;
3407
3408         if (action & F_BEGIN) {
3409                 /*
3410                  * Allocate arrays that will contain the graphs data
3411                  * and the min/max values.
3412                  */
3413                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3414         }
3415
3416         if (action & F_MAIN) {
3417                 /* Check for min/max values */
3418                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3419                              itv, spmin, spmax, g_fields);
3420
3421                 /* active/s */
3422                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3423                          S_VALUE(sntp->ActiveOpens, sntc->ActiveOpens, itv),
3424                          out, outsize, svg_p->restart);
3425                 /* passive/s */
3426                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3427                          S_VALUE(sntp->PassiveOpens, sntc->PassiveOpens, itv),
3428                          out + 1, outsize + 1, svg_p->restart);
3429                 /* iseg/s */
3430                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3431                          S_VALUE(sntp->InSegs, sntc->InSegs, itv),
3432                          out + 2, outsize + 2, svg_p->restart);
3433                 /* oseg/s */
3434                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3435                          S_VALUE(sntp->OutSegs, sntc->OutSegs, itv),
3436                          out + 3, outsize + 3, svg_p->restart);
3437         }
3438
3439         if (action & F_END) {
3440                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3441                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3442
3443                 /* Free remaining structures */
3444                 free_graphs(out, outsize, spmin, spmax);
3445         }
3446 }
3447
3448 /*
3449  ***************************************************************************
3450  * Display TCPv4 traffic errors statistics in SVG.
3451  *
3452  * IN:
3453  * @a           Activity structure with statistics.
3454  * @curr        Index in array for current sample statistics.
3455  * @action      Action expected from current function.
3456  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3457  *              flag indicating that a restart record has been previously
3458  *              found (.@restart) and time used for the X axis origin
3459  *              (@ust_time_ref).
3460  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3461  * @record_hdr  Pointer on record header of current stats sample.
3462  ***************************************************************************
3463  */
3464 __print_funct_t svg_print_net_etcp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3465                                          unsigned long long itv, struct record_header *record_hdr)
3466 {
3467         struct stats_net_etcp
3468                 *snetc = (struct stats_net_etcp *) a->buf[curr],
3469                 *snetp = (struct stats_net_etcp *) a->buf[!curr];
3470         int group[] = {2, 3};
3471         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3472         char *title[] = {"TCPv4 traffic errors statistics (1)", "TCPv4 traffic errors statistics (2)"};
3473         char *g_title[] = {"atmptf/s", "estres/s",
3474                            "retrans/s", "isegerr/s", "orsts/s"};
3475         int g_fields[] = {0, 1, 2, 3, 4};
3476         static double *spmin, *spmax;
3477         static char **out;
3478         static int *outsize;
3479
3480         if (action & F_BEGIN) {
3481                 /*
3482                  * Allocate arrays that will contain the graphs data
3483                  * and the min/max values.
3484                  */
3485                 out = allocate_graph_lines(5, &outsize, &spmin, &spmax);
3486         }
3487
3488         if (action & F_MAIN) {
3489                 /* Check for min/max values */
3490                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3491                              itv, spmin, spmax, g_fields);
3492
3493                 /* atmptf/s */
3494                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3495                          S_VALUE(snetp->AttemptFails, snetc->AttemptFails, itv),
3496                          out, outsize, svg_p->restart);
3497                 /* estres/s */
3498                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3499                          S_VALUE(snetp->EstabResets, snetc->EstabResets, itv),
3500                          out + 1, outsize + 1, svg_p->restart);
3501                 /* retrans/s */
3502                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3503                          S_VALUE(snetp->RetransSegs, snetc->RetransSegs, itv),
3504                          out + 2, outsize + 2, svg_p->restart);
3505                 /* isegerr/s */
3506                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3507                          S_VALUE(snetp->InErrs, snetc->InErrs, itv),
3508                          out + 3, outsize + 3, svg_p->restart);
3509                 /* orsts/s */
3510                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3511                          S_VALUE(snetp->OutRsts, snetc->OutRsts, itv),
3512                          out + 4, outsize + 4, svg_p->restart);
3513         }
3514
3515         if (action & F_END) {
3516                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3517                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3518
3519                 /* Free remaining structures */
3520                 free_graphs(out, outsize, spmin, spmax);
3521         }
3522 }
3523
3524 /*
3525  ***************************************************************************
3526  * Display UDPv4 traffic statistics in SVG.
3527  *
3528  * IN:
3529  * @a           Activity structure with statistics.
3530  * @curr        Index in array for current sample statistics.
3531  * @action      Action expected from current function.
3532  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3533  *              flag indicating that a restart record has been previously
3534  *              found (.@restart) and time used for the X axis origin
3535  *              (@ust_time_ref).
3536  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3537  * @record_hdr  Pointer on record header of current stats sample.
3538  ***************************************************************************
3539  */
3540 __print_funct_t svg_print_net_udp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3541                                         unsigned long long itv, struct record_header *record_hdr)
3542 {
3543         struct stats_net_udp
3544                 *snuc = (struct stats_net_udp *) a->buf[curr],
3545                 *snup = (struct stats_net_udp *) a->buf[!curr];
3546         int group[] = {2, 2};
3547         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3548         char *title[] = {"UDPv4 traffic statistics (1)", "UDPv4 traffic statistics (2)"};
3549         char *g_title[] = {"idgm/s", "odgm/s",
3550                            "noport/s", "idgmerr/s"};
3551         int g_fields[] = {0, 1, 2, 3};
3552         static double *spmin, *spmax;
3553         static char **out;
3554         static int *outsize;
3555
3556         if (action & F_BEGIN) {
3557                 /*
3558                  * Allocate arrays that will contain the graphs data
3559                  * and the min/max values.
3560                  */
3561                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3562         }
3563
3564         if (action & F_MAIN) {
3565                 /* Check for min/max values */
3566                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3567                              itv, spmin, spmax, g_fields);
3568
3569                 /* idgm/s */
3570                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3571                          S_VALUE(snup->InDatagrams, snuc->InDatagrams, itv),
3572                          out, outsize, svg_p->restart);
3573                 /* odgm/s */
3574                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3575                          S_VALUE(snup->OutDatagrams, snuc->OutDatagrams, itv),
3576                          out + 1, outsize + 1, svg_p->restart);
3577                 /* noport/s */
3578                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3579                          S_VALUE(snup->NoPorts, snuc->NoPorts, itv),
3580                          out + 2, outsize + 2, svg_p->restart);
3581                 /* idgmerr/s */
3582                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3583                          S_VALUE(snup->InErrors, snuc->InErrors, itv),
3584                          out + 3, outsize + 3, svg_p->restart);
3585         }
3586
3587         if (action & F_END) {
3588                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3589                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3590
3591                 /* Free remaining structures */
3592                 free_graphs(out, outsize, spmin, spmax);
3593         }
3594 }
3595
3596 /*
3597  ***************************************************************************
3598  * Display IPV6 socket statistics in SVG.
3599  *
3600  * IN:
3601  * @a           Activity structure with statistics.
3602  * @curr        Index in array for current sample statistics.
3603  * @action      Action expected from current function.
3604  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3605  *              flag indicating that a restart record has been previously
3606  *              found (.@restart) and time used for the X axis origin
3607  *              (@ust_time_ref).
3608  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3609  * @record_hdr  Pointer on record header of current stats sample.
3610  ***************************************************************************
3611  */
3612 __print_funct_t svg_print_net_sock6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3613                                           unsigned long long itv, struct record_header *record_hdr)
3614 {
3615         struct stats_net_sock6
3616                 *snsc = (struct stats_net_sock6 *) a->buf[curr];
3617         int group[] = {4};
3618         int g_type[] = {SVG_LINE_GRAPH};
3619         char *title[] = {"IPv6 sockets statistics"};
3620         char *g_title[] = {"~tcp6sck", "~udp6sck", "~raw6sck", "~ip6-frag"};
3621         int g_fields[] = {0, 1, 2, 3};
3622         static double *spmin, *spmax;
3623         static char **out;
3624         static int *outsize;
3625
3626         if (action & F_BEGIN) {
3627                 /*
3628                  * Allocate arrays that will contain the graphs data
3629                  * and the min/max values.
3630                  */
3631                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3632         }
3633
3634         if (action & F_MAIN) {
3635                 /* Check for min/max values */
3636                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
3637                              itv, spmin, spmax, g_fields);
3638                 /* tcp6sck */
3639                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3640                           (unsigned long long) snsc->tcp6_inuse,
3641                           out, outsize, svg_p->restart);
3642                 /* udp6sck */
3643                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3644                           (unsigned long long) snsc->udp6_inuse,
3645                           out + 1, outsize + 1, svg_p->restart);
3646                 /* raw6sck */
3647                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3648                           (unsigned long long) snsc->raw6_inuse,
3649                           out + 2, outsize + 2, svg_p->restart);
3650                 /* ip6-frag */
3651                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3652                           (unsigned long long) snsc->frag6_inuse,
3653                           out + 3, outsize + 3, svg_p->restart);
3654         }
3655
3656         if (action & F_END) {
3657                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3658                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3659
3660                 /* Free remaining structures */
3661                 free_graphs(out, outsize, spmin, spmax);
3662         }
3663 }
3664
3665 /*
3666  ***************************************************************************
3667  * Display IPv6 traffic statistics in SVG.
3668  *
3669  * IN:
3670  * @a           Activity structure with statistics.
3671  * @curr        Index in array for current sample statistics.
3672  * @action      Action expected from current function.
3673  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3674  *              flag indicating that a restart record has been previously
3675  *              found (.@restart) and time used for the X axis origin
3676  *              (@ust_time_ref).
3677  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3678  * @record_hdr  Pointer on record header of current stats sample.
3679  ***************************************************************************
3680  */
3681 __print_funct_t svg_print_net_ip6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3682                                         unsigned long long itv, struct record_header *record_hdr)
3683 {
3684         struct stats_net_ip6
3685                 *snic = (struct stats_net_ip6 *) a->buf[curr],
3686                 *snip = (struct stats_net_ip6 *) a->buf[!curr];
3687         int group[] = {4, 2, 2, 2};
3688         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3689                         SVG_LINE_GRAPH};
3690         char *title[] = {"IPv6 traffic statistics (1)", "IPv6 traffic statistics (2)",
3691                          "IPv6 traffic statistics (3)", "IPv6 traffic statistics (4)"};
3692         char *g_title[] = {"irec6/s", "fwddgm6/s", "idel6/s", "orq6/s",
3693                            "asmrq6/s", "asmok6/s",
3694                            "imcpck6/s", "omcpck6/s",
3695                            "fragok6/s", "fragcr6/s"};
3696         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
3697         static double *spmin, *spmax;
3698         static char **out;
3699         static int *outsize;
3700
3701         if (action & F_BEGIN) {
3702                 /*
3703                  * Allocate arrays that will contain the graphs data
3704                  * and the min/max values.
3705                  */
3706                 out = allocate_graph_lines(10, &outsize, &spmin, &spmax);
3707         }
3708
3709         if (action & F_MAIN) {
3710                 /* Check for min/max values */
3711                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3712                              itv, spmin, spmax, g_fields);
3713
3714                 /* irec6/s */
3715                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3716                          S_VALUE(snip->InReceives6, snic->InReceives6, itv),
3717                          out, outsize, svg_p->restart);
3718                 /* fwddgm6/s */
3719                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3720                          S_VALUE(snip->OutForwDatagrams6, snic->OutForwDatagrams6, itv),
3721                          out + 1, outsize + 1, svg_p->restart);
3722                 /* idel6/s */
3723                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3724                          S_VALUE(snip->InDelivers6, snic->InDelivers6, itv),
3725                          out + 2, outsize + 2, svg_p->restart);
3726                 /* orq6/s */
3727                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3728                          S_VALUE(snip->OutRequests6, snic->OutRequests6, itv),
3729                          out + 3, outsize + 3, svg_p->restart);
3730                 /* asmrq6/s */
3731                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3732                          S_VALUE(snip->ReasmReqds6, snic->ReasmReqds6, itv),
3733                          out + 4, outsize + 4, svg_p->restart);
3734                 /* asmok6/s */
3735                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3736                          S_VALUE(snip->ReasmOKs6, snic->ReasmOKs6, itv),
3737                          out + 5, outsize + 5, svg_p->restart);
3738                 /* imcpck6/s */
3739                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3740                          S_VALUE(snip->InMcastPkts6, snic->InMcastPkts6, itv),
3741                          out + 6, outsize + 6, svg_p->restart);
3742                 /* omcpck6/s */
3743                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3744                          S_VALUE(snip->OutMcastPkts6, snic->OutMcastPkts6, itv),
3745                          out + 7, outsize + 7, svg_p->restart);
3746                 /* fragok6/s */
3747                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3748                          S_VALUE(snip->FragOKs6, snic->FragOKs6, itv),
3749                          out + 8, outsize + 8, svg_p->restart);
3750                 /* fragcr6/s */
3751                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3752                          S_VALUE(snip->FragCreates6, snic->FragCreates6, itv),
3753                          out + 9, outsize + 9, svg_p->restart);
3754         }
3755
3756         if (action & F_END) {
3757                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3758                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3759
3760                 /* Free remaining structures */
3761                 free_graphs(out, outsize, spmin, spmax);
3762         }
3763 }
3764
3765 /*
3766  ***************************************************************************
3767  * Display IPv6 traffic errors statistics in SVG.
3768  *
3769  * IN:
3770  * @a           Activity structure with statistics.
3771  * @curr        Index in array for current sample statistics.
3772  * @action      Action expected from current function.
3773  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3774  *              flag indicating that a restart record has been previously
3775  *              found (.@restart) and time used for the X axis origin
3776  *              (@ust_time_ref).
3777  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3778  * @record_hdr  Pointer on record header of current stats sample.
3779  ***************************************************************************
3780  */
3781 __print_funct_t svg_print_net_eip6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3782                                          unsigned long long itv, struct record_header *record_hdr)
3783 {
3784         struct stats_net_eip6
3785                 *sneic = (struct stats_net_eip6 *) a->buf[curr],
3786                 *sneip = (struct stats_net_eip6 *) a->buf[!curr];
3787         int group[] = {4, 2, 2, 3};
3788         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3789                         SVG_LINE_GRAPH};
3790         char *title[] = {"IPv6 traffic errors statistics (1)", "IPv6 traffic errors statistics (2)",
3791                          "IPv6 traffic errors statistics (3)", "IPv6 traffic errors statistics (4)",
3792                          "IPv6 traffic errors statistics (5)"};
3793         char *g_title[] = {"ihdrer6/s", "iadrer6/s", "iukwnp6/s", "i2big6/s",
3794                            "idisc6/s", "odisc6/s",
3795                            "inort6/s", "onort6/s",
3796                            "asmf6/s", "fragf6/s", "itrpck6/s"};
3797         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
3798         static double *spmin, *spmax;
3799         static char **out;
3800         static int *outsize;
3801
3802         if (action & F_BEGIN) {
3803                 /*
3804                  * Allocate arrays that will contain the graphs data
3805                  * and the min/max values.
3806                  */
3807                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
3808         }
3809
3810         if (action & F_MAIN) {
3811                 /* Check for min/max values */
3812                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3813                              itv, spmin, spmax, g_fields);
3814
3815                 /* ihdrer6/s */
3816                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3817                          S_VALUE(sneip->InHdrErrors6, sneic->InHdrErrors6, itv),
3818                          out, outsize, svg_p->restart);
3819                 /* iadrer6/s */
3820                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3821                          S_VALUE(sneip->InAddrErrors6, sneic->InAddrErrors6, itv),
3822                          out + 1, outsize + 1, svg_p->restart);
3823                 /* iukwnp6/s */
3824                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3825                          S_VALUE(sneip->InUnknownProtos6, sneic->InUnknownProtos6, itv),
3826                          out + 2, outsize + 2, svg_p->restart);
3827                 /* i2big6/s */
3828                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3829                          S_VALUE(sneip->InTooBigErrors6, sneic->InTooBigErrors6, itv),
3830                          out + 3, outsize + 3, svg_p->restart);
3831                 /* idisc6/s */
3832                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3833                          S_VALUE(sneip->InDiscards6, sneic->InDiscards6, itv),
3834                          out + 4, outsize + 4, svg_p->restart);
3835                 /* odisc6/s */
3836                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3837                          S_VALUE(sneip->OutDiscards6, sneic->OutDiscards6, itv),
3838                          out + 5, outsize + 5, svg_p->restart);
3839                 /* inort6/s */
3840                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3841                          S_VALUE(sneip->InNoRoutes6, sneic->InNoRoutes6, itv),
3842                          out + 6, outsize + 6, svg_p->restart);
3843                 /* onort6/s */
3844                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3845                          S_VALUE(sneip->OutNoRoutes6, sneic->OutNoRoutes6, itv),
3846                          out + 7, outsize + 7, svg_p->restart);
3847                 /* asmf6/s */
3848                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3849                          S_VALUE(sneip->ReasmFails6, sneic->ReasmFails6, itv),
3850                          out + 8, outsize + 8, svg_p->restart);
3851                 /* fragf6/s */
3852                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3853                          S_VALUE(sneip->FragFails6, sneic->FragFails6, itv),
3854                          out + 9, outsize + 9, svg_p->restart);
3855                 /* itrpck6/s */
3856                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3857                          S_VALUE(sneip->InTruncatedPkts6, sneic->InTruncatedPkts6, itv),
3858                          out + 10, outsize + 10, svg_p->restart);
3859         }
3860
3861         if (action & F_END) {
3862                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3863                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3864
3865                 /* Free remaining structures */
3866                 free_graphs(out, outsize, spmin, spmax);
3867         }
3868 }
3869
3870 /*
3871  ***************************************************************************
3872  * Display ICMPv6 traffic statistics in SVG.
3873  *
3874  * IN:
3875  * @a           Activity structure with statistics.
3876  * @curr        Index in array for current sample statistics.
3877  * @action      Action expected from current function.
3878  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3879  *              flag indicating that a restart record has been previously
3880  *              found (.@restart) and time used for the X axis origin
3881  *              (@ust_time_ref).
3882  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3883  * @record_hdr  Pointer on record header of current stats sample.
3884  ***************************************************************************
3885  */
3886 __print_funct_t svg_print_net_icmp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3887                                           unsigned long long itv, struct record_header *record_hdr)
3888 {
3889         struct stats_net_icmp6
3890                 *snic = (struct stats_net_icmp6 *) a->buf[curr],
3891                 *snip = (struct stats_net_icmp6 *) a->buf[!curr];
3892         int group[] = {2, 3, 5, 3, 4};
3893         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3894                         SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3895         char *title[] = {"ICMPv6 traffic statistics (1)", "ICMPv6 traffic statistics (2)",
3896                          "ICMPv6 traffic statistics (3)", "ICMPv6 traffic statistics (4)",
3897                          "ICMPv6 traffic statistics (5)"};
3898         char *g_title[] = {"imsg6/s", "omsg6/s",
3899                            "iech6/s", "iechr6/s", "oechr6/s",
3900                            "igmbq6/s", "igmbr6/s", "ogmbr6/s", "igmbrd6/s", "ogmbrd6/s",
3901                            "irtsol6/s", "ortsol6/s", "irtad6/s",
3902                            "inbsol6/s", "onbsol6/s", "inbad6/s", "onbad6/s"};
3903         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
3904         static double *spmin, *spmax;
3905         static char **out;
3906         static int *outsize;
3907
3908         if (action & F_BEGIN) {
3909                 /*
3910                  * Allocate arrays that will contain the graphs data
3911                  * and the min/max values.
3912                  */
3913                 out = allocate_graph_lines(17, &outsize, &spmin, &spmax);
3914         }
3915
3916         if (action & F_MAIN) {
3917                 /* Check for min/max values */
3918                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3919                              itv, spmin, spmax, g_fields);
3920
3921                 /* imsg6/s */
3922                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3923                          S_VALUE(snip->InMsgs6, snic->InMsgs6, itv),
3924                          out, outsize, svg_p->restart);
3925                 /* omsg6/s */
3926                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3927                          S_VALUE(snip->OutMsgs6, snic->OutMsgs6, itv),
3928                          out + 1, outsize + 1, svg_p->restart);
3929                 /* iech6/s */
3930                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3931                          S_VALUE(snip->InEchos6, snic->InEchos6, itv),
3932                          out + 2, outsize + 2, svg_p->restart);
3933                 /* iechr6/s */
3934                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3935                          S_VALUE(snip->InEchoReplies6, snic->InEchoReplies6, itv),
3936                          out + 3, outsize + 3, svg_p->restart);
3937                 /* oechr6/s */
3938                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3939                          S_VALUE(snip->OutEchoReplies6, snic->OutEchoReplies6, itv),
3940                          out + 4, outsize + 4, svg_p->restart);
3941                 /* igmbq6/s */
3942                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3943                          S_VALUE(snip->InGroupMembQueries6, snic->InGroupMembQueries6, itv),
3944                          out + 5, outsize + 5, svg_p->restart);
3945                 /* igmbr6/s */
3946                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3947                          S_VALUE(snip->InGroupMembResponses6, snic->InGroupMembResponses6, itv),
3948                          out + 6, outsize + 6, svg_p->restart);
3949                 /* ogmbr6/s */
3950                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3951                          S_VALUE(snip->OutGroupMembResponses6, snic->OutGroupMembResponses6, itv),
3952                          out + 7, outsize + 7, svg_p->restart);
3953                 /* igmbrd6/s */
3954                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3955                          S_VALUE(snip->InGroupMembReductions6, snic->InGroupMembReductions6, itv),
3956                          out + 8, outsize + 8, svg_p->restart);
3957                 /* ogmbrd6/s */
3958                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3959                          S_VALUE(snip->OutGroupMembReductions6, snic->OutGroupMembReductions6, itv),
3960                          out + 9, outsize + 9, svg_p->restart);
3961                 /* irtsol6/s */
3962                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3963                          S_VALUE(snip->InRouterSolicits6, snic->InRouterSolicits6, itv),
3964                          out + 10, outsize + 10, svg_p->restart);
3965                 /* ortsol6/s */
3966                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3967                          S_VALUE(snip->OutRouterSolicits6, snic->OutRouterSolicits6, itv),
3968                          out + 11, outsize + 11, svg_p->restart);
3969                 /* irtad6/s */
3970                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3971                          S_VALUE(snip->InRouterAdvertisements6, snic->InRouterAdvertisements6, itv),
3972                          out + 12, outsize + 12, svg_p->restart);
3973                 /* inbsol6/s */
3974                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3975                          S_VALUE(snip->InNeighborSolicits6, snic->InNeighborSolicits6, itv),
3976                          out + 13, outsize + 13, svg_p->restart);
3977                 /* onbsol6/s */
3978                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3979                          S_VALUE(snip->OutNeighborSolicits6, snic->OutNeighborSolicits6, itv),
3980                          out + 14, outsize + 14, svg_p->restart);
3981                 /* inbad6/s */
3982                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3983                          S_VALUE(snip->InNeighborAdvertisements6, snic->InNeighborAdvertisements6, itv),
3984                          out + 15, outsize + 15, svg_p->restart);
3985                 /* onbad6/s */
3986                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3987                          S_VALUE(snip->OutNeighborAdvertisements6, snic->OutNeighborAdvertisements6, itv),
3988                          out + 16, outsize + 16, svg_p->restart);
3989         }
3990
3991         if (action & F_END) {
3992                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3993                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3994
3995                 /* Free remaining structures */
3996                 free_graphs(out, outsize, spmin, spmax);
3997         }
3998 }
3999
4000 /*
4001  ***************************************************************************
4002  * Display ICMPv6 traffic errors statistics in SVG.
4003  *
4004  * IN:
4005  * @a           Activity structure with statistics.
4006  * @curr        Index in array for current sample statistics.
4007  * @action      Action expected from current function.
4008  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4009  *              flag indicating that a restart record has been previously
4010  *              found (.@restart) and time used for the X axis origin
4011  *              (@ust_time_ref).
4012  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4013  * @record_hdr  Pointer on record header of current stats sample.
4014  ***************************************************************************
4015  */
4016 __print_funct_t svg_print_net_eicmp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4017                                            unsigned long long itv, struct record_header *record_hdr)
4018 {
4019         struct stats_net_eicmp6
4020                 *sneic = (struct stats_net_eicmp6 *) a->buf[curr],
4021                 *sneip = (struct stats_net_eicmp6 *) a->buf[!curr];
4022         int group[] = {1, 2, 2, 2, 2, 2};
4023         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
4024                         SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4025         char *title[] = {"ICMPv6 traffic errors statistics (1)", "ICMPv6 traffic errors statistics (2)",
4026                          "ICMPv6 traffic errors statistics (3)", "ICMPv6 traffic errors statistics (4)",
4027                          "ICMPv6 traffic errors statistics (5)", "ICMPv6 traffic errors statistics (6)"};
4028         char *g_title[] = {"ierr6/s",
4029                            "idtunr6/s", "odtunr6/s",
4030                            "itmex6/s", "otmex6/s",
4031                            "iprmpb6/s", "oprmpb6/s",
4032                            "iredir6/s", "oredir6/s",
4033                            "ipck2b6/s", "opck2b6/s"};
4034         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
4035         static double *spmin, *spmax;
4036         static char **out;
4037         static int *outsize;
4038
4039         if (action & F_BEGIN) {
4040                 /*
4041                  * Allocate arrays that will contain the graphs data
4042                  * and the min/max values.
4043                  */
4044                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
4045         }
4046
4047         if (action & F_MAIN) {
4048                 /* Check for min/max values */
4049                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
4050                              itv, spmin, spmax, g_fields);
4051
4052                 /* ierr6/s */
4053                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4054                          S_VALUE(sneip->InErrors6, sneic->InErrors6, itv),
4055                          out, outsize, svg_p->restart);
4056                 /* idtunr6/s */
4057                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4058                          S_VALUE(sneip->InDestUnreachs6, sneic->InDestUnreachs6, itv),
4059                          out + 1, outsize + 1, svg_p->restart);
4060                 /* odtunr6/s */
4061                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4062                          S_VALUE(sneip->OutDestUnreachs6, sneic->OutDestUnreachs6, itv),
4063                          out + 2, outsize + 2, svg_p->restart);
4064                 /* itmex6/s */
4065                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4066                          S_VALUE(sneip->InTimeExcds6, sneic->InTimeExcds6, itv),
4067                          out + 3, outsize + 3, svg_p->restart);
4068                 /* otmex6/s */
4069                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4070                          S_VALUE(sneip->OutTimeExcds6, sneic->OutTimeExcds6, itv),
4071                          out + 4, outsize + 4, svg_p->restart);
4072                 /* iprmpb6/s */
4073                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4074                          S_VALUE(sneip->InParmProblems6, sneic->InParmProblems6, itv),
4075                          out + 5, outsize + 5, svg_p->restart);
4076                 /* oprmpb6/s */
4077                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4078                          S_VALUE(sneip->OutParmProblems6, sneic->OutParmProblems6, itv),
4079                          out + 6, outsize + 6, svg_p->restart);
4080                 /* iredir6/s */
4081                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4082                          S_VALUE(sneip->InRedirects6, sneic->InRedirects6, itv),
4083                          out + 7, outsize + 7, svg_p->restart);
4084                 /* oredir6/s */
4085                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4086                          S_VALUE(sneip->OutRedirects6, sneic->OutRedirects6, itv),
4087                          out + 8, outsize + 8, svg_p->restart);
4088                 /* ipck2b6/s */
4089                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4090                          S_VALUE(sneip->InPktTooBigs6, sneic->InPktTooBigs6, itv),
4091                          out + 9, outsize + 9, svg_p->restart);
4092                 /* opck2b6/s */
4093                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4094                          S_VALUE(sneip->OutPktTooBigs6, sneic->OutPktTooBigs6, itv),
4095                          out + 10, outsize + 10, svg_p->restart);
4096         }
4097
4098         if (action & F_END) {
4099                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
4100                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
4101
4102                 /* Free remaining structures */
4103                 free_graphs(out, outsize, spmin, spmax);
4104         }
4105 }
4106
4107 /*
4108  ***************************************************************************
4109  * Display UDPv6 traffic statistics in SVG.
4110  *
4111  * IN:
4112  * @a           Activity structure with statistics.
4113  * @curr        Index in array for current sample statistics.
4114  * @action      Action expected from current function.
4115  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4116  *              flag indicating that a restart record has been previously
4117  *              found (.@restart) and time used for the X axis origin
4118  *              (@ust_time_ref).
4119  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4120  * @record_hdr  Pointer on record header of current stats sample.
4121  ***************************************************************************
4122  */
4123 __print_funct_t svg_print_net_udp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4124                                          unsigned long long itv, struct record_header *record_hdr)
4125 {
4126         struct stats_net_udp6
4127                 *snuc = (struct stats_net_udp6 *) a->buf[curr],
4128                 *snup = (struct stats_net_udp6 *) a->buf[!curr];
4129         int group[] = {2, 2};
4130         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4131         char *title[] = {"UDPv6 traffic statistics (1)", "UDPv6 traffic statistics (2)"};
4132         char *g_title[] = {"idgm6/s", "odgm6/s",
4133                            "noport6/s", "idgmer6/s"};
4134         int g_fields[] = {0, 1, 2, 3};
4135         static double *spmin, *spmax;
4136         static char **out;
4137         static int *outsize;
4138
4139         if (action & F_BEGIN) {
4140                 /*
4141                  * Allocate arrays that will contain the graphs data
4142                  * and the min/max values.
4143                  */
4144                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
4145         }
4146
4147         if (action & F_MAIN) {
4148                 /* Check for min/max values */
4149                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
4150                              itv, spmin, spmax, g_fields);
4151
4152                 /* idgm6/s */
4153                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4154                          S_VALUE(snup->InDatagrams6, snuc->InDatagrams6, itv),
4155                          out, outsize, svg_p->restart);
4156                 /* odgm6/s */
4157                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4158                          S_VALUE(snup->OutDatagrams6, snuc->OutDatagrams6, itv),
4159                          out + 1, outsize + 1, svg_p->restart);
4160                 /* noport6/s */
4161                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4162                          S_VALUE(snup->NoPorts6, snuc->NoPorts6, itv),
4163                          out + 2, outsize + 2, svg_p->restart);
4164                 /* idgmer6/s */
4165                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4166                          S_VALUE(snup->InErrors6, snuc->InErrors6, itv),
4167                          out + 3, outsize + 3, svg_p->restart);
4168         }
4169
4170         if (action & F_END) {
4171                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
4172                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
4173
4174                 /* Free remaining structures */
4175                 free_graphs(out, outsize, spmin, spmax);
4176         }
4177 }
4178
4179 /*
4180  ***************************************************************************
4181  * Display CPU frequency statistics in SVG.
4182  *
4183  * IN:
4184  * @a           Activity structure with statistics.
4185  * @curr        Index in array for current sample statistics.
4186  * @action      Action expected from current function.
4187  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4188  *              flag indicating that a restart record has been previously
4189  *              found (.@restart) and time used for the X axis origin
4190  *              (@ust_time_ref).
4191  * @itv         Interval of time in 1/100th of a second (unused here).
4192  * @record_hdr  Pointer on record header of current stats sample.
4193  ***************************************************************************
4194  */
4195 __print_funct_t svg_print_pwr_cpufreq_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4196                                             unsigned long long itv, struct record_header *record_hdr)
4197 {
4198         struct stats_pwr_cpufreq *spc, *spp;
4199         int group[] = {1};
4200         int g_type[] = {SVG_LINE_GRAPH};
4201         char *title[] = {"CPU clock frequency"};
4202         char *g_title[] = {"MHz"};
4203         static double *spmin, *spmax;
4204         static char **out;
4205         static int *outsize;
4206         char item_name[8];
4207         int i;
4208
4209         if (action & F_BEGIN) {
4210                 /*
4211                  * Allocate arrays that will contain the graphs data
4212                  * and the min/max values.
4213                  */
4214                 out = allocate_graph_lines(svg_p->nr_max, &outsize, &spmin, &spmax);
4215         }
4216
4217         if (action & F_MAIN) {
4218                 /* For each CPU */
4219                 for (i = 0; (i < a->nr[curr]) && (i < a->bitmap->b_size + 1); i++) {
4220
4221                         spc = (struct stats_pwr_cpufreq *) ((char *) a->buf[curr]  + i * a->msize);
4222                         spp = (struct stats_pwr_cpufreq *) ((char *) a->buf[!curr] + i * a->msize);
4223
4224                         /* Should current CPU (including CPU "all") be displayed? */
4225                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
4226                                 /* No */
4227                                 continue;
4228
4229                         /*
4230                          * Note: Don't skip offline CPU here as it is needed
4231                          * to make the graph go though 0.
4232                          */
4233
4234                         /* MHz */
4235                         recappend(record_hdr->ust_time - svg_p->ust_time_ref,
4236                                   ((double) spp->cpufreq) / 100,
4237                                   ((double) spc->cpufreq) / 100,
4238                                   out + i, outsize + i, svg_p->restart, svg_p->dt,
4239                                   spmin + i, spmax + i);
4240                 }
4241         }
4242
4243         if (action & F_END) {
4244                 int xid = 0;
4245
4246                 for (i = 0; (i < svg_p->nr_max) && (i < a->bitmap->b_size + 1); i++) {
4247
4248                         /* Should current CPU (including CPU "all") be displayed? */
4249                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
4250                                 /* No */
4251                                 continue;
4252
4253                         if (!i) {
4254                                 /* This is CPU "all" */
4255                                 strcpy(item_name, "all");
4256                         }
4257                         else {
4258                                 /*
4259                                  * If the maximum frequency reached by the CPU is 0, then
4260                                  * the CPU has been offline on the whole period.
4261                                  * => Don't display it.
4262                                  */
4263                                 if (*(spmax + i) == 0)
4264                                         continue;
4265
4266                                 sprintf(item_name, "%d", i - 1);
4267                         }
4268
4269                         if (draw_activity_graphs(a->g_nr, g_type,
4270                                                  title, g_title, item_name, group,
4271                                                  spmin + i, spmax + i, out + i, outsize + i,
4272                                                  svg_p, record_hdr, i, a->id, xid)) {
4273                                 xid++;
4274                         }
4275                 }
4276
4277                 /* Free remaining structures */
4278                 free_graphs(out, outsize, spmin, spmax);
4279         }
4280 }
4281
4282 /*
4283  ***************************************************************************
4284  * Display fan statistics in SVG.
4285  *
4286  * IN:
4287  * @a           Activity structure with statistics.
4288  * @curr        Index in array for current sample statistics.
4289  * @action      Action expected from current function.
4290  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4291  *              flag indicating that a restart record has been previously
4292  *              found (.@restart) and time used for the X axis origin
4293  *              (@ust_time_ref).
4294  * @itv         Interval of time in 1/100th of a second (unused here).
4295  * @record_hdr  Pointer on record header of current stats sample.
4296  ***************************************************************************
4297  */
4298 __print_funct_t svg_print_pwr_fan_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4299                                         unsigned long long itv, struct record_header *record_hdr)
4300 {
4301         struct stats_pwr_fan *spc, *spp;
4302         int group[] = {1};
4303         int g_type[] = {SVG_LINE_GRAPH};
4304         char *title[] = {"Fans speed"};
4305         char *g_title[] = {"~rpm"};
4306         static double *spmin, *spmax;
4307         static char **out;
4308         static int *outsize;
4309         char item_name[MAX_SENSORS_DEV_LEN + 8];
4310         int i;
4311
4312         if (action & F_BEGIN) {
4313                 /*
4314                  * Allocate arrays that will contain the graphs data
4315                  * and the min/max values.
4316                  */
4317                 out = allocate_graph_lines(svg_p->nr_max, &outsize, &spmin, &spmax);
4318         }
4319
4320         if (action & F_MAIN) {
4321                 /* For each fan */
4322                 for (i = 0; i < a->nr[curr]; i++) {
4323
4324                         spc = (struct stats_pwr_fan *) ((char *) a->buf[curr]  + i * a->msize);
4325                         spp = (struct stats_pwr_fan *) ((char *) a->buf[!curr] + i * a->msize);
4326
4327                         /* rpm */
4328                         recappend(record_hdr->ust_time - svg_p->ust_time_ref,
4329                                   (double) spp->rpm,
4330                                   (double) spc->rpm,
4331                                   out + i, outsize + i, svg_p->restart, svg_p->dt,
4332                                   spmin + i, spmax + i);
4333                 }
4334         }
4335
4336         if (action & F_END) {
4337                 int xid = 0;
4338
4339                 for (i = 0; i < svg_p->nr_max; i++) {
4340
4341                         spc = (struct stats_pwr_fan *) ((char *) a->buf[curr] + i * a->msize);
4342
4343                         snprintf(item_name, MAX_SENSORS_DEV_LEN + 8, "%d: %s", i + 1, spc->device);
4344                         item_name[MAX_SENSORS_DEV_LEN + 7] = '\0';
4345
4346                         if (draw_activity_graphs(a->g_nr, g_type,
4347                                                  title, g_title, item_name, group,
4348                                                  spmin + i, spmax + i, out + i, outsize + i,
4349                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
4350                                 xid++;
4351                         }
4352                 }
4353
4354                 /* Free remaining structures */
4355                 free_graphs(out, outsize, spmin, spmax);
4356         }
4357 }
4358
4359 /*
4360  ***************************************************************************
4361  * Display temperature statistics in SVG.
4362  *
4363  * IN:
4364  * @a           Activity structure with statistics.
4365  * @curr        Index in array for current sample statistics.
4366  * @action      Action expected from current function.
4367  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4368  *              flag indicating that a restart record has been previously
4369  *              found (.@restart) and time used for the X axis origin
4370  *              (@ust_time_ref).
4371  * @itv         Interval of time in 1/100th of a second (unused here).
4372  * @record_hdr  Pointer on record header of current stats sample.
4373  ***************************************************************************
4374  */
4375 __print_funct_t svg_print_pwr_temp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4376                                          unsigned long long itv, struct record_header *record_hdr)
4377 {
4378         struct stats_pwr_temp *spc;
4379         int group[] = {1, 1};
4380         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4381         char *title[] = {"Devices temperature (1)",
4382                          "Devices temperature (2)"};
4383         char *g_title[] = {"~degC",
4384                            "%temp"};
4385         static double *spmin, *spmax;
4386         static char **out;
4387         static int *outsize;
4388         char item_name[MAX_SENSORS_DEV_LEN + 8];
4389         int i;
4390         double tval;
4391
4392         if (action & F_BEGIN) {
4393                 /*
4394                  * Allocate arrays that will contain the graphs data
4395                  * and the min/max values.
4396                  */
4397                 out = allocate_graph_lines(2 * svg_p->nr_max, &outsize, &spmin, &spmax);
4398         }
4399
4400         if (action & F_MAIN) {
4401                 /* For each temperature sensor */
4402                 for (i = 0; i < a->nr[curr]; i++) {
4403
4404                         spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
4405
4406                         /* Look for min/max values */
4407                         if (spc->temp < *(spmin + 2 * i)) {
4408                                 *(spmin + 2 * i) = spc->temp;
4409                         }
4410                         if (spc->temp > *(spmax + 2 * i)) {
4411                                 *(spmax + 2 * i) = spc->temp;
4412                         }
4413                         tval = (spc->temp_max - spc->temp_min) ?
4414                                (spc->temp - spc->temp_min) / (spc->temp_max - spc->temp_min) * 100 :
4415                                0.0;
4416                         if (tval < *(spmin + 2 * i + 1)) {
4417                                 *(spmin + 2 * i + 1) = tval;
4418                         }
4419                         if (tval > *(spmax + 2 * i + 1)) {
4420                                 *(spmax + 2 * i + 1) = tval;
4421                         }
4422
4423                         /* degC */
4424                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4425                                  (double) spc->temp,
4426                                  out + 2 * i, outsize + 2 * i, svg_p->restart);
4427                         /* %temp */
4428                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4429                                  0.0, tval,
4430                                  out + 2 * i + 1, outsize + 2 * i + 1, svg_p->dt);
4431                 }
4432         }
4433
4434         if (action & F_END) {
4435                 int xid = 0;
4436
4437                 for (i = 0; i < svg_p->nr_max; i++) {
4438
4439                         spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
4440
4441                         snprintf(item_name, MAX_SENSORS_DEV_LEN + 8, "%d: %s", i + 1, spc->device);
4442                         item_name[MAX_SENSORS_DEV_LEN + 7] = '\0';
4443
4444                         if (draw_activity_graphs(a->g_nr, g_type,
4445                                                  title, g_title, item_name, group,
4446                                                  spmin + 2 * i, spmax + 2 * i, out + 2 * i, outsize + 2 * i,
4447                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
4448                                 xid++;
4449                         }
4450                 }
4451
4452                 /* Free remaining structures */
4453                 free_graphs(out, outsize, spmin, spmax);
4454         }
4455 }
4456
4457 /*
4458  ***************************************************************************
4459  * Display voltage inputs statistics in SVG.
4460  *
4461  * IN:
4462  * @a           Activity structure with statistics.
4463  * @curr        Index in array for current sample statistics.
4464  * @action      Action expected from current function.
4465  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4466  *              flag indicating that a restart record has been previously
4467  *              found (.@restart) and time used for the X axis origin
4468  *              (@ust_time_ref).
4469  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4470  * @record_hdr  Pointer on record header of current stats sample.
4471  ***************************************************************************
4472  */
4473 __print_funct_t svg_print_pwr_in_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4474                                        unsigned long long itv, struct record_header *record_hdr)
4475 {
4476         struct stats_pwr_in *spc;
4477         int group[] = {1, 1};
4478         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4479         char *title[] = {"Voltage inputs statistics (1)",
4480                          "Voltage inputs statistics (2)"};
4481         char *g_title[] = {"inV",
4482                            "%in"};
4483         static double *spmin, *spmax;
4484         static char **out;
4485         static int *outsize;
4486         char item_name[MAX_SENSORS_DEV_LEN + 8];
4487         int i;
4488         double tval;
4489
4490         if (action & F_BEGIN) {
4491                 /*
4492                  * Allocate arrays that will contain the graphs data
4493                  * and the min/max values.
4494                  */
4495                 out = allocate_graph_lines(2 * svg_p->nr_max, &outsize, &spmin, &spmax);
4496         }
4497
4498         if (action & F_MAIN) {
4499                 /* For each voltage input sensor */
4500                 for (i = 0; i < a->nr[curr]; i++) {
4501
4502                         spc = (struct stats_pwr_in *) ((char *) a->buf[curr] + i * a->msize);
4503
4504                         /* Look for min/max values */
4505                         if (spc->in < *(spmin + 2 * i)) {
4506                                 *(spmin + 2 * i) = spc->in;
4507                         }
4508                         if (spc->in > *(spmax + 2 * i)) {
4509                                 *(spmax + 2 * i) = spc->in;
4510                         }
4511                         tval = (spc->in_max - spc->in_min) ?
4512                                (spc->in - spc->in_min) / (spc->in_max - spc->in_min) * 100 :
4513                                0.0;
4514                         if (tval < *(spmin + 2 * i + 1)) {
4515                                 *(spmin + 2 * i + 1) = tval;
4516                         }
4517                         if (tval > *(spmax + 2 * i + 1)) {
4518                                 *(spmax + 2 * i + 1) = tval;
4519                         }
4520
4521                         /* inV */
4522                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4523                                  (double) spc->in,
4524                                  out + 2 * i, outsize + 2 * i, svg_p->restart);
4525                         /* %in */
4526                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4527                                  0.0, tval,
4528                                  out + 2 * i + 1, outsize + 2 * i + 1, svg_p->dt);
4529                 }
4530         }
4531
4532         if (action & F_END) {
4533                 int xid = 0;
4534
4535                 for (i = 0; i < svg_p->nr_max; i++) {
4536
4537                         spc = (struct stats_pwr_in *) ((char *) a->buf[curr]  + i * a->msize);
4538
4539                         snprintf(item_name, MAX_SENSORS_DEV_LEN + 8, "%d: %s", i + 1, spc->device);
4540                         item_name[MAX_SENSORS_DEV_LEN + 7] = '\0';
4541
4542                         if (draw_activity_graphs(a->g_nr, g_type,
4543                                                  title, g_title, item_name, group,
4544                                                  spmin + 2 * i, spmax + 2 * i, out + 2 * i, outsize + 2 * i,
4545                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
4546                                 xid++;
4547                         }
4548                 }
4549
4550                 /* Free remaining structures */
4551                 free_graphs(out, outsize, spmin, spmax);
4552         }
4553 }
4554
4555 /*
4556  ***************************************************************************
4557  * Display huge pages statistics in SVG.
4558  *
4559  * IN:
4560  * @a           Activity structure with statistics.
4561  * @curr        Index in array for current sample statistics.
4562  * @action      Action expected from current function.
4563  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4564  *              flag indicating that a restart record has been previously
4565  *              found (.@restart) and time used for the X axis origin
4566  *              (@ust_time_ref).
4567  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4568  * @record_hdr  Pointer on record header of current stats sample.
4569  ***************************************************************************
4570  */
4571 __print_funct_t svg_print_huge_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4572                                      unsigned long long itv, struct record_header *record_hdr)
4573 {
4574         struct stats_huge
4575                 *smc = (struct stats_huge *) a->buf[curr];
4576         int group[] = {2, 1};
4577         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4578         char *title[] = {"Huge pages utilization (1)",
4579                          "Huge pages utilization (2)"};
4580         char *g_title[] = {"~kbhugfree", "~kbhugused",
4581                            "%hugused"};
4582         int g_fields[] = {0};
4583         unsigned int local_types_nr[] = {0, 1, 0};
4584         static double *spmin, *spmax;
4585         static char **out;
4586         static int *outsize;
4587         double tval;
4588
4589         if (action & F_BEGIN) {
4590                 /*
4591                  * Allocate arrays that will contain the graphs data
4592                  * and the min/max values.
4593                  */
4594                 out = allocate_graph_lines(3, &outsize, &spmin, &spmax);
4595         }
4596
4597         if (action & F_MAIN) {
4598                 /* Check for min/max values */
4599                 save_extrema(local_types_nr, (void *) a->buf[curr], NULL,
4600                              itv, spmin, spmax, g_fields);
4601
4602                 if (smc->tlhkb - smc->frhkb < *(spmin + 1)) {
4603                         *(spmin + 1) = smc->tlhkb - smc->frhkb;
4604                 }
4605                 if (smc->tlhkb - smc->frhkb > *(spmax + 1)) {
4606                         *(spmax + 1) = smc->tlhkb - smc->frhkb;
4607                 }
4608                 tval = smc->tlhkb ? SP_VALUE(smc->frhkb, smc->tlhkb, smc->tlhkb) : 0.0;
4609                 if (tval < *(spmin + 2)) {
4610                         *(spmin + 2) = tval;
4611                 }
4612                 if (tval > *(spmax + 2)) {
4613                         *(spmax + 2) = tval;
4614                 }
4615
4616                 /* kbhugfree */
4617                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4618                           (unsigned long long) smc->frhkb,
4619                           out, outsize, svg_p->restart);
4620                 /* hugused */
4621                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4622                           (unsigned long long) smc->tlhkb - smc->frhkb,
4623                           out + 1, outsize + 1, svg_p->restart);
4624                 /* %hugused */
4625                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4626                          0.0, tval,
4627                          out + 2, outsize + 2, svg_p->dt);
4628         }
4629
4630         if (action & F_END) {
4631                 draw_activity_graphs(a->g_nr, g_type,
4632                                      title, g_title, NULL, group,
4633                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
4634
4635                 /* Free remaining structures */
4636                 free_graphs(out, outsize, spmin, spmax);
4637         }
4638 }
4639
4640 /*
4641  ***************************************************************************
4642  * Display filesystem statistics in SVG.
4643  *
4644  * IN:
4645  * @a           Activity structure with statistics.
4646  * @curr        Index in array for current sample statistics.
4647  * @action      Action expected from current function.
4648  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4649  *              flag indicating that a restart record has been previously
4650  *              found (.@restart) and time used for the X axis origin
4651  *              (@ust_time_ref).
4652  * @itv         Interval of time in 1/100th of a second (unused here).
4653  * @record_hdr  Pointer on record header of current stats sample.
4654  ***************************************************************************
4655  */
4656 __print_funct_t svg_print_filesystem_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4657                                            unsigned long long itv, struct record_header *record_hdr)
4658 {
4659         struct stats_filesystem *sfc, *sfp;
4660         int group[] = {2, 2, 2, 1};
4661         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH,
4662                         SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4663         char *title[] = {"Filesystems statistics (1)", "Filesystems statistics (2)",
4664                          "Filesystems statistics (3)", "Filesystems statistics (4)"};
4665         char *g_title[] = {"~MBfsfree", "~MBfsused",
4666                            "%ufsused", "%fsused",
4667                            "Ifree/1000", "Iused/1000",
4668                            "%Iused"};
4669         static double *spmin, *spmax;
4670         static char **out;
4671         static int *outsize;
4672         char *item_name = NULL;
4673         double tval;
4674         int i, k, pos, restart;
4675
4676         if (action & F_BEGIN) {
4677                 /*
4678                  * Allocate arrays (#0..6) that will contain the graphs data
4679                  * and the min/max values.
4680                  * Also allocate two additional arrays (#7..8) for each filesystem:
4681                  * out + 7 will contain the filesystem name,
4682                  * out + 8 will contain the mount point.
4683                  */
4684                 out = allocate_graph_lines(9 * svg_p->nr_max, &outsize, &spmin, &spmax);
4685         }
4686
4687         if (action & F_MAIN) {
4688                 /* For each filesystem structure */
4689                 for (i = 0; i < a->nr[curr]; i++) {
4690                         sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize);
4691
4692                         if (dlst_fs_idx) {
4693                                 /* A list of devices has been entered on the command line */
4694                                 if (!search_sa_dlist(st_fs_list, dlst_fs_idx,
4695                                                      DISPLAY_MOUNT(a->opt_flags) ? sfc->mountp : sfc->fs_name))
4696                                         /* Device not found */
4697                                         continue;
4698                         }
4699
4700                         /* Look for corresponding graph */
4701                         for (k = 0; k < svg_p->nr_max; k++) {
4702                                 item_name = *(out + k * 9 + 7);
4703                                 if (!strcmp(sfc->fs_name, item_name))
4704                                         /* Graph found! */
4705                                         break;
4706                         }
4707
4708                         if (k == svg_p->nr_max) {
4709                                 /* Graph not found: Look for first free entry */
4710                                 for (k = 0; k < svg_p->nr_max; k++) {
4711                                         item_name = *(out + k * 9 + 7);
4712                                         if (!strcmp(item_name, ""))
4713                                                 break;
4714                                 }
4715                                 if (k == svg_p->nr_max) {
4716                                         /* No free graph entry: Extend all buffers */
4717                                         reallocate_all_graph_lines(svg_p->nr_max,
4718                                                                    &out, &outsize, &spmin, &spmax);
4719                                         svg_p->nr_max *= 2;
4720                                 }
4721                         }
4722
4723                         pos = k * 9;
4724
4725                         if (!item_name[0]) {
4726                                 /* Save filesystem name and mount point (if not already done) */
4727                                 strncpy(item_name, sfc->fs_name, CHUNKSIZE);
4728                                 item_name[CHUNKSIZE - 1] = '\0';
4729                                 item_name = *(out + pos + 8);
4730                                 strncpy(item_name, sfc->mountp, CHUNKSIZE);
4731                                 item_name[CHUNKSIZE - 1] = '\0';
4732                         }
4733
4734                         restart = TRUE;
4735                         for (k = 0; k < a->nr[!curr]; k++) {
4736                                 sfp = (struct stats_filesystem *) ((char *) a->buf[!curr] + k * a->msize);
4737                                 if (!strcmp(sfc->fs_name, sfp->fs_name)) {
4738                                         /* Filesystem found in previous sample */
4739                                         restart = svg_p->restart;
4740                                 }
4741                         }
4742
4743                         /* Check for min/max values */
4744
4745                         /* Compute fsfree min/max values */
4746                         tval = (double) sfc->f_bfree;
4747                         if (tval > *(spmax + pos)) {
4748                                 *(spmax + pos) = tval;
4749                         }
4750                         if (tval < *(spmin + pos)) {
4751                                 *(spmin + pos) = tval;
4752                         }
4753                         /* Compute fsused min/max values */
4754                         tval = (double) (sfc->f_blocks - sfc->f_bfree);
4755                         if (tval > *(spmax + pos + 1)) {
4756                                 *(spmax + pos + 1) = tval;
4757                         }
4758                         if (tval < *(spmin + pos + 1)) {
4759                                 *(spmin + pos + 1) = tval;
4760                         }
4761                         /* Compute %ufsused min/max values */
4762                         tval = sfc->f_blocks ?
4763                                SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks) : 0.0;
4764                         if (tval > *(spmax + pos + 2)) {
4765                                 *(spmax + pos + 2) = tval;
4766                         }
4767                         if (tval < *(spmin + pos + 2)) {
4768                                 *(spmin + pos + 2) = tval;
4769                         }
4770                         /* Compute %fsused min/max values */
4771                         tval = sfc->f_blocks ?
4772                                SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks) : 0.0;
4773                         if (tval > *(spmax + pos + 3)) {
4774                                 *(spmax + pos + 3) = tval;
4775                         }
4776                         if (tval < *(spmin + pos + 3)) {
4777                                 *(spmin + pos + 3) = tval;
4778                         }
4779                         /* Compute Ifree min/max values */
4780                         tval = (double) sfc->f_ffree;
4781                         if (tval > *(spmax + pos + 4)) {
4782                                 *(spmax + pos + 4) = tval;
4783                         }
4784                         if (tval < *(spmin + pos + 4)) {
4785                                 *(spmin + pos + 4) = tval;
4786                         }
4787                         /* Compute Iused min/max values */
4788                         tval = (double) (sfc->f_files - sfc->f_ffree);
4789                         if (tval > *(spmax + pos + 5)) {
4790                                 *(spmax + pos + 5) = tval;
4791                         }
4792                         if (tval < *(spmin + pos + 5)) {
4793                                 *(spmin + pos + 5) = tval;
4794                         }
4795                         /* Compute %Iused min/max values */
4796                         tval = sfc->f_files ?
4797                                SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) : 0.0;
4798                         if (tval > *(spmax + pos + 6)) {
4799                                 *(spmax + pos + 6) = tval;
4800                         }
4801                         if (tval < *(spmin + pos + 6)) {
4802                                 *(spmin + pos + 6) = tval;
4803                         }
4804
4805                         /* MBfsfree */
4806                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4807                                  (double) sfc->f_bfree / 1024 / 1024,
4808                                  out + pos, outsize + pos, restart);
4809                         /* MBfsused */
4810                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4811                                  (double) (sfc->f_blocks - sfc->f_bfree) / 1024 / 1024,
4812                                  out + pos + 1, outsize + pos + 1, restart);
4813                         /* %ufsused */
4814                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4815                                  0.0,
4816                                  sfc->f_blocks ?
4817                                  SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks) : 0.0,
4818                                  out + pos + 2, outsize + pos + 2, svg_p->dt);
4819                         /* %fsused */
4820                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4821                                  0.0,
4822                                  sfc->f_blocks ?
4823                                  SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks) : 0.0,
4824                                  out + pos + 3, outsize + pos + 3, svg_p->dt);
4825                         /* Ifree */
4826                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4827                                  ((double) sfc->f_ffree) / 1000,
4828                                  out + pos + 4, outsize + pos + 4, restart);
4829                         /* Iused */
4830                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4831                                  ((double) (sfc->f_files - sfc->f_ffree)) / 1000,
4832                                  out + pos + 5, outsize + pos + 5, restart);
4833                         /* %Iused */
4834                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4835                                  0.0,
4836                                  sfc->f_files ?
4837                                  SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) : 0.0,
4838                                  out + pos + 6, outsize + pos + 6, svg_p->dt);
4839                 }
4840         }
4841
4842         if (action & F_END) {
4843                 int xid = 0;
4844
4845                 for (i = 0; i < svg_p->nr_max; i++) {
4846
4847                         /* Check if there is something to display */
4848                         pos = i * 9;
4849                         if (!**(out + pos))
4850                                 continue;
4851
4852                         /* Conversion B -> MB and inodes/1000 */
4853                         for (k = 0; k < 2; k++) {
4854                                 *(spmin + pos + k) /= (1024 * 1024);
4855                                 *(spmax + pos + k) /= (1024 * 1024);
4856                                 *(spmin + pos + 4 + k) /= 1000;
4857                                 *(spmax + pos + 4 + k) /= 1000;
4858                         }
4859
4860                         if (DISPLAY_MOUNT(a->opt_flags)) {
4861                                 item_name = *(out + pos + 8);
4862                         }
4863                         else {
4864                                 item_name = *(out + pos + 7);
4865                         }
4866
4867                         if (draw_activity_graphs(a->g_nr, g_type, title, g_title, item_name, group,
4868                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
4869                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
4870                                 xid++;
4871                         }
4872                 }
4873
4874                 /* Free remaining structures */
4875                 free_graphs(out, outsize, spmin, spmax);
4876         }
4877 }
4878
4879 /*
4880  ***************************************************************************
4881  * Display Fibre Channel HBA statistics in SVG.
4882  *
4883  * IN:
4884  * @a           Activity structure with statistics.
4885  * @curr        Index in array for current sample statistics.
4886  * @action      Action expected from current function.
4887  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4888  *              flag indicating that a restart record has been previously
4889  *              found (.@restart) and time used for the X axis origin
4890  *              (@ust_time_ref).
4891  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4892  * @record_hdr  Pointer on record header of current stats sample.
4893  ***************************************************************************
4894  */
4895 __print_funct_t svg_print_fchost_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4896                                        unsigned long long itv, struct record_header *record_hdr)
4897 {
4898         struct stats_fchost *sfcc, *sfcp;
4899         int group[] = {2, 2};
4900         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4901         char *title[] = {"Fibre Channel HBA statistics (1)", "Fibre Channel HBA statistics (2)"};
4902         char *g_title[] = {"fch_rxf/s", "fch_txf/s",
4903                            "fch_rxw/s", "fch_txw/s"};
4904         int g_fields[] = {0, 1, 2, 3};
4905         static double *spmin, *spmax;
4906         static char **out;
4907         static int *outsize;
4908         char *item_name;
4909         int i, j, j0, k, found, pos, restart, *unregistered;
4910
4911         if (action & F_BEGIN) {
4912                 /*
4913                  * Allocate arrays (#0..3) that will contain the graphs data
4914                  * and the min/max values.
4915                  * Also allocate one additional array (#4) that will contain
4916                  * FC HBA name (out + 4) and a positive value (TRUE) if the interface
4917                  * has either still not been registered, or has been unregistered
4918                  * (outsize + 4).
4919                  */
4920                 out = allocate_graph_lines(5 * svg_p->nr_max, &outsize, &spmin, &spmax);
4921         }
4922
4923         if (action & F_MAIN) {
4924                 restart = svg_p->restart;
4925                 /*
4926                  * Mark previously registered interfaces as now
4927                  * possibly unregistered for all graphs.
4928                  */
4929                 for (k = 0; k < svg_p->nr_max; k++) {
4930                         unregistered = outsize + k * 5 + 4;
4931                         if (*unregistered == FALSE) {
4932                                 *unregistered = MAYBE;
4933                         }
4934                 }
4935
4936                 /* For each FC HBA */
4937                 for (i = 0; i < a->nr[curr]; i++) {
4938
4939                         found = FALSE;
4940
4941                         if (a->nr[!curr] > 0) {
4942                                 sfcc = (struct stats_fchost *) ((char *) a->buf[curr] + i * a->msize);
4943
4944                                 /* Look for corresponding graph */
4945                                 for (k = 0; k < svg_p->nr_max; k++) {
4946                                         item_name = *(out + k * 5 + 4);
4947                                         if (!strcmp(sfcc->fchost_name, item_name))
4948                                                 /* Graph found! */
4949                                                 break;
4950                                 }
4951                                 if (k == svg_p->nr_max) {
4952                                         /* Graph not found: Look for first free entry */
4953                                         for (k = 0; k < svg_p->nr_max; k++) {
4954                                                 item_name = *(out + k * 5 + 4);
4955                                                 if (!strcmp(item_name, ""))
4956                                                         break;
4957                                         }
4958                                         if (k == svg_p->nr_max) {
4959                                                 /* No free graph entry: Extend all buffers */
4960                                                 reallocate_all_graph_lines(svg_p->nr_max,
4961                                                                            &out, &outsize, &spmin, &spmax);
4962                                                 svg_p->nr_max *= 2;
4963                                         }
4964                                 }
4965
4966                                 pos = k * 5;
4967                                 unregistered = outsize + pos + 4;
4968
4969                                 /* Look for corresponding structure in previous iteration */
4970                                 j = i;
4971
4972                                 if (j >= a->nr[!curr]) {
4973                                         j = a->nr[!curr] - 1;
4974                                 }
4975
4976                                 j0 = j;
4977
4978                                 do {
4979                                         sfcp = (struct stats_fchost *) ((char *) a->buf[!curr] + j * a->msize);
4980                                         if (!strcmp(sfcc->fchost_name, sfcp->fchost_name)) {
4981                                                 found = TRUE;
4982                                                 break;
4983                                         }
4984                                         if (++j >= a->nr[!curr]) {
4985                                                 j = 0;
4986                                         }
4987                                 }
4988                                 while (j != j0);
4989                         }
4990
4991                         if (!found)
4992                                 continue;
4993
4994                         /*
4995                          * If current interface was marked as previously unregistered,
4996                          * then set restart variable to TRUE so that the graph will be
4997                          * discontinuous, and mark it as now registered.
4998                          */
4999                         if (*unregistered == TRUE) {
5000                                 restart = TRUE;
5001                         }
5002                         *unregistered = FALSE;
5003
5004                         item_name = *(out + pos + 4);
5005                         if (!item_name[0]) {
5006                                 /* Save FC HBA name */
5007                                 strncpy(item_name, sfcc->fchost_name, CHUNKSIZE);
5008                                 item_name[CHUNKSIZE - 1] = '\0';
5009                         }
5010
5011                         /* Look for min/max values */
5012                         save_extrema(a->gtypes_nr, (void *) sfcc, (void *) sfcp,
5013                                 itv, spmin + pos, spmax + pos, g_fields);
5014
5015                         /* fch_rxf/s */
5016                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5017                                  S_VALUE(sfcp->f_rxframes, sfcc->f_rxframes, itv),
5018                                  out + pos, outsize + pos, restart);
5019                         /* fch_txf/s */
5020                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5021                                  S_VALUE(sfcp->f_txframes, sfcc->f_txframes, itv),
5022                                  out + pos + 1, outsize + pos + 1, restart);
5023                         /* fch_rxw/s */
5024                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5025                                  S_VALUE(sfcp->f_rxwords, sfcc->f_rxwords, itv),
5026                                  out + pos + 2, outsize + pos + 2, restart);
5027                         /* fch_txw/s */
5028                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5029                                  S_VALUE(sfcp->f_txwords, sfcc->f_txwords, itv),
5030                                  out + pos + 3, outsize + pos + 3, restart);
5031                 }
5032
5033                 /* Mark interfaces not seen here as now unregistered */
5034                 for (k = 0; k < svg_p->nr_max; k++) {
5035                         unregistered = outsize + k * 5 + 4;
5036                         if (*unregistered != FALSE) {
5037                                 *unregistered = TRUE;
5038                         }
5039                 }
5040         }
5041
5042         if (action & F_END) {
5043                 for (i = 0; i < svg_p->nr_max; i++) {
5044
5045                         /* Check if there is something to display */
5046                         pos = i * 5;
5047                         if (!**(out + pos))
5048                                 continue;
5049
5050                         item_name = *(out + pos + 4);
5051                         draw_activity_graphs(a->g_nr, g_type,
5052                                              title, g_title, item_name, group,
5053                                              spmin + pos, spmax + pos, out + pos, outsize + pos,
5054                                              svg_p, record_hdr, FALSE, a->id, i);
5055                 }
5056
5057                 /* Free remaining structures */
5058                 free_graphs(out, outsize, spmin, spmax);
5059         }
5060 }
5061
5062 /*
5063  ***************************************************************************
5064  * Display softnet statistics in SVG.
5065  *
5066  * IN:
5067  * @a           Activity structure with statistics.
5068  * @curr        Index in array for current sample statistics.
5069  * @action      Action expected from current function.
5070  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5071  *              flag indicating that a restart record has been previously
5072  *              found (.@restart) and time used for the X axis origin
5073  *              (@ust_time_ref).
5074  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5075  * @record_hdr  Pointer on record header of current stats sample.
5076  ***************************************************************************
5077  */
5078 __print_funct_t svg_print_softnet_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5079                                         unsigned long long itv, struct record_header *record_hdr)
5080 {
5081         struct stats_softnet *ssnc, *ssnp, ssnczero;
5082         int group[] = {2, 3};
5083         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
5084         char *title[] = {"Software-based network processing statistics (1)",
5085                          "Software-based network processing statistics (2)"};
5086         char *g_title[] = {"total/s", "dropd/s",
5087                            "squeezd/s", "rx_rps/s", "flw_lim/s"};
5088         int g_fields[] = {0, 1, 2, 3, 4};
5089         static double *spmin, *spmax;
5090         static char **out;
5091         static int *outsize;
5092         char item_name[8];
5093         unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
5094         int i, pos, restart;
5095
5096         if (action & F_BEGIN) {
5097                 /*
5098                  * Allocate arrays that will contain the graphs data
5099                  * and the min/max values.
5100                  */
5101                 out = allocate_graph_lines(5 * svg_p->nr_max, &outsize, &spmin, &spmax);
5102         }
5103
5104         if (action & F_MAIN) {
5105                 memset(&ssnczero, 0, STATS_SOFTNET_SIZE);
5106
5107                 /* @nr[curr] cannot normally be greater than @nr_ini */
5108                 if (a->nr[curr] > a->nr_ini) {
5109                         a->nr_ini = a->nr[curr];
5110                 }
5111
5112                 /* Compute statistics for CPU "all" */
5113                 get_global_soft_statistics(a, !curr, curr, flags, offline_cpu_bitmap);
5114
5115                 /* For each CPU */
5116                 for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
5117                         restart = svg_p->restart;
5118
5119                         /* Should current CPU (including CPU "all") be displayed? */
5120                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
5121                                 /* No */
5122                                 continue;
5123
5124                         ssnc = (struct stats_softnet *) ((char *) a->buf[curr]  + i * a->msize);
5125                         ssnp = (struct stats_softnet *) ((char *) a->buf[!curr] + i * a->msize);
5126
5127                         /* Is current CPU marked offline? */
5128                         if (offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07))) {
5129                                 /*
5130                                  * Yes and it doesn't follow a RESTART record.
5131                                  * To add a discontinuity in graph, we simulate
5132                                  * a RESTART mark.
5133                                  */
5134                                 restart = TRUE;
5135                                 if (svg_p->restart) {
5136                                         /*
5137                                          * CPU is offline and it follows a real
5138                                          * RESTART record. Ignore its current value
5139                                          * (no previous sample).
5140                                          */
5141                                         ssnc = &ssnczero;
5142                                 }
5143                         }
5144                         pos = i * 5;
5145
5146                         /* Check for min/max values */
5147                         save_extrema(a->gtypes_nr, (void *) ssnc, (void *) ssnp,
5148                                      itv, spmin + pos, spmax + pos, g_fields);
5149
5150                         /* total/s */
5151                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5152                                  S_VALUE(ssnp->processed, ssnc->processed, itv),
5153                                  out + pos, outsize + pos, restart);
5154                         /* dropd/s */
5155                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5156                                  S_VALUE(ssnp->dropped, ssnc->dropped, itv),
5157                                  out + pos + 1, outsize + pos + 1, restart);
5158                         /* squeezd/s */
5159                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5160                                  S_VALUE(ssnp->time_squeeze, ssnc->time_squeeze, itv),
5161                                  out + pos + 2, outsize + pos + 2, restart);
5162                         /* rx_rps/s */
5163                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5164                                  S_VALUE(ssnp->received_rps, ssnc->received_rps, itv),
5165                                  out + pos + 3, outsize + pos + 3, restart);
5166                         /* flw_lim/s */
5167                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5168                                  S_VALUE(ssnp->flow_limit, ssnc->flow_limit, itv),
5169                                  out + pos + 4, outsize + pos + 4, restart);
5170                 }
5171         }
5172
5173         if (action & F_END) {
5174                 for (i = 0; (i < svg_p->nr_max) && (i < a->bitmap->b_size + 1); i++) {
5175
5176                         /* Should current CPU (including CPU "all") be displayed? */
5177                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
5178                                 /* No */
5179                                 continue;
5180
5181                         pos = i * 5;
5182
5183                         if (!i) {
5184                                 /* This is CPU "all" */
5185                                 strcpy(item_name, "all");
5186                         }
5187                         else {
5188                                 sprintf(item_name, "%d", i - 1);
5189                         }
5190
5191                         draw_activity_graphs(a->g_nr, g_type,
5192                                              title, g_title, item_name, group,
5193                                              spmin + pos, spmax + pos, out + pos, outsize + pos,
5194                                              svg_p, record_hdr, FALSE, a->id, i);
5195                 }
5196
5197                 /* Free remaining structures */
5198                 free_graphs(out, outsize, spmin, spmax);
5199         }
5200 }