]> granicus.if.org Git - sysstat/commitdiff
sadf: PCP: Initial support for A_QUEUE activity
authorSebastien GODARD <sysstat@users.noreply.github.com>
Sat, 23 Feb 2019 10:15:25 +0000 (11:15 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Sat, 23 Feb 2019 10:15:25 +0000 (11:15 +0100)
This is the initial (and experimental) support for creating PCP archives
by sadf.
I used the work made by Steve Kay (@stevekay) to create this patch: See
issue #136.
At the present time, only A_QUEUE activity is supported (i.e. the
metrics displayed by "sar -q").

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
activity.c
format.c
pcp_stats.c [new file with mode: 0644]
pcp_stats.h [new file with mode: 0644]
sa.h
sadf.c
sadf.h
sadf_misc.c

index 5276762767201b6d0adc2e139dfac2bc83e2e87e..d2a626a9c0f1491e5d0ae95b7d2e34f77af6d6a1 100644 (file)
@@ -31,6 +31,7 @@
 #include "json_stats.h"
 #include "svg_stats.h"
 #include "raw_stats.h"
+#include "pcp_stats.h"
 #endif
 
 /*
@@ -453,6 +454,7 @@ struct activity queue_act = {
        .f_json_print   = json_print_queue_stats,
        .f_svg_print    = svg_print_queue_stats,
        .f_raw_print    = raw_print_queue_stats,
+       .f_pcp_print    = pcp_print_queue_stats,
        .f_count_new    = NULL,
        .item_list      = NULL,
        .desc           = "Queue length and load average statistics",
index cf609e420ead2ace765f0670e1127d542f043c93..94cfc0c07a873096c550d0369bc7cbe4f5b3373a 100644 (file)
--- a/format.c
+++ b/format.c
@@ -140,6 +140,19 @@ struct report_format raw_fmt = {
        .f_comment      = print_raw_comment
 };
 
+/*
+ * PCP output.
+ */
+struct report_format pcp_fmt = {
+       .id             = F_PCP_OUTPUT,
+       .options        = FO_HEADER_ONLY,
+       .f_header       = print_pcp_header,
+       .f_statistics   = print_pcp_statistics,
+       .f_timestamp    = NULL,
+       .f_restart      = NULL,
+       .f_comment      = NULL
+};
+
 /*
  * Array of output formats.
  */
@@ -151,7 +164,8 @@ struct report_format *fmt[NR_FMT] = {
        &json_fmt,
        &conv_fmt,
        &svg_fmt,
-       &raw_fmt
+       &raw_fmt,
+       &pcp_fmt
 };
 #endif
 
diff --git a/pcp_stats.c b/pcp_stats.c
new file mode 100644 (file)
index 0000000..ecb5ac3
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * pcp_stats.c: Funtions used by sadf to create PCP archive files.
+ * (C) 2019 by Sebastien GODARD (sysstat <at> orange.fr)
+ *
+ ***************************************************************************
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU General Public License as published  by  the *
+ * Free Software Foundation; either version 2 of the License, or (at  your *
+ * option) any later version.                                              *
+ *                                                                         *
+ * This program is distributed in the hope that it  will  be  useful,  but *
+ * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
+ * for more details.                                                       *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License along *
+ * with this program; if not, write to the Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
+ ***************************************************************************
+ */
+
+#include "sa.h"
+#include "pcp_stats.h"
+
+#ifdef USE_NLS
+#include <locale.h>
+#include <libintl.h>
+#define _(string) gettext(string)
+#else
+#define _(string) (string)
+#endif
+
+extern unsigned int flags;
+
+#ifdef HAVE_PCP
+#include <pcp/pmapi.h>
+#include <pcp/import.h>
+#endif
+
+/*
+ ***************************************************************************
+ * Display PCP message error then exit.
+ *
+ * IN:
+ * @rc Error code.
+ ***************************************************************************
+ */
+void print_pcp_error(int rc)
+{
+#ifdef HAVE_PCP
+       fprintf(stderr, "PCP: pmiWrite: %s\n", pmiErrStr(rc));
+       exit(4);
+#endif
+}
+
+/*
+ ***************************************************************************
+ * Display queue and load statistics in PCP format
+ *
+ * IN:
+ * @a          Activity structure with statistics.
+ * @curr       Index in array for current sample statistics.
+ * @itv                Interval of time in 1/100th of a second.
+ * @record_hdr Record header for current sample.
+ ***************************************************************************
+ */
+__print_funct_t pcp_print_queue_stats(struct activity *a, int curr, unsigned long long itv,
+                                     struct record_header *record_hdr)
+{
+#ifdef HAVE_PCP
+       int rc;
+       char buf[64];
+       struct stats_queue
+               *sqc = (struct stats_queue *) a->buf[curr];
+
+       snprintf(buf, sizeof(buf), "%llu", sqc->nr_running);
+       pmiPutValue("proc.runq.runnable", NULL, buf);
+
+       snprintf(buf, sizeof(buf), "%llu", sqc->nr_threads);
+       pmiPutValue("proc.nprocs", NULL, buf);
+
+       snprintf(buf, sizeof(buf), "%llu", sqc->procs_blocked);
+       pmiPutValue("proc.blocked", NULL, buf);
+
+       snprintf(buf, sizeof(buf), "%f", (double) sqc->load_avg_1 / 100);
+       pmiPutValue("kernel.all.load", "1 min", buf);
+
+       snprintf(buf, sizeof(buf), "%f", (double) sqc->load_avg_5 / 100);
+       pmiPutValue("kernel.all.load", "5 min", buf);
+
+       snprintf(buf, sizeof(buf), "%f", (double) sqc->load_avg_15 / 100);
+       pmiPutValue("kernel.all.load", "15 min", buf);
+
+       if ((rc = pmiWrite(record_hdr->ust_time, 0)) < 0) {
+               print_pcp_error(rc);
+       }
+#endif /* HAVE_PCP */
+}
+
diff --git a/pcp_stats.h b/pcp_stats.h
new file mode 100644 (file)
index 0000000..e5a051d
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * pcp_stats.h: Include file used to display system statistics in PCP format.
+ * (C) 2019 by Sebastien Godard (sysstat <at> orange.fr)
+ */
+
+#ifndef _PCP_STATS_H
+#define _PCP_STATS_H
+
+/*
+ ***************************************************************************
+ * Prototypes for functions used to display system statistics in PCP format
+ ***************************************************************************
+ */
+
+/* Functions used to display statistics in PCP format */
+__print_funct_t pcp_print_queue_stats
+       (struct activity *, int, unsigned long long, struct record_header *);
+
+#endif /* _PCP_STATS_H */
diff --git a/sa.h b/sa.h
index 349e5fad48464cc72ad6ed72231a7276ae3d72fc..db34f7beae9965c99b5818d588dbe907cdc6ed25 100644 (file)
--- a/sa.h
+++ b/sa.h
@@ -817,6 +817,11 @@ struct activity {
         * This function is used by sadf to display activity statistics in raw format.
         */
        __print_funct_t (*f_raw_print) (struct activity *, char *, int);
+       /*
+        * This function is used by sadf to display activity statistics in PCP format.
+        */
+       __print_funct_t (*f_pcp_print) (struct activity *, int, unsigned long long,
+                                       struct record_header *);
        /*
         * This function is used by sadf to count the number of new items in current
         * sample and add them to the linked list @item_list.
@@ -1010,9 +1015,9 @@ struct report_format {
                                      struct activity * [], unsigned int [], struct file_activity *);
        /*
         * This function defines the statistics part of the report.
-        * Used only with textual (XML-like) reports.
+        * Used only with textual (XML-like) reports and PCP archives.
         */
-       __printf_funct_t (*f_statistics) (int *, int);
+       __printf_funct_t (*f_statistics) (int *, int, struct activity * [], unsigned int []);
        /*
         * This function defines the timestamp part of the report.
         * Used only with textual (XML-like) reports.
diff --git a/sadf.c b/sadf.c
index b2db388913ab67c5f941f353ed226eb02a73f27f..13086416e8ce3b65f30be7217e01063252c2a3bb 100644 (file)
--- a/sadf.c
+++ b/sadf.c
 # define _(string) (string)
 #endif
 
+#ifdef HAVE_PCP
+#include <pcp/pmapi.h>
+#include <pcp/import.h>
+#endif
+
 #ifdef USE_SCCSID
 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
 char *sccsid(void) { return (SCCSID); }
@@ -763,6 +768,13 @@ int generic_write_stats(int curr, int use_tm_start, int use_tm_end, int reset,
                                (*act[i]->f_raw_print)(act[i], pre, curr);
                        }
 
+                       else if (format == F_PCP_OUTPUT) {
+                               /* PCP archive */
+                               if (*act[i]->f_pcp_print) {
+                                       (*act[i]->f_pcp_print)(act[i], curr, itv, &record_hdr[curr]);
+                               }
+                       }
+
                        else {
                                /* Other output formats: db, ppc */
                                (*act[i]->f_render)(act[i], (format == F_DB_OUTPUT), pre, curr, itv);
@@ -981,12 +993,13 @@ void display_curr_act_graphs(int ifd, int *curr, long *cnt, int *eosaf,
  ***************************************************************************
  * Display file contents in selected format (logic #1).
  * Logic #1:   Grouped by record type. Sorted by timestamp.
- * Formats:    XML, JSON
+ * Formats:    XML, JSON, PCP
  *
  * IN:
  * @ifd                File descriptor of input file.
  * @file_actlst        List of (known or unknown) activities in file.
  * @file       System activity data file name (name of file being read).
+ * @pcparchive PCP archive file name.
  * @file_magic System activity file magic header.
  * @rectime    Structure where timestamp (expressed in local time or in UTC
  *             depending on whether options -T/-t have been used or not) can
@@ -996,7 +1009,7 @@ void display_curr_act_graphs(int ifd, int *curr, long *cnt, int *eosaf,
  ***************************************************************************
  */
 void logic1_display_loop(int ifd, struct file_activity *file_actlst, char *file,
-                        struct file_magic *file_magic,
+                        char *pcparchive, struct file_magic *file_magic,
                         struct tm *rectime, struct tm *loctime)
 {
        int curr, tab = 0, rtype;
@@ -1013,13 +1026,13 @@ void logic1_display_loop(int ifd, struct file_activity *file_actlst, char *file,
 
        /* Print header (eg. XML file header) */
        if (*fmt[f_position]->f_header) {
-               (*fmt[f_position]->f_header)(&tab, F_BEGIN, file, file_magic,
+               (*fmt[f_position]->f_header)(&tab, F_BEGIN, pcparchive, file_magic,
                                             &file_hdr, act, id_seq, file_actlst);
        }
 
        /* Process activities */
        if (*fmt[f_position]->f_statistics) {
-               (*fmt[f_position]->f_statistics)(&tab, F_BEGIN);
+               (*fmt[f_position]->f_statistics)(&tab, F_BEGIN, act, id_seq);
        }
 
        do {
@@ -1051,7 +1064,7 @@ void logic1_display_loop(int ifd, struct file_activity *file_actlst, char *file,
 
                                if (!eosaf && (rtype != R_COMMENT) && (rtype != R_RESTART)) {
                                        if (*fmt[f_position]->f_statistics) {
-                                               (*fmt[f_position]->f_statistics)(&tab, F_MAIN);
+                                               (*fmt[f_position]->f_statistics)(&tab, F_MAIN, act, id_seq);
                                        }
 
                                        /* next is set to 1 when we were close enough to desired interval */
@@ -1085,7 +1098,7 @@ void logic1_display_loop(int ifd, struct file_activity *file_actlst, char *file,
        while (!eosaf);
 
        if (*fmt[f_position]->f_statistics) {
-               (*fmt[f_position]->f_statistics)(&tab, F_END);
+               (*fmt[f_position]->f_statistics)(&tab, F_END, act, id_seq);
        }
 
        /* Rewind file */
@@ -1132,7 +1145,7 @@ void logic1_display_loop(int ifd, struct file_activity *file_actlst, char *file,
 
        /* Print header trailer */
        if (*fmt[f_position]->f_header) {
-               (*fmt[f_position]->f_header)(&tab, F_END, file, file_magic,
+               (*fmt[f_position]->f_header)(&tab, F_END, pcparchive, file_magic,
                                             &file_hdr, act, id_seq, file_actlst);
        }
 }
@@ -1402,9 +1415,10 @@ close_svg:
  *
  * IN:
  * @dfile      System activity data file name.
+ * @pcparchive PCP archive file name.
  ***************************************************************************
  */
-void read_stats_from_file(char dfile[])
+void read_stats_from_file(char dfile[], char pcparchive[])
 {
        struct file_magic file_magic;
        struct file_activity *file_actlst = NULL;
@@ -1418,6 +1432,9 @@ void read_stats_from_file(char dfile[])
 
        if (DISPLAY_HDR_ONLY(flags)) {
                if (*fmt[f_position]->f_header) {
+                       if (format == F_PCP_OUTPUT) {
+                               dfile = pcparchive;
+                       }
                        /* Display only data file header then exit */
                        (*fmt[f_position]->f_header)(&tab, F_BEGIN + F_END, dfile, &file_magic,
                                                     &file_hdr, act, id_seq, file_actlst);
@@ -1438,7 +1455,7 @@ void read_stats_from_file(char dfile[])
                                    &rectime, &loctime, dfile, &file_magic);
        }
        else {
-               logic1_display_loop(ifd, file_actlst, dfile,
+               logic1_display_loop(ifd, file_actlst, dfile, pcparchive,
                                    &file_magic, &rectime, &loctime);
        }
 
@@ -1831,7 +1848,7 @@ int main(int argc, char **argv)
        }
        else {
                /* Read stats from file */
-               read_stats_from_file(dfile);
+               read_stats_from_file(dfile, pcparchive);
        }
 
        /* Free bitmaps */
diff --git a/sadf.h b/sadf.h
index 98b90af7974d462506d7228b17b5c8de9c1978ff..1d892e87d17eb3a5ea5a9cc2786e08ee87e7498c 100644 (file)
--- a/sadf.h
+++ b/sadf.h
@@ -161,9 +161,11 @@ __printf_funct_t print_raw_comment
  * Prototypes used to display the statistics part of the report
  */
 __printf_funct_t print_xml_statistics
-       (int *, int);
+       (int *, int, struct activity * [], unsigned int []);
 __printf_funct_t print_json_statistics
-       (int *, int);
+       (int *, int, struct activity * [], unsigned int []);
+__printf_funct_t print_pcp_statistics
+       (int *, int, struct activity * [], unsigned int []);
 
 /*
  * Prototypes used to display the timestamp part of the report
@@ -194,5 +196,8 @@ __printf_funct_t print_hdr_header
 __printf_funct_t print_svg_header
        (void *, int, char *, struct file_magic *, struct file_header *,
         struct activity * [], unsigned int [], struct file_activity *);
+__printf_funct_t print_pcp_header
+       (void *, int, char *, struct file_magic *, struct file_header *,
+        struct activity * [], unsigned int [], struct file_activity *);
 
 #endif  /* _SADF_H */
index 9242ac2d14a9c0fa16c2046031d6f48b74e69b86..e3d952081278ff791b063bde729aaffbcd8bbe84 100644 (file)
 #define _(string) (string)
 #endif
 
+#ifdef HAVE_PCP
+#include <pcp/pmapi.h>
+#include <pcp/import.h>
+#endif
+
 extern unsigned int flags;
 extern char *seps[];
 
@@ -406,12 +411,15 @@ __printf_funct_t print_raw_comment(int *tab, int action, char *cur_date,
  * IN:
  * @tab                Number of tabulations.
  * @action     Action expected from current function.
+ * @act                Array of activities (unused here).
+ * @id_seq     Activity sequence (unused here).
  *
  * OUT:
  * @tab                Number of tabulations.
  ***************************************************************************
  */
-__printf_funct_t print_xml_statistics(int *tab, int action)
+__printf_funct_t print_xml_statistics(int *tab, int action, struct activity *act[],
+                                     unsigned int id_seq[])
 {
        if (action & F_BEGIN) {
                xprintf((*tab)++, "<statistics>");
@@ -428,12 +436,15 @@ __printf_funct_t print_xml_statistics(int *tab, int action)
  * IN:
  * @tab                Number of tabulations.
  * @action     Action expected from current function.
+ * @act                Array of activities (unused here).
+ * @id_seq     Activity sequence (unused here).
  *
  * OUT:
  * @tab                Number of tabulations.
  ***************************************************************************
  */
-__printf_funct_t print_json_statistics(int *tab, int action)
+__printf_funct_t print_json_statistics(int *tab, int action, struct activity *act[],
+                                      unsigned int id_seq[])
 {
        static int sep = FALSE;
 
@@ -457,6 +468,59 @@ __printf_funct_t print_json_statistics(int *tab, int action)
        }
 }
 
+/*
+ ***************************************************************************
+ * Display the "statistics" part of the report (PCP format).
+ *
+ * IN:
+ * @tab                Number of tabulations (unused here).
+ * @action     Action expected from current function.
+ * @act                Array of activities.
+ * @id_seq     Activity sequence.
+ ***************************************************************************
+ */
+__printf_funct_t print_pcp_statistics(int *tab, int action, struct activity *act[],
+                                     unsigned int id_seq[])
+{
+#ifdef HAVE_PCP
+       int i, p;
+       pmInDom indom;
+
+       if (action & F_BEGIN) {
+               for (i = 0; i < NR_ACT; i++) {
+                       if (!id_seq[i])
+                               continue;       /* Activity not in file */
+
+                       p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
+                       if (!IS_SELECTED(act[p]->options))
+                               continue;       /* Activity not selected */
+
+                       switch (act[p]->id) {
+
+                               case A_QUEUE:
+                                       pmiAddMetric("proc.runq.runnable",
+                                                    PM_IN_NULL, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT,
+                                                    pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
+                                       pmiAddMetric("proc.nprocs",
+                                                    PM_IN_NULL, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT,
+                                                    pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
+                                       pmiAddMetric("proc.blocked",
+                                                    PM_IN_NULL, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT,
+                                                    pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
+                                       indom = pmInDom_build(0, 0);
+                                       pmiAddMetric("kernel.all.load",
+                                                    PM_IN_NULL, PM_TYPE_FLOAT, indom, PM_SEM_INSTANT,
+                                                    pmiUnits(0, 0, 0, 0, 0, 0));
+                                       pmiAddInstance(indom, "1 min", 0);
+                                       pmiAddInstance(indom, "5 min", 1);
+                                       pmiAddInstance(indom, "15 min", 2);
+                                       break;
+                       }
+               }
+       }
+#endif /* HAVE_PCP */
+}
+
 /*
  ***************************************************************************
  * Display the "timestamp" part of the report (db and ppc format).
@@ -679,7 +743,7 @@ __tm_funct_t print_raw_timestamp(void *parm, int action, char *cur_date,
  * IN:
  * @parm       Specific parameter. Here: number of tabulations.
  * @action     Action expected from current function.
- * @dfile      Name of system activity data file.
+ * @dfile      Unused here (PCP archive file).
  * @file_magic System activity file magic header.
  * @file_hdr   System activity file standard header.
  * @act                Array of activities (unused here).
@@ -747,7 +811,7 @@ __printf_funct_t print_xml_header(void *parm, int action, char *dfile,
  * IN:
  * @parm       Specific parameter. Here: number of tabulations.
  * @action     Action expected from current function.
- * @dfile      Name of system activity data file.
+ * @dfile      Unused here (PCP archive file).
  * @file_magic System activity file magic header.
  * @file_hdr   System activity file standard header.
  * @act                Array of activities (unused here).
@@ -808,7 +872,7 @@ __printf_funct_t print_json_header(void *parm, int action, char *dfile,
  * IN:
  * @parm       Specific parameter (unused here).
  * @action     Action expected from current function.
- * @dfile      Name of system activity data file.
+ * @dfile      Name of system activity data file (unused here).
  * @file_magic System activity file magic header.
  * @file_hdr   System activity file standard header.
  * @act                Array of activities.
@@ -1005,6 +1069,53 @@ __printf_funct_t print_svg_header(void *parm, int action, char *dfile,
        }
 }
 
+/*
+ ***************************************************************************
+ * PCP header function.
+ *
+ * IN:
+ * @parm       Specific parameter.
+ * @action     Action expected from current function.
+ * @dfile      Name of PCP archive file.
+ * @file_magic System activity file magic header (unused here).
+ * @file_hdr   System activity file standard header (unused here).
+ * @act                Array of activities (unused here).
+ * @id_seq     Activity sequence (unused here).
+ * @file_actlst        List of (known or unknown) activities in file (unused here).
+ ***************************************************************************
+ */
+__printf_funct_t print_pcp_header(void *parm, int action, char *dfile,
+                                 struct file_magic *file_magic,
+                                 struct file_header *file_hdr,
+                                 struct activity *act[], unsigned int id_seq[],
+                                 struct file_activity *file_actlst)
+{
+#ifdef HAVE_PCP
+       char buf[64];
+
+       if (action & F_BEGIN) {
+               /* Create new PCP context */
+               pmiStart(dfile, FALSE);
+               pmiSetTimezone("UTC");
+
+               /* Save number of CPU in PCP archive */
+               pmiAddMetric("hinv.ncpu",
+                            PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+                            pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE));
+               snprintf(buf, sizeof(buf), "%u",
+                        file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
+               pmiPutValue("hinv.ncpu", NULL, buf);
+       }
+
+       if (action & F_END) {
+               if (action & F_BEGIN) {
+                       pmiWrite(file_hdr->sa_ust_time, 0);
+               }
+               pmiEnd();
+       }
+#endif
+}
+
 /*
  ***************************************************************************
  * Count the number of new network interfaces in current sample. If a new