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