2 * svg_stats.c: Funtions used by sadf to display statistics in SVG format.
3 * (C) 2016 by Sebastien GODARD (sysstat <at> orange.fr)
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. *
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 *
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 ***************************************************************************
31 #include "svg_stats.h"
36 #define _(string) gettext(string)
38 #define _(string) (string)
41 extern unsigned int flags;
42 extern unsigned int dm_major;
44 unsigned int svg_colors[] = {0x00cc00, 0xff00bf, 0x00ffff, 0xff0000,
45 0xe85f00, 0x0000ff, 0x006020, 0x7030a0,
46 0xffff00, 0x666635, 0xd60093, 0x00bfbf,
47 0xcc3300, 0xbfbfbf, 0xffffbf, 0xff3300};
48 #define SVG_COLORS_IDX_MASK 0x0f
51 ***************************************************************************
52 * Compare the values of a statistics sample with the max and min values
53 * already found in previous samples for this same activity. If some new
54 * min or max values are found, then save them.
55 * The structure containing the statistics sample is composed of @llu_nr
56 * unsigned long long fields, followed by @lu_nr unsigned long fields, then
57 * followed by @u_nr unsigned int fields.
60 * @llu_nr Number of unsigned long long fields composing the structure.
61 * @lu_nr Number of unsigned long fields composing the structure.
62 * @u_nr Number of unsigned int fields composing the structure.
63 * @cs Pointer on current sample statistics structure.
64 * @ps Pointer on previous sample statistics structure (may be NULL).
65 * @itv Interval of time in jiffies.
66 * @minv Array containing min values already found for this activity.
67 * @maxv Array containing max values already found for this activity.
70 * @minv Array containg the possible new min values for current activity.
71 * @maxv Array containg the possible new max values for current activity.
73 * NB: @minv and @maxv arrays contain values in the same order as the fields
74 * in the statistics structure.
75 ***************************************************************************
77 void save_extrema(int llu_nr, int lu_nr, int u_nr, void *cs, void *ps,
78 unsigned long long itv, double minv[], double maxv[])
80 unsigned long long *lluc, *llup;
81 unsigned long *luc, *lup;
82 unsigned int *uc, *up;
86 /* Compare unsigned long long fields */
87 lluc = (unsigned long long *) cs;
88 llup = (unsigned long long *) ps;
89 for (i = 0; i < llu_nr; i++, m++) {
91 val = S_VALUE(*llup, *lluc, itv);
95 * If no pointer on previous sample has been given
96 * then the value is not a per-second one.
106 lluc = (unsigned long long *) ((char *) lluc + ULL_ALIGNMENT_WIDTH);
108 llup = (unsigned long long *) ((char *) llup + ULL_ALIGNMENT_WIDTH);
112 /* Compare unsigned long fields */
113 luc = (unsigned long *) lluc;
114 lup = (unsigned long *) llup;
115 for (i = 0; i < lu_nr; i++, m++) {
117 val = S_VALUE(*lup, *luc, itv);
128 luc = (unsigned long *) ((char *) luc + UL_ALIGNMENT_WIDTH);
130 lup = (unsigned long *) ((char *) lup + UL_ALIGNMENT_WIDTH);
134 /* Compare unsigned int fields */
135 uc = (unsigned int *) luc;
136 up = (unsigned int *) lup;
137 for (i = 0; i < u_nr; i++, m++) {
139 val = S_VALUE(*up, *uc, itv);
150 uc = (unsigned int *) ((char *) uc + U_ALIGNMENT_WIDTH);
152 up = (unsigned int *) ((char *) up + U_ALIGNMENT_WIDTH);
158 ***************************************************************************
159 * Find the min and max values of all the graphs that will be drawn in the
160 * same view. The graphs have their own min and max values in
161 * minv[pos...pos+n-1] and maxv[pos...pos+n-1].
164 * @pos Position in array for the first graph extrema value.
165 * @n Number of graphs to scan.
166 * @minv Array containing min values for graphs.
167 * @maxv Array containing max values for graphs.
170 * @gmin Global min value found.
171 * @gmax Global max value found.
172 ***************************************************************************
174 void get_global_extrema(int pos, int n, double minv[], double maxv[], double *gmin, double *gmax)
181 for (i = 1; i < n; i++) {
182 if (minv[pos + i] < *gmin) {
183 *gmin = minv[pos + i];
185 if (maxv[pos + i] > *gmax) {
186 *gmax = maxv[pos + i];
192 ***************************************************************************
193 * Allocate arrays used to save graphs data, min and max values.
194 * @n arrays of chars are allocated for @n graphs to draw. A pointer on this
195 * array is returned. This is equivalent to "char data[][n]" where each
196 * element is of indeterminate size and will contain the graph data (eg.
197 * << path d="M12,14 L13,16..." ... >>.
198 * The size of element data[i] is given by outsize[i].
199 * Also allocate an array to save min values (equivalent to "double spmin[n]")
200 * and an array for max values (equivalent to "double spmax[n]").
203 * @n Number of graphs to draw for current activity.
206 * @outsize Array that will contain the sizes of each element in array
207 * of chars. Equivalent to "int outsize[n]" with
208 * outsize[n] = sizeof(data[][n]).
209 * @spmin Array that will contain min values for current activity.
210 * @spmax Array that will contain max values for current activity.
213 * Pointer on array of arrays of chars that will contain the graphs data.
215 * NB: @min and @max arrays contain values in the same order as the fields
216 * in the statistics structure.
217 ***************************************************************************
219 char **allocate_graph_lines(int n, int **outsize, double **spmin, double **spmax)
226 * Allocate an array of pointers. Each of these pointers will
227 * be an array of chars.
229 if ((out = (char **) malloc(n * sizeof(char *))) == NULL) {
233 /* Allocate array that will contain the size of each array of chars */
234 if ((*outsize = (int *) malloc(n * sizeof(int))) == NULL) {
238 /* Allocate array that will contain the min value of each graph */
239 if ((*spmin = (double *) malloc(n * sizeof(double))) == NULL) {
243 /* Allocate array that will contain the max value of each graph */
244 if ((*spmax = (double *) malloc(n * sizeof(double))) == NULL) {
248 /* Allocate arrays of chars that will contain graphs data */
249 for (i = 0; i < n; i++) {
250 if ((out_p = (char *) malloc(CHUNKSIZE * sizeof(char))) == NULL) {
255 *out_p = '\0'; /* Reset string so that it can be safely strncat()'d later */
256 *(*outsize + i) = CHUNKSIZE; /* Each array of chars has a default size of CHUNKSIZE */
257 *(*spmin + i) = DBL_MAX; /* Init min and max values */
258 *(*spmax + i) = -DBL_MAX;
265 ***************************************************************************
266 * Save SVG code for current graph.
269 * @data SVG code to append to current graph definition.
270 * @out Pointer on array of chars for current graph definition.
271 * @outsize Size of array of chars for current graph definition.
274 * @out Pointer on array of chars for current graph definition that
275 * has been updated with the addition of current sample data.
276 * @outsize Array that containing the (possibly new) sizes of each
277 * element in array of chars.
278 ***************************************************************************
280 void save_svg_data(char *data, char **out, int *outsize)
286 /* Determine space left in array */
287 len = *outsize - strlen(out_p) - 1;
288 if (strlen(data) >= len) {
290 * If current array of chars doesn't have enough space left
291 * then reallocate it with CHUNKSIZE more bytes.
293 SREALLOC(out_p, char, *outsize + CHUNKSIZE);
295 *outsize += CHUNKSIZE;
298 strncat(out_p, data, len);
302 ***************************************************************************
303 * Update line graph definition by appending current X,Y coordinates.
306 * @timetag Timestamp in seconds since the epoch for current sample
307 * stats. Will be used as X coordinate.
308 * @value Value of current sample metric. Will be used as Y coordinate.
309 * @out Pointer on array of chars for current graph definition.
310 * @outsize Size of array of chars for current graph definition.
311 * @restart Set to TRUE if a RESTART record has been read since the last
315 * @out Pointer on array of chars for current graph definition that
316 * has been updated with the addition of current sample data.
317 * @outsize Array that containing the (possibly new) sizes of each
318 * element in array of chars.
319 ***************************************************************************
321 void lnappend(unsigned long timetag, double value, char **out, int *outsize, int restart)
325 /* Prepare additional graph definition data */
326 snprintf(data, 128, " %c%lu,%.2f", restart ? 'M' : 'L', timetag, value);
329 save_svg_data(data, out, outsize);
333 ***************************************************************************
334 * Update line graph definition by appending current X,Y coordinates. Use
335 * (unsigned long) integer values here.
338 * @timetag Timestamp in seconds since the epoch for current sample
339 * stats. Will be used as X coordinate.
340 * @value Value of current sample metric. Will be used as Y coordinate.
341 * @out Pointer on array of chars for current graph definition.
342 * @outsize Size of array of chars for current graph definition.
343 * @restart Set to TRUE if a RESTART record has been read since the last
347 * @out Pointer on array of chars for current graph definition that
348 * has been updated with the addition of current sample data.
349 * @outsize Array that containing the (possibly new) sizes of each
350 * element in array of chars.
351 ***************************************************************************
353 void lniappend(unsigned long timetag, unsigned long value, char **out, int *outsize,
358 /* Prepare additional graph definition data */
359 snprintf(data, 128, " %c%lu,%lu", restart ? 'M' : 'L', timetag, value);
362 save_svg_data(data, out, outsize);
366 ***************************************************************************
367 * Update bar graph definition by adding a new rectangle.
370 * @timetag Timestamp in seconds since the epoch for current sample
371 * stats. Will be used as X coordinate.
372 * @value Value of current sample metric. Will be used as rectangle
374 * @offset Offset for Y coordinate.
375 * @out Pointer on array of chars for current graph definition.
376 * @outsize Size of array of chars for current graph definition.
377 * @dt Interval of time in seconds between current and previous
381 * @out Pointer on array of chars for current graph definition that
382 * has been updated with the addition of current sample data.
383 * @outsize Array that containing the (possibly new) sizes of each
384 * element in array of chars.
385 ***************************************************************************
387 void brappend(unsigned long timetag, double offset, double value, char **out, int *outsize,
392 /* Prepare additional graph definition data */
394 /* Dont draw a flat rectangle! */
397 snprintf(data, 128, "<rect x=\"%lu\" y=\"%.2f\" height=\"%.2f\" width=\"%lu\"/>",
398 timetag - dt, MINIMUM(offset, 100.0), MINIMUM(value, (100.0 - offset)), dt);
401 save_svg_data(data, out, outsize);
406 ***************************************************************************
407 * Update CPU graph and min/max values for each metric.
410 * @timetag Timestamp in seconds since the epoch for current sample
411 * stats. Will be used as X coordinate.
412 * @offset Offset for Y coordinate.
413 * @value Value of current CPU metric. Will be used as rectangle
415 * @out Pointer on array of chars for current graph definition.
416 * @outsize Size of array of chars for current graph definition.
417 * @dt Interval of time in seconds between current and previous
419 * @spmin Min value already found for this CPU metric.
420 * @spmax Max value already found for this CPU metric.
423 * @offset New offset value, to use to draw next rectangle
424 * @out Pointer on array of chars for current graph definition that
425 * has been updated with the addition of current sample data.
426 * @outsize Array that containing the (possibly new) sizes of each
427 * element in array of chars.
428 ***************************************************************************
430 void cpuappend(unsigned long timetag, double *offset, double value, char **out, int *outsize,
431 unsigned long dt, double *spmin, double *spmax)
433 /* Save min and max values */
434 if (value < *spmin) {
437 if (value > *spmax) {
440 /* Prepare additional graph definition data */
441 brappend(timetag, *offset, value, out, outsize, dt);
447 ***************************************************************************
448 * Update rectangular graph and min/max values.
451 * @timetag Timestamp in seconds since the epoch for current sample
452 * stats. Will be used as X coordinate.
453 * @p_value Metric value for previous sample
454 * @value Metric value for current sample.
455 * @out Pointer on array of chars for current graph definition.
456 * @outsize Size of array of chars for current graph definition.
457 * @restart Set to TRUE if a RESTART record has been read since the last
459 * @dt Interval of time in seconds between current and previous
461 * @spmin Min value already found for this metric.
462 * @spmax Max value already found for this metric.
465 * @out Pointer on array of chars for current graph definition that
466 * has been updated with the addition of current sample data.
467 * @outsize Array that containing the (possibly new) sizes of each
468 * element in array of chars.
469 * @spmin Min value for this metric.
470 * @spmax Max value for this metric.
471 ***************************************************************************
473 void recappend(unsigned long timetag, double p_value, double value, char **out, int *outsize,
474 int restart, unsigned long dt, double *spmin, double *spmax)
476 char data[128], data1[128], data2[128];
478 /* Save min and max values */
479 if (value < *spmin) {
482 if (value > *spmax) {
485 /* Prepare additional graph definition data */
487 snprintf(data1, 128, " M%lu,%.2f", timetag - dt, p_value);
490 if (p_value != value) {
491 snprintf(data2, 128, " L%lu,%.2f", timetag, value);
494 snprintf(data, 128, "%s L%lu,%.2f%s", restart ? data1 : "", timetag, p_value,
495 p_value != value ? data2 : "");
498 save_svg_data(data, out, outsize);
502 ***************************************************************************
503 * Calculate 10 raised to the power of n.
506 * @n Power number to use.
509 * 10 raised to the power of n.
510 ***************************************************************************
512 unsigned int pwr10(int n)
517 for (i = 0; i < n; i++) {
525 ***************************************************************************
526 * Calculate the value on the Y axis between two horizontal lines that will
527 * make the graph background grid.
530 * @lmax Max value reached for this graph.
533 * @dp Number of decimal places for Y graduations.
536 * Value between two horizontal lines.
537 ***************************************************************************
539 double ygrid(double lmax, int *dp)
550 n = (long) (lmax / SVG_H_GRIDNR);
553 return (lmax / SVG_H_GRIDNR);
555 snprintf(val, 32, "%ld", n);
562 return ((double) (((long) (n / e)) * e));
566 ***************************************************************************
567 * Calculate the value on the X axis between two vertical lines that will
568 * make the graph background grid.
571 * @timestart First data timestamp (X coordinate of the first data point).
572 * @timeend Last data timestamp (X coordinate of the last data point).
573 * @v_gridnr Number of vertical lines to display. Its value is normally
574 * SVG_V_GRIDNR, except when option "oneday" is used, in which
575 * case it is set to 12.
578 * Value between two vertical lines.
579 ***************************************************************************
581 long int xgrid(unsigned long timestart, unsigned long timeend, int v_gridnr)
583 if ((timeend - timestart) <= v_gridnr)
586 return ((timeend - timestart) / v_gridnr);
590 ***************************************************************************
591 * Free global graphs structures.
594 * @out Pointer on array of chars for each graph definition.
595 * @outsize Size of array of chars for each graph definition.
596 * @spmin Array containing min values for graphs.
597 * @spmax Array containing max values for graphs.
598 ***************************************************************************
600 void free_graphs(char **out, int *outsize, double *spmin, double *spmax)
617 ***************************************************************************
618 * Display all graphs for current activity.
621 * @g_nr Number of sets of graphs (views) to display.
622 * @g_type Type of graph (SVG_LINE_GRAPH, SVG_BAR_GRAPH).
623 * @title Titles for each set of graphs.
624 * @g_title Titles for each graph.
625 * @item_name Item (network interface, etc.) name.
626 * @group Indicate how graphs are grouped together to make sets.
627 * @spmin Array containing min values for graphs.
628 * @spmax Array containing max values for graphs.
629 * @out Pointer on array of chars for each graph definition.
630 * @outsize Size of array of chars for each graph definition.
631 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
632 * time for the first sample of stats (.@ust_time_first), and
633 * times used as start and end values on the X axis
634 * (.@ust_time_ref and .@ust_time_end).
635 * @record_hdr Pointer on record header of current stats sample.
636 ***************************************************************************
638 void draw_activity_graphs(int g_nr, int g_type, char *title[], char *g_title[], char *item_name,
639 int group[], double *spmin, double *spmax, char **out, int *outsize,
640 struct svg_parm *svg_p, struct record_header *record_hdr)
642 struct record_header stamp;
645 int i, j, dp, pos = 0, views_nr = 0;
647 unsigned int asfactor[16];
649 double lmax, xfactor, yfactor, ypos, gmin, gmax;
650 char cur_time[32], val[32];
652 /* Translate to proper position for current activity */
653 printf("<g id=\"g%d\" transform=\"translate(0,%d)\">\n",
655 SVG_H_YSIZE + svg_p->graph_no * SVG_T_YSIZE);
657 /* For each set of graphs which are part of current activity */
658 for (i = 0; i < g_nr; i++) {
660 /* Get global min and max value for current set of graphs */
661 get_global_extrema(pos, group[i], spmin, spmax, &gmin, &gmax);
663 /* Don't display empty views if requested */
664 if (SKIP_EMPTY_VIEWS(flags) && (gmax < 0.005))
666 /* Increment number of views actually displayed */
669 /* Graph background */
670 printf("<rect x=\"0\" y=\"%d\" height=\"%d\" width=\"%d\"/>\n",
672 SVG_V_YSIZE, SVG_V_XSIZE);
675 printf("<text x=\"0\" y=\"%d\" style=\"fill: yellow; stroke: none\">%s",
676 20 + i * SVG_T_YSIZE, title[i]);
678 printf(" [%s]", item_name);
681 printf("<tspan x=\"%d\" y=\"%d\" style=\"fill: yellow; stroke: none; font-size: 12px\">"
682 "(Min, Max values)</tspan>\n</text>\n",
683 5 + SVG_M_XSIZE + SVG_G_XSIZE,
684 25 + i * SVG_T_YSIZE);
687 * At least two samples are needed.
688 * And a min and max value should have been found.
690 if ((record_hdr->ust_time == svg_p->ust_time_first) ||
691 (*(spmin + pos) == DBL_MAX) || (*(spmax + pos) == -DBL_MIN)) {
693 printf("<text x=\"0\" y=\"%d\" style=\"fill: red; stroke: none\">No data</text>\n",
694 SVG_M_YSIZE + i * SVG_T_YSIZE);
699 printf("<polyline points=\"%d,%d %d,%d %d,%d\" stroke=\"white\" stroke-width=\"2\"/>\n",
700 SVG_M_XSIZE, SVG_M_YSIZE + i * SVG_T_YSIZE,
701 SVG_M_XSIZE, SVG_M_YSIZE + SVG_G_YSIZE + i * SVG_T_YSIZE,
702 SVG_M_XSIZE + SVG_G_XSIZE, SVG_M_YSIZE + SVG_G_YSIZE + i * SVG_T_YSIZE);
704 for (j = 0; j < 16; j++) {
705 /* Init autoscale factors */
709 if (AUTOSCALE_ON(flags) && (group[i] > 1) && gmax && (g_type == SVG_LINE_GRAPH)) {
711 for (j = 0; (j < group[i]) && (j < 16); j++) {
712 if (!*(spmax + pos + j) || (*(spmax + pos + j) == gmax))
715 snprintf(val, 32, "%u", (unsigned int) (gmax / *(spmax + pos + j)));
716 if (strlen(val) > 0) {
717 asfactor[j] = pwr10(strlen(val) - 1);
723 for (j = 0; j < group[i]; j++) {
724 /* Set dp to TRUE (1) if current metric is based on integer values */
725 dp = (g_title[pos + j][0] == '~');
726 snprintf(val, 32, "x%u ", asfactor[j]);
727 printf("<text x=\"%d\" y=\"%d\" style=\"fill: #%06x; stroke: none; font-size: 12px\">"
728 "%s %s(%.*f, %.*f)</text>\n",
729 5 + SVG_M_XSIZE + SVG_G_XSIZE, SVG_M_YSIZE + i * SVG_T_YSIZE + j * 15,
730 svg_colors[(pos + j) & SVG_COLORS_IDX_MASK], g_title[pos + j] + dp,
731 asfactor[j] == 1 ? "" : val,
732 !dp * 2, *(spmin + pos + j) * asfactor[j],
733 !dp * 2, *(spmax + pos + j) * asfactor[j]);
736 /* Translate to proper position for current graph within current activity */
737 printf("<g transform=\"translate(%d,%d)\">\n",
738 SVG_M_XSIZE, SVG_M_YSIZE + SVG_G_YSIZE + i * SVG_T_YSIZE);
741 if (g_type == SVG_LINE_GRAPH) {
742 /* For line graphs */
744 /* If all values are zero then set current max value to 1 */
750 /* Max value cannot be too small, else Y graduations will be meaningless */
751 if (lmax < SVG_H_GRIDNR * 0.01) {
752 lmax = SVG_H_GRIDNR * 0.01;
754 ypos = ygrid(lmax, &dp);
757 /* For bar graphs (used for %values) */
758 ypos = 25.0; /* Draw lines at 25%, 50%, 75% and 100% */
759 dp = 0; /* No decimals */
761 /* Max should be always 100% except for percentage values greater than 100% */
769 yfactor = (double) -SVG_G_YSIZE / lmax;
772 printf("<polyline points=\"0,%.2f %d,%.2f\" style=\"vector-effect: non-scaling-stroke; "
773 "stroke: #202020\" transform=\"scale(1,%f)\"/>\n",
774 ypos * j, SVG_G_XSIZE, ypos * j, yfactor);
777 while (ypos * j <= lmax);
780 printf("<text x=\"0\" y=\"%ld\" style=\"fill: white; stroke: none; font-size: 12px; "
781 "text-anchor: end\">%.*f.</text>\n",
782 (long) (ypos * j * yfactor), dp, ypos * j);
785 while (ypos * j <= lmax);
787 /* Set number of vertical lines to 12 when option "oneday" is used */
788 v_gridnr = DISPLAY_ONE_DAY(flags) ? 12 : SVG_V_GRIDNR;
790 k = xgrid(svg_p->ust_time_ref, svg_p->ust_time_end, v_gridnr);
791 xfactor = (double) SVG_G_XSIZE / (svg_p->ust_time_end - svg_p->ust_time_ref);
792 stamp.ust_time = svg_p->ust_time_ref; /* Only ust_time field needs to be set. TRUE_TIME not allowed */
794 for (j = 0; (j <= v_gridnr) && (stamp.ust_time <= svg_p->ust_time_end); j++) {
795 sa_get_record_timestamp_struct(flags, &stamp, &rectime, NULL);
796 set_record_timestamp_string(flags, &stamp, NULL, cur_time, 32, &rectime);
797 printf("<polyline points=\"%ld,0 %ld,%d\" style=\"vector-effect: non-scaling-stroke; "
798 "stroke: #202020\" transform=\"scale(%f,1)\"/>\n",
799 k * j, k * j, -SVG_G_YSIZE, xfactor);
801 * NB: We may have tm_min != 0 if we have more than 24H worth of data in one datafile.
802 * In this case, we should rather display the exact time instead of only the hour.
804 if (DISPLAY_ONE_DAY(flags) && (rectime.tm_min == 0)) {
805 printf("<text x=\"%ld\" y=\"15\" style=\"fill: white; stroke: none; font-size: 14px; "
806 "text-anchor: start\">%2dH</text>\n",
807 (long) (k * j * xfactor) - 8, rectime.tm_hour);
810 printf("<text x=\"%ld\" y=\"10\" style=\"fill: white; stroke: none; font-size: 12px; "
811 "text-anchor: start\" transform=\"rotate(45,%ld,0)\">%s</text>\n",
812 (long) (k * j * xfactor), (long) (k * j * xfactor), cur_time);
816 if (!PRINT_LOCAL_TIME(flags)) {
817 printf("<text x=\"-10\" y=\"30\" style=\"fill: yellow; stroke: none; font-size: 12px; "
818 "text-anchor: end\">UTC</text>\n");
821 /* Draw current graphs set */
822 for (j = 0; j < group[i]; j++) {
823 out_p = *(out + pos + j);
824 if (g_type == SVG_LINE_GRAPH) {
826 printf("<path id=\"g%dp%d\" d=\"%s\" "
827 "style=\"vector-effect: non-scaling-stroke; "
828 "stroke: #%06x; stroke-width: 1; fill-opacity: 0\" "
829 "transform=\"scale(%f,%f)\"/>\n",
830 svg_p->graph_no, pos + j, out_p,
831 svg_colors[(pos + j) & SVG_COLORS_IDX_MASK],
833 yfactor * asfactor[j]);
835 else if (*out_p) { /* Ignore flat bars */
837 printf("<g style=\"fill: #%06x; stroke: none\" transform=\"scale(%f,%f)\">\n",
838 svg_colors[(pos + j) & SVG_COLORS_IDX_MASK], xfactor, yfactor);
839 printf("%s\n", out_p);
850 (svg_p->graph_no) += views_nr;
854 ***************************************************************************
855 * Display CPU statistics in SVG.
858 * @a Activity structure with statistics.
859 * @curr Index in array for current sample statistics.
860 * @action Action expected from current function.
861 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
862 * flag indicating that a restart record has been previously
863 * found (.@restart), and time used for the X axis origin
865 * @itv Interval of time in jiffies (only with F_MAIN action).
866 * @record_hdr Pointer on record header of current stats sample.
867 ***************************************************************************
869 __print_funct_t svg_print_cpu_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
870 unsigned long long g_itv, struct record_header *record_hdr)
872 struct stats_cpu *scc, *scp;
875 char *title[] = {"CPU load"};
876 char *g_title1[] = {"%user", "%nice", "%system", "%iowait", "%steal", "%idle"};
877 char *g_title2[] = {"%usr", "%nice", "%sys", "%iowait", "%steal", "%irq", "%soft", "%guest", "%gnice", "%idle"};
878 static double *spmin, *spmax;
883 int i, j, k, pos, cpu_offline;
885 if (action & F_BEGIN) {
887 * Allocate arrays that will contain the graphs data
888 * and the min/max values.
890 out = allocate_graph_lines(10 * a->nr, &outsize, &spmin, &spmax);
893 if (action & F_MAIN) {
895 for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
897 scc = (struct stats_cpu *) ((char *) a->buf[curr] + i * a->msize);
898 scp = (struct stats_cpu *) ((char *) a->buf[!curr] + i * a->msize);
900 /* Should current CPU (including CPU "all") be displayed? */
901 if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
908 if (i) { /* Don't test CPU "all" here */
910 * If the CPU is offline then it is omited from /proc/stat:
911 * All the fields couldn't have been read and the sum of them is zero.
912 * (Remember that guest/guest_nice times are already included in
915 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
916 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
917 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
919 * Set current struct fields (which have been set to zero)
920 * to values from previous iteration. Hence their values won't
921 * jump from zero when the CPU comes back online.
930 * Recalculate interval for current proc.
931 * If result is 0 then current CPU is a tickless one.
933 g_itv = get_per_cpu_interval(scc, scp);
937 if (!g_itv) { /* Current CPU is offline or tickless */
939 val = (cpu_offline ? 0.0 /* Offline CPU: %idle = 0% */
940 : 100.0); /* Tickless CPU: %idle = 100% */
942 if (DISPLAY_CPU_DEF(a->opt_flags)) {
945 else { /* DISPLAY_CPU_ALL(a->opt_flags) */
949 /* Check min/max values for %user, etc. */
950 for (k = 0; k < j; k++) {
951 if (0.0 < *(spmin + pos + k)) {
952 *(spmin + pos + k) = 0.0;
954 if (0.0 > *(spmax + pos + k)) {
955 *(spmax + pos + k) = 0.0;
960 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
962 out + pos + j, outsize + pos + j, svg_p->dt,
963 spmin + pos + j, spmax + pos + j);
968 if (DISPLAY_CPU_DEF(a->opt_flags)) {
970 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
971 &offset, ll_sp_value(scp->cpu_user, scc->cpu_user, g_itv),
972 out + pos, outsize + pos, svg_p->dt,
973 spmin + pos, spmax + pos);
977 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
979 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
981 ll_sp_value(scp->cpu_user - scp->cpu_guest,
982 scc->cpu_user - scc->cpu_guest, g_itv),
983 out + pos, outsize + pos, svg_p->dt,
984 spmin + pos, spmax + pos);
987 if (DISPLAY_CPU_DEF(a->opt_flags)) {
989 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
990 &offset, ll_sp_value(scp->cpu_nice, scc->cpu_nice, g_itv),
991 out + pos + 1, outsize + pos + 1, svg_p->dt,
992 spmin + pos + 1, spmax + pos + 1);
996 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
998 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
1000 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
1001 scc->cpu_nice - scc->cpu_guest_nice, g_itv),
1002 out + pos + 1, outsize + pos + 1, svg_p->dt,
1003 spmin + pos + 1, spmax + pos + 1);
1006 if (DISPLAY_CPU_DEF(a->opt_flags)) {
1008 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1010 ll_sp_value(scp->cpu_sys + scp->cpu_hardirq + scp->cpu_softirq,
1011 scc->cpu_sys + scc->cpu_hardirq + scc->cpu_softirq,
1013 out + pos + 2, outsize + pos + 2, svg_p->dt,
1014 spmin + pos + 2, spmax + pos + 2);
1018 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1019 &offset, ll_sp_value(scp->cpu_sys, scc->cpu_sys, g_itv),
1020 out + pos + 2, outsize + pos + 2, svg_p->dt,
1021 spmin + pos + 2, spmax + pos + 2);
1025 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1026 &offset, ll_sp_value(scp->cpu_iowait, scc->cpu_iowait, g_itv),
1027 out + pos + 3, outsize + pos + 3, svg_p->dt,
1028 spmin + pos + 3, spmax + pos + 3);
1031 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1032 &offset, ll_sp_value(scp->cpu_steal, scc->cpu_steal, g_itv),
1033 out + pos + 4, outsize + pos + 4, svg_p->dt,
1034 spmin + pos + 4, spmax + pos + 4);
1036 if (DISPLAY_CPU_ALL(a->opt_flags)) {
1038 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1039 &offset, ll_sp_value(scp->cpu_hardirq, scc->cpu_hardirq, g_itv),
1040 out + pos + 5, outsize + pos + 5, svg_p->dt,
1041 spmin + pos + 5, spmax + pos + 5);
1044 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1045 &offset, ll_sp_value(scp->cpu_softirq, scc->cpu_softirq, g_itv),
1046 out + pos + 6, outsize + pos + 6, svg_p->dt,
1047 spmin + pos + 6, spmax + pos + 6);
1050 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1051 &offset, ll_sp_value(scp->cpu_guest, scc->cpu_guest, g_itv),
1052 out + pos + 7, outsize + pos + 7, svg_p->dt,
1053 spmin + pos + 7, spmax + pos + 7);
1056 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1057 &offset, ll_sp_value(scp->cpu_guest_nice, scc->cpu_guest_nice, g_itv),
1058 out + pos + 8, outsize + pos + 8, svg_p->dt,
1059 spmin + pos + 8, spmax + pos + 8);
1068 cpuappend(record_hdr->ust_time - svg_p->ust_time_ref,
1070 (scc->cpu_idle < scp->cpu_idle ? 0.0 :
1071 ll_sp_value(scp->cpu_idle, scc->cpu_idle, g_itv)),
1072 out + pos + j, outsize + pos + j, svg_p->dt,
1073 spmin + pos + j, spmax + pos + j);
1077 if (action & F_END) {
1078 for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
1080 /* Should current CPU (including CPU "all") be displayed? */
1081 if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
1087 /* This is CPU "all" */
1088 strcpy(item_name, "all");
1091 sprintf(item_name, "%d", i - 1);
1094 if (DISPLAY_CPU_DEF(a->opt_flags)) {
1095 draw_activity_graphs(a->g_nr, SVG_BAR_GRAPH,
1096 title, g_title1, item_name, group1,
1097 spmin + pos, spmax + pos, out + pos, outsize + pos,
1101 draw_activity_graphs(a->g_nr, SVG_BAR_GRAPH,
1102 title, g_title2, item_name, group2,
1103 spmin + pos, spmax + pos, out + pos, outsize + pos,
1108 /* Free remaining structures */
1109 free_graphs(out, outsize, spmin, spmax);
1114 ***************************************************************************
1115 * Display task creation and context switch statistics in SVG.
1118 * @a Activity structure with statistics.
1119 * @curr Index in array for current sample statistics.
1120 * @action Action expected from current function.
1121 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1122 * flag indicating that a restart record has been previously
1123 * found (.@restart) and time used for the X axis origin
1125 * @itv Interval of time in jiffies (only with F_MAIN action).
1126 * @record_hdr Pointer on record header of current stats sample.
1127 ***************************************************************************
1129 __print_funct_t svg_print_pcsw_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1130 unsigned long long itv, struct record_header *record_hdr)
1133 *spc = (struct stats_pcsw *) a->buf[curr],
1134 *spp = (struct stats_pcsw *) a->buf[!curr];
1135 int group[] = {1, 1};
1136 char *title[] = {"Switching activity", "Task creation"};
1137 char *g_title[] = {"cswch/s",
1139 static double *spmin, *spmax;
1141 static int *outsize;
1143 if (action & F_BEGIN) {
1145 * Allocate arrays that will contain the graphs data
1146 * and the min/max values.
1148 out = allocate_graph_lines(2, &outsize, &spmin, &spmax);
1151 if (action & F_MAIN) {
1152 /* Check for min/max values */
1153 save_extrema(1, 1, 0, (void *) a->buf[curr], (void *) a->buf[!curr],
1156 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1157 S_VALUE(spp->context_switch, spc->context_switch, itv),
1158 out, outsize, svg_p->restart);
1160 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1161 S_VALUE(spp->processes, spc->processes, itv),
1162 out + 1, outsize + 1, svg_p->restart);
1165 if (action & F_END) {
1166 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
1167 spmin, spmax, out, outsize, svg_p, record_hdr);
1169 /* Free remaining structures */
1170 free_graphs(out, outsize, spmin, spmax);
1175 ***************************************************************************
1176 * Display swap statistics in SVG.
1179 * @a Activity structure with statistics.
1180 * @curr Index in array for current sample statistics.
1181 * @action Action expected from current function.
1182 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1183 * flag indicating that a restart record has been previously
1184 * found (.@restart) and time used for the X axis origin
1186 * @itv Interval of time in jiffies (only with F_MAIN action).
1187 * @record_hdr Pointer on record header of current stats sample.
1188 ***************************************************************************
1190 __print_funct_t svg_print_swap_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1191 unsigned long long itv, struct record_header *record_hdr)
1194 *ssc = (struct stats_swap *) a->buf[curr],
1195 *ssp = (struct stats_swap *) a->buf[!curr];
1197 char *title[] = {"Swap activity"};
1198 char *g_title[] = {"pswpin/s", "pswpout/s" };
1199 static double *spmin, *spmax;
1201 static int *outsize;
1203 if (action & F_BEGIN) {
1205 * Allocate arrays that will contain the graphs data
1206 * and the min/max values.
1208 out = allocate_graph_lines(2, &outsize, &spmin, &spmax);
1211 if (action & F_MAIN) {
1212 /* Check for min/max values */
1213 save_extrema(0, 2, 0, (void *) a->buf[curr], (void *) a->buf[!curr],
1216 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1217 S_VALUE(ssp->pswpin, ssc->pswpin, itv),
1218 out, outsize, svg_p->restart);
1220 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1221 S_VALUE(ssp->pswpout, ssc->pswpout, itv),
1222 out + 1, outsize + 1, svg_p->restart);
1225 if (action & F_END) {
1226 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
1227 spmin, spmax, out, outsize, svg_p, record_hdr);
1229 /* Free remaining structures */
1230 free_graphs(out, outsize, spmin, spmax);
1235 ***************************************************************************
1236 * Display paging statistics in SVG.
1239 * @a Activity structure with statistics.
1240 * @curr Index in array for current sample statistics.
1241 * @action Action expected from current function.
1242 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1243 * flag indicating that a restart record has been previously
1244 * found (.@restart) and time used for the X axis origin
1246 * @itv Interval of time in jiffies (only with F_MAIN action).
1247 * @record_hdr Pointer on record header of current stats sample.
1248 ***************************************************************************
1250 __print_funct_t svg_print_paging_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1251 unsigned long long itv, struct record_header *record_hdr)
1254 *spc = (struct stats_paging *) a->buf[curr],
1255 *spp = (struct stats_paging *) a->buf[!curr];
1256 int group[] = {2, 2, 4};
1257 char *title[] = {"Paging activity (1)", "Paging activity (2)", "Paging activity (3)"};
1258 char *g_title[] = {"pgpgin/s", "pgpgout/s",
1259 "fault/s", "majflt/s",
1260 "pgfree/s", "pgscank/s", "pgscand/s", "pgsteal/s"};
1261 static double *spmin, *spmax;
1263 static int *outsize;
1265 if (action & F_BEGIN) {
1267 * Allocate arrays that will contain the graphs data
1268 * and the min/max values.
1270 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
1273 if (action & F_MAIN) {
1274 /* Check for min/max values */
1275 save_extrema(0, 8, 0, (void *) a->buf[curr], (void *) a->buf[!curr],
1278 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1279 S_VALUE(spp->pgpgin, spc->pgpgin, itv),
1280 out, outsize, svg_p->restart);
1282 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1283 S_VALUE(spp->pgpgout, spc->pgpgout, itv),
1284 out + 1, outsize + 1, svg_p->restart);
1286 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1287 S_VALUE(spp->pgfault, spc->pgfault, itv),
1288 out + 2, outsize + 2, svg_p->restart);
1290 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1291 S_VALUE(spp->pgmajfault, spc->pgmajfault, itv),
1292 out + 3, outsize + 3, svg_p->restart);
1294 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1295 S_VALUE(spp->pgfree, spc->pgfree, itv),
1296 out + 4, outsize + 4, svg_p->restart);
1298 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1299 S_VALUE(spp->pgscan_kswapd, spc->pgscan_kswapd, itv),
1300 out + 5, outsize + 5, svg_p->restart);
1302 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1303 S_VALUE(spp->pgscan_direct, spc->pgscan_direct, itv),
1304 out + 6, outsize + 6, svg_p->restart);
1306 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1307 S_VALUE(spp->pgsteal, spc->pgsteal, itv),
1308 out + 7, outsize + 7, svg_p->restart);
1311 if (action & F_END) {
1312 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
1313 spmin, spmax, out, outsize, svg_p, record_hdr);
1315 /* Free remaining structures */
1316 free_graphs(out, outsize, spmin, spmax);
1321 ***************************************************************************
1322 * Display I/O and transfer rate statistics in SVG.
1325 * @a Activity structure with statistics.
1326 * @curr Index in array for current sample statistics.
1327 * @action Action expected from current function.
1328 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1329 * flag indicating that a restart record has been previously
1330 * found (.@restart) and time used for the X axis origin
1332 * @itv Interval of time in jiffies (only with F_MAIN action).
1333 * @record_hdr Pointer on record header of current stats sample.
1334 ***************************************************************************
1336 __print_funct_t svg_print_io_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1337 unsigned long long itv, struct record_header *record_hdr)
1340 *sic = (struct stats_io *) a->buf[curr],
1341 *sip = (struct stats_io *) a->buf[!curr];
1342 int group[] = {3, 2};
1343 char *title[] = {"I/O and transfer rate statistics (1)", "I/O and transfer rate statistics (2)"};
1344 char *g_title[] = {"tps", "rtps", "wtps",
1345 "bread/s", "bwrtn/s"};
1346 static double *spmin, *spmax;
1348 static int *outsize;
1350 if (action & F_BEGIN) {
1352 * Allocate arrays that will contain the graphs data
1353 * and the min/max values.
1355 out = allocate_graph_lines(5, &outsize, &spmin, &spmax);
1358 if (action & F_MAIN) {
1359 /* Check for min/max values */
1360 save_extrema(0, 5, 0, (void *) a->buf[curr], (void *) a->buf[!curr],
1364 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1365 S_VALUE(sip->dk_drive, sic->dk_drive, itv),
1366 out, outsize, svg_p->restart);
1368 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1369 S_VALUE(sip->dk_drive_rio, sic->dk_drive_rio, itv),
1370 out + 1, outsize + 1, svg_p->restart);
1372 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1373 S_VALUE(sip->dk_drive_wio, sic->dk_drive_wio, itv),
1374 out + 2, outsize + 2, svg_p->restart);
1376 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1377 S_VALUE(sip->dk_drive_rblk, sic->dk_drive_rblk, itv),
1378 out + 3, outsize + 3, svg_p->restart);
1380 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1381 S_VALUE(sip->dk_drive_wblk, sic->dk_drive_wblk, itv),
1382 out + 4, outsize + 4, svg_p->restart);
1385 if (action & F_END) {
1386 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
1387 spmin, spmax, out, outsize, svg_p, record_hdr);
1389 /* Free remaining structures */
1390 free_graphs(out, outsize, spmin, spmax);
1395 ***************************************************************************
1396 * Display memory statistics in SVG.
1399 * @a Activity structure with statistics.
1400 * @curr Index in array for current sample statistics.
1401 * @action Action expected from current function.
1402 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1403 * flag indicating that a restart record has been previously
1404 * found (.@restart) and time used for the X axis origin
1406 * @itv Interval of time in jiffies (only with F_MAIN action).
1407 * @record_hdr Pointer on record header of current stats sample.
1408 ***************************************************************************
1410 __print_funct_t svg_print_memory_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1411 unsigned long long itv, struct record_header *record_hdr)
1414 *smc = (struct stats_memory *) a->buf[curr];
1415 int group1a[] = {2, 2};
1416 int group1b[] = {1, 1};
1417 int group1c[] = {4, 5};
1418 int group2a[] = {3};
1419 int group2b[] = {1, 1};
1420 char *title1a[] = {"Memory utilization (1)", "Memory utilization (2)"};
1421 char *title1b[] = {"Memory utilization (3)", "Memory utilization (4)"};
1422 char *title1c[] = {"Memory utilization (5)", "Memory utilization (6)"};
1423 char *title2a[] = {"Swap utilization (1)"};
1424 char *title2b[] = {"Swap utilization (2)", "Swap utilization (3)"};
1425 char *g_title1a[] = {"MBmemfree", "MBmemused",
1426 "MBcached", "MBbuffers"};
1427 char *g_title1b[] = {"%memused", "%commit"};
1428 char *g_title1c[] = {"MBcommit", "MBactive", "MBinact", "MBdirty",
1429 "MBanonpg", "MBslab", "MBkstack", "MBpgtbl", "MBvmused"};
1430 char *g_title2a[] = {"MBswpfree", "MBswpused", "MBswpcad"};
1431 char *g_title2b[] = {"%swpused", "%swpcad"};
1432 static double *spmin, *spmax;
1434 static int *outsize;
1438 if (action & F_BEGIN) {
1440 * Allocate arrays that will contain the graphs data
1441 * and the min/max values.
1443 out = allocate_graph_lines(22, &outsize, &spmin, &spmax);
1446 if (action & F_MAIN) {
1447 /* Check for min/max values */
1448 save_extrema(0, 16, 0, (void *) a->buf[curr], NULL,
1450 /* Compute %memused min/max values */
1451 tval = smc->tlmkb ? SP_VALUE(smc->frmkb, smc->tlmkb, smc->tlmkb) : 0.0;
1452 if (tval > *(spmax + 16)) {
1453 *(spmax + 16) = tval;
1455 if (tval < *(spmin + 16)) {
1456 *(spmin + 16) = tval;
1458 /* Compute %commit min/max values */
1459 tval = (smc->tlmkb + smc->tlskb) ?
1460 SP_VALUE(0, smc->comkb, smc->tlmkb + smc->tlskb) : 0.0;
1461 if (tval > *(spmax + 17)) {
1462 *(spmax + 17) = tval;
1464 if (tval < *(spmin + 17)) {
1465 *(spmin + 17) = tval;
1467 /* Compute %swpused min/max values */
1469 SP_VALUE(smc->frskb, smc->tlskb, smc->tlskb) : 0.0;
1470 if (tval > *(spmax + 18)) {
1471 *(spmax + 18) = tval;
1473 if (tval < *(spmin + 18)) {
1474 *(spmin + 18) = tval;
1476 /* Compute %swpcad min/max values */
1477 tval = (smc->tlskb - smc->frskb) ?
1478 SP_VALUE(0, smc->caskb, smc->tlskb - smc->frskb) : 0.0;
1479 if (tval > *(spmax + 19)) {
1480 *(spmax + 19) = tval;
1482 if (tval < *(spmin + 19)) {
1483 *(spmin + 19) = tval;
1485 /* Compute memused min/max values in MB */
1486 tval = ((double) (smc->tlmkb - smc->frmkb)) / 1024;
1487 if (tval > *(spmax + 20)) {
1488 *(spmax + 20) = tval;
1490 if (tval < *(spmin + 20)) {
1491 *(spmin + 20) = tval;
1493 /* Compute swpused min/max values in MB */
1494 tval = ((double) (smc->tlskb - smc->frskb)) / 1024;
1495 if (tval > *(spmax + 21)) {
1496 *(spmax + 21) = tval;
1498 if (tval < *(spmin + 21)) {
1499 *(spmin + 21) = tval;
1503 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1504 ((double) smc->frmkb) / 1024,
1505 out, outsize, svg_p->restart);
1507 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1508 ((double) (smc->tlmkb - smc->frmkb)) / 1024,
1509 out + 1, outsize + 1, svg_p->restart);
1511 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1512 ((double) smc->camkb) / 1024,
1513 out + 2, outsize + 2, svg_p->restart);
1515 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1516 ((double) smc->bufkb) / 1024,
1517 out + 3, outsize + 3, svg_p->restart);
1519 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1520 ((double) smc->frskb) / 1024,
1521 out + 4, outsize + 4, svg_p->restart);
1523 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1524 ((double) (smc->tlskb - smc->frskb)) / 1024,
1525 out + 5, outsize + 5, svg_p->restart);
1527 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1528 ((double) smc->caskb) / 1024,
1529 out + 6, outsize + 6, svg_p->restart);
1531 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1532 ((double) smc->comkb) / 1024,
1533 out + 7, outsize + 7, svg_p->restart);
1535 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1536 ((double) smc->activekb) / 1024,
1537 out + 8, outsize + 8, svg_p->restart);
1539 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1540 ((double) smc->inactkb) / 1024,
1541 out + 9, outsize + 9, svg_p->restart);
1543 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1544 ((double) smc->dirtykb) / 1024,
1545 out + 10, outsize + 10, svg_p->restart);
1547 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1548 ((double) smc->anonpgkb) / 1024,
1549 out + 11, outsize + 11, svg_p->restart);
1551 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1552 ((double) smc->slabkb) / 1024,
1553 out + 12, outsize + 12, svg_p->restart);
1555 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1556 ((double) smc->kstackkb) / 1024,
1557 out + 13, outsize + 13, svg_p->restart);
1559 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1560 ((double) smc->pgtblkb) / 1024,
1561 out + 14, outsize + 14, svg_p->restart);
1563 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1564 ((double) smc->vmusedkb) / 1024,
1565 out + 15, outsize + 15, svg_p->restart);
1567 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1570 SP_VALUE(smc->frmkb, smc->tlmkb, smc->tlmkb) : 0.0,
1571 out + 16, outsize + 16, svg_p->dt);
1573 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1575 (smc->tlmkb + smc->tlskb) ?
1576 SP_VALUE(0, smc->comkb, smc->tlmkb + smc->tlskb) : 0.0,
1577 out + 17, outsize + 17, svg_p->dt);
1579 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1582 SP_VALUE(smc->frskb, smc->tlskb, smc->tlskb) : 0.0,
1583 out + 18, outsize + 18, svg_p->dt);
1585 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1587 (smc->tlskb - smc->frskb) ?
1588 SP_VALUE(0, smc->caskb, smc->tlskb - smc->frskb) : 0.0,
1589 out + 19, outsize + 19, svg_p->dt);
1592 if (action & F_END) {
1594 /* Conversion kB -> MB */
1595 for (i = 0; i < 16; i++) {
1596 *(spmin + i) /= 1024;
1597 *(spmax + i) /= 1024;
1600 if (DISPLAY_MEM_AMT(a->opt_flags)) {
1601 /* frmkb and tlmkb should be together because they will be drawn on the same view */
1602 *(spmax + 3) = *(spmax + 1);
1603 *(spmin + 3) = *(spmin + 1);
1604 /* Move memused min/max values */
1605 *(spmax + 1) = *(spmax + 20);
1606 *(spmin + 1) = *(spmin + 20);
1608 draw_activity_graphs(2, SVG_LINE_GRAPH, title1a, g_title1a, NULL, group1a,
1609 spmin, spmax, out, outsize, svg_p, record_hdr);
1610 draw_activity_graphs(2, SVG_BAR_GRAPH, title1b, g_title1b, NULL, group1b,
1611 spmin + 16, spmax + 16, out + 16, outsize + 16, svg_p, record_hdr);
1612 draw_activity_graphs(DISPLAY_MEM_ALL(a->opt_flags) ? 2 : 1,
1613 SVG_LINE_GRAPH, title1c, g_title1c, NULL, group1c,
1614 spmin + 7, spmax + 7, out + 7, outsize + 7, svg_p, record_hdr);
1617 if (DISPLAY_SWAP(a->opt_flags)) {
1618 /* Move swpused min/max values */
1619 *(spmax + 5) = *(spmax + 21);
1620 *(spmin + 5) = *(spmin + 21);
1622 draw_activity_graphs(1, SVG_LINE_GRAPH, title2a, g_title2a, NULL, group2a,
1623 spmin + 4, spmax + 4, out + 4, outsize + 4, svg_p, record_hdr);
1624 draw_activity_graphs(2, SVG_BAR_GRAPH, title2b, g_title2b, NULL, group2b,
1625 spmin + 18, spmax + 18, out + 18, outsize + 18, svg_p, record_hdr);
1628 /* Free remaining structures */
1629 free_graphs(out, outsize, spmin, spmax);
1634 ***************************************************************************
1635 * Display kernel tables statistics in SVG.
1638 * @a Activity structure with statistics.
1639 * @curr Index in array for current sample statistics.
1640 * @action Action expected from current function.
1641 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1642 * flag indicating that a restart record has been previously
1643 * found (.@restart) and time used for the X axis origin
1645 * @itv Interval of time in jiffies (only with F_MAIN action).
1646 * @record_hdr Pointer on record header of current stats sample.
1647 ***************************************************************************
1649 __print_funct_t svg_print_ktables_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1650 unsigned long long itv, struct record_header *record_hdr)
1652 struct stats_ktables
1653 *skc = (struct stats_ktables *) a->buf[curr];
1654 int group[] = {3, 1};
1655 char *title[] = {"Kernel tables (1)", "Kernel tables (2)"};
1656 char *g_title[] = {"~file-nr", "~inode-nr", "~dentunusd",
1658 static double *spmin, *spmax;
1660 static int *outsize;
1662 if (action & F_BEGIN) {
1664 * Allocate arrays that will contain the graphs data
1665 * and the min/max values.
1667 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
1670 if (action & F_MAIN) {
1671 /* Check for min/max values */
1672 save_extrema(0, 0, 4, (void *) a->buf[curr], NULL,
1675 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1676 (unsigned long) skc->file_used,
1677 out, outsize, svg_p->restart);
1679 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1680 (unsigned long) skc->inode_used,
1681 out + 1, outsize + 1, svg_p->restart);
1683 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1684 (unsigned long) skc->dentry_stat,
1685 out + 2, outsize + 2, svg_p->restart);
1687 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1688 (unsigned long) skc->pty_nr,
1689 out + 3, outsize + 3, svg_p->restart);
1692 if (action & F_END) {
1693 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
1694 spmin, spmax, out, outsize, svg_p, record_hdr);
1696 /* Free remaining structures */
1697 free_graphs(out, outsize, spmin, spmax);
1702 ***************************************************************************
1703 * Display queue and load statistics in SVG.
1706 * @a Activity structure with statistics.
1707 * @curr Index in array for current sample statistics.
1708 * @action Action expected from current function.
1709 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1710 * flag indicating that a restart record has been previously
1711 * found (.@restart) and time used for the X axis origin
1713 * @itv Interval of time in jiffies (only with F_MAIN action).
1714 * @record_hdr Pointer on record header of current stats sample.
1715 ***************************************************************************
1717 __print_funct_t svg_print_queue_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1718 unsigned long long itv, struct record_header *record_hdr)
1721 *sqc = (struct stats_queue *) a->buf[curr];
1722 int group[] = {2, 3, 1};
1723 char *title[] = {"Queue length", "Load average", "Task list"};
1724 char *g_title[] = {"~runq-sz", "~blocked",
1725 "ldavg-1", "ldavg-5", "ldavg-15",
1727 static double *spmin, *spmax;
1729 static int *outsize;
1731 if (action & F_BEGIN) {
1733 * Allocate arrays that will contain the graphs data
1734 * and the min/max values.
1736 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
1739 if (action & F_MAIN) {
1740 /* Check for min/max values */
1741 save_extrema(0, 2, 4, (void *) a->buf[curr], NULL,
1744 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1745 (unsigned long) sqc->nr_running,
1746 out, outsize, svg_p->restart);
1748 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1749 (unsigned long) sqc->procs_blocked,
1750 out + 1, outsize + 1, svg_p->restart);
1752 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1753 (double) sqc->load_avg_1 / 100,
1754 out + 2, outsize + 2, svg_p->restart);
1756 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1757 (double) sqc->load_avg_5 / 100,
1758 out + 3, outsize + 3, svg_p->restart);
1760 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1761 (double) sqc->load_avg_15 / 100,
1762 out + 4, outsize + 4, svg_p->restart);
1764 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
1765 (unsigned long) sqc->nr_threads,
1766 out + 5, outsize + 5, svg_p->restart);
1769 if (action & F_END) {
1770 /* Fix min/max values for load average */
1771 *(spmin + 2) /= 100; *(spmax + 2) /= 100;
1772 *(spmin + 3) /= 100; *(spmax + 3) /= 100;
1773 *(spmin + 4) /= 100; *(spmax + 4) /= 100;
1775 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
1776 spmin, spmax, out, outsize, svg_p, record_hdr);
1778 /* Free remaining structures */
1779 free_graphs(out, outsize, spmin, spmax);
1784 ***************************************************************************
1785 * Display network interfaces statistics in SVG.
1788 * @a Activity structure with statistics.
1789 * @curr Index in array for current sample statistics.
1790 * @action Action expected from current function.
1791 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1792 * flag indicating that a restart record has been previously
1793 * found (.@restart) and time used for the X axis origin
1795 * @itv Interval of time in jiffies (only with F_MAIN action).
1796 * @record_hdr Pointer on record header of current stats sample.
1797 ***************************************************************************
1799 __print_funct_t svg_print_net_dev_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
1800 unsigned long long itv, struct record_header *record_hdr)
1802 struct stats_net_dev *sndc, *sndp;
1803 int group1[] = {2, 2, 3};
1805 char *title1[] = {"Network statistics (1)", "Network statistics (2)",
1806 "Network statistics (3)"};
1807 char *title2[] = {"Network statistics (4)"};
1808 char *g_title1[] = {"rxpck/s", "txpck/s",
1810 "rxcmp/s", "txcmp/s", "rxmcst/s"};
1811 char *g_title2[] = {"%ifutil"};
1812 static double *spmin, *spmax;
1814 static int *outsize;
1816 double rxkb, txkb, ifutil;
1817 int i, j, k, pos, restart, *unregistered;
1819 if (action & F_BEGIN) {
1821 * Allocate arrays (#0..7) that will contain the graphs data
1822 * and the min/max values.
1823 * Also allocate one additional array (#8) for each interface:
1824 * out + 8 will contain the interface name,
1825 * outsize + 8 will contain a positive value (TRUE) if the interface
1826 * has either still not been registered, or has been unregistered.
1828 out = allocate_graph_lines(9 * a->nr, &outsize, &spmin, &spmax);
1831 if (action & F_MAIN) {
1832 restart = svg_p->restart;
1834 * Mark previously registered interfaces as now
1835 * possibly unregistered for all graphs.
1837 for (k = 0; k < a->nr; k++) {
1838 unregistered = outsize + k * 9 + 8;
1839 if (*unregistered == FALSE) {
1840 *unregistered = MAYBE;
1844 /* For each network interfaces structure */
1845 for (i = 0; i < a->nr; i++) {
1846 sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
1847 if (!strcmp(sndc->interface, ""))
1848 /* Empty structure: Ignore it */
1851 /* Look for corresponding graph */
1852 for (k = 0; k < a->nr; k++) {
1853 item_name = *(out + k * 9 + 8);
1854 if (!strcmp(sndc->interface, item_name))
1859 /* Graph not found: Look for first free entry */
1860 for (k = 0; k < a->nr; k++) {
1861 item_name = *(out + k * 9 + 8);
1862 if (!strcmp(item_name, ""))
1866 /* No free graph entry: Graph for this item won't be drawn */
1871 unregistered = outsize + pos + 8;
1873 j = check_net_dev_reg(a, curr, !curr, i);
1874 sndp = (struct stats_net_dev *) ((char *) a->buf[!curr] + j * a->msize);
1877 * If current interface was marked as previously unregistered,
1878 * then set restart variable to TRUE so that the graph will be
1879 * discontinuous, and mark it as now registered.
1881 if (*unregistered == TRUE) {
1884 *unregistered = FALSE;
1886 if (!item_name[0]) {
1887 /* Save network interface name (if not already done) */
1888 strncpy(item_name, sndc->interface, CHUNKSIZE);
1889 item_name[CHUNKSIZE - 1] = '\0';
1892 /* Check for min/max values */
1893 save_extrema(7, 0, 0, (void *) sndc, (void *) sndp,
1894 itv, spmin + pos, spmax + pos);
1896 rxkb = S_VALUE(sndp->rx_bytes, sndc->rx_bytes, itv);
1897 txkb = S_VALUE(sndp->tx_bytes, sndc->tx_bytes, itv);
1898 ifutil = compute_ifutil(sndc, rxkb, txkb);
1899 if (ifutil < *(spmin + pos + 7)) {
1900 *(spmin + pos + 7) = ifutil;
1902 if (ifutil > *(spmax + pos + 7)) {
1903 *(spmax + pos + 7) = ifutil;
1907 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1908 S_VALUE(sndp->rx_packets, sndc->rx_packets, itv),
1909 out + pos, outsize + pos, restart);
1912 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1913 S_VALUE(sndp->tx_packets, sndc->tx_packets, itv),
1914 out + pos + 1, outsize + pos + 1, restart);
1917 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1919 out + pos + 2, outsize + pos + 2, restart);
1922 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1924 out + pos + 3, outsize + pos + 3, restart);
1927 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1928 S_VALUE(sndp->rx_compressed, sndc->rx_compressed, itv),
1929 out + pos + 4, outsize + pos + 4, restart);
1932 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1933 S_VALUE(sndp->tx_compressed, sndc->tx_compressed, itv),
1934 out + pos + 5, outsize + pos + 5, restart);
1937 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
1938 S_VALUE(sndp->multicast, sndc->multicast, itv),
1939 out + pos + 6, outsize + pos + 6, restart);
1942 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
1944 out + pos + 7, outsize + pos + 7, svg_p->dt);
1947 /* Mark interfaces not seen here as now unregistered */
1948 for (k = 0; k < a->nr; k++) {
1949 unregistered = outsize + k * 9 + 8;
1950 if (*unregistered != FALSE) {
1951 *unregistered = TRUE;
1956 if (action & F_END) {
1957 for (i = 0; i < a->nr; i++) {
1959 * Check if there is something to display.
1960 * Don't test sndc->interface because maybe the network
1961 * interface has been registered later.
1967 /* Recalculate min and max values in kB, not in B */
1968 *(spmin + pos + 2) /= 1024;
1969 *(spmax + pos + 2) /= 1024;
1970 *(spmin + pos + 3) /= 1024;
1971 *(spmax + pos + 3) /= 1024;
1973 item_name = *(out + pos + 8);
1974 draw_activity_graphs(a->g_nr - 1, SVG_LINE_GRAPH,
1975 title1, g_title1, item_name, group1,
1976 spmin + pos, spmax + pos, out + pos, outsize + pos,
1978 draw_activity_graphs(1, SVG_BAR_GRAPH,
1979 title2, g_title2, item_name, group2,
1980 spmin + pos + 7, spmax + pos + 7, out + pos + 7, outsize + pos + 7,
1984 /* Free remaining structures */
1985 free_graphs(out, outsize, spmin, spmax);
1990 ***************************************************************************
1991 * Display network socket statistics in SVG.
1994 * @a Activity structure with statistics.
1995 * @curr Index in array for current sample statistics.
1996 * @action Action expected from current function.
1997 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
1998 * flag indicating that a restart record has been previously
1999 * found (.@restart) and time used for the X axis origin
2001 * @itv Interval of time in jiffies (only with F_MAIN action).
2002 * @record_hdr Pointer on record header of current stats sample.
2003 ***************************************************************************
2005 __print_funct_t svg_print_net_sock_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2006 unsigned long long itv, struct record_header *record_hdr)
2008 struct stats_net_sock
2009 *snsc = (struct stats_net_sock *) a->buf[curr];
2010 int group[] = {1, 5};
2011 char *title[] = {"Network sockets (1)", "Network sockets (2)"};
2012 char *g_title[] = {"~totsck",
2013 "~tcpsck", "~tcp-tw", "~udpsck", "~rawsck", "~ip-frag"};
2014 static double *spmin, *spmax;
2016 static int *outsize;
2018 if (action & F_BEGIN) {
2020 * Allocate arrays that will contain the graphs data
2021 * and the min/max values.
2023 out = allocate_graph_lines(6, &outsize, &spmin, &spmax);
2026 if (action & F_MAIN) {
2027 /* Check for min/max values */
2028 save_extrema(0, 0, 6, (void *) a->buf[curr], NULL,
2031 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2032 (unsigned long) snsc->sock_inuse,
2033 out, outsize, svg_p->restart);
2035 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2036 (unsigned long) snsc->tcp_inuse,
2037 out + 1, outsize + 1, svg_p->restart);
2039 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2040 (unsigned long) snsc->tcp_tw,
2041 out + 2, outsize + 2, svg_p->restart);
2043 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2044 (unsigned long) snsc->udp_inuse,
2045 out + 3, outsize + 3, svg_p->restart);
2047 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2048 (unsigned long) snsc->raw_inuse,
2049 out + 4, outsize + 4, svg_p->restart);
2051 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2052 (unsigned long) snsc->frag_inuse,
2053 out + 5, outsize + 5, svg_p->restart);
2056 if (action & F_END) {
2057 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
2058 spmin, spmax, out, outsize, svg_p, record_hdr);
2060 /* Free remaining structures */
2061 free_graphs(out, outsize, spmin, spmax);
2066 ***************************************************************************
2067 * Display IPv4 network statistics in SVG.
2070 * @a Activity structure with statistics.
2071 * @curr Index in array for current sample statistics.
2072 * @action Action expected from current function.
2073 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
2074 * flag indicating that a restart record has been previously
2075 * found (.@restart) and time used for the X axis origin
2077 * @itv Interval of time in jiffies (only with F_MAIN action).
2078 * @record_hdr Pointer on record header of current stats sample.
2079 ***************************************************************************
2081 __print_funct_t svg_print_net_ip_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2082 unsigned long long itv, struct record_header *record_hdr)
2085 *snic = (struct stats_net_ip *) a->buf[curr],
2086 *snip = (struct stats_net_ip *) a->buf[!curr];
2087 int group[] = {4, 2, 2};
2088 char *title[] = {"IPv4 network statistics (1)", "IPv4 network statistics (2)", "IPv4 network statistics (3)"};
2089 char *g_title[] = {"irec/s", "fwddgm/s", "idel/s", "orq/s",
2090 "asmrq/s", "asmok/s",
2091 "fragok/s", "fragcrt/s"};
2092 static double *spmin, *spmax;
2094 static int *outsize;
2096 if (action & F_BEGIN) {
2098 * Allocate arrays that will contain the graphs data
2099 * and the min/max values.
2101 out = allocate_graph_lines(8, &outsize, &spmin, &spmax);
2104 if (action & F_MAIN) {
2105 /* Check for min/max values */
2106 save_extrema(8, 0, 0, (void *) a->buf[curr], (void *) a->buf[!curr],
2110 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2111 S_VALUE(snip->InReceives, snic->InReceives, itv),
2112 out, outsize, svg_p->restart);
2114 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2115 S_VALUE(snip->ForwDatagrams, snic->ForwDatagrams, itv),
2116 out + 1, outsize + 1, svg_p->restart);
2118 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2119 S_VALUE(snip->InDelivers, snic->InDelivers, itv),
2120 out + 2, outsize + 2, svg_p->restart);
2122 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2123 S_VALUE(snip->OutRequests, snic->OutRequests, itv),
2124 out + 3, outsize + 3, svg_p->restart);
2126 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2127 S_VALUE(snip->ReasmReqds, snic->ReasmReqds, itv),
2128 out + 4, outsize + 4, svg_p->restart);
2130 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2131 S_VALUE(snip->ReasmOKs, snic->ReasmOKs, itv),
2132 out + 5, outsize + 5, svg_p->restart);
2134 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2135 S_VALUE(snip->FragOKs, snic->FragOKs, itv),
2136 out + 6, outsize + 6, svg_p->restart);
2138 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2139 S_VALUE(snip->FragCreates, snic->FragCreates, itv),
2140 out + 7, outsize + 7, svg_p->restart);
2143 if (action & F_END) {
2144 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
2145 spmin, spmax, out, outsize, svg_p, record_hdr);
2147 /* Free remaining structures */
2148 free_graphs(out, outsize, spmin, spmax);
2153 ***************************************************************************
2154 * Display TCPv4 network statistics in SVG.
2157 * @a Activity structure with statistics.
2158 * @curr Index in array for current sample statistics.
2159 * @action Action expected from current function.
2160 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
2161 * flag indicating that a restart record has been previously
2162 * found (.@restart) and time used for the X axis origin
2164 * @itv Interval of time in jiffies (only with F_MAIN action).
2165 * @record_hdr Pointer on record header of current stats sample.
2166 ***************************************************************************
2168 __print_funct_t svg_print_net_tcp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2169 unsigned long long itv, struct record_header *record_hdr)
2171 struct stats_net_tcp
2172 *sntc = (struct stats_net_tcp *) a->buf[curr],
2173 *sntp = (struct stats_net_tcp *) a->buf[!curr];
2174 int group[] = {2, 2};
2175 char *title[] = {"TCPv4 network statistics (1)", "TCPv4 network statistics (2)"};
2176 char *g_title[] = {"active/s", "passive/s",
2177 "iseg/s", "oseg/s"};
2178 static double *spmin, *spmax;
2180 static int *outsize;
2182 if (action & F_BEGIN) {
2184 * Allocate arrays that will contain the graphs data
2185 * and the min/max values.
2187 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
2190 if (action & F_MAIN) {
2191 /* Check for min/max values */
2192 save_extrema(0, 4, 0, (void *) a->buf[curr], (void *) a->buf[!curr],
2196 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2197 S_VALUE(sntp->ActiveOpens, sntc->ActiveOpens, itv),
2198 out, outsize, svg_p->restart);
2200 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2201 S_VALUE(sntp->PassiveOpens, sntc->PassiveOpens, itv),
2202 out + 1, outsize + 1, svg_p->restart);
2204 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2205 S_VALUE(sntp->InSegs, sntc->InSegs, itv),
2206 out + 2, outsize + 2, svg_p->restart);
2208 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2209 S_VALUE(sntp->OutSegs, sntc->OutSegs, itv),
2210 out + 3, outsize + 3, svg_p->restart);
2213 if (action & F_END) {
2214 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
2215 spmin, spmax, out, outsize, svg_p, record_hdr);
2217 /* Free remaining structures */
2218 free_graphs(out, outsize, spmin, spmax);
2223 ***************************************************************************
2224 * Display UDPv4 network statistics in SVG.
2227 * @a Activity structure with statistics.
2228 * @curr Index in array for current sample statistics.
2229 * @action Action expected from current function.
2230 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
2231 * flag indicating that a restart record has been previously
2232 * found (.@restart) and time used for the X axis origin
2234 * @itv Interval of time in jiffies (only with F_MAIN action).
2235 * @record_hdr Pointer on record header of current stats sample.
2236 ***************************************************************************
2238 __print_funct_t svg_print_net_udp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2239 unsigned long long itv, struct record_header *record_hdr)
2241 struct stats_net_udp
2242 *snuc = (struct stats_net_udp *) a->buf[curr],
2243 *snup = (struct stats_net_udp *) a->buf[!curr];
2244 int group[] = {2, 2};
2245 char *title[] = {"UDPv4 network statistics (1)", "UDPv4 network statistics (2)"};
2246 char *g_title[] = {"idgm/s", "odgm/s",
2247 "noport/s", "idgmerr/s"};
2248 static double *spmin, *spmax;
2250 static int *outsize;
2252 if (action & F_BEGIN) {
2254 * Allocate arrays that will contain the graphs data
2255 * and the min/max values.
2257 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
2260 if (action & F_MAIN) {
2261 /* Check for min/max values */
2262 save_extrema(0, 4, 0, (void *) a->buf[curr], (void *) a->buf[!curr],
2266 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2267 S_VALUE(snup->InDatagrams, snuc->InDatagrams, itv),
2268 out, outsize, svg_p->restart);
2270 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2271 S_VALUE(snup->OutDatagrams, snuc->OutDatagrams, itv),
2272 out + 1, outsize + 1, svg_p->restart);
2274 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2275 S_VALUE(snup->NoPorts, snuc->NoPorts, itv),
2276 out + 2, outsize + 2, svg_p->restart);
2278 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2279 S_VALUE(snup->InErrors, snuc->InErrors, itv),
2280 out + 3, outsize + 3, svg_p->restart);
2283 if (action & F_END) {
2284 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
2285 spmin, spmax, out, outsize, svg_p, record_hdr);
2287 /* Free remaining structures */
2288 free_graphs(out, outsize, spmin, spmax);
2293 ***************************************************************************
2294 * Display IPV6 network socket statistics in SVG.
2297 * @a Activity structure with statistics.
2298 * @curr Index in array for current sample statistics.
2299 * @action Action expected from current function.
2300 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
2301 * flag indicating that a restart record has been previously
2302 * found (.@restart) and time used for the X axis origin
2304 * @itv Interval of time in jiffies (only with F_MAIN action).
2305 * @record_hdr Pointer on record header of current stats sample.
2306 ***************************************************************************
2308 __print_funct_t svg_print_net_sock6_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2309 unsigned long long itv, struct record_header *record_hdr)
2311 struct stats_net_sock6
2312 *snsc = (struct stats_net_sock6 *) a->buf[curr];
2314 char *title[] = {"IPv6 network sockets"};
2315 char *g_title[] = {"~tcp6sck", "~udp6sck", "~raw6sck", "~ip6-frag"};
2316 static double *spmin, *spmax;
2318 static int *outsize;
2320 if (action & F_BEGIN) {
2322 * Allocate arrays that will contain the graphs data
2323 * and the min/max values.
2325 out = allocate_graph_lines(4, &outsize, &spmin, &spmax);
2328 if (action & F_MAIN) {
2329 /* Check for min/max values */
2330 save_extrema(0, 0, 4, (void *) a->buf[curr], NULL,
2333 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2334 (unsigned long) snsc->tcp6_inuse,
2335 out, outsize, svg_p->restart);
2337 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2338 (unsigned long) snsc->udp6_inuse,
2339 out + 1, outsize + 1, svg_p->restart);
2341 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2342 (unsigned long) snsc->raw6_inuse,
2343 out + 2, outsize + 2, svg_p->restart);
2345 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2346 (unsigned long) snsc->frag6_inuse,
2347 out + 3, outsize + 3, svg_p->restart);
2350 if (action & F_END) {
2351 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH, title, g_title, NULL, group,
2352 spmin, spmax, out, outsize, svg_p, record_hdr);
2354 /* Free remaining structures */
2355 free_graphs(out, outsize, spmin, spmax);
2360 ***************************************************************************
2361 * Display CPU frequency statistics in SVG.
2364 * @a Activity structure with statistics.
2365 * @curr Index in array for current sample statistics.
2366 * @action Action expected from current function.
2367 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
2368 * flag indicating that a restart record has been previously
2369 * found (.@restart) and time used for the X axis origin
2371 * @itv Interval of time in jiffies (only with F_MAIN action).
2372 * @record_hdr Pointer on record header of current stats sample.
2373 ***************************************************************************
2375 __print_funct_t svg_print_pwr_cpufreq_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2376 unsigned long long g_itv, struct record_header *record_hdr)
2378 struct stats_pwr_cpufreq *spc, *spp;
2380 char *title[] = {"CPU frequency"};
2381 char *g_title[] = {"MHz"};
2382 static double *spmin, *spmax;
2384 static int *outsize;
2388 if (action & F_BEGIN) {
2390 * Allocate arrays that will contain the graphs data
2391 * and the min/max values.
2393 out = allocate_graph_lines(a->nr, &outsize, &spmin, &spmax);
2396 if (action & F_MAIN) {
2398 for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
2400 spc = (struct stats_pwr_cpufreq *) ((char *) a->buf[curr] + i * a->msize);
2401 spp = (struct stats_pwr_cpufreq *) ((char *) a->buf[!curr] + i * a->msize);
2403 /* Should current CPU (including CPU "all") be displayed? */
2404 if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
2409 recappend(record_hdr->ust_time - svg_p->ust_time_ref,
2410 ((double) spp->cpufreq) / 100,
2411 ((double) spc->cpufreq) / 100,
2412 out + i, outsize + i, svg_p->restart, svg_p->dt,
2413 spmin + i, spmax + i);
2417 if (action & F_END) {
2418 for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
2420 /* Should current CPU (including CPU "all") be displayed? */
2421 if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
2426 /* This is CPU "all" */
2427 strcpy(item_name, "all");
2430 sprintf(item_name, "%d", i - 1);
2433 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH,
2434 title, g_title, item_name, group,
2435 spmin + i, spmax + i, out + i, outsize + i,
2439 /* Free remaining structures */
2440 free_graphs(out, outsize, spmin, spmax);
2445 ***************************************************************************
2446 * Display fan statistics in SVG.
2449 * @a Activity structure with statistics.
2450 * @curr Index in array for current sample statistics.
2451 * @action Action expected from current function.
2452 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
2453 * flag indicating that a restart record has been previously
2454 * found (.@restart) and time used for the X axis origin
2456 * @itv Interval of time in jiffies (only with F_MAIN action).
2457 * @record_hdr Pointer on record header of current stats sample.
2458 ***************************************************************************
2460 __print_funct_t svg_print_pwr_fan_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2461 unsigned long long g_itv, struct record_header *record_hdr)
2463 struct stats_pwr_fan *spc, *spp;
2465 char *title[] = {"Fan speed"};
2466 char *g_title[] = {"~rpm"};
2467 static double *spmin, *spmax;
2469 static int *outsize;
2470 char item_name[MAX_SENSORS_DEV_LEN + 8];
2473 if (action & F_BEGIN) {
2475 * Allocate arrays that will contain the graphs data
2476 * and the min/max values.
2478 out = allocate_graph_lines(a->nr, &outsize, &spmin, &spmax);
2481 if (action & F_MAIN) {
2483 for (i = 0; i < a->nr; i++) {
2485 spc = (struct stats_pwr_fan *) ((char *) a->buf[curr] + i * a->msize);
2486 spp = (struct stats_pwr_fan *) ((char *) a->buf[!curr] + i * a->msize);
2489 recappend(record_hdr->ust_time - svg_p->ust_time_ref,
2492 out + i, outsize + i, svg_p->restart, svg_p->dt,
2493 spmin + i, spmax + i);
2497 if (action & F_END) {
2498 for (i = 0; i < a->nr; i++) {
2500 spc = (struct stats_pwr_fan *) ((char *) a->buf[curr] + i * a->msize);
2502 snprintf(item_name, MAX_SENSORS_DEV_LEN + 8, "%d: %s", i + 1, spc->device);
2503 item_name[MAX_SENSORS_DEV_LEN + 7] = '\0';
2505 draw_activity_graphs(a->g_nr, SVG_LINE_GRAPH,
2506 title, g_title, item_name, group,
2507 spmin + i, spmax + i, out + i, outsize + i,
2511 /* Free remaining structures */
2512 free_graphs(out, outsize, spmin, spmax);
2517 ***************************************************************************
2518 * Display temperature statistics in SVG.
2521 * @a Activity structure with statistics.
2522 * @curr Index in array for current sample statistics.
2523 * @action Action expected from current function.
2524 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
2525 * flag indicating that a restart record has been previously
2526 * found (.@restart) and time used for the X axis origin
2528 * @itv Interval of time in jiffies (only with F_MAIN action).
2529 * @record_hdr Pointer on record header of current stats sample.
2530 ***************************************************************************
2532 __print_funct_t svg_print_pwr_temp_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2533 unsigned long long g_itv, struct record_header *record_hdr)
2535 struct stats_pwr_temp *spc;
2537 char *title1[] = {"Device temperature (1)"};
2538 char *title2[] = {"Device temperature (2)"};
2539 char *g1_title[] = {"~degC"};
2540 char *g2_title[] = {"%temp"};
2541 static double *spmin, *spmax;
2543 static int *outsize;
2544 char item_name[MAX_SENSORS_DEV_LEN + 8];
2548 if (action & F_BEGIN) {
2550 * Allocate arrays that will contain the graphs data
2551 * and the min/max values.
2553 out = allocate_graph_lines(2 * a->nr, &outsize, &spmin, &spmax);
2556 if (action & F_MAIN) {
2557 /* For each temperature sensor */
2558 for (i = 0; i < a->nr; i++) {
2560 spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
2562 /* Look for min/max values */
2563 if (spc->temp < *(spmin + 2 * i)) {
2564 *(spmin + 2 * i) = spc->temp;
2566 if (spc->temp > *(spmax + 2 * i)) {
2567 *(spmax + 2 * i) = spc->temp;
2569 tval = (spc->temp_max - spc->temp_min) ?
2570 (spc->temp - spc->temp_min) / (spc->temp_max - spc->temp_min) * 100 :
2572 if (tval < *(spmin + 2 * i + 1)) {
2573 *(spmin + 2 * i + 1) = tval;
2575 if (tval > *(spmax + 2 * i + 1)) {
2576 *(spmax + 2 * i + 1) = tval;
2580 lnappend(record_hdr->ust_time - svg_p->ust_time_ref,
2582 out + 2 * i, outsize + 2 * i, svg_p->restart);
2584 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
2586 out + 2 * i + 1, outsize + 2 * i + 1, svg_p->dt);
2590 if (action & F_END) {
2591 for (i = 0; i < a->nr; i++) {
2593 spc = (struct stats_pwr_temp *) ((char *) a->buf[curr] + i * a->msize);
2595 snprintf(item_name, MAX_SENSORS_DEV_LEN + 8, "%d: %s", i + 1, spc->device);
2596 item_name[MAX_SENSORS_DEV_LEN + 7] = '\0';
2598 draw_activity_graphs(1, SVG_LINE_GRAPH,
2599 title1, g1_title, item_name, group,
2600 spmin + 2 * i, spmax + 2 * i, out + 2 * i, outsize + 2 * i,
2602 draw_activity_graphs(1, SVG_BAR_GRAPH,
2603 title2, g2_title, item_name, group,
2604 spmin + 2 * i + 1, spmax + 2 * i + 1,
2605 out + 2 * i + 1, outsize + 2 * i + 1,
2609 /* Free remaining structures */
2610 free_graphs(out, outsize, spmin, spmax);
2615 ***************************************************************************
2616 * Display huge pages statistics in SVG.
2619 * @a Activity structure with statistics.
2620 * @curr Index in array for current sample statistics.
2621 * @action Action expected from current function.
2622 * @svg_p SVG specific parameters: Current graph number (.@graph_no),
2623 * flag indicating that a restart record has been previously
2624 * found (.@restart) and time used for the X axis origin
2626 * @itv Interval of time in jiffies (only with F_MAIN action).
2627 * @record_hdr Pointer on record header of current stats sample.
2628 ***************************************************************************
2630 __print_funct_t svg_print_huge_stats(struct activity *a, int curr, int action, struct svg_parm *svg_p,
2631 unsigned long long itv, struct record_header *record_hdr)
2634 *smc = (struct stats_huge *) a->buf[curr];
2637 char *title1[] = {"Huge pages utilization (1)"};
2638 char *title2[] = {"Huge pages utilization (2)"};
2639 char *g1_title[] = {"~kbhugfree", "~kbhugused"};
2640 char *g2_title[] = {"%hugused"};
2641 static double *spmin, *spmax;
2643 static int *outsize;
2646 if (action & F_BEGIN) {
2648 * Allocate arrays that will contain the graphs data
2649 * and the min/max values.
2651 out = allocate_graph_lines(3, &outsize, &spmin, &spmax);
2654 if (action & F_MAIN) {
2655 /* Check for min/max values */
2656 save_extrema(0, 1, 0, (void *) a->buf[curr], NULL,
2659 if (smc->tlhkb - smc->frhkb < *(spmin + 1)) {
2660 *(spmin + 1) = smc->tlhkb - smc->frhkb;
2662 if (smc->tlhkb - smc->frhkb > *(spmax + 1)) {
2663 *(spmax + 1) = smc->tlhkb - smc->frhkb;
2665 tval = smc->tlhkb ? SP_VALUE(smc->frhkb, smc->tlhkb, smc->tlhkb) : 0.0;
2666 if (tval < *(spmin + 2)) {
2667 *(spmin + 2) = tval;
2669 if (tval > *(spmax + 2)) {
2670 *(spmax + 2) = tval;
2674 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2675 (unsigned long) smc->frhkb,
2676 out, outsize, svg_p->restart);
2678 lniappend(record_hdr->ust_time - svg_p->ust_time_ref,
2679 (unsigned long) smc->tlhkb - smc->frhkb,
2680 out + 1, outsize + 1, svg_p->restart);
2682 brappend(record_hdr->ust_time - svg_p->ust_time_ref,
2684 out + 2, outsize + 2, svg_p->dt);
2687 if (action & F_END) {
2688 draw_activity_graphs(1, SVG_LINE_GRAPH,
2689 title1, g1_title, NULL, group1,
2690 spmin, spmax, out, outsize, svg_p, record_hdr);
2691 draw_activity_graphs(1, SVG_BAR_GRAPH,
2692 title2, g2_title, NULL, group2,
2693 spmin + 2, spmax + 2, out + 2, outsize + 2,
2696 /* Free remaining structures */
2697 free_graphs(out, outsize, spmin, spmax);