#include "json_stats.h"
#include "svg_stats.h"
#include "raw_stats.h"
+#include "pcp_stats.h"
#endif
/*
.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",
.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.
*/
&json_fmt,
&conv_fmt,
&svg_fmt,
- &raw_fmt
+ &raw_fmt,
+ &pcp_fmt
};
#endif
--- /dev/null
+/*
+ * 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 */
+}
+
--- /dev/null
+/*
+ * 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 */
* 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.
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.
# 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); }
(*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);
***************************************************************************
* 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
***************************************************************************
*/
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;
/* 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 {
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 */
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 */
/* 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);
}
}
*
* 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;
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);
&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);
}
}
else {
/* Read stats from file */
- read_stats_from_file(dfile);
+ read_stats_from_file(dfile, pcparchive);
}
/* Free bitmaps */
* 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
__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 */
#define _(string) (string)
#endif
+#ifdef HAVE_PCP
+#include <pcp/pmapi.h>
+#include <pcp/import.h>
+#endif
+
extern unsigned int flags;
extern char *seps[];
* 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>");
* 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;
}
}
+/*
+ ***************************************************************************
+ * 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).
* 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).
* 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).
* 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.
}
}
+/*
+ ***************************************************************************
+ * 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