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