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