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