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