]> granicus.if.org Git - sysstat/blob - svg_stats.c
sar/sadc: Dereference nr array pointer in struct activity
[sysstat] / svg_stats.c
1 /*
2  * svg_stats.c: Funtions used by sadf to display statistics in SVG format.
3  * (C) 2016-2020 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_device_name(sdc->major, sdc->minor, sdc->wwn, sdc->part_nr,
2130                                                    DISPLAY_PRETTY(flags), DISPLAY_PERSIST_NAME_S(flags),
2131                                                    USE_STABLE_ID(flags), NULL);
2132
2133                         if (a->item_list != NULL) {
2134                                 /* A list of devices has been entered on the command line */
2135                                 if (!search_list_item(a->item_list, dev_name))
2136                                         /* Device not found */
2137                                         continue;
2138                         }
2139
2140                         /* Look for corresponding graph */
2141                         for (k = 0; k < a->item_list_sz; k++) {
2142                                 item_name = *(out + k * nr_arrays + 8);
2143                                 if (!strcmp(dev_name, item_name))
2144                                         /* Graph found! */
2145                                         break;
2146                         }
2147                         if (k == a->item_list_sz) {
2148                                 /* Graph not found: Look for first free entry */
2149                                 for (k = 0; k < a->item_list_sz; k++) {
2150                                         item_name = *(out + k * nr_arrays + 8);
2151                                         if (!strcmp(item_name, ""))
2152                                                 break;
2153                                 }
2154                                 if (k == a->item_list_sz) {
2155                                         /* No free graph entry: Ignore it (should never happen) */
2156 #ifdef DEBUG
2157                                         fprintf(stderr, "%s: Name=%s major=%d minor=%d\n",
2158                                                 __FUNCTION__, dev_name, sdc->major, sdc->minor);
2159 #endif
2160                                         continue;
2161                                 }
2162                         }
2163                         pos = k * nr_arrays;
2164                         unregistered = outsize + pos + 8;
2165
2166                         /*
2167                          * If current device was marked as previously unregistered,
2168                          * then set restart variable to TRUE so that the graph will be
2169                          * discontinuous, and mark it as now registered.
2170                          */
2171                         if (*unregistered == TRUE) {
2172                                 restart = TRUE;
2173                         }
2174                         *unregistered = FALSE;
2175
2176                         item_name = *(out + pos + 8);
2177                         if (!item_name[0]) {
2178                                 /* Save device name (WWN id or pretty name) if not already done */
2179                                 strncpy(item_name, dev_name, CHUNKSIZE);
2180                                 item_name[CHUNKSIZE - 1] = '\0';
2181                         }
2182
2183                         j = check_disk_reg(a, curr, !curr, i);
2184                         if (j < 0) {
2185                                 /* This is a newly registered interface. Previous stats are zero */
2186                                 sdp = &sdpzero;
2187                         }
2188                         else {
2189                                 sdp = (struct stats_disk *) ((char *) a->buf[!curr] + j * a->msize);
2190                         }
2191
2192                         /* Check for min/max values */
2193                         save_extrema(local_types_nr, (void *) sdc, (void *) sdp,
2194                                      itv, spmin + pos, spmax + pos, g_fields);
2195
2196                         rkB = S_VALUE(sdp->rd_sect, sdc->rd_sect, itv) / 2;
2197                         wkB = S_VALUE(sdp->wr_sect, sdc->wr_sect, itv) / 2;
2198                         dkB = S_VALUE(sdp->dc_sect, sdc->dc_sect, itv) / 2;
2199                         if (rkB < *(spmin + pos + 1)) {
2200                                 *(spmin + pos + 1) = rkB;
2201                         }
2202                         if (rkB > *(spmax + pos + 1)) {
2203                                 *(spmax + pos + 1) = rkB;
2204                         }
2205                         if (wkB < *(spmin + pos + 2)) {
2206                                 *(spmin + pos + 2) = wkB;
2207                         }
2208                         if (wkB > *(spmax + pos + 2)) {
2209                                 *(spmax + pos + 2) = wkB;
2210                         }
2211                         if (dkB < *(spmin + pos + 3)) {
2212                                 *(spmin + pos + 3) = dkB;
2213                         }
2214                         if (dkB > *(spmax + pos + 3)) {
2215                                 *(spmax + pos + 3) = dkB;
2216                         }
2217
2218                         compute_ext_disk_stats(sdc, sdp, itv, &xds);
2219                         if ((xds.arqsz / 2) < *(spmin + pos + 4)) {
2220                                 *(spmin + pos + 4) = xds.arqsz / 2;
2221                         }
2222                         if ((xds.arqsz / 2) > *(spmax + pos + 4)) {
2223                                 *(spmax + pos + 4) = xds.arqsz / 2;
2224                         }
2225                         aqusz = S_VALUE(sdp->rq_ticks, sdc->rq_ticks, itv) / 1000.0;
2226                         if (aqusz < *(spmin + pos + 5)) {
2227                                 *(spmin + pos + 5) = aqusz;
2228                         }
2229                         if (aqusz > *(spmax + pos + 5)) {
2230                                 *(spmax + pos + 5) = aqusz;
2231                         }
2232                         if (xds.await < *(spmin + pos + 6)) {
2233                                 *(spmin + pos + 6) = xds.await;
2234                         }
2235                         if (xds.await > *(spmax + pos + 6)) {
2236                                 *(spmax + pos + 6) = xds.await;
2237                         }
2238                         if ((xds.util / 10.0) < *(spmin + pos + 7)) {
2239                                 *(spmin + pos + 7) = xds.util / 10.0;
2240                         }
2241                         if ((xds.util / 10.0) > *(spmax + pos + 7)) {
2242                                 *(spmax + pos + 7) = xds.util / 10.0;
2243                         }
2244
2245                         /* tps */
2246                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2247                                  S_VALUE(sdp->nr_ios, sdc->nr_ios, itv),
2248                                  out + pos, outsize + pos, restart);
2249                         /* rkB/s */
2250                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2251                                  S_VALUE(sdp->rd_sect, sdc->rd_sect, itv) / 2,
2252                                  out + pos + 1, outsize + pos + 1, restart);
2253                         /* wkB/s */
2254                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2255                                  S_VALUE(sdp->wr_sect, sdc->wr_sect, itv) / 2,
2256                                  out + pos + 2, outsize + pos + 2, restart);
2257                         /* dkB/s */
2258                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2259                                  S_VALUE(sdp->dc_sect, sdc->dc_sect, itv) / 2,
2260                                  out + pos + 3, outsize + pos + 3, restart);
2261                         /* areq-sz */
2262                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2263                                  xds.arqsz / 2,
2264                                  out + pos + 4, outsize + pos + 4, restart);
2265                         /* aqu-sz */
2266                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2267                                  aqusz,
2268                                  out + pos + 5, outsize + pos + 5, restart);
2269                         /* await */
2270                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2271                                  xds.await,
2272                                  out + pos + 6, outsize + pos + 6, restart);
2273                         /* %util */
2274                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
2275                                  0.0, xds.util / 10.0,
2276                                  out + pos + 7, outsize + pos + 7, svg_p->dt);
2277                 }
2278
2279                 /* Mark devices not seen here as now unregistered */
2280                 for (k = 0; k < a->item_list_sz; k++) {
2281                         unregistered = outsize + k * nr_arrays + 8;
2282                         if (*unregistered != FALSE) {
2283                                 *unregistered = TRUE;
2284                         }
2285                 }
2286         }
2287
2288         if (action & F_END) {
2289                 int xid = 0;
2290
2291                 for (i = 0; i < a->item_list_sz; i++) {
2292                         /* Check if there is something to display */
2293                         pos = i * nr_arrays;
2294                         if (!**(out + pos))
2295                                 continue;
2296
2297                         item_name = *(out + pos + 8);
2298                         if (draw_activity_graphs(a->g_nr, g_type,
2299                                                  title, g_title, item_name, group,
2300                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2301                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
2302                                 xid++;
2303                         }
2304                 }
2305
2306                 /* Free remaining structures */
2307                 free_graphs(out, outsize, spmin, spmax);
2308         }
2309 }
2310
2311 /*
2312  ***************************************************************************
2313  * Display network interfaces statistics in SVG.
2314  *
2315  * IN:
2316  * @a           Activity structure with statistics.
2317  * @curr        Index in array for current sample statistics.
2318  * @action      Action expected from current function.
2319  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2320  *              flag indicating that a restart record has been previously
2321  *              found (.@restart) and time used for the X axis origin
2322  *              (@ust_time_ref).
2323  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2324  * @record_hdr  Pointer on record header of current stats sample.
2325  ***************************************************************************
2326  */
2327 __print_funct_t svg_print_net_dev_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2328                                         unsigned long long itv, struct record_header *record_hdr)
2329 {
2330         struct stats_net_dev *sndc, *sndp, sndzero;
2331         int group[] = {2, 2, 3, 1};
2332         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2333                         SVG_BAR_GRAPH};
2334         char *title[] = {"Network interfaces statistics (1)", "Network interfaces statistics (2)",
2335                          "Network interfaces statistics (3)", "Network interfaces statistics (4)"};
2336         char *g_title[] = {"rxpck/s", "txpck/s",
2337                            "rxkB/s", "txkB/s",
2338                            "rxcmp/s", "txcmp/s", "rxmcst/s",
2339                            "%ifutil"};
2340         int g_fields[] = {0, 1, 2, 3, 4, 5, 6};
2341         unsigned int local_types_nr[] = {7, 0, 0};
2342         static double *spmin, *spmax;
2343         static char **out;
2344         static int *outsize;
2345         char *item_name;
2346         double rxkb, txkb, ifutil;
2347         int i, j, k, pos, restart, *unregistered;
2348
2349         if (action & F_BEGIN) {
2350                 /*
2351                  * Allocate arrays (#0..7) that will contain the graphs data
2352                  * and the min/max values.
2353                  * Also allocate one additional array (#8) for each interface:
2354                  * out + 8 will contain the interface name,
2355                  * outsize + 8 will contain a positive value (TRUE) if the interface
2356                  * has either still not been registered, or has been unregistered.
2357                  */
2358                 out = allocate_graph_lines(9 * a->item_list_sz, &outsize, &spmin, &spmax);
2359         }
2360
2361         if (action & F_MAIN) {
2362                 memset(&sndzero, 0, STATS_NET_DEV_SIZE);
2363                 restart = svg_p->restart;
2364                 /*
2365                  * Mark previously registered interfaces as now
2366                  * possibly unregistered for all graphs.
2367                  */
2368                 for (k = 0; k < a->item_list_sz; k++) {
2369                         unregistered = outsize + k * 9 + 8;
2370                         if (*unregistered == FALSE) {
2371                                 *unregistered = MAYBE;
2372                         }
2373                 }
2374
2375                 /* For each network interfaces structure */
2376                 for (i = 0; i < a->nr[curr]; i++) {
2377                         sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
2378
2379                         if (a->item_list != NULL) {
2380                                 /* A list of devices has been entered on the command line */
2381                                 if (!search_list_item(a->item_list, sndc->interface))
2382                                         /* Device not found */
2383                                         continue;
2384                         }
2385
2386                         /* Look for corresponding graph */
2387                         for (k = 0; k < a->item_list_sz; k++) {
2388                                 item_name = *(out + k * 9 + 8);
2389                                 if (!strcmp(sndc->interface, item_name))
2390                                         /* Graph found! */
2391                                         break;
2392                         }
2393                         if (k == a->item_list_sz) {
2394                                 /* Graph not found: Look for first free entry */
2395                                 for (k = 0; k < a->item_list_sz; k++) {
2396                                         item_name = *(out + k * 9 + 8);
2397                                         if (!strcmp(item_name, ""))
2398                                                 break;
2399                                 }
2400                                 if (k == a->item_list_sz) {
2401                                         /* No free graph entry: Ignore it (should never happen) */
2402 #ifdef DEBUG
2403                                         fprintf(stderr, "%s: Name=%s\n",
2404                                                 __FUNCTION__, sndc->interface);
2405 #endif
2406                                         continue;
2407                                 }
2408                         }
2409                         pos = k * 9;
2410                         unregistered = outsize + pos + 8;
2411
2412                         j = check_net_dev_reg(a, curr, !curr, i);
2413                         if (j < 0) {
2414                                 /* This is a newly registered interface. Previous stats are zero */
2415                                 sndp = &sndzero;
2416                         }
2417                         else {
2418                                 sndp = (struct stats_net_dev *) ((char *) a->buf[!curr] + j * a->msize);
2419                         }
2420
2421                         /*
2422                          * If current interface was marked as previously unregistered,
2423                          * then set restart variable to TRUE so that the graph will be
2424                          * discontinuous, and mark it as now registered.
2425                          */
2426                         if (*unregistered == TRUE) {
2427                                 restart = TRUE;
2428                         }
2429                         *unregistered = FALSE;
2430
2431                         item_name = *(out + pos + 8);
2432                         if (!item_name[0]) {
2433                                 /* Save network interface name (if not already done) */
2434                                 strncpy(item_name, sndc->interface, CHUNKSIZE);
2435                                 item_name[CHUNKSIZE - 1] = '\0';
2436                         }
2437
2438                         /* Check for min/max values */
2439                         save_extrema(local_types_nr, (void *) sndc, (void *) sndp,
2440                                      itv, spmin + pos, spmax + pos, g_fields);
2441
2442                         rxkb = S_VALUE(sndp->rx_bytes, sndc->rx_bytes, itv);
2443                         txkb = S_VALUE(sndp->tx_bytes, sndc->tx_bytes, itv);
2444                         ifutil = compute_ifutil(sndc, rxkb, txkb);
2445                         if (ifutil < *(spmin + pos + 7)) {
2446                                 *(spmin + pos + 7) = ifutil;
2447                         }
2448                         if (ifutil > *(spmax + pos + 7)) {
2449                                 *(spmax + pos + 7) = ifutil;
2450                         }
2451
2452                         /* rxpck/s */
2453                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2454                                  S_VALUE(sndp->rx_packets, sndc->rx_packets, itv),
2455                                  out + pos, outsize + pos, restart);
2456                         /* txpck/s */
2457                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2458                                  S_VALUE(sndp->tx_packets, sndc->tx_packets, itv),
2459                                  out + pos + 1, outsize + pos + 1, restart);
2460                         /* rxkB/s */
2461                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2462                                  rxkb / 1024,
2463                                  out + pos + 2, outsize + pos + 2, restart);
2464                         /* txkB/s */
2465                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2466                                  txkb / 1024,
2467                                  out + pos + 3, outsize + pos + 3, restart);
2468                         /* rxcmp/s */
2469                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2470                                  S_VALUE(sndp->rx_compressed, sndc->rx_compressed, itv),
2471                                  out + pos + 4, outsize + pos + 4, restart);
2472                         /* txcmp/s */
2473                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2474                                  S_VALUE(sndp->tx_compressed, sndc->tx_compressed, itv),
2475                                  out + pos + 5, outsize + pos + 5, restart);
2476                         /* rxmcst/s */
2477                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2478                                  S_VALUE(sndp->multicast, sndc->multicast, itv),
2479                                  out + pos + 6, outsize + pos + 6, restart);
2480                         /* %ifutil */
2481                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
2482                                  0.0, ifutil,
2483                                  out + pos + 7, outsize + pos + 7, svg_p->dt);
2484                 }
2485
2486                 /* Mark interfaces not seen here as now unregistered */
2487                 for (k = 0; k < a->item_list_sz; k++) {
2488                         unregistered = outsize + k * 9 + 8;
2489                         if (*unregistered != FALSE) {
2490                                 *unregistered = TRUE;
2491                         }
2492                 }
2493         }
2494
2495         if (action & F_END) {
2496                 int xid = 0;
2497
2498                 for (i = 0; i < a->item_list_sz; i++) {
2499                         /*
2500                          * Check if there is something to display.
2501                          * Don't test sndc->interface because maybe the network
2502                          * interface has been registered later.
2503                          */
2504                         pos = i * 9;
2505                         if (!**(out + pos))
2506                                 continue;
2507
2508                         /* Recalculate min and max values in kB, not in B */
2509                         *(spmin + pos + 2) /= 1024;
2510                         *(spmax + pos + 2) /= 1024;
2511                         *(spmin + pos + 3) /= 1024;
2512                         *(spmax + pos + 3) /= 1024;
2513
2514                         item_name = *(out + pos + 8);
2515                         if (draw_activity_graphs(a->g_nr, g_type,
2516                                                  title, g_title, item_name, group,
2517                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2518                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
2519                                 xid++;
2520                         }
2521                 }
2522
2523                 /* Free remaining structures */
2524                 free_graphs(out, outsize, spmin, spmax);
2525         }
2526 }
2527
2528 /*
2529  ***************************************************************************
2530  * Display network interfaces errors statistics in SVG.
2531  *
2532  * IN:
2533  * @a           Activity structure with statistics.
2534  * @curr        Index in array for current sample statistics.
2535  * @action      Action expected from current function.
2536  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2537  *              flag indicating that a restart record has been previously
2538  *              found (.@restart) and time used for the X axis origin
2539  *              (@ust_time_ref).
2540  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2541  * @record_hdr  Pointer on record header of current stats sample.
2542  ***************************************************************************
2543  */
2544 __print_funct_t svg_print_net_edev_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2545                                          unsigned long long itv, struct record_header *record_hdr)
2546 {
2547         struct stats_net_edev *snedc, *snedp, snedzero;
2548         int group[] = {2, 2, 2, 3};
2549         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2550                         SVG_LINE_GRAPH};
2551         char *title[] = {"Network interfaces errors statistics (1)", "Network interfaces errors statistics (2)",
2552                          "Network interfaces errors statistics (3)", "Network interfaces errors statistics (4)"};
2553         char *g_title[] = {"rxerr/s", "txerr/s",
2554                             "rxdrop/s", "txdrop/s",
2555                             "rxfifo/s", "txfifo/s",
2556                             "coll/s", "txcarr/s", "rxfram/s"};
2557         int g_fields[] = {6, 0, 1, 2, 3, 4, 5, 8, 7};
2558         static double *spmin, *spmax;
2559         static char **out;
2560         static int *outsize;
2561         char *item_name;
2562         int i, j, k, pos, restart, *unregistered;
2563
2564         if (action & F_BEGIN) {
2565                 /*
2566                  * Allocate arrays (#0..8) that will contain the graphs data
2567                  * and the min/max values.
2568                  * Also allocate one additional array (#9) for each interface:
2569                  * out + 9 will contain the interface name,
2570                  * outsize + 9 will contain a positive value (TRUE) if the interface
2571                  * has either still not been registered, or has been unregistered.
2572                  */
2573                 out = allocate_graph_lines(10 * a->item_list_sz, &outsize, &spmin, &spmax);
2574         }
2575
2576         if (action & F_MAIN) {
2577                 memset(&snedzero, 0, STATS_NET_EDEV_SIZE);
2578                 restart = svg_p->restart;
2579                 /*
2580                  * Mark previously registered interfaces as now
2581                  * possibly unregistered for all graphs.
2582                  */
2583                 for (k = 0; k < a->item_list_sz; k++) {
2584                         unregistered = outsize + k * 10 + 9;
2585                         if (*unregistered == FALSE) {
2586                                 *unregistered = MAYBE;
2587                         }
2588                 }
2589
2590                 /* For each network interfaces structure */
2591                 for (i = 0; i < a->nr[curr]; i++) {
2592                         snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + i * a->msize);
2593                         if (!strcmp(snedc->interface, ""))
2594                                 /* Empty structure: This is the end of the list */
2595                                 break;
2596
2597                         if (a->item_list != NULL) {
2598                                 /* A list of devices has been entered on the command line */
2599                                 if (!search_list_item(a->item_list, snedc->interface))
2600                                         /* Device not found */
2601                                         continue;
2602                         }
2603
2604                         /* Look for corresponding graph */
2605                         for (k = 0; k < a->item_list_sz; k++) {
2606                                 item_name = *(out + k * 10 + 9);
2607                                 if (!strcmp(snedc->interface, item_name))
2608                                         /* Graph found! */
2609                                         break;
2610                         }
2611                         if (k == a->item_list_sz) {
2612                                 /* Graph not found: Look for first free entry */
2613                                 for (k = 0; k < a->item_list_sz; k++) {
2614                                         item_name = *(out + k * 10 + 9);
2615                                         if (!strcmp(item_name, ""))
2616                                                 break;
2617                                 }
2618                                 if (k == a->item_list_sz) {
2619                                         /* No free graph entry: Ignore it (should never happen) */
2620 #ifdef DEBUG
2621                                         fprintf(stderr, "%s: Name=%s\n",
2622                                                 __FUNCTION__, snedc->interface);
2623 #endif
2624                                         continue;
2625                                 }
2626                         }
2627
2628                         pos = k * 10;
2629                         unregistered = outsize + pos + 9;
2630
2631                         j = check_net_edev_reg(a, curr, !curr, i);
2632                         if (j < 0) {
2633                                 /* This is a newly registered interface. Previous stats are zero */
2634                                 snedp = &snedzero;
2635                         }
2636                         else {
2637                                 snedp = (struct stats_net_edev *) ((char *) a->buf[!curr] + j * a->msize);
2638                         }
2639
2640                         /*
2641                          * If current interface was marked as previously unregistered,
2642                          * then set restart variable to TRUE so that the graph will be
2643                          * discontinuous, and mark it as now registered.
2644                          */
2645                         if (*unregistered == TRUE) {
2646                                 restart = TRUE;
2647                         }
2648                         *unregistered = FALSE;
2649
2650                         item_name = *(out + pos + 9);
2651                         if (!item_name[0]) {
2652                                 /* Save network interface name (if not already done) */
2653                                 strncpy(item_name, snedc->interface, CHUNKSIZE);
2654                                 item_name[CHUNKSIZE - 1] = '\0';
2655                         }
2656
2657                         /* Check for min/max values */
2658                         save_extrema(a->gtypes_nr, (void *) snedc, (void *) snedp,
2659                                      itv, spmin + pos, spmax + pos, g_fields);
2660
2661                         /* rxerr/s */
2662                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2663                                  S_VALUE(snedp->rx_errors, snedc->rx_errors, itv),
2664                                  out + pos, outsize + pos, restart);
2665                         /* txerr/s */
2666                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2667                                  S_VALUE(snedp->tx_errors, snedc->tx_errors, itv),
2668                                  out + pos + 1, outsize + pos + 1, restart);
2669                         /* rxdrop/s */
2670                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2671                                  S_VALUE(snedp->rx_dropped, snedc->rx_dropped, itv),
2672                                  out + pos + 2, outsize + pos + 2, restart);
2673                         /* txdrop/s */
2674                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2675                                  S_VALUE(snedp->tx_dropped, snedc->tx_dropped, itv),
2676                                  out + pos + 3, outsize + pos + 3, restart);
2677                         /* rxfifo/s */
2678                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2679                                  S_VALUE(snedp->rx_fifo_errors, snedc->rx_fifo_errors, itv),
2680                                  out + pos + 4, outsize + pos + 4, restart);
2681                         /* txfifo/s */
2682                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2683                                  S_VALUE(snedp->tx_fifo_errors, snedc->tx_fifo_errors, itv),
2684                                  out + pos + 5, outsize + pos + 5, restart);
2685                         /* coll/s */
2686                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2687                                  S_VALUE(snedp->collisions, snedc->collisions, itv),
2688                                  out + pos + 6, outsize + pos + 6, restart);
2689                         /* txcarr/s */
2690                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2691                                  S_VALUE(snedp->tx_carrier_errors, snedc->tx_carrier_errors, itv),
2692                                  out + pos + 7, outsize + pos + 7, restart);
2693                         /* rxfram/s */
2694                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2695                                  S_VALUE(snedp->rx_frame_errors, snedc->rx_frame_errors, itv),
2696                                  out + pos + 8, outsize + pos + 8, restart);
2697                 }
2698
2699                 /* Mark interfaces not seen here as now unregistered */
2700                 for (k = 0; k < a->item_list_sz; k++) {
2701                         unregistered = outsize + k * 10 + 9;
2702                         if (*unregistered != FALSE) {
2703                                 *unregistered = TRUE;
2704                         }
2705                 }
2706         }
2707
2708         if (action & F_END) {
2709                 int xid = 0;
2710
2711                 for (i = 0; i < a->item_list_sz; i++) {
2712                         /*
2713                          * Check if there is something to display.
2714                          * Don't test snedc->interface because maybe the network
2715                          * interface has been registered later.
2716                          */
2717                         pos = i * 10;
2718                         if (!**(out + pos))
2719                                 continue;
2720
2721                         item_name = *(out + pos + 9);
2722                         if (draw_activity_graphs(a->g_nr, g_type,
2723                                                  title, g_title, item_name, group,
2724                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
2725                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
2726                                 xid++;
2727                         }
2728                 }
2729
2730                 /* Free remaining structures */
2731                 free_graphs(out, outsize, spmin, spmax);
2732         }
2733 }
2734
2735 /*
2736  ***************************************************************************
2737  * Display NFS client statistics in SVG.
2738  *
2739  * IN:
2740  * @a           Activity structure with statistics.
2741  * @curr        Index in array for current sample statistics.
2742  * @action      Action expected from current function.
2743  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2744  *              flag indicating that a restart record has been previously
2745  *              found (.@restart) and time used for the X axis origin
2746  *              (@ust_time_ref).
2747  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2748  * @record_hdr  Pointer on record header of current stats sample.
2749  ***************************************************************************
2750  */
2751 __print_funct_t svg_print_net_nfs_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2752                                         unsigned long long itv, struct record_header *record_hdr)
2753 {
2754         struct stats_net_nfs
2755                 *snnc = (struct stats_net_nfs *) a->buf[curr],
2756                 *snnp = (struct stats_net_nfs *) a->buf[!curr];
2757         int group[] = {2, 2, 2};
2758         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2759         char *title[] = {"NFS client statistics (1)", "NFS client statistics (2)",
2760                          "NFS client statistics (3)"};
2761         char *g_title[] = {"call/s", "retrans/s",
2762                            "read/s", "write/s",
2763                            "access/s", "getatt/s"};
2764         int g_fields[] = {0, 1, 2, 3, 4, 5};
2765         static double *spmin, *spmax;
2766         static char **out;
2767         static int *outsize;
2768
2769         if (action & F_BEGIN) {
2770                 /*
2771                  * Allocate arrays that will contain the graphs data
2772                  * and the min/max values.
2773                  */
2774                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
2775         }
2776
2777         if (action & F_MAIN) {
2778                 /* Check for min/max values */
2779                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
2780                              itv, spmin, spmax, g_fields);
2781
2782                 /* call/s */
2783                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2784                          S_VALUE(snnp->nfs_rpccnt, snnc->nfs_rpccnt, itv),
2785                          out, outsize, svg_p->restart);
2786                 /* retrans/s */
2787                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2788                          S_VALUE(snnp->nfs_rpcretrans, snnc->nfs_rpcretrans, itv),
2789                          out + 1, outsize + 1, svg_p->restart);
2790                 /* read/s */
2791                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2792                          S_VALUE(snnp->nfs_readcnt, snnc->nfs_readcnt, itv),
2793                          out + 2, outsize + 2, svg_p->restart);
2794                 /* write/s */
2795                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2796                          S_VALUE(snnp->nfs_writecnt, snnc->nfs_writecnt, itv),
2797                          out + 3, outsize + 3, svg_p->restart);
2798                 /* access/s */
2799                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2800                          S_VALUE(snnp->nfs_accesscnt, snnc->nfs_accesscnt, itv),
2801                          out + 4, outsize + 4, svg_p->restart);
2802                 /* getatt/s */
2803                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2804                          S_VALUE(snnp->nfs_getattcnt, snnc->nfs_getattcnt, itv),
2805                          out + 5, outsize + 5, svg_p->restart);
2806         }
2807
2808         if (action & F_END) {
2809                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2810                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
2811
2812                 /* Free remaining structures */
2813                 free_graphs(out, outsize, spmin, spmax);
2814         }
2815 }
2816
2817 /*
2818  ***************************************************************************
2819  * Display NFS server statistics in SVG.
2820  *
2821  * IN:
2822  * @a           Activity structure with statistics.
2823  * @curr        Index in array for current sample statistics.
2824  * @action      Action expected from current function.
2825  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2826  *              flag indicating that a restart record has been previously
2827  *              found (.@restart) and time used for the X axis origin
2828  *              (@ust_time_ref).
2829  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2830  * @record_hdr  Pointer on record header of current stats sample.
2831  ***************************************************************************
2832  */
2833 __print_funct_t svg_print_net_nfsd_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2834                                          unsigned long long itv, struct record_header *record_hdr)
2835 {
2836         struct stats_net_nfsd
2837                 *snndc = (struct stats_net_nfsd *) a->buf[curr],
2838                 *snndp = (struct stats_net_nfsd *) a->buf[!curr];
2839         int group[] = {2, 3, 2, 2, 2};
2840         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
2841                         SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2842         char *title[] = {"NFS server statistics (1)", "NFS server statistics (2)",
2843                          "NFS server statistics (3)", "NFS server statistics (4)",
2844                          "NFS server statistics (5)"};
2845         char *g_title[] = {"scall/s", "badcall/s",
2846                            "packet/s", "udp/s", "tcp/s",
2847                            "hit/s", "miss/s",
2848                            "sread/s", "swrite/s",
2849                            "saccess/s", "sgetatt/s"};
2850         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
2851         static double *spmin, *spmax;
2852         static char **out;
2853         static int *outsize;
2854
2855         if (action & F_BEGIN) {
2856                 /*
2857                  * Allocate arrays that will contain the graphs data
2858                  * and the min/max values.
2859                  */
2860                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
2861         }
2862
2863         if (action & F_MAIN) {
2864                 /* Check for min/max values */
2865                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
2866                              itv, spmin, spmax, g_fields);
2867
2868                 /* scall/s */
2869                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2870                          S_VALUE(snndp->nfsd_rpccnt, snndc->nfsd_rpccnt, itv),
2871                          out, outsize, svg_p->restart);
2872                 /* badcall/s */
2873                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2874                          S_VALUE(snndp->nfsd_rpcbad, snndc->nfsd_rpcbad, itv),
2875                          out + 1, outsize + 1, svg_p->restart);
2876                 /* packet/s */
2877                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2878                          S_VALUE(snndp->nfsd_netcnt, snndc->nfsd_netcnt, itv),
2879                          out + 2, outsize + 2, svg_p->restart);
2880                 /* udp/s */
2881                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2882                          S_VALUE(snndp->nfsd_netudpcnt, snndc->nfsd_netudpcnt, itv),
2883                          out + 3, outsize + 3, svg_p->restart);
2884                 /* tcp/s */
2885                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2886                          S_VALUE(snndp->nfsd_nettcpcnt, snndc->nfsd_nettcpcnt, itv),
2887                          out + 4, outsize + 4, svg_p->restart);
2888                 /* hit/s */
2889                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2890                          S_VALUE(snndp->nfsd_rchits, snndc->nfsd_rchits, itv),
2891                          out + 5, outsize + 5, svg_p->restart);
2892                 /* miss/s */
2893                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2894                          S_VALUE(snndp->nfsd_rcmisses, snndc->nfsd_rcmisses, itv),
2895                          out + 6, outsize + 6, svg_p->restart);
2896                 /* sread/s */
2897                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2898                          S_VALUE(snndp->nfsd_readcnt, snndc->nfsd_readcnt, itv),
2899                          out + 7, outsize + 7, svg_p->restart);
2900                 /* swrite/s */
2901                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2902                          S_VALUE(snndp->nfsd_writecnt, snndc->nfsd_writecnt, itv),
2903                          out + 8, outsize + 8, svg_p->restart);
2904                 /* saccess/s */
2905                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2906                          S_VALUE(snndp->nfsd_accesscnt, snndc->nfsd_accesscnt, itv),
2907                          out + 9, outsize + 9, svg_p->restart);
2908                 /* sgetatt/s */
2909                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2910                          S_VALUE(snndp->nfsd_getattcnt, snndc->nfsd_getattcnt, itv),
2911                          out + 10, outsize + 10, svg_p->restart);
2912         }
2913
2914         if (action & F_END) {
2915                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2916                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
2917
2918                 /* Free remaining structures */
2919                 free_graphs(out, outsize, spmin, spmax);
2920         }
2921 }
2922
2923 /*
2924  ***************************************************************************
2925  * Display socket statistics in SVG.
2926  *
2927  * IN:
2928  * @a           Activity structure with statistics.
2929  * @curr        Index in array for current sample statistics.
2930  * @action      Action expected from current function.
2931  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
2932  *              flag indicating that a restart record has been previously
2933  *              found (.@restart) and time used for the X axis origin
2934  *              (@ust_time_ref).
2935  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
2936  * @record_hdr  Pointer on record header of current stats sample.
2937  ***************************************************************************
2938  */
2939 __print_funct_t svg_print_net_sock_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2940                                          unsigned long long itv, struct record_header *record_hdr)
2941 {
2942         struct stats_net_sock
2943                 *snsc = (struct stats_net_sock *) a->buf[curr];
2944         int group[] = {1, 5};
2945         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
2946         char *title[] = {"IPv4 sockets statistics (1)", "IPv4 sockets statistics (2)"};
2947         char *g_title[] = {"~totsck",
2948                            "~tcpsck", "~udpsck", "~rawsck", "~ip-frag", "~tcp-tw"};
2949         int g_fields[] = {0, 1, 5, 2, 3, 4};
2950         static double *spmin, *spmax;
2951         static char **out;
2952         static int *outsize;
2953
2954         if (action & F_BEGIN) {
2955                 /*
2956                  * Allocate arrays that will contain the graphs data
2957                  * and the min/max values.
2958                  */
2959                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
2960         }
2961
2962         if (action & F_MAIN) {
2963                 /* Check for min/max values */
2964                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
2965                              itv, spmin, spmax, g_fields);
2966                 /* totsck */
2967                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2968                           (unsigned long long) snsc->sock_inuse,
2969                           out, outsize, svg_p->restart);
2970                 /* tcpsck */
2971                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2972                           (unsigned long long) snsc->tcp_inuse,
2973                           out + 1, outsize + 1, svg_p->restart);
2974                 /* udpsck */
2975                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2976                           (unsigned long long) snsc->udp_inuse,
2977                           out + 2, outsize + 2, svg_p->restart);
2978                 /* rawsck */
2979                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2980                           (unsigned long long) snsc->raw_inuse,
2981                           out + 3, outsize + 3, svg_p->restart);
2982                 /* ip-frag */
2983                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2984                           (unsigned long long) snsc->frag_inuse,
2985                           out + 4, outsize + 4, svg_p->restart);
2986                 /* tcp-tw */
2987                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2988                           (unsigned long long) snsc->tcp_tw,
2989                           out + 5, outsize + 5, svg_p->restart);
2990         }
2991
2992         if (action & F_END) {
2993                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
2994                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
2995
2996                 /* Free remaining structures */
2997                 free_graphs(out, outsize, spmin, spmax);
2998         }
2999 }
3000
3001 /*
3002  ***************************************************************************
3003  * Display IPv4 traffic statistics in SVG.
3004  *
3005  * IN:
3006  * @a           Activity structure with statistics.
3007  * @curr        Index in array for current sample statistics.
3008  * @action      Action expected from current function.
3009  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3010  *              flag indicating that a restart record has been previously
3011  *              found (.@restart) and time used for the X axis origin
3012  *              (@ust_time_ref).
3013  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3014  * @record_hdr  Pointer on record header of current stats sample.
3015  ***************************************************************************
3016  */
3017 __print_funct_t svg_print_net_ip_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3018                                        unsigned long long itv, struct record_header *record_hdr)
3019 {
3020         struct stats_net_ip
3021                 *snic = (struct stats_net_ip *) a->buf[curr],
3022                 *snip = (struct stats_net_ip *) a->buf[!curr];
3023         int group[] = {4, 2, 2};
3024         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3025         char *title[] = {"IPv4 traffic statistics (1)", "IPv4 traffic statistics (2)", "IPv4 traffic statistics (3)"};
3026         char *g_title[] = {"irec/s", "fwddgm/s", "idel/s", "orq/s",
3027                            "asmrq/s", "asmok/s",
3028                            "fragok/s", "fragcrt/s"};
3029         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7};
3030         static double *spmin, *spmax;
3031         static char **out;
3032         static int *outsize;
3033
3034         if (action & F_BEGIN) {
3035                 /*
3036                  * Allocate arrays that will contain the graphs data
3037                  * and the min/max values.
3038                  */
3039                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
3040         }
3041
3042         if (action & F_MAIN) {
3043                 /* Check for min/max values */
3044                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3045                              itv, spmin, spmax, g_fields);
3046
3047                 /* irec/s */
3048                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3049                          S_VALUE(snip->InReceives, snic->InReceives, itv),
3050                          out, outsize, svg_p->restart);
3051                 /* fwddgm/s */
3052                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3053                          S_VALUE(snip->ForwDatagrams, snic->ForwDatagrams, itv),
3054                          out + 1, outsize + 1, svg_p->restart);
3055                 /* idel/s */
3056                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3057                          S_VALUE(snip->InDelivers, snic->InDelivers, itv),
3058                          out + 2, outsize + 2, svg_p->restart);
3059                 /* orq/s */
3060                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3061                          S_VALUE(snip->OutRequests, snic->OutRequests, itv),
3062                          out + 3, outsize + 3, svg_p->restart);
3063                 /* asmrq/s */
3064                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3065                          S_VALUE(snip->ReasmReqds, snic->ReasmReqds, itv),
3066                          out + 4, outsize + 4, svg_p->restart);
3067                 /* asmok/s */
3068                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3069                          S_VALUE(snip->ReasmOKs, snic->ReasmOKs, itv),
3070                          out + 5, outsize + 5, svg_p->restart);
3071                 /* fragok/s */
3072                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3073                          S_VALUE(snip->FragOKs, snic->FragOKs, itv),
3074                          out + 6, outsize + 6, svg_p->restart);
3075                 /* fragcrt/s */
3076                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3077                          S_VALUE(snip->FragCreates, snic->FragCreates, itv),
3078                          out + 7, outsize + 7, svg_p->restart);
3079         }
3080
3081         if (action & F_END) {
3082                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3083                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3084
3085                 /* Free remaining structures */
3086                 free_graphs(out, outsize, spmin, spmax);
3087         }
3088 }
3089
3090 /*
3091  ***************************************************************************
3092  * Display IPv4 traffic errors statistics in SVG.
3093  *
3094  * IN:
3095  * @a           Activity structure with statistics.
3096  * @curr        Index in array for current sample statistics.
3097  * @action      Action expected from current function.
3098  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3099  *              flag indicating that a restart record has been previously
3100  *              found (.@restart) and time used for the X axis origin
3101  *              (@ust_time_ref).
3102  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3103  * @record_hdr  Pointer on record header of current stats sample.
3104  ***************************************************************************
3105  */
3106 __print_funct_t svg_print_net_eip_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3107                                         unsigned long long itv, struct record_header *record_hdr)
3108 {
3109         struct stats_net_eip
3110                 *sneic = (struct stats_net_eip *) a->buf[curr],
3111                 *sneip = (struct stats_net_eip *) a->buf[!curr];
3112         int group[] = {3, 2, 3};
3113         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3114         char *title[] = {"IPv4 traffic errors statistics (1)", "IPv4 traffic errors statistics (2)",
3115                          "IPv4 traffic errors statistics (3)"};
3116         char *g_title[] = {"ihdrerr/s", "iadrerr/s", "iukwnpr/s",
3117                            "idisc/s", "odisc/s",
3118                            "onort/s", "asmf/s", "fragf/s"};
3119         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7};
3120         static double *spmin, *spmax;
3121         static char **out;
3122         static int *outsize;
3123
3124         if (action & F_BEGIN) {
3125                 /*
3126                  * Allocate arrays that will contain the graphs data
3127                  * and the min/max values.
3128                  */
3129                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
3130         }
3131
3132         if (action & F_MAIN) {
3133                 /* Check for min/max values */
3134                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3135                              itv, spmin, spmax, g_fields);
3136
3137                 /* ihdrerr/s */
3138                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3139                          S_VALUE(sneip->InHdrErrors, sneic->InHdrErrors, itv),
3140                          out, outsize, svg_p->restart);
3141                 /* iadrerr/s */
3142                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3143                          S_VALUE(sneip->InAddrErrors, sneic->InAddrErrors, itv),
3144                          out + 1, outsize + 1, svg_p->restart);
3145                 /* iukwnpr/s */
3146                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3147                          S_VALUE(sneip->InUnknownProtos, sneic->InUnknownProtos, itv),
3148                          out + 2, outsize + 2, svg_p->restart);
3149                 /* idisc/s */
3150                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3151                          S_VALUE(sneip->InDiscards, sneic->InDiscards, itv),
3152                          out + 3, outsize + 3, svg_p->restart);
3153                 /* odisc/s */
3154                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3155                          S_VALUE(sneip->OutDiscards, sneic->OutDiscards, itv),
3156                          out + 4, outsize + 4, svg_p->restart);
3157                 /* onort/s */
3158                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3159                          S_VALUE(sneip->OutNoRoutes, sneic->OutNoRoutes, itv),
3160                          out + 5, outsize + 5, svg_p->restart);
3161                 /* asmf/s */
3162                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3163                          S_VALUE(sneip->ReasmFails, sneic->ReasmFails, itv),
3164                          out + 6, outsize + 6, svg_p->restart);
3165                 /* fragf/s */
3166                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3167                          S_VALUE(sneip->FragFails, sneic->FragFails, itv),
3168                          out + 7, outsize + 7, svg_p->restart);
3169         }
3170
3171         if (action & F_END) {
3172                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3173                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3174
3175                 /* Free remaining structures */
3176                 free_graphs(out, outsize, spmin, spmax);
3177         }
3178 }
3179
3180 /*
3181  ***************************************************************************
3182  * Display ICMPv4 traffic statistics in SVG.
3183  *
3184  * IN:
3185  * @a           Activity structure with statistics.
3186  * @curr        Index in array for current sample statistics.
3187  * @action      Action expected from current function.
3188  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3189  *              flag indicating that a restart record has been previously
3190  *              found (.@restart) and time used for the X axis origin
3191  *              (@ust_time_ref).
3192  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3193  * @record_hdr  Pointer on record header of current stats sample.
3194  ***************************************************************************
3195  */
3196 __print_funct_t svg_print_net_icmp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3197                                          unsigned long long itv, struct record_header *record_hdr)
3198 {
3199         struct stats_net_icmp
3200                 *snic = (struct stats_net_icmp *) a->buf[curr],
3201                 *snip = (struct stats_net_icmp *) a->buf[!curr];
3202         int group[] = {2, 4, 4, 4};
3203         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3204                         SVG_LINE_GRAPH};
3205         char *title[] = {"ICMPv4 traffic statistics (1)", "ICMPv4 traffic statistics (2)",
3206                          "ICMPv4 traffic statistics (3)", "ICMPv4 traffic statistics (4)"};
3207         char *g_title[] = {"imsg/s", "omsg/s",
3208                            "iech/s", "iechr/s", "oech/s", "oechr/s",
3209                            "itm/s", "itmr/s", "otm/s", "otmr/s",
3210                            "iadrmk/s", "iadrmkr/s", "oadrmk/s", "oadrmkr/s"};
3211         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
3212         static double *spmin, *spmax;
3213         static char **out;
3214         static int *outsize;
3215
3216         if (action & F_BEGIN) {
3217                 /*
3218                  * Allocate arrays that will contain the graphs data
3219                  * and the min/max values.
3220                  */
3221                 out = allocate_graph_lines(14, &outsize, &spmin, &spmax);
3222         }
3223
3224         if (action & F_MAIN) {
3225                 /* Check for min/max values */
3226                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3227                              itv, spmin, spmax, g_fields);
3228
3229                 /* imsg/s */
3230                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3231                          S_VALUE(snip->InMsgs, snic->InMsgs, itv),
3232                          out, outsize, svg_p->restart);
3233                 /* omsg/s */
3234                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3235                          S_VALUE(snip->OutMsgs, snic->OutMsgs, itv),
3236                          out + 1, outsize + 1, svg_p->restart);
3237                 /* iech/s */
3238                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3239                          S_VALUE(snip->InEchos, snic->InEchos, itv),
3240                          out + 2, outsize + 2, svg_p->restart);
3241                 /* iechr/s */
3242                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3243                          S_VALUE(snip->InEchoReps, snic->InEchoReps, itv),
3244                          out + 3, outsize + 3, svg_p->restart);
3245                 /* oech/s */
3246                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3247                          S_VALUE(snip->OutEchos, snic->OutEchos, itv),
3248                          out + 4, outsize + 4, svg_p->restart);
3249                 /* oechr/s */
3250                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3251                          S_VALUE(snip->OutEchoReps, snic->OutEchoReps, itv),
3252                          out + 5, outsize + 5, svg_p->restart);
3253                 /* itm/s */
3254                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3255                          S_VALUE(snip->InTimestamps, snic->InTimestamps, itv),
3256                          out + 6, outsize + 6, svg_p->restart);
3257                 /* itmr/s */
3258                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3259                          S_VALUE(snip->InTimestampReps, snic->InTimestampReps, itv),
3260                          out + 7, outsize + 7, svg_p->restart);
3261                 /* otm/s */
3262                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3263                          S_VALUE(snip->OutTimestamps, snic->OutTimestamps, itv),
3264                          out + 8, outsize + 8, svg_p->restart);
3265                 /* otmr/s */
3266                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3267                          S_VALUE(snip->OutTimestampReps, snic->OutTimestampReps, itv),
3268                          out + 9, outsize + 9, svg_p->restart);
3269                 /* iadrmk/s */
3270                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3271                          S_VALUE(snip->InAddrMasks, snic->InAddrMasks, itv),
3272                          out + 10, outsize + 10, svg_p->restart);
3273                 /* iadrmkr/s */
3274                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3275                          S_VALUE(snip->InAddrMaskReps, snic->InAddrMaskReps, itv),
3276                          out + 11, outsize + 11, svg_p->restart);
3277                 /* oadrmk/s */
3278                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3279                          S_VALUE(snip->OutAddrMasks, snic->OutAddrMasks, itv),
3280                          out + 12, outsize + 12, svg_p->restart);
3281                 /* oadrmkr/s */
3282                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3283                          S_VALUE(snip->OutAddrMaskReps, snic->OutAddrMaskReps, itv),
3284                          out + 13, outsize + 13, svg_p->restart);
3285         }
3286
3287         if (action & F_END) {
3288                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3289                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3290
3291                 /* Free remaining structures */
3292                 free_graphs(out, outsize, spmin, spmax);
3293         }
3294 }
3295
3296 /*
3297  ***************************************************************************
3298  * Display ICMPv4 traffic errors statistics in SVG.
3299  *
3300  * IN:
3301  * @a           Activity structure with statistics.
3302  * @curr        Index in array for current sample statistics.
3303  * @action      Action expected from current function.
3304  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3305  *              flag indicating that a restart record has been previously
3306  *              found (.@restart) and time used for the X axis origin
3307  *              (@ust_time_ref).
3308  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3309  * @record_hdr  Pointer on record header of current stats sample.
3310  ***************************************************************************
3311  */
3312 __print_funct_t svg_print_net_eicmp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3313                                           unsigned long long itv, struct record_header *record_hdr)
3314 {
3315         struct stats_net_eicmp
3316                 *sneic = (struct stats_net_eicmp *) a->buf[curr],
3317                 *sneip = (struct stats_net_eicmp *) a->buf[!curr];
3318         int group[] = {2, 2, 2, 2, 2, 2};
3319         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3320                         SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3321         char *title[] = {"ICMPv4 traffic errors statistics (1)", "ICMPv4 traffic errors statistics (2)",
3322                          "ICMPv4 traffic errors statistics (3)", "ICMPv4 traffic errors statistics (4)",
3323                          "ICMPv4 traffic errors statistics (5)", "ICMPv4 traffic errors statistics (6)"};
3324         char *g_title[] = {"ierr/s", "oerr/s",
3325                            "idstunr/s", "odstunr/s",
3326                            "itmex/s", "otmex/s",
3327                            "iparmpb/s", "oparmpb/s",
3328                            "isrcq/s", "osrcq/s",
3329                            "iredir/s", "oredir/s"};
3330         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
3331         static double *spmin, *spmax;
3332         static char **out;
3333         static int *outsize;
3334
3335         if (action & F_BEGIN) {
3336                 /*
3337                  * Allocate arrays that will contain the graphs data
3338                  * and the min/max values.
3339                  */
3340                 out = allocate_graph_lines(12, &outsize, &spmin, &spmax);
3341         }
3342
3343         if (action & F_MAIN) {
3344                 /* Check for min/max values */
3345                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3346                              itv, spmin, spmax, g_fields);
3347
3348                 /* ierr/s */
3349                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3350                          S_VALUE(sneip->InErrors, sneic->InErrors, itv),
3351                          out, outsize, svg_p->restart);
3352                 /* oerr/s */
3353                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3354                          S_VALUE(sneip->OutErrors, sneic->OutErrors, itv),
3355                          out + 1, outsize + 1, svg_p->restart);
3356                 /* idstunr/s */
3357                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3358                          S_VALUE(sneip->InDestUnreachs, sneic->InDestUnreachs, itv),
3359                          out + 2, outsize + 2, svg_p->restart);
3360                 /* odstunr/s */
3361                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3362                          S_VALUE(sneip->OutDestUnreachs, sneic->OutDestUnreachs, itv),
3363                          out + 3, outsize + 3, svg_p->restart);
3364                 /* itmex/s */
3365                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3366                          S_VALUE(sneip->InTimeExcds, sneic->InTimeExcds, itv),
3367                          out + 4, outsize + 4, svg_p->restart);
3368                 /* otmex/s */
3369                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3370                          S_VALUE(sneip->OutTimeExcds, sneic->OutTimeExcds, itv),
3371                          out + 5, outsize + 5, svg_p->restart);
3372                 /* iparmpb/s */
3373                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3374                          S_VALUE(sneip->InParmProbs, sneic->InParmProbs, itv),
3375                          out + 6, outsize + 6, svg_p->restart);
3376                 /* oparmpb/s */
3377                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3378                          S_VALUE(sneip->OutParmProbs, sneic->OutParmProbs, itv),
3379                          out + 7, outsize + 7, svg_p->restart);
3380                 /* isrcq/s */
3381                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3382                          S_VALUE(sneip->InSrcQuenchs, sneic->InSrcQuenchs, itv),
3383                          out + 8, outsize + 8, svg_p->restart);
3384                 /* osrcq/s */
3385                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3386                          S_VALUE(sneip->OutSrcQuenchs, sneic->OutSrcQuenchs, itv),
3387                          out + 9, outsize + 9, svg_p->restart);
3388                 /* iredir/s */
3389                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3390                          S_VALUE(sneip->InRedirects, sneic->InRedirects, itv),
3391                          out + 10, outsize + 10, svg_p->restart);
3392                 /* oredir/s */
3393                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3394                          S_VALUE(sneip->OutRedirects, sneic->OutRedirects, itv),
3395                          out + 11, outsize + 11, svg_p->restart);
3396         }
3397
3398         if (action & F_END) {
3399                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3400                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3401
3402                 /* Free remaining structures */
3403                 free_graphs(out, outsize, spmin, spmax);
3404         }
3405 }
3406
3407 /*
3408  ***************************************************************************
3409  * Display TCPv4 traffic statistics in SVG.
3410  *
3411  * IN:
3412  * @a           Activity structure with statistics.
3413  * @curr        Index in array for current sample statistics.
3414  * @action      Action expected from current function.
3415  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3416  *              flag indicating that a restart record has been previously
3417  *              found (.@restart) and time used for the X axis origin
3418  *              (@ust_time_ref).
3419  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3420  * @record_hdr  Pointer on record header of current stats sample.
3421  ***************************************************************************
3422  */
3423 __print_funct_t svg_print_net_tcp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3424                                         unsigned long long itv, struct record_header *record_hdr)
3425 {
3426         struct stats_net_tcp
3427                 *sntc = (struct stats_net_tcp *) a->buf[curr],
3428                 *sntp = (struct stats_net_tcp *) a->buf[!curr];
3429         int group[] = {2, 2};
3430         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3431         char *title[] = {"TCPv4 traffic statistics (1)", "TCPv4 traffic statistics (2)"};
3432         char *g_title[] = {"active/s", "passive/s",
3433                            "iseg/s", "oseg/s"};
3434         int g_fields[] = {0, 1, 2, 3};
3435         static double *spmin, *spmax;
3436         static char **out;
3437         static int *outsize;
3438
3439         if (action & F_BEGIN) {
3440                 /*
3441                  * Allocate arrays that will contain the graphs data
3442                  * and the min/max values.
3443                  */
3444                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3445         }
3446
3447         if (action & F_MAIN) {
3448                 /* Check for min/max values */
3449                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3450                              itv, spmin, spmax, g_fields);
3451
3452                 /* active/s */
3453                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3454                          S_VALUE(sntp->ActiveOpens, sntc->ActiveOpens, itv),
3455                          out, outsize, svg_p->restart);
3456                 /* passive/s */
3457                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3458                          S_VALUE(sntp->PassiveOpens, sntc->PassiveOpens, itv),
3459                          out + 1, outsize + 1, svg_p->restart);
3460                 /* iseg/s */
3461                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3462                          S_VALUE(sntp->InSegs, sntc->InSegs, itv),
3463                          out + 2, outsize + 2, svg_p->restart);
3464                 /* oseg/s */
3465                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3466                          S_VALUE(sntp->OutSegs, sntc->OutSegs, itv),
3467                          out + 3, outsize + 3, svg_p->restart);
3468         }
3469
3470         if (action & F_END) {
3471                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3472                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3473
3474                 /* Free remaining structures */
3475                 free_graphs(out, outsize, spmin, spmax);
3476         }
3477 }
3478
3479 /*
3480  ***************************************************************************
3481  * Display TCPv4 traffic errors statistics in SVG.
3482  *
3483  * IN:
3484  * @a           Activity structure with statistics.
3485  * @curr        Index in array for current sample statistics.
3486  * @action      Action expected from current function.
3487  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3488  *              flag indicating that a restart record has been previously
3489  *              found (.@restart) and time used for the X axis origin
3490  *              (@ust_time_ref).
3491  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3492  * @record_hdr  Pointer on record header of current stats sample.
3493  ***************************************************************************
3494  */
3495 __print_funct_t svg_print_net_etcp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3496                                          unsigned long long itv, struct record_header *record_hdr)
3497 {
3498         struct stats_net_etcp
3499                 *snetc = (struct stats_net_etcp *) a->buf[curr],
3500                 *snetp = (struct stats_net_etcp *) a->buf[!curr];
3501         int group[] = {2, 3};
3502         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3503         char *title[] = {"TCPv4 traffic errors statistics (1)", "TCPv4 traffic errors statistics (2)"};
3504         char *g_title[] = {"atmptf/s", "estres/s",
3505                            "retrans/s", "isegerr/s", "orsts/s"};
3506         int g_fields[] = {0, 1, 2, 3, 4};
3507         static double *spmin, *spmax;
3508         static char **out;
3509         static int *outsize;
3510
3511         if (action & F_BEGIN) {
3512                 /*
3513                  * Allocate arrays that will contain the graphs data
3514                  * and the min/max values.
3515                  */
3516                 out = allocate_graph_lines(5, &outsize, &spmin, &spmax);
3517         }
3518
3519         if (action & F_MAIN) {
3520                 /* Check for min/max values */
3521                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3522                              itv, spmin, spmax, g_fields);
3523
3524                 /* atmptf/s */
3525                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3526                          S_VALUE(snetp->AttemptFails, snetc->AttemptFails, itv),
3527                          out, outsize, svg_p->restart);
3528                 /* estres/s */
3529                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3530                          S_VALUE(snetp->EstabResets, snetc->EstabResets, itv),
3531                          out + 1, outsize + 1, svg_p->restart);
3532                 /* retrans/s */
3533                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3534                          S_VALUE(snetp->RetransSegs, snetc->RetransSegs, itv),
3535                          out + 2, outsize + 2, svg_p->restart);
3536                 /* isegerr/s */
3537                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3538                          S_VALUE(snetp->InErrs, snetc->InErrs, itv),
3539                          out + 3, outsize + 3, svg_p->restart);
3540                 /* orsts/s */
3541                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3542                          S_VALUE(snetp->OutRsts, snetc->OutRsts, itv),
3543                          out + 4, outsize + 4, svg_p->restart);
3544         }
3545
3546         if (action & F_END) {
3547                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3548                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3549
3550                 /* Free remaining structures */
3551                 free_graphs(out, outsize, spmin, spmax);
3552         }
3553 }
3554
3555 /*
3556  ***************************************************************************
3557  * Display UDPv4 traffic statistics in SVG.
3558  *
3559  * IN:
3560  * @a           Activity structure with statistics.
3561  * @curr        Index in array for current sample statistics.
3562  * @action      Action expected from current function.
3563  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3564  *              flag indicating that a restart record has been previously
3565  *              found (.@restart) and time used for the X axis origin
3566  *              (@ust_time_ref).
3567  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3568  * @record_hdr  Pointer on record header of current stats sample.
3569  ***************************************************************************
3570  */
3571 __print_funct_t svg_print_net_udp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3572                                         unsigned long long itv, struct record_header *record_hdr)
3573 {
3574         struct stats_net_udp
3575                 *snuc = (struct stats_net_udp *) a->buf[curr],
3576                 *snup = (struct stats_net_udp *) a->buf[!curr];
3577         int group[] = {2, 2};
3578         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3579         char *title[] = {"UDPv4 traffic statistics (1)", "UDPv4 traffic statistics (2)"};
3580         char *g_title[] = {"idgm/s", "odgm/s",
3581                            "noport/s", "idgmerr/s"};
3582         int g_fields[] = {0, 1, 2, 3};
3583         static double *spmin, *spmax;
3584         static char **out;
3585         static int *outsize;
3586
3587         if (action & F_BEGIN) {
3588                 /*
3589                  * Allocate arrays that will contain the graphs data
3590                  * and the min/max values.
3591                  */
3592                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3593         }
3594
3595         if (action & F_MAIN) {
3596                 /* Check for min/max values */
3597                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3598                              itv, spmin, spmax, g_fields);
3599
3600                 /* idgm/s */
3601                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3602                          S_VALUE(snup->InDatagrams, snuc->InDatagrams, itv),
3603                          out, outsize, svg_p->restart);
3604                 /* odgm/s */
3605                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3606                          S_VALUE(snup->OutDatagrams, snuc->OutDatagrams, itv),
3607                          out + 1, outsize + 1, svg_p->restart);
3608                 /* noport/s */
3609                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3610                          S_VALUE(snup->NoPorts, snuc->NoPorts, itv),
3611                          out + 2, outsize + 2, svg_p->restart);
3612                 /* idgmerr/s */
3613                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3614                          S_VALUE(snup->InErrors, snuc->InErrors, itv),
3615                          out + 3, outsize + 3, svg_p->restart);
3616         }
3617
3618         if (action & F_END) {
3619                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3620                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3621
3622                 /* Free remaining structures */
3623                 free_graphs(out, outsize, spmin, spmax);
3624         }
3625 }
3626
3627 /*
3628  ***************************************************************************
3629  * Display IPV6 socket statistics in SVG.
3630  *
3631  * IN:
3632  * @a           Activity structure with statistics.
3633  * @curr        Index in array for current sample statistics.
3634  * @action      Action expected from current function.
3635  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3636  *              flag indicating that a restart record has been previously
3637  *              found (.@restart) and time used for the X axis origin
3638  *              (@ust_time_ref).
3639  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3640  * @record_hdr  Pointer on record header of current stats sample.
3641  ***************************************************************************
3642  */
3643 __print_funct_t svg_print_net_sock6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3644                                           unsigned long long itv, struct record_header *record_hdr)
3645 {
3646         struct stats_net_sock6
3647                 *snsc = (struct stats_net_sock6 *) a->buf[curr];
3648         int group[] = {4};
3649         int g_type[] = {SVG_LINE_GRAPH};
3650         char *title[] = {"IPv6 sockets statistics"};
3651         char *g_title[] = {"~tcp6sck", "~udp6sck", "~raw6sck", "~ip6-frag"};
3652         int g_fields[] = {0, 1, 2, 3};
3653         static double *spmin, *spmax;
3654         static char **out;
3655         static int *outsize;
3656
3657         if (action & F_BEGIN) {
3658                 /*
3659                  * Allocate arrays that will contain the graphs data
3660                  * and the min/max values.
3661                  */
3662                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
3663         }
3664
3665         if (action & F_MAIN) {
3666                 /* Check for min/max values */
3667                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
3668                              itv, spmin, spmax, g_fields);
3669                 /* tcp6sck */
3670                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3671                           (unsigned long long) snsc->tcp6_inuse,
3672                           out, outsize, svg_p->restart);
3673                 /* udp6sck */
3674                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3675                           (unsigned long long) snsc->udp6_inuse,
3676                           out + 1, outsize + 1, svg_p->restart);
3677                 /* raw6sck */
3678                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3679                           (unsigned long long) snsc->raw6_inuse,
3680                           out + 2, outsize + 2, svg_p->restart);
3681                 /* ip6-frag */
3682                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
3683                           (unsigned long long) snsc->frag6_inuse,
3684                           out + 3, outsize + 3, svg_p->restart);
3685         }
3686
3687         if (action & F_END) {
3688                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3689                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3690
3691                 /* Free remaining structures */
3692                 free_graphs(out, outsize, spmin, spmax);
3693         }
3694 }
3695
3696 /*
3697  ***************************************************************************
3698  * Display IPv6 traffic statistics in SVG.
3699  *
3700  * IN:
3701  * @a           Activity structure with statistics.
3702  * @curr        Index in array for current sample statistics.
3703  * @action      Action expected from current function.
3704  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3705  *              flag indicating that a restart record has been previously
3706  *              found (.@restart) and time used for the X axis origin
3707  *              (@ust_time_ref).
3708  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3709  * @record_hdr  Pointer on record header of current stats sample.
3710  ***************************************************************************
3711  */
3712 __print_funct_t svg_print_net_ip6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3713                                         unsigned long long itv, struct record_header *record_hdr)
3714 {
3715         struct stats_net_ip6
3716                 *snic = (struct stats_net_ip6 *) a->buf[curr],
3717                 *snip = (struct stats_net_ip6 *) a->buf[!curr];
3718         int group[] = {4, 2, 2, 2};
3719         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3720                         SVG_LINE_GRAPH};
3721         char *title[] = {"IPv6 traffic statistics (1)", "IPv6 traffic statistics (2)",
3722                          "IPv6 traffic statistics (3)", "IPv6 traffic statistics (4)"};
3723         char *g_title[] = {"irec6/s", "fwddgm6/s", "idel6/s", "orq6/s",
3724                            "asmrq6/s", "asmok6/s",
3725                            "imcpck6/s", "omcpck6/s",
3726                            "fragok6/s", "fragcr6/s"};
3727         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
3728         static double *spmin, *spmax;
3729         static char **out;
3730         static int *outsize;
3731
3732         if (action & F_BEGIN) {
3733                 /*
3734                  * Allocate arrays that will contain the graphs data
3735                  * and the min/max values.
3736                  */
3737                 out = allocate_graph_lines(10, &outsize, &spmin, &spmax);
3738         }
3739
3740         if (action & F_MAIN) {
3741                 /* Check for min/max values */
3742                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3743                              itv, spmin, spmax, g_fields);
3744
3745                 /* irec6/s */
3746                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3747                          S_VALUE(snip->InReceives6, snic->InReceives6, itv),
3748                          out, outsize, svg_p->restart);
3749                 /* fwddgm6/s */
3750                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3751                          S_VALUE(snip->OutForwDatagrams6, snic->OutForwDatagrams6, itv),
3752                          out + 1, outsize + 1, svg_p->restart);
3753                 /* idel6/s */
3754                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3755                          S_VALUE(snip->InDelivers6, snic->InDelivers6, itv),
3756                          out + 2, outsize + 2, svg_p->restart);
3757                 /* orq6/s */
3758                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3759                          S_VALUE(snip->OutRequests6, snic->OutRequests6, itv),
3760                          out + 3, outsize + 3, svg_p->restart);
3761                 /* asmrq6/s */
3762                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3763                          S_VALUE(snip->ReasmReqds6, snic->ReasmReqds6, itv),
3764                          out + 4, outsize + 4, svg_p->restart);
3765                 /* asmok6/s */
3766                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3767                          S_VALUE(snip->ReasmOKs6, snic->ReasmOKs6, itv),
3768                          out + 5, outsize + 5, svg_p->restart);
3769                 /* imcpck6/s */
3770                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3771                          S_VALUE(snip->InMcastPkts6, snic->InMcastPkts6, itv),
3772                          out + 6, outsize + 6, svg_p->restart);
3773                 /* omcpck6/s */
3774                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3775                          S_VALUE(snip->OutMcastPkts6, snic->OutMcastPkts6, itv),
3776                          out + 7, outsize + 7, svg_p->restart);
3777                 /* fragok6/s */
3778                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3779                          S_VALUE(snip->FragOKs6, snic->FragOKs6, itv),
3780                          out + 8, outsize + 8, svg_p->restart);
3781                 /* fragcr6/s */
3782                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3783                          S_VALUE(snip->FragCreates6, snic->FragCreates6, itv),
3784                          out + 9, outsize + 9, svg_p->restart);
3785         }
3786
3787         if (action & F_END) {
3788                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3789                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3790
3791                 /* Free remaining structures */
3792                 free_graphs(out, outsize, spmin, spmax);
3793         }
3794 }
3795
3796 /*
3797  ***************************************************************************
3798  * Display IPv6 traffic errors statistics in SVG.
3799  *
3800  * IN:
3801  * @a           Activity structure with statistics.
3802  * @curr        Index in array for current sample statistics.
3803  * @action      Action expected from current function.
3804  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3805  *              flag indicating that a restart record has been previously
3806  *              found (.@restart) and time used for the X axis origin
3807  *              (@ust_time_ref).
3808  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3809  * @record_hdr  Pointer on record header of current stats sample.
3810  ***************************************************************************
3811  */
3812 __print_funct_t svg_print_net_eip6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3813                                          unsigned long long itv, struct record_header *record_hdr)
3814 {
3815         struct stats_net_eip6
3816                 *sneic = (struct stats_net_eip6 *) a->buf[curr],
3817                 *sneip = (struct stats_net_eip6 *) a->buf[!curr];
3818         int group[] = {4, 2, 2, 3};
3819         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3820                         SVG_LINE_GRAPH};
3821         char *title[] = {"IPv6 traffic errors statistics (1)", "IPv6 traffic errors statistics (2)",
3822                          "IPv6 traffic errors statistics (3)", "IPv6 traffic errors statistics (4)",
3823                          "IPv6 traffic errors statistics (5)"};
3824         char *g_title[] = {"ihdrer6/s", "iadrer6/s", "iukwnp6/s", "i2big6/s",
3825                            "idisc6/s", "odisc6/s",
3826                            "inort6/s", "onort6/s",
3827                            "asmf6/s", "fragf6/s", "itrpck6/s"};
3828         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
3829         static double *spmin, *spmax;
3830         static char **out;
3831         static int *outsize;
3832
3833         if (action & F_BEGIN) {
3834                 /*
3835                  * Allocate arrays that will contain the graphs data
3836                  * and the min/max values.
3837                  */
3838                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
3839         }
3840
3841         if (action & F_MAIN) {
3842                 /* Check for min/max values */
3843                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3844                              itv, spmin, spmax, g_fields);
3845
3846                 /* ihdrer6/s */
3847                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3848                          S_VALUE(sneip->InHdrErrors6, sneic->InHdrErrors6, itv),
3849                          out, outsize, svg_p->restart);
3850                 /* iadrer6/s */
3851                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3852                          S_VALUE(sneip->InAddrErrors6, sneic->InAddrErrors6, itv),
3853                          out + 1, outsize + 1, svg_p->restart);
3854                 /* iukwnp6/s */
3855                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3856                          S_VALUE(sneip->InUnknownProtos6, sneic->InUnknownProtos6, itv),
3857                          out + 2, outsize + 2, svg_p->restart);
3858                 /* i2big6/s */
3859                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3860                          S_VALUE(sneip->InTooBigErrors6, sneic->InTooBigErrors6, itv),
3861                          out + 3, outsize + 3, svg_p->restart);
3862                 /* idisc6/s */
3863                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3864                          S_VALUE(sneip->InDiscards6, sneic->InDiscards6, itv),
3865                          out + 4, outsize + 4, svg_p->restart);
3866                 /* odisc6/s */
3867                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3868                          S_VALUE(sneip->OutDiscards6, sneic->OutDiscards6, itv),
3869                          out + 5, outsize + 5, svg_p->restart);
3870                 /* inort6/s */
3871                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3872                          S_VALUE(sneip->InNoRoutes6, sneic->InNoRoutes6, itv),
3873                          out + 6, outsize + 6, svg_p->restart);
3874                 /* onort6/s */
3875                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3876                          S_VALUE(sneip->OutNoRoutes6, sneic->OutNoRoutes6, itv),
3877                          out + 7, outsize + 7, svg_p->restart);
3878                 /* asmf6/s */
3879                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3880                          S_VALUE(sneip->ReasmFails6, sneic->ReasmFails6, itv),
3881                          out + 8, outsize + 8, svg_p->restart);
3882                 /* fragf6/s */
3883                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3884                          S_VALUE(sneip->FragFails6, sneic->FragFails6, itv),
3885                          out + 9, outsize + 9, svg_p->restart);
3886                 /* itrpck6/s */
3887                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3888                          S_VALUE(sneip->InTruncatedPkts6, sneic->InTruncatedPkts6, itv),
3889                          out + 10, outsize + 10, svg_p->restart);
3890         }
3891
3892         if (action & F_END) {
3893                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
3894                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
3895
3896                 /* Free remaining structures */
3897                 free_graphs(out, outsize, spmin, spmax);
3898         }
3899 }
3900
3901 /*
3902  ***************************************************************************
3903  * Display ICMPv6 traffic statistics in SVG.
3904  *
3905  * IN:
3906  * @a           Activity structure with statistics.
3907  * @curr        Index in array for current sample statistics.
3908  * @action      Action expected from current function.
3909  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
3910  *              flag indicating that a restart record has been previously
3911  *              found (.@restart) and time used for the X axis origin
3912  *              (@ust_time_ref).
3913  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
3914  * @record_hdr  Pointer on record header of current stats sample.
3915  ***************************************************************************
3916  */
3917 __print_funct_t svg_print_net_icmp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
3918                                           unsigned long long itv, struct record_header *record_hdr)
3919 {
3920         struct stats_net_icmp6
3921                 *snic = (struct stats_net_icmp6 *) a->buf[curr],
3922                 *snip = (struct stats_net_icmp6 *) a->buf[!curr];
3923         int group[] = {2, 3, 5, 3, 4};
3924         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
3925                         SVG_LINE_GRAPH, SVG_LINE_GRAPH};
3926         char *title[] = {"ICMPv6 traffic statistics (1)", "ICMPv6 traffic statistics (2)",
3927                          "ICMPv6 traffic statistics (3)", "ICMPv6 traffic statistics (4)",
3928                          "ICMPv6 traffic statistics (5)"};
3929         char *g_title[] = {"imsg6/s", "omsg6/s",
3930                            "iech6/s", "iechr6/s", "oechr6/s",
3931                            "igmbq6/s", "igmbr6/s", "ogmbr6/s", "igmbrd6/s", "ogmbrd6/s",
3932                            "irtsol6/s", "ortsol6/s", "irtad6/s",
3933                            "inbsol6/s", "onbsol6/s", "inbad6/s", "onbad6/s"};
3934         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
3935         static double *spmin, *spmax;
3936         static char **out;
3937         static int *outsize;
3938
3939         if (action & F_BEGIN) {
3940                 /*
3941                  * Allocate arrays that will contain the graphs data
3942                  * and the min/max values.
3943                  */
3944                 out = allocate_graph_lines(17, &outsize, &spmin, &spmax);
3945         }
3946
3947         if (action & F_MAIN) {
3948                 /* Check for min/max values */
3949                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
3950                              itv, spmin, spmax, g_fields);
3951
3952                 /* imsg6/s */
3953                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3954                          S_VALUE(snip->InMsgs6, snic->InMsgs6, itv),
3955                          out, outsize, svg_p->restart);
3956                 /* omsg6/s */
3957                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3958                          S_VALUE(snip->OutMsgs6, snic->OutMsgs6, itv),
3959                          out + 1, outsize + 1, svg_p->restart);
3960                 /* iech6/s */
3961                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3962                          S_VALUE(snip->InEchos6, snic->InEchos6, itv),
3963                          out + 2, outsize + 2, svg_p->restart);
3964                 /* iechr6/s */
3965                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3966                          S_VALUE(snip->InEchoReplies6, snic->InEchoReplies6, itv),
3967                          out + 3, outsize + 3, svg_p->restart);
3968                 /* oechr6/s */
3969                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3970                          S_VALUE(snip->OutEchoReplies6, snic->OutEchoReplies6, itv),
3971                          out + 4, outsize + 4, svg_p->restart);
3972                 /* igmbq6/s */
3973                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3974                          S_VALUE(snip->InGroupMembQueries6, snic->InGroupMembQueries6, itv),
3975                          out + 5, outsize + 5, svg_p->restart);
3976                 /* igmbr6/s */
3977                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3978                          S_VALUE(snip->InGroupMembResponses6, snic->InGroupMembResponses6, itv),
3979                          out + 6, outsize + 6, svg_p->restart);
3980                 /* ogmbr6/s */
3981                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3982                          S_VALUE(snip->OutGroupMembResponses6, snic->OutGroupMembResponses6, itv),
3983                          out + 7, outsize + 7, svg_p->restart);
3984                 /* igmbrd6/s */
3985                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3986                          S_VALUE(snip->InGroupMembReductions6, snic->InGroupMembReductions6, itv),
3987                          out + 8, outsize + 8, svg_p->restart);
3988                 /* ogmbrd6/s */
3989                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3990                          S_VALUE(snip->OutGroupMembReductions6, snic->OutGroupMembReductions6, itv),
3991                          out + 9, outsize + 9, svg_p->restart);
3992                 /* irtsol6/s */
3993                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3994                          S_VALUE(snip->InRouterSolicits6, snic->InRouterSolicits6, itv),
3995                          out + 10, outsize + 10, svg_p->restart);
3996                 /* ortsol6/s */
3997                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
3998                          S_VALUE(snip->OutRouterSolicits6, snic->OutRouterSolicits6, itv),
3999                          out + 11, outsize + 11, svg_p->restart);
4000                 /* irtad6/s */
4001                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4002                          S_VALUE(snip->InRouterAdvertisements6, snic->InRouterAdvertisements6, itv),
4003                          out + 12, outsize + 12, svg_p->restart);
4004                 /* inbsol6/s */
4005                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4006                          S_VALUE(snip->InNeighborSolicits6, snic->InNeighborSolicits6, itv),
4007                          out + 13, outsize + 13, svg_p->restart);
4008                 /* onbsol6/s */
4009                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4010                          S_VALUE(snip->OutNeighborSolicits6, snic->OutNeighborSolicits6, itv),
4011                          out + 14, outsize + 14, svg_p->restart);
4012                 /* inbad6/s */
4013                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4014                          S_VALUE(snip->InNeighborAdvertisements6, snic->InNeighborAdvertisements6, itv),
4015                          out + 15, outsize + 15, svg_p->restart);
4016                 /* onbad6/s */
4017                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4018                          S_VALUE(snip->OutNeighborAdvertisements6, snic->OutNeighborAdvertisements6, itv),
4019                          out + 16, outsize + 16, svg_p->restart);
4020         }
4021
4022         if (action & F_END) {
4023                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
4024                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
4025
4026                 /* Free remaining structures */
4027                 free_graphs(out, outsize, spmin, spmax);
4028         }
4029 }
4030
4031 /*
4032  ***************************************************************************
4033  * Display ICMPv6 traffic errors statistics in SVG.
4034  *
4035  * IN:
4036  * @a           Activity structure with statistics.
4037  * @curr        Index in array for current sample statistics.
4038  * @action      Action expected from current function.
4039  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4040  *              flag indicating that a restart record has been previously
4041  *              found (.@restart) and time used for the X axis origin
4042  *              (@ust_time_ref).
4043  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4044  * @record_hdr  Pointer on record header of current stats sample.
4045  ***************************************************************************
4046  */
4047 __print_funct_t svg_print_net_eicmp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4048                                            unsigned long long itv, struct record_header *record_hdr)
4049 {
4050         struct stats_net_eicmp6
4051                 *sneic = (struct stats_net_eicmp6 *) a->buf[curr],
4052                 *sneip = (struct stats_net_eicmp6 *) a->buf[!curr];
4053         int group[] = {1, 2, 2, 2, 2, 2};
4054         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH,
4055                         SVG_LINE_GRAPH, SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4056         char *title[] = {"ICMPv6 traffic errors statistics (1)", "ICMPv6 traffic errors statistics (2)",
4057                          "ICMPv6 traffic errors statistics (3)", "ICMPv6 traffic errors statistics (4)",
4058                          "ICMPv6 traffic errors statistics (5)", "ICMPv6 traffic errors statistics (6)"};
4059         char *g_title[] = {"ierr6/s",
4060                            "idtunr6/s", "odtunr6/s",
4061                            "itmex6/s", "otmex6/s",
4062                            "iprmpb6/s", "oprmpb6/s",
4063                            "iredir6/s", "oredir6/s",
4064                            "ipck2b6/s", "opck2b6/s"};
4065         int g_fields[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
4066         static double *spmin, *spmax;
4067         static char **out;
4068         static int *outsize;
4069
4070         if (action & F_BEGIN) {
4071                 /*
4072                  * Allocate arrays that will contain the graphs data
4073                  * and the min/max values.
4074                  */
4075                 out = allocate_graph_lines(11, &outsize, &spmin, &spmax);
4076         }
4077
4078         if (action & F_MAIN) {
4079                 /* Check for min/max values */
4080                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
4081                              itv, spmin, spmax, g_fields);
4082
4083                 /* ierr6/s */
4084                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4085                          S_VALUE(sneip->InErrors6, sneic->InErrors6, itv),
4086                          out, outsize, svg_p->restart);
4087                 /* idtunr6/s */
4088                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4089                          S_VALUE(sneip->InDestUnreachs6, sneic->InDestUnreachs6, itv),
4090                          out + 1, outsize + 1, svg_p->restart);
4091                 /* odtunr6/s */
4092                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4093                          S_VALUE(sneip->OutDestUnreachs6, sneic->OutDestUnreachs6, itv),
4094                          out + 2, outsize + 2, svg_p->restart);
4095                 /* itmex6/s */
4096                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4097                          S_VALUE(sneip->InTimeExcds6, sneic->InTimeExcds6, itv),
4098                          out + 3, outsize + 3, svg_p->restart);
4099                 /* otmex6/s */
4100                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4101                          S_VALUE(sneip->OutTimeExcds6, sneic->OutTimeExcds6, itv),
4102                          out + 4, outsize + 4, svg_p->restart);
4103                 /* iprmpb6/s */
4104                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4105                          S_VALUE(sneip->InParmProblems6, sneic->InParmProblems6, itv),
4106                          out + 5, outsize + 5, svg_p->restart);
4107                 /* oprmpb6/s */
4108                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4109                          S_VALUE(sneip->OutParmProblems6, sneic->OutParmProblems6, itv),
4110                          out + 6, outsize + 6, svg_p->restart);
4111                 /* iredir6/s */
4112                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4113                          S_VALUE(sneip->InRedirects6, sneic->InRedirects6, itv),
4114                          out + 7, outsize + 7, svg_p->restart);
4115                 /* oredir6/s */
4116                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4117                          S_VALUE(sneip->OutRedirects6, sneic->OutRedirects6, itv),
4118                          out + 8, outsize + 8, svg_p->restart);
4119                 /* ipck2b6/s */
4120                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4121                          S_VALUE(sneip->InPktTooBigs6, sneic->InPktTooBigs6, itv),
4122                          out + 9, outsize + 9, svg_p->restart);
4123                 /* opck2b6/s */
4124                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4125                          S_VALUE(sneip->OutPktTooBigs6, sneic->OutPktTooBigs6, itv),
4126                          out + 10, outsize + 10, svg_p->restart);
4127         }
4128
4129         if (action & F_END) {
4130                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
4131                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
4132
4133                 /* Free remaining structures */
4134                 free_graphs(out, outsize, spmin, spmax);
4135         }
4136 }
4137
4138 /*
4139  ***************************************************************************
4140  * Display UDPv6 traffic statistics in SVG.
4141  *
4142  * IN:
4143  * @a           Activity structure with statistics.
4144  * @curr        Index in array for current sample statistics.
4145  * @action      Action expected from current function.
4146  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4147  *              flag indicating that a restart record has been previously
4148  *              found (.@restart) and time used for the X axis origin
4149  *              (@ust_time_ref).
4150  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4151  * @record_hdr  Pointer on record header of current stats sample.
4152  ***************************************************************************
4153  */
4154 __print_funct_t svg_print_net_udp6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4155                                          unsigned long long itv, struct record_header *record_hdr)
4156 {
4157         struct stats_net_udp6
4158                 *snuc = (struct stats_net_udp6 *) a->buf[curr],
4159                 *snup = (struct stats_net_udp6 *) a->buf[!curr];
4160         int group[] = {2, 2};
4161         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4162         char *title[] = {"UDPv6 traffic statistics (1)", "UDPv6 traffic statistics (2)"};
4163         char *g_title[] = {"idgm6/s", "odgm6/s",
4164                            "noport6/s", "idgmer6/s"};
4165         int g_fields[] = {0, 1, 2, 3};
4166         static double *spmin, *spmax;
4167         static char **out;
4168         static int *outsize;
4169
4170         if (action & F_BEGIN) {
4171                 /*
4172                  * Allocate arrays that will contain the graphs data
4173                  * and the min/max values.
4174                  */
4175                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
4176         }
4177
4178         if (action & F_MAIN) {
4179                 /* Check for min/max values */
4180                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], (void *) a->buf[!curr],
4181                              itv, spmin, spmax, g_fields);
4182
4183                 /* idgm6/s */
4184                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4185                          S_VALUE(snup->InDatagrams6, snuc->InDatagrams6, itv),
4186                          out, outsize, svg_p->restart);
4187                 /* odgm6/s */
4188                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4189                          S_VALUE(snup->OutDatagrams6, snuc->OutDatagrams6, itv),
4190                          out + 1, outsize + 1, svg_p->restart);
4191                 /* noport6/s */
4192                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4193                          S_VALUE(snup->NoPorts6, snuc->NoPorts6, itv),
4194                          out + 2, outsize + 2, svg_p->restart);
4195                 /* idgmer6/s */
4196                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4197                          S_VALUE(snup->InErrors6, snuc->InErrors6, itv),
4198                          out + 3, outsize + 3, svg_p->restart);
4199         }
4200
4201         if (action & F_END) {
4202                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
4203                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
4204
4205                 /* Free remaining structures */
4206                 free_graphs(out, outsize, spmin, spmax);
4207         }
4208 }
4209
4210 /*
4211  ***************************************************************************
4212  * Display CPU frequency statistics in SVG.
4213  *
4214  * IN:
4215  * @a           Activity structure with statistics.
4216  * @curr        Index in array for current sample statistics.
4217  * @action      Action expected from current function.
4218  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4219  *              flag indicating that a restart record has been previously
4220  *              found (.@restart) and time used for the X axis origin
4221  *              (@ust_time_ref).
4222  * @itv         Interval of time in 1/100th of a second (unused here).
4223  * @record_hdr  Pointer on record header of current stats sample.
4224  ***************************************************************************
4225  */
4226 __print_funct_t svg_print_pwr_cpufreq_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4227                                             unsigned long long itv, struct record_header *record_hdr)
4228 {
4229         struct stats_pwr_cpufreq *spc, *spp;
4230         int group[] = {1};
4231         int g_type[] = {SVG_LINE_GRAPH};
4232         char *title[] = {"CPU clock frequency"};
4233         char *g_title[] = {"MHz"};
4234         static double *spmin, *spmax;
4235         static char **out;
4236         static int *outsize;
4237         char item_name[16];
4238         int i;
4239
4240         if (action & F_BEGIN) {
4241                 /*
4242                  * Allocate arrays that will contain the graphs data
4243                  * and the min/max values.
4244                  */
4245                 out = allocate_graph_lines(a->item_list_sz, &outsize, &spmin, &spmax);
4246         }
4247
4248         if (action & F_MAIN) {
4249                 /* For each CPU */
4250                 for (i = 0; (i < a->nr[curr]) && (i < a->bitmap->b_size + 1); i++) {
4251
4252                         spc = (struct stats_pwr_cpufreq *) ((char *) a->buf[curr]  + i * a->msize);
4253                         spp = (struct stats_pwr_cpufreq *) ((char *) a->buf[!curr] + i * a->msize);
4254
4255                         /* Should current CPU (including CPU "all") be displayed? */
4256                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
4257                                 /* No */
4258                                 continue;
4259
4260                         /*
4261                          * Note: Don't skip offline CPU here as it is needed
4262                          * to make the graph go though 0.
4263                          */
4264
4265                         /* MHz */
4266                         recappend(record_hdr->ust_time - svg_p->ust_time_ref,
4267                                   ((double) spp->cpufreq) / 100,
4268                                   ((double) spc->cpufreq) / 100,
4269                                   out + i, outsize + i, svg_p->restart, svg_p->dt,
4270                                   spmin + i, spmax + i);
4271                 }
4272         }
4273
4274         if (action & F_END) {
4275                 int xid = 0;
4276
4277                 for (i = 0; (i < a->item_list_sz) && (i < a->bitmap->b_size + 1); i++) {
4278
4279                         /* Should current CPU (including CPU "all") be displayed? */
4280                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
4281                                 /* No */
4282                                 continue;
4283
4284                         if (!i) {
4285                                 /* This is CPU "all" */
4286                                 strcpy(item_name, "all");
4287                         }
4288                         else {
4289                                 /*
4290                                  * If the maximum frequency reached by the CPU is 0, then
4291                                  * the CPU has been offline on the whole period.
4292                                  * => Don't display it.
4293                                  */
4294                                 if (*(spmax + i) == 0)
4295                                         continue;
4296
4297                                 sprintf(item_name, "%d", i - 1);
4298                         }
4299
4300                         if (draw_activity_graphs(a->g_nr, g_type,
4301                                                  title, g_title, item_name, group,
4302                                                  spmin + i, spmax + i, out + i, outsize + i,
4303                                                  svg_p, record_hdr, i, a->id, xid)) {
4304                                 xid++;
4305                         }
4306                 }
4307
4308                 /* Free remaining structures */
4309                 free_graphs(out, outsize, spmin, spmax);
4310         }
4311 }
4312
4313 /*
4314  ***************************************************************************
4315  * Display fan statistics in SVG.
4316  *
4317  * IN:
4318  * @a           Activity structure with statistics.
4319  * @curr        Index in array for current sample statistics.
4320  * @action      Action expected from current function.
4321  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4322  *              flag indicating that a restart record has been previously
4323  *              found (.@restart) and time used for the X axis origin
4324  *              (@ust_time_ref).
4325  * @itv         Interval of time in 1/100th of a second (unused here).
4326  * @record_hdr  Pointer on record header of current stats sample.
4327  ***************************************************************************
4328  */
4329 __print_funct_t svg_print_pwr_fan_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4330                                         unsigned long long itv, struct record_header *record_hdr)
4331 {
4332         struct stats_pwr_fan *spc, *spp;
4333         int group[] = {1};
4334         int g_type[] = {SVG_LINE_GRAPH};
4335         char *title[] = {"Fans speed"};
4336         char *g_title[] = {"~rpm"};
4337         static double *spmin, *spmax;
4338         static char **out;
4339         static int *outsize;
4340         char item_name[MAX_SENSORS_DEV_LEN + 16];
4341         int i;
4342
4343         if (action & F_BEGIN) {
4344                 /*
4345                  * Allocate arrays that will contain the graphs data
4346                  * and the min/max values.
4347                  */
4348                 out = allocate_graph_lines(a->item_list_sz, &outsize, &spmin, &spmax);
4349         }
4350
4351         if (action & F_MAIN) {
4352                 /* For each fan */
4353                 for (i = 0; i < a->nr[curr]; i++) {
4354
4355                         spc = (struct stats_pwr_fan *) ((char *) a->buf[curr]  + i * a->msize);
4356                         spp = (struct stats_pwr_fan *) ((char *) a->buf[!curr] + i * a->msize);
4357
4358                         /* rpm */
4359                         recappend(record_hdr->ust_time - svg_p->ust_time_ref,
4360                                   (double) spp->rpm,
4361                                   (double) spc->rpm,
4362                                   out + i, outsize + i, svg_p->restart, svg_p->dt,
4363                                   spmin + i, spmax + i);
4364                 }
4365         }
4366
4367         if (action & F_END) {
4368                 int xid = 0;
4369
4370                 for (i = 0; i < a->item_list_sz; i++) {
4371
4372                         spc = (struct stats_pwr_fan *) ((char *) a->buf[curr] + i * a->msize);
4373
4374                         snprintf(item_name, sizeof(item_name), "%d: %s", i + 1, spc->device);
4375                         item_name[sizeof(item_name) - 1] = '\0';
4376
4377                         if (draw_activity_graphs(a->g_nr, g_type,
4378                                                  title, g_title, item_name, group,
4379                                                  spmin + i, spmax + i, out + i, outsize + i,
4380                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
4381                                 xid++;
4382                         }
4383                 }
4384
4385                 /* Free remaining structures */
4386                 free_graphs(out, outsize, spmin, spmax);
4387         }
4388 }
4389
4390 /*
4391  ***************************************************************************
4392  * Display temperature statistics in SVG.
4393  *
4394  * IN:
4395  * @a           Activity structure with statistics.
4396  * @curr        Index in array for current sample statistics.
4397  * @action      Action expected from current function.
4398  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4399  *              flag indicating that a restart record has been previously
4400  *              found (.@restart) and time used for the X axis origin
4401  *              (@ust_time_ref).
4402  * @itv         Interval of time in 1/100th of a second (unused here).
4403  * @record_hdr  Pointer on record header of current stats sample.
4404  ***************************************************************************
4405  */
4406 __print_funct_t svg_print_pwr_temp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4407                                          unsigned long long itv, struct record_header *record_hdr)
4408 {
4409         struct stats_pwr_temp *spc;
4410         int group[] = {1, 1};
4411         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4412         char *title[] = {"Devices temperature (1)",
4413                          "Devices temperature (2)"};
4414         char *g_title[] = {"~degC",
4415                            "%temp"};
4416         static double *spmin, *spmax;
4417         static char **out;
4418         static int *outsize;
4419         char item_name[MAX_SENSORS_DEV_LEN + 16];
4420         int i;
4421         double tval;
4422
4423         if (action & F_BEGIN) {
4424                 /*
4425                  * Allocate arrays that will contain the graphs data
4426                  * and the min/max values.
4427                  */
4428                 out = allocate_graph_lines(2 * a->item_list_sz, &outsize, &spmin, &spmax);
4429         }
4430
4431         if (action & F_MAIN) {
4432                 /* For each temperature sensor */
4433                 for (i = 0; i < a->nr[curr]; i++) {
4434
4435                         spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
4436
4437                         /* Look for min/max values */
4438                         if (spc->temp < *(spmin + 2 * i)) {
4439                                 *(spmin + 2 * i) = spc->temp;
4440                         }
4441                         if (spc->temp > *(spmax + 2 * i)) {
4442                                 *(spmax + 2 * i) = spc->temp;
4443                         }
4444                         tval = (spc->temp_max - spc->temp_min) ?
4445                                (spc->temp - spc->temp_min) / (spc->temp_max - spc->temp_min) * 100 :
4446                                0.0;
4447                         if (tval < *(spmin + 2 * i + 1)) {
4448                                 *(spmin + 2 * i + 1) = tval;
4449                         }
4450                         if (tval > *(spmax + 2 * i + 1)) {
4451                                 *(spmax + 2 * i + 1) = tval;
4452                         }
4453
4454                         /* degC */
4455                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4456                                  (double) spc->temp,
4457                                  out + 2 * i, outsize + 2 * i, svg_p->restart);
4458                         /* %temp */
4459                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4460                                  0.0, tval,
4461                                  out + 2 * i + 1, outsize + 2 * i + 1, svg_p->dt);
4462                 }
4463         }
4464
4465         if (action & F_END) {
4466                 int xid = 0;
4467
4468                 for (i = 0; i < a->item_list_sz; i++) {
4469
4470                         spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
4471
4472                         snprintf(item_name, sizeof(item_name), "%d: %s", i + 1, spc->device);
4473                         item_name[sizeof(item_name) - 1] = '\0';
4474
4475                         if (draw_activity_graphs(a->g_nr, g_type,
4476                                                  title, g_title, item_name, group,
4477                                                  spmin + 2 * i, spmax + 2 * i, out + 2 * i, outsize + 2 * i,
4478                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
4479                                 xid++;
4480                         }
4481                 }
4482
4483                 /* Free remaining structures */
4484                 free_graphs(out, outsize, spmin, spmax);
4485         }
4486 }
4487
4488 /*
4489  ***************************************************************************
4490  * Display voltage inputs statistics in SVG.
4491  *
4492  * IN:
4493  * @a           Activity structure with statistics.
4494  * @curr        Index in array for current sample statistics.
4495  * @action      Action expected from current function.
4496  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4497  *              flag indicating that a restart record has been previously
4498  *              found (.@restart) and time used for the X axis origin
4499  *              (@ust_time_ref).
4500  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4501  * @record_hdr  Pointer on record header of current stats sample.
4502  ***************************************************************************
4503  */
4504 __print_funct_t svg_print_pwr_in_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4505                                        unsigned long long itv, struct record_header *record_hdr)
4506 {
4507         struct stats_pwr_in *spc;
4508         int group[] = {1, 1};
4509         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4510         char *title[] = {"Voltage inputs statistics (1)",
4511                          "Voltage inputs statistics (2)"};
4512         char *g_title[] = {"inV",
4513                            "%in"};
4514         static double *spmin, *spmax;
4515         static char **out;
4516         static int *outsize;
4517         char item_name[MAX_SENSORS_DEV_LEN + 16];
4518         int i;
4519         double tval;
4520
4521         if (action & F_BEGIN) {
4522                 /*
4523                  * Allocate arrays that will contain the graphs data
4524                  * and the min/max values.
4525                  */
4526                 out = allocate_graph_lines(2 * a->item_list_sz, &outsize, &spmin, &spmax);
4527         }
4528
4529         if (action & F_MAIN) {
4530                 /* For each voltage input sensor */
4531                 for (i = 0; i < a->nr[curr]; i++) {
4532
4533                         spc = (struct stats_pwr_in *) ((char *) a->buf[curr] + i * a->msize);
4534
4535                         /* Look for min/max values */
4536                         if (spc->in < *(spmin + 2 * i)) {
4537                                 *(spmin + 2 * i) = spc->in;
4538                         }
4539                         if (spc->in > *(spmax + 2 * i)) {
4540                                 *(spmax + 2 * i) = spc->in;
4541                         }
4542                         tval = (spc->in_max - spc->in_min) ?
4543                                (spc->in - spc->in_min) / (spc->in_max - spc->in_min) * 100 :
4544                                0.0;
4545                         if (tval < *(spmin + 2 * i + 1)) {
4546                                 *(spmin + 2 * i + 1) = tval;
4547                         }
4548                         if (tval > *(spmax + 2 * i + 1)) {
4549                                 *(spmax + 2 * i + 1) = tval;
4550                         }
4551
4552                         /* inV */
4553                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
4554                                  (double) spc->in,
4555                                  out + 2 * i, outsize + 2 * i, svg_p->restart);
4556                         /* %in */
4557                         brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4558                                  0.0, tval,
4559                                  out + 2 * i + 1, outsize + 2 * i + 1, svg_p->dt);
4560                 }
4561         }
4562
4563         if (action & F_END) {
4564                 int xid = 0;
4565
4566                 for (i = 0; i < a->item_list_sz; i++) {
4567
4568                         spc = (struct stats_pwr_in *) ((char *) a->buf[curr]  + i * a->msize);
4569
4570                         snprintf(item_name, sizeof(item_name), "%d: %s", i + 1, spc->device);
4571                         item_name[sizeof(item_name) - 1] = '\0';
4572
4573                         if (draw_activity_graphs(a->g_nr, g_type,
4574                                                  title, g_title, item_name, group,
4575                                                  spmin + 2 * i, spmax + 2 * i, out + 2 * i, outsize + 2 * i,
4576                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
4577                                 xid++;
4578                         }
4579                 }
4580
4581                 /* Free remaining structures */
4582                 free_graphs(out, outsize, spmin, spmax);
4583         }
4584 }
4585
4586 /*
4587  ***************************************************************************
4588  * Display huge pages statistics in SVG.
4589  *
4590  * IN:
4591  * @a           Activity structure with statistics.
4592  * @curr        Index in array for current sample statistics.
4593  * @action      Action expected from current function.
4594  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4595  *              flag indicating that a restart record has been previously
4596  *              found (.@restart) and time used for the X axis origin
4597  *              (@ust_time_ref).
4598  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4599  * @record_hdr  Pointer on record header of current stats sample.
4600  ***************************************************************************
4601  */
4602 __print_funct_t svg_print_huge_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4603                                      unsigned long long itv, struct record_header *record_hdr)
4604 {
4605         struct stats_huge
4606                 *smc = (struct stats_huge *) a->buf[curr];
4607         int group[] = {4, 1};
4608         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4609         char *title[] = {"Huge pages utilization (1)",
4610                          "Huge pages utilization (2)"};
4611         char *g_title[] = {"~kbhugfree", "~kbhugused", "~kbhugrsvd", "~kbhugsurp",
4612                            "%hugused"};
4613         int g_fields[] = {0, 5, 2, 3};
4614         static double *spmin, *spmax;
4615         static char **out;
4616         static int *outsize;
4617         double tval;
4618
4619         if (action & F_BEGIN) {
4620                 /*
4621                  * Allocate arrays that will contain the graphs data
4622                  * and the min/max values.
4623                  * Allocate one additional array (#5) to save min/max
4624                  * values for tlhkb (unused).
4625                  */
4626                 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
4627         }
4628
4629         if (action & F_MAIN) {
4630                 /* Check for min/max values */
4631                 save_extrema(a->gtypes_nr, (void *) a->buf[curr], NULL,
4632                              itv, spmin, spmax, g_fields);
4633
4634                 if (smc->tlhkb - smc->frhkb < *(spmin + 1)) {
4635                         *(spmin + 1) = smc->tlhkb - smc->frhkb;
4636                 }
4637                 if (smc->tlhkb - smc->frhkb > *(spmax + 1)) {
4638                         *(spmax + 1) = smc->tlhkb - smc->frhkb;
4639                 }
4640                 tval = smc->tlhkb ? SP_VALUE(smc->frhkb, smc->tlhkb, smc->tlhkb) : 0.0;
4641                 if (tval < *(spmin + 4)) {
4642                         *(spmin + 4) = tval;
4643                 }
4644                 if (tval > *(spmax + 4)) {
4645                         *(spmax + 4) = tval;
4646                 }
4647
4648                 /* kbhugfree */
4649                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4650                           (unsigned long long) smc->frhkb,
4651                           out, outsize, svg_p->restart);
4652                 /* hugused */
4653                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4654                           (unsigned long long) smc->tlhkb - smc->frhkb,
4655                           out + 1, outsize + 1, svg_p->restart);
4656                 /* kbhugrsvd */
4657                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4658                           (unsigned long long) smc->rsvdhkb,
4659                           out + 2, outsize + 2, svg_p->restart);
4660                 /* kbhugsurp */
4661                 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
4662                           (unsigned long long) smc->surphkb,
4663                           out + 3, outsize + 3, svg_p->restart);
4664                 /* %hugused */
4665                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
4666                          0.0, tval,
4667                          out + 4, outsize + 4, svg_p->dt);
4668         }
4669
4670         if (action & F_END) {
4671                 draw_activity_graphs(a->g_nr, g_type,
4672                                      title, g_title, NULL, group,
4673                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
4674
4675                 /* Free remaining structures */
4676                 free_graphs(out, outsize, spmin, spmax);
4677         }
4678 }
4679
4680 /*
4681  ***************************************************************************
4682  * Display filesystem statistics in SVG.
4683  *
4684  * IN:
4685  * @a           Activity structure with statistics.
4686  * @curr        Index in array for current sample statistics.
4687  * @action      Action expected from current function.
4688  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4689  *              flag indicating that a restart record has been previously
4690  *              found (.@restart) and time used for the X axis origin
4691  *              (@ust_time_ref).
4692  * @itv         Interval of time in 1/100th of a second (unused here).
4693  * @record_hdr  Pointer on record header of current stats sample.
4694  ***************************************************************************
4695  */
4696 __print_funct_t svg_print_filesystem_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4697                                            unsigned long long itv, struct record_header *record_hdr)
4698 {
4699         struct stats_filesystem *sfc, *sfp;
4700         int group[] = {2, 2, 2, 1};
4701         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH,
4702                         SVG_LINE_GRAPH, SVG_BAR_GRAPH};
4703         char *title[] = {"Filesystems statistics (1)", "Filesystems statistics (2)",
4704                          "Filesystems statistics (3)", "Filesystems statistics (4)"};
4705         char *g_title[] = {"~MBfsfree", "~MBfsused",
4706                            "%ufsused", "%fsused",
4707                            "Ifree/1000", "Iused/1000",
4708                            "%Iused"};
4709         int nr_arrays = 8;
4710         static double *spmin, *spmax;
4711         static char **out;
4712         static int *outsize;
4713         char *dev_name, *item_name;
4714         double tval;
4715         int i, k, pos, restart;
4716
4717         if (action & F_BEGIN) {
4718                 /*
4719                  * Allocate arrays (#0..6) that will contain the graphs data
4720                  * and the min/max values.
4721                  * Also allocate an additional arrays (#7) for each filesystem:
4722                  * out + 7 will contain the persistent or standard fs name, or mount point.
4723                  */
4724                 out = allocate_graph_lines(nr_arrays * a->item_list_sz, &outsize, &spmin, &spmax);
4725         }
4726
4727         if (action & F_MAIN) {
4728                 /* For each filesystem structure */
4729                 for (i = 0; i < a->nr[curr]; i++) {
4730                         sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize);
4731
4732                         /* Get name to display (persistent or standard fs name, or mount point) */
4733                         dev_name = get_fs_name_to_display(a, flags, sfc);
4734
4735                         if (a->item_list != NULL) {
4736                                 /* A list of devices has been entered on the command line */
4737                                 if (!search_list_item(a->item_list, dev_name))
4738                                         /* Device not found */
4739                                         continue;
4740                         }
4741
4742                         /* Look for corresponding graph */
4743                         for (k = 0; k < a->item_list_sz; k++) {
4744                                 item_name = *(out + k * nr_arrays + 7);
4745                                 if (!strcmp(dev_name, item_name))
4746                                         /* Graph found! */
4747                                         break;
4748                         }
4749
4750                         if (k == a->item_list_sz) {
4751                                 /* Graph not found: Look for first free entry */
4752                                 for (k = 0; k < a->item_list_sz; k++) {
4753                                         item_name = *(out + k * nr_arrays + 7);
4754                                         if (!strcmp(item_name, ""))
4755                                                 break;
4756                                 }
4757                                 if (k == a->item_list_sz) {
4758                                         /* No free graph entry: Ignore it (should never happen) */
4759 #ifdef DEBUG
4760                                         fprintf(stderr, "%s: Name=%s\n",
4761                                                 __FUNCTION__, sfc->fs_name);
4762 #endif
4763                                         continue;
4764                                 }
4765                         }
4766
4767                         pos = k * nr_arrays;
4768
4769                         item_name = *(out + pos + 7);
4770                         if (!item_name[0]) {
4771                                 /* Save filesystem name and mount point (if not already done) */
4772                                 strncpy(item_name, dev_name, 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 * nr_arrays;
4891                         if (!**(out + pos))
4892                                 continue;
4893
4894                         /* Conversion B -> MiB 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                         item_name = *(out + pos + 7);
4903
4904                         if (draw_activity_graphs(a->g_nr, g_type, title, g_title, item_name, group,
4905                                                  spmin + pos, spmax + pos, out + pos, outsize + pos,
4906                                                  svg_p, record_hdr, FALSE, a->id, xid)) {
4907                                 xid++;
4908                         }
4909                 }
4910
4911                 /* Free remaining structures */
4912                 free_graphs(out, outsize, spmin, spmax);
4913         }
4914 }
4915
4916 /*
4917  ***************************************************************************
4918  * Display Fibre Channel HBA statistics in SVG.
4919  *
4920  * IN:
4921  * @a           Activity structure with statistics.
4922  * @curr        Index in array for current sample statistics.
4923  * @action      Action expected from current function.
4924  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
4925  *              flag indicating that a restart record has been previously
4926  *              found (.@restart) and time used for the X axis origin
4927  *              (@ust_time_ref).
4928  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
4929  * @record_hdr  Pointer on record header of current stats sample.
4930  ***************************************************************************
4931  */
4932 __print_funct_t svg_print_fchost_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
4933                                        unsigned long long itv, struct record_header *record_hdr)
4934 {
4935         struct stats_fchost *sfcc, *sfcp, sfczero;
4936         int group[] = {2, 2};
4937         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
4938         char *title[] = {"Fibre Channel HBA statistics (1)", "Fibre Channel HBA statistics (2)"};
4939         char *g_title[] = {"fch_rxf/s", "fch_txf/s",
4940                            "fch_rxw/s", "fch_txw/s"};
4941         int g_fields[] = {0, 1, 2, 3};
4942         static double *spmin, *spmax;
4943         static char **out;
4944         static int *outsize;
4945         char *item_name;
4946         int i, j, j0, k, found, pos, restart, *unregistered;
4947
4948         if (action & F_BEGIN) {
4949                 /*
4950                  * Allocate arrays (#0..3) that will contain the graphs data
4951                  * and the min/max values.
4952                  * Also allocate one additional array (#4) that will contain
4953                  * FC HBA name (out + 4) and a positive value (TRUE) if the interface
4954                  * has either still not been registered, or has been unregistered
4955                  * (outsize + 4).
4956                  */
4957                 out = allocate_graph_lines(5 * a->item_list_sz, &outsize, &spmin, &spmax);
4958         }
4959
4960         if (action & F_MAIN) {
4961                 memset(&sfczero, 0, sizeof(struct stats_fchost));
4962                 restart = svg_p->restart;
4963                 /*
4964                  * Mark previously registered interfaces as now
4965                  * possibly unregistered for all graphs.
4966                  */
4967                 for (k = 0; k < a->item_list_sz; k++) {
4968                         unregistered = outsize + k * 5 + 4;
4969                         if (*unregistered == FALSE) {
4970                                 *unregistered = MAYBE;
4971                         }
4972                 }
4973
4974                 /* For each FC HBA */
4975                 for (i = 0; i < a->nr[curr]; i++) {
4976
4977                         found = FALSE;
4978                         sfcc = (struct stats_fchost *) ((char *) a->buf[curr] + i * a->msize);
4979
4980                         /* Look for corresponding graph */
4981                         for (k = 0; k < a->item_list_sz; k++) {
4982                                 item_name = *(out + k * 5 + 4);
4983                                 if (!strcmp(sfcc->fchost_name, item_name))
4984                                         /* Graph found! */
4985                                         break;
4986                         }
4987                         if (k == a->item_list_sz) {
4988                                 /* Graph not found: Look for first free entry */
4989                                 for (k = 0; k < a->item_list_sz; k++) {
4990                                         item_name = *(out + k * 5 + 4);
4991                                         if (!strcmp(item_name, ""))
4992                                                 break;
4993                                 }
4994                                 if (k == a->item_list_sz) {
4995                                         /* No free graph entry: Ignore it (should never happen) */
4996 #ifdef DEBUG
4997                                         fprintf(stderr, "%s: Name=%s\n",
4998                                                 __FUNCTION__, sfcc->fchost_name);
4999 #endif
5000                                         continue;
5001                                 }
5002                         }
5003
5004                         pos = k * 5;
5005                         unregistered = outsize + pos + 4;
5006
5007                         if (a->nr[!curr] > 0) {
5008                                 /* Look for corresponding structure in previous iteration */
5009                                 j = i;
5010
5011                                 if (j >= a->nr[!curr]) {
5012                                         j = a->nr[!curr] - 1;
5013                                 }
5014
5015                                 j0 = j;
5016
5017                                 do {
5018                                         sfcp = (struct stats_fchost *) ((char *) a->buf[!curr] + j * a->msize);
5019                                         if (!strcmp(sfcc->fchost_name, sfcp->fchost_name)) {
5020                                                 found = TRUE;
5021                                                 break;
5022                                         }
5023                                         if (++j >= a->nr[!curr]) {
5024                                                 j = 0;
5025                                         }
5026                                 }
5027                                 while (j != j0);
5028                         }
5029
5030                         if (!found) {
5031                                 /* This is a newly registered host */
5032                                 sfcp = &sfczero;
5033                         }
5034
5035                         /*
5036                          * If current interface was marked as previously unregistered,
5037                          * then set restart variable to TRUE so that the graph will be
5038                          * discontinuous, and mark it as now registered.
5039                          */
5040                         if (*unregistered == TRUE) {
5041                                 restart = TRUE;
5042                         }
5043                         *unregistered = FALSE;
5044
5045                         item_name = *(out + pos + 4);
5046                         if (!item_name[0]) {
5047                                 /* Save FC HBA name */
5048                                 strncpy(item_name, sfcc->fchost_name, CHUNKSIZE);
5049                                 item_name[CHUNKSIZE - 1] = '\0';
5050                         }
5051
5052                         /* Look for min/max values */
5053                         save_extrema(a->gtypes_nr, (void *) sfcc, (void *) sfcp,
5054                                 itv, spmin + pos, spmax + pos, g_fields);
5055
5056                         /* fch_rxf/s */
5057                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5058                                  S_VALUE(sfcp->f_rxframes, sfcc->f_rxframes, itv),
5059                                  out + pos, outsize + pos, restart);
5060                         /* fch_txf/s */
5061                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5062                                  S_VALUE(sfcp->f_txframes, sfcc->f_txframes, itv),
5063                                  out + pos + 1, outsize + pos + 1, restart);
5064                         /* fch_rxw/s */
5065                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5066                                  S_VALUE(sfcp->f_rxwords, sfcc->f_rxwords, itv),
5067                                  out + pos + 2, outsize + pos + 2, restart);
5068                         /* fch_txw/s */
5069                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5070                                  S_VALUE(sfcp->f_txwords, sfcc->f_txwords, itv),
5071                                  out + pos + 3, outsize + pos + 3, restart);
5072                 }
5073
5074                 /* Mark interfaces not seen here as now unregistered */
5075                 for (k = 0; k < a->item_list_sz; k++) {
5076                         unregistered = outsize + k * 5 + 4;
5077                         if (*unregistered != FALSE) {
5078                                 *unregistered = TRUE;
5079                         }
5080                 }
5081         }
5082
5083         if (action & F_END) {
5084                 for (i = 0; i < a->item_list_sz; i++) {
5085
5086                         /* Check if there is something to display */
5087                         pos = i * 5;
5088                         if (!**(out + pos))
5089                                 continue;
5090
5091                         item_name = *(out + pos + 4);
5092                         draw_activity_graphs(a->g_nr, g_type,
5093                                              title, g_title, item_name, group,
5094                                              spmin + pos, spmax + pos, out + pos, outsize + pos,
5095                                              svg_p, record_hdr, FALSE, a->id, i);
5096                 }
5097
5098                 /* Free remaining structures */
5099                 free_graphs(out, outsize, spmin, spmax);
5100         }
5101 }
5102
5103 /*
5104  ***************************************************************************
5105  * Display softnet statistics in SVG.
5106  *
5107  * IN:
5108  * @a           Activity structure with statistics.
5109  * @curr        Index in array for current sample statistics.
5110  * @action      Action expected from current function.
5111  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5112  *              flag indicating that a restart record has been previously
5113  *              found (.@restart) and time used for the X axis origin
5114  *              (@ust_time_ref).
5115  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5116  * @record_hdr  Pointer on record header of current stats sample.
5117  ***************************************************************************
5118  */
5119 __print_funct_t svg_print_softnet_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5120                                         unsigned long long itv, struct record_header *record_hdr)
5121 {
5122         struct stats_softnet *ssnc, *ssnp, ssnczero;
5123         int group[] = {2, 3};
5124         int g_type[] = {SVG_LINE_GRAPH, SVG_LINE_GRAPH};
5125         char *title[] = {"Software-based network processing statistics (1)",
5126                          "Software-based network processing statistics (2)"};
5127         char *g_title[] = {"total/s", "dropd/s",
5128                            "squeezd/s", "rx_rps/s", "flw_lim/s"};
5129         int g_fields[] = {0, 1, 2, 3, 4};
5130         static double *spmin, *spmax;
5131         static char **out;
5132         static int *outsize;
5133         char item_name[16];
5134         unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
5135         int i, pos, restart;
5136
5137         if (action & F_BEGIN) {
5138                 /*
5139                  * Allocate arrays that will contain the graphs data
5140                  * and the min/max values.
5141                  */
5142                 out = allocate_graph_lines(5 * a->item_list_sz, &outsize, &spmin, &spmax);
5143         }
5144
5145         if (action & F_MAIN) {
5146                 memset(&ssnczero, 0, STATS_SOFTNET_SIZE);
5147
5148                 /* @nr[curr] cannot normally be greater than @nr_ini */
5149                 if (a->nr[curr] > a->nr_ini) {
5150                         a->nr_ini = a->nr[curr];
5151                 }
5152
5153                 /* Compute statistics for CPU "all" */
5154                 get_global_soft_statistics(a, !curr, curr, flags, offline_cpu_bitmap);
5155
5156                 /* For each CPU */
5157                 for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
5158                         restart = svg_p->restart;
5159
5160                         /* Should current CPU (including CPU "all") be displayed? */
5161                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
5162                                 /* No */
5163                                 continue;
5164
5165                         ssnc = (struct stats_softnet *) ((char *) a->buf[curr]  + i * a->msize);
5166                         ssnp = (struct stats_softnet *) ((char *) a->buf[!curr] + i * a->msize);
5167
5168                         /* Is current CPU marked offline? */
5169                         if (offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07))) {
5170                                 /*
5171                                  * Yes and it doesn't follow a RESTART record.
5172                                  * To add a discontinuity in graph, we simulate
5173                                  * a RESTART mark.
5174                                  */
5175                                 restart = TRUE;
5176                                 if (svg_p->restart) {
5177                                         /*
5178                                          * CPU is offline and it follows a real
5179                                          * RESTART record. Ignore its current value
5180                                          * (no previous sample).
5181                                          */
5182                                         ssnc = &ssnczero;
5183                                 }
5184                         }
5185                         pos = i * 5;
5186
5187                         /* Check for min/max values */
5188                         save_extrema(a->gtypes_nr, (void *) ssnc, (void *) ssnp,
5189                                      itv, spmin + pos, spmax + pos, g_fields);
5190
5191                         /* total/s */
5192                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5193                                  S_VALUE(ssnp->processed, ssnc->processed, itv),
5194                                  out + pos, outsize + pos, restart);
5195                         /* dropd/s */
5196                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5197                                  S_VALUE(ssnp->dropped, ssnc->dropped, itv),
5198                                  out + pos + 1, outsize + pos + 1, restart);
5199                         /* squeezd/s */
5200                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5201                                  S_VALUE(ssnp->time_squeeze, ssnc->time_squeeze, itv),
5202                                  out + pos + 2, outsize + pos + 2, restart);
5203                         /* rx_rps/s */
5204                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5205                                  S_VALUE(ssnp->received_rps, ssnc->received_rps, itv),
5206                                  out + pos + 3, outsize + pos + 3, restart);
5207                         /* flw_lim/s */
5208                         lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5209                                  S_VALUE(ssnp->flow_limit, ssnc->flow_limit, itv),
5210                                  out + pos + 4, outsize + pos + 4, restart);
5211                 }
5212         }
5213
5214         if (action & F_END) {
5215                 for (i = 0; (i < a->item_list_sz) && (i < a->bitmap->b_size + 1); i++) {
5216
5217                         /* Should current CPU (including CPU "all") be displayed? */
5218                         if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
5219                                 /* No */
5220                                 continue;
5221
5222                         pos = i * 5;
5223
5224                         if (!i) {
5225                                 /* This is CPU "all" */
5226                                 strcpy(item_name, "all");
5227                         }
5228                         else {
5229                                 sprintf(item_name, "%d", i - 1);
5230                         }
5231
5232                         draw_activity_graphs(a->g_nr, g_type,
5233                                              title, g_title, item_name, group,
5234                                              spmin + pos, spmax + pos, out + pos, outsize + pos,
5235                                              svg_p, record_hdr, FALSE, a->id, i);
5236                 }
5237
5238                 /* Free remaining structures */
5239                 free_graphs(out, outsize, spmin, spmax);
5240         }
5241 }
5242
5243 /*
5244  ***************************************************************************
5245  * Display pressure-stall CPU statistics in SVG.
5246  *
5247  * IN:
5248  * @a           Activity structure with statistics.
5249  * @curr        Index in array for current sample statistics.
5250  * @action      Action expected from current function.
5251  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5252  *              flag indicating that a restart record has been previously
5253  *              found (.@restart) and time used for the X axis origin
5254  *              (@ust_time_ref).
5255  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5256  * @record_hdr  Pointer on record header of current stats sample.
5257  ***************************************************************************
5258  */
5259 __print_funct_t svg_print_psicpu_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5260                                        unsigned long long itv, struct record_header *record_hdr)
5261 {
5262         struct stats_psi_cpu
5263                 *psic = (struct stats_psi_cpu *) a->buf[curr],
5264                 *psip = (struct stats_psi_cpu *) a->buf[!curr];
5265         int group[] = {3, 1};
5266         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH};
5267         char *title[] = {"CPU pressure trends (some tasks)", "CPU stall time (some tasks)"};
5268         char *g_title[] = {"%scpu-10", "%scpu-60", "%scpu-300",
5269                            "%scpu"};
5270         static double *spmin, *spmax;
5271         static char **out;
5272         static int *outsize;
5273         double tval;
5274
5275         if (action & F_BEGIN) {
5276                 /*
5277                  * Allocate arrays that will contain the graphs data
5278                  * and the min/max values.
5279                  */
5280                 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
5281         }
5282
5283         if (action & F_MAIN) {
5284                 /* Check for min/max values */
5285                 if (psic->some_acpu_10 > *spmax) {
5286                         *spmax = psic->some_acpu_10;
5287                 }
5288                 if (psic->some_acpu_10 < *spmin) {
5289                         *spmin = psic->some_acpu_10;
5290                 }
5291                 if (psic->some_acpu_60 > *(spmax + 1)) {
5292                         *(spmax + 1) = psic->some_acpu_60;
5293                 }
5294                 if (psic->some_acpu_60 < *(spmin + 1)) {
5295                         *(spmin + 1) = psic->some_acpu_60;
5296                 }
5297                 if (psic->some_acpu_300 > *(spmax + 2)) {
5298                         *(spmax + 2) = psic->some_acpu_300;
5299                 }
5300                 if (psic->some_acpu_300 < *(spmin + 2)) {
5301                         *(spmin + 2) = psic->some_acpu_300;
5302                 }
5303                 tval = ((double) psic->some_cpu_total - psip->some_cpu_total) / (100 * itv);
5304                 if (tval > *(spmax + 3)) {
5305                         *(spmax + 3) = tval;
5306                 }
5307                 if (tval < *(spmin + 3)) {
5308                         *(spmin + 3) = tval;
5309                 }
5310
5311                 /* %scpu-10 */
5312                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5313                          (double) psic->some_acpu_10 / 100,
5314                          out, outsize, svg_p->restart);
5315                 /* %scpu-60 */
5316                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5317                          (double) psic->some_acpu_60 / 100,
5318                          out + 1, outsize + 1, svg_p->restart);
5319                 /* %scpu-300 */
5320                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5321                          (double) psic->some_acpu_300 / 100,
5322                          out + 2, outsize + 2, svg_p->restart);
5323                 /* %scpu */
5324                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5325                          0.0,
5326                          ((double) psic->some_cpu_total - psip->some_cpu_total) / (100 * itv),
5327                          out + 3, outsize + 3, svg_p->dt);
5328         }
5329
5330         if (action & F_END) {
5331                 /* Fix min/max values for pressure ratios */
5332                 *spmin /= 100; *spmax /= 100;
5333                 *(spmin + 1) /= 100; *(spmax + 1) /= 100;
5334                 *(spmin + 2) /= 100; *(spmax + 2) /= 100;
5335
5336                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
5337                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
5338
5339                 /* Free remaining structures */
5340                 free_graphs(out, outsize, spmin, spmax);
5341         }
5342 }
5343
5344 /*
5345  ***************************************************************************
5346  * Display pressure-stall I/O statistics in SVG.
5347  *
5348  * IN:
5349  * @a           Activity structure with statistics.
5350  * @curr        Index in array for current sample statistics.
5351  * @action      Action expected from current function.
5352  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5353  *              flag indicating that a restart record has been previously
5354  *              found (.@restart) and time used for the X axis origin
5355  *              (@ust_time_ref).
5356  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5357  * @record_hdr  Pointer on record header of current stats sample.
5358  ***************************************************************************
5359  */
5360 __print_funct_t svg_print_psiio_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5361                                       unsigned long long itv, struct record_header *record_hdr)
5362 {
5363         struct stats_psi_io
5364                 *psic = (struct stats_psi_io *) a->buf[curr],
5365                 *psip = (struct stats_psi_io *) a->buf[!curr];
5366         int group[] = {3, 1, 3, 1};
5367         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH, SVG_LINE_GRAPH, SVG_BAR_GRAPH};
5368         char *title[] = {"I/O pressure trends (some tasks)", "I/O stall time (some tasks)",
5369                          "I/O pressure trends (full)", "I/O stall time (full)"};
5370         char *g_title[] = {"%sio-10", "%sio-60", "%sio-300",
5371                            "%sio",
5372                            "%fio-10", "%fio-60", "%fio-300",
5373                            "%fio"};
5374         static double *spmin, *spmax;
5375         static char **out;
5376         static int *outsize;
5377         double tval;
5378
5379         if (action & F_BEGIN) {
5380                 /*
5381                  * Allocate arrays that will contain the graphs data
5382                  * and the min/max values.
5383                  */
5384                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
5385         }
5386
5387         if (action & F_MAIN) {
5388                 /* Check for min/max values */
5389                 if (psic->some_aio_10 > *spmax) {
5390                         *spmax = psic->some_aio_10;
5391                 }
5392                 if (psic->some_aio_10 < *spmin) {
5393                         *spmin = psic->some_aio_10;
5394                 }
5395                 if (psic->some_aio_60 > *(spmax + 1)) {
5396                         *(spmax + 1) = psic->some_aio_60;
5397                 }
5398                 if (psic->some_aio_60 < *(spmin + 1)) {
5399                         *(spmin + 1) = psic->some_aio_60;
5400                 }
5401                 if (psic->some_aio_300 > *(spmax + 2)) {
5402                         *(spmax + 2) = psic->some_aio_300;
5403                 }
5404                 if (psic->some_aio_300 < *(spmin + 2)) {
5405                         *(spmin + 2) = psic->some_aio_300;
5406                 }
5407                 tval = ((double) psic->some_io_total - psip->some_io_total) / (100 * itv);
5408                 if (tval > *(spmax + 3)) {
5409                         *(spmax + 3) = tval;
5410                 }
5411                 if (tval < *(spmin + 3)) {
5412                         *(spmin + 3) = tval;
5413                 }
5414
5415                 if (psic->full_aio_10 > *(spmax + 4)) {
5416                         *(spmax + 4) = psic->full_aio_10;
5417                 }
5418                 if (psic->full_aio_10 < *(spmin + 4)) {
5419                         *(spmin + 4) = psic->full_aio_10;
5420                 }
5421                 if (psic->full_aio_60 > *(spmax + 5)) {
5422                         *(spmax + 5) = psic->full_aio_60;
5423                 }
5424                 if (psic->full_aio_60 < *(spmin + 5)) {
5425                         *(spmin + 5) = psic->full_aio_60;
5426                 }
5427                 if (psic->full_aio_300 > *(spmax + 6)) {
5428                         *(spmax + 6) = psic->full_aio_300;
5429                 }
5430                 if (psic->full_aio_300 < *(spmin + 6)) {
5431                         *(spmin + 6) = psic->full_aio_300;
5432                 }
5433                 tval = ((double) psic->full_io_total - psip->full_io_total) / (100 * itv);
5434                 if (tval > *(spmax + 7)) {
5435                         *(spmax + 7) = tval;
5436                 }
5437                 if (tval < *(spmin + 7)) {
5438                         *(spmin + 7) = tval;
5439                 }
5440
5441                 /* %sio-10 */
5442                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5443                          (double) psic->some_aio_10 / 100,
5444                          out, outsize, svg_p->restart);
5445                 /* %sio-60 */
5446                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5447                          (double) psic->some_aio_60 / 100,
5448                          out + 1, outsize + 1, svg_p->restart);
5449                 /* %sio-300 */
5450                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5451                          (double) psic->some_aio_300 / 100,
5452                          out + 2, outsize + 2, svg_p->restart);
5453                 /* %sio */
5454                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5455                          0.0,
5456                          ((double) psic->some_io_total - psip->some_io_total) / (100 * itv),
5457                          out + 3, outsize + 3, svg_p->dt);
5458
5459                 /* %fio-10 */
5460                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5461                          (double) psic->full_aio_10 / 100,
5462                          out + 4, outsize + 4, svg_p->restart);
5463                 /* %fio-60 */
5464                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5465                          (double) psic->full_aio_60 / 100,
5466                          out + 5, outsize + 5, svg_p->restart);
5467                 /* %fio-300 */
5468                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5469                          (double) psic->full_aio_300 / 100,
5470                          out + 6, outsize + 6, svg_p->restart);
5471                 /* %fio */
5472                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5473                          0.0,
5474                          ((double) psic->full_io_total - psip->full_io_total) / (100 * itv),
5475                          out + 7, outsize + 7, svg_p->dt);
5476         }
5477
5478         if (action & F_END) {
5479                 /* Fix min/max values for pressure ratios */
5480                 *spmin /= 100; *spmax /= 100;
5481                 *(spmin + 1) /= 100; *(spmax + 1) /= 100;
5482                 *(spmin + 2) /= 100; *(spmax + 2) /= 100;
5483
5484                 *(spmin + 4) /= 100; *(spmax + 4) /= 100;
5485                 *(spmin + 5) /= 100; *(spmax + 5) /= 100;
5486                 *(spmin + 6) /= 100; *(spmax + 6) /= 100;
5487
5488                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
5489                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
5490
5491                 /* Free remaining structures */
5492                 free_graphs(out, outsize, spmin, spmax);
5493         }
5494 }
5495
5496 /*
5497  ***************************************************************************
5498  * Display pressure-stall memory statistics in SVG.
5499  *
5500  * IN:
5501  * @a           Activity structure with statistics.
5502  * @curr        Index in array for current sample statistics.
5503  * @action      Action expected from current function.
5504  * @svg_p       SVG specific parameters: Current graph number (.@graph_no),
5505  *              flag indicating that a restart record has been previously
5506  *              found (.@restart) and time used for the X axis origin
5507  *              (@ust_time_ref).
5508  * @itv         Interval of time in 1/100th of a second (only with F_MAIN action).
5509  * @record_hdr  Pointer on record header of current stats sample.
5510  ***************************************************************************
5511  */
5512 __print_funct_t svg_print_psimem_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
5513                                        unsigned long long itv, struct record_header *record_hdr)
5514 {
5515         struct stats_psi_mem
5516                 *psic = (struct stats_psi_mem *) a->buf[curr],
5517                 *psip = (struct stats_psi_mem *) a->buf[!curr];
5518         int group[] = {3, 1, 3, 1};
5519         int g_type[] = {SVG_LINE_GRAPH, SVG_BAR_GRAPH, SVG_LINE_GRAPH, SVG_BAR_GRAPH};
5520         char *title[] = {"Memory pressure trends (some tasks)", "Memory stall time (some tasks)",
5521                          "Memory pressure trends (full)", "Memory stall time (full)"};
5522         char *g_title[] = {"%smem-10", "%smem-60", "%smem-300",
5523                            "%smem",
5524                            "%fmem-10", "%fmem-60", "%fmem-300",
5525                            "%fmem"};
5526         static double *spmin, *spmax;
5527         static char **out;
5528         static int *outsize;
5529         double tval;
5530
5531         if (action & F_BEGIN) {
5532                 /*
5533                  * Allocate arrays that will contain the graphs data
5534                  * and the min/max values.
5535                  */
5536                 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
5537         }
5538
5539         if (action & F_MAIN) {
5540                 /* Check for min/max values */
5541                 if (psic->some_amem_10 > *spmax) {
5542                         *spmax = psic->some_amem_10;
5543                 }
5544                 if (psic->some_amem_10 < *spmin) {
5545                         *spmin = psic->some_amem_10;
5546                 }
5547                 if (psic->some_amem_60 > *(spmax + 1)) {
5548                         *(spmax + 1) = psic->some_amem_60;
5549                 }
5550                 if (psic->some_amem_60 < *(spmin + 1)) {
5551                         *(spmin + 1) = psic->some_amem_60;
5552                 }
5553                 if (psic->some_amem_300 > *(spmax + 2)) {
5554                         *(spmax + 2) = psic->some_amem_300;
5555                 }
5556                 if (psic->some_amem_300 < *(spmin + 2)) {
5557                         *(spmin + 2) = psic->some_amem_300;
5558                 }
5559                 tval = ((double) psic->some_mem_total - psip->some_mem_total) / (100 * itv);
5560                 if (tval > *(spmax + 3)) {
5561                         *(spmax + 3) = tval;
5562                 }
5563                 if (tval < *(spmin + 3)) {
5564                         *(spmin + 3) = tval;
5565                 }
5566
5567                 if (psic->full_amem_10 > *(spmax + 4)) {
5568                         *(spmax + 4) = psic->full_amem_10;
5569                 }
5570                 if (psic->full_amem_10 < *(spmin + 4)) {
5571                         *(spmin + 4) = psic->full_amem_10;
5572                 }
5573                 if (psic->full_amem_60 > *(spmax + 5)) {
5574                         *(spmax + 5) = psic->full_amem_60;
5575                 }
5576                 if (psic->full_amem_60 < *(spmin + 5)) {
5577                         *(spmin + 5) = psic->full_amem_60;
5578                 }
5579                 if (psic->full_amem_300 > *(spmax + 6)) {
5580                         *(spmax + 6) = psic->full_amem_300;
5581                 }
5582                 if (psic->full_amem_300 < *(spmin + 6)) {
5583                         *(spmin + 6) = psic->full_amem_300;
5584                 }
5585                 tval = ((double) psic->full_mem_total - psip->full_mem_total) / (100 * itv);
5586                 if (tval > *(spmax + 7)) {
5587                         *(spmax + 7) = tval;
5588                 }
5589                 if (tval < *(spmin + 7)) {
5590                         *(spmin + 7) = tval;
5591                 }
5592
5593                 /* %smem-10 */
5594                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5595                          (double) psic->some_amem_10 / 100,
5596                          out, outsize, svg_p->restart);
5597                 /* %smem-60 */
5598                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5599                          (double) psic->some_amem_60 / 100,
5600                          out + 1, outsize + 1, svg_p->restart);
5601                 /* %smem-300 */
5602                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5603                          (double) psic->some_amem_300 / 100,
5604                          out + 2, outsize + 2, svg_p->restart);
5605                 /* %smem */
5606                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5607                          0.0,
5608                          ((double) psic->some_mem_total - psip->some_mem_total) / (100 * itv),
5609                          out + 3, outsize + 3, svg_p->dt);
5610
5611                 /* %fmem-10 */
5612                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5613                          (double) psic->full_amem_10 / 100,
5614                          out + 4, outsize + 4, svg_p->restart);
5615                 /* %fmem-60 */
5616                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5617                          (double) psic->full_amem_60 / 100,
5618                          out + 5, outsize + 5, svg_p->restart);
5619                 /* %fmem-300 */
5620                 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
5621                          (double) psic->full_amem_300 / 100,
5622                          out + 6, outsize + 6, svg_p->restart);
5623                 /* %fmem */
5624                 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
5625                          0.0,
5626                          ((double) psic->full_mem_total - psip->full_mem_total) / (100 * itv),
5627                          out + 7, outsize + 7, svg_p->dt);
5628         }
5629
5630         if (action & F_END) {
5631                 /* Fix min/max values for pressure ratios */
5632                 *spmin /= 100; *spmax /= 100;
5633                 *(spmin + 1) /= 100; *(spmax + 1) /= 100;
5634                 *(spmin + 2) /= 100; *(spmax + 2) /= 100;
5635
5636                 *(spmin + 4) /= 100; *(spmax + 4) /= 100;
5637                 *(spmin + 5) /= 100; *(spmax + 5) /= 100;
5638                 *(spmin + 6) /= 100; *(spmax + 6) /= 100;
5639
5640                 draw_activity_graphs(a->g_nr, g_type, title, g_title, NULL, group,
5641                                      spmin, spmax, out, outsize, svg_p, record_hdr, FALSE, a->id, 0);
5642
5643                 /* Free remaining structures */
5644                 free_graphs(out, outsize, spmin, spmax);
5645         }
5646 }