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