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