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