2 * sadf_misc.c: Funtions used by sadf to display special records
3 * (C) 2011-2019 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 ***************************************************************************
27 #include "pcp_def_metrics.h"
32 #define _(string) gettext(string)
34 #define _(string) (string)
38 #include <pcp/pmapi.h>
39 #include <pcp/import.h>
42 extern char *tzname[2];
44 extern unsigned int flags;
48 extern unsigned int svg_colors[][SVG_COL_PALETTE_SIZE];
51 ***************************************************************************
52 * Flush data to PCP archive.
55 * @record_hdr Record header for current sample.
56 * @flags Flags for common options.
57 ***************************************************************************
59 void pcp_write_data(struct record_header *record_hdr, unsigned int flags)
64 unsigned long long utc_sec = record_hdr->ust_time;
65 static long long delta_utc = LONG_MAX;
67 if (!PRINT_LOCAL_TIME(flags)) {
68 if (delta_utc == LONG_MAX) {
69 /* Convert a time_t value from local time to UTC */
70 if (gmtime_r((const time_t *) &(record_hdr->ust_time), &lrectime)) {
71 utc_sec = mktime(&lrectime);
72 delta_utc = utc_sec - record_hdr->ust_time;
77 * Once pmiWrite() has been called (after the first stats sample),
78 * subsequent mktime() calls will not give the same result with
79 * the same input data. So compute a time shift that will be used
80 * for the next samples.
81 * We should (really) be careful if pmiWrite() was to be used sooner
82 * than for the first stats sample (e.g. if we want to save a
83 * LINUX RESTART record heading the file).
89 /* Write data to PCP archive */
90 if ((rc = pmiWrite(utc_sec, 0)) < 0) {
91 fprintf(stderr, "PCP: pmiWrite: %s\n", pmiErrStr(rc));
98 ***************************************************************************
99 * Display restart messages (database and ppc formats).
102 * @cur_date Date string of current restart message.
103 * @cur_time Time string of current restart message.
104 * @utc True if @cur_time is expressed in UTC.
105 * @sep Character used as separator.
106 * @file_hdr System activity file standard header.
107 ***************************************************************************
109 void print_dbppc_restart(char *cur_date, char *cur_time, int utc, char sep,
110 struct file_header *file_hdr)
112 printf("%s%c-1%c", file_hdr->sa_nodename, sep, sep);
113 if (strlen(cur_date)) {
114 printf("%s ", cur_date);
116 printf("%s", cur_time);
117 if (strlen(cur_date) && utc) {
120 printf("%cLINUX-RESTART\t(%d CPU)\n",
121 sep, file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
125 ***************************************************************************
126 * Display restart messages (ppc format).
129 * @tab Number of tabulations (unused here).
130 * @action Action expected from current function.
131 * @cur_date Date string of current restart message.
132 * @cur_time Time string of current restart message.
133 * @utc True if @cur_time is expressed in UTC.
134 * @file_hdr System activity file standard header.
135 * @record_hdr Current record header (unused here).
136 ***************************************************************************
138 __printf_funct_t print_db_restart(int *tab, int action, char *cur_date,
139 char *cur_time, int utc, struct file_header *file_hdr,
140 struct record_header *record_hdr)
142 /* Actions F_BEGIN and F_END ignored */
143 if (action == F_MAIN) {
144 print_dbppc_restart(cur_date, cur_time, utc, ';', file_hdr);
149 ***************************************************************************
150 * Display restart messages (database format).
153 * @tab Number of tabulations (unused here).
154 * @action Action expected from current function.
155 * @cur_date Date string of current restart message.
156 * @cur_time Time string of current restart message.
157 * @utc True if @cur_time is expressed in UTC.
158 * @file_hdr System activity file standard header.
159 * @record_hdr Current record header (unused here).
160 ***************************************************************************
162 __printf_funct_t print_ppc_restart(int *tab, int action, char *cur_date,
163 char *cur_time, int utc, struct file_header *file_hdr,
164 struct record_header *record_hdr)
166 /* Actions F_BEGIN and F_END ignored */
167 if (action == F_MAIN) {
168 print_dbppc_restart(cur_date, cur_time, utc, '\t', file_hdr);
173 ***************************************************************************
174 * Display restart messages (XML format).
177 * @tab Number of tabulations.
178 * @action Action expected from current function.
179 * @cur_date Date string of current restart message.
180 * @cur_time Time string of current restart message.
181 * @utc True if @cur_time is expressed in UTC.
182 * @file_hdr System activity file standard header.
183 * @record_hdr Current record header (unused here).
186 * @tab Number of tabulations.
187 ***************************************************************************
189 __printf_funct_t print_xml_restart(int *tab, int action, char *cur_date,
190 char *cur_time, int utc, struct file_header *file_hdr,
191 struct record_header *record_hdr)
193 if (action & F_BEGIN) {
194 xprintf((*tab)++, "<restarts>");
196 if (action & F_MAIN) {
197 xprintf(*tab, "<boot date=\"%s\" time=\"%s\" utc=\"%d\" cpu_count=\"%d\"/>",
198 cur_date, cur_time, utc ? 1 : 0,
199 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
201 if (action & F_END) {
202 xprintf(--(*tab), "</restarts>");
207 ***************************************************************************
208 * Display restart messages (JSON format).
211 * @tab Number of tabulations.
212 * @action Action expected from current function.
213 * @cur_date Date string of current restart message.
214 * @cur_time Time string of current restart message.
215 * @utc True if @cur_time is expressed in UTC.
216 * @file_hdr System activity file standard header.
217 * @record_hdr Current record header (unused here).
220 * @tab Number of tabulations.
221 ***************************************************************************
223 __printf_funct_t print_json_restart(int *tab, int action, char *cur_date,
224 char *cur_time, int utc, struct file_header *file_hdr,
225 struct record_header *record_hdr)
227 static int sep = FALSE;
229 if (action & F_BEGIN) {
231 xprintf((*tab)++, "\"restarts\": [");
233 if (action & F_MAIN) {
237 xprintf((*tab)++, "{");
238 xprintf(*tab, "\"boot\": {\"date\": \"%s\", \"time\": \"%s\", \"utc\": %d, \"cpu_count\": %d}",
239 cur_date, cur_time, utc ? 1 : 0,
240 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
241 xprintf0(--(*tab), "}");
244 if (action & F_END) {
249 xprintf0(--(*tab), "]");
254 ***************************************************************************
255 * Display restart messages (raw format).
258 * @tab Number of tabulations (unused here).
259 * @action Action expected from current function.
260 * @cur_date Date string of current restart message.
261 * @cur_time Time string of current restart message.
262 * @utc True if @cur_time is expressed in UTC.
263 * @file_hdr System activity file standard header.
264 * @record_hdr Current record header (unused here).
265 ***************************************************************************
267 __printf_funct_t print_raw_restart(int *tab, int action, char *cur_date,
268 char *cur_time, int utc, struct file_header *file_hdr,
269 struct record_header *record_hdr)
271 /* Actions F_BEGIN and F_END ignored */
272 if (action == F_MAIN) {
273 printf("%s", cur_time);
274 if (strlen(cur_date) && utc) {
277 printf("; LINUX-RESTART (%d CPU)\n",
278 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
283 ***************************************************************************
284 * Display restart messages (PCP format).
287 * @tab Number of tabulations (unused here).
288 * @action Action expected from current function.
289 * @cur_date Date string of current restart message (unused here).
290 * @cur_time Time string of current restart message (unused here).
291 * @utc True if @cur_time is expressed in UTC (unused here).
292 * @file_hdr System activity file standard header.
293 * @record_hdr Current record header.
294 ***************************************************************************
296 __printf_funct_t print_pcp_restart(int *tab, int action, char *cur_date, char *cur_time,
297 int utc, struct file_header *file_hdr,
298 struct record_header *record_hdr)
301 static int def_metrics = FALSE;
304 if (action & F_BEGIN) {
306 pmiAddMetric("system.restart.count",
307 PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
308 pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
310 pmiAddMetric("system.restart.ncpu",
311 PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
312 pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
317 if (action & F_MAIN) {
318 pmiPutValue("system.restart.count", NULL, "1");
320 snprintf(buf, sizeof(buf), "%u",
321 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
322 pmiPutValue("system.restart.ncpu", NULL, buf);
324 /* Write data to PCP archive */
325 pcp_write_data(record_hdr, flags);
327 #endif /* HAVE_PCP */
331 ***************************************************************************
332 * Display comments (database and ppc formats).
335 * @cur_date Date string of current restart message.
336 * @cur_time Time string of current restart message.
337 * @utc True if @cur_time is expressed in UTC.
338 * @comment Comment to display.
339 * @sep Character used as separator.
340 * @file_hdr System activity file standard header.
341 ***************************************************************************
343 void print_dbppc_comment(char *cur_date, char *cur_time, int utc,
344 char *comment, char sep, struct file_header *file_hdr)
346 printf("%s%c-1%c", file_hdr->sa_nodename, sep, sep);
347 if (strlen(cur_date)) {
348 printf("%s ", cur_date);
350 printf("%s", cur_time);
351 if (strlen(cur_date) && utc) {
354 printf("%cCOM %s\n", sep, comment);
358 ***************************************************************************
359 * Display comments (database format).
362 * @tab Number of tabulations (unused here).
363 * @action Action expected from current function.
364 * @cur_date Date string of current restart message.
365 * @cur_time Time string of current restart message.
366 * @utc True if @cur_time is expressed in UTC.
367 * @comment Comment to display.
368 * @file_hdr System activity file standard header.
369 * @record_hdr Current record header (unused here).
370 ***************************************************************************
372 __printf_funct_t print_db_comment(int *tab, int action, char *cur_date, char *cur_time,
373 int utc, char *comment, struct file_header *file_hdr,
374 struct record_header *record_hdr)
376 /* Actions F_BEGIN and F_END ignored */
377 if (action & F_MAIN) {
378 print_dbppc_comment(cur_date, cur_time, utc, comment,
384 ***************************************************************************
385 * Display comments (ppc format).
388 * @tab Number of tabulations (unused here).
389 * @action Action expected from current function.
390 * @cur_date Date string of current restart message.
391 * @cur_time Time string of current restart message.
392 * @utc True if @cur_time is expressed in UTC.
393 * @comment Comment to display.
394 * @file_hdr System activity file standard header.
395 * @record_hdr Current record header (unused here).
396 ***************************************************************************
398 __printf_funct_t print_ppc_comment(int *tab, int action, char *cur_date, char *cur_time,
399 int utc, char *comment, struct file_header *file_hdr,
400 struct record_header *record_hdr)
402 /* Actions F_BEGIN and F_END ignored */
403 if (action & F_MAIN) {
404 print_dbppc_comment(cur_date, cur_time, utc, comment,
410 ***************************************************************************
411 * Display comments (XML format).
414 * @tab Number of tabulations.
415 * @action Action expected from current function.
416 * @cur_date Date string of current comment.
417 * @cur_time Time string of current comment.
418 * @utc True if @cur_time is expressed in UTC.
419 * @comment Comment to display.
420 * @file_hdr System activity file standard header (unused here).
421 * @record_hdr Current record header (unused here).
424 * @tab Number of tabulations.
425 ***************************************************************************
427 __printf_funct_t print_xml_comment(int *tab, int action, char *cur_date, char *cur_time,
428 int utc, char *comment, struct file_header *file_hdr,
429 struct record_header *record_hdr)
431 if (action & F_BEGIN) {
432 xprintf((*tab)++, "<comments>");
434 if (action & F_MAIN) {
435 xprintf(*tab, "<comment date=\"%s\" time=\"%s\" utc=\"%d\" com=\"%s\"/>",
436 cur_date, cur_time, utc ? 1 : 0, comment);
438 if (action & F_END) {
439 xprintf(--(*tab), "</comments>");
444 ***************************************************************************
445 * Display comments (JSON format).
448 * @tab Number of tabulations.
449 * @action Action expected from current function.
450 * @cur_date Date string of current comment.
451 * @cur_time Time string of current comment.
452 * @utc True if @cur_time is expressed in UTC.
453 * @comment Comment to display.
454 * @file_hdr System activity file standard header (unused here).
455 * @record_hdr Current record header (unused here).
458 * @tab Number of tabulations.
459 ***************************************************************************
461 __printf_funct_t print_json_comment(int *tab, int action, char *cur_date, char *cur_time,
462 int utc, char *comment, struct file_header *file_hdr,
463 struct record_header *record_hdr)
465 static int sep = FALSE;
467 if (action & F_BEGIN) {
469 xprintf((*tab)++, "\"comments\": [");
471 if (action & F_MAIN) {
475 xprintf((*tab)++, "{");
477 "\"comment\": {\"date\": \"%s\", \"time\": \"%s\", "
478 "\"utc\": %d, \"com\": \"%s\"}",
479 cur_date, cur_time, utc ? 1 : 0, comment);
480 xprintf0(--(*tab), "}");
483 if (action & F_END) {
488 xprintf0(--(*tab), "]");
493 ***************************************************************************
494 * Display comments (raw format).
497 * @tab Number of tabulations (unused here).
498 * @action Action expected from current function.
499 * @cur_date Date string of current restart message.
500 * @cur_time Time string of current restart message.
501 * @utc True if @cur_time is expressed in UTC.
502 * @comment Comment to display.
503 * @file_hdr System activity file standard header (unused here).
504 * @record_hdr Current record header (unused here).
505 ***************************************************************************
507 __printf_funct_t print_raw_comment(int *tab, int action, char *cur_date, char *cur_time,
508 int utc, char *comment, struct file_header *file_hdr,
509 struct record_header *record_hdr)
511 /* Actions F_BEGIN and F_END ignored */
512 if (action & F_MAIN) {
513 printf("%s", cur_time);
514 if (strlen(cur_date) && utc) {
517 printf("; COM %s\n", comment);
522 ***************************************************************************
523 * Display comments (PCP format).
526 * @tab Number of tabulations (unused here).
527 * @action Action expected from current function.
528 * @cur_date Date string of current restart message (unused here).
529 * @cur_time Time string of current restart message (unused here).
530 * @utc True if @cur_time is expressed in UTC (unused here).
531 * @comment Comment to display.
532 * @file_hdr System activity file standard header (unused here).
533 * @record_hdr Current record header.
534 ***************************************************************************
536 __printf_funct_t print_pcp_comment(int *tab, int action, char *cur_date, char *cur_time,
537 int utc, char *comment, struct file_header *file_hdr,
538 struct record_header *record_hdr)
541 static int def_metrics = FALSE;
543 if (action & F_BEGIN) {
545 pmiAddMetric("system.comment.value",
546 PM_IN_NULL, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE,
547 pmiUnits(0, 0, 0, 0, 0, 0));
552 if (action & F_MAIN) {
553 pmiPutValue("system.comment.value", NULL, comment);
555 /* Write data to PCP archive */
556 pcp_write_data(record_hdr, flags);
558 #endif /* HAVE_PCP */
562 ***************************************************************************
563 * Display the "statistics" part of the report (XML format).
566 * @tab Number of tabulations.
567 * @action Action expected from current function.
568 * @act Array of activities (unused here).
569 * @id_seq Activity sequence (unused here).
572 * @tab Number of tabulations.
573 ***************************************************************************
575 __printf_funct_t print_xml_statistics(int *tab, int action, struct activity *act[],
576 unsigned int id_seq[])
578 if (action & F_BEGIN) {
579 xprintf((*tab)++, "<statistics>");
581 if (action & F_END) {
582 xprintf(--(*tab), "</statistics>");
587 ***************************************************************************
588 * Display the "statistics" part of the report (JSON format).
591 * @tab Number of tabulations.
592 * @action Action expected from current function.
593 * @act Array of activities (unused here).
594 * @id_seq Activity sequence (unused here).
597 * @tab Number of tabulations.
598 ***************************************************************************
600 __printf_funct_t print_json_statistics(int *tab, int action, struct activity *act[],
601 unsigned int id_seq[])
603 static int sep = FALSE;
605 if (action & F_BEGIN) {
607 xprintf((*tab)++, "\"statistics\": [");
609 if (action & F_MAIN) {
611 xprintf(--(*tab), "},");
613 xprintf((*tab)++, "{");
616 if (action & F_END) {
618 xprintf(--(*tab), "}");
621 xprintf0(--(*tab), "]");
626 ***************************************************************************
627 * Display the "statistics" part of the report (PCP format).
630 * @tab Number of tabulations (unused here).
631 * @action Action expected from current function.
632 * @act Array of activities.
633 * @id_seq Activity sequence.
634 ***************************************************************************
636 __printf_funct_t print_pcp_statistics(int *tab, int action, struct activity *act[],
637 unsigned int id_seq[])
642 if (action & F_BEGIN) {
643 for (i = 0; i < NR_ACT; i++) {
645 continue; /* Activity not in file */
647 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
648 if (!IS_SELECTED(act[p]->options))
649 continue; /* Activity not selected */
651 switch (act[p]->id) {
656 pcp_def_cpu_metrics(act[p]);
660 pcp_def_pcsw_metrics();
664 pcp_def_irq_metrics(act[p]);
668 pcp_def_swap_metrics();
672 pcp_def_paging_metrics();
676 pcp_def_io_metrics();
680 pcp_def_memory_metrics(act[p]);
684 pcp_def_ktables_metrics();
688 pcp_def_queue_metrics();
692 pcp_def_serial_metrics(act[p]);
696 pcp_def_disk_metrics(act[p]);
701 pcp_def_net_dev_metrics(act[p]);
705 pcp_def_net_nfs_metrics();
709 pcp_def_net_nfsd_metrics();
713 pcp_def_net_sock_metrics();
717 pcp_def_net_ip_metrics();
721 pcp_def_net_eip_metrics();
725 pcp_def_net_icmp_metrics();
729 pcp_def_net_eicmp_metrics();
733 pcp_def_net_tcp_metrics();
737 pcp_def_net_etcp_metrics();
741 pcp_def_net_udp_metrics();
745 pcp_def_net_sock6_metrics();
749 pcp_def_net_ip6_metrics();
753 pcp_def_net_eip6_metrics();
757 pcp_def_net_icmp6_metrics();
761 pcp_def_net_eicmp6_metrics();
765 pcp_def_net_udp6_metrics();
769 pcp_def_huge_metrics();
773 pcp_def_pwr_fan_metrics(act[p]);
777 pcp_def_pwr_usb_metrics(act[p]);
781 pcp_def_filesystem_metrics(act[p]);
785 pcp_def_fchost_metrics(act[p]);
790 #endif /* HAVE_PCP */
794 ***************************************************************************
795 * Display the "timestamp" part of the report (db and ppc format).
798 * @fmt Output format (F_DB_OUTPUT or F_PPC_OUTPUT).
799 * @file_hdr System activity file standard header.
800 * @cur_date Date string of current record.
801 * @cur_time Time string of current record.
802 * @utc True if @cur_time is expressed in UTC.
803 * @itv Interval of time with preceding record.
806 * Pointer on the "timestamp" string.
807 ***************************************************************************
809 char *print_dbppc_timestamp(int fmt, struct file_header *file_hdr, char *cur_date,
810 char *cur_time, int utc, unsigned long long itv)
812 int isdb = (fmt == F_DB_OUTPUT);
813 static char pre[512];
814 char temp1[128], temp2[256];
816 /* This substring appears on every output line, preformat it here */
817 snprintf(temp1, sizeof(temp1), "%s%s%lld%s",
818 file_hdr->sa_nodename, seps[isdb], itv, seps[isdb]);
819 if (strlen(cur_date)) {
820 snprintf(temp2, sizeof(temp2), "%s%s ", temp1, cur_date);
823 strcpy(temp2, temp1);
825 snprintf(pre, sizeof(pre), "%s%s%s", temp2, cur_time,
826 strlen(cur_date) && utc ? " UTC" : "");
827 pre[sizeof(pre) - 1] = '\0';
829 if (DISPLAY_HORIZONTALLY(flags)) {
837 ***************************************************************************
838 * Display the "timestamp" part of the report (ppc format).
841 * @parm Pointer on specific parameters (unused here).
842 * @action Action expected from current function.
843 * @cur_date Date string of current record.
844 * @cur_time Time string of current record.
845 * @itv Interval of time with preceding record.
846 * @record_hdr Record header for current sample (unused here).
847 * @file_hdr System activity file standard header.
848 * @flags Flags for common options.
851 * Pointer on the "timestamp" string.
852 ***************************************************************************
854 __tm_funct_t print_ppc_timestamp(void *parm, int action, char *cur_date,
855 char *cur_time, unsigned long long itv,
856 struct record_header *record_hdr,
857 struct file_header *file_hdr, unsigned int flags)
859 int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
861 if (action & F_BEGIN) {
862 return print_dbppc_timestamp(F_PPC_OUTPUT, file_hdr, cur_date, cur_time, utc, itv);
864 if (action & F_END) {
865 if (DISPLAY_HORIZONTALLY(flags)) {
874 ***************************************************************************
875 * Display the "timestamp" part of the report (db format).
878 * @parm Pointer on specific parameters (unused here).
879 * @action Action expected from current function.
880 * @cur_date Date string of current record.
881 * @cur_time Time string of current record.
882 * @itv Interval of time with preceding record.
883 * @record_hdr Record header for current sample (unused here).
884 * @file_hdr System activity file standard header.
885 * @flags Flags for common options.
888 * Pointer on the "timestamp" string.
889 ***************************************************************************
891 __tm_funct_t print_db_timestamp(void *parm, int action, char *cur_date,
892 char *cur_time, unsigned long long itv,
893 struct record_header *record_hdr,
894 struct file_header *file_hdr, unsigned int flags)
896 int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
898 if (action & F_BEGIN) {
899 return print_dbppc_timestamp(F_DB_OUTPUT, file_hdr, cur_date, cur_time, utc, itv);
901 if (action & F_END) {
902 if (DISPLAY_HORIZONTALLY(flags)) {
911 ***************************************************************************
912 * Display the "timestamp" part of the report (XML format).
915 * @parm Specific parameter. Here: number of tabulations.
916 * @action Action expected from current function.
917 * @cur_date Date string of current comment.
918 * @cur_time Time string of current comment.
919 * @itv Interval of time with preceding record.
920 * @record_hdr Record header for current sample (unused here).
921 * @file_hdr System activity file standard header (unused here).
922 * @flags Flags for common options.
923 ***************************************************************************
925 __tm_funct_t print_xml_timestamp(void *parm, int action, char *cur_date,
926 char *cur_time, unsigned long long itv,
927 struct record_header *record_hdr,
928 struct file_header *file_hdr, unsigned int flags)
930 int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
931 int *tab = (int *) parm;
933 if (action & F_BEGIN) {
934 xprintf((*tab)++, "<timestamp date=\"%s\" time=\"%s\" utc=\"%d\" interval=\"%llu\">",
935 cur_date, cur_time, utc ? 1 : 0, itv);
937 if (action & F_END) {
938 xprintf(--(*tab), "</timestamp>");
945 ***************************************************************************
946 * Display the "timestamp" part of the report (JSON format).
949 * @parm Specific parameter. Here: number of tabulations.
950 * @action Action expected from current function.
951 * @cur_date Date string of current comment.
952 * @cur_time Time string of current comment.
953 * @itv Interval of time with preceding record.
954 * @record_hdr Record header for current sample (unused here).
955 * @file_hdr System activity file standard header (unused here).
956 * @flags Flags for common options.
957 ***************************************************************************
959 __tm_funct_t print_json_timestamp(void *parm, int action, char *cur_date,
960 char *cur_time, unsigned long long itv,
961 struct record_header *record_hdr,
962 struct file_header *file_hdr, unsigned int flags)
964 int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
965 int *tab = (int *) parm;
967 if (action & F_BEGIN) {
969 "\"timestamp\": {\"date\": \"%s\", \"time\": \"%s\", "
970 "\"utc\": %d, \"interval\": %llu}",
971 cur_date, cur_time, utc ? 1 : 0, itv);
973 if (action & F_MAIN) {
976 if (action & F_END) {
984 ***************************************************************************
985 * Display the "timestamp" part of the report (raw format).
988 * @parm Pointer on specific parameters (unused here).
989 * @action Action expected from current function.
990 * @cur_date Date string of current record.
991 * @cur_time Time string of current record.
992 * @itv Interval of time with preceding record (unused here).
993 * @record_hdr Record header for current sample (unused here).
994 * @file_hdr System activity file standard header (unused here).
995 * @flags Flags for common options.
998 * Pointer on the "timestamp" string.
999 ***************************************************************************
1001 __tm_funct_t print_raw_timestamp(void *parm, int action, char *cur_date,
1002 char *cur_time, unsigned long long itv,
1003 struct record_header *record_hdr,
1004 struct file_header *file_hdr, unsigned int flags)
1006 int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags);
1007 static char pre[80];
1009 if (action & F_BEGIN) {
1010 snprintf(pre, 80, "%s%s", cur_time, strlen(cur_date) && utc ? " UTC" : "");
1019 ***************************************************************************
1020 * Display the "timestamp" part of the report (PCP format).
1023 * @parm Pointer on specific parameters (unused here).
1024 * @action Action expected from current function.
1025 * @cur_date Date string of current record (unused here).
1026 * @cur_time Time string of current record (unused here).
1027 * @itv Interval of time with preceding record (unused here).
1028 * @record_hdr Record header for current sample.
1029 * @file_hdr System activity file standard header (unused here).
1030 * @flags Flags for common options.
1033 * Pointer on the "timestamp" string.
1034 ***************************************************************************
1036 __tm_funct_t print_pcp_timestamp(void *parm, int action, char *cur_date,
1037 char *cur_time, unsigned long long itv,
1038 struct record_header *record_hdr,
1039 struct file_header *file_hdr, unsigned int flags)
1041 if (action & F_END) {
1042 pcp_write_data(record_hdr, flags);
1049 ***************************************************************************
1050 * Display the header of the report (XML format).
1053 * @parm Specific parameter. Here: number of tabulations.
1054 * @action Action expected from current function.
1055 * @dfile Unused here (PCP archive file).
1056 * @file_magic System activity file magic header.
1057 * @file_hdr System activity file standard header.
1058 * @act Array of activities (unused here).
1059 * @id_seq Activity sequence (unused here).
1060 * @file_actlst List of (known or unknown) activities in file (unused here).
1063 * @parm Number of tabulations.
1064 ***************************************************************************
1066 __printf_funct_t print_xml_header(void *parm, int action, char *dfile,
1067 struct file_magic *file_magic,
1068 struct file_header *file_hdr,
1069 struct activity *act[], unsigned int id_seq[],
1070 struct file_activity *file_actlst)
1072 struct tm rectime, loc_t;
1073 char cur_time[TIMESTAMP_LEN];
1074 int *tab = (int *) parm;
1076 if (action & F_BEGIN) {
1077 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1078 printf("<!DOCTYPE sysstat PUBLIC \"DTD v%s sysstat //EN\"\n",
1080 printf("\"http://pagesperso-orange.fr/sebastien.godard/sysstat-%s.dtd\">\n",
1083 xprintf(*tab, "<sysstat\n"
1084 "xmlns=\"http://pagesperso-orange.fr/sebastien.godard/sysstat\"\n"
1085 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
1086 "xsi:schemaLocation=\"http://pagesperso-orange.fr/sebastien.godard sysstat.xsd\">");
1088 xprintf(++(*tab), "<sysdata-version>%s</sysdata-version>",
1091 xprintf(*tab, "<host nodename=\"%s\">", file_hdr->sa_nodename);
1092 xprintf(++(*tab), "<sysname>%s</sysname>", file_hdr->sa_sysname);
1093 xprintf(*tab, "<release>%s</release>", file_hdr->sa_release);
1095 xprintf(*tab, "<machine>%s</machine>", file_hdr->sa_machine);
1096 xprintf(*tab, "<number-of-cpus>%d</number-of-cpus>",
1097 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1099 /* Fill file timestmap structure (rectime) */
1100 get_file_timestamp_struct(flags, &rectime, file_hdr);
1101 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1102 xprintf(*tab, "<file-date>%s</file-date>", cur_time);
1104 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1105 strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1106 xprintf(*tab, "<file-utc-time>%s</file-utc-time>", cur_time);
1110 if (action & F_END) {
1111 xprintf(--(*tab), "</host>");
1112 xprintf(--(*tab), "</sysstat>");
1117 ***************************************************************************
1118 * Display the header of the report (JSON format).
1121 * @parm Specific parameter. Here: number of tabulations.
1122 * @action Action expected from current function.
1123 * @dfile Unused here (PCP archive file).
1124 * @file_magic System activity file magic header.
1125 * @file_hdr System activity file standard header.
1126 * @act Array of activities (unused here).
1127 * @id_seq Activity sequence (unused here).
1128 * @file_actlst List of (known or unknown) activities in file (unused here).
1131 * @parm Number of tabulations.
1132 ***************************************************************************
1134 __printf_funct_t print_json_header(void *parm, int action, char *dfile,
1135 struct file_magic *file_magic,
1136 struct file_header *file_hdr,
1137 struct activity *act[], unsigned int id_seq[],
1138 struct file_activity *file_actlst)
1140 struct tm rectime, loc_t;
1141 char cur_time[TIMESTAMP_LEN];
1142 int *tab = (int *) parm;
1144 if (action & F_BEGIN) {
1145 xprintf(*tab, "{\"sysstat\": {");
1147 xprintf(++(*tab), "\"hosts\": [");
1148 xprintf(++(*tab), "{");
1149 xprintf(++(*tab), "\"nodename\": \"%s\",", file_hdr->sa_nodename);
1150 xprintf(*tab, "\"sysname\": \"%s\",", file_hdr->sa_sysname);
1151 xprintf(*tab, "\"release\": \"%s\",", file_hdr->sa_release);
1153 xprintf(*tab, "\"machine\": \"%s\",", file_hdr->sa_machine);
1154 xprintf(*tab, "\"number-of-cpus\": %d,",
1155 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1157 /* Fill file timestmap structure (rectime) */
1158 get_file_timestamp_struct(flags, &rectime, file_hdr);
1159 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1160 xprintf0(*tab, "\"file-date\": \"%s\"", cur_time);
1162 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1163 strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1165 xprintf0(*tab, "\"file-utc-time\": \"%s\"", cur_time);
1169 if (action & F_END) {
1171 xprintf(--(*tab), "}");
1172 xprintf(--(*tab), "]");
1173 xprintf(--(*tab), "}}");
1178 ***************************************************************************
1179 * Display data file header.
1182 * @parm Specific parameter (unused here).
1183 * @action Action expected from current function.
1184 * @dfile Name of system activity data file (unused here).
1185 * @file_magic System activity file magic header.
1186 * @file_hdr System activity file standard header.
1187 * @act Array of activities.
1188 * @id_seq Activity sequence.
1189 * @file_actlst List of (known or unknown) activities in file.
1190 ***************************************************************************
1192 __printf_funct_t print_hdr_header(void *parm, int action, char *dfile,
1193 struct file_magic *file_magic,
1194 struct file_header *file_hdr,
1195 struct activity *act[], unsigned int id_seq[],
1196 struct file_activity *file_actlst)
1199 struct tm rectime, loc_t;
1200 struct file_activity *fal;
1201 char cur_time[TIMESTAMP_LEN];
1203 /* Actions F_MAIN and F_END ignored */
1204 if (action & F_BEGIN) {
1205 printf(_("System activity data file: %s (%#x)\n"),
1206 dfile, file_magic->format_magic);
1208 display_sa_file_version(stdout, file_magic);
1210 if (file_magic->format_magic != FORMAT_MAGIC) {
1214 printf(_("Genuine sa datafile: %s (%x)\n"),
1215 file_magic->upgraded ? _("no") : _("yes"),
1216 file_magic->upgraded);
1218 printf(_("Host: "));
1219 print_gal_header(localtime_r((const time_t *) &(file_hdr->sa_ust_time), &rectime),
1220 file_hdr->sa_sysname, file_hdr->sa_release,
1221 file_hdr->sa_nodename, file_hdr->sa_machine,
1222 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
1225 /* Fill file timestmap structure (rectime) */
1226 get_file_timestamp_struct(flags, &rectime, file_hdr);
1227 strftime(cur_time, sizeof(cur_time), "%Y-%m-%d", &rectime);
1228 printf(_("File date: %s\n"), cur_time);
1230 if (gmtime_r((const time_t *) &file_hdr->sa_ust_time, &loc_t) != NULL) {
1231 printf(_("File time: "));
1232 strftime(cur_time, sizeof(cur_time), "%T", &loc_t);
1233 printf("%s UTC\n", cur_time);
1236 /* File composition: file_header, file_activity, record_header */
1237 printf(_("File composition: (%d,%d,%d),(%d,%d,%d),(%d,%d,%d)\n"),
1238 file_magic->hdr_types_nr[0], file_magic->hdr_types_nr[1], file_magic->hdr_types_nr[2],
1239 file_hdr->act_types_nr[0], file_hdr->act_types_nr[1], file_hdr->act_types_nr[2],
1240 file_hdr->rec_types_nr[0], file_hdr->rec_types_nr[1], file_hdr->rec_types_nr[2]);
1242 printf(_("Size of a long int: %d\n"), file_hdr->sa_sizeof_long);
1243 printf("HZ = %lu\n", file_hdr->sa_hz);
1244 printf(_("Number of activities in file: %u\n"),
1245 file_hdr->sa_act_nr);
1247 printf(_("List of activities:\n"));
1249 for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1251 p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND);
1253 printf("%02d: [%02x] ", fal->id, fal->magic);
1255 printf("%-20s", act[p]->name);
1258 printf("%-20s", _("Unknown activity"));
1260 printf(" %c:%4d", fal->has_nr ? 'Y' : 'N', fal->nr);
1262 printf("x%d", fal->nr2);
1264 printf("\t(%d,%d,%d)", fal->types_nr[0], fal->types_nr[1], fal->types_nr[2]);
1265 if ((p >= 0) && (act[p]->magic == ACTIVITY_MAGIC_UNKNOWN)) {
1266 printf(_(" \t[Unknown format]"));
1274 ***************************************************************************
1275 * Display the header of the report (SVG format).
1278 * @parm Specific parameters. Here: number of rows of views to display
1279 * or canvas height entered on the command line (@graph_nr), and
1280 * max number of views on a single row (@views_per_row).
1281 * @action Action expected from current function.
1282 * @dfile Name of system activity data file (unused here).
1283 * @file_magic System activity file magic header (unused here).
1284 * @file_hdr System activity file standard header.
1285 * @act Array of activities (unused here).
1286 * @id_seq Activity sequence (unused here).
1287 * @file_actlst List of (known or unknown) activities in file (unused here).
1288 ***************************************************************************
1290 __printf_funct_t print_svg_header(void *parm, int action, char *dfile,
1291 struct file_magic *file_magic,
1292 struct file_header *file_hdr,
1293 struct activity *act[], unsigned int id_seq[],
1294 struct file_activity *file_actlst)
1296 struct svg_hdr_parm *hdr_parm = (struct svg_hdr_parm *) parm;
1298 unsigned int height = 0, ht = 0;
1301 if (action & F_BEGIN) {
1302 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1303 printf("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
1304 printf("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
1305 printf("<svg xmlns=\"http://www.w3.org/2000/svg\"");
1306 if (DISPLAY_TOC(flags)) {
1307 printf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
1309 if (action & F_END) {
1314 if (action & F_MAIN) {
1315 if (SET_CANVAS_HEIGHT(flags)) {
1317 * Option "-O height=..." used: @graph_nr is
1318 * the SVG canvas height set on the command line.
1320 height = hdr_parm->graph_nr;
1323 height = SVG_H_YSIZE +
1324 SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0) +
1325 SVG_T_YSIZE * hdr_parm->graph_nr;
1328 /* Min canvas height is 100 (at least to display "No data") */
1331 printf(" width=\"%d\" height=\"%d\""
1332 " fill=\"black\" stroke=\"#%06x\" stroke-width=\"1\">\n",
1333 SVG_T_XSIZE * (hdr_parm->views_per_row), height,
1334 svg_colors[palette][SVG_COL_DEFAULT_IDX]);
1335 printf("<text x=\"0\" y=\"30\" text-anchor=\"start\" stroke=\"#%06x\">",
1336 svg_colors[palette][SVG_COL_HEADER_IDX]);
1337 print_gal_header(localtime_r((const time_t *) &(file_hdr->sa_ust_time), &rectime),
1338 file_hdr->sa_sysname, file_hdr->sa_release,
1339 file_hdr->sa_nodename, file_hdr->sa_machine,
1340 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
1342 printf("</text>\n");
1343 if (DISPLAY_TOC(flags)) {
1344 for (i = 0; i < NR_ACT; i++) {
1346 continue; /* Activity not in file */
1348 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1349 if (!IS_SELECTED(act[p]->options) || !act[p]->g_nr)
1350 continue; /* Activity not selected or no graph available */
1352 printf("<a xlink:href=\"#g%d-0\" xlink:title=\"%s\">\n",
1353 act[p]->id, act[p]->name);
1354 printf("<text x=\"10\" y=\"%d\">%s</text></a>\n",
1355 SVG_H_YSIZE + ht, act[p]->desc);
1361 if (action & F_END) {
1362 if (!(action & F_BEGIN)) {
1363 if (!hdr_parm->graph_nr) {
1364 /* No views displayed */
1365 printf("<text x= \"0\" y=\"%d\" text-anchor=\"start\" stroke=\"#%06x\">",
1367 SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0),
1368 svg_colors[palette][SVG_COL_ERROR_IDX]);
1369 printf("No data!</text>\n");
1371 /* Give actual SVG height */
1372 printf("<!-- Actual canvas height: %d -->\n",
1374 SVG_C_YSIZE * (DISPLAY_TOC(flags) ? hdr_parm->nr_act_dispd : 0) +
1375 SVG_T_YSIZE * hdr_parm->graph_nr);
1382 ***************************************************************************
1383 * PCP header function.
1386 * @parm Specific parameter (unused here).
1387 * @action Action expected from current function.
1388 * @dfile Name of PCP archive file.
1389 * @file_magic System activity file magic header (unused here).
1390 * @file_hdr System activity file standard header (unused here).
1391 * @act Array of activities (unused here).
1392 * @id_seq Activity sequence (unused here).
1393 * @file_actlst List of (known or unknown) activities in file (unused here).
1394 ***************************************************************************
1396 __printf_funct_t print_pcp_header(void *parm, int action, char *dfile,
1397 struct file_magic *file_magic,
1398 struct file_header *file_hdr,
1399 struct activity *act[], unsigned int id_seq[],
1400 struct file_activity *file_actlst)
1405 unsigned long long utc_sec = file_hdr->sa_ust_time;
1407 if (action & F_BEGIN) {
1408 /* Create new PCP context */
1409 pmiStart(dfile, FALSE);
1411 if (PRINT_LOCAL_TIME(flags)) {
1412 tzset(); /* Set timezone value in tzname */
1413 pmiSetTimezone(tzname[0]);
1416 pmiSetTimezone("UTC");
1420 pmiSetHostname(file_hdr->sa_nodename);
1422 /* Save number of CPU in PCP archive */
1423 pmiAddMetric("hinv.ncpu",
1424 PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
1425 pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
1426 snprintf(buf, sizeof(buf), "%u",
1427 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
1428 pmiPutValue("hinv.ncpu", NULL, buf);
1431 if (action & F_END) {
1432 if (action & F_BEGIN) {
1433 /* Only the header data will be written to PCP archive */
1434 if (!PRINT_LOCAL_TIME(flags)) {
1435 /* Convert a time_t value from local time to UTC */
1436 if (gmtime_r((const time_t *) &(file_hdr->sa_ust_time), &lrectime)) {
1437 utc_sec = mktime(&lrectime);
1440 pmiWrite(utc_sec, 0);
1448 ***************************************************************************
1449 * Count the number of new network interfaces in current sample. If a new
1450 * interface is found then add it to the linked list starting at
1454 * @a Activity structure with statistics.
1455 * @curr Index in array for current sample statistics.
1458 * Number of new interfaces identified in current sample that were not
1459 * previously in the list.
1460 ***************************************************************************
1462 __nr_t count_new_net_dev(struct activity *a, int curr)
1465 struct stats_net_dev *sndc;
1467 for (i = 0; i < a->nr[curr]; i++) {
1468 sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + i * a->msize);
1470 nr += add_list_item(&(a->item_list), sndc->interface, MAX_IFACE_LEN);
1477 ***************************************************************************
1478 * Count the number of new network interfaces in current sample. If a new
1479 * interface is found then add it to the linked list starting at
1483 * @a Activity structure with statistics.
1484 * @curr Index in array for current sample statistics.
1487 * Number of new interfaces identified in current sample that were not
1488 * previously in the list.
1489 ***************************************************************************
1491 __nr_t count_new_net_edev(struct activity *a, int curr)
1494 struct stats_net_edev *snedc;
1496 for (i = 0; i < a->nr[curr]; i++) {
1497 snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + i * a->msize);
1499 nr += add_list_item(&(a->item_list), snedc->interface, MAX_IFACE_LEN);
1506 ***************************************************************************
1507 * Count the number of new filesystems in current sample. If a new
1508 * filesystem is found then add it to the linked list starting at
1512 * @a Activity structure with statistics.
1513 * @curr Index in array for current sample statistics.
1516 * Number of new filesystems identified in current sample that were not
1517 * previously in the list.
1518 ***************************************************************************
1520 __nr_t count_new_filesystem(struct activity *a, int curr)
1523 struct stats_filesystem *sfc;
1525 for (i = 0; i < a->nr[curr]; i++) {
1526 sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize);
1528 nr += add_list_item(&(a->item_list),
1529 DISPLAY_MOUNT(a->opt_flags) ? sfc->mountp : sfc->fs_name,
1537 ***************************************************************************
1538 * Count the number of new fchosts in current sample. If a new
1539 * fchost is found then add it to the linked list starting at
1543 * @a Activity structure with statistics.
1544 * @curr Index in array for current sample statistics.
1547 * Number of new fchosts identified in current sample that were not
1548 * previously in the list.
1549 ***************************************************************************
1551 __nr_t count_new_fchost(struct activity *a, int curr)
1554 struct stats_fchost *sfcc;
1556 for (i = 0; i < a->nr[curr]; i++) {
1557 sfcc = (struct stats_fchost *) ((char *) a->buf[curr] + i * a->msize);
1559 nr += add_list_item(&(a->item_list), sfcc->fchost_name, MAX_FCH_LEN);
1566 ***************************************************************************
1567 * Count the number of new block devices in current sample. If a new
1568 * block device is found then add it to the linked list starting at
1572 * @a Activity structure with statistics.
1573 * @curr Index in array for current sample statistics.
1576 * Number of new block devices identified in current sample that were not
1577 * previously in the list.
1578 ***************************************************************************
1580 __nr_t count_new_disk(struct activity *a, int curr)
1583 struct stats_disk *sdc;
1585 for (i = 0; i < a->nr[curr]; i++) {
1586 sdc = (struct stats_disk *) ((char *) a->buf[curr] + i * a->msize);
1588 nr += add_list_item(&(a->item_list),
1589 get_sa_devname(sdc->major, sdc->minor, flags),
1597 ***************************************************************************
1598 * Init custom color palette used to draw graphs (sadf -g).
1599 ***************************************************************************
1601 void init_custom_color_palette()
1607 /* Read S_COLORS_PALETTE environment variable */
1608 if ((e = __getenv(ENV_COLORS_PALETTE)) == NULL)
1609 /* Environment variable not set */
1612 for (p = strtok(e, ":"); p; p =strtok(NULL, ":")) {
1615 if ((len > 8) || (len < 3) || (*(p + 1) != '=') ||
1616 (strspn(p + 2, "0123456789ABCDEFabcdef") != (len - 2)))
1617 /* Ignore malformed codes */
1620 sscanf(p + 2, "%x", &val);
1622 if ((*p >= '0') && (*p <= '9')) {
1623 svg_colors[SVG_CUSTOM_COL_PALETTE][*p & 0xf] = val;
1626 else if (((*p >= 'A') && (*p <= 'F')) ||
1627 ((*p >= 'a') && (*p <= 'f'))) {
1628 svg_colors[SVG_CUSTOM_COL_PALETTE][9 + (*p & 0xf)] = val;
1634 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_GRID_IDX] = val;
1637 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_HEADER_IDX] = val;
1640 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_INFO_IDX] = val;
1643 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_BCKGRD_IDX] = val;
1646 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_DEFAULT_IDX] = val;
1649 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_TITLE_IDX] = val;
1652 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_ERROR_IDX] = val;
1655 svg_colors[SVG_CUSTOM_COL_PALETTE][SVG_COL_AXIS_IDX] = val;