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