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