From: Daniel Wagner <dwagner@suse.de> To: Clark Williams <williams@redhat.com>, John Kacur <jkacur@redhat.com> Cc: linux-rt-users@vger.kernel.org, Daniel Wagner <dwagner@suse.de> Subject: [RFC rt-tests v1 4/4] cyclictest: Add JSON output feature Date: Fri, 18 Dec 2020 20:35:40 +0100 [thread overview] Message-ID: <20201218193540.6168-5-dwagner@suse.de> (raw) In-Reply-To: <20201218193540.6168-1-dwagner@suse.de> Add --output command line opttion which will store the results into a JSON file. Signed-off-by: Daniel Wagner <dwagner@suse.de> --- src/cyclictest/cyclictest.c | 146 +++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c index c0e7600b4740..a93e9ee2426d 100644 --- a/src/cyclictest/cyclictest.c +++ b/src/cyclictest/cyclictest.c @@ -11,6 +11,7 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> +#include <inttypes.h> #include <stdarg.h> #include <unistd.h> #include <fcntl.h> @@ -217,6 +218,7 @@ static struct timespec globalt; static char fifopath[MAX_PATH]; static char histfile[MAX_PATH]; +static char outfile[MAX_PATH]; static struct thread_param **parameters; static struct thread_stat **statistics; @@ -950,7 +952,7 @@ enum option_values { OPT_TRIGGER_NODES, OPT_UNBUFFERED, OPT_NUMA, OPT_VERBOSE, OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, OPT_NUMOPTS, OPT_ALIGNED, OPT_SECALIGNED, OPT_LAPTOP, OPT_SMI, - OPT_TRACEMARK, OPT_POSIX_TIMERS, + OPT_TRACEMARK, OPT_POSIX_TIMERS, OPT_OUTPUT }; /* Process commandline options */ @@ -1003,6 +1005,7 @@ static void process_options(int argc, char *argv[]) {"policy", required_argument, NULL, OPT_POLICY }, {"help", no_argument, NULL, OPT_HELP }, {"posix_timers", no_argument, NULL, OPT_POSIX_TIMERS }, + {"output", required_argument, NULL, OPT_OUTPUT }, {NULL, 0, NULL, 0 }, }; int c = getopt_long(argc, argv, "a::A::b:c:d:D:h:H:i:l:MNo:p:mqrRsSt::uvD:x", @@ -1059,6 +1062,7 @@ static void process_options(int argc, char *argv[]) case OPT_HISTFILE: use_histfile = 1; strncpy(histfile, optarg, strnlen(optarg, MAX_PATH-1)); + histfile[MAX_PATH-1] = '\0'; break; case 'i': case OPT_INTERVAL: @@ -1078,6 +1082,10 @@ static void process_options(int argc, char *argv[]) case 'o': case OPT_OSCOPE: oscope_reduction = atoi(optarg); break; + case OPT_OUTPUT: + strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1)); + outfile[MAX_PATH-1] = '\0'; + break; case 'p': case OPT_PRIORITY: priority = atoi(optarg); @@ -1695,6 +1703,124 @@ static void rstat_setup(void) return; } +struct system_info { + char *sysname; + char *nodename; + char *release; + char *version; + char *machine; +}; + +struct system_info *collect_system_info(void) +{ + struct system_info *si; + struct utsname buf; + int err; + + si = malloc(sizeof(struct system_info)); + if (!si) + err_exit(ENOMEM, "malloc()"); + + err = uname(&buf); + if (err) + err_exit(errno, "Could not retrieve system information"); + + si->sysname = strdup(buf.sysname); + si->nodename = strdup(buf.nodename); + si->release = strdup(buf.release); + si->version = strdup(buf.version); + si->machine = strdup(buf.machine); + + if (!si->sysname || + !si->nodename || + !si->release || + !si->version || + !si->machine) + err_exit(ENOMEM, "Could not copy system information"); + + return si; +} + +static char *get_cmdline(int argc, char *argv[]) +{ + char *cmdline; + int len, i; + + len = 0; + for (i = 0; i < argc; i++) + len += strlen(argv[i]) + 1; + + cmdline = malloc(len); + if (!cmdline) + err_exit(ENOMEM, "Could not copy cmdline"); + + cmdline[0] = '\0'; + for (i = 0; i < argc;) { + cmdline = strcat(cmdline, argv[i]); + i++; + if (i < argc) + cmdline = strcat(cmdline, " "); + } + + return cmdline; +} + +void free_system_info(struct system_info *sysinfo) +{ + free(sysinfo->sysname); + free(sysinfo->nodename); + free(sysinfo->release); + free(sysinfo->version); + free(sysinfo->machine); + free(sysinfo); +} + +static void dump_stats(FILE *f, struct system_info *sysinfo, + char *cmdline, struct thread_param **par) +{ + unsigned int i, j, comma; + struct thread_stat *s; + + fprintf(f, "{\n"); + fprintf(f, " \"file_version\": 1,\n"); + fprintf(f, " \"version:\": \"cyclictest V %1.2f\",\n", VERSION); + fprintf(f, " \"num_threads\": %d,\n", num_threads); + fprintf(f, " \"resolution_in_ns\": %u,\n", use_nsecs); + fprintf(f, " \"cmdline:\": \"%s\",\n", cmdline); + fprintf(f, " \"sysinfo\": {\n"); + fprintf(f, " \"sysname\": \"%s\",\n", sysinfo->sysname); + fprintf(f, " \"nodename\": \"%s\",\n", sysinfo->nodename); + fprintf(f, " \"release\": \"%s\",\n", sysinfo->release); + fprintf(f, " \"version\": \"%s\",\n", sysinfo->version); + fprintf(f, " \"machine\": \"%s\"\n", sysinfo->machine); + fprintf(f, " },\n"); + fprintf(f, " \"thread\": {\n"); + for (i = 0; i < num_threads; i++) { + fprintf(f, " \"%u\": {\n", i); + + fprintf(f, " \"histogram\": {"); + s = par[i]->stats; + for (j = 0, comma = 0; j < histogram; j++) { + if (s->hist_array[j] == 0) + continue; + fprintf(f, "%s", comma ? ",\n" : "\n"); + fprintf(f, " \"%u\": %" PRIu64,j, s->hist_array[j]); + comma = 1; + } + if (comma) + fprintf(f, "\n"); + fprintf(f, " },\n"); + fprintf(f, " \"cycles\": %" PRIu64 ",\n", s->cycles); + fprintf(f, " \"min\": %" PRIu64 ",\n", s->min); + fprintf(f, " \"max\": %" PRIu64 ",\n", s->max); + fprintf(f, " \"avg\": %.2f,\n", s->avg/s->cycles); + fprintf(f, " \"cpu\": %d,\n", par[i]->cpu); + fprintf(f, " \"node\": %d\n", par[i]->node); + fprintf(f, " }%s\n", i == num_threads - 1 ? "" : ","); + } + fprintf(f, " }\n"); + fprintf(f, "}\n"); +} int main(int argc, char **argv) { @@ -2038,6 +2164,24 @@ int main(int argc, char **argv) if (!verbose && !quiet && refresh_on_max) printf("\033[%dB", num_threads + 2); + if (strlen(outfile) != 0) { + FILE *f = fopen(outfile, "w"); + struct system_info *sysinfo; + char *cmdline; + + if (!f) + err_exit(errno, "Failed to open output file '%s'", outfile); + + sysinfo = collect_system_info(); + cmdline = get_cmdline(argc, argv); + + dump_stats(f, sysinfo, cmdline, parameters); + + free(cmdline); + free_system_info(sysinfo); + fclose(f); + } + if (quiet) quiet = 2; for (i = 0; i < num_threads; i++) { -- 2.29.2
prev parent reply other threads:[~2020-12-18 19:36 UTC|newest] Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-12-18 19:35 [RFC rt-tests v1 0/4] Generate machine-readable output Daniel Wagner 2020-12-18 19:35 ` [RFC rt-tests v1 1/4] rt-tests: Rename error.h to rt-error.h Daniel Wagner 2020-12-18 19:35 ` [RFC rt-tests v1 2/4] cyclictest: Move thread data to struct thread_param Daniel Wagner 2020-12-18 19:35 ` [RFC rt-tests v1 3/4] signaltest: " Daniel Wagner 2020-12-18 19:35 ` Daniel Wagner [this message]
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20201218193540.6168-5-dwagner@suse.de \ --to=dwagner@suse.de \ --cc=jkacur@redhat.com \ --cc=linux-rt-users@vger.kernel.org \ --cc=williams@redhat.com \ --subject='Re: [RFC rt-tests v1 4/4] cyclictest: Add JSON output feature' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.