All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 0/6] Generate machine-readable output
@ 2021-01-11 17:33 Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 1/6] rt-tests: Rename error.h to rt-error.h Daniel Wagner
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Daniel Wagner @ 2021-01-11 17:33 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

changes 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

[1] https://github.com/igaw/jitterdebugger/blob/master/jitterplot
[2] https://www.monom.org/data/jitterdebug/jitterplot-hist.png
[3] https://www.monom.org/data/jitterdebug/jitterplot-samples.png

Daniel Wagner (6):
  rt-tests: Rename error.h to rt-error.h
  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

 src/cyclictest/cyclictest.c         |  87 +++++++++++----
 src/include/pip_stress.h            |   5 +-
 src/include/{error.h => rt-error.h} |   0
 src/include/rt-utils.h              |   4 +
 src/lib/error.c                     |   2 +-
 src/lib/rt-numa.c                   |   2 +-
 src/lib/rt-utils.c                  |  61 ++++++++++-
 src/oslat/oslat.c                   |   2 +-
 src/pi_tests/pi_stress.c            |   3 +-
 src/pmqtest/pmqtest.c               |   6 +-
 src/ptsematest/ptsematest.c         |   6 +-
 src/signaltest/signaltest.c         | 159 ++++++++++++++++++++--------
 src/sigwaittest/sigwaittest.c       |   2 +-
 src/svsematest/svsematest.c         |   3 +-
 14 files changed, 263 insertions(+), 79 deletions(-)
 rename src/include/{error.h => rt-error.h} (100%)

-- 
2.29.2


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

* [RFC v2 1/6] rt-tests: Rename error.h to rt-error.h
  2021-01-11 17:33 [RFC v2 0/6] Generate machine-readable output Daniel Wagner
@ 2021-01-11 17:33 ` Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 2/6] cyclictest: Move thread data to struct thread_param Daniel Wagner
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Daniel Wagner @ 2021-01-11 17:33 UTC (permalink / raw)
  To: Clark Williams, John Kacur; +Cc: linux-rt-users, Daniel Wagner

Avoid confusion with the system header called error.h.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
---
 src/cyclictest/cyclictest.c         | 2 +-
 src/include/pip_stress.h            | 5 +++--
 src/include/{error.h => rt-error.h} | 0
 src/lib/error.c                     | 2 +-
 src/lib/rt-numa.c                   | 2 +-
 src/lib/rt-utils.c                  | 3 ++-
 src/oslat/oslat.c                   | 2 +-
 src/pi_tests/pi_stress.c            | 3 +--
 src/pmqtest/pmqtest.c               | 6 +++---
 src/ptsematest/ptsematest.c         | 6 +++---
 src/signaltest/signaltest.c         | 2 +-
 src/sigwaittest/sigwaittest.c       | 2 +-
 src/svsematest/svsematest.c         | 3 ++-
 13 files changed, 20 insertions(+), 18 deletions(-)
 rename src/include/{error.h => rt-error.h} (100%)

diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
index 5c738005f778..9225e52aa982 100644
--- a/src/cyclictest/cyclictest.c
+++ b/src/cyclictest/cyclictest.c
@@ -36,7 +36,7 @@
 
 #include "rt-utils.h"
 #include "rt-numa.h"
-#include "error.h"
+#include "rt-error.h"
 
 #include <bionic.h>
 
diff --git a/src/include/pip_stress.h b/src/include/pip_stress.h
index ee8b545ab117..f03aaf397897 100644
--- a/src/include/pip_stress.h
+++ b/src/include/pip_stress.h
@@ -14,8 +14,9 @@
 #include <sys/wait.h>
 #include <signal.h>
 #include <sched.h>
-#include <rt-utils.h>
-#include "error.h"
+
+#include "rt-utils.h"
+#include "rt-error.h"
 
 void low(pid_t pid);	/* low priority process */
 void medium(void);	/* medium priority process */
diff --git a/src/include/error.h b/src/include/rt-error.h
similarity index 100%
rename from src/include/error.h
rename to src/include/rt-error.h
diff --git a/src/lib/error.c b/src/lib/error.c
index 4434a842da17..616f70b044e0 100644
--- a/src/lib/error.c
+++ b/src/lib/error.c
@@ -5,7 +5,7 @@
  * error routines, similar to those found in
  * Advanced Programming in the UNIX Environment 2nd ed.
  */
-#include "error.h"
+#include "rt-error.h"
 
 /* Print an error message, plus a message for err and exit with error err */
 void err_exit(int err, char *fmt, ...)
diff --git a/src/lib/rt-numa.c b/src/lib/rt-numa.c
index 04f2e9adb4b1..4a0865715141 100644
--- a/src/lib/rt-numa.c
+++ b/src/lib/rt-numa.c
@@ -10,7 +10,7 @@
 #include <sched.h>
 #include <pthread.h>
 
-#include "error.h"
+#include "rt-error.h"
 #include "rt-numa.h"
 
 int get_available_cpus(struct bitmask *cpumask)
diff --git a/src/lib/rt-utils.c b/src/lib/rt-utils.c
index 2d68d62cd875..321a11b1172d 100644
--- a/src/lib/rt-utils.c
+++ b/src/lib/rt-utils.c
@@ -20,9 +20,10 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/syscall.h> /* For SYS_gettid definitions */
+
 #include "rt-utils.h"
 #include "rt-sched.h"
-#include "error.h"
+#include "rt-error.h"
 
 #define  TRACEBUFSIZ  1024
 
diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c
index 0811079d9f04..9e6f70600830 100644
--- a/src/oslat/oslat.c
+++ b/src/oslat/oslat.c
@@ -43,7 +43,7 @@
 
 #include "rt-utils.h"
 #include "rt-numa.h"
-#include "error.h"
+#include "rt-error.h"
 
 #ifdef __GNUC__
 # define atomic_inc(ptr)   __sync_add_and_fetch((ptr), 1)
diff --git a/src/pi_tests/pi_stress.c b/src/pi_tests/pi_stress.c
index 538d12c975aa..49f89b7b0136 100644
--- a/src/pi_tests/pi_stress.c
+++ b/src/pi_tests/pi_stress.c
@@ -47,8 +47,7 @@
 
 #include "rt-sched.h"
 #include "rt-utils.h"
-
-#include "error.h"
+#include "rt-error.h"
 
 /* test timeout */
 #define TIMEOUT 2
diff --git a/src/pmqtest/pmqtest.c b/src/pmqtest/pmqtest.c
index 5f7a24d55db6..349b47741003 100644
--- a/src/pmqtest/pmqtest.c
+++ b/src/pmqtest/pmqtest.c
@@ -21,11 +21,11 @@
 #include <linux/unistd.h>
 #include <utmpx.h>
 #include <mqueue.h>
+#include <pthread.h>
+
 #include "rt-utils.h"
 #include "rt-get_cpu.h"
-#include "error.h"
-
-#include <pthread.h>
+#include "rt-error.h"
 
 #define SYNCMQ_NAME "/syncmsg%d"
 #define TESTMQ_NAME "/testmsg%d"
diff --git a/src/ptsematest/ptsematest.c b/src/ptsematest/ptsematest.c
index 2e392299fdc4..e41b8af127da 100644
--- a/src/ptsematest/ptsematest.c
+++ b/src/ptsematest/ptsematest.c
@@ -19,11 +19,11 @@
 #include <sys/mman.h>
 #include <linux/unistd.h>
 #include <utmpx.h>
+#include <pthread.h>
+
 #include "rt-utils.h"
 #include "rt-get_cpu.h"
-#include "error.h"
-
-#include <pthread.h>
+#include "rt-error.h"
 
 enum {
 	AFFINITY_UNSPECIFIED,
diff --git a/src/signaltest/signaltest.c b/src/signaltest/signaltest.c
index 5427db7f8d85..c34bc994d886 100644
--- a/src/signaltest/signaltest.c
+++ b/src/signaltest/signaltest.c
@@ -31,7 +31,7 @@
 #include <sys/time.h>
 #include <sys/mman.h>
 
-#include "error.h"
+#include "rt-error.h"
 #include "rt-utils.h"
 #include "rt-numa.h"
 
diff --git a/src/sigwaittest/sigwaittest.c b/src/sigwaittest/sigwaittest.c
index 7e287bd2424f..f10c24914d4a 100644
--- a/src/sigwaittest/sigwaittest.c
+++ b/src/sigwaittest/sigwaittest.c
@@ -42,7 +42,7 @@
 
 #include "rt-utils.h"
 #include "rt-get_cpu.h"
-#include "error.h"
+#include "rt-error.h"
 
 enum {
 	AFFINITY_UNSPECIFIED,
diff --git a/src/svsematest/svsematest.c b/src/svsematest/svsematest.c
index 7388efb3f488..7a298e0dea8c 100644
--- a/src/svsematest/svsematest.c
+++ b/src/svsematest/svsematest.c
@@ -28,9 +28,10 @@
 #include <sys/sem.h>
 #include <sys/time.h>
 #include <sys/mman.h>
+
 #include "rt-utils.h"
 #include "rt-get_cpu.h"
-#include "error.h"
+#include "rt-error.h"
 
 #define SEM_WAIT_FOR_RECEIVER 0
 #define SEM_WAIT_FOR_SENDER 1
-- 
2.29.2


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

* [RFC v2 2/6] cyclictest: Move thread data to struct thread_param
  2021-01-11 17:33 [RFC v2 0/6] Generate machine-readable output Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 1/6] rt-tests: Rename error.h to rt-error.h Daniel Wagner
@ 2021-01-11 17:33 ` Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 3/6] signaltest: " Daniel Wagner
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Daniel Wagner @ 2021-01-11 17:33 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 9225e52aa982..c0e7600b4740 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;
 }
@@ -1298,7 +1298,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");
 }
 
@@ -1412,7 +1412,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);
@@ -1468,7 +1468,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);
@@ -1969,9 +1969,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));
 
@@ -2041,10 +2041,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.29.2


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

* [RFC v2 3/6] signaltest: Move thread data to struct thread_param
  2021-01-11 17:33 [RFC v2 0/6] Generate machine-readable output Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 1/6] rt-tests: Rename error.h to rt-error.h Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 2/6] cyclictest: Move thread data to struct thread_param Daniel Wagner
@ 2021-01-11 17:33 ` Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 4/6] rt-utils: Add JSON common header output helper Daniel Wagner
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Daniel Wagner @ 2021-01-11 17:33 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.29.2


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

* [RFC v2 4/6] rt-utils: Add JSON common header output helper
  2021-01-11 17:33 [RFC v2 0/6] Generate machine-readable output Daniel Wagner
                   ` (2 preceding siblings ...)
  2021-01-11 17:33 ` [RFC v2 3/6] signaltest: " Daniel Wagner
@ 2021-01-11 17:33 ` Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 5/6] cyclictest: Add JSON output feature Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 6/6] signaltest: " Daniel Wagner
  5 siblings, 0 replies; 7+ messages in thread
From: Daniel Wagner @ 2021-01-11 17:33 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.

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

diff --git a/src/include/rt-utils.h b/src/include/rt-utils.h
index 39ddbd9eae29..ca9984d7cf35 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(FILE *f, 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..8fe0b7ed1f63 100644
--- a/src/lib/rt-utils.c
+++ b/src/lib/rt-utils.c
@@ -20,6 +20,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/syscall.h> /* For SYS_gettid definitions */
+#include <sys/utsname.h>
 
 #include "rt-utils.h"
 #include "rt-sched.h"
@@ -482,3 +483,60 @@ 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");
+
+	cmdline[0] = '\0';
+	for (i = 0; i < argc;) {
+		cmdline = strcat(cmdline, argv[i]);
+		i++;
+		if (i < argc)
+			cmdline = strcat(cmdline, " ");
+	}
+
+	return cmdline;
+}
+
+void rt_write_json(FILE *f, int argc, char *argv[],
+		  void (*cb)(FILE *, void *),
+		  void *data)
+{
+	struct utsname buf;
+	char *cmdline;
+
+	cmdline = get_cmdline(argc, argv);
+	if (!cmdline)
+		err_exit(ENOMEM, "get_cmdline()");
+
+	if (uname(&buf))
+		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, "  \"sysinfo\": {\n");
+	fprintf(f, "    \"sysname\": \"%s\",\n", buf.sysname);
+	fprintf(f, "    \"nodename\": \"%s\",\n", buf.nodename);
+	fprintf(f, "    \"release\": \"%s\",\n", buf.release);
+	fprintf(f, "    \"version\": \"%s\",\n", buf.version);
+	fprintf(f, "    \"machine\": \"%s\"\n", buf.machine);
+	fprintf(f, "  },\n");
+
+	(cb)(f, data);
+
+	fprintf(f, "}\n");
+
+	free(cmdline);
+}
-- 
2.29.2


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

* [RFC v2 5/6] cyclictest: Add JSON output feature
  2021-01-11 17:33 [RFC v2 0/6] Generate machine-readable output Daniel Wagner
                   ` (3 preceding siblings ...)
  2021-01-11 17:33 ` [RFC v2 4/6] rt-utils: Add JSON common header output helper Daniel Wagner
@ 2021-01-11 17:33 ` Daniel Wagner
  2021-01-11 17:33 ` [RFC v2 6/6] signaltest: " Daniel Wagner
  5 siblings, 0 replies; 7+ messages in thread
From: Daniel Wagner @ 2021-01-11 17:33 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 | 51 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
index c0e7600b4740..d746e822be72 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;
@@ -843,6 +845,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"
@@ -950,7 +953,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 */
@@ -984,6 +987,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 },
@@ -1078,6 +1082,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);
@@ -1695,6 +1702,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)
 {
@@ -2038,6 +2079,14 @@ int main(int argc, char **argv)
 	if (!verbose && !quiet && refresh_on_max)
 		printf("\033[%dB", num_threads + 2);
 
+	if (strlen(outfile) != 0) {
+		FILE *f = fopen(outfile, "w");
+		if (!f)
+			err_exit(errno, "Failed to open output file '%s'", outfile);
+		rt_write_json(f, argc, argv, write_stats, NULL);
+		fclose(f);
+	}
+
 	if (quiet)
 		quiet = 2;
 	for (i = 0; i < num_threads; i++) {
-- 
2.29.2


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

* [RFC v2 6/6] signaltest: Add JSON output feature
  2021-01-11 17:33 [RFC v2 0/6] Generate machine-readable output Daniel Wagner
                   ` (4 preceding siblings ...)
  2021-01-11 17:33 ` [RFC v2 5/6] cyclictest: Add JSON output feature Daniel Wagner
@ 2021-01-11 17:33 ` Daniel Wagner
  5 siblings, 0 replies; 7+ messages in thread
From: Daniel Wagner @ 2021-01-11 17:33 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.

Reviewed-by: Daniel Wagner <dwagner@suse.de>
---
 src/signaltest/signaltest.c | 113 +++++++++++++++++++++++++++++-------
 1 file changed, 92 insertions(+), 21 deletions(-)

diff --git a/src/signaltest/signaltest.c b/src/signaltest/signaltest.c
index dd5633d5fc51..9f725ef91ad7 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,13 @@ int main(int argc, char **argv)
 		if (stat[i].values)
 			free(stat[i].values);
 	}
+	if (strlen(outfile) != 0) {
+		FILE *f = fopen(outfile, "w");
+		if (!f)
+			err_exit(errno, "Failed to open output file '%s'", outfile);
+		rt_write_json(f, argc, argv, write_stats, par);
+		fclose(f);
+	}
 	free(stat);
  outpar:
 	free(par);
-- 
2.29.2


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

end of thread, other threads:[~2021-01-11 17:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-11 17:33 [RFC v2 0/6] Generate machine-readable output Daniel Wagner
2021-01-11 17:33 ` [RFC v2 1/6] rt-tests: Rename error.h to rt-error.h Daniel Wagner
2021-01-11 17:33 ` [RFC v2 2/6] cyclictest: Move thread data to struct thread_param Daniel Wagner
2021-01-11 17:33 ` [RFC v2 3/6] signaltest: " Daniel Wagner
2021-01-11 17:33 ` [RFC v2 4/6] rt-utils: Add JSON common header output helper Daniel Wagner
2021-01-11 17:33 ` [RFC v2 5/6] cyclictest: Add JSON output feature Daniel Wagner
2021-01-11 17:33 ` [RFC v2 6/6] signaltest: " Daniel Wagner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.