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