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