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