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