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