linux-rt-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH rt-tests v5 00/13] Generate machine-readable output
@ 2021-02-10 17:51 Daniel Wagner
  2021-02-10 17:51 ` [PATCH rt-tests v5 01/13] cyclictest: Move thread data to struct thread_param Daniel Wagner
                   ` (12 more replies)
  0 siblings, 13 replies; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

v5:
  - add 'realtime' to common header
  - add timestamp to common header
  - oslat add quiet option
  - oslat fix JSON formatting
  - rt-migrate fix JSON formatting
 
v4:
  - rebased on top of '[rt-tests v3 00/16] rt-numa.h cleanups' series
  - dropped applied patches
  - dropped RFC label

v3:
  - A number of bug fixes added at the beginning of
    the series.
  - Add --output option to all tests which have a
    numeric results, not just failed/passed

v2:
  - Moved the common JSON parts into rt-util.[ch]
  - Add --output option to signaltest

The current output of cyclictest is optimized for humans to read. This
is all good when working directly with the tools. But for CI
integration it's a bit of pain. Furthermore, not all rt-tests use the
same output format.

By using some easy to parse existing machine-readable format we can use
standard libraries to parse the data. For example in jitterdebug there
is a short Python program[1] to visualize either the histogram[2] or
all samples[3].

The implementation for JSON output for this is very simple. The last
patch adds a version of jitterdebugs's JSON output, which looks like

{
  "file_version": 1,
  "version:": "cyclictest V 1.90",
  "num_threads": 2,
  "resolution_in_ns": 0,
  "cmdline:": "./cyclictest --affinity=1-2 --duration=1s --output=dump.json -h 1000 -p 80",
  "sysinfo": {
    "sysname": "Linux",
    "nodename": "beryllium",
    "release": "5.9.14-1-default",
    "version": "#1 SMP Sat Dec 12 06:57:32 UTC 2020 (c648a46)",
    "machine": "x86_64"
  },
  "thread": {
    "0": {
      "histogram": {
        "0": 16,
        "1": 853,
        "2": 80,
        "3": 50,
        "4": 1
      },
      "cycles": 1000,
      "min": 0,
      "max": 4,
      "avg": 1.17,
      "cpu": 1,
      "node": 0
    },
    "1": {
      "histogram": {
        "0": 14,
        "1": 833,
        "2": 93,
        "3": 56,
        "4": 4
      },
      "cycles": 1000,
      "min": 0,
      "max": 4,
      "avg": 1.20,
      "cpu": 2,
      "node": 0
    }
  }
}

It's just a rough version. I didn't try to make it generic for the
other rt-tests or make it as plugin as John was suggesting. I'd think
we could make this feature as compile option, if you want to keep the
program small. Obviously, we could also make the terminal output a
compile option, to keep it small.

Anyway, what do you think about it?

Thanks,
Daniel

Daniel Wagner (13):
  cyclictest: Move thread data to struct thread_param
  signaltest: Move thread data to struct thread_param
  rt-utils: Add JSON common header output helper
  cyclictest: Add JSON output feature
  signaltest: Add JSON output feature
  cyclicdeadline: Add JSON output feature
  pmqtest: Add JSON output feature
  ptsematest: Add JSON output feature
  sigwaittest: Add JSON output feature
  svsematest: Add JSON output feature
  oslat: Add JSON output feature
  rt-migrate-test: Add JSON output feature
  oslat: Add quiet command line option

 src/cyclictest/cyclictest.c           |  80 ++++++++++---
 src/include/rt-utils.h                |   4 +
 src/lib/rt-utils.c                    |  96 ++++++++++++++++
 src/oslat/oslat.c                     | 118 ++++++++++++++++----
 src/pmqtest/pmqtest.c                 | 137 +++++++++++++++++++----
 src/ptsematest/ptsematest.c           | 120 ++++++++++++++++----
 src/rt-migrate-test/rt-migrate-test.c | 120 ++++++++++++++++----
 src/sched_deadline/cyclicdeadline.c   |  72 +++++++++---
 src/signaltest/signaltest.c           | 154 +++++++++++++++++++-------
 src/sigwaittest/sigwaittest.c         | 117 ++++++++++++++++---
 src/svsematest/svsematest.c           | 124 +++++++++++++++++----
 11 files changed, 946 insertions(+), 196 deletions(-)

-- 
2.30.0


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 01/13] cyclictest: Move thread data to struct thread_param
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:52   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 02/13] signaltest: " Daniel Wagner
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Group thread realated data such as thread ID to struct thread_param.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/cyclictest/cyclictest.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
index c4b2369bee6b..7c45732c1553 100644
--- a/src/cyclictest/cyclictest.c
+++ b/src/cyclictest/cyclictest.c
@@ -113,6 +113,9 @@ static char *policyname(int policy);
 
 /* Struct to transfer parameters to the thread */
 struct thread_param {
+	pthread_t thread;
+	int threadstarted;
+	int tid;
 	int prio;
 	int policy;
 	int mode;
@@ -141,9 +144,6 @@ struct thread_stat {
 	long *smis;
 	long *hist_array;
 	long *outliers;
-	pthread_t thread;
-	int threadstarted;
-	int tid;
 	long reduce;
 	long redmax;
 	long cycleofmax;
@@ -530,7 +530,7 @@ static void *timerthread(void *param)
 	interval.tv_sec = par->interval / USEC_PER_SEC;
 	interval.tv_nsec = (par->interval % USEC_PER_SEC) * 1000;
 
-	stat->tid = gettid();
+	par->tid = gettid();
 
 	sigemptyset(&sigset);
 	sigaddset(&sigset, par->signal);
@@ -539,7 +539,7 @@ static void *timerthread(void *param)
 	if (par->mode == MODE_CYCLIC) {
 		sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
 		sigev.sigev_signo = par->signal;
-		sigev.sigev_notify_thread_id = stat->tid;
+		sigev.sigev_notify_thread_id = par->tid;
 		timer_create(par->clock, &sigev, &timer);
 		tspec.it_interval = interval;
 	}
@@ -613,7 +613,7 @@ static void *timerthread(void *param)
 		setitimer(ITIMER_REAL, &itimer, NULL);
 	}
 
-	stat->threadstarted++;
+	par->threadstarted++;
 
 	while (!shutdown) {
 
@@ -719,7 +719,7 @@ static void *timerthread(void *param)
 			shutdown++;
 			pthread_mutex_lock(&break_thread_id_lock);
 			if (break_thread_id == 0) {
-				break_thread_id = stat->tid;
+				break_thread_id = par->tid;
 				tracemark("hit latency threshold (%llu > %d)",
 					  (unsigned long long) diff, tracelimit);
 				break_thread_value = diff;
@@ -795,7 +795,7 @@ static void *timerthread(void *param)
 	/* switch to normal */
 	schedp.sched_priority = 0;
 	sched_setscheduler(0, SCHED_OTHER, &schedp);
-	stat->threadstarted = -1;
+	par->threadstarted = -1;
 
 	return NULL;
 }
@@ -1293,7 +1293,7 @@ static void print_tids(struct thread_param *par[], int nthreads)
 
 	printf("# Thread Ids:");
 	for (i = 0; i < nthreads; i++)
-		printf(" %05d", par[i]->stats->tid);
+		printf(" %05d", par[i]->tid);
 	printf("\n");
 }
 
@@ -1407,7 +1407,7 @@ static void print_stat(FILE *fp, struct thread_param *par, int index, int verbos
 				fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
 				        "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld";
 
-			fprintf(fp, fmt, index, stat->tid, par->prio,
+			fprintf(fp, fmt, index, par->tid, par->prio,
 				par->interval, stat->cycles, stat->min,
 				stat->act, stat->cycles ?
 				(long)(stat->avg/stat->cycles) : 0, stat->max);
@@ -1463,7 +1463,7 @@ static void rstat_print_stat(struct thread_param *par, int index, int verbose, i
 				fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
 				        "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld";
 
-			dprintf(fd, fmt, index, stat->tid, par->prio,
+			dprintf(fd, fmt, index, par->tid, par->prio,
 				par->interval, stat->cycles, stat->min,
 				stat->act, stat->cycles ?
 				(long)(stat->avg/stat->cycles) : 0, stat->max);
@@ -1966,9 +1966,9 @@ int main(int argc, char **argv)
 		stat->min = 1000000;
 		stat->max = 0;
 		stat->avg = 0.0;
-		stat->threadstarted = 1;
 		stat->smi_count = 0;
-		status = pthread_create(&stat->thread, &attr, timerthread, par);
+		par->threadstarted = 1;
+		status = pthread_create(&par->thread, &attr, timerthread, par);
 		if (status)
 			fatal("failed to create thread %d: %s\n", i, strerror(status));
 
@@ -2038,10 +2038,10 @@ int main(int argc, char **argv)
 	if (quiet)
 		quiet = 2;
 	for (i = 0; i < num_threads; i++) {
-		if (statistics[i]->threadstarted > 0)
-			pthread_kill(statistics[i]->thread, SIGTERM);
-		if (statistics[i]->threadstarted) {
-			pthread_join(statistics[i]->thread, NULL);
+		if (parameters[i]->threadstarted > 0)
+			pthread_kill(parameters[i]->thread, SIGTERM);
+		if (parameters[i]->threadstarted) {
+			pthread_join(parameters[i]->thread, NULL);
 			if (quiet && !histogram)
 				print_stat(stdout, parameters[i], i, 0, 0);
 		}
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 02/13] signaltest: Move thread data to struct thread_param
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
  2021-02-10 17:51 ` [PATCH rt-tests v5 01/13] cyclictest: Move thread data to struct thread_param Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:52   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 03/13] rt-utils: Add JSON common header output helper Daniel Wagner
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Group thread realated data such as thread ID to struct thread_param.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/signaltest/signaltest.c | 44 ++++++++++++++++++-------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/src/signaltest/signaltest.c b/src/signaltest/signaltest.c
index c34bc994d886..dd5633d5fc51 100644
--- a/src/signaltest/signaltest.c
+++ b/src/signaltest/signaltest.c
@@ -40,6 +40,10 @@
 
 /* Struct to transfer parameters to the thread */
 struct thread_param {
+	pthread_t thread;
+	pthread_t tothread;
+	int threadstarted;
+	int tid;
 	int id;
 	int prio;
 	int signal;
@@ -47,6 +51,7 @@ struct thread_param {
 	struct thread_stat *stats;
 	int bufmsk;
 	int cpu;
+	int interrupted;
 };
 
 /* Struct for statistics */
@@ -58,11 +63,6 @@ struct thread_stat {
 	long act;
 	double avg;
 	long *values;
-	pthread_t thread;
-	pthread_t tothread;
-	int threadstarted;
-	int tid;
-	int interrupted;
 };
 
 static int shutdown;
@@ -86,7 +86,7 @@ void *signalthread(void *param)
 	pthread_t thread;
 	cpu_set_t mask;
 
-	stat->tid = gettid();
+	par->tid = gettid();
 
 	if (par->cpu != -1) {
 		CPU_ZERO(&mask);
@@ -105,7 +105,7 @@ void *signalthread(void *param)
 	schedp.sched_priority = par->prio;
 	sched_setscheduler(0, policy, &schedp);
 
-	stat->threadstarted++;
+	par->threadstarted++;
 
 	clock_gettime(CLOCK_MONOTONIC, &before);
 
@@ -128,7 +128,7 @@ void *signalthread(void *param)
 
 		/* Get current time */
 		clock_gettime(CLOCK_MONOTONIC, &now);
-		pthread_kill(stat->tothread, SIGUSR1);
+		pthread_kill(par->tothread, SIGUSR1);
 
 		/* Skip the first cycle */
 		if (first) {
@@ -148,7 +148,7 @@ void *signalthread(void *param)
 
 		if (!stopped && tracelimit && !par->id  && (diff > tracelimit)) {
 			stat->act = diff;
-			stat->interrupted = 1;
+			par->interrupted = 1;
 			stopped++;
 			shutdown++;
 		}
@@ -167,7 +167,7 @@ void *signalthread(void *param)
 	schedp.sched_priority = 0;
 	sched_setscheduler(0, SCHED_OTHER, &schedp);
 
-	stat->threadstarted = -1;
+	par->threadstarted = -1;
 
 	return NULL;
 }
@@ -298,7 +298,7 @@ static void print_stat(struct thread_param *par, int index, int verbose)
 		if (quiet != 1) {
 			printf("T:%2d (%5d) P:%2d C:%7lu "
 			       "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld\n",
-			       index, stat->tid, par->prio,
+			       index, par->tid, par->prio,
 			       stat->cycles, stat->min, stat->act,
 			       stat->cycles ?
 			       (long)(stat->avg/stat->cycles) : 0, stat->max);
@@ -389,8 +389,8 @@ int main(int argc, char **argv)
 		stat[i].min = 1000000;
 		stat[i].max = -1000000;
 		stat[i].avg = 0.0;
-		stat[i].threadstarted = 1;
-		status = pthread_create(&stat[i].thread, NULL, signalthread,
+		par[i].threadstarted = 1;
+		status = pthread_create(&par[i].thread, NULL, signalthread,
 					&par[i]);
 		if (status)
 			fatal("failed to create thread %d: %s\n", i,
@@ -401,18 +401,18 @@ int main(int argc, char **argv)
 		int allstarted = 1;
 
 		for (i = 0; i < num_threads; i++) {
-			if (stat[i].threadstarted != 2)
+			if (par[i].threadstarted != 2)
 				allstarted = 0;
 		}
 		if (!allstarted)
 			continue;
 
 		for (i = 0; i < num_threads - 1; i++)
-			stat[i].tothread = stat[i+1].thread;
-		stat[i].tothread = stat[0].thread;
+			par[i].tothread = par[i+1].thread;
+		par[i].tothread = par[0].thread;
 		break;
 	}
-	pthread_kill(stat[0].thread, signum);
+	pthread_kill(par[0].thread, signum);
 
 	while (!shutdown) {
 		char lavg[256];
@@ -443,12 +443,12 @@ int main(int argc, char **argv)
 	if (quiet)
 		quiet = 2;
 	for (i = 0; i < num_threads; i++) {
-		if (stat[i].threadstarted > 0)
-			pthread_kill(stat[i].thread, SIGUSR1);
-		if (stat[i].interrupted)
+		if (par[i].threadstarted > 0)
+			pthread_kill(par[i].thread, SIGUSR1);
+		if (par[i].interrupted)
 			printf("Thread %d exceeded trace limit.\n", i);
-		if (stat[i].threadstarted) {
-			pthread_join(stat[i].thread, NULL);
+		if (par[i].threadstarted) {
+			pthread_join(par[i].thread, NULL);
 			print_stat(&par[i], i, 0);
 		}
 		if (stat[i].values)
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 03/13] rt-utils: Add JSON common header output helper
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
  2021-02-10 17:51 ` [PATCH rt-tests v5 01/13] cyclictest: Move thread data to struct thread_param Daniel Wagner
  2021-02-10 17:51 ` [PATCH rt-tests v5 02/13] signaltest: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:50   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 04/13] cyclictest: Add JSON output feature Daniel Wagner
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

rt_write_json writes the common system information header of the
rt-test currently executed.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/include/rt-utils.h |  4 ++
 src/lib/rt-utils.c     | 96 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+)

diff --git a/src/include/rt-utils.h b/src/include/rt-utils.h
index 39ddbd9eae29..36af92b170df 100644
--- a/src/include/rt-utils.h
+++ b/src/include/rt-utils.h
@@ -80,4 +80,8 @@ static inline int64_t calctime(struct timespec t)
 	return time;
 }
 
+void rt_write_json(const char *filename, int argc, char *argv[],
+		   void (*cb)(FILE *, void *),
+		   void *data);
+
 #endif	/* __RT_UTILS.H */
diff --git a/src/lib/rt-utils.c b/src/lib/rt-utils.c
index 321a11b1172d..00907c573d6a 100644
--- a/src/lib/rt-utils.c
+++ b/src/lib/rt-utils.c
@@ -20,6 +20,9 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/syscall.h> /* For SYS_gettid definitions */
+#include <sys/utsname.h>
+#include <time.h>
+#include <sys/time.h>
 
 #include "rt-utils.h"
 #include "rt-sched.h"
@@ -482,3 +485,96 @@ void disable_trace_mark(void)
 {
 	close_tracemark_fd();
 }
+
+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");
+
+	memset(cmdline, 0, len);
+	for (i = 0; i < argc;) {
+		cmdline = strcat(cmdline, argv[i]);
+		i++;
+		if (i < argc)
+			cmdline = strcat(cmdline, " ");
+	}
+
+	return cmdline;
+}
+
+void rt_write_json(const char *filename, int argc, char *argv[],
+		  void (*cb)(FILE *, void *),
+		  void *data)
+{
+	unsigned char buf[1];
+	struct utsname uts;
+	struct timeval tv;
+	char tsbuf[64];
+	struct tm *tm;
+	char *cmdline;
+	FILE *f, *s;
+	time_t t;
+	size_t n;
+	int rt = 0;
+
+	if (!filename || !strcmp("-", filename)) {
+		f = stdout;
+	} else {
+		f = fopen(filename, "w");
+		if (!f)
+			err_exit(errno, "Failed to open '%s'\n", filename);
+	}
+
+	cmdline = get_cmdline(argc, argv);
+	if (!cmdline)
+		err_exit(ENOMEM, "get_cmdline()");
+
+
+	gettimeofday(&tv, NULL);
+	t = tv.tv_sec;
+	tm = localtime(&t);
+	/* RFC 2822-compliant date format */
+	strftime(tsbuf, sizeof(tsbuf), "%a, %d %b %Y %T %z", tm);
+
+	s = fopen("/sys/kernel/realtime", "r");
+	if (s) {
+		n = fread(buf, 1, 1, s);
+		if (n == 1 && buf[0] == '1')
+			rt = 1;
+		fclose(s);
+	}
+
+	if (uname(&uts))
+		err_exit(errno, "Could not retrieve system information");
+
+	fprintf(f, "{\n");
+	fprintf(f, "  \"file_version\": 1,\n");
+	fprintf(f, "  \"cmdline:\": \"%s\",\n", cmdline);
+	fprintf(f, "  \"rt_test_version:\": \"%1.2f\",\n", VERSION);
+	fprintf(f, "  \"finished\": \"%s\",\n", tsbuf);
+	fprintf(f, "  \"sysinfo\": {\n");
+	fprintf(f, "    \"sysname\": \"%s\",\n", uts.sysname);
+	fprintf(f, "    \"nodename\": \"%s\",\n", uts.nodename);
+	fprintf(f, "    \"release\": \"%s\",\n", uts.release);
+	fprintf(f, "    \"version\": \"%s\",\n", uts.version);
+	fprintf(f, "    \"machine\": \"%s\",\n", uts.machine);
+	fprintf(f, "    \"realtime\": %d\n", rt);
+	fprintf(f, "  },\n");
+
+	(cb)(f, data);
+
+	fprintf(f, "}\n");
+
+	free(cmdline);
+
+	if (!filename || strcmp("-", filename))
+		fclose(f);
+}
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 04/13] cyclictest: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (2 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 03/13] rt-utils: Add JSON common header output helper Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:50   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 05/13] signaltest: " Daniel Wagner
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/cyclictest/cyclictest.c | 46 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
index 7c45732c1553..3d0cf3f84b69 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;
@@ -838,6 +840,7 @@ static void display_help(int error)
 	       "			   latency is hit. Useful for low bandwidth.\n"
 	       "-N       --nsecs           print results in ns instead of us (default us)\n"
 	       "-o RED   --oscope=RED      oscilloscope mode, reduce verbose output by RED\n"
+	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
 	       "-p PRIO  --priority=PRIO   priority of highest prio thread\n"
 	       "	 --policy=NAME     policy of measurement thread, where NAME may be one\n"
 	       "                           of: other, normal, batch, idle, fifo or rr.\n"
@@ -945,7 +948,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 */
@@ -979,6 +982,7 @@ static void process_options(int argc, char *argv[])
 			{"refresh_on_max",   no_argument,       NULL, OPT_REFRESH },
 			{"nsecs",            no_argument,       NULL, OPT_NSECS },
 			{"oscope",           required_argument, NULL, OPT_OSCOPE },
+			{"output",           required_argument, NULL, OPT_OUTPUT },
 			{"priority",         required_argument, NULL, OPT_PRIORITY },
 			{"quiet",            no_argument,       NULL, OPT_QUIET },
 			{"priospread",       no_argument,       NULL, OPT_PRIOSPREAD },
@@ -1073,6 +1077,9 @@ 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));
+			break;
 		case 'p':
 		case OPT_PRIORITY:
 			priority = atoi(optarg);
@@ -1690,6 +1697,40 @@ static void rstat_setup(void)
 	return;
 }
 
+static void write_stats(FILE *f, void *data)
+{
+	struct thread_param **par = parameters;
+	unsigned int i, j, comma;
+	struct thread_stat *s;
+
+	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
+	fprintf(f, "  \"resolution_in_ns\": %u,\n", use_nsecs);
+	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");
+}
 
 int main(int argc, char **argv)
 {
@@ -2035,6 +2076,9 @@ int main(int argc, char **argv)
 	if (!verbose && !quiet && refresh_on_max)
 		printf("\033[%dB", num_threads + 2);
 
+	if (strlen(outfile) != 0)
+		rt_write_json(outfile, argc, argv, write_stats, NULL);
+
 	if (quiet)
 		quiet = 2;
 	for (i = 0; i < num_threads; i++) {
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 05/13] signaltest: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (3 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 04/13] cyclictest: Add JSON output feature Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:50   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 06/13] cyclicdeadline: " Daniel Wagner
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/signaltest/signaltest.c | 109 +++++++++++++++++++++++++++++-------
 1 file changed, 88 insertions(+), 21 deletions(-)

diff --git a/src/signaltest/signaltest.c b/src/signaltest/signaltest.c
index dd5633d5fc51..09039b299367 100644
--- a/src/signaltest/signaltest.c
+++ b/src/signaltest/signaltest.c
@@ -22,6 +22,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sched.h>
+#include <inttypes.h>
 
 #include <linux/unistd.h>
 
@@ -205,6 +206,14 @@ static int verbose;
 static int quiet;
 static int lockall;
 static struct bitmask *affinity_mask = NULL;
+static char outfile[MAX_PATH];
+
+enum option_values {
+	OPT_AFFINITY=1, OPT_BREAKTRACE,
+	OPT_DURATION, OPT_HELP, OPT_LOOPS,
+	OPT_MLOCKALL, OPT_OUTPUT, OPT_PRIORITY,
+	OPT_QUIET, OPT_SMP, OPT_THREADS, OPT_VERBOSE
+};
 
 /* Process commandline options */
 static void process_options(int argc, char *argv[])
@@ -216,17 +225,18 @@ static void process_options(int argc, char *argv[])
 		int option_index = 0;
 		/** Options for getopt */
 		static struct option long_options[] = {
-			{"affinity",		optional_argument,	NULL, 'a'},
-			{"breaktrace",		required_argument,	NULL, 'b'},
-			{"duration",		required_argument,	NULL, 'D'},
-			{"help",		no_argument,		NULL, 'h'},
-			{"loops",		required_argument,	NULL, 'l'},
-			{"mlockall",		no_argument,		NULL, 'm'},
-			{"priority",		required_argument,	NULL, 'p'},
-			{"quiet",		no_argument,		NULL, 'q'},
-			{"smp",			no_argument,		NULL, 'S'},
-			{"threads",		required_argument,	NULL, 't'},
-			{"verbose",		no_argument,		NULL, 'v'},
+			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
+			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
+			{"duration",	required_argument,	NULL, OPT_DURATION},
+			{"help",	no_argument,		NULL, OPT_HELP},
+			{"loops",	required_argument,	NULL, OPT_LOOPS},
+			{"mlockall",	no_argument,		NULL, OPT_MLOCKALL},
+			{"output",	required_argument,	NULL, OPT_OUTPUT},
+			{"priority",	required_argument,	NULL, OPT_PRIORITY},
+			{"quiet",	no_argument,		NULL, OPT_QUIET},
+			{"smp",		no_argument,		NULL, OPT_SMP},
+			{"threads",	required_argument,	NULL, OPT_THREADS},
+			{"verbose",	no_argument,		NULL, OPT_VERBOSE},
 			{NULL, 0, NULL, 0}
 		};
 		int c = getopt_long(argc, argv, "a::b:D:hl:mp:qSt:v",
@@ -234,6 +244,7 @@ static void process_options(int argc, char *argv[])
 		if (c == -1)
 			break;
 		switch (c) {
+		case OPT_AFFINITY:
 		case 'a':
 			if (optarg) {
 				parse_cpumask(optarg, &affinity_mask);
@@ -248,17 +259,49 @@ static void process_options(int argc, char *argv[])
 				printf("Using %u cpus.\n",
 					numa_bitmask_weight(affinity_mask));
 			break;
-		case 'b': tracelimit = atoi(optarg); break;
-		case 'D': duration = parse_time_string(optarg); break;
+		case OPT_BREAKTRACE:
+		case 'b':
+			tracelimit = atoi(optarg);
+			break;
+		case OPT_DURATION:
+		case 'D':
+			duration = parse_time_string(optarg);
+			break;
+		case OPT_HELP:
 		case '?':
-		case 'h': display_help(0); break;
-		case 'l': max_cycles = atoi(optarg); break;
-		case 'm': lockall = 1; break;
-		case 'p': priority = atoi(optarg); break;
-		case 'q': quiet = 1; break;
-		case 'S': smp = 1; break;
-		case 't': num_threads = atoi(optarg); break;
-		case 'v': verbose = 1; break;
+		case 'h':
+			display_help(0);
+			break;
+		case OPT_LOOPS:
+		case 'l':
+			max_cycles = atoi(optarg);
+			break;
+		case OPT_MLOCKALL:
+		case 'm':
+			lockall = 1;
+			break;
+		case OPT_OUTPUT:
+			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
+			break;
+		case OPT_PRIORITY:
+		case 'p':
+			priority = atoi(optarg);
+			break;
+		case OPT_QUIET:
+		case 'q':
+			quiet = 1;
+			break;
+		case OPT_SMP:
+		case 'S':
+			smp = 1;
+			break;
+		case OPT_THREADS:
+		case 't':
+			num_threads = atoi(optarg);
+			break;
+		case OPT_VERBOSE:
+		case 'v': verbose = 1;
+			break;
 		}
 	}
 
@@ -312,6 +355,27 @@ static void print_stat(struct thread_param *par, int index, int verbose)
 	}
 }
 
+static void write_stats(FILE *f, void *data)
+{
+	struct thread_param *par = data;
+	struct thread_stat *s;
+	unsigned int i;
+
+	fprintf(f, "  \"thread\": {\n");
+	for (i = 0; i < num_threads; i++) {
+		fprintf(f, "    \"%u\": {\n", i);
+		s = &par->stats[i];
+		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->cpu);
+		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
+
+	}
+	fprintf(f, "  }\n");
+}
+
 int main(int argc, char **argv)
 {
 	sigset_t sigset;
@@ -454,6 +518,9 @@ int main(int argc, char **argv)
 		if (stat[i].values)
 			free(stat[i].values);
 	}
+	if (strlen(outfile) != 0)
+		rt_write_json(outfile, argc, argv, write_stats, par);
+
 	free(stat);
  outpar:
 	free(par);
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 06/13] cyclicdeadline: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (4 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 05/13] signaltest: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:51   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 07/13] pmqtest: " Daniel Wagner
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/sched_deadline/cyclicdeadline.c | 72 ++++++++++++++++++++++-------
 1 file changed, 56 insertions(+), 16 deletions(-)

diff --git a/src/sched_deadline/cyclicdeadline.c b/src/sched_deadline/cyclicdeadline.c
index 71cde5781499..ed3c960d9916 100644
--- a/src/sched_deadline/cyclicdeadline.c
+++ b/src/sched_deadline/cyclicdeadline.c
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <getopt.h>
+#include <inttypes.h>
 
 #include <sys/syscall.h>
 #include <sys/types.h>
@@ -85,13 +86,11 @@ static pthread_barrier_t barrier;
 
 static int cpu_count;
 static int all_cpus;
-
 static int nr_threads;
 static int use_nsecs;
-
 static int mark_fd;
-
 static int quiet;
+static char outfile[MAX_PATH];
 
 static int find_mount(const char *mount, char *debugfs)
 {
@@ -603,16 +602,17 @@ static void usage(int error)
 	       "                           tasks on. An empty CPUSET runs on all CPUs a deadline\n"
 	       "                           task.\n"
 	       "                           on CPU 4, and thread #5 on CPU 5.\n"
-	       "-D TIME     --duration     Specify a length for the test run.\n"
+	       "-D TIME  --duration        Specify a length for the test run.\n"
 	       "                           Append 'm', 'h', or 'd' to specify minutes, hours or\n"
 	       "                           days\n"
-	       "-h          --help         Show this help menu.\n"
-	       "-i INTV     --interval     The shortest deadline for the tasks in us\n"
+	       "-h       --help            Show this help menu.\n"
+	       "-i INTV  --interval        The shortest deadline for the tasks in us\n"
 	       "                           (default 1000us).\n"
-	       "-s STEP     --step         The amount to increase the deadline for each task in us\n"
+	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
+	       "-s STEP  --step            The amount to increase the deadline for each task in us\n"
 	       "                           (default 500us).\n"
-	       "-t NUM      --threads      The number of threads to run as deadline (default 1).\n"
-	       "-q          --quiet        print a summary only on exit\n"
+	       "-t NUM   --threads         The number of threads to run as deadline (default 1).\n"
+	       "-q       --quiet           print a summary only on exit\n"
 	       );
 	exit(error);
 }
@@ -966,6 +966,32 @@ static void loop(struct sched_data *sched_data, int nr_threads)
 	}
 }
 
+static void write_stats(FILE *f, void *data)
+{
+	struct sched_data *sd = data;
+	struct thread_stat *s;
+	unsigned int i;
+
+	fprintf(f, "  \"num_threads\": %d,\n", nr_threads);
+	fprintf(f, "  \"resolution_in_ns\": %u,\n", use_nsecs);
+	fprintf(f, "  \"thread\": {\n");
+	for (i = 0; i < nr_threads; i++) {
+		s = &sd[i].stat;
+		fprintf(f, "    \"%u\": {\n", i);
+		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, "    }%s\n", i == nr_threads - 1 ? "" : ",");
+	}
+	fprintf(f, "  }\n");
+}
+
+enum options_valud {
+	OPT_AFFINITY=1, OPT_DURATION, OPT_HELP, OPT_INTERVAL,
+	OPT_OUTPUT, OPT_STEP, OPT_THREADS, OPT_QUIET
+};
+
 int main(int argc, char **argv)
 {
 	struct sched_data *sched_data;
@@ -992,19 +1018,21 @@ int main(int argc, char **argv)
 
 	for (;;) {
 		static struct option options[] = {
-			{ "affinity",	optional_argument,	NULL,	'a' },
-			{ "duration",	required_argument,	NULL,	'D' },
-			{ "help",	no_argument,		NULL,	'h' },
-			{ "interval",	required_argument,	NULL,	'i' },
-			{ "step",	required_argument,	NULL,	's' },
-			{ "threads",	required_argument,	NULL,	't' },
-			{ "quiet",	no_argument,		NULL,	'q' },
+			{ "affinity",	optional_argument,	NULL,	OPT_AFFINITY },
+			{ "duration",	required_argument,	NULL,	OPT_DURATION },
+			{ "help",	no_argument,		NULL,	OPT_HELP },
+			{ "interval",	required_argument,	NULL,	OPT_INTERVAL },
+			{ "output",	required_argument,	NULL,	OPT_OUTPUT },
+			{ "step",	required_argument,	NULL,	OPT_STEP },
+			{ "threads",	required_argument,	NULL,	OPT_THREADS },
+			{ "quiet",	no_argument,		NULL,	OPT_QUIET },
 			{ NULL,		0,			NULL,	0   },
 		};
 		c = getopt_long(argc, argv, "a::c:D:hi:s:t:q", options, NULL);
 		if (c == -1)
 			break;
 		switch (c) {
+		case OPT_AFFINITY:
 		case 'a':
 		case 'c':
 			if (!nr_threads)
@@ -1016,21 +1044,30 @@ int main(int argc, char **argv)
 			else
 				all_cpus = 1;
 			break;
+		case OPT_INTERVAL:
 		case 'i':
 			interval = atoi(optarg);
 			break;
+		case OPT_OUTPUT:
+			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
+			break;
+		case OPT_STEP:
 		case 's':
 			step = atoi(optarg);
 			break;
+		case OPT_THREADS:
 		case 't':
 			nr_threads = atoi(optarg);
 			break;
+		case OPT_DURATION:
 		case 'D':
 			duration = parse_time_string(optarg);
 			break;
+		case OPT_QUIET:
 		case 'q':
 			quiet = 1;
 			break;
+		case OPT_HELP:
 		case 'h':
 			usage(0);
 			break;
@@ -1190,6 +1227,9 @@ int main(int argc, char **argv)
 		}
 	}
 
+	if (strlen(outfile) != 0)
+		rt_write_json(outfile, argc, argv, write_stats, sched_data);
+
 	if (setcpu_buf)
 		free(setcpu_buf);
 	free(thread);
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 07/13] pmqtest: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (5 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 06/13] cyclicdeadline: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:51   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 08/13] ptsematest: " Daniel Wagner
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/pmqtest/pmqtest.c | 137 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 114 insertions(+), 23 deletions(-)

diff --git a/src/pmqtest/pmqtest.c b/src/pmqtest/pmqtest.c
index 349b47741003..e1f59836ea07 100644
--- a/src/pmqtest/pmqtest.c
+++ b/src/pmqtest/pmqtest.c
@@ -22,6 +22,7 @@
 #include <utmpx.h>
 #include <mqueue.h>
 #include <pthread.h>
+#include <inttypes.h>
 
 #include "rt-utils.h"
 #include "rt-get_cpu.h"
@@ -231,6 +232,7 @@ static void display_help(int error)
 	       "-h       --help            print this help message\n"
 	       "-i INTV  --interval=INTV   base interval of thread in us default=1000\n"
 	       "-l LOOPS --loops=LOOPS     number of loops: default=0(endless)\n"
+	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
 	       "-p PRIO  --prio=PRIO       priority\n"
 	       "-q       --quiet           print a summary only on exit\n"
 	       "-S       --smp             SMP testing: options -a -t and same priority\n"
@@ -258,6 +260,14 @@ static int sameprio;
 static int timeout;
 static int forcetimeout;
 static int quiet;
+static char outfile[MAX_PATH];
+
+enum option_value {
+	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_DISTANCE, OPT_DURATION,
+	OPT_FORCETIMEOUT, OPT_HELP, OPT_INTERVAL, OPT_LOOPS,
+	OPT_OUTPUT, OPT_PRIORITY, OPT_QUIET, OPT_SMP, OPT_THREADS,
+	OPT_TIMEOUT
+};
 
 static void process_options(int argc, char *argv[])
 {
@@ -268,19 +278,20 @@ static void process_options(int argc, char *argv[])
 		int option_index = 0;
 		/** Options for getopt */
 		static struct option long_options[] = {
-			{"affinity",		optional_argument,	NULL, 'a'},
-			{"breaktrace",		required_argument,	NULL, 'b'},
-			{"distance",		required_argument,	NULL, 'd'},
-			{"duration",		required_argument,	NULL, 'D'},
-			{"forcetimeout",	required_argument,	NULL, 'f'},
-			{"help",		no_argument,		NULL, 'h'},
-			{"interval",		required_argument,	NULL, 'i'},
-			{"loops",		required_argument,	NULL, 'l'},
-			{"priority",		required_argument,	NULL, 'p'},
-			{"quiet",		no_argument,		NULL, 'q'},
-			{"smp",			no_argument,		NULL, 'S'},
-			{"threads",		optional_argument,	NULL, 't'},
-			{"timeout",		required_argument,	NULL, 'T'},
+			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
+			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
+			{"distance",	required_argument,	NULL, OPT_DISTANCE},
+			{"duration",	required_argument,	NULL, OPT_DURATION},
+			{"forcetimeout",required_argument,	NULL, OPT_FORCETIMEOUT},
+			{"help",	no_argument,		NULL, OPT_HELP},
+			{"interval",	required_argument,	NULL, OPT_INTERVAL},
+			{"loops",	required_argument,	NULL, OPT_LOOPS},
+			{"output",	required_argument,      NULL, OPT_OUTPUT },
+			{"priority",	required_argument,	NULL, OPT_PRIORITY},
+			{"quiet",	no_argument,		NULL, OPT_QUIET},
+			{"smp",		no_argument,		NULL, OPT_SMP},
+			{"threads",	optional_argument,	NULL, OPT_THREADS},
+			{"timeout",	required_argument,	NULL, OPT_TIMEOUT},
 			{NULL, 0, NULL, 0}
 		};
 		int c = getopt_long (argc, argv, "a::b:d:D:f:i:l:p:qSt::T:",
@@ -288,6 +299,7 @@ static void process_options(int argc, char *argv[])
 		if (c == -1)
 			break;
 		switch (c) {
+		case OPT_AFFINITY:
 		case 'a':
 			if (smp) {
 				warn("-a ignored due to --smp\n");
@@ -303,21 +315,53 @@ static void process_options(int argc, char *argv[])
 				setaffinity = AFFINITY_USEALL;
 			}
 			break;
-		case 'b': tracelimit = atoi(optarg); break;
-		case 'd': distance = atoi(optarg); break;
-		case 'D': duration = parse_time_string(optarg); break;
-		case 'f': forcetimeout = atoi(optarg); break;
+		case OPT_BREAKTRACE:
+		case 'b':
+			tracelimit = atoi(optarg);
+			break;
+		case OPT_DISTANCE:
+		case 'd':
+			distance = atoi(optarg);
+			break;
+		case OPT_DURATION:
+		case 'D':
+			duration = parse_time_string(optarg);
+			break;
+		case OPT_FORCETIMEOUT:
+		case 'f':
+			forcetimeout = atoi(optarg);
+			break;
+		case OPT_HELP:
 		case '?':
-		case 'h': display_help(0); break;
-		case 'i': interval = atoi(optarg); break;
-		case 'l': max_cycles = atoi(optarg); break;
-		case 'p': priority = atoi(optarg); break;
-		case 'q': quiet = 1; break;
+		case 'h':
+			display_help(0);
+			break;
+		case OPT_INTERVAL:
+		case 'i':
+			interval = atoi(optarg);
+			break;
+		case OPT_LOOPS:
+		case 'l':
+			max_cycles = atoi(optarg);
+			break;
+		case OPT_OUTPUT:
+			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
+			break;
+		case OPT_PRIORITY:
+		case 'p':
+			priority = atoi(optarg);
+			break;
+		case OPT_QUIET:
+		case 'q':
+			quiet = 1;
+			break;
+		case OPT_SMP:
 		case 'S':
 			smp = 1;
 			num_threads = max_cpus;
 			setaffinity = AFFINITY_USEALL;
 			break;
+		case OPT_THREADS:
 		case 't':
 			if (smp) {
 				warn("-t ignored due to --smp\n");
@@ -330,7 +374,10 @@ static void process_options(int argc, char *argv[])
 			else
 				num_threads = max_cpus;
 			break;
-		case 'T': timeout = atoi(optarg); break;
+		case OPT_TIMEOUT:
+		case 'T':
+			timeout = atoi(optarg);
+			break;
 		default:
 			display_help(1);
 			break;
@@ -401,6 +448,42 @@ static void print_stat(FILE *fp, struct params *receiver, struct params *sender,
 	}
 }
 
+struct params_stats {
+	struct params *receiver;
+	struct params *sender;
+};
+
+static void write_stats(FILE *f, void *data)
+{
+	struct params_stats *ps = data;
+	struct params *s, *r;
+	unsigned int i;
+
+	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
+	fprintf(f, "  \"thread\": {\n");
+	for (i = 0; i < num_threads; i++) {
+		s = &ps->sender[i];
+		r = &ps->receiver[i];
+		fprintf(f, "    \"%u\": {\n", i);
+		fprintf(f, "      \"sender\": {\n");
+		fprintf(f, "        \"cpu\": %d,\n", s->cpu);
+		fprintf(f, "        \"priority\": %d,\n", s->priority);
+		fprintf(f, "        \"samples\": %d,\n", s->samples);
+		fprintf(f, "        \"interval\": %ld\n", r->delay.tv_nsec/1000);
+		fprintf(f, "      },\n");
+		fprintf(f, "      \"receiver\": {\n");
+		fprintf(f, "        \"cpu\": %d,\n", r->cpu);
+		fprintf(f, "        \"priority\": %d,\n", r->priority);
+		fprintf(f, "        \"timeoutcount\": %d,\n", r->timeoutcount);
+		fprintf(f, "        \"min\": %d,\n", r->mindiff);
+		fprintf(f, "        \"avg\": %.2f,\n", r->sumdiff/r->samples);
+		fprintf(f, "        \"max\": %d\n", r->maxdiff);
+		fprintf(f, "      }\n");
+		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
+	}
+	fprintf(f, "  }\n");
+}
+
 int main(int argc, char *argv[])
 {
 	int i;
@@ -562,6 +645,14 @@ int main(int argc, char *argv[])
 		mq_unlink(mqname);
 	}
 
+	if (strlen(outfile) != 0) {
+		struct params_stats ps = {
+			.receiver = receiver,
+			.sender = sender,
+		};
+		rt_write_json(outfile, argc, argv, write_stats, &ps);
+	}
+
 nomem:
 
 	return 0;
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 08/13] ptsematest: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (6 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 07/13] pmqtest: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:51   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 09/13] sigwaittest: " Daniel Wagner
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/ptsematest/ptsematest.c | 120 ++++++++++++++++++++++++++++++------
 1 file changed, 101 insertions(+), 19 deletions(-)

diff --git a/src/ptsematest/ptsematest.c b/src/ptsematest/ptsematest.c
index 7d4ca97773d6..2755bfde5210 100644
--- a/src/ptsematest/ptsematest.c
+++ b/src/ptsematest/ptsematest.c
@@ -20,6 +20,7 @@
 #include <linux/unistd.h>
 #include <utmpx.h>
 #include <pthread.h>
+#include <inttypes.h>
 
 #include "rt-utils.h"
 #include "rt-get_cpu.h"
@@ -155,6 +156,7 @@ static void display_help(int error)
 	       "                           days.\n"
 	       "-i INTV  --interval=INTV   base interval of thread in us default=1000\n"
 	       "-l LOOPS --loops=LOOPS     number of loops: default=0(endless)\n"
+	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
 	       "-p PRIO  --prio=PRIO       priority\n"
 	       "-q       --quiet           print a summary only on exit\n"
 	       "-S       --smp             SMP testing: options -a -t and same priority\n"
@@ -180,6 +182,13 @@ static int distance = 500;
 static int smp;
 static int sameprio;
 static int quiet;
+static char outfile[MAX_PATH];
+
+enum option_value {
+	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_DISTANCE, OPT_DURATION,
+	OPT_HELP, OPT_INTERVAL, OPT_LOOPS, OPT_OUTPUT, OPT_PRIORITY,
+	OPT_QUIET, OPT_SMP, OPT_THREADS
+};
 
 static void process_options(int argc, char *argv[])
 {
@@ -190,17 +199,18 @@ static void process_options(int argc, char *argv[])
 		int option_index = 0;
 		/** Options for getopt */
 		static struct option long_options[] = {
-			{"affinity",	optional_argument,	NULL, 'a'},
-			{"breaktrace",	required_argument,	NULL, 'b'},
-			{"distance",	required_argument,	NULL, 'd'},
-			{"duration",	required_argument,	NULL, 'D'},
-			{"help",	no_argument,		NULL, 'h'},
-			{"interval",	required_argument,	NULL, 'i'},
-			{"loops",	required_argument,	NULL, 'l'},
-			{"priority",	required_argument,	NULL, 'p'},
-			{"quiet",	no_argument	,	NULL, 'q'},
-			{"smp",		no_argument,		NULL, 'S'},
-			{"threads",	optional_argument,	NULL, 't'},
+			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
+			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
+			{"distance",	required_argument,	NULL, OPT_DISTANCE},
+			{"duration",	required_argument,	NULL, OPT_DURATION},
+			{"help",	no_argument,		NULL, OPT_HELP},
+			{"interval",	required_argument,	NULL, OPT_INTERVAL},
+			{"loops",	required_argument,	NULL, OPT_LOOPS},
+			{"output",	required_argument,      NULL, OPT_OUTPUT },
+			{"priority",	required_argument,	NULL, OPT_PRIORITY},
+			{"quiet",	no_argument	,	NULL, OPT_QUIET},
+			{"smp",		no_argument,		NULL, OPT_SMP},
+			{"threads",	optional_argument,	NULL, OPT_THREADS},
 			{NULL, 0, NULL, 0}
 		};
 		int c = getopt_long (argc, argv, "a::b:d:i:l:D:p:qSt::h",
@@ -208,6 +218,7 @@ static void process_options(int argc, char *argv[])
 		if (c == -1)
 			break;
 		switch (c) {
+		case OPT_AFFINITY:
 		case 'a':
 			if (smp) {
 				warn("-a ignored due to --smp\n");
@@ -223,20 +234,49 @@ static void process_options(int argc, char *argv[])
 				setaffinity = AFFINITY_USEALL;
 			}
 			break;
-		case 'b': tracelimit = atoi(optarg); break;
-		case 'd': distance = atoi(optarg); break;
-		case 'D': duration = parse_time_string(optarg); break;
-		case 'i': interval = atoi(optarg); break;
+		case OPT_BREAKTRACE:
+		case 'b':
+			tracelimit = atoi(optarg);
+			break;
+		case OPT_DISTANCE:
+		case 'd':
+			distance = atoi(optarg);
+			break;
+		case OPT_DURATION:
+		case 'D':
+			duration = parse_time_string(optarg);
+			break;
+		case OPT_INTERVAL:
+		case 'i':
+			interval = atoi(optarg);
+			break;
+		case OPT_HELP:
 		case '?':
-		case 'h': display_help(0); break;
-		case 'l': max_cycles = atoi(optarg); break;
-		case 'p': priority = atoi(optarg); break;
-		case 'q': quiet = 1; break;
+		case 'h':
+			display_help(0);
+			break;
+		case OPT_LOOPS:
+		case 'l':
+			max_cycles = atoi(optarg);
+			break;
+		case OPT_OUTPUT:
+			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
+			break;
+		case OPT_PRIORITY:
+		case 'p':
+			priority = atoi(optarg);
+			break;
+		case OPT_QUIET:
+		case 'q':
+			quiet = 1;
+			break;
+		case OPT_SMP:
 		case 'S':
 			smp = 1;
 			num_threads = max_cpus;
 			setaffinity = AFFINITY_USEALL;
 			break;
+		case OPT_THREADS:
 		case 't':
 			if (smp) {
 				warn("-t ignored due to --smp\n");
@@ -316,6 +356,40 @@ static void print_stat(FILE *fp, struct params *receiver, struct params *sender,
 	}
 }
 
+struct params_stats {
+	struct params *receiver;
+	struct params *sender;
+};
+
+static void write_stats(FILE *f, void *data)
+{
+	struct params_stats *ps = data;
+	struct params *s, *r;
+	unsigned int i;
+
+	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
+	fprintf(f, "  \"thread\": {\n");
+	for (i = 0; i < num_threads; i++) {
+		s = &ps->sender[i];
+		r = &ps->receiver[i];
+		fprintf(f, "    \"%u\": {\n", i);
+		fprintf(f, "      \"sender\": {\n");
+		fprintf(f, "        \"cpu\": %d,\n", s->cpu);
+		fprintf(f, "        \"priority\": %d,\n", s->priority);
+		fprintf(f, "        \"samples\": %d,\n", s->samples);
+		fprintf(f, "        \"interval\": %ld\n", r->delay.tv_nsec/1000);
+		fprintf(f, "      },\n");
+		fprintf(f, "      \"receiver\": {\n");
+		fprintf(f, "        \"cpu\": %d,\n", r->cpu);
+		fprintf(f, "        \"priority\": %d,\n", r->priority);
+		fprintf(f, "        \"min\": %d,\n", r->mindiff);
+		fprintf(f, "        \"avg\": %.2f,\n", r->sumdiff/r->samples);
+		fprintf(f, "        \"max\": %d\n", r->maxdiff);
+		fprintf(f, "      }\n");
+		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
+	}
+	fprintf(f, "  }\n");
+}
 
 int main(int argc, char *argv[])
 {
@@ -439,6 +513,14 @@ int main(int argc, char *argv[])
 		pthread_mutex_destroy(&syncmutex[i]);
 	}
 
+	if (strlen(outfile) != 0) {
+		struct params_stats ps = {
+			.receiver = receiver,
+			.sender = sender,
+		};
+		rt_write_json(outfile, argc, argv, write_stats, &ps);
+	}
+
 nomem:
 
 	return 0;
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 09/13] sigwaittest: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (7 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 08/13] ptsematest: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:51   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 10/13] svsematest: " Daniel Wagner
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/signaltest/signaltest.c   |   1 +
 src/sigwaittest/sigwaittest.c | 117 ++++++++++++++++++++++++++++------
 2 files changed, 100 insertions(+), 18 deletions(-)

diff --git a/src/signaltest/signaltest.c b/src/signaltest/signaltest.c
index 09039b299367..b1a71efdf42f 100644
--- a/src/signaltest/signaltest.c
+++ b/src/signaltest/signaltest.c
@@ -361,6 +361,7 @@ static void write_stats(FILE *f, void *data)
 	struct thread_stat *s;
 	unsigned int i;
 
+	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
 	fprintf(f, "  \"thread\": {\n");
 	for (i = 0; i < num_threads; i++) {
 		fprintf(f, "    \"%u\": {\n", i);
diff --git a/src/sigwaittest/sigwaittest.c b/src/sigwaittest/sigwaittest.c
index f10c24914d4a..0cdf30a6a769 100644
--- a/src/sigwaittest/sigwaittest.c
+++ b/src/sigwaittest/sigwaittest.c
@@ -39,6 +39,7 @@
 #include <linux/unistd.h>
 #include <utmpx.h>
 #include <pthread.h>
+#include <inttypes.h>
 
 #include "rt-utils.h"
 #include "rt-get_cpu.h"
@@ -220,6 +221,7 @@ static void display_help(int error)
 	       "-f [OPT] --fork[=OPT]      fork new processes instead of creating threads\n"
 	       "-i INTV  --interval=INTV   base interval of thread in us default=1000\n"
 	       "-l LOOPS --loops=LOOPS     number of loops: default=0(endless)\n"
+	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
 	       "-p PRIO  --prio=PRIO       priority\n"
 	       "-q       --quiet           print a summary only on exit\n"
 	       "-t       --threads         one thread per available processor\n"
@@ -240,6 +242,13 @@ static int duration;
 static int interval = 1000;
 static int distance = 500;
 static int quiet;
+static char outfile[MAX_PATH];
+
+enum option_value {
+	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_DISTANCE, OPT_DURATION,
+	OPT_FORK, OPT_HELP, OPT_INTERVAL, OPT_LOOPS, OPT_OUTPUT,
+	OPT_PRIORITY, OPT_QUIET, OPT_THREADS
+};
 
 static void process_options(int argc, char *argv[])
 {
@@ -251,17 +260,18 @@ static void process_options(int argc, char *argv[])
 		int option_index = 0;
 		/** Options for getopt */
 		static struct option long_options[] = {
-			{"affinity",		optional_argument,	NULL, 'a'},
-			{"breaktrace",		required_argument,	NULL, 'b'},
-			{"distance",		required_argument,	NULL, 'd'},
-			{"duration",		required_argument,	NULL, 'D'},
-			{"fork",		optional_argument,	NULL, 'f'},
-			{"help",		no_argument,		NULL, 'h'},
-			{"interval",		required_argument,	NULL, 'i'},
-			{"loops",		required_argument,	NULL, 'l'},
-			{"priority",		required_argument,	NULL, 'p'},
-			{"quiet",		no_argument,		NULL, 'q'},
-			{"threads",		optional_argument,	NULL, 't'},
+			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
+			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
+			{"distance",	required_argument,	NULL, OPT_DISTANCE},
+			{"duration",	required_argument,	NULL, OPT_DURATION},
+			{"fork",	optional_argument,	NULL, OPT_FORK},
+			{"help",	no_argument,		NULL, OPT_HELP},
+			{"interval",	required_argument,	NULL, OPT_INTERVAL},
+			{"loops",	required_argument,	NULL, OPT_LOOPS},
+			{"output",	required_argument,      NULL, OPT_OUTPUT },
+			{"priority",	required_argument,	NULL, OPT_PRIORITY},
+			{"quiet",	no_argument,		NULL, OPT_QUIET},
+			{"threads",	optional_argument,	NULL, OPT_THREADS},
 			{NULL, 0, NULL, 0}
 		};
 		int c = getopt_long (argc, argv, "a::b:d:D:f::hi:l:p:qt::",
@@ -269,6 +279,7 @@ static void process_options(int argc, char *argv[])
 		if (c == -1)
 			break;
 		switch (c) {
+		case OPT_AFFINITY:
 		case 'a':
 			if (optarg != NULL) {
 				affinity = atoi(optarg);
@@ -280,9 +291,19 @@ static void process_options(int argc, char *argv[])
 				setaffinity = AFFINITY_USEALL;
 			}
 			break;
-		case 'b': thistracelimit = atoi(optarg); break;
-		case 'd': distance = atoi(optarg); break;
-		case 'D': duration = parse_time_string(optarg); break;
+		case OPT_BREAKTRACE:
+		case 'b':
+			thistracelimit = atoi(optarg);
+			break;
+		case OPT_DISTANCE:
+		case 'd':
+			distance = atoi(optarg);
+			break;
+		case OPT_DURATION:
+		case 'D':
+			duration = parse_time_string(optarg);
+			break;
+		case OPT_FORK:
 		case 'f':
 			if (optarg != NULL) {
 				wasforked = 1;
@@ -294,14 +315,31 @@ static void process_options(int argc, char *argv[])
 			} else
 				mustfork = 1;
 			break;
+		case OPT_HELP:
 		case '?':
 		case 'h':
 			display_help(0);
 			break;
-		case 'i': interval = atoi(optarg); break;
-		case 'l': max_cycles = atoi(optarg); break;
-		case 'p': priority = atoi(optarg); break;
-		case 'q': quiet = 1; break;
+		case OPT_INTERVAL:
+		case 'i':
+			interval = atoi(optarg);
+			break;
+		case OPT_LOOPS:
+		case 'l':
+			max_cycles = atoi(optarg);
+			break;
+		case OPT_OUTPUT:
+			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
+			break;
+		case OPT_PRIORITY:
+		case 'p':
+			priority = atoi(optarg);
+			break;
+		case OPT_QUIET:
+		case 'q':
+			quiet = 1;
+			break;
+		case OPT_THREADS:
 		case 't':
 			if (optarg != NULL)
 				num_threads = atoi(optarg);
@@ -388,6 +426,41 @@ static void print_stat(FILE *fp, struct params *receiver, struct params *sender,
 	}
 }
 
+struct params_stats {
+	struct params *receiver;
+	struct params *sender;
+};
+
+static void write_stats(FILE *f, void *data)
+{
+	struct params_stats *ps = data;
+	struct params *s, *r;
+	unsigned int i;
+
+	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
+	fprintf(f, "  \"thread\": {\n");
+	for (i = 0; i < num_threads; i++) {
+		s = &ps->sender[i];
+		r = &ps->receiver[i];
+		fprintf(f, "    \"%u\": {\n", i);
+		fprintf(f, "      \"sender\": {\n");
+		fprintf(f, "        \"cpu\": %d,\n", s->cpu);
+		fprintf(f, "        \"priority\": %d,\n", s->priority);
+		fprintf(f, "        \"samples\": %d,\n", s->samples);
+		fprintf(f, "        \"interval\": %ld\n", r->delay.tv_nsec/1000);
+		fprintf(f, "      },\n");
+		fprintf(f, "      \"receiver\": {\n");
+		fprintf(f, "        \"cpu\": %d,\n", r->cpu);
+		fprintf(f, "        \"priority\": %d,\n", r->priority);
+		fprintf(f, "        \"min\": %d,\n", r->mindiff);
+		fprintf(f, "        \"avg\": %.2f,\n", r->sumdiff/r->samples);
+		fprintf(f, "        \"max\": %d\n", r->maxdiff);
+		fprintf(f, "      }\n");
+		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
+	}
+	fprintf(f, "  }\n");
+}
+
 int main(int argc, char *argv[])
 {
 	int i, totalsize = 0;
@@ -627,6 +700,14 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	if (strlen(outfile) != 0) {
+		struct params_stats ps = {
+			.receiver = receiver,
+			.sender = sender,
+		};
+		rt_write_json(outfile, argc, argv, write_stats, &ps);
+	}
+
 nomem:
 	if (mustfork) {
 		munmap(param, totalsize);
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 10/13] svsematest: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (8 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 09/13] sigwaittest: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:51   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 11/13] oslat: " Daniel Wagner
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/svsematest/svsematest.c | 124 ++++++++++++++++++++++++++++++------
 1 file changed, 104 insertions(+), 20 deletions(-)

diff --git a/src/svsematest/svsematest.c b/src/svsematest/svsematest.c
index 7a298e0dea8c..23f84bcbd3dc 100644
--- a/src/svsematest/svsematest.c
+++ b/src/svsematest/svsematest.c
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <time.h>
 #include <utmpx.h>
+#include <inttypes.h>
 
 #include <linux/unistd.h>
 
@@ -233,6 +234,7 @@ static void display_help(int error)
 	       "-f [OPT] --fork[=OPT]      fork new processes instead of creating threads\n"
 	       "-i INTV  --interval=INTV   base interval of thread in us default=1000\n"
 	       "-l LOOPS --loops=LOOPS     number of loops: default=0(endless)\n"
+	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
 	       "-p PRIO  --prio=PRIO       priority\n"
 	       "-S       --smp             SMP testing: options -a -t and same priority\n"
 	       "                           of all threads\n"
@@ -255,6 +257,13 @@ static int distance = 500;
 static int smp;
 static int sameprio;
 static int quiet;
+static char outfile[MAX_PATH];
+
+enum option_value {
+	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_DISTANCE, OPT_DURATION,
+	OPT_FORK, OPT_HELP, OPT_INTERVAL, OPT_LOOPS, OPT_OUTPUT,
+	OPT_PRIORITY, OPT_QUIET, OPT_SMP, OPT_THREADS
+};
 
 static void process_options(int argc, char *argv[])
 {
@@ -266,18 +275,19 @@ static void process_options(int argc, char *argv[])
 		int option_index = 0;
 		/** Options for getopt */
 		static struct option long_options[] = {
-			{"affinity",		optional_argument,	NULL, 'a'},
-			{"breaktrace",		required_argument,	NULL, 'b'},
-			{"distance",		required_argument,	NULL, 'd'},
-			{"duration",		required_argument,	NULL, 'D'},
-			{"fork",		optional_argument,	NULL, 'f'},
-			{"help",		no_argument,		NULL, 'h'},
-			{"interval",		required_argument,	NULL, 'i'},
-			{"loops",		required_argument,	NULL, 'l'},
-			{"priority",		required_argument,	NULL, 'p'},
-			{"quiet",		no_argument,		NULL, 'q'},
-			{"smp",			no_argument,		NULL, 'S'},
-			{"threads",		optional_argument,	NULL, 't'},
+			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
+			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
+			{"distance",	required_argument,	NULL, OPT_DISTANCE},
+			{"duration",	required_argument,	NULL, OPT_DURATION},
+			{"fork",	optional_argument,	NULL, OPT_FORK},
+			{"help",	no_argument,		NULL, OPT_HELP},
+			{"interval",	required_argument,	NULL, OPT_INTERVAL},
+			{"loops",	required_argument,	NULL, OPT_LOOPS},
+			{"output",	required_argument,      NULL, OPT_OUTPUT},
+			{"priority",	required_argument,	NULL, OPT_PRIORITY},
+			{"quiet",	no_argument,		NULL, OPT_QUIET},
+			{"smp",		no_argument,		NULL, OPT_SMP},
+			{"threads",	optional_argument,	NULL, OPT_THREADS},
 			{NULL, 0, NULL, 0}
 		};
 		int c = getopt_long (argc, argv, "a::b:d:D:f::hi:l:p:qSt::",
@@ -285,6 +295,7 @@ static void process_options(int argc, char *argv[])
 		if (c == -1)
 			break;
 		switch (c) {
+		case OPT_AFFINITY:
 		case 'a':
 			if (smp) {
 				warn("-a ignored due to --smp\n");
@@ -300,9 +311,19 @@ static void process_options(int argc, char *argv[])
 				setaffinity = AFFINITY_USEALL;
 			}
 			break;
-		case 'b': thistracelimit = atoi(optarg); break;
-		case 'd': distance = atoi(optarg); break;
-		case 'D': duration = parse_time_string(optarg); break;
+		case OPT_BREAKTRACE:
+		case 'b':
+			thistracelimit = atoi(optarg);
+			break;
+		case OPT_DISTANCE:
+		case 'd':
+			distance = atoi(optarg);
+			break;
+		case OPT_DURATION:
+		case 'D':
+			duration = parse_time_string(optarg);
+			break;
+		case OPT_FORK:
 		case 'f':
 			if (optarg != NULL) {
 				wasforked = 1;
@@ -314,16 +335,36 @@ static void process_options(int argc, char *argv[])
 			} else
 				mustfork = 1;
 			break;
-		case 'h': display_help(0); break;
-		case 'i': interval = atoi(optarg); break;
-		case 'l': max_cycles = atoi(optarg); break;
-		case 'p': priority = atoi(optarg); break;
-		case 'q': quiet = 1; break;
+		case OPT_HELP:
+		case 'h':
+			display_help(0);
+			break;
+		case OPT_INTERVAL:
+		case 'i':
+			interval = atoi(optarg);
+			break;
+		case OPT_LOOPS:
+		case 'l':
+			max_cycles = atoi(optarg);
+			break;
+		case OPT_OUTPUT:
+			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
+			break;
+		case OPT_PRIORITY:
+		case 'p':
+			priority = atoi(optarg);
+			break;
+		case OPT_QUIET:
+		case 'q':
+			quiet = 1;
+			break;
+		case OPT_SMP:
 		case 'S':
 			smp = 1;
 			num_threads = max_cpus;
 			setaffinity = AFFINITY_USEALL;
 			break;
+		case OPT_THREADS:
 		case 't':
 			if (smp) {
 				warn("-t ignored due to --smp\n");
@@ -380,6 +421,41 @@ static void sighand(int sig)
 	mustshutdown = 1;
 }
 
+struct params_stats {
+	struct params *receiver;
+	struct params *sender;
+};
+
+static void write_stats(FILE *f, void *data)
+{
+	struct params_stats *ps = data;
+	struct params *s, *r;
+	unsigned int i;
+
+	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
+	fprintf(f, "  \"thread\": {\n");
+	for (i = 0; i < num_threads; i++) {
+		s = &ps->sender[i];
+		r = &ps->receiver[i];
+		fprintf(f, "    \"%u\": {\n", i);
+		fprintf(f, "      \"sender\": {\n");
+		fprintf(f, "        \"cpu\": %d,\n", s->cpu);
+		fprintf(f, "        \"priority\": %d,\n", s->priority);
+		fprintf(f, "        \"samples\": %d,\n", s->samples);
+		fprintf(f, "        \"interval\": %ld\n", r->delay.tv_nsec/1000);
+		fprintf(f, "      },\n");
+		fprintf(f, "      \"receiver\": {\n");
+		fprintf(f, "        \"cpu\": %d,\n", r->cpu);
+		fprintf(f, "        \"priority\": %d,\n", r->priority);
+		fprintf(f, "        \"min\": %d,\n", r->mindiff);
+		fprintf(f, "        \"avg\": %.2f,\n", r->sumdiff/r->samples);
+		fprintf(f, "        \"max\": %d\n", r->maxdiff);
+		fprintf(f, "      }\n");
+		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
+	}
+	fprintf(f, "  }\n");
+}
+
 static void print_stat(FILE *fp, struct params *receiver, struct params *sender,
 		       int verbose, int quiet)
 {
@@ -696,6 +772,14 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	if (strlen(outfile) != 0) {
+		struct params_stats ps = {
+			.receiver = receiver,
+			.sender = sender,
+		};
+		rt_write_json(outfile, argc, argv, write_stats, &ps);
+	}
+
 nosem:
 	for (i = 0; i < num_threads; i++)
 		semctl(receiver[i].semid, -1, IPC_RMID);
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 11/13] oslat: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (9 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 10/13] svsematest: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:51   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 12/13] rt-migrate-test: " Daniel Wagner
  2021-02-10 17:51 ` [PATCH rt-tests v5 13/13] oslat: Add quiet command line option Daniel Wagner
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/oslat/oslat.c | 97 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 82 insertions(+), 15 deletions(-)

diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c
index 9e6f70600830..987f2002985d 100644
--- a/src/oslat/oslat.c
+++ b/src/oslat/oslat.c
@@ -29,7 +29,7 @@
 #include <numa.h>
 #include <math.h>
 #include <limits.h>
-#include <linux/unistd.h>
+#include <inttypes.h>
 
 #include <sys/prctl.h>
 #include <sys/stat.h>
@@ -41,6 +41,8 @@
 #include <sys/mman.h>
 #include <sys/syscall.h>
 
+#include <linux/unistd.h>
+
 #include "rt-utils.h"
 #include "rt-numa.h"
 #include "rt-error.h"
@@ -171,6 +173,7 @@ struct global {
 	uint64_t              bias;
 	int                   single_preheat_thread;
 	int                   output_omit_zero_buckets;
+	char                  outfile[MAX_PATH];
 
 	/* Mutable state. */
 	volatile enum command cmd;
@@ -479,6 +482,39 @@ static void write_summary(struct thread *t)
 	printf("\n");
 }
 
+static void write_summary_json(FILE *f, void *data)
+{
+	struct thread *t = data;
+	int i, j, comma;
+
+	fprintf(f, "  \"num_threads\": %d,\n", g.n_threads);
+	fprintf(f, "  \"thread\": {\n");
+	for (i = 0; i < g.n_threads; ++i) {
+		fprintf(f, "    \"%u\": {\n", i);
+		fprintf(f, "      \"cpu\": %d,\n", t[i].core_i);
+		fprintf(f, "      \"freq\": %d,\n", t[i].cpu_mhz);
+		fprintf(f, "      \"min\": %" PRIu64 ",\n", t[i].minlat);
+		fprintf(f, "      \"avg\": %3lf,\n", t[i].average);
+		fprintf(f, "      \"max\": %" PRIu64 ",\n", t[i].maxlat);
+		fprintf(f, "      \"duration\": %.3f,\n",
+			cycles_to_sec(&(t[i]), t[i].runtime));
+		fprintf(f, "      \"histogram\": {");
+		for (j = 0, comma = 0; j < g.bucket_size; j++) {
+			if (t[i].buckets[j] == 0)
+				continue;
+			fprintf(f, "%s", comma ? ",\n" : "\n");
+			fprintf(f, "        \"%" PRIu64 "\": %" PRIu64,
+				g.bias+j+1, t[i].buckets[j]);
+			comma = 1;
+		}
+		if (comma)
+			fprintf(f, "\n");
+		fprintf(f, "      }\n");
+		fprintf(f, "    }%s\n", i == g.n_threads - 1 ? "" : ",");
+	}
+	fprintf(f, "  }\n");
+}
+
 static void run_expt(struct thread *threads, int runtime_secs)
 {
 	int i;
@@ -533,6 +569,7 @@ static void usage(int error)
 	       "                       NOTE: please make sure the CPU frequency on all testing cores\n"
 	       "                       are locked before using this parmater.  If you don't know how\n"
 	       "                       to lock the freq then please don't use this parameter.\n"
+	       "    --output=FILENAME  write final results into FILENAME, JSON formatted\n"
 	       "-T, --trace-threshold  Stop the test when threshold triggered (in us),\n"
 	       "                       print a marker in ftrace and stop ftrace too.\n"
 	       "-v, --version          Display the version of the software.\n"
@@ -557,34 +594,45 @@ static int workload_select(char *name)
 	return -1;
 }
 
+enum option_value {
+	OPT_BUCKETSIZE=1, OPT_CPU_LIST, OPT_CPU_MAIN_THREAD,
+	OPT_DURATION, OPT_RT_PRIO, OPT_HELP, OPT_TRACE_TH,
+	OPT_WORKLOAD, OPT_WORKLOAD_MEM, OPT_BIAS, OPT_OUTPUT,
+	OPT_SINGLE_PREHEAT, OPT_ZERO_OMIT, OPT_VERSION
+
+};
+
 /* Process commandline options */
 static void parse_options(int argc, char *argv[])
 {
 	while (1) {
+		int option_index = 0;
 		static struct option options[] = {
-			{ "bucket-size", required_argument, NULL, 'b' },
-			{ "cpu-list", required_argument, NULL, 'c' },
-			{ "cpu-main-thread", required_argument, NULL, 'C'},
-			{ "duration", required_argument, NULL, 'D' },
-			{ "rtprio", required_argument, NULL, 'f' },
-			{ "help", no_argument, NULL, 'h' },
-			{ "trace-threshold", required_argument, NULL, 'T' },
-			{ "workload", required_argument, NULL, 'w'},
-			{ "workload-mem", required_argument, NULL, 'm'},
-			{ "bias", no_argument, NULL, 'B'},
-			{ "single-preheat", no_argument, NULL, 's'},
-			{ "zero-omit", no_argument, NULL, 'u'},
-			{ "version", no_argument, NULL, 'v'},
+			{ "bucket-size",required_argument,	NULL, OPT_BUCKETSIZE },
+			{ "cpu-list",	required_argument,	NULL, OPT_CPU_LIST },
+			{ "cpu-main-thread", required_argument, NULL, OPT_CPU_MAIN_THREAD},
+			{ "duration",	required_argument,	NULL, OPT_DURATION },
+			{ "rtprio",	required_argument,	NULL, OPT_RT_PRIO },
+			{ "help",	no_argument,		NULL, OPT_HELP },
+			{ "trace-threshold", required_argument,	NULL, OPT_TRACE_TH },
+			{ "workload",	required_argument,	NULL, OPT_WORKLOAD },
+			{ "workload-mem", required_argument,	NULL, OPT_WORKLOAD_MEM },
+			{ "bias",	no_argument,		NULL, OPT_BIAS },
+			{ "single-preheat", no_argument,	NULL, OPT_SINGLE_PREHEAT },
+			{ "output",	required_argument,      NULL, OPT_OUTPUT },
+			{ "zero-omit",	no_argument,		NULL, OPT_ZERO_OMIT },
+			{ "version",	no_argument,		NULL, OPT_VERSION },
 			{ NULL, 0, NULL, 0 },
 		};
 		int i, c = getopt_long(argc, argv, "b:Bc:C:D:f:hm:sw:T:vz",
-				       options, NULL);
+				       options, &option_index);
 		long ncores;
 
 		if (c == -1)
 			break;
 
 		switch (c) {
+		case OPT_BUCKETSIZE:
 		case 'b':
 			g.bucket_size = strtol(optarg, NULL, 10);
 			if (g.bucket_size > 1024 || g.bucket_size <= 4) {
@@ -593,12 +641,15 @@ static void parse_options(int argc, char *argv[])
 				exit(1);
 			}
 			break;
+		case OPT_BIAS:
 		case 'B':
 			g.enable_bias = 1;
 			break;
+		case OPT_CPU_LIST:
 		case 'c':
 			g.cpu_list = strdup(optarg);
 			break;
+		case OPT_CPU_MAIN_THREAD:
 		case 'C':
 			ncores = sysconf(_SC_NPROCESSORS_CONF);
 			g.cpu_main_thread = strtol(optarg, NULL, 10);
@@ -608,6 +659,7 @@ static void parse_options(int argc, char *argv[])
 				exit(1);
 			}
 			break;
+		case OPT_DURATION:
 		case 'D':
 			g.runtime = parse_time_string(optarg);
 			if (!g.runtime) {
@@ -615,6 +667,7 @@ static void parse_options(int argc, char *argv[])
 				exit(1);
 			}
 			break;
+		case OPT_RT_PRIO:
 		case 'f':
 			g.rtprio = strtol(optarg, NULL, 10);
 			if (g.rtprio < 1 || g.rtprio > 99) {
@@ -622,6 +675,10 @@ static void parse_options(int argc, char *argv[])
 				exit(1);
 			}
 			break;
+		case OPT_OUTPUT:
+			strncpy(g.outfile, optarg, strnlen(optarg, MAX_PATH-1));
+			break;
+		case OPT_TRACE_TH:
 		case 'T':
 			g.trace_threshold = strtol(optarg, NULL, 10);
 			if (g.trace_threshold <= 0) {
@@ -630,6 +687,7 @@ static void parse_options(int argc, char *argv[])
 			}
 			enable_trace_mark();
 			break;
+		case OPT_WORKLOAD:
 		case 'w':
 			if (workload_select(optarg)) {
 				printf("Unknown workload '%s'.  Please choose from: ", optarg);
@@ -642,12 +700,14 @@ static void parse_options(int argc, char *argv[])
 				exit(1);
 			}
 			break;
+		case OPT_WORKLOAD_MEM:
 		case 'm':
 			if (parse_mem_string(optarg, &g.workload_mem_size)) {
 				printf("Unknown workload memory size '%s'.\n\n", optarg);
 				exit(1);
 			}
 			break;
+		case OPT_SINGLE_PREHEAT:
 		case 's':
 			/*
 			 * Only use one core for pre-heat.  Then if --bias is used, the
@@ -655,6 +715,7 @@ static void parse_options(int argc, char *argv[])
 			 */
 			g.single_preheat_thread = true;
 			break;
+		case OPT_VERSION:
 		case 'v':
 			/*
 			 * Because we always dump the version even before parsing options,
@@ -662,9 +723,11 @@ static void parse_options(int argc, char *argv[])
 			 */
 			exit(0);
 			break;
+		case OPT_ZERO_OMIT:
 		case 'z':
 			g.output_omit_zero_buckets = 1;
 			break;
+		case OPT_HELP:
 		case 'h':
 			usage(0);
 			break;
@@ -781,6 +844,10 @@ int main(int argc, char *argv[])
 
 	write_summary(threads);
 
+	if (strlen(g.outfile) != 0)
+		rt_write_json(g.outfile, argc, argv,
+			write_summary_json, threads);
+
 	if (g.cpu_list) {
 		free(g.cpu_list);
 		g.cpu_list = NULL;
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 12/13] rt-migrate-test: Add JSON output feature
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (10 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 11/13] oslat: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:52   ` John Kacur
  2021-02-10 17:51 ` [PATCH rt-tests v5 13/13] oslat: Add quiet command line option Daniel Wagner
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Write the test results as JSON output to a file. This allows to
simplifies any parsing later on.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/rt-migrate-test/rt-migrate-test.c | 120 ++++++++++++++++++++++----
 1 file changed, 101 insertions(+), 19 deletions(-)

diff --git a/src/rt-migrate-test/rt-migrate-test.c b/src/rt-migrate-test/rt-migrate-test.c
index 9bf716c9178c..56b7b66ccdf4 100644
--- a/src/rt-migrate-test/rt-migrate-test.c
+++ b/src/rt-migrate-test/rt-migrate-test.c
@@ -19,11 +19,14 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <sys/time.h>
-#include <linux/unistd.h>
 #include <sys/syscall.h>
 #include <errno.h>
 #include <sched.h>
 #include <pthread.h>
+#include <inttypes.h>
+
+#include <linux/unistd.h>
+
 #include "rt-utils.h"
 
 int nr_tasks;
@@ -99,6 +102,7 @@ static int done;
 static int loop;
 static int duration;
 static int quiet;
+static char outfile[MAX_PATH];
 
 static pthread_barrier_t start_barrier;
 static pthread_barrier_t end_barrier;
@@ -160,6 +164,7 @@ static void usage(int error)
 	       "-h       --help            Print this help message\n"
 	       "-l LOOPS --loops=LOOPS     Number of iterations to run (50)\n"
 	       "-m TIME  --maxerr=TIME     Max allowed error (microsecs)\n"
+	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
 	       "-p PRIO  --prio=PRIO       base priority to start RT tasks with (2)\n"
 	       "-q       --quiet           print a summary only on exit\n"
 	       "-r TIME  --run-time=TIME   Run time (ms) to busy loop the threads (20)\n"
@@ -169,22 +174,29 @@ static void usage(int error)
 	exit(error);
 }
 
+enum option_value {
+	OPT_CHECK=1, OPT_DURATION, OPT_EQUAL, OPT_HELP, OPT_LOOPS,
+	OPT_MAXERR, OPT_OUTPUT, OPT_PRIO, OPT_QUIET, OPT_RUN_TIME,
+	OPT_SLEEP_TIME
+};
+
 static void parse_options(int argc, char *argv[])
 {
 	for (;;) {
 		int option_index = 0;
 		/** Options for getopt */
 		static struct option long_options[] = {
-			{"check",	no_argument,		NULL, 'c'},
-			{"duration",	required_argument,	NULL, 'D'},
-			{"equal",	no_argument,		NULL, 'e'},
-			{"help",	no_argument,		NULL, 'h'},
-			{"loops",	required_argument,	NULL, 'l'},
-			{"maxerr",	required_argument,	NULL, 'm'},
-			{"prio",	required_argument,	NULL, 'p'},
-			{"quiet",	no_argument,		NULL, 'q'},
-			{"run-time",	required_argument,	NULL, 'r'},
-			{"sleep-time",	required_argument,	NULL, 's'},
+			{"check",	no_argument,		NULL, OPT_CHECK},
+			{"duration",	required_argument,	NULL, OPT_DURATION},
+			{"equal",	no_argument,		NULL, OPT_EQUAL},
+			{"help",	no_argument,		NULL, OPT_HELP},
+			{"loops",	required_argument,	NULL, OPT_LOOPS},
+			{"maxerr",	required_argument,	NULL, OPT_MAXERR},
+			{"output",	required_argument,      NULL, OPT_OUTPUT },
+			{"prio",	required_argument,	NULL, OPT_PRIO},
+			{"quiet",	no_argument,		NULL, OPT_QUIET},
+			{"run-time",	required_argument,	NULL, OPT_RUN_TIME},
+			{"sleep-time",	required_argument,	NULL, OPT_SLEEP_TIME},
 			{NULL, 0, NULL, 0}
 		};
 		int c = getopt_long(argc, argv, "cD:ehl:m:p:qr:s:",
@@ -192,21 +204,50 @@ static void parse_options(int argc, char *argv[])
 		if (c == -1)
 			break;
 		switch (c) {
-		case 'c': check = 1; break;
-		case 'D': duration = parse_time_string(optarg); break;
-		case 'e': equal = 1; break;
+		case OPT_CHECK:
+		case 'c':
+			check = 1;
+			break;
+		case OPT_DURATION:
+		case 'D':
+			duration = parse_time_string(optarg);
+			break;
+		case OPT_EQUAL:
+		case 'e':
+			equal = 1;
+			break;
+		case OPT_HELP:
 		case '?':
 		case 'h':
 			usage(0);
 			break;
-		case 'l': nr_runs = atoi(optarg); break;
-		case 'm': max_err = usec2nano(atoi(optarg)); break;
-		case 'p': prio_start = atoi(optarg); break;
-		case 'q': quiet = 1; break;
+		case OPT_LOOPS:
+		case 'l':
+			nr_runs = atoi(optarg);
+			break;
+		case OPT_MAXERR:
+		case 'm':
+			max_err = usec2nano(atoi(optarg));
+			break;
+		case OPT_OUTPUT:
+			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
+			break;
+		case OPT_PRIO:
+		case 'p':
+			prio_start = atoi(optarg);
+			break;
+		case OPT_QUIET:
+		case 'q':
+			quiet = 1;
+			break;
+		case OPT_RUN_TIME:
 		case 'r':
 			run_interval = atoi(optarg);
 			break;
-		case 's': interval = atoi(optarg); break;
+		case OPT_SLEEP_TIME:
+		case 's':
+			interval = atoi(optarg);
+			break;
 		default:
 			usage(1);
 		}
@@ -313,6 +354,44 @@ static void print_results(void)
 	}
 }
 
+static void write_stats(FILE *f, void *data)
+{
+	int i;
+	int t;
+	unsigned long long tasks_max[nr_tasks];
+	unsigned long long tasks_min[nr_tasks];
+	unsigned long long tasks_avg[nr_tasks];
+
+	memset(tasks_max, 0, sizeof(tasks_max[0])*nr_tasks);
+	memset(tasks_min, 0xff, sizeof(tasks_min[0])*nr_tasks);
+	memset(tasks_avg, 0, sizeof(tasks_avg[0])*nr_tasks);
+
+	for (i=0; i < nr_runs; i++) {
+		for (t=0; t < nr_tasks; t++) {
+			unsigned long long itv = intervals[i][t];
+
+			if (tasks_max[t] < itv)
+				tasks_max[t] = itv;
+			if (tasks_min[t] > itv)
+				tasks_min[t] = itv;
+			tasks_avg[t] += itv;
+		}
+	}
+
+	fprintf(f, "  \"num_threads\": %d,\n", nr_tasks);
+	fprintf(f, "  \"thread\": {\n");
+	for (i = 0; i < nr_tasks; i++) {
+		fprintf(f, "    \"%u\": {\n", i);
+		fprintf(f, "      \"prio\": %d,\n", calc_prio(i));
+		fprintf(f, "      \"min\": %lld,\n", nano2usec(tasks_min[i]));
+		fprintf(f, "      \"avg\": %lld,\n", nano2usec(tasks_avg[i]) / nr_runs);
+		fprintf(f, "      \"max\": %lld,\n", nano2usec(tasks_max[i]));
+		fprintf(f, "      \"total\": %lld\n", nano2usec(tasks_avg[i]));
+		fprintf(f, "    }%s\n", i == nr_tasks - 1 ? "" : ",");
+	}
+	fprintf(f, "  }\n");
+}
+
 static unsigned long busy_loop(unsigned long long start_time)
 {
 	unsigned long long time;
@@ -582,6 +661,9 @@ int main (int argc, char **argv)
 
 	print_results();
 
+	if (strlen(outfile) != 0)
+		rt_write_json(outfile, argc, argv, write_stats, NULL);
+
 	if (stop) {
 		/*
 		 * We use this test in bash while loops
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH rt-tests v5 13/13] oslat: Add quiet command line option
  2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
                   ` (11 preceding siblings ...)
  2021-02-10 17:51 ` [PATCH rt-tests v5 12/13] rt-migrate-test: " Daniel Wagner
@ 2021-02-10 17:51 ` Daniel Wagner
  2021-02-17  3:52   ` John Kacur
  12 siblings, 1 reply; 27+ messages in thread
From: Daniel Wagner @ 2021-02-10 17:51 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

The quiet option is useful for automated test setups where
only the final result of the run is interesting.

Furthermore, this makes oslat accept rt-tests standard options.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/oslat/oslat.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c
index 987f2002985d..0d9afedbdc82 100644
--- a/src/oslat/oslat.c
+++ b/src/oslat/oslat.c
@@ -171,6 +171,7 @@ struct global {
 	uint64_t              workload_mem_size;
 	int                   enable_bias;
 	uint64_t              bias;
+	int                   quiet;
 	int                   single_preheat_thread;
 	int                   output_omit_zero_buckets;
 	char                  outfile[MAX_PATH];
@@ -565,6 +566,7 @@ static void usage(int error)
 	       "                       Total memory usage will be this value multiplies 2*N,\n"
 	       "                       because there will be src/dst buffers for each thread, and\n"
 	       "                       N is the number of processors for testing.\n"
+	       "-q  --quiet            print a summary only on exit\n"
 	       "-s, --single-preheat   Use a single thread when measuring latency at preheat stage\n"
 	       "                       NOTE: please make sure the CPU frequency on all testing cores\n"
 	       "                       are locked before using this parmater.  If you don't know how\n"
@@ -598,8 +600,8 @@ enum option_value {
 	OPT_BUCKETSIZE=1, OPT_CPU_LIST, OPT_CPU_MAIN_THREAD,
 	OPT_DURATION, OPT_RT_PRIO, OPT_HELP, OPT_TRACE_TH,
 	OPT_WORKLOAD, OPT_WORKLOAD_MEM, OPT_BIAS, OPT_OUTPUT,
-	OPT_SINGLE_PREHEAT, OPT_ZERO_OMIT, OPT_VERSION
-
+	OPT_QUIET, OPT_SINGLE_PREHEAT, OPT_ZERO_OMIT,
+	OPT_VERSION
 };
 
 /* Process commandline options */
@@ -618,13 +620,14 @@ static void parse_options(int argc, char *argv[])
 			{ "workload",	required_argument,	NULL, OPT_WORKLOAD },
 			{ "workload-mem", required_argument,	NULL, OPT_WORKLOAD_MEM },
 			{ "bias",	no_argument,		NULL, OPT_BIAS },
+			{ "quiet",	no_argument,		NULL, OPT_QUIET },
 			{ "single-preheat", no_argument,	NULL, OPT_SINGLE_PREHEAT },
 			{ "output",	required_argument,      NULL, OPT_OUTPUT },
 			{ "zero-omit",	no_argument,		NULL, OPT_ZERO_OMIT },
 			{ "version",	no_argument,		NULL, OPT_VERSION },
 			{ NULL, 0, NULL, 0 },
 		};
-		int i, c = getopt_long(argc, argv, "b:Bc:C:D:f:hm:sw:T:vz",
+		int i, c = getopt_long(argc, argv, "b:Bc:C:D:f:hm:qsw:T:vz",
 				       options, &option_index);
 		long ncores;
 
@@ -707,6 +710,10 @@ static void parse_options(int argc, char *argv[])
 				exit(1);
 			}
 			break;
+		case OPT_QUIET:
+		case 'q':
+			g.quiet = 1;
+			break;
 		case OPT_SINGLE_PREHEAT:
 		case 's':
 			/*
@@ -825,9 +832,11 @@ int main(int argc, char *argv[])
 	signal(SIGINT, handle_alarm);
 	signal(SIGTERM, handle_alarm);
 
-	dump_globals();
+	if (!g.quiet)
+		dump_globals();
 
-	printf("Pre-heat for 1 seconds...\n");
+	if (!g.quiet)
+		printf("Pre-heat for 1 seconds...\n");
 	if (g.single_preheat_thread)
 		g.n_threads = 1;
 	else
@@ -835,12 +844,14 @@ int main(int argc, char *argv[])
 	run_expt(threads, 1);
 	record_bias(threads);
 
-	printf("Test starts...\n");
+	if (!g.quiet)
+		printf("Test starts...\n");
 	/* Reset n_threads to always run on all the cores */
 	g.n_threads = g.n_threads_total;
 	run_expt(threads, g.runtime);
 
-	printf("Test completed.\n\n");
+	if (!g.quiet)
+		printf("Test completed.\n\n");
 
 	write_summary(threads);
 
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 03/13] rt-utils: Add JSON common header output helper
  2021-02-10 17:51 ` [PATCH rt-tests v5 03/13] rt-utils: Add JSON common header output helper Daniel Wagner
@ 2021-02-17  3:50   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:50 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> rt_write_json writes the common system information header of the
> rt-test currently executed.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/include/rt-utils.h |  4 ++
>  src/lib/rt-utils.c     | 96 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 100 insertions(+)
> 
> diff --git a/src/include/rt-utils.h b/src/include/rt-utils.h
> index 39ddbd9eae29..36af92b170df 100644
> --- a/src/include/rt-utils.h
> +++ b/src/include/rt-utils.h
> @@ -80,4 +80,8 @@ static inline int64_t calctime(struct timespec t)
>  	return time;
>  }
>  
> +void rt_write_json(const char *filename, int argc, char *argv[],
> +		   void (*cb)(FILE *, void *),
> +		   void *data);
> +
>  #endif	/* __RT_UTILS.H */
> diff --git a/src/lib/rt-utils.c b/src/lib/rt-utils.c
> index 321a11b1172d..00907c573d6a 100644
> --- a/src/lib/rt-utils.c
> +++ b/src/lib/rt-utils.c
> @@ -20,6 +20,9 @@
>  #include <sys/stat.h>
>  #include <unistd.h>
>  #include <sys/syscall.h> /* For SYS_gettid definitions */
> +#include <sys/utsname.h>
> +#include <time.h>
> +#include <sys/time.h>
>  
>  #include "rt-utils.h"
>  #include "rt-sched.h"
> @@ -482,3 +485,96 @@ void disable_trace_mark(void)
>  {
>  	close_tracemark_fd();
>  }
> +
> +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");
> +
> +	memset(cmdline, 0, len);
> +	for (i = 0; i < argc;) {
> +		cmdline = strcat(cmdline, argv[i]);
> +		i++;
> +		if (i < argc)
> +			cmdline = strcat(cmdline, " ");
> +	}
> +
> +	return cmdline;
> +}
> +
> +void rt_write_json(const char *filename, int argc, char *argv[],
> +		  void (*cb)(FILE *, void *),
> +		  void *data)
> +{
> +	unsigned char buf[1];
> +	struct utsname uts;
> +	struct timeval tv;
> +	char tsbuf[64];
> +	struct tm *tm;
> +	char *cmdline;
> +	FILE *f, *s;
> +	time_t t;
> +	size_t n;
> +	int rt = 0;
> +
> +	if (!filename || !strcmp("-", filename)) {
> +		f = stdout;
> +	} else {
> +		f = fopen(filename, "w");
> +		if (!f)
> +			err_exit(errno, "Failed to open '%s'\n", filename);
> +	}
> +
> +	cmdline = get_cmdline(argc, argv);
> +	if (!cmdline)
> +		err_exit(ENOMEM, "get_cmdline()");
> +
> +
> +	gettimeofday(&tv, NULL);
> +	t = tv.tv_sec;
> +	tm = localtime(&t);
> +	/* RFC 2822-compliant date format */
> +	strftime(tsbuf, sizeof(tsbuf), "%a, %d %b %Y %T %z", tm);
> +
> +	s = fopen("/sys/kernel/realtime", "r");
> +	if (s) {
> +		n = fread(buf, 1, 1, s);
> +		if (n == 1 && buf[0] == '1')
> +			rt = 1;
> +		fclose(s);
> +	}
> +
> +	if (uname(&uts))
> +		err_exit(errno, "Could not retrieve system information");
> +
> +	fprintf(f, "{\n");
> +	fprintf(f, "  \"file_version\": 1,\n");
> +	fprintf(f, "  \"cmdline:\": \"%s\",\n", cmdline);
> +	fprintf(f, "  \"rt_test_version:\": \"%1.2f\",\n", VERSION);
> +	fprintf(f, "  \"finished\": \"%s\",\n", tsbuf);
> +	fprintf(f, "  \"sysinfo\": {\n");
> +	fprintf(f, "    \"sysname\": \"%s\",\n", uts.sysname);
> +	fprintf(f, "    \"nodename\": \"%s\",\n", uts.nodename);
> +	fprintf(f, "    \"release\": \"%s\",\n", uts.release);
> +	fprintf(f, "    \"version\": \"%s\",\n", uts.version);
> +	fprintf(f, "    \"machine\": \"%s\",\n", uts.machine);
> +	fprintf(f, "    \"realtime\": %d\n", rt);
> +	fprintf(f, "  },\n");
> +
> +	(cb)(f, data);
> +
> +	fprintf(f, "}\n");
> +
> +	free(cmdline);
> +
> +	if (!filename || strcmp("-", filename))
> +		fclose(f);
> +}
> -- 
> 2.30.0
> 
> 

Signed-off-by: John Kacur <jkacur@redhat.com>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 04/13] cyclictest: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 04/13] cyclictest: Add JSON output feature Daniel Wagner
@ 2021-02-17  3:50   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:50 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/cyclictest/cyclictest.c | 46 ++++++++++++++++++++++++++++++++++++-
>  1 file changed, 45 insertions(+), 1 deletion(-)
> 
> diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
> index 7c45732c1553..3d0cf3f84b69 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;
> @@ -838,6 +840,7 @@ static void display_help(int error)
>  	       "			   latency is hit. Useful for low bandwidth.\n"
>  	       "-N       --nsecs           print results in ns instead of us (default us)\n"
>  	       "-o RED   --oscope=RED      oscilloscope mode, reduce verbose output by RED\n"
> +	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
>  	       "-p PRIO  --priority=PRIO   priority of highest prio thread\n"
>  	       "	 --policy=NAME     policy of measurement thread, where NAME may be one\n"
>  	       "                           of: other, normal, batch, idle, fifo or rr.\n"
> @@ -945,7 +948,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 */
> @@ -979,6 +982,7 @@ static void process_options(int argc, char *argv[])
>  			{"refresh_on_max",   no_argument,       NULL, OPT_REFRESH },
>  			{"nsecs",            no_argument,       NULL, OPT_NSECS },
>  			{"oscope",           required_argument, NULL, OPT_OSCOPE },
> +			{"output",           required_argument, NULL, OPT_OUTPUT },
>  			{"priority",         required_argument, NULL, OPT_PRIORITY },
>  			{"quiet",            no_argument,       NULL, OPT_QUIET },
>  			{"priospread",       no_argument,       NULL, OPT_PRIOSPREAD },
> @@ -1073,6 +1077,9 @@ 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));
> +			break;
>  		case 'p':
>  		case OPT_PRIORITY:
>  			priority = atoi(optarg);
> @@ -1690,6 +1697,40 @@ static void rstat_setup(void)
>  	return;
>  }
>  
> +static void write_stats(FILE *f, void *data)
> +{
> +	struct thread_param **par = parameters;
> +	unsigned int i, j, comma;
> +	struct thread_stat *s;
> +
> +	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
> +	fprintf(f, "  \"resolution_in_ns\": %u,\n", use_nsecs);
> +	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");
> +}
>  
>  int main(int argc, char **argv)
>  {
> @@ -2035,6 +2076,9 @@ int main(int argc, char **argv)
>  	if (!verbose && !quiet && refresh_on_max)
>  		printf("\033[%dB", num_threads + 2);
>  
> +	if (strlen(outfile) != 0)
> +		rt_write_json(outfile, argc, argv, write_stats, NULL);
> +
>  	if (quiet)
>  		quiet = 2;
>  	for (i = 0; i < num_threads; i++) {
> -- 
> 2.30.0
> 
> 
   - Added a space after a comma in fprintf
    Signed-off-by: John Kacur <jkacur@redhat.com>


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 05/13] signaltest: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 05/13] signaltest: " Daniel Wagner
@ 2021-02-17  3:50   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:50 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/signaltest/signaltest.c | 109 +++++++++++++++++++++++++++++-------
>  1 file changed, 88 insertions(+), 21 deletions(-)
> 
> diff --git a/src/signaltest/signaltest.c b/src/signaltest/signaltest.c
> index dd5633d5fc51..09039b299367 100644
> --- a/src/signaltest/signaltest.c
> +++ b/src/signaltest/signaltest.c
> @@ -22,6 +22,7 @@
>  #include <unistd.h>
>  #include <errno.h>
>  #include <sched.h>
> +#include <inttypes.h>
>  
>  #include <linux/unistd.h>
>  
> @@ -205,6 +206,14 @@ static int verbose;
>  static int quiet;
>  static int lockall;
>  static struct bitmask *affinity_mask = NULL;
> +static char outfile[MAX_PATH];
> +
> +enum option_values {
> +	OPT_AFFINITY=1, OPT_BREAKTRACE,
> +	OPT_DURATION, OPT_HELP, OPT_LOOPS,
> +	OPT_MLOCKALL, OPT_OUTPUT, OPT_PRIORITY,
> +	OPT_QUIET, OPT_SMP, OPT_THREADS, OPT_VERBOSE
> +};
>  
>  /* Process commandline options */
>  static void process_options(int argc, char *argv[])
> @@ -216,17 +225,18 @@ static void process_options(int argc, char *argv[])
>  		int option_index = 0;
>  		/** Options for getopt */
>  		static struct option long_options[] = {
> -			{"affinity",		optional_argument,	NULL, 'a'},
> -			{"breaktrace",		required_argument,	NULL, 'b'},
> -			{"duration",		required_argument,	NULL, 'D'},
> -			{"help",		no_argument,		NULL, 'h'},
> -			{"loops",		required_argument,	NULL, 'l'},
> -			{"mlockall",		no_argument,		NULL, 'm'},
> -			{"priority",		required_argument,	NULL, 'p'},
> -			{"quiet",		no_argument,		NULL, 'q'},
> -			{"smp",			no_argument,		NULL, 'S'},
> -			{"threads",		required_argument,	NULL, 't'},
> -			{"verbose",		no_argument,		NULL, 'v'},
> +			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
> +			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
> +			{"duration",	required_argument,	NULL, OPT_DURATION},
> +			{"help",	no_argument,		NULL, OPT_HELP},
> +			{"loops",	required_argument,	NULL, OPT_LOOPS},
> +			{"mlockall",	no_argument,		NULL, OPT_MLOCKALL},
> +			{"output",	required_argument,	NULL, OPT_OUTPUT},
> +			{"priority",	required_argument,	NULL, OPT_PRIORITY},
> +			{"quiet",	no_argument,		NULL, OPT_QUIET},
> +			{"smp",		no_argument,		NULL, OPT_SMP},
> +			{"threads",	required_argument,	NULL, OPT_THREADS},
> +			{"verbose",	no_argument,		NULL, OPT_VERBOSE},
>  			{NULL, 0, NULL, 0}
>  		};
>  		int c = getopt_long(argc, argv, "a::b:D:hl:mp:qSt:v",
> @@ -234,6 +244,7 @@ static void process_options(int argc, char *argv[])
>  		if (c == -1)
>  			break;
>  		switch (c) {
> +		case OPT_AFFINITY:
>  		case 'a':
>  			if (optarg) {
>  				parse_cpumask(optarg, &affinity_mask);
> @@ -248,17 +259,49 @@ static void process_options(int argc, char *argv[])
>  				printf("Using %u cpus.\n",
>  					numa_bitmask_weight(affinity_mask));
>  			break;
> -		case 'b': tracelimit = atoi(optarg); break;
> -		case 'D': duration = parse_time_string(optarg); break;
> +		case OPT_BREAKTRACE:
> +		case 'b':
> +			tracelimit = atoi(optarg);
> +			break;
> +		case OPT_DURATION:
> +		case 'D':
> +			duration = parse_time_string(optarg);
> +			break;
> +		case OPT_HELP:
>  		case '?':
> -		case 'h': display_help(0); break;
> -		case 'l': max_cycles = atoi(optarg); break;
> -		case 'm': lockall = 1; break;
> -		case 'p': priority = atoi(optarg); break;
> -		case 'q': quiet = 1; break;
> -		case 'S': smp = 1; break;
> -		case 't': num_threads = atoi(optarg); break;
> -		case 'v': verbose = 1; break;
> +		case 'h':
> +			display_help(0);
> +			break;
> +		case OPT_LOOPS:
> +		case 'l':
> +			max_cycles = atoi(optarg);
> +			break;
> +		case OPT_MLOCKALL:
> +		case 'm':
> +			lockall = 1;
> +			break;
> +		case OPT_OUTPUT:
> +			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
> +			break;
> +		case OPT_PRIORITY:
> +		case 'p':
> +			priority = atoi(optarg);
> +			break;
> +		case OPT_QUIET:
> +		case 'q':
> +			quiet = 1;
> +			break;
> +		case OPT_SMP:
> +		case 'S':
> +			smp = 1;
> +			break;
> +		case OPT_THREADS:
> +		case 't':
> +			num_threads = atoi(optarg);
> +			break;
> +		case OPT_VERBOSE:
> +		case 'v': verbose = 1;
> +			break;
>  		}
>  	}
>  
> @@ -312,6 +355,27 @@ static void print_stat(struct thread_param *par, int index, int verbose)
>  	}
>  }
>  
> +static void write_stats(FILE *f, void *data)
> +{
> +	struct thread_param *par = data;
> +	struct thread_stat *s;
> +	unsigned int i;
> +
> +	fprintf(f, "  \"thread\": {\n");
> +	for (i = 0; i < num_threads; i++) {
> +		fprintf(f, "    \"%u\": {\n", i);
> +		s = &par->stats[i];
> +		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->cpu);
> +		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
> +
> +	}
> +	fprintf(f, "  }\n");
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	sigset_t sigset;
> @@ -454,6 +518,9 @@ int main(int argc, char **argv)
>  		if (stat[i].values)
>  			free(stat[i].values);
>  	}
> +	if (strlen(outfile) != 0)
> +		rt_write_json(outfile, argc, argv, write_stats, par);
> +
>  	free(stat);
>   outpar:
>  	free(par);
> -- 
> 2.30.0
> 
> 

This has a number of conflicts due to me
not applying all of the changes to smp / numa

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 06/13] cyclicdeadline: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 06/13] cyclicdeadline: " Daniel Wagner
@ 2021-02-17  3:51   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:51 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/sched_deadline/cyclicdeadline.c | 72 ++++++++++++++++++++++-------
>  1 file changed, 56 insertions(+), 16 deletions(-)
> 
> diff --git a/src/sched_deadline/cyclicdeadline.c b/src/sched_deadline/cyclicdeadline.c
> index 71cde5781499..ed3c960d9916 100644
> --- a/src/sched_deadline/cyclicdeadline.c
> +++ b/src/sched_deadline/cyclicdeadline.c
> @@ -18,6 +18,7 @@
>  #include <errno.h>
>  #include <signal.h>
>  #include <getopt.h>
> +#include <inttypes.h>
>  
>  #include <sys/syscall.h>
>  #include <sys/types.h>
> @@ -85,13 +86,11 @@ static pthread_barrier_t barrier;
>  
>  static int cpu_count;
>  static int all_cpus;
> -
>  static int nr_threads;
>  static int use_nsecs;
> -
>  static int mark_fd;
> -
>  static int quiet;
> +static char outfile[MAX_PATH];
>  
>  static int find_mount(const char *mount, char *debugfs)
>  {
> @@ -603,16 +602,17 @@ static void usage(int error)
>  	       "                           tasks on. An empty CPUSET runs on all CPUs a deadline\n"
>  	       "                           task.\n"
>  	       "                           on CPU 4, and thread #5 on CPU 5.\n"
> -	       "-D TIME     --duration     Specify a length for the test run.\n"
> +	       "-D TIME  --duration        Specify a length for the test run.\n"
>  	       "                           Append 'm', 'h', or 'd' to specify minutes, hours or\n"
>  	       "                           days\n"
> -	       "-h          --help         Show this help menu.\n"
> -	       "-i INTV     --interval     The shortest deadline for the tasks in us\n"
> +	       "-h       --help            Show this help menu.\n"
> +	       "-i INTV  --interval        The shortest deadline for the tasks in us\n"
>  	       "                           (default 1000us).\n"
> -	       "-s STEP     --step         The amount to increase the deadline for each task in us\n"
> +	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
> +	       "-s STEP  --step            The amount to increase the deadline for each task in us\n"
>  	       "                           (default 500us).\n"
> -	       "-t NUM      --threads      The number of threads to run as deadline (default 1).\n"
> -	       "-q          --quiet        print a summary only on exit\n"
> +	       "-t NUM   --threads         The number of threads to run as deadline (default 1).\n"
> +	       "-q       --quiet           print a summary only on exit\n"
>  	       );
>  	exit(error);
>  }
> @@ -966,6 +966,32 @@ static void loop(struct sched_data *sched_data, int nr_threads)
>  	}
>  }
>  
> +static void write_stats(FILE *f, void *data)
> +{
> +	struct sched_data *sd = data;
> +	struct thread_stat *s;
> +	unsigned int i;
> +
> +	fprintf(f, "  \"num_threads\": %d,\n", nr_threads);
> +	fprintf(f, "  \"resolution_in_ns\": %u,\n", use_nsecs);
> +	fprintf(f, "  \"thread\": {\n");
> +	for (i = 0; i < nr_threads; i++) {
> +		s = &sd[i].stat;
> +		fprintf(f, "    \"%u\": {\n", i);
> +		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, "    }%s\n", i == nr_threads - 1 ? "" : ",");
> +	}
> +	fprintf(f, "  }\n");
> +}
> +
> +enum options_valud {
> +	OPT_AFFINITY=1, OPT_DURATION, OPT_HELP, OPT_INTERVAL,
> +	OPT_OUTPUT, OPT_STEP, OPT_THREADS, OPT_QUIET
> +};
> +
>  int main(int argc, char **argv)
>  {
>  	struct sched_data *sched_data;
> @@ -992,19 +1018,21 @@ int main(int argc, char **argv)
>  
>  	for (;;) {
>  		static struct option options[] = {
> -			{ "affinity",	optional_argument,	NULL,	'a' },
> -			{ "duration",	required_argument,	NULL,	'D' },
> -			{ "help",	no_argument,		NULL,	'h' },
> -			{ "interval",	required_argument,	NULL,	'i' },
> -			{ "step",	required_argument,	NULL,	's' },
> -			{ "threads",	required_argument,	NULL,	't' },
> -			{ "quiet",	no_argument,		NULL,	'q' },
> +			{ "affinity",	optional_argument,	NULL,	OPT_AFFINITY },
> +			{ "duration",	required_argument,	NULL,	OPT_DURATION },
> +			{ "help",	no_argument,		NULL,	OPT_HELP },
> +			{ "interval",	required_argument,	NULL,	OPT_INTERVAL },
> +			{ "output",	required_argument,	NULL,	OPT_OUTPUT },
> +			{ "step",	required_argument,	NULL,	OPT_STEP },
> +			{ "threads",	required_argument,	NULL,	OPT_THREADS },
> +			{ "quiet",	no_argument,		NULL,	OPT_QUIET },
>  			{ NULL,		0,			NULL,	0   },
>  		};
>  		c = getopt_long(argc, argv, "a::c:D:hi:s:t:q", options, NULL);
>  		if (c == -1)
>  			break;
>  		switch (c) {
> +		case OPT_AFFINITY:
>  		case 'a':
>  		case 'c':
>  			if (!nr_threads)
> @@ -1016,21 +1044,30 @@ int main(int argc, char **argv)
>  			else
>  				all_cpus = 1;
>  			break;
> +		case OPT_INTERVAL:
>  		case 'i':
>  			interval = atoi(optarg);
>  			break;
> +		case OPT_OUTPUT:
> +			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
> +			break;
> +		case OPT_STEP:
>  		case 's':
>  			step = atoi(optarg);
>  			break;
> +		case OPT_THREADS:
>  		case 't':
>  			nr_threads = atoi(optarg);
>  			break;
> +		case OPT_DURATION:
>  		case 'D':
>  			duration = parse_time_string(optarg);
>  			break;
> +		case OPT_QUIET:
>  		case 'q':
>  			quiet = 1;
>  			break;
> +		case OPT_HELP:
>  		case 'h':
>  			usage(0);
>  			break;
> @@ -1190,6 +1227,9 @@ int main(int argc, char **argv)
>  		}
>  	}
>  
> +	if (strlen(outfile) != 0)
> +		rt_write_json(outfile, argc, argv, write_stats, sched_data);
> +
>  	if (setcpu_buf)
>  		free(setcpu_buf);
>  	free(thread);
> -- 
> 2.30.0
> 
> 

Signed-off-by: John Kacur <jkacur@redhat.com>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 07/13] pmqtest: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 07/13] pmqtest: " Daniel Wagner
@ 2021-02-17  3:51   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:51 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/pmqtest/pmqtest.c | 137 +++++++++++++++++++++++++++++++++++-------
>  1 file changed, 114 insertions(+), 23 deletions(-)
> 
> diff --git a/src/pmqtest/pmqtest.c b/src/pmqtest/pmqtest.c
> index 349b47741003..e1f59836ea07 100644
> --- a/src/pmqtest/pmqtest.c
> +++ b/src/pmqtest/pmqtest.c
> @@ -22,6 +22,7 @@
>  #include <utmpx.h>
>  #include <mqueue.h>
>  #include <pthread.h>
> +#include <inttypes.h>
>  
>  #include "rt-utils.h"
>  #include "rt-get_cpu.h"
> @@ -231,6 +232,7 @@ static void display_help(int error)
>  	       "-h       --help            print this help message\n"
>  	       "-i INTV  --interval=INTV   base interval of thread in us default=1000\n"
>  	       "-l LOOPS --loops=LOOPS     number of loops: default=0(endless)\n"
> +	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
>  	       "-p PRIO  --prio=PRIO       priority\n"
>  	       "-q       --quiet           print a summary only on exit\n"
>  	       "-S       --smp             SMP testing: options -a -t and same priority\n"
> @@ -258,6 +260,14 @@ static int sameprio;
>  static int timeout;
>  static int forcetimeout;
>  static int quiet;
> +static char outfile[MAX_PATH];
> +
> +enum option_value {
> +	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_DISTANCE, OPT_DURATION,
> +	OPT_FORCETIMEOUT, OPT_HELP, OPT_INTERVAL, OPT_LOOPS,
> +	OPT_OUTPUT, OPT_PRIORITY, OPT_QUIET, OPT_SMP, OPT_THREADS,
> +	OPT_TIMEOUT
> +};
>  
>  static void process_options(int argc, char *argv[])
>  {
> @@ -268,19 +278,20 @@ static void process_options(int argc, char *argv[])
>  		int option_index = 0;
>  		/** Options for getopt */
>  		static struct option long_options[] = {
> -			{"affinity",		optional_argument,	NULL, 'a'},
> -			{"breaktrace",		required_argument,	NULL, 'b'},
> -			{"distance",		required_argument,	NULL, 'd'},
> -			{"duration",		required_argument,	NULL, 'D'},
> -			{"forcetimeout",	required_argument,	NULL, 'f'},
> -			{"help",		no_argument,		NULL, 'h'},
> -			{"interval",		required_argument,	NULL, 'i'},
> -			{"loops",		required_argument,	NULL, 'l'},
> -			{"priority",		required_argument,	NULL, 'p'},
> -			{"quiet",		no_argument,		NULL, 'q'},
> -			{"smp",			no_argument,		NULL, 'S'},
> -			{"threads",		optional_argument,	NULL, 't'},
> -			{"timeout",		required_argument,	NULL, 'T'},
> +			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
> +			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
> +			{"distance",	required_argument,	NULL, OPT_DISTANCE},
> +			{"duration",	required_argument,	NULL, OPT_DURATION},
> +			{"forcetimeout",required_argument,	NULL, OPT_FORCETIMEOUT},
> +			{"help",	no_argument,		NULL, OPT_HELP},
> +			{"interval",	required_argument,	NULL, OPT_INTERVAL},
> +			{"loops",	required_argument,	NULL, OPT_LOOPS},
> +			{"output",	required_argument,      NULL, OPT_OUTPUT },
> +			{"priority",	required_argument,	NULL, OPT_PRIORITY},
> +			{"quiet",	no_argument,		NULL, OPT_QUIET},
> +			{"smp",		no_argument,		NULL, OPT_SMP},
> +			{"threads",	optional_argument,	NULL, OPT_THREADS},
> +			{"timeout",	required_argument,	NULL, OPT_TIMEOUT},
>  			{NULL, 0, NULL, 0}
>  		};
>  		int c = getopt_long (argc, argv, "a::b:d:D:f:i:l:p:qSt::T:",
> @@ -288,6 +299,7 @@ static void process_options(int argc, char *argv[])
>  		if (c == -1)
>  			break;
>  		switch (c) {
> +		case OPT_AFFINITY:
>  		case 'a':
>  			if (smp) {
>  				warn("-a ignored due to --smp\n");
> @@ -303,21 +315,53 @@ static void process_options(int argc, char *argv[])
>  				setaffinity = AFFINITY_USEALL;
>  			}
>  			break;
> -		case 'b': tracelimit = atoi(optarg); break;
> -		case 'd': distance = atoi(optarg); break;
> -		case 'D': duration = parse_time_string(optarg); break;
> -		case 'f': forcetimeout = atoi(optarg); break;
> +		case OPT_BREAKTRACE:
> +		case 'b':
> +			tracelimit = atoi(optarg);
> +			break;
> +		case OPT_DISTANCE:
> +		case 'd':
> +			distance = atoi(optarg);
> +			break;
> +		case OPT_DURATION:
> +		case 'D':
> +			duration = parse_time_string(optarg);
> +			break;
> +		case OPT_FORCETIMEOUT:
> +		case 'f':
> +			forcetimeout = atoi(optarg);
> +			break;
> +		case OPT_HELP:
>  		case '?':
> -		case 'h': display_help(0); break;
> -		case 'i': interval = atoi(optarg); break;
> -		case 'l': max_cycles = atoi(optarg); break;
> -		case 'p': priority = atoi(optarg); break;
> -		case 'q': quiet = 1; break;
> +		case 'h':
> +			display_help(0);
> +			break;
> +		case OPT_INTERVAL:
> +		case 'i':
> +			interval = atoi(optarg);
> +			break;
> +		case OPT_LOOPS:
> +		case 'l':
> +			max_cycles = atoi(optarg);
> +			break;
> +		case OPT_OUTPUT:
> +			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
> +			break;
> +		case OPT_PRIORITY:
> +		case 'p':
> +			priority = atoi(optarg);
> +			break;
> +		case OPT_QUIET:
> +		case 'q':
> +			quiet = 1;
> +			break;
> +		case OPT_SMP:
>  		case 'S':
>  			smp = 1;
>  			num_threads = max_cpus;
>  			setaffinity = AFFINITY_USEALL;
>  			break;
> +		case OPT_THREADS:
>  		case 't':
>  			if (smp) {
>  				warn("-t ignored due to --smp\n");
> @@ -330,7 +374,10 @@ static void process_options(int argc, char *argv[])
>  			else
>  				num_threads = max_cpus;
>  			break;
> -		case 'T': timeout = atoi(optarg); break;
> +		case OPT_TIMEOUT:
> +		case 'T':
> +			timeout = atoi(optarg);
> +			break;
>  		default:
>  			display_help(1);
>  			break;
> @@ -401,6 +448,42 @@ static void print_stat(FILE *fp, struct params *receiver, struct params *sender,
>  	}
>  }
>  
> +struct params_stats {
> +	struct params *receiver;
> +	struct params *sender;
> +};
> +
> +static void write_stats(FILE *f, void *data)
> +{
> +	struct params_stats *ps = data;
> +	struct params *s, *r;
> +	unsigned int i;
> +
> +	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
> +	fprintf(f, "  \"thread\": {\n");
> +	for (i = 0; i < num_threads; i++) {
> +		s = &ps->sender[i];
> +		r = &ps->receiver[i];
> +		fprintf(f, "    \"%u\": {\n", i);
> +		fprintf(f, "      \"sender\": {\n");
> +		fprintf(f, "        \"cpu\": %d,\n", s->cpu);
> +		fprintf(f, "        \"priority\": %d,\n", s->priority);
> +		fprintf(f, "        \"samples\": %d,\n", s->samples);
> +		fprintf(f, "        \"interval\": %ld\n", r->delay.tv_nsec/1000);
> +		fprintf(f, "      },\n");
> +		fprintf(f, "      \"receiver\": {\n");
> +		fprintf(f, "        \"cpu\": %d,\n", r->cpu);
> +		fprintf(f, "        \"priority\": %d,\n", r->priority);
> +		fprintf(f, "        \"timeoutcount\": %d,\n", r->timeoutcount);
> +		fprintf(f, "        \"min\": %d,\n", r->mindiff);
> +		fprintf(f, "        \"avg\": %.2f,\n", r->sumdiff/r->samples);
> +		fprintf(f, "        \"max\": %d\n", r->maxdiff);
> +		fprintf(f, "      }\n");
> +		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
> +	}
> +	fprintf(f, "  }\n");
> +}
> +
>  int main(int argc, char *argv[])
>  {
>  	int i;
> @@ -562,6 +645,14 @@ int main(int argc, char *argv[])
>  		mq_unlink(mqname);
>  	}
>  
> +	if (strlen(outfile) != 0) {
> +		struct params_stats ps = {
> +			.receiver = receiver,
> +			.sender = sender,
> +		};
> +		rt_write_json(outfile, argc, argv, write_stats, &ps);
> +	}
> +
>  nomem:
>  
>  	return 0;
> -- 
> 2.30.0
> 
> 

Signed-off-by: John Kacur <jkacur@redhat.com>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 08/13] ptsematest: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 08/13] ptsematest: " Daniel Wagner
@ 2021-02-17  3:51   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:51 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/ptsematest/ptsematest.c | 120 ++++++++++++++++++++++++++++++------
>  1 file changed, 101 insertions(+), 19 deletions(-)
> 
> diff --git a/src/ptsematest/ptsematest.c b/src/ptsematest/ptsematest.c
> index 7d4ca97773d6..2755bfde5210 100644
> --- a/src/ptsematest/ptsematest.c
> +++ b/src/ptsematest/ptsematest.c
> @@ -20,6 +20,7 @@
>  #include <linux/unistd.h>
>  #include <utmpx.h>
>  #include <pthread.h>
> +#include <inttypes.h>
>  
>  #include "rt-utils.h"
>  #include "rt-get_cpu.h"
> @@ -155,6 +156,7 @@ static void display_help(int error)
>  	       "                           days.\n"
>  	       "-i INTV  --interval=INTV   base interval of thread in us default=1000\n"
>  	       "-l LOOPS --loops=LOOPS     number of loops: default=0(endless)\n"
> +	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
>  	       "-p PRIO  --prio=PRIO       priority\n"
>  	       "-q       --quiet           print a summary only on exit\n"
>  	       "-S       --smp             SMP testing: options -a -t and same priority\n"
> @@ -180,6 +182,13 @@ static int distance = 500;
>  static int smp;
>  static int sameprio;
>  static int quiet;
> +static char outfile[MAX_PATH];
> +
> +enum option_value {
> +	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_DISTANCE, OPT_DURATION,
> +	OPT_HELP, OPT_INTERVAL, OPT_LOOPS, OPT_OUTPUT, OPT_PRIORITY,
> +	OPT_QUIET, OPT_SMP, OPT_THREADS
> +};
>  
>  static void process_options(int argc, char *argv[])
>  {
> @@ -190,17 +199,18 @@ static void process_options(int argc, char *argv[])
>  		int option_index = 0;
>  		/** Options for getopt */
>  		static struct option long_options[] = {
> -			{"affinity",	optional_argument,	NULL, 'a'},
> -			{"breaktrace",	required_argument,	NULL, 'b'},
> -			{"distance",	required_argument,	NULL, 'd'},
> -			{"duration",	required_argument,	NULL, 'D'},
> -			{"help",	no_argument,		NULL, 'h'},
> -			{"interval",	required_argument,	NULL, 'i'},
> -			{"loops",	required_argument,	NULL, 'l'},
> -			{"priority",	required_argument,	NULL, 'p'},
> -			{"quiet",	no_argument	,	NULL, 'q'},
> -			{"smp",		no_argument,		NULL, 'S'},
> -			{"threads",	optional_argument,	NULL, 't'},
> +			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
> +			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
> +			{"distance",	required_argument,	NULL, OPT_DISTANCE},
> +			{"duration",	required_argument,	NULL, OPT_DURATION},
> +			{"help",	no_argument,		NULL, OPT_HELP},
> +			{"interval",	required_argument,	NULL, OPT_INTERVAL},
> +			{"loops",	required_argument,	NULL, OPT_LOOPS},
> +			{"output",	required_argument,      NULL, OPT_OUTPUT },
> +			{"priority",	required_argument,	NULL, OPT_PRIORITY},
> +			{"quiet",	no_argument	,	NULL, OPT_QUIET},
> +			{"smp",		no_argument,		NULL, OPT_SMP},
> +			{"threads",	optional_argument,	NULL, OPT_THREADS},
>  			{NULL, 0, NULL, 0}
>  		};
>  		int c = getopt_long (argc, argv, "a::b:d:i:l:D:p:qSt::h",
> @@ -208,6 +218,7 @@ static void process_options(int argc, char *argv[])
>  		if (c == -1)
>  			break;
>  		switch (c) {
> +		case OPT_AFFINITY:
>  		case 'a':
>  			if (smp) {
>  				warn("-a ignored due to --smp\n");
> @@ -223,20 +234,49 @@ static void process_options(int argc, char *argv[])
>  				setaffinity = AFFINITY_USEALL;
>  			}
>  			break;
> -		case 'b': tracelimit = atoi(optarg); break;
> -		case 'd': distance = atoi(optarg); break;
> -		case 'D': duration = parse_time_string(optarg); break;
> -		case 'i': interval = atoi(optarg); break;
> +		case OPT_BREAKTRACE:
> +		case 'b':
> +			tracelimit = atoi(optarg);
> +			break;
> +		case OPT_DISTANCE:
> +		case 'd':
> +			distance = atoi(optarg);
> +			break;
> +		case OPT_DURATION:
> +		case 'D':
> +			duration = parse_time_string(optarg);
> +			break;
> +		case OPT_INTERVAL:
> +		case 'i':
> +			interval = atoi(optarg);
> +			break;
> +		case OPT_HELP:
>  		case '?':
> -		case 'h': display_help(0); break;
> -		case 'l': max_cycles = atoi(optarg); break;
> -		case 'p': priority = atoi(optarg); break;
> -		case 'q': quiet = 1; break;
> +		case 'h':
> +			display_help(0);
> +			break;
> +		case OPT_LOOPS:
> +		case 'l':
> +			max_cycles = atoi(optarg);
> +			break;
> +		case OPT_OUTPUT:
> +			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
> +			break;
> +		case OPT_PRIORITY:
> +		case 'p':
> +			priority = atoi(optarg);
> +			break;
> +		case OPT_QUIET:
> +		case 'q':
> +			quiet = 1;
> +			break;
> +		case OPT_SMP:
>  		case 'S':
>  			smp = 1;
>  			num_threads = max_cpus;
>  			setaffinity = AFFINITY_USEALL;
>  			break;
> +		case OPT_THREADS:
>  		case 't':
>  			if (smp) {
>  				warn("-t ignored due to --smp\n");
> @@ -316,6 +356,40 @@ static void print_stat(FILE *fp, struct params *receiver, struct params *sender,
>  	}
>  }
>  
> +struct params_stats {
> +	struct params *receiver;
> +	struct params *sender;
> +};
> +
> +static void write_stats(FILE *f, void *data)
> +{
> +	struct params_stats *ps = data;
> +	struct params *s, *r;
> +	unsigned int i;
> +
> +	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
> +	fprintf(f, "  \"thread\": {\n");
> +	for (i = 0; i < num_threads; i++) {
> +		s = &ps->sender[i];
> +		r = &ps->receiver[i];
> +		fprintf(f, "    \"%u\": {\n", i);
> +		fprintf(f, "      \"sender\": {\n");
> +		fprintf(f, "        \"cpu\": %d,\n", s->cpu);
> +		fprintf(f, "        \"priority\": %d,\n", s->priority);
> +		fprintf(f, "        \"samples\": %d,\n", s->samples);
> +		fprintf(f, "        \"interval\": %ld\n", r->delay.tv_nsec/1000);
> +		fprintf(f, "      },\n");
> +		fprintf(f, "      \"receiver\": {\n");
> +		fprintf(f, "        \"cpu\": %d,\n", r->cpu);
> +		fprintf(f, "        \"priority\": %d,\n", r->priority);
> +		fprintf(f, "        \"min\": %d,\n", r->mindiff);
> +		fprintf(f, "        \"avg\": %.2f,\n", r->sumdiff/r->samples);
> +		fprintf(f, "        \"max\": %d\n", r->maxdiff);
> +		fprintf(f, "      }\n");
> +		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
> +	}
> +	fprintf(f, "  }\n");
> +}
>  
>  int main(int argc, char *argv[])
>  {
> @@ -439,6 +513,14 @@ int main(int argc, char *argv[])
>  		pthread_mutex_destroy(&syncmutex[i]);
>  	}
>  
> +	if (strlen(outfile) != 0) {
> +		struct params_stats ps = {
> +			.receiver = receiver,
> +			.sender = sender,
> +		};
> +		rt_write_json(outfile, argc, argv, write_stats, &ps);
> +	}
> +
>  nomem:
>  
>  	return 0;
> -- 
> 2.30.0
> 
> 

Signed-off-by: John Kacur <jkacur@redhat.com>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 09/13] sigwaittest: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 09/13] sigwaittest: " Daniel Wagner
@ 2021-02-17  3:51   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:51 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/signaltest/signaltest.c   |   1 +
>  src/sigwaittest/sigwaittest.c | 117 ++++++++++++++++++++++++++++------
>  2 files changed, 100 insertions(+), 18 deletions(-)
> 
> diff --git a/src/signaltest/signaltest.c b/src/signaltest/signaltest.c
> index 09039b299367..b1a71efdf42f 100644
> --- a/src/signaltest/signaltest.c
> +++ b/src/signaltest/signaltest.c
> @@ -361,6 +361,7 @@ static void write_stats(FILE *f, void *data)
>  	struct thread_stat *s;
>  	unsigned int i;
>  
> +	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
>  	fprintf(f, "  \"thread\": {\n");
>  	for (i = 0; i < num_threads; i++) {
>  		fprintf(f, "    \"%u\": {\n", i);
> diff --git a/src/sigwaittest/sigwaittest.c b/src/sigwaittest/sigwaittest.c
> index f10c24914d4a..0cdf30a6a769 100644
> --- a/src/sigwaittest/sigwaittest.c
> +++ b/src/sigwaittest/sigwaittest.c
> @@ -39,6 +39,7 @@
>  #include <linux/unistd.h>
>  #include <utmpx.h>
>  #include <pthread.h>
> +#include <inttypes.h>
>  
>  #include "rt-utils.h"
>  #include "rt-get_cpu.h"
> @@ -220,6 +221,7 @@ static void display_help(int error)
>  	       "-f [OPT] --fork[=OPT]      fork new processes instead of creating threads\n"
>  	       "-i INTV  --interval=INTV   base interval of thread in us default=1000\n"
>  	       "-l LOOPS --loops=LOOPS     number of loops: default=0(endless)\n"
> +	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
>  	       "-p PRIO  --prio=PRIO       priority\n"
>  	       "-q       --quiet           print a summary only on exit\n"
>  	       "-t       --threads         one thread per available processor\n"
> @@ -240,6 +242,13 @@ static int duration;
>  static int interval = 1000;
>  static int distance = 500;
>  static int quiet;
> +static char outfile[MAX_PATH];
> +
> +enum option_value {
> +	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_DISTANCE, OPT_DURATION,
> +	OPT_FORK, OPT_HELP, OPT_INTERVAL, OPT_LOOPS, OPT_OUTPUT,
> +	OPT_PRIORITY, OPT_QUIET, OPT_THREADS
> +};
>  
>  static void process_options(int argc, char *argv[])
>  {
> @@ -251,17 +260,18 @@ static void process_options(int argc, char *argv[])
>  		int option_index = 0;
>  		/** Options for getopt */
>  		static struct option long_options[] = {
> -			{"affinity",		optional_argument,	NULL, 'a'},
> -			{"breaktrace",		required_argument,	NULL, 'b'},
> -			{"distance",		required_argument,	NULL, 'd'},
> -			{"duration",		required_argument,	NULL, 'D'},
> -			{"fork",		optional_argument,	NULL, 'f'},
> -			{"help",		no_argument,		NULL, 'h'},
> -			{"interval",		required_argument,	NULL, 'i'},
> -			{"loops",		required_argument,	NULL, 'l'},
> -			{"priority",		required_argument,	NULL, 'p'},
> -			{"quiet",		no_argument,		NULL, 'q'},
> -			{"threads",		optional_argument,	NULL, 't'},
> +			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
> +			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
> +			{"distance",	required_argument,	NULL, OPT_DISTANCE},
> +			{"duration",	required_argument,	NULL, OPT_DURATION},
> +			{"fork",	optional_argument,	NULL, OPT_FORK},
> +			{"help",	no_argument,		NULL, OPT_HELP},
> +			{"interval",	required_argument,	NULL, OPT_INTERVAL},
> +			{"loops",	required_argument,	NULL, OPT_LOOPS},
> +			{"output",	required_argument,      NULL, OPT_OUTPUT },
> +			{"priority",	required_argument,	NULL, OPT_PRIORITY},
> +			{"quiet",	no_argument,		NULL, OPT_QUIET},
> +			{"threads",	optional_argument,	NULL, OPT_THREADS},
>  			{NULL, 0, NULL, 0}
>  		};
>  		int c = getopt_long (argc, argv, "a::b:d:D:f::hi:l:p:qt::",
> @@ -269,6 +279,7 @@ static void process_options(int argc, char *argv[])
>  		if (c == -1)
>  			break;
>  		switch (c) {
> +		case OPT_AFFINITY:
>  		case 'a':
>  			if (optarg != NULL) {
>  				affinity = atoi(optarg);
> @@ -280,9 +291,19 @@ static void process_options(int argc, char *argv[])
>  				setaffinity = AFFINITY_USEALL;
>  			}
>  			break;
> -		case 'b': thistracelimit = atoi(optarg); break;
> -		case 'd': distance = atoi(optarg); break;
> -		case 'D': duration = parse_time_string(optarg); break;
> +		case OPT_BREAKTRACE:
> +		case 'b':
> +			thistracelimit = atoi(optarg);
> +			break;
> +		case OPT_DISTANCE:
> +		case 'd':
> +			distance = atoi(optarg);
> +			break;
> +		case OPT_DURATION:
> +		case 'D':
> +			duration = parse_time_string(optarg);
> +			break;
> +		case OPT_FORK:
>  		case 'f':
>  			if (optarg != NULL) {
>  				wasforked = 1;
> @@ -294,14 +315,31 @@ static void process_options(int argc, char *argv[])
>  			} else
>  				mustfork = 1;
>  			break;
> +		case OPT_HELP:
>  		case '?':
>  		case 'h':
>  			display_help(0);
>  			break;
> -		case 'i': interval = atoi(optarg); break;
> -		case 'l': max_cycles = atoi(optarg); break;
> -		case 'p': priority = atoi(optarg); break;
> -		case 'q': quiet = 1; break;
> +		case OPT_INTERVAL:
> +		case 'i':
> +			interval = atoi(optarg);
> +			break;
> +		case OPT_LOOPS:
> +		case 'l':
> +			max_cycles = atoi(optarg);
> +			break;
> +		case OPT_OUTPUT:
> +			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
> +			break;
> +		case OPT_PRIORITY:
> +		case 'p':
> +			priority = atoi(optarg);
> +			break;
> +		case OPT_QUIET:
> +		case 'q':
> +			quiet = 1;
> +			break;
> +		case OPT_THREADS:
>  		case 't':
>  			if (optarg != NULL)
>  				num_threads = atoi(optarg);
> @@ -388,6 +426,41 @@ static void print_stat(FILE *fp, struct params *receiver, struct params *sender,
>  	}
>  }
>  
> +struct params_stats {
> +	struct params *receiver;
> +	struct params *sender;
> +};
> +
> +static void write_stats(FILE *f, void *data)
> +{
> +	struct params_stats *ps = data;
> +	struct params *s, *r;
> +	unsigned int i;
> +
> +	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
> +	fprintf(f, "  \"thread\": {\n");
> +	for (i = 0; i < num_threads; i++) {
> +		s = &ps->sender[i];
> +		r = &ps->receiver[i];
> +		fprintf(f, "    \"%u\": {\n", i);
> +		fprintf(f, "      \"sender\": {\n");
> +		fprintf(f, "        \"cpu\": %d,\n", s->cpu);
> +		fprintf(f, "        \"priority\": %d,\n", s->priority);
> +		fprintf(f, "        \"samples\": %d,\n", s->samples);
> +		fprintf(f, "        \"interval\": %ld\n", r->delay.tv_nsec/1000);
> +		fprintf(f, "      },\n");
> +		fprintf(f, "      \"receiver\": {\n");
> +		fprintf(f, "        \"cpu\": %d,\n", r->cpu);
> +		fprintf(f, "        \"priority\": %d,\n", r->priority);
> +		fprintf(f, "        \"min\": %d,\n", r->mindiff);
> +		fprintf(f, "        \"avg\": %.2f,\n", r->sumdiff/r->samples);
> +		fprintf(f, "        \"max\": %d\n", r->maxdiff);
> +		fprintf(f, "      }\n");
> +		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
> +	}
> +	fprintf(f, "  }\n");
> +}
> +
>  int main(int argc, char *argv[])
>  {
>  	int i, totalsize = 0;
> @@ -627,6 +700,14 @@ int main(int argc, char *argv[])
>  		}
>  	}
>  
> +	if (strlen(outfile) != 0) {
> +		struct params_stats ps = {
> +			.receiver = receiver,
> +			.sender = sender,
> +		};
> +		rt_write_json(outfile, argc, argv, write_stats, &ps);
> +	}
> +
>  nomem:
>  	if (mustfork) {
>  		munmap(param, totalsize);
> -- 
> 2.30.0
> 
> 

Doesn't apply

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 10/13] svsematest: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 10/13] svsematest: " Daniel Wagner
@ 2021-02-17  3:51   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:51 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/svsematest/svsematest.c | 124 ++++++++++++++++++++++++++++++------
>  1 file changed, 104 insertions(+), 20 deletions(-)
> 
> diff --git a/src/svsematest/svsematest.c b/src/svsematest/svsematest.c
> index 7a298e0dea8c..23f84bcbd3dc 100644
> --- a/src/svsematest/svsematest.c
> +++ b/src/svsematest/svsematest.c
> @@ -20,6 +20,7 @@
>  #include <string.h>
>  #include <time.h>
>  #include <utmpx.h>
> +#include <inttypes.h>
>  
>  #include <linux/unistd.h>
>  
> @@ -233,6 +234,7 @@ static void display_help(int error)
>  	       "-f [OPT] --fork[=OPT]      fork new processes instead of creating threads\n"
>  	       "-i INTV  --interval=INTV   base interval of thread in us default=1000\n"
>  	       "-l LOOPS --loops=LOOPS     number of loops: default=0(endless)\n"
> +	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
>  	       "-p PRIO  --prio=PRIO       priority\n"
>  	       "-S       --smp             SMP testing: options -a -t and same priority\n"
>  	       "                           of all threads\n"
> @@ -255,6 +257,13 @@ static int distance = 500;
>  static int smp;
>  static int sameprio;
>  static int quiet;
> +static char outfile[MAX_PATH];
> +
> +enum option_value {
> +	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_DISTANCE, OPT_DURATION,
> +	OPT_FORK, OPT_HELP, OPT_INTERVAL, OPT_LOOPS, OPT_OUTPUT,
> +	OPT_PRIORITY, OPT_QUIET, OPT_SMP, OPT_THREADS
> +};
>  
>  static void process_options(int argc, char *argv[])
>  {
> @@ -266,18 +275,19 @@ static void process_options(int argc, char *argv[])
>  		int option_index = 0;
>  		/** Options for getopt */
>  		static struct option long_options[] = {
> -			{"affinity",		optional_argument,	NULL, 'a'},
> -			{"breaktrace",		required_argument,	NULL, 'b'},
> -			{"distance",		required_argument,	NULL, 'd'},
> -			{"duration",		required_argument,	NULL, 'D'},
> -			{"fork",		optional_argument,	NULL, 'f'},
> -			{"help",		no_argument,		NULL, 'h'},
> -			{"interval",		required_argument,	NULL, 'i'},
> -			{"loops",		required_argument,	NULL, 'l'},
> -			{"priority",		required_argument,	NULL, 'p'},
> -			{"quiet",		no_argument,		NULL, 'q'},
> -			{"smp",			no_argument,		NULL, 'S'},
> -			{"threads",		optional_argument,	NULL, 't'},
> +			{"affinity",	optional_argument,	NULL, OPT_AFFINITY},
> +			{"breaktrace",	required_argument,	NULL, OPT_BREAKTRACE},
> +			{"distance",	required_argument,	NULL, OPT_DISTANCE},
> +			{"duration",	required_argument,	NULL, OPT_DURATION},
> +			{"fork",	optional_argument,	NULL, OPT_FORK},
> +			{"help",	no_argument,		NULL, OPT_HELP},
> +			{"interval",	required_argument,	NULL, OPT_INTERVAL},
> +			{"loops",	required_argument,	NULL, OPT_LOOPS},
> +			{"output",	required_argument,      NULL, OPT_OUTPUT},
> +			{"priority",	required_argument,	NULL, OPT_PRIORITY},
> +			{"quiet",	no_argument,		NULL, OPT_QUIET},
> +			{"smp",		no_argument,		NULL, OPT_SMP},
> +			{"threads",	optional_argument,	NULL, OPT_THREADS},
>  			{NULL, 0, NULL, 0}
>  		};
>  		int c = getopt_long (argc, argv, "a::b:d:D:f::hi:l:p:qSt::",
> @@ -285,6 +295,7 @@ static void process_options(int argc, char *argv[])
>  		if (c == -1)
>  			break;
>  		switch (c) {
> +		case OPT_AFFINITY:
>  		case 'a':
>  			if (smp) {
>  				warn("-a ignored due to --smp\n");
> @@ -300,9 +311,19 @@ static void process_options(int argc, char *argv[])
>  				setaffinity = AFFINITY_USEALL;
>  			}
>  			break;
> -		case 'b': thistracelimit = atoi(optarg); break;
> -		case 'd': distance = atoi(optarg); break;
> -		case 'D': duration = parse_time_string(optarg); break;
> +		case OPT_BREAKTRACE:
> +		case 'b':
> +			thistracelimit = atoi(optarg);
> +			break;
> +		case OPT_DISTANCE:
> +		case 'd':
> +			distance = atoi(optarg);
> +			break;
> +		case OPT_DURATION:
> +		case 'D':
> +			duration = parse_time_string(optarg);
> +			break;
> +		case OPT_FORK:
>  		case 'f':
>  			if (optarg != NULL) {
>  				wasforked = 1;
> @@ -314,16 +335,36 @@ static void process_options(int argc, char *argv[])
>  			} else
>  				mustfork = 1;
>  			break;
> -		case 'h': display_help(0); break;
> -		case 'i': interval = atoi(optarg); break;
> -		case 'l': max_cycles = atoi(optarg); break;
> -		case 'p': priority = atoi(optarg); break;
> -		case 'q': quiet = 1; break;
> +		case OPT_HELP:
> +		case 'h':
> +			display_help(0);
> +			break;
> +		case OPT_INTERVAL:
> +		case 'i':
> +			interval = atoi(optarg);
> +			break;
> +		case OPT_LOOPS:
> +		case 'l':
> +			max_cycles = atoi(optarg);
> +			break;
> +		case OPT_OUTPUT:
> +			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
> +			break;
> +		case OPT_PRIORITY:
> +		case 'p':
> +			priority = atoi(optarg);
> +			break;
> +		case OPT_QUIET:
> +		case 'q':
> +			quiet = 1;
> +			break;
> +		case OPT_SMP:
>  		case 'S':
>  			smp = 1;
>  			num_threads = max_cpus;
>  			setaffinity = AFFINITY_USEALL;
>  			break;
> +		case OPT_THREADS:
>  		case 't':
>  			if (smp) {
>  				warn("-t ignored due to --smp\n");
> @@ -380,6 +421,41 @@ static void sighand(int sig)
>  	mustshutdown = 1;
>  }
>  
> +struct params_stats {
> +	struct params *receiver;
> +	struct params *sender;
> +};
> +
> +static void write_stats(FILE *f, void *data)
> +{
> +	struct params_stats *ps = data;
> +	struct params *s, *r;
> +	unsigned int i;
> +
> +	fprintf(f, "  \"num_threads\": %d,\n", num_threads);
> +	fprintf(f, "  \"thread\": {\n");
> +	for (i = 0; i < num_threads; i++) {
> +		s = &ps->sender[i];
> +		r = &ps->receiver[i];
> +		fprintf(f, "    \"%u\": {\n", i);
> +		fprintf(f, "      \"sender\": {\n");
> +		fprintf(f, "        \"cpu\": %d,\n", s->cpu);
> +		fprintf(f, "        \"priority\": %d,\n", s->priority);
> +		fprintf(f, "        \"samples\": %d,\n", s->samples);
> +		fprintf(f, "        \"interval\": %ld\n", r->delay.tv_nsec/1000);
> +		fprintf(f, "      },\n");
> +		fprintf(f, "      \"receiver\": {\n");
> +		fprintf(f, "        \"cpu\": %d,\n", r->cpu);
> +		fprintf(f, "        \"priority\": %d,\n", r->priority);
> +		fprintf(f, "        \"min\": %d,\n", r->mindiff);
> +		fprintf(f, "        \"avg\": %.2f,\n", r->sumdiff/r->samples);
> +		fprintf(f, "        \"max\": %d\n", r->maxdiff);
> +		fprintf(f, "      }\n");
> +		fprintf(f, "    }%s\n", i == num_threads - 1 ? "" : ",");
> +	}
> +	fprintf(f, "  }\n");
> +}
> +
>  static void print_stat(FILE *fp, struct params *receiver, struct params *sender,
>  		       int verbose, int quiet)
>  {
> @@ -696,6 +772,14 @@ int main(int argc, char *argv[])
>  		}
>  	}
>  
> +	if (strlen(outfile) != 0) {
> +		struct params_stats ps = {
> +			.receiver = receiver,
> +			.sender = sender,
> +		};
> +		rt_write_json(outfile, argc, argv, write_stats, &ps);
> +	}
> +
>  nosem:
>  	for (i = 0; i < num_threads; i++)
>  		semctl(receiver[i].semid, -1, IPC_RMID);
> -- 
> 2.30.0
> 
> 

Signed-off-by: John Kacur <jkacur@redhat.com>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 11/13] oslat: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 11/13] oslat: " Daniel Wagner
@ 2021-02-17  3:51   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:51 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/oslat/oslat.c | 97 +++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 82 insertions(+), 15 deletions(-)
> 
> diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c
> index 9e6f70600830..987f2002985d 100644
> --- a/src/oslat/oslat.c
> +++ b/src/oslat/oslat.c
> @@ -29,7 +29,7 @@
>  #include <numa.h>
>  #include <math.h>
>  #include <limits.h>
> -#include <linux/unistd.h>
> +#include <inttypes.h>
>  
>  #include <sys/prctl.h>
>  #include <sys/stat.h>
> @@ -41,6 +41,8 @@
>  #include <sys/mman.h>
>  #include <sys/syscall.h>
>  
> +#include <linux/unistd.h>
> +
>  #include "rt-utils.h"
>  #include "rt-numa.h"
>  #include "rt-error.h"
> @@ -171,6 +173,7 @@ struct global {
>  	uint64_t              bias;
>  	int                   single_preheat_thread;
>  	int                   output_omit_zero_buckets;
> +	char                  outfile[MAX_PATH];
>  
>  	/* Mutable state. */
>  	volatile enum command cmd;
> @@ -479,6 +482,39 @@ static void write_summary(struct thread *t)
>  	printf("\n");
>  }
>  
> +static void write_summary_json(FILE *f, void *data)
> +{
> +	struct thread *t = data;
> +	int i, j, comma;
> +
> +	fprintf(f, "  \"num_threads\": %d,\n", g.n_threads);
> +	fprintf(f, "  \"thread\": {\n");
> +	for (i = 0; i < g.n_threads; ++i) {
> +		fprintf(f, "    \"%u\": {\n", i);
> +		fprintf(f, "      \"cpu\": %d,\n", t[i].core_i);
> +		fprintf(f, "      \"freq\": %d,\n", t[i].cpu_mhz);
> +		fprintf(f, "      \"min\": %" PRIu64 ",\n", t[i].minlat);
> +		fprintf(f, "      \"avg\": %3lf,\n", t[i].average);
> +		fprintf(f, "      \"max\": %" PRIu64 ",\n", t[i].maxlat);
> +		fprintf(f, "      \"duration\": %.3f,\n",
> +			cycles_to_sec(&(t[i]), t[i].runtime));
> +		fprintf(f, "      \"histogram\": {");
> +		for (j = 0, comma = 0; j < g.bucket_size; j++) {
> +			if (t[i].buckets[j] == 0)
> +				continue;
> +			fprintf(f, "%s", comma ? ",\n" : "\n");
> +			fprintf(f, "        \"%" PRIu64 "\": %" PRIu64,
> +				g.bias+j+1, t[i].buckets[j]);
> +			comma = 1;
> +		}
> +		if (comma)
> +			fprintf(f, "\n");
> +		fprintf(f, "      }\n");
> +		fprintf(f, "    }%s\n", i == g.n_threads - 1 ? "" : ",");
> +	}
> +	fprintf(f, "  }\n");
> +}
> +
>  static void run_expt(struct thread *threads, int runtime_secs)
>  {
>  	int i;
> @@ -533,6 +569,7 @@ static void usage(int error)
>  	       "                       NOTE: please make sure the CPU frequency on all testing cores\n"
>  	       "                       are locked before using this parmater.  If you don't know how\n"
>  	       "                       to lock the freq then please don't use this parameter.\n"
> +	       "    --output=FILENAME  write final results into FILENAME, JSON formatted\n"
>  	       "-T, --trace-threshold  Stop the test when threshold triggered (in us),\n"
>  	       "                       print a marker in ftrace and stop ftrace too.\n"
>  	       "-v, --version          Display the version of the software.\n"
> @@ -557,34 +594,45 @@ static int workload_select(char *name)
>  	return -1;
>  }
>  
> +enum option_value {
> +	OPT_BUCKETSIZE=1, OPT_CPU_LIST, OPT_CPU_MAIN_THREAD,
> +	OPT_DURATION, OPT_RT_PRIO, OPT_HELP, OPT_TRACE_TH,
> +	OPT_WORKLOAD, OPT_WORKLOAD_MEM, OPT_BIAS, OPT_OUTPUT,
> +	OPT_SINGLE_PREHEAT, OPT_ZERO_OMIT, OPT_VERSION
> +
> +};
> +
>  /* Process commandline options */
>  static void parse_options(int argc, char *argv[])
>  {
>  	while (1) {
> +		int option_index = 0;
>  		static struct option options[] = {
> -			{ "bucket-size", required_argument, NULL, 'b' },
> -			{ "cpu-list", required_argument, NULL, 'c' },
> -			{ "cpu-main-thread", required_argument, NULL, 'C'},
> -			{ "duration", required_argument, NULL, 'D' },
> -			{ "rtprio", required_argument, NULL, 'f' },
> -			{ "help", no_argument, NULL, 'h' },
> -			{ "trace-threshold", required_argument, NULL, 'T' },
> -			{ "workload", required_argument, NULL, 'w'},
> -			{ "workload-mem", required_argument, NULL, 'm'},
> -			{ "bias", no_argument, NULL, 'B'},
> -			{ "single-preheat", no_argument, NULL, 's'},
> -			{ "zero-omit", no_argument, NULL, 'u'},
> -			{ "version", no_argument, NULL, 'v'},
> +			{ "bucket-size",required_argument,	NULL, OPT_BUCKETSIZE },
> +			{ "cpu-list",	required_argument,	NULL, OPT_CPU_LIST },
> +			{ "cpu-main-thread", required_argument, NULL, OPT_CPU_MAIN_THREAD},
> +			{ "duration",	required_argument,	NULL, OPT_DURATION },
> +			{ "rtprio",	required_argument,	NULL, OPT_RT_PRIO },
> +			{ "help",	no_argument,		NULL, OPT_HELP },
> +			{ "trace-threshold", required_argument,	NULL, OPT_TRACE_TH },
> +			{ "workload",	required_argument,	NULL, OPT_WORKLOAD },
> +			{ "workload-mem", required_argument,	NULL, OPT_WORKLOAD_MEM },
> +			{ "bias",	no_argument,		NULL, OPT_BIAS },
> +			{ "single-preheat", no_argument,	NULL, OPT_SINGLE_PREHEAT },
> +			{ "output",	required_argument,      NULL, OPT_OUTPUT },
> +			{ "zero-omit",	no_argument,		NULL, OPT_ZERO_OMIT },
> +			{ "version",	no_argument,		NULL, OPT_VERSION },
>  			{ NULL, 0, NULL, 0 },
>  		};
>  		int i, c = getopt_long(argc, argv, "b:Bc:C:D:f:hm:sw:T:vz",
> -				       options, NULL);
> +				       options, &option_index);
>  		long ncores;
>  
>  		if (c == -1)
>  			break;
>  
>  		switch (c) {
> +		case OPT_BUCKETSIZE:
>  		case 'b':
>  			g.bucket_size = strtol(optarg, NULL, 10);
>  			if (g.bucket_size > 1024 || g.bucket_size <= 4) {
> @@ -593,12 +641,15 @@ static void parse_options(int argc, char *argv[])
>  				exit(1);
>  			}
>  			break;
> +		case OPT_BIAS:
>  		case 'B':
>  			g.enable_bias = 1;
>  			break;
> +		case OPT_CPU_LIST:
>  		case 'c':
>  			g.cpu_list = strdup(optarg);
>  			break;
> +		case OPT_CPU_MAIN_THREAD:
>  		case 'C':
>  			ncores = sysconf(_SC_NPROCESSORS_CONF);
>  			g.cpu_main_thread = strtol(optarg, NULL, 10);
> @@ -608,6 +659,7 @@ static void parse_options(int argc, char *argv[])
>  				exit(1);
>  			}
>  			break;
> +		case OPT_DURATION:
>  		case 'D':
>  			g.runtime = parse_time_string(optarg);
>  			if (!g.runtime) {
> @@ -615,6 +667,7 @@ static void parse_options(int argc, char *argv[])
>  				exit(1);
>  			}
>  			break;
> +		case OPT_RT_PRIO:
>  		case 'f':
>  			g.rtprio = strtol(optarg, NULL, 10);
>  			if (g.rtprio < 1 || g.rtprio > 99) {
> @@ -622,6 +675,10 @@ static void parse_options(int argc, char *argv[])
>  				exit(1);
>  			}
>  			break;
> +		case OPT_OUTPUT:
> +			strncpy(g.outfile, optarg, strnlen(optarg, MAX_PATH-1));
> +			break;
> +		case OPT_TRACE_TH:
>  		case 'T':
>  			g.trace_threshold = strtol(optarg, NULL, 10);
>  			if (g.trace_threshold <= 0) {
> @@ -630,6 +687,7 @@ static void parse_options(int argc, char *argv[])
>  			}
>  			enable_trace_mark();
>  			break;
> +		case OPT_WORKLOAD:
>  		case 'w':
>  			if (workload_select(optarg)) {
>  				printf("Unknown workload '%s'.  Please choose from: ", optarg);
> @@ -642,12 +700,14 @@ static void parse_options(int argc, char *argv[])
>  				exit(1);
>  			}
>  			break;
> +		case OPT_WORKLOAD_MEM:
>  		case 'm':
>  			if (parse_mem_string(optarg, &g.workload_mem_size)) {
>  				printf("Unknown workload memory size '%s'.\n\n", optarg);
>  				exit(1);
>  			}
>  			break;
> +		case OPT_SINGLE_PREHEAT:
>  		case 's':
>  			/*
>  			 * Only use one core for pre-heat.  Then if --bias is used, the
> @@ -655,6 +715,7 @@ static void parse_options(int argc, char *argv[])
>  			 */
>  			g.single_preheat_thread = true;
>  			break;
> +		case OPT_VERSION:
>  		case 'v':
>  			/*
>  			 * Because we always dump the version even before parsing options,
> @@ -662,9 +723,11 @@ static void parse_options(int argc, char *argv[])
>  			 */
>  			exit(0);
>  			break;
> +		case OPT_ZERO_OMIT:
>  		case 'z':
>  			g.output_omit_zero_buckets = 1;
>  			break;
> +		case OPT_HELP:
>  		case 'h':
>  			usage(0);
>  			break;
> @@ -781,6 +844,10 @@ int main(int argc, char *argv[])
>  
>  	write_summary(threads);
>  
> +	if (strlen(g.outfile) != 0)
> +		rt_write_json(g.outfile, argc, argv,
> +			write_summary_json, threads);
> +
>  	if (g.cpu_list) {
>  		free(g.cpu_list);
>  		g.cpu_list = NULL;
> -- 
> 2.30.0
> 
> 

    - Added a space after a common parse_options
    Signed-off-by: John Kacur <jkacur@redhat.com>


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 12/13] rt-migrate-test: Add JSON output feature
  2021-02-10 17:51 ` [PATCH rt-tests v5 12/13] rt-migrate-test: " Daniel Wagner
@ 2021-02-17  3:52   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:52 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Write the test results as JSON output to a file. This allows to
> simplifies any parsing later on.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/rt-migrate-test/rt-migrate-test.c | 120 ++++++++++++++++++++++----
>  1 file changed, 101 insertions(+), 19 deletions(-)
> 
> diff --git a/src/rt-migrate-test/rt-migrate-test.c b/src/rt-migrate-test/rt-migrate-test.c
> index 9bf716c9178c..56b7b66ccdf4 100644
> --- a/src/rt-migrate-test/rt-migrate-test.c
> +++ b/src/rt-migrate-test/rt-migrate-test.c
> @@ -19,11 +19,14 @@
>  #include <fcntl.h>
>  #include <signal.h>
>  #include <sys/time.h>
> -#include <linux/unistd.h>
>  #include <sys/syscall.h>
>  #include <errno.h>
>  #include <sched.h>
>  #include <pthread.h>
> +#include <inttypes.h>
> +
> +#include <linux/unistd.h>
> +
>  #include "rt-utils.h"
>  
>  int nr_tasks;
> @@ -99,6 +102,7 @@ static int done;
>  static int loop;
>  static int duration;
>  static int quiet;
> +static char outfile[MAX_PATH];
>  
>  static pthread_barrier_t start_barrier;
>  static pthread_barrier_t end_barrier;
> @@ -160,6 +164,7 @@ static void usage(int error)
>  	       "-h       --help            Print this help message\n"
>  	       "-l LOOPS --loops=LOOPS     Number of iterations to run (50)\n"
>  	       "-m TIME  --maxerr=TIME     Max allowed error (microsecs)\n"
> +	       "         --output=FILENAME write final results into FILENAME, JSON formatted\n"
>  	       "-p PRIO  --prio=PRIO       base priority to start RT tasks with (2)\n"
>  	       "-q       --quiet           print a summary only on exit\n"
>  	       "-r TIME  --run-time=TIME   Run time (ms) to busy loop the threads (20)\n"
> @@ -169,22 +174,29 @@ static void usage(int error)
>  	exit(error);
>  }
>  
> +enum option_value {
> +	OPT_CHECK=1, OPT_DURATION, OPT_EQUAL, OPT_HELP, OPT_LOOPS,
> +	OPT_MAXERR, OPT_OUTPUT, OPT_PRIO, OPT_QUIET, OPT_RUN_TIME,
> +	OPT_SLEEP_TIME
> +};
> +
>  static void parse_options(int argc, char *argv[])
>  {
>  	for (;;) {
>  		int option_index = 0;
>  		/** Options for getopt */
>  		static struct option long_options[] = {
> -			{"check",	no_argument,		NULL, 'c'},
> -			{"duration",	required_argument,	NULL, 'D'},
> -			{"equal",	no_argument,		NULL, 'e'},
> -			{"help",	no_argument,		NULL, 'h'},
> -			{"loops",	required_argument,	NULL, 'l'},
> -			{"maxerr",	required_argument,	NULL, 'm'},
> -			{"prio",	required_argument,	NULL, 'p'},
> -			{"quiet",	no_argument,		NULL, 'q'},
> -			{"run-time",	required_argument,	NULL, 'r'},
> -			{"sleep-time",	required_argument,	NULL, 's'},
> +			{"check",	no_argument,		NULL, OPT_CHECK},
> +			{"duration",	required_argument,	NULL, OPT_DURATION},
> +			{"equal",	no_argument,		NULL, OPT_EQUAL},
> +			{"help",	no_argument,		NULL, OPT_HELP},
> +			{"loops",	required_argument,	NULL, OPT_LOOPS},
> +			{"maxerr",	required_argument,	NULL, OPT_MAXERR},
> +			{"output",	required_argument,      NULL, OPT_OUTPUT },
> +			{"prio",	required_argument,	NULL, OPT_PRIO},
> +			{"quiet",	no_argument,		NULL, OPT_QUIET},
> +			{"run-time",	required_argument,	NULL, OPT_RUN_TIME},
> +			{"sleep-time",	required_argument,	NULL, OPT_SLEEP_TIME},
>  			{NULL, 0, NULL, 0}
>  		};
>  		int c = getopt_long(argc, argv, "cD:ehl:m:p:qr:s:",
> @@ -192,21 +204,50 @@ static void parse_options(int argc, char *argv[])
>  		if (c == -1)
>  			break;
>  		switch (c) {
> -		case 'c': check = 1; break;
> -		case 'D': duration = parse_time_string(optarg); break;
> -		case 'e': equal = 1; break;
> +		case OPT_CHECK:
> +		case 'c':
> +			check = 1;
> +			break;
> +		case OPT_DURATION:
> +		case 'D':
> +			duration = parse_time_string(optarg);
> +			break;
> +		case OPT_EQUAL:
> +		case 'e':
> +			equal = 1;
> +			break;
> +		case OPT_HELP:
>  		case '?':
>  		case 'h':
>  			usage(0);
>  			break;
> -		case 'l': nr_runs = atoi(optarg); break;
> -		case 'm': max_err = usec2nano(atoi(optarg)); break;
> -		case 'p': prio_start = atoi(optarg); break;
> -		case 'q': quiet = 1; break;
> +		case OPT_LOOPS:
> +		case 'l':
> +			nr_runs = atoi(optarg);
> +			break;
> +		case OPT_MAXERR:
> +		case 'm':
> +			max_err = usec2nano(atoi(optarg));
> +			break;
> +		case OPT_OUTPUT:
> +			strncpy(outfile, optarg, strnlen(optarg, MAX_PATH-1));
> +			break;
> +		case OPT_PRIO:
> +		case 'p':
> +			prio_start = atoi(optarg);
> +			break;
> +		case OPT_QUIET:
> +		case 'q':
> +			quiet = 1;
> +			break;
> +		case OPT_RUN_TIME:
>  		case 'r':
>  			run_interval = atoi(optarg);
>  			break;
> -		case 's': interval = atoi(optarg); break;
> +		case OPT_SLEEP_TIME:
> +		case 's':
> +			interval = atoi(optarg);
> +			break;
>  		default:
>  			usage(1);
>  		}
> @@ -313,6 +354,44 @@ static void print_results(void)
>  	}
>  }
>  
> +static void write_stats(FILE *f, void *data)
> +{
> +	int i;
> +	int t;
> +	unsigned long long tasks_max[nr_tasks];
> +	unsigned long long tasks_min[nr_tasks];
> +	unsigned long long tasks_avg[nr_tasks];
> +
> +	memset(tasks_max, 0, sizeof(tasks_max[0])*nr_tasks);
> +	memset(tasks_min, 0xff, sizeof(tasks_min[0])*nr_tasks);
> +	memset(tasks_avg, 0, sizeof(tasks_avg[0])*nr_tasks);
> +
> +	for (i=0; i < nr_runs; i++) {
> +		for (t=0; t < nr_tasks; t++) {
> +			unsigned long long itv = intervals[i][t];
> +
> +			if (tasks_max[t] < itv)
> +				tasks_max[t] = itv;
> +			if (tasks_min[t] > itv)
> +				tasks_min[t] = itv;
> +			tasks_avg[t] += itv;
> +		}
> +	}
> +
> +	fprintf(f, "  \"num_threads\": %d,\n", nr_tasks);
> +	fprintf(f, "  \"thread\": {\n");
> +	for (i = 0; i < nr_tasks; i++) {
> +		fprintf(f, "    \"%u\": {\n", i);
> +		fprintf(f, "      \"prio\": %d,\n", calc_prio(i));
> +		fprintf(f, "      \"min\": %lld,\n", nano2usec(tasks_min[i]));
> +		fprintf(f, "      \"avg\": %lld,\n", nano2usec(tasks_avg[i]) / nr_runs);
> +		fprintf(f, "      \"max\": %lld,\n", nano2usec(tasks_max[i]));
> +		fprintf(f, "      \"total\": %lld\n", nano2usec(tasks_avg[i]));
> +		fprintf(f, "    }%s\n", i == nr_tasks - 1 ? "" : ",");
> +	}
> +	fprintf(f, "  }\n");
> +}
> +
>  static unsigned long busy_loop(unsigned long long start_time)
>  {
>  	unsigned long long time;
> @@ -582,6 +661,9 @@ int main (int argc, char **argv)
>  
>  	print_results();
>  
> +	if (strlen(outfile) != 0)
> +		rt_write_json(outfile, argc, argv, write_stats, NULL);
> +
>  	if (stop) {
>  		/*
>  		 * We use this test in bash while loops
> -- 
> 2.30.0
> 
> 

Signed-off-by: John Kacur <jkacur@redhat.com>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 13/13] oslat: Add quiet command line option
  2021-02-10 17:51 ` [PATCH rt-tests v5 13/13] oslat: Add quiet command line option Daniel Wagner
@ 2021-02-17  3:52   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:52 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> The quiet option is useful for automated test setups where
> only the final result of the run is interesting.
> 
> Furthermore, this makes oslat accept rt-tests standard options.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/oslat/oslat.c | 25 ++++++++++++++++++-------
>  1 file changed, 18 insertions(+), 7 deletions(-)
> 
> diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c
> index 987f2002985d..0d9afedbdc82 100644
> --- a/src/oslat/oslat.c
> +++ b/src/oslat/oslat.c
> @@ -171,6 +171,7 @@ struct global {
>  	uint64_t              workload_mem_size;
>  	int                   enable_bias;
>  	uint64_t              bias;
> +	int                   quiet;
>  	int                   single_preheat_thread;
>  	int                   output_omit_zero_buckets;
>  	char                  outfile[MAX_PATH];
> @@ -565,6 +566,7 @@ static void usage(int error)
>  	       "                       Total memory usage will be this value multiplies 2*N,\n"
>  	       "                       because there will be src/dst buffers for each thread, and\n"
>  	       "                       N is the number of processors for testing.\n"
> +	       "-q  --quiet            print a summary only on exit\n"
>  	       "-s, --single-preheat   Use a single thread when measuring latency at preheat stage\n"
>  	       "                       NOTE: please make sure the CPU frequency on all testing cores\n"
>  	       "                       are locked before using this parmater.  If you don't know how\n"
> @@ -598,8 +600,8 @@ enum option_value {
>  	OPT_BUCKETSIZE=1, OPT_CPU_LIST, OPT_CPU_MAIN_THREAD,
>  	OPT_DURATION, OPT_RT_PRIO, OPT_HELP, OPT_TRACE_TH,
>  	OPT_WORKLOAD, OPT_WORKLOAD_MEM, OPT_BIAS, OPT_OUTPUT,
> -	OPT_SINGLE_PREHEAT, OPT_ZERO_OMIT, OPT_VERSION
> -
> +	OPT_QUIET, OPT_SINGLE_PREHEAT, OPT_ZERO_OMIT,
> +	OPT_VERSION
>  };
>  
>  /* Process commandline options */
> @@ -618,13 +620,14 @@ static void parse_options(int argc, char *argv[])
>  			{ "workload",	required_argument,	NULL, OPT_WORKLOAD },
>  			{ "workload-mem", required_argument,	NULL, OPT_WORKLOAD_MEM },
>  			{ "bias",	no_argument,		NULL, OPT_BIAS },
> +			{ "quiet",	no_argument,		NULL, OPT_QUIET },
>  			{ "single-preheat", no_argument,	NULL, OPT_SINGLE_PREHEAT },
>  			{ "output",	required_argument,      NULL, OPT_OUTPUT },
>  			{ "zero-omit",	no_argument,		NULL, OPT_ZERO_OMIT },
>  			{ "version",	no_argument,		NULL, OPT_VERSION },
>  			{ NULL, 0, NULL, 0 },
>  		};
> -		int i, c = getopt_long(argc, argv, "b:Bc:C:D:f:hm:sw:T:vz",
> +		int i, c = getopt_long(argc, argv, "b:Bc:C:D:f:hm:qsw:T:vz",
>  				       options, &option_index);
>  		long ncores;
>  
> @@ -707,6 +710,10 @@ static void parse_options(int argc, char *argv[])
>  				exit(1);
>  			}
>  			break;
> +		case OPT_QUIET:
> +		case 'q':
> +			g.quiet = 1;
> +			break;
>  		case OPT_SINGLE_PREHEAT:
>  		case 's':
>  			/*
> @@ -825,9 +832,11 @@ int main(int argc, char *argv[])
>  	signal(SIGINT, handle_alarm);
>  	signal(SIGTERM, handle_alarm);
>  
> -	dump_globals();
> +	if (!g.quiet)
> +		dump_globals();
>  
> -	printf("Pre-heat for 1 seconds...\n");
> +	if (!g.quiet)
> +		printf("Pre-heat for 1 seconds...\n");
>  	if (g.single_preheat_thread)
>  		g.n_threads = 1;
>  	else
> @@ -835,12 +844,14 @@ int main(int argc, char *argv[])
>  	run_expt(threads, 1);
>  	record_bias(threads);
>  
> -	printf("Test starts...\n");
> +	if (!g.quiet)
> +		printf("Test starts...\n");
>  	/* Reset n_threads to always run on all the cores */
>  	g.n_threads = g.n_threads_total;
>  	run_expt(threads, g.runtime);
>  
> -	printf("Test completed.\n\n");
> +	if (!g.quiet)
> +		printf("Test completed.\n\n");
>  
>  	write_summary(threads);
>  
> -- 
> 2.30.0
> 
> 

Signed-off-by: John Kacur <jkacur@redhat.com>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 01/13] cyclictest: Move thread data to struct thread_param
  2021-02-10 17:51 ` [PATCH rt-tests v5 01/13] cyclictest: Move thread data to struct thread_param Daniel Wagner
@ 2021-02-17  3:52   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:52 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Group thread realated data such as thread ID to struct thread_param.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/cyclictest/cyclictest.c | 34 +++++++++++++++++-----------------
>  1 file changed, 17 insertions(+), 17 deletions(-)
> 
> diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
> index c4b2369bee6b..7c45732c1553 100644
> --- a/src/cyclictest/cyclictest.c
> +++ b/src/cyclictest/cyclictest.c
> @@ -113,6 +113,9 @@ static char *policyname(int policy);
>  
>  /* Struct to transfer parameters to the thread */
>  struct thread_param {
> +	pthread_t thread;
> +	int threadstarted;
> +	int tid;
>  	int prio;
>  	int policy;
>  	int mode;
> @@ -141,9 +144,6 @@ struct thread_stat {
>  	long *smis;
>  	long *hist_array;
>  	long *outliers;
> -	pthread_t thread;
> -	int threadstarted;
> -	int tid;
>  	long reduce;
>  	long redmax;
>  	long cycleofmax;
> @@ -530,7 +530,7 @@ static void *timerthread(void *param)
>  	interval.tv_sec = par->interval / USEC_PER_SEC;
>  	interval.tv_nsec = (par->interval % USEC_PER_SEC) * 1000;
>  
> -	stat->tid = gettid();
> +	par->tid = gettid();
>  
>  	sigemptyset(&sigset);
>  	sigaddset(&sigset, par->signal);
> @@ -539,7 +539,7 @@ static void *timerthread(void *param)
>  	if (par->mode == MODE_CYCLIC) {
>  		sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
>  		sigev.sigev_signo = par->signal;
> -		sigev.sigev_notify_thread_id = stat->tid;
> +		sigev.sigev_notify_thread_id = par->tid;
>  		timer_create(par->clock, &sigev, &timer);
>  		tspec.it_interval = interval;
>  	}
> @@ -613,7 +613,7 @@ static void *timerthread(void *param)
>  		setitimer(ITIMER_REAL, &itimer, NULL);
>  	}
>  
> -	stat->threadstarted++;
> +	par->threadstarted++;
>  
>  	while (!shutdown) {
>  
> @@ -719,7 +719,7 @@ static void *timerthread(void *param)
>  			shutdown++;
>  			pthread_mutex_lock(&break_thread_id_lock);
>  			if (break_thread_id == 0) {
> -				break_thread_id = stat->tid;
> +				break_thread_id = par->tid;
>  				tracemark("hit latency threshold (%llu > %d)",
>  					  (unsigned long long) diff, tracelimit);
>  				break_thread_value = diff;
> @@ -795,7 +795,7 @@ static void *timerthread(void *param)
>  	/* switch to normal */
>  	schedp.sched_priority = 0;
>  	sched_setscheduler(0, SCHED_OTHER, &schedp);
> -	stat->threadstarted = -1;
> +	par->threadstarted = -1;
>  
>  	return NULL;
>  }
> @@ -1293,7 +1293,7 @@ static void print_tids(struct thread_param *par[], int nthreads)
>  
>  	printf("# Thread Ids:");
>  	for (i = 0; i < nthreads; i++)
> -		printf(" %05d", par[i]->stats->tid);
> +		printf(" %05d", par[i]->tid);
>  	printf("\n");
>  }
>  
> @@ -1407,7 +1407,7 @@ static void print_stat(FILE *fp, struct thread_param *par, int index, int verbos
>  				fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
>  				        "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld";
>  
> -			fprintf(fp, fmt, index, stat->tid, par->prio,
> +			fprintf(fp, fmt, index, par->tid, par->prio,
>  				par->interval, stat->cycles, stat->min,
>  				stat->act, stat->cycles ?
>  				(long)(stat->avg/stat->cycles) : 0, stat->max);
> @@ -1463,7 +1463,7 @@ static void rstat_print_stat(struct thread_param *par, int index, int verbose, i
>  				fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
>  				        "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld";
>  
> -			dprintf(fd, fmt, index, stat->tid, par->prio,
> +			dprintf(fd, fmt, index, par->tid, par->prio,
>  				par->interval, stat->cycles, stat->min,
>  				stat->act, stat->cycles ?
>  				(long)(stat->avg/stat->cycles) : 0, stat->max);
> @@ -1966,9 +1966,9 @@ int main(int argc, char **argv)
>  		stat->min = 1000000;
>  		stat->max = 0;
>  		stat->avg = 0.0;
> -		stat->threadstarted = 1;
>  		stat->smi_count = 0;
> -		status = pthread_create(&stat->thread, &attr, timerthread, par);
> +		par->threadstarted = 1;
> +		status = pthread_create(&par->thread, &attr, timerthread, par);
>  		if (status)
>  			fatal("failed to create thread %d: %s\n", i, strerror(status));
>  
> @@ -2038,10 +2038,10 @@ int main(int argc, char **argv)
>  	if (quiet)
>  		quiet = 2;
>  	for (i = 0; i < num_threads; i++) {
> -		if (statistics[i]->threadstarted > 0)
> -			pthread_kill(statistics[i]->thread, SIGTERM);
> -		if (statistics[i]->threadstarted) {
> -			pthread_join(statistics[i]->thread, NULL);
> +		if (parameters[i]->threadstarted > 0)
> +			pthread_kill(parameters[i]->thread, SIGTERM);
> +		if (parameters[i]->threadstarted) {
> +			pthread_join(parameters[i]->thread, NULL);
>  			if (quiet && !histogram)
>  				print_stat(stdout, parameters[i], i, 0, 0);
>  		}
> -- 
> 2.30.0
> 
> 

Why? I don't see any advantage to this, and according to the comments at 
the top of the struct, thread_param is to transfer params to a thread
and thread_stat is for statistics. This is unnecessary churn, unless
you can convince me otherwise. I was worried that your JSON changes
would rely on this being changed, but as far as I can see, they do not!

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH rt-tests v5 02/13] signaltest: Move thread data to struct thread_param
  2021-02-10 17:51 ` [PATCH rt-tests v5 02/13] signaltest: " Daniel Wagner
@ 2021-02-17  3:52   ` John Kacur
  0 siblings, 0 replies; 27+ messages in thread
From: John Kacur @ 2021-02-17  3:52 UTC (permalink / raw)
  To: Daniel Wagner; +Cc: Clark Williams, linux-rt-users



On Wed, 10 Feb 2021, Daniel Wagner wrote:

> Group thread realated data such as thread ID to struct thread_param.
> 
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> ---
>  src/signaltest/signaltest.c | 44 ++++++++++++++++++-------------------
>  1 file changed, 22 insertions(+), 22 deletions(-)
> 
> diff --git a/src/signaltest/signaltest.c b/src/signaltest/signaltest.c
> index c34bc994d886..dd5633d5fc51 100644
> --- a/src/signaltest/signaltest.c
> +++ b/src/signaltest/signaltest.c
> @@ -40,6 +40,10 @@
>  
>  /* Struct to transfer parameters to the thread */
>  struct thread_param {
> +	pthread_t thread;
> +	pthread_t tothread;
> +	int threadstarted;
> +	int tid;
>  	int id;
>  	int prio;
>  	int signal;
> @@ -47,6 +51,7 @@ struct thread_param {
>  	struct thread_stat *stats;
>  	int bufmsk;
>  	int cpu;
> +	int interrupted;
>  };
>  
>  /* Struct for statistics */
> @@ -58,11 +63,6 @@ struct thread_stat {
>  	long act;
>  	double avg;
>  	long *values;
> -	pthread_t thread;
> -	pthread_t tothread;
> -	int threadstarted;
> -	int tid;
> -	int interrupted;
>  };
>  
>  static int shutdown;
> @@ -86,7 +86,7 @@ void *signalthread(void *param)
>  	pthread_t thread;
>  	cpu_set_t mask;
>  
> -	stat->tid = gettid();
> +	par->tid = gettid();
>  
>  	if (par->cpu != -1) {
>  		CPU_ZERO(&mask);
> @@ -105,7 +105,7 @@ void *signalthread(void *param)
>  	schedp.sched_priority = par->prio;
>  	sched_setscheduler(0, policy, &schedp);
>  
> -	stat->threadstarted++;
> +	par->threadstarted++;
>  
>  	clock_gettime(CLOCK_MONOTONIC, &before);
>  
> @@ -128,7 +128,7 @@ void *signalthread(void *param)
>  
>  		/* Get current time */
>  		clock_gettime(CLOCK_MONOTONIC, &now);
> -		pthread_kill(stat->tothread, SIGUSR1);
> +		pthread_kill(par->tothread, SIGUSR1);
>  
>  		/* Skip the first cycle */
>  		if (first) {
> @@ -148,7 +148,7 @@ void *signalthread(void *param)
>  
>  		if (!stopped && tracelimit && !par->id  && (diff > tracelimit)) {
>  			stat->act = diff;
> -			stat->interrupted = 1;
> +			par->interrupted = 1;
>  			stopped++;
>  			shutdown++;
>  		}
> @@ -167,7 +167,7 @@ void *signalthread(void *param)
>  	schedp.sched_priority = 0;
>  	sched_setscheduler(0, SCHED_OTHER, &schedp);
>  
> -	stat->threadstarted = -1;
> +	par->threadstarted = -1;
>  
>  	return NULL;
>  }
> @@ -298,7 +298,7 @@ static void print_stat(struct thread_param *par, int index, int verbose)
>  		if (quiet != 1) {
>  			printf("T:%2d (%5d) P:%2d C:%7lu "
>  			       "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld\n",
> -			       index, stat->tid, par->prio,
> +			       index, par->tid, par->prio,
>  			       stat->cycles, stat->min, stat->act,
>  			       stat->cycles ?
>  			       (long)(stat->avg/stat->cycles) : 0, stat->max);
> @@ -389,8 +389,8 @@ int main(int argc, char **argv)
>  		stat[i].min = 1000000;
>  		stat[i].max = -1000000;
>  		stat[i].avg = 0.0;
> -		stat[i].threadstarted = 1;
> -		status = pthread_create(&stat[i].thread, NULL, signalthread,
> +		par[i].threadstarted = 1;
> +		status = pthread_create(&par[i].thread, NULL, signalthread,
>  					&par[i]);
>  		if (status)
>  			fatal("failed to create thread %d: %s\n", i,
> @@ -401,18 +401,18 @@ int main(int argc, char **argv)
>  		int allstarted = 1;
>  
>  		for (i = 0; i < num_threads; i++) {
> -			if (stat[i].threadstarted != 2)
> +			if (par[i].threadstarted != 2)
>  				allstarted = 0;
>  		}
>  		if (!allstarted)
>  			continue;
>  
>  		for (i = 0; i < num_threads - 1; i++)
> -			stat[i].tothread = stat[i+1].thread;
> -		stat[i].tothread = stat[0].thread;
> +			par[i].tothread = par[i+1].thread;
> +		par[i].tothread = par[0].thread;
>  		break;
>  	}
> -	pthread_kill(stat[0].thread, signum);
> +	pthread_kill(par[0].thread, signum);
>  
>  	while (!shutdown) {
>  		char lavg[256];
> @@ -443,12 +443,12 @@ int main(int argc, char **argv)
>  	if (quiet)
>  		quiet = 2;
>  	for (i = 0; i < num_threads; i++) {
> -		if (stat[i].threadstarted > 0)
> -			pthread_kill(stat[i].thread, SIGUSR1);
> -		if (stat[i].interrupted)
> +		if (par[i].threadstarted > 0)
> +			pthread_kill(par[i].thread, SIGUSR1);
> +		if (par[i].interrupted)
>  			printf("Thread %d exceeded trace limit.\n", i);
> -		if (stat[i].threadstarted) {
> -			pthread_join(stat[i].thread, NULL);
> +		if (par[i].threadstarted) {
> +			pthread_join(par[i].thread, NULL);
>  			print_stat(&par[i], i, 0);
>  		}
>  		if (stat[i].values)
> -- 
> 2.30.0
> 
> 
No for the same reasons I gave for cyclictest.
Unncessary churn, and it makes backporting fixes harder too.

John

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2021-02-17  3:53 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-10 17:51 [PATCH rt-tests v5 00/13] Generate machine-readable output Daniel Wagner
2021-02-10 17:51 ` [PATCH rt-tests v5 01/13] cyclictest: Move thread data to struct thread_param Daniel Wagner
2021-02-17  3:52   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 02/13] signaltest: " Daniel Wagner
2021-02-17  3:52   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 03/13] rt-utils: Add JSON common header output helper Daniel Wagner
2021-02-17  3:50   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 04/13] cyclictest: Add JSON output feature Daniel Wagner
2021-02-17  3:50   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 05/13] signaltest: " Daniel Wagner
2021-02-17  3:50   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 06/13] cyclicdeadline: " Daniel Wagner
2021-02-17  3:51   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 07/13] pmqtest: " Daniel Wagner
2021-02-17  3:51   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 08/13] ptsematest: " Daniel Wagner
2021-02-17  3:51   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 09/13] sigwaittest: " Daniel Wagner
2021-02-17  3:51   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 10/13] svsematest: " Daniel Wagner
2021-02-17  3:51   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 11/13] oslat: " Daniel Wagner
2021-02-17  3:51   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 12/13] rt-migrate-test: " Daniel Wagner
2021-02-17  3:52   ` John Kacur
2021-02-10 17:51 ` [PATCH rt-tests v5 13/13] oslat: Add quiet command line option Daniel Wagner
2021-02-17  3:52   ` John Kacur

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).