diff --git a/.gitignore b/.gitignore index d52a338..97a3fb3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/rt-tests-1.8.tar.xz +SOURCES/rt-tests-1.10.tar.xz diff --git a/.rt-tests.metadata b/.rt-tests.metadata index 77a85ed..d359e83 100644 --- a/.rt-tests.metadata +++ b/.rt-tests.metadata @@ -1 +1 @@ -50737a762ff27d6440798f10a33f720f476e1438 SOURCES/rt-tests-1.8.tar.xz +7befc28537ebfa23b989037da99dd4eb842ee9b6 SOURCES/rt-tests-1.10.tar.xz diff --git a/SOURCES/cyclictest-Fix-setaffinity-error-on-large-NUMA-machines.patch b/SOURCES/cyclictest-Fix-setaffinity-error-on-large-NUMA-machines.patch deleted file mode 100644 index 96084c2..0000000 --- a/SOURCES/cyclictest-Fix-setaffinity-error-on-large-NUMA-machines.patch +++ /dev/null @@ -1,84 +0,0 @@ -From b07c57b33e4e24e873e680b8327f9be4f321caa9 Mon Sep 17 00:00:00 2001 -From: Yunfeng Ye -Date: Wed, 22 Apr 2020 10:19:52 +0800 -Subject: [PATCH] cyclictest: Fix setaffinity error on large NUMA machines - -An Error occurs when run: ./cyclictest -v -t 5 -p 80 -i 1000 -a 3 - -On large NUMA machines still getting the following error -WARN: Couldn't setaffinity in main thread: Invalid argument - -Instead of calling numa_bitmask_alloc() with max_cpus, use -numa_allocate_cpumask() to fix this. - -Also, make sure numa_available() is called before any other calls to the -numa library. Depending on how the options were invoked this could -happen in parse_cpumask for example. Note, this did not seem to cause -any problems in practice, but let's adhere to the library contract. - -Signed-off-by: John Kacur ---- - src/cyclictest/cyclictest.c | 26 +++++++++++++++++++------- - 1 file changed, 19 insertions(+), 7 deletions(-) - -diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c -index c5f1fd46567a..79bb1cb71c68 100644 ---- a/src/cyclictest/cyclictest.c -+++ b/src/cyclictest/cyclictest.c -@@ -1135,7 +1135,7 @@ static void use_current_cpuset(const int max_cpus) - - pid = getpid(); - -- curmask = numa_bitmask_alloc(sizeof(struct bitmask)); -+ curmask = numa_allocate_cpumask(); - numa_sched_getaffinity(pid, curmask); - - /* Clear bits that are not set in both the cpuset from the environment, -@@ -1225,6 +1225,20 @@ enum option_values { - OPT_TRACEMARK, OPT_POSIX_TIMERS, - }; - -+/* numa_available() must be called before any other calls to the numa library */ -+static void numa_initialize(void) -+{ -+ static int is_initialized; -+ -+ if (is_initialized == 1) -+ return; -+ -+ if (numa_available() != -1) -+ numa = 1; -+ -+ is_initialized = 1; -+} -+ - /* Process commandline options */ - static void process_options (int argc, char *argv[], int max_cpus) - { -@@ -1288,6 +1302,7 @@ static void process_options (int argc, char *argv[], int max_cpus) - /* smp sets AFFINITY_USEALL in OPT_SMP */ - if (smp) - break; -+ numa_initialize(); - if (optarg != NULL) { - parse_cpumask(optarg, max_cpus); - setaffinity = AFFINITY_SPECIFIED; -@@ -1460,12 +1475,9 @@ static void process_options (int argc, char *argv[], int max_cpus) - /* if smp wasn't requested, test for numa automatically */ - if (!smp) { - #ifdef NUMA -- if (numa_available() != -1) { -- numa = 1; -- if (setaffinity == AFFINITY_UNSPECIFIED) { -- setaffinity = AFFINITY_USEALL; -- } -- } -+ numa_initialize(); -+ if (setaffinity == AFFINITY_UNSPECIFIED) -+ setaffinity = AFFINITY_USEALL; - #else - warn("cyclictest was not built with the numa option\n"); - numa = 0; --- -2.21.3 - diff --git a/SOURCES/oslat-Use-cpuset-size-as-upper-bound.patch b/SOURCES/oslat-Use-cpuset-size-as-upper-bound.patch new file mode 100644 index 0000000..415b023 --- /dev/null +++ b/SOURCES/oslat-Use-cpuset-size-as-upper-bound.patch @@ -0,0 +1,38 @@ +From 6d5aa2b00d41ecdb6eb1355309737647e177e5e6 Mon Sep 17 00:00:00 2001 +From: Daniel Wagner +Date: Wed, 10 Feb 2021 17:54:07 +0100 +Subject: [PATCH 2/3] oslat: Use cpuset size as upper bound + +To assign the threads to the correct CPU we need to use the cpuset +size as upper bound for the loop and not the number of threads. + +Fixes: 85b0763dacd9 ("oslat: Use parse_cpumask() from rt-numa.h") +Reported-by: Peter Xu +Signed-off-by: Daniel Wagner +Signed-off-by: John Kacur +--- + src/oslat/oslat.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c +index 7826c277f26d..2fe550b3ee12 100644 +--- a/src/oslat/oslat.c ++++ b/src/oslat/oslat.c +@@ -747,9 +747,12 @@ int main(int argc, char *argv[]) + n_cores = numa_bitmask_weight(cpu_set); + + TEST(threads = calloc(1, n_cores * sizeof(threads[0]))); +- for (i = 0; i < n_cores; ++i) +- if (numa_bitmask_isbitset(cpu_set, i) && move_to_core(i) == 0) ++ for (i = 0; n_cores && i < cpu_set->size; i++) { ++ if (numa_bitmask_isbitset(cpu_set, i) && move_to_core(i) == 0) { + threads[g.n_threads_total++].core_i = i; ++ n_cores--; ++ } ++ } + + if (numa_bitmask_isbitset(cpu_set, 0) && g.rtprio) + printf("WARNING: Running SCHED_FIFO workload on CPU 0 may hang the thread\n"); +-- +2.26.2 + diff --git a/SOURCES/oslat-allow-scheduling-on-all-possible-cores.patch b/SOURCES/oslat-allow-scheduling-on-all-possible-cores.patch new file mode 100644 index 0000000..a80e336 --- /dev/null +++ b/SOURCES/oslat-allow-scheduling-on-all-possible-cores.patch @@ -0,0 +1,73 @@ +From 29884cff6352856fee9fffecb4a715efd70e08f5 Mon Sep 17 00:00:00 2001 +From: Peter Xu +Date: Thu, 18 Feb 2021 14:27:29 -0500 +Subject: [PATCH] oslat: Fix --cpu-list won't allow to schedule on all possible + cores + +parse_cpumask() is too strict for oslat, in that use_current_cpuset() will +filter out all the cores that are not allowed for current process to run. This +seems to be unnecessary at least for oslat. For example, the bash process that +runs the oslat program may have a sched affinity of 0-2, however it's still +legal to have it start a oslat thread running on the cores outside 0-2 as long +as the follow up sched_setaffinity() will succeed. + +numa_parse_cpustring_all() suites exactly for this case, which should already +have considered sysconf(_SC_NPROCESSORS_ONLN) limit. Use that instead. + +Since at it, also remove initialization of cpu_set variable otherwise it's +leaked in previous parse_cpumask too: numa_parse_cpustring_all() will return a +newly allocated buffer already. Quotting from manual: + + numa_parse_nodestring() parses a character string list of nodes into a bit + mask. The bit mask is allocated by numa_allocate_nodemask(). + + numa_parse_nodestring_all() is similar to numa_parse_nodestring, but can + parse all possible nodes, not only current nodeset. + +Cc: John Kacur +Cc: Daniel Wagner +Cc: Clark Williams +Reported-by: Pradipta Kumar Sahoo +Reported-by: Mike Stowell +Signed-off-by: Peter Xu +Signed-off-by: John Kacur +--- + src/oslat/oslat.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c +index b2c5373388fb..465a694cdd1d 100644 +--- a/src/oslat/oslat.c ++++ b/src/oslat/oslat.c +@@ -785,7 +785,6 @@ int main(int argc, char *argv[]) + struct thread *threads; + int i, n_cores; + struct bitmask *cpu_set = NULL; +- int max_cpus = sysconf(_SC_NPROCESSORS_ONLN); + + #ifdef FRC_MISSING + printf("This architecture is not yet supported. " +@@ -797,10 +796,6 @@ int main(int argc, char *argv[]) + exit(1); + } + +- cpu_set = numa_allocate_cpumask(); +- if (!cpu_set) +- fatal("oslat: Could not allocate cpumask\n"); +- + g.app_name = argv[0]; + g.rtprio = 0; + g.bucket_size = BUCKET_SIZE; +@@ -817,7 +812,8 @@ int main(int argc, char *argv[]) + if (!g.cpu_list) + g.cpu_list = strdup("all"); + +- if (parse_cpumask(g.cpu_list, max_cpus, &cpu_set) != 0) ++ cpu_set = numa_parse_cpustring_all(g.cpu_list); ++ if (!cpu_set) + fatal("oslat: parse_cpumask failed.\n"); + n_cores = numa_bitmask_weight(cpu_set); + +-- +2.26.2 + diff --git a/SOURCES/pi_stress-limit-the-number-of-inversion-groups-to-th.patch b/SOURCES/pi_stress-limit-the-number-of-inversion-groups-to-th.patch deleted file mode 100644 index c0e9cd2..0000000 --- a/SOURCES/pi_stress-limit-the-number-of-inversion-groups-to-th.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 3359c4464c2a13ab04f15598b1c79040399978f5 Mon Sep 17 00:00:00 2001 -From: Clark Williams -Date: Tue, 21 Jul 2020 16:10:22 -0500 -Subject: [PATCH] pi_stress: limit the number of inversion groups to the number - of online cores - -Each inversion group is three SCHED_FIFO threads, so the chances of more groups -than online cores actually getting to run is very slim. Limit the number of -groups requested to be <= the number of online cpus. - -Signed-off-by: Clark Williams - -Changing the conversion in printf to %ld since the number of online -processors is a long. -Signed-off-by: John Kacur ---- - src/pi_tests/pi_stress.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/pi_tests/pi_stress.c b/src/pi_tests/pi_stress.c -index 0ed844c636cd..eba21d7727bc 100644 ---- a/src/pi_tests/pi_stress.c -+++ b/src/pi_tests/pi_stress.c -@@ -1327,6 +1327,12 @@ void process_command_line(int argc, char **argv) - break; - case 'g': - ngroups = strtol(optarg, NULL, 10); -+ if (ngroups > num_processors) { -+ pi_error("the number of groups cannot exceed " -+ "the number of online processors (%ld)\n", -+ num_processors); -+ exit(-1); -+ } - pi_info("number of groups set to %d\n", ngroups); - break; - case 'r': --- -2.26.2 - diff --git a/SOURCES/rt-tests-Add-a-man-page-for-get_cyclictest_snapshot.patch b/SOURCES/rt-tests-Add-a-man-page-for-get_cyclictest_snapshot.patch deleted file mode 100644 index ca2184c..0000000 --- a/SOURCES/rt-tests-Add-a-man-page-for-get_cyclictest_snapshot.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 82aa302cc1b5fba57792dbf43721897aa3305cff Mon Sep 17 00:00:00 2001 -From: John Kacur -Date: Mon, 6 Jul 2020 13:18:40 -0400 -Subject: [PATCH 4/7] rt-tests: Add a man page for get_cyclictest_snapshot - -Add a man page for get_cyclictest_snapshot based on -h - -Signed-off-by: John Kacur ---- - src/cyclictest/get_cyclictest_snapshot.8 | 44 ++++++++++++++++++++++++ - 1 file changed, 44 insertions(+) - create mode 100644 src/cyclictest/get_cyclictest_snapshot.8 - -diff --git a/src/cyclictest/get_cyclictest_snapshot.8 b/src/cyclictest/get_cyclictest_snapshot.8 -new file mode 100644 -index 000000000000..e9251a8e821f ---- /dev/null -+++ b/src/cyclictest/get_cyclictest_snapshot.8 -@@ -0,0 +1,44 @@ -+.\" Hey, EMACS: -*- nroff -*- -+.TH GET_CYCLICTEST_SNAPSHOT 8 "July 6, 2020" -+.\" Please adjust this date whenever revising the manpage. -+.\" -+.\" Some roff macros, for reference: -+.\" .nh disable hyphenation -+.\" .hy enable hyphenation -+.\" .ad l left justify -+.\" .ad b justify to both left and right margins -+.\" .nf disable filling -+.\" .fi enable filling -+.\" .br insert line break -+.\" .sp insert n+1 empty lines -+.\" for manpage-specific macros, see man(7) -+.SH NAME -+get_cyclictest_snapshot \- Get a snapshot of running instances of cyclictest -+.SH SYNOPSIS -+.SY get_cyclictest_snapshot -+.OP [\-h]\ [\-l]\ [\-s\ [pid [pid ...]]] -+.br -+.OP [\-p\ [pid\ [pid ...]]] -+.SH OPTIONS -+Without options, this program will send USR2 to cyclictest to create a snapshot and then print it out. -+.br -+.TP -+Optional arguments: -+.TP -+.B -h, --help -+show this help message and exit -+.TP -+.B -l, --list -+list the main pid(s) of running instances of cyclictest -+.TP -+.B -s [pid [pid ...]], --snapshot [pid [pid ...]] -+take a snapshot of running instances of cyclictest -+.br -+by sending USR2 to cyclictest -+.TP -+.B -p [pid [pid ...]], --print [pid [pid ...]] -+print the snapshots -+.SH SEE ALSO -+.BR cyclictest (8), -+.SH AUTHOR -+get_cyclictest_snapshot was written by John Kacur --- -2.21.3 - diff --git a/SOURCES/rt-tests-Install-new-man-page-get_cyclictest_snapshot.patch b/SOURCES/rt-tests-Install-new-man-page-get_cyclictest_snapshot.patch deleted file mode 100644 index 5dda144..0000000 --- a/SOURCES/rt-tests-Install-new-man-page-get_cyclictest_snapshot.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 7731b805fa5a38e7e2dc0e551e102d2d5e6fa8d7 Mon Sep 17 00:00:00 2001 -From: John Kacur -Date: Mon, 6 Jul 2020 23:19:24 -0400 -Subject: [PATCH] rt-tests: Install new man page get_cyclictest_snapshot.8 - -Install the new man page, get_cyclictest_snapshot.8 - -Signed-off-by: John Kacur ---- - Makefile | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/Makefile b/Makefile -index 05fc5eda71fa..be7831277c88 100644 ---- a/Makefile -+++ b/Makefile -@@ -47,7 +47,8 @@ MANPAGES = src/cyclictest/cyclictest.8 \ - src/queuelat/queuelat.8 \ - src/sched_deadline/deadline_test.8 \ - src/ssdd/ssdd.8 \ -- src/sched_deadline/cyclicdeadline.8 -+ src/sched_deadline/cyclicdeadline.8 \ -+ src/cyclictest/get_cyclictest_snapshot.8 - - ifdef PYLIB - MANPAGES += src/hwlatdetect/hwlatdetect.8 --- -2.21.3 - diff --git a/SOURCES/rt-tests-Tweak-the-cyclictest-man-page.patch b/SOURCES/rt-tests-Tweak-the-cyclictest-man-page.patch deleted file mode 100644 index 5ed211b..0000000 --- a/SOURCES/rt-tests-Tweak-the-cyclictest-man-page.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 89f9ce00774c02388bd29e0da05147282d24830e Mon Sep 17 00:00:00 2001 -From: John Kacur -Date: Mon, 6 Jul 2020 13:21:42 -0400 -Subject: [PATCH 5/7] rt-tests: Tweak the cyclictest man page - -Tweak the cyclictest man page with the .SY macro to make the cyclictest -command stand out apart from the options - -Signed-off-by: John Kacur ---- - src/cyclictest/cyclictest.8 | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/cyclictest/cyclictest.8 b/src/cyclictest/cyclictest.8 -index 00e2d2403996..44b5d0dbcc4a 100644 ---- a/src/cyclictest/cyclictest.8 -+++ b/src/cyclictest/cyclictest.8 -@@ -15,7 +15,7 @@ - .SH NAME - cyclictest \- High resolution test program - .SH SYNOPSIS --.B cyclictest -+.SY cyclictest - .RI "[ \-hfmnqrsvMS ] [\-a " proc " ] [\-A " align " ] [\-b " usec " ] [\-c " clock " ] [\-d " dist " ] \ - [\-h " histogram " ] [\-i " intv " ] [\-l " loop " ] [\-o " red " ] [\-p " prio " ] \ - [\-t " num " ] [\-D " time "] [\-w] [\-W] [\-y " policy " ] [ \-S | \-U ]" --- -2.21.3 - diff --git a/SOURCES/rt-tests-cyclictest-Move-ftrace-helpers-into-rt-util.patch b/SOURCES/rt-tests-cyclictest-Move-ftrace-helpers-into-rt-util.patch deleted file mode 100644 index 99112be..0000000 --- a/SOURCES/rt-tests-cyclictest-Move-ftrace-helpers-into-rt-util.patch +++ /dev/null @@ -1,259 +0,0 @@ -From dc433f68c9f19eb0a28e0f00342dfd33f319f0fa Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Mon, 17 Aug 2020 17:55:04 -0400 -Subject: [PATCH 1/2] rt-tests: cyclictest: Move ftrace helpers into - rt-utils.[ch] - -Then they can be further used by other programs too. - -Two trivial things to mention. - -Firstly, move trace_marker out of enable_trace_mark(). No functional change. - -Secondly, remove the fileprefix setting in process_options(), because if -tracelimit is non-zero, fileprefix will be after all replaced by a further call -to get_debugfileprefix() in debugfs_prepare(). - -Signed-off-by: Peter Xu -Signed-off-by: John Kacur ---- - src/cyclictest/cyclictest.c | 90 +------------------------------------ - src/include/rt-utils.h | 3 ++ - src/lib/rt-utils.c | 82 +++++++++++++++++++++++++++++++++ - 3 files changed, 86 insertions(+), 89 deletions(-) - -diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c -index eb61be394f2e..dd418939a0c2 100644 ---- a/src/cyclictest/cyclictest.c -+++ b/src/cyclictest/cyclictest.c -@@ -219,8 +219,6 @@ static pthread_barrier_t align_barr; - static pthread_barrier_t globalt_barr; - static struct timespec globalt; - --static char *procfileprefix = "/proc/sys/kernel/"; --static char *fileprefix; - static char fifopath[MAX_PATH]; - static char histfile[MAX_PATH]; - -@@ -330,89 +328,6 @@ static inline int64_t calctime(struct timespec t) - return time; - } - --static int trace_file_exists(char *name) --{ -- struct stat sbuf; -- char *tracing_prefix = get_debugfileprefix(); -- char path[MAX_PATH]; -- strcat(strcpy(path, tracing_prefix), name); -- return stat(path, &sbuf) ? 0 : 1; --} -- --#define TRACEBUFSIZ 1024 --static __thread char tracebuf[TRACEBUFSIZ]; -- --static void tracemark(char *fmt, ...) __attribute__((format(printf, 1, 2))); --static void tracemark(char *fmt, ...) --{ -- va_list ap; -- int len; -- -- /* bail out if we're not tracing */ -- /* or if the kernel doesn't support trace_mark */ -- if (tracemark_fd < 0 || trace_fd < 0) -- return; -- -- va_start(ap, fmt); -- len = vsnprintf(tracebuf, TRACEBUFSIZ, fmt, ap); -- va_end(ap); -- -- /* write the tracemark message */ -- write(tracemark_fd, tracebuf, len); -- -- /* now stop any trace */ -- write(trace_fd, "0\n", 2); --} -- --static void open_tracemark_fd(void) --{ -- char path[MAX_PATH]; -- -- /* -- * open the tracemark file if it's not already open -- */ -- if (tracemark_fd < 0) { -- sprintf(path, "%s/%s", fileprefix, "trace_marker"); -- tracemark_fd = open(path, O_WRONLY); -- if (tracemark_fd < 0) { -- warn("unable to open trace_marker file: %s\n", path); -- return; -- } -- } -- -- /* -- * if we're not tracing and the tracing_on fd is not open, -- * open the tracing_on file so that we can stop the trace -- * if we hit a breaktrace threshold -- */ -- if (trace_fd < 0) { -- sprintf(path, "%s/%s", fileprefix, "tracing_on"); -- if ((trace_fd = open(path, O_WRONLY)) < 0) -- warn("unable to open tracing_on file: %s\n", path); -- } --} -- --static void debugfs_prepare(void) --{ -- if (mount_debugfs(NULL)) -- fatal("could not mount debugfs"); -- -- fileprefix = get_debugfileprefix(); -- if (!trace_file_exists("tracing_enabled") && -- !trace_file_exists("tracing_on")) -- warn("tracing_enabled or tracing_on not found\n" -- "debug fs not mounted"); --} -- --static void enable_trace_mark(void) --{ -- if (!trace_marker) -- return; -- -- debugfs_prepare(); -- open_tracemark_fd(); --} -- - /* - * Raise the soft priority limit up to prio, if that is less than or equal - * to the hard limit -@@ -1498,9 +1413,6 @@ static void process_options (int argc, char *argv[], int max_cpus) - "on this processor\n"); - } - -- if (tracelimit) -- fileprefix = procfileprefix; -- - if (clocksel < 0 || clocksel > ARRAY_SIZE(clocksources)) - error = 1; - -@@ -2065,7 +1977,7 @@ int main(int argc, char **argv) - /* use the /dev/cpu_dma_latency trick if it's there */ - set_latency_target(); - -- if (tracelimit) -+ if (tracelimit && trace_marker) - enable_trace_mark(); - - if (check_timer()) -diff --git a/src/include/rt-utils.h b/src/include/rt-utils.h -index 6ec2b2011959..51489b408e6c 100644 ---- a/src/include/rt-utils.h -+++ b/src/include/rt-utils.h -@@ -27,4 +27,7 @@ pid_t gettid(void); - - int parse_time_string(char *val); - -+void enable_trace_mark(void); -+void tracemark(char *fmt, ...) __attribute__((format(printf, 1, 2))); -+ - #endif /* __RT_UTILS.H */ -diff --git a/src/lib/rt-utils.c b/src/lib/rt-utils.c -index 1998a327d036..f786588706cd 100644 ---- a/src/lib/rt-utils.c -+++ b/src/lib/rt-utils.c -@@ -24,7 +24,13 @@ - #include "rt-sched.h" - #include "error.h" - -+#define TRACEBUFSIZ 1024 -+ - static char debugfileprefix[MAX_PATH]; -+static char *fileprefix; -+static int trace_fd = -1; -+static int tracemark_fd = -1; -+static __thread char tracebuf[TRACEBUFSIZ]; - - /* - * Finds the tracing directory in a mounted debugfs -@@ -355,3 +361,79 @@ int parse_time_string(char *val) - } - return t; - } -+ -+void open_tracemark_fd(void) -+{ -+ char path[MAX_PATH]; -+ -+ /* -+ * open the tracemark file if it's not already open -+ */ -+ if (tracemark_fd < 0) { -+ sprintf(path, "%s/%s", fileprefix, "trace_marker"); -+ tracemark_fd = open(path, O_WRONLY); -+ if (tracemark_fd < 0) { -+ warn("unable to open trace_marker file: %s\n", path); -+ return; -+ } -+ } -+ -+ /* -+ * if we're not tracing and the tracing_on fd is not open, -+ * open the tracing_on file so that we can stop the trace -+ * if we hit a breaktrace threshold -+ */ -+ if (trace_fd < 0) { -+ sprintf(path, "%s/%s", fileprefix, "tracing_on"); -+ if ((trace_fd = open(path, O_WRONLY)) < 0) -+ warn("unable to open tracing_on file: %s\n", path); -+ } -+} -+ -+int trace_file_exists(char *name) -+{ -+ struct stat sbuf; -+ char *tracing_prefix = get_debugfileprefix(); -+ char path[MAX_PATH]; -+ strcat(strcpy(path, tracing_prefix), name); -+ return stat(path, &sbuf) ? 0 : 1; -+} -+ -+void debugfs_prepare(void) -+{ -+ if (mount_debugfs(NULL)) -+ fatal("could not mount debugfs"); -+ -+ fileprefix = get_debugfileprefix(); -+ if (!trace_file_exists("tracing_enabled") && -+ !trace_file_exists("tracing_on")) -+ warn("tracing_enabled or tracing_on not found\n" -+ "debug fs not mounted"); -+} -+ -+void tracemark(char *fmt, ...) -+{ -+ va_list ap; -+ int len; -+ -+ /* bail out if we're not tracing */ -+ /* or if the kernel doesn't support trace_mark */ -+ if (tracemark_fd < 0 || trace_fd < 0) -+ return; -+ -+ va_start(ap, fmt); -+ len = vsnprintf(tracebuf, TRACEBUFSIZ, fmt, ap); -+ va_end(ap); -+ -+ /* write the tracemark message */ -+ write(tracemark_fd, tracebuf, len); -+ -+ /* now stop any trace */ -+ write(trace_fd, "0\n", 2); -+} -+ -+void enable_trace_mark(void) -+{ -+ debugfs_prepare(); -+ open_tracemark_fd(); -+} --- -2.26.2 - diff --git a/SOURCES/rt-tests-cyclictest-remove-the-debug-log-pid-xxx-in-.patch b/SOURCES/rt-tests-cyclictest-remove-the-debug-log-pid-xxx-in-.patch deleted file mode 100644 index 9efe7e8..0000000 --- a/SOURCES/rt-tests-cyclictest-remove-the-debug-log-pid-xxx-in-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From caaec484d88fe4dfc1f83b8ce2e2ff1167193517 Mon Sep 17 00:00:00 2001 -From: Yunfeng Ye -Date: Thu, 2 Jul 2020 10:22:21 +0800 -Subject: [PATCH] rt-tests: cyclictest: remove the debug log "pid = xxx" in - rstat_shm_open() - -The infomation "pid = xxx" is printed with other infomation on the same -line. so remove this left over debug message in rstat_shm_open(). - -Signed-off-by: yeyunfeng - -Edited the descriptioin in the log a little bit. -Signed-off-by: John Kacur ---- - src/cyclictest/cyclictest.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c -index 79bb1cb71c68..eb61be394f2e 100644 ---- a/src/cyclictest/cyclictest.c -+++ b/src/cyclictest/cyclictest.c -@@ -1921,7 +1921,6 @@ static int rstat_shm_open(void) - pid_t pid; - - pid = getpid(); -- printf("pid = %d", pid); - - snprintf(shm_name, SHM_BUF_SIZE, "%s%d", "/cyclictest", pid); - --- -2.21.3 - diff --git a/SOURCES/rt-tests-get_cyclictest_snapshot-Warn-if-no-cyclicte.patch b/SOURCES/rt-tests-get_cyclictest_snapshot-Warn-if-no-cyclicte.patch deleted file mode 100644 index f17b9ac..0000000 --- a/SOURCES/rt-tests-get_cyclictest_snapshot-Warn-if-no-cyclicte.patch +++ /dev/null @@ -1,76 +0,0 @@ -From c7b4217ff2b04d774ee5e2728eeb5da1cba275ff Mon Sep 17 00:00:00 2001 -From: John Kacur -Date: Mon, 6 Jul 2020 16:07:17 -0400 -Subject: [PATCH 7/7] rt-tests: get_cyclictest_snapshot: Warn if no cyclictest - instance found - -- Print a warning if no cyclictest instance is found. -- Also fix up the method take_snapshot for the case when the user - provides a pid. - -Signed-off-by: John Kacur ---- - src/cyclictest/get_cyclictest_snapshot.py | 23 +++++++++++++++++++++-- - 1 file changed, 21 insertions(+), 2 deletions(-) - -diff --git a/src/cyclictest/get_cyclictest_snapshot.py b/src/cyclictest/get_cyclictest_snapshot.py -index 27fc629ca53e..aed9681e4cc5 100755 ---- a/src/cyclictest/get_cyclictest_snapshot.py -+++ b/src/cyclictest/get_cyclictest_snapshot.py -@@ -19,6 +19,14 @@ args = parser.parse_args() - class Snapshot: - """ Class for getting a snapshot of a running cyclictest instance """ - -+ warned = False -+ -+ def print_warning(): -+ """ print a warning one time only even if called multiple times """ -+ if not Snapshot.warned: -+ Snapshot.warned = True -+ print("No cyclictest instance found") -+ - def __init__(self): - self.pids = [] - self.shm_files = [] -@@ -36,18 +44,27 @@ class Snapshot: - def take_snapshot(self, spids=None): - """ Send USR2 to all running instances of cyclictest, - or just to a specific pid (spids) if specified. """ -- for pid in self.pids: -- if (spids is None) or (pid in spids): -+ if spids is None: -+ if not self.pids: -+ Snapshot.print_warning() -+ for pid in self.pids: -+ subprocess.run(["kill", "-s", "USR2", pid]) -+ else: -+ for pid in spids: - subprocess.run(["kill", "-s", "USR2", pid]) - - def print_pids(self): - """ Print the list of pids of running cyclictest instances. """ -+ if not self.pids: -+ Snapshot.print_warning() - for pid in self.pids: - print(pid) - - def print(self, spids=None): - """ Print the data in /dev/shm/cyclictest* """ - if spids is None: -+ if not self.shm_files: -+ Snapshot.print_warning() - for shm_file in self.shm_files: - with open(shm_file, 'r') as f: - data = f.read() -@@ -59,6 +76,8 @@ class Snapshot: - with open(shm_file, 'r') as f: - data = f.read() - print(data) -+ else: -+ Snapshot.print_warning() - - snapshot = Snapshot() - --- -2.21.3 - diff --git a/SOURCES/rt-tests-improvements-to-the-python-style-in-get_cyc.patch b/SOURCES/rt-tests-improvements-to-the-python-style-in-get_cyc.patch deleted file mode 100644 index 38d527f..0000000 --- a/SOURCES/rt-tests-improvements-to-the-python-style-in-get_cyc.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 3ee764c75dd0cdb2ade1a832ed3769ed4964cd30 Mon Sep 17 00:00:00 2001 -From: John Kacur -Date: Thu, 2 Jul 2020 21:19:55 -0400 -Subject: [PATCH 1/7] rt-tests: improvements to the python style in - get_cyclictest_snapshot - -Improvements to the python style in get_cyclictest_snapshot - -- Add comments to the methods, functions, class and moduleb -- Put imports on individual lines -- Use "is" and "is not" with None insteald of == or != -- Don't compare the length of lists to zero, to determine if they are - empty - -Signed-off-by: John Kacur ---- - src/cyclictest/get_cyclictest_snapshot.py | 38 +++++++++++++---------- - 1 file changed, 22 insertions(+), 16 deletions(-) - -diff --git a/src/cyclictest/get_cyclictest_snapshot.py b/src/cyclictest/get_cyclictest_snapshot.py -index 7dddfc5d65b0..27fc629ca53e 100755 ---- a/src/cyclictest/get_cyclictest_snapshot.py -+++ b/src/cyclictest/get_cyclictest_snapshot.py -@@ -1,9 +1,14 @@ - #!/usr/bin/env python3 -+""" Program to get a snapshot of a running instance of cyclictest """ - - # SPDX-License-Identifier: GPL-2.0-or-later - # Copyright (C) 2020 John Kacur - --import subprocess, signal, argparse, re, glob, sys -+import subprocess -+import argparse -+import re -+import glob -+import sys - - parser = argparse.ArgumentParser(description='Get a snapshot of running instances of cyclictest') - parser.add_argument('-l', '--list', action='store_true', help='list the main pid(s) of running instances of cyclictest') -@@ -11,8 +16,8 @@ parser.add_argument('-s', '--snapshot', nargs='*', metavar='pid', help='take a s - parser.add_argument('-p', '--print', nargs='*', metavar='pid', help='print the snapshots') - args = parser.parse_args() - -- - class Snapshot: -+ """ Class for getting a snapshot of a running cyclictest instance """ - - def __init__(self): - self.pids = [] -@@ -20,6 +25,7 @@ class Snapshot: - self.refresh() - - def refresh(self): -+ """ Create a list of running cyclictest instances. """ - self.pids = [] - self.shm_files = glob.glob('/dev/shm/cyclictest*') - self.shm_files.sort() -@@ -27,21 +33,21 @@ class Snapshot: - pid = re.search('[0-9]*$', shm_file).group() - self.pids += [pid] - -- # Send USR2 to all running instances of cyclictest or just to -- # a specific pid (spid) if specified - def take_snapshot(self, spids=None): -+ """ Send USR2 to all running instances of cyclictest, -+ or just to a specific pid (spids) if specified. """ - for pid in self.pids: -- if (spids == None) or (pid in spids): -- # print("kill -s USR2 ", pid) -+ if (spids is None) or (pid in spids): - subprocess.run(["kill", "-s", "USR2", pid]) - - def print_pids(self): -+ """ Print the list of pids of running cyclictest instances. """ - for pid in self.pids: - print(pid) - -- # Print the data in /dev/shm/cyclictest* - def print(self, spids=None): -- if spids == None: -+ """ Print the data in /dev/shm/cyclictest* """ -+ if spids is None: - for shm_file in self.shm_files: - with open(shm_file, 'r') as f: - data = f.read() -@@ -59,17 +65,17 @@ snapshot = Snapshot() - if args.list: - snapshot.print_pids() - --if args.snapshot != None: -- if len(args.snapshot) == 0: -- snapshot.take_snapshot() -- else: -+if args.snapshot is not None: -+ if args.snapshot: - snapshot.take_snapshot(args.snapshot) -- --if args.print != None: -- if len(args.print) == 0: -- snapshot.print() - else: -+ snapshot.take_snapshot() -+ -+if args.print is not None: -+ if args.print: - snapshot.print(args.print) -+ else: -+ snapshot.print() - - if len(sys.argv) == 1: - snapshot.take_snapshot() --- -2.21.3 - diff --git a/SOURCES/rt-tests-oslat-Allocate-memory-for-cpu_set.patch b/SOURCES/rt-tests-oslat-Allocate-memory-for-cpu_set.patch new file mode 100644 index 0000000..708e927 --- /dev/null +++ b/SOURCES/rt-tests-oslat-Allocate-memory-for-cpu_set.patch @@ -0,0 +1,47 @@ +From 5821269dde6a778b0af06c172bc2f19bbe324bda Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Fri, 12 Feb 2021 12:22:23 -0500 +Subject: [PATCH 3/3] rt-tests: oslat: Allocate memory for cpu_set + +- cpu_set is a pointer to a bitmask struct +Memory needs to be allocated for the struct, so call +numa_allocate_cpumask() + +- use rt-tests fatal to exit on error conditions + +Reviewed-by: Daniel Wagner +Signed-off-by: John Kacur +--- + src/oslat/oslat.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c +index 2fe550b3ee12..2a3be393a268 100644 +--- a/src/oslat/oslat.c ++++ b/src/oslat/oslat.c +@@ -727,6 +727,10 @@ int main(int argc, char *argv[]) + exit(1); + } + ++ cpu_set = numa_allocate_cpumask(); ++ if (!cpu_set) ++ fatal("oslat: Could not allocate cpumask\n"); ++ + g.app_name = argv[0]; + g.rtprio = 0; + g.bucket_size = BUCKET_SIZE; +@@ -742,8 +746,9 @@ int main(int argc, char *argv[]) + + if (!g.cpu_list) + g.cpu_list = strdup("all"); +- if (parse_cpumask(g.cpu_list, max_cpus, &cpu_set)) +- exit(1); ++ ++ if (parse_cpumask(g.cpu_list, max_cpus, &cpu_set) != 0) ++ fatal("oslat: parse_cpumask failed.\n"); + n_cores = numa_bitmask_weight(cpu_set); + + TEST(threads = calloc(1, n_cores * sizeof(threads[0]))); +-- +2.26.2 + diff --git a/SOURCES/rt-tests-oslat-Init-commit.patch b/SOURCES/rt-tests-oslat-Init-commit.patch deleted file mode 100644 index 60727a5..0000000 --- a/SOURCES/rt-tests-oslat-Init-commit.patch +++ /dev/null @@ -1,1043 +0,0 @@ -From c86dec5765e1ad0bd1d0c429ca7c138c11da2c80 Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Mon, 17 Aug 2020 17:55:05 -0400 -Subject: [PATCH 2/2] rt-tests: oslat: Init commit - -oslat was initially a standalone program [1]. This patch merges oslat into -rt-tests repo. - -This is a direct port of oslat v0.1.7 into rt-tests. It naturally bumps the -version to latest rt-tests version. - -[1] https://github.com/xzpeter/oslat - -Signed-off-by: Peter Xu -A few minor fixes to the grammar in the man page -Signed-off-by: John Kacur ---- - Makefile | 10 +- - src/oslat/oslat.8 | 66 ++++ - src/oslat/oslat.c | 896 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 970 insertions(+), 2 deletions(-) - create mode 100644 src/oslat/oslat.8 - create mode 100644 src/oslat/oslat.c - -diff --git a/Makefile b/Makefile -index be7831277c88..3f59efba2885 100644 ---- a/Makefile -+++ b/Makefile -@@ -17,7 +17,8 @@ sources = cyclictest.c \ - cyclicdeadline.c \ - deadline_test.c \ - queuelat.c \ -- ssdd.c -+ ssdd.c \ -+ oslat.c - - TARGETS = $(sources:.c=) - LIBS = -lrt -lpthread -@@ -48,7 +49,8 @@ MANPAGES = src/cyclictest/cyclictest.8 \ - src/sched_deadline/deadline_test.8 \ - src/ssdd/ssdd.8 \ - src/sched_deadline/cyclicdeadline.8 \ -- src/cyclictest/get_cyclictest_snapshot.8 -+ src/cyclictest/get_cyclictest_snapshot.8 \ -+ src/oslat/oslat.8 - - ifdef PYLIB - MANPAGES += src/hwlatdetect/hwlatdetect.8 -@@ -97,6 +99,7 @@ VPATH += src/hackbench: - VPATH += src/sched_deadline: - VPATH += src/queuelat: - VPATH += src/ssdd: -+VPATH += src/oslat: - - $(OBJDIR)/%.o: %.c | $(OBJDIR) - $(CC) -D VERSION=$(VERSION) -c $< $(CFLAGS) $(CPPFLAGS) -o $@ -@@ -164,6 +167,9 @@ queuelat: $(OBJDIR)/queuelat.o $(OBJDIR)/librttest.a - ssdd: $(OBJDIR)/ssdd.o $(OBJDIR)/librttest.a - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(RTTESTLIB) - -+oslat: $(OBJDIR)/oslat.o $(OBJDIR)/librttest.a -+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(RTTESTLIB) $(NUMA_LIBS) -+ - %.8.gz: %.8 - gzip -nc $< > $@ - -diff --git a/src/oslat/oslat.8 b/src/oslat/oslat.8 -new file mode 100644 -index 000000000000..85f2c5bcdf5c ---- /dev/null -+++ b/src/oslat/oslat.8 -@@ -0,0 +1,66 @@ -+.TH OSLAT 8 "August 17, 2020" -+.\" for manpage-specific macros, see man(7) -+.SH NAME -+oslat \- OS Latency Detector -+.SH SYNOPSIS -+.SY oslat -+.RI "[ \-shvz ] [ \-b " bucket-size " ] [ \-B " bias " ] [ \-c " cpu-list " ] \ -+[ \-C " cpu-main-thread " ] [ \-f " rt-prio " ] [ \-m " workload-mem " ] \ -+[\-t " runtime " ] [ \-T " trace-threshold " ] [ \-w " workload " ]" -+.SH DESCRIPTION -+.B oslat -+is an open source userspace polling mode stress program to detect OS level -+latency. The program runs a busy loop with no or various workloads, collecting -+TSC information and measuring the time frequently during the process. -+.SH OPTIONS -+.TP -+.B \-b, \-\-bucket-size=N -+Specify the number of the buckets (4-1024). -+.TP -+.B \-B, \-\-bias=USEC -+Add a bias to all the buckets using the estimated mininum. -+.TP -+.B \-c, \-\-cpu-list=CPULIST -+Specify CPUs to run on. For example, '1,3,5,7-15'. -+.TP -+.B \-C, \-\-cpu-main-thread=CORE -+Specify which CPU the main thread runs on. Default is cpu0. -+.TP -+.B \-f, \-\-rtprio=PRIORITY -+Using specific SCHED_FIFO priority (1-99). Otherwise use the default -+priority, normally it will be SCHED_OTHER. -+.TP -+.B \-m, \-\-workload-mem=SIZE -+Size of the memory to use for the workload (e.g., 4K, 1M). -+Total memory usage will be this value multiplies 2*N, -+because there will be src/dst buffers for each thread, and -+N is the number of processors for testing. -+.TP -+.B \-t, \-\-runtime=SEC -+Specify test duration, e.g., 60, 20m, 2H (m/M: minutes, h/H: hours, d/D: days). -+By default the unit is s/second. -+.TP -+.B \-T, \-\-trace-threshold=THRESHOLD -+Stop the test when threshold triggered (in USEC). At the meantime, print a -+marker in ftrace and stop ftrace too. -+.TP -+.B \-w, \-\-workload=WORKLOAD -+Specify a kind of workload, default is no workload. Options: "no", "memmove". -+.TP -+.B \-s, \-\-single-preheat -+Use a single thread when measuring latency at preheat stage -+NOTE: please make sure the CPU frequency on all testing cores -+are locked before using this parmater. If you don't know how -+to lock the freq then please don't use this parameter. -+.TP -+.B \-h, \-\-help -+Show the help message. -+.TP -+.B \-v, \-\-version -+Show the version of the program. -+.TP -+.B \-z, \-\-zero-omit -+Don't display buckets in the output histogram if all zeros. -+.SH AUTHOR -+.B oslat -+was written by Peter Xu . -diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c -new file mode 100644 -index 000000000000..d79691926247 ---- /dev/null -+++ b/src/oslat/oslat.c -@@ -0,0 +1,896 @@ -+/* -+ * oslat - OS latency detector -+ * -+ * Copyright 2020 Red Hat Inc. -+ * -+ * Authors: Peter Xu -+ * -+ * Some of the utility code based on sysjitter-1.3: -+ * Copyright 2010-2015 David Riddoch -+ * -+ * This program is free software: you can redistribute it and/or modify it -+ * under the terms of version 3 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "rt-utils.h" -+#include "error.h" -+ -+#ifdef __GNUC__ -+# define atomic_inc(ptr) __sync_add_and_fetch((ptr), 1) -+# if defined(__x86_64__) -+# define relax() __asm__ __volatile__("pause" ::: "memory") -+static inline void frc(uint64_t* pval) -+{ -+ uint32_t low, high; -+ /* See rdtsc_ordered() of Linux */ -+ __asm__ __volatile__("lfence"); -+ __asm__ __volatile__("rdtsc" : "=a" (low) , "=d" (high)); -+ *pval = ((uint64_t) high << 32) | low; -+} -+# elif defined(__i386__) -+# define relax() __asm__ __volatile__("pause" ::: "memory") -+static inline void frc(uint64_t* pval) -+{ -+ __asm__ __volatile__("rdtsc" : "=A" (*pval)); -+} -+# elif defined(__PPC64__) -+# define relax() do{}while(0) -+static inline void frc(uint64_t* pval) -+{ -+ __asm__ __volatile__("mfspr %0, 268\n" : "=r" (*pval)); -+} -+# else -+# error Need frc() for this platform. -+# endif -+#else -+# error Need to add support for this compiler. -+#endif -+ -+typedef uint64_t stamp_t; /* timestamp */ -+typedef uint64_t cycles_t; /* number of cycles */ -+typedef unsigned char bool; -+ -+#define true 1 -+#define false 0 -+ -+enum command { -+ WAIT, -+ GO, -+ STOP -+}; -+ -+enum workload_type { -+ WORKLOAD_NONE = 0, -+ WORKLOAD_MEMMOVE, -+ WORKLOAD_NUM, -+}; -+ -+/* This workload needs pre-allocated memory */ -+#define WORK_NEED_MEM (1UL << 0) -+ -+typedef void (*workload_fn)(char *src, char *dst, size_t size); -+ -+struct workload { -+ const char *w_name; -+ uint64_t w_flags; -+ workload_fn w_fn; -+}; -+ -+/* We'll have buckets 1us, 2us, ..., (BUCKET_SIZE) us. */ -+#define BUCKET_SIZE (32) -+ -+/* Default size of the workloads per thread (in bytes, which is 16KB) */ -+#define WORKLOAD_MEM_SIZE (16UL << 10) -+ -+/* By default, no workload */ -+#define WORKLOAD_DEFUALT WORKLOAD_NONE -+ -+struct thread { -+ int core_i; -+ pthread_t thread_id; -+ -+ /* NOTE! this is also how many ticks per us */ -+ unsigned cpu_mhz; -+ cycles_t int_total; -+ stamp_t frc_start; -+ stamp_t frc_stop; -+ cycles_t runtime; -+ stamp_t *buckets; -+ uint64_t minlat; -+ /* Maximum latency detected */ -+ uint64_t maxlat; -+ /* -+ * The extra part of the interruptions that cannot be put into even the -+ * biggest bucket. We'll use this to calculate a more accurate average at -+ * the end of the tests. -+ */ -+ uint64_t overflow_sum; -+ int memory_allocated; -+ -+ /* Buffers used for the workloads */ -+ char * src_buf; -+ char * dst_buf; -+ -+ /* These variables are calculated after the test */ -+ double average; -+}; -+ -+struct global { -+ /* Configuration. */ -+ unsigned runtime_secs; -+ /* Number of threads running for current test (either pre heat or real run) */ -+ unsigned n_threads; -+ /* Number of threads to test for the real run */ -+ unsigned n_threads_total; -+ struct timeval tv_start; -+ int rtprio; -+ int bucket_size; -+ int trace_threshold; -+ int runtime; -+ /* The core that we run the main thread. Default is cpu0 */ -+ int cpu_main_thread; -+ char * cpu_list; -+ char * app_name; -+ struct workload * workload; -+ uint64_t workload_mem_size; -+ int enable_bias; -+ uint64_t bias; -+ bool single_preheat_thread; -+ bool output_omit_zero_buckets; -+ -+ /* Mutable state. */ -+ volatile enum command cmd; -+ volatile unsigned n_threads_started; -+ volatile unsigned n_threads_ready; -+ volatile unsigned n_threads_running; -+ volatile unsigned n_threads_finished; -+}; -+ -+static struct global g; -+ -+static void workload_nop(char *dst, char *src, size_t size) -+{ -+ /* Nop */ -+} -+ -+static void workload_memmove(char *dst, char *src, size_t size) -+{ -+ memmove(dst, src, size); -+} -+ -+struct workload workload_list[WORKLOAD_NUM] = { -+ { "no", 0, workload_nop }, -+ { "memmove", WORK_NEED_MEM, workload_memmove }, -+}; -+ -+#define TEST(x) \ -+ do { \ -+ if( ! (x) ) \ -+ test_fail(#x, __LINE__); \ -+ } while( 0 ) -+ -+#define TEST0(x) TEST((x) == 0) -+ -+static void test_fail(const char* what, int line) -+{ -+ fprintf(stderr, "ERROR:\n"); -+ fprintf(stderr, "ERROR: TEST(%s)\n", what); -+ fprintf(stderr, "ERROR: at line %d\n", line); -+ fprintf(stderr, "ERROR: errno=%d (%s)\n", errno, strerror(errno)); -+ fprintf(stderr, "ERROR:\n"); -+ exit(1); -+} -+ -+static int move_to_core(int core_i) -+{ -+ cpu_set_t cpus; -+ CPU_ZERO(&cpus); -+ CPU_SET(core_i, &cpus); -+ return sched_setaffinity(0, sizeof(cpus), &cpus); -+} -+ -+static cycles_t __measure_cpu_hz(void) -+{ -+ struct timeval tvs, tve; -+ stamp_t s, e; -+ double sec; -+ -+ frc(&s); -+ e = s; -+ gettimeofday(&tvs, NULL); -+ while( e - s < 1000000 ) -+ frc(&e); -+ gettimeofday(&tve, NULL); -+ sec = tve.tv_sec - tvs.tv_sec + (tve.tv_usec - tvs.tv_usec) / 1e6; -+ return (cycles_t) ((e - s) / sec); -+} -+ -+static unsigned measure_cpu_mhz(void) -+{ -+ cycles_t m, mprev, d; -+ -+ mprev = __measure_cpu_hz(); -+ do { -+ m = __measure_cpu_hz(); -+ if( m > mprev ) d = m - mprev; -+ else d = mprev - m; -+ mprev = m; -+ } while( d > m / 1000 ); -+ -+ return (unsigned) (m / 1000000); -+} -+ -+static void thread_init(struct thread* t) -+{ -+ t->cpu_mhz = measure_cpu_mhz(); -+ t->maxlat = 0; -+ t->overflow_sum = 0; -+ t->minlat = (uint64_t)-1; -+ -+ /* NOTE: all the buffers are not freed until the process quits. */ -+ if (!t->memory_allocated) { -+ TEST(t->buckets = calloc(1, sizeof(t->buckets[0]) * g.bucket_size)); -+ if (g.workload->w_flags & WORK_NEED_MEM) { -+ TEST0(posix_memalign((void **)&t->src_buf, getpagesize(), -+ g.workload_mem_size)); -+ memset(t->src_buf, 0, g.workload_mem_size); -+ TEST0(posix_memalign((void **)&t->dst_buf, getpagesize(), -+ g.workload_mem_size)); -+ memset(t->dst_buf, 0, g.workload_mem_size); -+ } -+ t->memory_allocated = 1; -+ } else { -+ /* Clear the buckets */ -+ memset(t->buckets, 0, sizeof(t->buckets[0]) * g.bucket_size); -+ } -+} -+ -+static float cycles_to_sec(const struct thread* t, uint64_t cycles) -+{ -+ return cycles / (t->cpu_mhz * 1e6); -+} -+ -+static void insert_bucket(struct thread *t, stamp_t value) -+{ -+ int index, us; -+ uint64_t extra; -+ -+ index = value / t->cpu_mhz; -+ assert(index >= 0); -+ us = index + 1; -+ assert(us > 0); -+ -+ if (g.trace_threshold && us >= g.trace_threshold) { -+ char *line = "%s: Trace threshold (%d us) triggered with %u us! " -+ "Stopping the test.\n"; -+ tracemark(line, g.app_name, g.trace_threshold, us); -+ err_quit(line, g.app_name, g.trace_threshold, us); -+ } -+ -+ /* Update max latency */ -+ if (us > t->maxlat) { -+ t->maxlat = us; -+ } -+ -+ if (us < t->minlat) { -+ t->minlat = us; -+ } -+ -+ if (g.bias) { -+ /* t->bias will be set after pre-heat if user enabled it */ -+ us -= g.bias; -+ /* -+ * Negative should hardly happen, but if it happens, we assume we're in -+ * the smallest bucket, which is 1us. Same to index. -+ */ -+ if (us <= 0) { -+ us = 1; -+ } -+ index -= g.bias; -+ if (index < 0) { -+ index = 0; -+ } -+ } -+ -+ /* Too big the jitter; put into the last bucket */ -+ if (index >= g.bucket_size) { -+ /* Keep the extra bit (in us) */ -+ extra = index - g.bucket_size; -+ if (t->overflow_sum + extra < t->overflow_sum) { -+ /* The uint64_t even overflowed itself; bail out */ -+ printf("Accumulated overflow too much!\n"); -+ exit(1); -+ } -+ t->overflow_sum += extra; -+ index = g.bucket_size - 1; -+ } -+ -+ t->buckets[index]++; -+ if (t->buckets[index] == 0) { -+ printf("Bucket %d overflowed\n", index); -+ exit(1); -+ } -+} -+ -+static void doit(struct thread* t) -+{ -+ stamp_t ts1, ts2; -+ workload_fn workload_fn = g.workload->w_fn; -+ -+ frc(&ts2); -+ do { -+ workload_fn(t->dst_buf, t->src_buf, g.workload_mem_size); -+ frc(&ts1); -+ insert_bucket(t, ts1 - ts2); -+ ts2 = ts1; -+ } while (g.cmd == GO); -+} -+ -+static int set_fifo_prio(int prio) -+{ -+ struct sched_param param; -+ -+ memset(¶m, 0, sizeof(param)); -+ param.sched_priority = prio; -+ return sched_setscheduler(0, SCHED_FIFO, ¶m); -+} -+ -+static void* thread_main(void* arg) -+{ -+ /* Important thing to note here is that once we start bashing the CPU, we -+ * need to keep doing so to prevent the core from changing frequency or -+ * dropping into a low power state. -+ */ -+ struct thread* t = arg; -+ -+ /* Alloc memory in the thread itself after setting affinity to get the -+ * best chance of getting numa-local memory. Doesn't matter so much for -+ * the "struct thread" since we expect that to stay cache resident. -+ */ -+ TEST(move_to_core(t->core_i) == 0); -+ if (g.rtprio) -+ TEST(set_fifo_prio(g.rtprio) == 0); -+ -+ /* Don't bash the cpu until all threads have got going. */ -+ atomic_inc(&g.n_threads_started); -+ while( g.cmd == WAIT ) -+ usleep(1000); -+ -+ thread_init(t); -+ -+ /* Ensure we all start at the same time. */ -+ atomic_inc(&g.n_threads_running); -+ while( g.n_threads_running != g.n_threads ) -+ relax(); -+ -+ frc(&t->frc_start); -+ doit(t); -+ frc(&t->frc_stop); -+ -+ t->runtime = t->frc_stop - t->frc_start; -+ -+ /* Wait for everyone to finish so we don't disturb them by exiting and -+ * waking the main thread. -+ */ -+ atomic_inc(&g.n_threads_finished); -+ while( g.n_threads_finished != g.n_threads ) -+ relax(); -+ -+ return NULL; -+} -+ -+#define putfield(label, val, fmt, end) do { \ -+ printf("%12s:\t", label); \ -+ for (i = 0; i < g.n_threads; ++i) \ -+ printf(" %"fmt, val); \ -+ printf("%s\n", end); \ -+ } while (0) -+ -+void calculate(struct thread *t) -+{ -+ int i, j; -+ double sum; -+ uint64_t count; -+ -+ for (i = 0; i < g.n_threads; ++i) { -+ /* Calculate average */ -+ sum = count = 0; -+ for (j = 0; j < g.bucket_size; j++) { -+ sum += 1.0 * t[i].buckets[j] * (g.bias+j+1); -+ count += t[i].buckets[j]; -+ } -+ /* Add the extra amount of huge spikes in */ -+ sum += t->overflow_sum; -+ t[i].average = sum / count; -+ } -+} -+ -+static void write_summary(struct thread* t) -+{ -+ int i, j, k, print_dotdotdot = 0; -+ char bucket_name[64]; -+ -+ calculate(t); -+ -+ putfield("Core", t[i].core_i, "d", ""); -+ putfield("CPU Freq", t[i].cpu_mhz, "u", " (Mhz)"); -+ -+ for (j = 0; j < g.bucket_size; j++) { -+ if (j < g.bucket_size-1 && g.output_omit_zero_buckets) { -+ for (k = 0; k < g.n_threads; k++) { -+ if (t[k].buckets[j] != 0) -+ break; -+ } -+ if (k == g.n_threads) { -+ print_dotdotdot = 1; -+ continue; -+ } -+ } -+ -+ if (print_dotdotdot) { -+ printf(" ...\n"); -+ print_dotdotdot = 0; -+ } -+ -+ snprintf(bucket_name, sizeof(bucket_name), "%03"PRIu64 -+ " (us)", g.bias+j+1); -+ putfield(bucket_name, t[i].buckets[j], PRIu64, -+ (j==g.bucket_size-1) ? " (including overflows)" : ""); -+ } -+ -+ putfield("Minimum", t[i].minlat, PRIu64, " (us)"); -+ putfield("Average", t[i].average, ".3lf", " (us)"); -+ putfield("Maximum", t[i].maxlat, PRIu64, " (us)"); -+ putfield("Max-Min", t[i].maxlat - t[i].minlat, PRIu64, " (us)"); -+ putfield("Duration", cycles_to_sec(&(t[i]), t[i].runtime), -+ ".3f", " (sec)"); -+ printf("\n"); -+} -+ -+static void run_expt(struct thread* threads, int runtime_secs) -+{ -+ int i; -+ -+ g.runtime_secs = runtime_secs; -+ g.n_threads_started = 0; -+ g.n_threads_ready = 0; -+ g.n_threads_running = 0; -+ g.n_threads_finished = 0; -+ g.cmd = WAIT; -+ -+ for( i = 0; i < g.n_threads; ++i ) { -+ TEST0(pthread_create(&(threads[i].thread_id), NULL, -+ thread_main, &(threads[i]))); -+ } -+ while( g.n_threads_started != g.n_threads ) { -+ usleep(1000); -+ } -+ -+ gettimeofday(&g.tv_start, NULL); -+ g.cmd = GO; -+ -+ alarm(runtime_secs); -+ -+ /* Go to sleep until the threads have done their stuff. */ -+ for( i = 0; i < g.n_threads; ++i ) { -+ pthread_join(threads[i].thread_id, NULL); -+ } -+} -+ -+static void handle_alarm(int code) -+{ -+ g.cmd = STOP; -+} -+ -+const char *helpmsg = -+ "Usage: %s [options]\n" -+ "\n" -+ "This is an OS latency detector by running busy loops on specified cores.\n" -+ "Please run this tool using root.\n" -+ "\n" -+ "Available options:\n" -+ "\n" -+ " -b, --bucket-size Specify the number of the buckets (4-1024)\n" -+ " -B, --bias Add a bias to all the buckets using the estimated mininum\n" -+ " -c, --cpu-list Specify CPUs to run on, e.g. '1,3,5,7-15'\n" -+ " -C, --cpu-main-thread Specify which CPU the main thread runs on. Default is cpu0.\n" -+ " -f, --rtprio Using SCHED_FIFO priority (1-99)\n" -+ " -m, --workload-mem Size of the memory to use for the workload (e.g., 4K, 1M).\n" -+ " 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" -+ " -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" -+ " to lock the freq then please don't use this parameter.\n" -+ " -t, --runtime Specify test duration, e.g., 60, 20m, 2H\n" -+ " (m/M: minutes, h/H: hours, d/D: days)\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" -+ " -w, --workload Specify a kind of workload, default is no workload\n" -+ " (options: no, memmove)\n" -+ " -z, --zero-omit Don't display buckets in the output histogram if all zeros.\n" -+ "\n" -+ ; -+ -+static void usage(void) -+{ -+ printf(helpmsg, g.app_name); -+ exit(1); -+} -+ -+/* TODO: use libnuma? */ -+static int parse_cpu_list(char *cpu_list, cpu_set_t *cpu_set) -+{ -+ struct bitmask *cpu_mask; -+ int i, n_cores; -+ -+ n_cores = sysconf(_SC_NPROCESSORS_CONF); -+ -+ if (!cpu_list) { -+ for (i = 0; i < n_cores; i++) -+ CPU_SET(i, cpu_set); -+ return n_cores; -+ } -+ -+ cpu_mask = numa_parse_cpustring_all(cpu_list); -+ if (cpu_mask) { -+ for (i = 0; i < n_cores; i++) { -+ if (numa_bitmask_isbitset(cpu_mask, i)) { -+ CPU_SET(i, cpu_set); -+ } -+ } -+ numa_bitmask_free(cpu_mask); -+ } else { -+ warn("Unknown cpu-list: %s, using all available cpus\n", cpu_list); -+ for (i = 0; i < n_cores; i++) -+ CPU_SET(i, cpu_set); -+ } -+ -+ return n_cores; -+} -+ -+static int parse_runtime(const char *str) -+{ -+ char *endptr; -+ int v = strtol(str, &endptr, 10); -+ -+ if (!*endptr) { -+ return v; -+ } -+ -+ switch (*endptr) { -+ case 'd': -+ case 'D': -+ /* Days */ -+ v *= 24; -+ case 'h': -+ case 'H': -+ /* Hours */ -+ v *= 60; -+ case 'm': -+ case 'M': -+ /* Minutes */ -+ v *= 60; -+ case 's': -+ case 'S': -+ /* Seconds */ -+ break; -+ default: -+ printf("Unknown runtime suffix: %s\n", endptr); -+ v = 0; -+ break; -+ } -+ -+ return v; -+} -+ -+static int parse_mem_size(char *str, uint64_t *val) -+{ -+ char *endptr; -+ int v = strtol(str, &endptr, 10); -+ -+ if (!*endptr) { -+ return v; -+ } -+ -+ switch (*endptr) { -+ case 'g': -+ case 'G': -+ v *= 1024; -+ case 'm': -+ case 'M': -+ v *= 1024; -+ case 'k': -+ case 'K': -+ v *= 1024; -+ case 'b': -+ case 'B': -+ break; -+ default: -+ return -1; -+ } -+ -+ *val = v; -+ -+ return 0; -+} -+ -+static int workload_select(char *name) -+{ -+ int i = 0; -+ -+ for (i = 0; i < WORKLOAD_NUM; i++) { -+ if (!strcmp(name, workload_list[i].w_name)) { -+ g.workload = &workload_list[i]; -+ return 0; -+ } -+ } -+ -+ return -1; -+} -+ -+/* Process commandline options */ -+static void parse_options(int argc, char *argv[]) -+{ -+ while (1) { -+ static struct option options[] = { -+ { "bucket-size", required_argument, NULL, 'b' }, -+ { "cpu-list", required_argument, NULL, 'c' }, -+ { "cpu-main-thread", required_argument, NULL, 'C'}, -+ { "runtime", required_argument, NULL, 't' }, -+ { "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'}, -+ { NULL, 0, NULL, 0 }, -+ }; -+ int i, c = getopt_long(argc, argv, "b:Bc:C:f:hm:st:w:T:vz", -+ options, NULL); -+ long ncores; -+ -+ if (c == -1) -+ break; -+ -+ switch (c) { -+ case 'b': -+ g.bucket_size = strtol(optarg, NULL, 10); -+ if (g.bucket_size > 1024 || g.bucket_size <= 4) { -+ printf("Illegal bucket size: %s (should be: 4-1024)\n", -+ optarg); -+ exit(1); -+ } -+ break; -+ case 'B': -+ g.enable_bias = 1; -+ break; -+ case 'c': -+ g.cpu_list = strdup(optarg); -+ break; -+ case 'C': -+ ncores = sysconf(_SC_NPROCESSORS_CONF); -+ g.cpu_main_thread = strtol(optarg, NULL, 10); -+ if (g.cpu_main_thread < 0 || g.cpu_main_thread > ncores) { -+ printf("Illegal core for main thread: %s (should be: 0-%ld)\n", -+ optarg, ncores); -+ exit(1); -+ } -+ break; -+ case 't': -+ g.runtime = parse_runtime(optarg); -+ if (!g.runtime) { -+ printf("Illegal runtime: %s\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'f': -+ g.rtprio = strtol(optarg, NULL, 10); -+ if (g.rtprio < 1 || g.rtprio > 99) { -+ printf("Illegal RT priority: %s (should be: 1-99)\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'T': -+ g.trace_threshold = strtol(optarg, NULL, 10); -+ if (g.trace_threshold <= 0) { -+ printf("Parameter --trace-threshold needs to be positive\n"); -+ exit(1); -+ } -+ enable_trace_mark(); -+ break; -+ case 'w': -+ if (workload_select(optarg)) { -+ printf("Unknown workload '%s'. Please choose from: ", optarg); -+ for (i = 0; i < WORKLOAD_NUM; i++) { -+ printf("'%s'", workload_list[i].w_name); -+ if (i != WORKLOAD_NUM - 1) { -+ printf(", "); -+ } -+ } -+ printf("\n\n"); -+ exit(1); -+ } -+ break; -+ case 'm': -+ if (parse_mem_size(optarg, &g.workload_mem_size)) { -+ printf("Unknown workload memory size '%s'.\n\n", optarg); -+ exit(1); -+ } -+ break; -+ case 's': -+ /* -+ * Only use one core for pre-heat. Then if --bias is used, the -+ * bias will be exactly the min value of the pre-heat core. -+ */ -+ g.single_preheat_thread = true; -+ break; -+ case 'v': -+ /* -+ * Because we always dump the version even before parsing options, -+ * what we need to do is to quit.. -+ */ -+ exit(0); -+ break; -+ case 'z': -+ g.output_omit_zero_buckets = 1; -+ break; -+ default: -+ usage(); -+ break; -+ } -+ } -+} -+ -+void dump_globals(void) -+{ -+ printf("Total runtime: \t\t%d seconds\n", g.runtime); -+ printf("Thread priority: \t"); -+ if (g.rtprio) { -+ printf("SCHED_FIFO:%d\n", g.rtprio); -+ } else { -+ printf("default\n"); -+ } -+ printf("CPU list: \t\t%s\n", g.cpu_list ?: "(all cores)"); -+ printf("CPU for main thread: \t%d\n", g.cpu_main_thread); -+ printf("Workload: \t\t%s\n", g.workload->w_name); -+ printf("Workload mem: \t\t%"PRIu64" (KiB)\n", -+ (g.workload->w_flags & WORK_NEED_MEM) ? -+ (g.workload_mem_size / 1024) : 0); -+ printf("Preheat cores: \t\t%d\n", g.single_preheat_thread ? -+ 1 : g.n_threads_total); -+ printf("\n"); -+} -+ -+static void record_bias(struct thread *t) -+{ -+ int i; -+ uint64_t bias = (uint64_t)-1; -+ -+ if (!g.enable_bias) { -+ return; -+ } -+ -+ /* Record the min value of minlat on all the threads */ -+ for( i = 0; i < g.n_threads; ++i ) { -+ if (t[i].minlat < bias) { -+ bias = t[i].minlat; -+ } -+ } -+ g.bias = bias; -+ printf("Global bias set to %" PRId64 " (us)\n", bias); -+} -+ -+int main(int argc, char* argv[]) -+{ -+ struct thread* threads; -+ int i, n_cores; -+ cpu_set_t cpu_set; -+ -+ CPU_ZERO(&cpu_set); -+ -+ g.app_name = argv[0]; -+ g.rtprio = 0; -+ g.bucket_size = BUCKET_SIZE; -+ g.runtime = 1; -+ g.workload = &workload_list[WORKLOAD_DEFUALT]; -+ g.workload_mem_size = WORKLOAD_MEM_SIZE; -+ /* Run the main thread on cpu0 by default */ -+ g.cpu_main_thread = 0; -+ -+ printf("\nVersion: %1.2f\n\n", VERSION); -+ -+ parse_options(argc, argv); -+ -+ TEST(mlockall(MCL_CURRENT | MCL_FUTURE) == 0); -+ -+ n_cores = parse_cpu_list(g.cpu_list, &cpu_set); -+ -+ TEST( threads = calloc(1, CPU_COUNT(&cpu_set) * sizeof(threads[0])) ); -+ for( i = 0; i < n_cores; ++i ) -+ if (CPU_ISSET(i, &cpu_set) && move_to_core(i) == 0) -+ threads[g.n_threads_total++].core_i = i; -+ -+ if (CPU_ISSET(0, &cpu_set) && g.rtprio) { -+ printf("WARNING: Running SCHED_FIFO workload on CPU 0 " -+ "may hang the main thread\n"); -+ } -+ -+ TEST(move_to_core(g.cpu_main_thread) == 0); -+ -+ signal(SIGALRM, handle_alarm); -+ signal(SIGINT, handle_alarm); -+ signal(SIGTERM, handle_alarm); -+ -+ dump_globals(); -+ -+ printf("Pre-heat for 1 seconds...\n"); -+ if (g.single_preheat_thread) { -+ g.n_threads = 1; -+ } else { -+ g.n_threads = g.n_threads_total; -+ } -+ run_expt(threads, 1); -+ record_bias(threads); -+ -+ 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"); -+ -+ write_summary(threads); -+ -+ if (g.cpu_list) { -+ free(g.cpu_list); -+ g.cpu_list = NULL; -+ } -+ -+ return 0; -+} --- -2.26.2 - diff --git a/SOURCES/rt-tests-oslat-Proper-reformat-of-code.patch b/SOURCES/rt-tests-oslat-Proper-reformat-of-code.patch deleted file mode 100644 index fb8fb70..0000000 --- a/SOURCES/rt-tests-oslat-Proper-reformat-of-code.patch +++ /dev/null @@ -1,1526 +0,0 @@ -From 8dad377d0e54c3e31da50deb55cd7c257e542d8f Mon Sep 17 00:00:00 2001 -From: Peter Xu -Date: Wed, 19 Aug 2020 16:19:40 -0400 -Subject: [PATCH] rt-tests: oslat: Proper reformat of code - -Format the code with kernel coding style. Meanwhile use spdx license -identifier as suggested by John. - -Signed-off-by: Peter Xu -Signed-off-by: John Kacur ---- - src/oslat/oslat.c | 1323 ++++++++++++++++++++++----------------------- - 1 file changed, 649 insertions(+), 674 deletions(-) - -diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c -index d79691926247..f1a82f2367d2 100644 ---- a/src/oslat/oslat.c -+++ b/src/oslat/oslat.c -@@ -1,3 +1,4 @@ -+// SPDX-License-Identifier: GPL-3.0-only - /* - * oslat - OS latency detector - * -@@ -7,18 +8,6 @@ - * - * Some of the utility code based on sysjitter-1.3: - * Copyright 2010-2015 David Riddoch -- * -- * This program is free software: you can redistribute it and/or modify it -- * under the terms of version 3 of the GNU General Public License as -- * published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, but -- * WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- * General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License along -- * with this program. If not, see . - */ - - #include -@@ -59,25 +48,25 @@ - # define atomic_inc(ptr) __sync_add_and_fetch((ptr), 1) - # if defined(__x86_64__) - # define relax() __asm__ __volatile__("pause" ::: "memory") --static inline void frc(uint64_t* pval) -+static inline void frc(uint64_t *pval) - { -- uint32_t low, high; -- /* See rdtsc_ordered() of Linux */ -- __asm__ __volatile__("lfence"); -- __asm__ __volatile__("rdtsc" : "=a" (low) , "=d" (high)); -- *pval = ((uint64_t) high << 32) | low; -+ uint32_t low, high; -+ /* See rdtsc_ordered() of Linux */ -+ __asm__ __volatile__("lfence"); -+ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)); -+ *pval = ((uint64_t) high << 32) | low; - } - # elif defined(__i386__) - # define relax() __asm__ __volatile__("pause" ::: "memory") --static inline void frc(uint64_t* pval) -+static inline void frc(uint64_t *pval) - { -- __asm__ __volatile__("rdtsc" : "=A" (*pval)); -+ __asm__ __volatile__("rdtsc" : "=A" (*pval)); - } - # elif defined(__PPC64__) --# define relax() do{}while(0) --static inline void frc(uint64_t* pval) -+# define relax() do { } while (0) -+static inline void frc(uint64_t *pval) - { -- __asm__ __volatile__("mfspr %0, 268\n" : "=r" (*pval)); -+ __asm__ __volatile__("mfspr %0, 268\n" : "=r" (*pval)); - } - # else - # error Need frc() for this platform. -@@ -88,21 +77,20 @@ static inline void frc(uint64_t* pval) - - typedef uint64_t stamp_t; /* timestamp */ - typedef uint64_t cycles_t; /* number of cycles */ --typedef unsigned char bool; - - #define true 1 - #define false 0 - - enum command { -- WAIT, -- GO, -- STOP -+ WAIT, -+ GO, -+ STOP - }; - - enum workload_type { -- WORKLOAD_NONE = 0, -- WORKLOAD_MEMMOVE, -- WORKLOAD_NUM, -+ WORKLOAD_NONE = 0, -+ WORKLOAD_MEMMOVE, -+ WORKLOAD_NUM, - }; - - /* This workload needs pre-allocated memory */ -@@ -111,9 +99,9 @@ enum workload_type { - typedef void (*workload_fn)(char *src, char *dst, size_t size); - - struct workload { -- const char *w_name; -- uint64_t w_flags; -- workload_fn w_fn; -+ const char *w_name; -+ uint64_t w_flags; -+ workload_fn w_fn; - }; - - /* We'll have buckets 1us, 2us, ..., (BUCKET_SIZE) us. */ -@@ -123,774 +111,761 @@ struct workload { - #define WORKLOAD_MEM_SIZE (16UL << 10) - - /* By default, no workload */ --#define WORKLOAD_DEFUALT WORKLOAD_NONE -+#define WORKLOAD_DEFAULT WORKLOAD_NONE - - struct thread { -- int core_i; -- pthread_t thread_id; -- -- /* NOTE! this is also how many ticks per us */ -- unsigned cpu_mhz; -- cycles_t int_total; -- stamp_t frc_start; -- stamp_t frc_stop; -- cycles_t runtime; -- stamp_t *buckets; -- uint64_t minlat; -- /* Maximum latency detected */ -- uint64_t maxlat; -- /* -- * The extra part of the interruptions that cannot be put into even the -- * biggest bucket. We'll use this to calculate a more accurate average at -- * the end of the tests. -- */ -- uint64_t overflow_sum; -- int memory_allocated; -- -- /* Buffers used for the workloads */ -- char * src_buf; -- char * dst_buf; -- -- /* These variables are calculated after the test */ -- double average; -+ int core_i; -+ pthread_t thread_id; -+ -+ /* NOTE! this is also how many ticks per us */ -+ unsigned int cpu_mhz; -+ cycles_t int_total; -+ stamp_t frc_start; -+ stamp_t frc_stop; -+ cycles_t runtime; -+ stamp_t *buckets; -+ uint64_t minlat; -+ /* Maximum latency detected */ -+ uint64_t maxlat; -+ /* -+ * The extra part of the interruptions that cannot be put into even the -+ * biggest bucket. We'll use this to calculate a more accurate average at -+ * the end of the tests. -+ */ -+ uint64_t overflow_sum; -+ int memory_allocated; -+ -+ /* Buffers used for the workloads */ -+ char *src_buf; -+ char *dst_buf; -+ -+ /* These variables are calculated after the test */ -+ double average; - }; - - struct global { -- /* Configuration. */ -- unsigned runtime_secs; -- /* Number of threads running for current test (either pre heat or real run) */ -- unsigned n_threads; -- /* Number of threads to test for the real run */ -- unsigned n_threads_total; -- struct timeval tv_start; -- int rtprio; -- int bucket_size; -- int trace_threshold; -- int runtime; -- /* The core that we run the main thread. Default is cpu0 */ -- int cpu_main_thread; -- char * cpu_list; -- char * app_name; -- struct workload * workload; -- uint64_t workload_mem_size; -- int enable_bias; -- uint64_t bias; -- bool single_preheat_thread; -- bool output_omit_zero_buckets; -- -- /* Mutable state. */ -- volatile enum command cmd; -- volatile unsigned n_threads_started; -- volatile unsigned n_threads_ready; -- volatile unsigned n_threads_running; -- volatile unsigned n_threads_finished; -+ /* Configuration. */ -+ unsigned int runtime_secs; -+ /* -+ * Number of threads running for current test -+ * (either pre heat or real run) -+ */ -+ unsigned int n_threads; -+ /* Number of threads to test for the real run */ -+ unsigned int n_threads_total; -+ struct timeval tv_start; -+ int rtprio; -+ int bucket_size; -+ int trace_threshold; -+ int runtime; -+ /* The core that we run the main thread. Default is cpu0 */ -+ int cpu_main_thread; -+ char *cpu_list; -+ char *app_name; -+ struct workload *workload; -+ uint64_t workload_mem_size; -+ int enable_bias; -+ uint64_t bias; -+ int single_preheat_thread; -+ int output_omit_zero_buckets; -+ -+ /* Mutable state. */ -+ volatile enum command cmd; -+ volatile unsigned int n_threads_started; -+ volatile unsigned int n_threads_running; -+ volatile unsigned int n_threads_finished; - }; - - static struct global g; - - static void workload_nop(char *dst, char *src, size_t size) - { -- /* Nop */ -+ /* Nop */ - } - - static void workload_memmove(char *dst, char *src, size_t size) - { -- memmove(dst, src, size); -+ memmove(dst, src, size); - } - - struct workload workload_list[WORKLOAD_NUM] = { -- { "no", 0, workload_nop }, -- { "memmove", WORK_NEED_MEM, workload_memmove }, -+ { "no", 0, workload_nop }, -+ { "memmove", WORK_NEED_MEM, workload_memmove }, - }; - --#define TEST(x) \ -- do { \ -- if( ! (x) ) \ -- test_fail(#x, __LINE__); \ -- } while( 0 ) -+#define TEST(x) \ -+ do { \ -+ if (!(x)) \ -+ test_fail(#x, __LINE__); \ -+ } while (0) - - #define TEST0(x) TEST((x) == 0) - --static void test_fail(const char* what, int line) -+static void test_fail(const char *what, int line) - { -- fprintf(stderr, "ERROR:\n"); -- fprintf(stderr, "ERROR: TEST(%s)\n", what); -- fprintf(stderr, "ERROR: at line %d\n", line); -- fprintf(stderr, "ERROR: errno=%d (%s)\n", errno, strerror(errno)); -- fprintf(stderr, "ERROR:\n"); -- exit(1); -+ fprintf(stderr, "ERROR:\n"); -+ fprintf(stderr, "ERROR: TEST(%s)\n", what); -+ fprintf(stderr, "ERROR: at line %d\n", line); -+ fprintf(stderr, "ERROR: errno=%d (%s)\n", errno, strerror(errno)); -+ fprintf(stderr, "ERROR:\n"); -+ exit(1); - } - - static int move_to_core(int core_i) - { -- cpu_set_t cpus; -- CPU_ZERO(&cpus); -- CPU_SET(core_i, &cpus); -- return sched_setaffinity(0, sizeof(cpus), &cpus); -+ cpu_set_t cpus; -+ -+ CPU_ZERO(&cpus); -+ CPU_SET(core_i, &cpus); -+ return sched_setaffinity(0, sizeof(cpus), &cpus); - } - - static cycles_t __measure_cpu_hz(void) - { -- struct timeval tvs, tve; -- stamp_t s, e; -- double sec; -- -- frc(&s); -- e = s; -- gettimeofday(&tvs, NULL); -- while( e - s < 1000000 ) -- frc(&e); -- gettimeofday(&tve, NULL); -- sec = tve.tv_sec - tvs.tv_sec + (tve.tv_usec - tvs.tv_usec) / 1e6; -- return (cycles_t) ((e - s) / sec); -+ struct timeval tvs, tve; -+ stamp_t s, e; -+ double sec; -+ -+ frc(&s); -+ e = s; -+ gettimeofday(&tvs, NULL); -+ while (e - s < 1000000) -+ frc(&e); -+ gettimeofday(&tve, NULL); -+ sec = tve.tv_sec - tvs.tv_sec + (tve.tv_usec - tvs.tv_usec) / 1e6; -+ return (cycles_t) ((e - s) / sec); - } - --static unsigned measure_cpu_mhz(void) -+static unsigned int measure_cpu_mhz(void) - { -- cycles_t m, mprev, d; -- -- mprev = __measure_cpu_hz(); -- do { -- m = __measure_cpu_hz(); -- if( m > mprev ) d = m - mprev; -- else d = mprev - m; -- mprev = m; -- } while( d > m / 1000 ); -- -- return (unsigned) (m / 1000000); -+ cycles_t m, mprev, d; -+ -+ mprev = __measure_cpu_hz(); -+ do { -+ m = __measure_cpu_hz(); -+ if (m > mprev) -+ d = m - mprev; -+ else -+ d = mprev - m; -+ mprev = m; -+ } while (d > m / 1000); -+ -+ return (unsigned int) (m / 1000000); - } - --static void thread_init(struct thread* t) -+static void thread_init(struct thread *t) - { -- t->cpu_mhz = measure_cpu_mhz(); -- t->maxlat = 0; -- t->overflow_sum = 0; -- t->minlat = (uint64_t)-1; -- -- /* NOTE: all the buffers are not freed until the process quits. */ -- if (!t->memory_allocated) { -- TEST(t->buckets = calloc(1, sizeof(t->buckets[0]) * g.bucket_size)); -- if (g.workload->w_flags & WORK_NEED_MEM) { -- TEST0(posix_memalign((void **)&t->src_buf, getpagesize(), -- g.workload_mem_size)); -- memset(t->src_buf, 0, g.workload_mem_size); -- TEST0(posix_memalign((void **)&t->dst_buf, getpagesize(), -- g.workload_mem_size)); -- memset(t->dst_buf, 0, g.workload_mem_size); -- } -- t->memory_allocated = 1; -- } else { -- /* Clear the buckets */ -- memset(t->buckets, 0, sizeof(t->buckets[0]) * g.bucket_size); -- } -+ t->cpu_mhz = measure_cpu_mhz(); -+ t->maxlat = 0; -+ t->overflow_sum = 0; -+ t->minlat = (uint64_t)-1; -+ -+ /* NOTE: all the buffers are not freed until the process quits. */ -+ if (!t->memory_allocated) { -+ TEST(t->buckets = calloc(1, sizeof(t->buckets[0]) * g.bucket_size)); -+ if (g.workload->w_flags & WORK_NEED_MEM) { -+ TEST0(posix_memalign((void **)&t->src_buf, getpagesize(), -+ g.workload_mem_size)); -+ memset(t->src_buf, 0, g.workload_mem_size); -+ TEST0(posix_memalign((void **)&t->dst_buf, getpagesize(), -+ g.workload_mem_size)); -+ memset(t->dst_buf, 0, g.workload_mem_size); -+ } -+ t->memory_allocated = 1; -+ } else { -+ /* Clear the buckets */ -+ memset(t->buckets, 0, sizeof(t->buckets[0]) * g.bucket_size); -+ } - } - --static float cycles_to_sec(const struct thread* t, uint64_t cycles) -+static float cycles_to_sec(const struct thread *t, uint64_t cycles) - { -- return cycles / (t->cpu_mhz * 1e6); -+ return cycles / (t->cpu_mhz * 1e6); - } - - static void insert_bucket(struct thread *t, stamp_t value) - { -- int index, us; -- uint64_t extra; -- -- index = value / t->cpu_mhz; -- assert(index >= 0); -- us = index + 1; -- assert(us > 0); -- -- if (g.trace_threshold && us >= g.trace_threshold) { -- char *line = "%s: Trace threshold (%d us) triggered with %u us! " -- "Stopping the test.\n"; -- tracemark(line, g.app_name, g.trace_threshold, us); -- err_quit(line, g.app_name, g.trace_threshold, us); -- } -- -- /* Update max latency */ -- if (us > t->maxlat) { -- t->maxlat = us; -- } -- -- if (us < t->minlat) { -- t->minlat = us; -- } -- -- if (g.bias) { -- /* t->bias will be set after pre-heat if user enabled it */ -- us -= g.bias; -- /* -- * Negative should hardly happen, but if it happens, we assume we're in -- * the smallest bucket, which is 1us. Same to index. -- */ -- if (us <= 0) { -- us = 1; -- } -- index -= g.bias; -- if (index < 0) { -- index = 0; -- } -- } -- -- /* Too big the jitter; put into the last bucket */ -- if (index >= g.bucket_size) { -- /* Keep the extra bit (in us) */ -- extra = index - g.bucket_size; -- if (t->overflow_sum + extra < t->overflow_sum) { -- /* The uint64_t even overflowed itself; bail out */ -- printf("Accumulated overflow too much!\n"); -- exit(1); -- } -- t->overflow_sum += extra; -- index = g.bucket_size - 1; -- } -- -- t->buckets[index]++; -- if (t->buckets[index] == 0) { -- printf("Bucket %d overflowed\n", index); -- exit(1); -- } -+ int index, us; -+ uint64_t extra; -+ -+ index = value / t->cpu_mhz; -+ assert(index >= 0); -+ us = index + 1; -+ assert(us > 0); -+ -+ if (g.trace_threshold && us >= g.trace_threshold) { -+ char *line = "%s: Trace threshold (%d us) triggered with %u us!\n" -+ "Stopping the test.\n"; -+ tracemark(line, g.app_name, g.trace_threshold, us); -+ err_quit(line, g.app_name, g.trace_threshold, us); -+ } -+ -+ /* Update max latency */ -+ if (us > t->maxlat) -+ t->maxlat = us; -+ -+ if (us < t->minlat) -+ t->minlat = us; -+ -+ if (g.bias) { -+ /* t->bias will be set after pre-heat if user enabled it */ -+ us -= g.bias; -+ /* -+ * Negative should hardly happen, but if it happens, we assume we're in -+ * the smallest bucket, which is 1us. Same to index. -+ */ -+ if (us <= 0) -+ us = 1; -+ index -= g.bias; -+ if (index < 0) -+ index = 0; -+ } -+ -+ /* Too big the jitter; put into the last bucket */ -+ if (index >= g.bucket_size) { -+ /* Keep the extra bit (in us) */ -+ extra = index - g.bucket_size; -+ if (t->overflow_sum + extra < t->overflow_sum) { -+ /* The uint64_t even overflowed itself; bail out */ -+ printf("Accumulated overflow too much!\n"); -+ exit(1); -+ } -+ t->overflow_sum += extra; -+ index = g.bucket_size - 1; -+ } -+ -+ t->buckets[index]++; -+ if (t->buckets[index] == 0) { -+ printf("Bucket %d overflowed\n", index); -+ exit(1); -+ } - } - --static void doit(struct thread* t) -+static void doit(struct thread *t) - { -- stamp_t ts1, ts2; -- workload_fn workload_fn = g.workload->w_fn; -- -- frc(&ts2); -- do { -- workload_fn(t->dst_buf, t->src_buf, g.workload_mem_size); -- frc(&ts1); -- insert_bucket(t, ts1 - ts2); -- ts2 = ts1; -- } while (g.cmd == GO); -+ stamp_t ts1, ts2; -+ workload_fn workload_fn = g.workload->w_fn; -+ -+ frc(&ts2); -+ do { -+ workload_fn(t->dst_buf, t->src_buf, g.workload_mem_size); -+ frc(&ts1); -+ insert_bucket(t, ts1 - ts2); -+ ts2 = ts1; -+ } while (g.cmd == GO); - } - - static int set_fifo_prio(int prio) - { -- struct sched_param param; -+ struct sched_param param; - -- memset(¶m, 0, sizeof(param)); -- param.sched_priority = prio; -- return sched_setscheduler(0, SCHED_FIFO, ¶m); -+ memset(¶m, 0, sizeof(param)); -+ param.sched_priority = prio; -+ return sched_setscheduler(0, SCHED_FIFO, ¶m); - } - --static void* thread_main(void* arg) -+static void *thread_main(void *arg) - { -- /* Important thing to note here is that once we start bashing the CPU, we -- * need to keep doing so to prevent the core from changing frequency or -- * dropping into a low power state. -- */ -- struct thread* t = arg; -- -- /* Alloc memory in the thread itself after setting affinity to get the -- * best chance of getting numa-local memory. Doesn't matter so much for -- * the "struct thread" since we expect that to stay cache resident. -- */ -- TEST(move_to_core(t->core_i) == 0); -- if (g.rtprio) -- TEST(set_fifo_prio(g.rtprio) == 0); -- -- /* Don't bash the cpu until all threads have got going. */ -- atomic_inc(&g.n_threads_started); -- while( g.cmd == WAIT ) -- usleep(1000); -- -- thread_init(t); -- -- /* Ensure we all start at the same time. */ -- atomic_inc(&g.n_threads_running); -- while( g.n_threads_running != g.n_threads ) -- relax(); -- -- frc(&t->frc_start); -- doit(t); -- frc(&t->frc_stop); -- -- t->runtime = t->frc_stop - t->frc_start; -- -- /* Wait for everyone to finish so we don't disturb them by exiting and -- * waking the main thread. -- */ -- atomic_inc(&g.n_threads_finished); -- while( g.n_threads_finished != g.n_threads ) -- relax(); -- -- return NULL; -+ /* Important thing to note here is that once we start bashing the CPU, we -+ * need to keep doing so to prevent the core from changing frequency or -+ * dropping into a low power state. -+ */ -+ struct thread *t = arg; -+ -+ /* Alloc memory in the thread itself after setting affinity to get the -+ * best chance of getting numa-local memory. Doesn't matter so much for -+ * the "struct thread" since we expect that to stay cache resident. -+ */ -+ TEST(move_to_core(t->core_i) == 0); -+ if (g.rtprio) -+ TEST(set_fifo_prio(g.rtprio) == 0); -+ -+ /* Don't bash the cpu until all threads have got going. */ -+ atomic_inc(&g.n_threads_started); -+ while (g.cmd == WAIT) -+ usleep(1000); -+ -+ thread_init(t); -+ -+ /* Ensure we all start at the same time. */ -+ atomic_inc(&g.n_threads_running); -+ while (g.n_threads_running != g.n_threads) -+ relax(); -+ -+ frc(&t->frc_start); -+ doit(t); -+ frc(&t->frc_stop); -+ -+ t->runtime = t->frc_stop - t->frc_start; -+ -+ /* Wait for everyone to finish so we don't disturb them by exiting and -+ * waking the main thread. -+ */ -+ atomic_inc(&g.n_threads_finished); -+ while (g.n_threads_finished != g.n_threads) -+ relax(); -+ -+ return NULL; - } - --#define putfield(label, val, fmt, end) do { \ -- printf("%12s:\t", label); \ -- for (i = 0; i < g.n_threads; ++i) \ -- printf(" %"fmt, val); \ -- printf("%s\n", end); \ -- } while (0) -+#define putfield(label, val, fmt, end) do { \ -+ printf("%12s:\t", label); \ -+ for (i = 0; i < g.n_threads; ++i) \ -+ printf(" %"fmt, val); \ -+ printf("%s\n", end); \ -+ } while (0) - - void calculate(struct thread *t) - { -- int i, j; -- double sum; -- uint64_t count; -- -- for (i = 0; i < g.n_threads; ++i) { -- /* Calculate average */ -- sum = count = 0; -- for (j = 0; j < g.bucket_size; j++) { -- sum += 1.0 * t[i].buckets[j] * (g.bias+j+1); -- count += t[i].buckets[j]; -- } -- /* Add the extra amount of huge spikes in */ -- sum += t->overflow_sum; -- t[i].average = sum / count; -- } -+ int i, j; -+ double sum; -+ uint64_t count; -+ -+ for (i = 0; i < g.n_threads; ++i) { -+ /* Calculate average */ -+ sum = count = 0; -+ for (j = 0; j < g.bucket_size; j++) { -+ sum += 1.0 * t[i].buckets[j] * (g.bias+j+1); -+ count += t[i].buckets[j]; -+ } -+ /* Add the extra amount of huge spikes in */ -+ sum += t->overflow_sum; -+ t[i].average = sum / count; -+ } - } - --static void write_summary(struct thread* t) -+static void write_summary(struct thread *t) - { -- int i, j, k, print_dotdotdot = 0; -- char bucket_name[64]; -- -- calculate(t); -- -- putfield("Core", t[i].core_i, "d", ""); -- putfield("CPU Freq", t[i].cpu_mhz, "u", " (Mhz)"); -- -- for (j = 0; j < g.bucket_size; j++) { -- if (j < g.bucket_size-1 && g.output_omit_zero_buckets) { -- for (k = 0; k < g.n_threads; k++) { -- if (t[k].buckets[j] != 0) -- break; -- } -- if (k == g.n_threads) { -- print_dotdotdot = 1; -- continue; -- } -- } -- -- if (print_dotdotdot) { -- printf(" ...\n"); -- print_dotdotdot = 0; -- } -- -- snprintf(bucket_name, sizeof(bucket_name), "%03"PRIu64 -- " (us)", g.bias+j+1); -- putfield(bucket_name, t[i].buckets[j], PRIu64, -- (j==g.bucket_size-1) ? " (including overflows)" : ""); -- } -- -- putfield("Minimum", t[i].minlat, PRIu64, " (us)"); -- putfield("Average", t[i].average, ".3lf", " (us)"); -- putfield("Maximum", t[i].maxlat, PRIu64, " (us)"); -- putfield("Max-Min", t[i].maxlat - t[i].minlat, PRIu64, " (us)"); -- putfield("Duration", cycles_to_sec(&(t[i]), t[i].runtime), -- ".3f", " (sec)"); -- printf("\n"); -+ int i, j, k, print_dotdotdot = 0; -+ char bucket_name[64]; -+ -+ calculate(t); -+ -+ putfield("Core", t[i].core_i, "d", ""); -+ putfield("CPU Freq", t[i].cpu_mhz, "u", " (Mhz)"); -+ -+ for (j = 0; j < g.bucket_size; j++) { -+ if (j < g.bucket_size-1 && g.output_omit_zero_buckets) { -+ for (k = 0; k < g.n_threads; k++) { -+ if (t[k].buckets[j] != 0) -+ break; -+ } -+ if (k == g.n_threads) { -+ print_dotdotdot = 1; -+ continue; -+ } -+ } -+ -+ if (print_dotdotdot) { -+ printf(" ...\n"); -+ print_dotdotdot = 0; -+ } -+ -+ snprintf(bucket_name, sizeof(bucket_name), "%03"PRIu64 -+ " (us)", g.bias+j+1); -+ putfield(bucket_name, t[i].buckets[j], PRIu64, -+ (j == g.bucket_size - 1) ? " (including overflows)" : ""); -+ } -+ -+ putfield("Minimum", t[i].minlat, PRIu64, " (us)"); -+ putfield("Average", t[i].average, ".3lf", " (us)"); -+ putfield("Maximum", t[i].maxlat, PRIu64, " (us)"); -+ putfield("Max-Min", t[i].maxlat - t[i].minlat, PRIu64, " (us)"); -+ putfield("Duration", cycles_to_sec(&(t[i]), t[i].runtime), -+ ".3f", " (sec)"); -+ printf("\n"); - } - --static void run_expt(struct thread* threads, int runtime_secs) -+static void run_expt(struct thread *threads, int runtime_secs) - { -- int i; -- -- g.runtime_secs = runtime_secs; -- g.n_threads_started = 0; -- g.n_threads_ready = 0; -- g.n_threads_running = 0; -- g.n_threads_finished = 0; -- g.cmd = WAIT; -- -- for( i = 0; i < g.n_threads; ++i ) { -- TEST0(pthread_create(&(threads[i].thread_id), NULL, -- thread_main, &(threads[i]))); -- } -- while( g.n_threads_started != g.n_threads ) { -- usleep(1000); -- } -- -- gettimeofday(&g.tv_start, NULL); -- g.cmd = GO; -- -- alarm(runtime_secs); -- -- /* Go to sleep until the threads have done their stuff. */ -- for( i = 0; i < g.n_threads; ++i ) { -- pthread_join(threads[i].thread_id, NULL); -- } -+ int i; -+ -+ g.runtime_secs = runtime_secs; -+ g.n_threads_started = 0; -+ g.n_threads_running = 0; -+ g.n_threads_finished = 0; -+ g.cmd = WAIT; -+ -+ for (i = 0; i < g.n_threads; ++i) -+ TEST0(pthread_create(&(threads[i].thread_id), NULL, -+ thread_main, &(threads[i]))); -+ while (g.n_threads_started != g.n_threads) -+ usleep(1000); -+ -+ gettimeofday(&g.tv_start, NULL); -+ g.cmd = GO; -+ -+ alarm(runtime_secs); -+ -+ /* Go to sleep until the threads have done their stuff. */ -+ for (i = 0; i < g.n_threads; ++i) -+ pthread_join(threads[i].thread_id, NULL); - } - - static void handle_alarm(int code) - { -- g.cmd = STOP; -+ g.cmd = STOP; - } - - const char *helpmsg = -- "Usage: %s [options]\n" -- "\n" -- "This is an OS latency detector by running busy loops on specified cores.\n" -- "Please run this tool using root.\n" -- "\n" -- "Available options:\n" -- "\n" -- " -b, --bucket-size Specify the number of the buckets (4-1024)\n" -- " -B, --bias Add a bias to all the buckets using the estimated mininum\n" -- " -c, --cpu-list Specify CPUs to run on, e.g. '1,3,5,7-15'\n" -- " -C, --cpu-main-thread Specify which CPU the main thread runs on. Default is cpu0.\n" -- " -f, --rtprio Using SCHED_FIFO priority (1-99)\n" -- " -m, --workload-mem Size of the memory to use for the workload (e.g., 4K, 1M).\n" -- " 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" -- " -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" -- " to lock the freq then please don't use this parameter.\n" -- " -t, --runtime Specify test duration, e.g., 60, 20m, 2H\n" -- " (m/M: minutes, h/H: hours, d/D: days)\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" -- " -w, --workload Specify a kind of workload, default is no workload\n" -- " (options: no, memmove)\n" -- " -z, --zero-omit Don't display buckets in the output histogram if all zeros.\n" -- "\n" -- ; -+"Usage: %s [options]\n" -+"\n" -+"This is an OS latency detector by running busy loops on specified cores.\n" -+"Please run this tool using root.\n" -+"\n" -+"Available options:\n" -+"\n" -+" -b, --bucket-size Specify the number of the buckets (4-1024)\n" -+" -B, --bias Add a bias to all the buckets using the estimated mininum\n" -+" -c, --cpu-list Specify CPUs to run on, e.g. '1,3,5,7-15'\n" -+" -C, --cpu-main-thread Specify which CPU the main thread runs on. Default is cpu0.\n" -+" -f, --rtprio Using SCHED_FIFO priority (1-99)\n" -+" -m, --workload-mem Size of the memory to use for the workload (e.g., 4K, 1M).\n" -+" 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" -+" -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" -+" to lock the freq then please don't use this parameter.\n" -+" -t, --runtime Specify test duration, e.g., 60, 20m, 2H\n" -+" (m/M: minutes, h/H: hours, d/D: days)\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" -+" -w, --workload Specify a kind of workload, default is no workload\n" -+" (options: no, memmove)\n" -+" -z, --zero-omit Don't display buckets in the output histogram if all zeros.\n" -+"\n" -+; - - static void usage(void) - { -- printf(helpmsg, g.app_name); -- exit(1); -+ printf(helpmsg, g.app_name); -+ exit(1); - } - - /* TODO: use libnuma? */ - static int parse_cpu_list(char *cpu_list, cpu_set_t *cpu_set) - { -- struct bitmask *cpu_mask; -- int i, n_cores; -- -- n_cores = sysconf(_SC_NPROCESSORS_CONF); -- -- if (!cpu_list) { -- for (i = 0; i < n_cores; i++) -- CPU_SET(i, cpu_set); -- return n_cores; -- } -- -- cpu_mask = numa_parse_cpustring_all(cpu_list); -- if (cpu_mask) { -- for (i = 0; i < n_cores; i++) { -- if (numa_bitmask_isbitset(cpu_mask, i)) { -- CPU_SET(i, cpu_set); -- } -- } -- numa_bitmask_free(cpu_mask); -- } else { -- warn("Unknown cpu-list: %s, using all available cpus\n", cpu_list); -- for (i = 0; i < n_cores; i++) -- CPU_SET(i, cpu_set); -- } -- -- return n_cores; -+ struct bitmask *cpu_mask; -+ int i, n_cores; -+ -+ n_cores = sysconf(_SC_NPROCESSORS_CONF); -+ -+ if (!cpu_list) { -+ for (i = 0; i < n_cores; i++) -+ CPU_SET(i, cpu_set); -+ return n_cores; -+ } -+ -+ cpu_mask = numa_parse_cpustring_all(cpu_list); -+ if (cpu_mask) { -+ for (i = 0; i < n_cores; i++) { -+ if (numa_bitmask_isbitset(cpu_mask, i)) -+ CPU_SET(i, cpu_set); -+ } -+ numa_bitmask_free(cpu_mask); -+ } else { -+ warn("Unknown cpu-list: %s, using all available cpus\n", cpu_list); -+ for (i = 0; i < n_cores; i++) -+ CPU_SET(i, cpu_set); -+ } -+ -+ return n_cores; - } - - static int parse_runtime(const char *str) - { -- char *endptr; -- int v = strtol(str, &endptr, 10); -- -- if (!*endptr) { -- return v; -- } -- -- switch (*endptr) { -- case 'd': -- case 'D': -- /* Days */ -- v *= 24; -- case 'h': -- case 'H': -- /* Hours */ -- v *= 60; -- case 'm': -- case 'M': -- /* Minutes */ -- v *= 60; -- case 's': -- case 'S': -- /* Seconds */ -- break; -- default: -- printf("Unknown runtime suffix: %s\n", endptr); -- v = 0; -- break; -- } -- -- return v; -+ char *endptr; -+ int v = strtol(str, &endptr, 10); -+ -+ if (!*endptr) -+ return v; -+ -+ switch (*endptr) { -+ case 'd': -+ case 'D': -+ /* Days */ -+ v *= 24; -+ case 'h': -+ case 'H': -+ /* Hours */ -+ v *= 60; -+ case 'm': -+ case 'M': -+ /* Minutes */ -+ v *= 60; -+ case 's': -+ case 'S': -+ /* Seconds */ -+ break; -+ default: -+ printf("Unknown runtime suffix: %s\n", endptr); -+ v = 0; -+ break; -+ } -+ -+ return v; - } - - static int parse_mem_size(char *str, uint64_t *val) - { -- char *endptr; -- int v = strtol(str, &endptr, 10); -- -- if (!*endptr) { -- return v; -- } -- -- switch (*endptr) { -- case 'g': -- case 'G': -- v *= 1024; -- case 'm': -- case 'M': -- v *= 1024; -- case 'k': -- case 'K': -- v *= 1024; -- case 'b': -- case 'B': -- break; -- default: -- return -1; -- } -- -- *val = v; -- -- return 0; -+ char *endptr; -+ int v = strtol(str, &endptr, 10); -+ -+ if (!*endptr) -+ return v; -+ -+ switch (*endptr) { -+ case 'g': -+ case 'G': -+ v *= 1024; -+ case 'm': -+ case 'M': -+ v *= 1024; -+ case 'k': -+ case 'K': -+ v *= 1024; -+ case 'b': -+ case 'B': -+ break; -+ default: -+ return -1; -+ } -+ -+ *val = v; -+ -+ return 0; - } - - static int workload_select(char *name) - { -- int i = 0; -+ int i = 0; - -- for (i = 0; i < WORKLOAD_NUM; i++) { -- if (!strcmp(name, workload_list[i].w_name)) { -- g.workload = &workload_list[i]; -- return 0; -- } -- } -+ for (i = 0; i < WORKLOAD_NUM; i++) { -+ if (!strcmp(name, workload_list[i].w_name)) { -+ g.workload = &workload_list[i]; -+ return 0; -+ } -+ } - -- return -1; -+ return -1; - } - - /* Process commandline options */ - static void parse_options(int argc, char *argv[]) - { -- while (1) { -- static struct option options[] = { -- { "bucket-size", required_argument, NULL, 'b' }, -- { "cpu-list", required_argument, NULL, 'c' }, -- { "cpu-main-thread", required_argument, NULL, 'C'}, -- { "runtime", required_argument, NULL, 't' }, -- { "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'}, -- { NULL, 0, NULL, 0 }, -- }; -- int i, c = getopt_long(argc, argv, "b:Bc:C:f:hm:st:w:T:vz", -- options, NULL); -- long ncores; -- -- if (c == -1) -- break; -- -- switch (c) { -- case 'b': -- g.bucket_size = strtol(optarg, NULL, 10); -- if (g.bucket_size > 1024 || g.bucket_size <= 4) { -- printf("Illegal bucket size: %s (should be: 4-1024)\n", -- optarg); -- exit(1); -- } -- break; -- case 'B': -- g.enable_bias = 1; -- break; -- case 'c': -- g.cpu_list = strdup(optarg); -- break; -- case 'C': -- ncores = sysconf(_SC_NPROCESSORS_CONF); -- g.cpu_main_thread = strtol(optarg, NULL, 10); -- if (g.cpu_main_thread < 0 || g.cpu_main_thread > ncores) { -- printf("Illegal core for main thread: %s (should be: 0-%ld)\n", -- optarg, ncores); -- exit(1); -- } -- break; -- case 't': -- g.runtime = parse_runtime(optarg); -- if (!g.runtime) { -- printf("Illegal runtime: %s\n", optarg); -- exit(1); -- } -- break; -- case 'f': -- g.rtprio = strtol(optarg, NULL, 10); -- if (g.rtprio < 1 || g.rtprio > 99) { -- printf("Illegal RT priority: %s (should be: 1-99)\n", optarg); -- exit(1); -- } -- break; -- case 'T': -- g.trace_threshold = strtol(optarg, NULL, 10); -- if (g.trace_threshold <= 0) { -- printf("Parameter --trace-threshold needs to be positive\n"); -- exit(1); -- } -- enable_trace_mark(); -- break; -- case 'w': -- if (workload_select(optarg)) { -- printf("Unknown workload '%s'. Please choose from: ", optarg); -- for (i = 0; i < WORKLOAD_NUM; i++) { -- printf("'%s'", workload_list[i].w_name); -- if (i != WORKLOAD_NUM - 1) { -- printf(", "); -- } -- } -- printf("\n\n"); -- exit(1); -- } -- break; -- case 'm': -- if (parse_mem_size(optarg, &g.workload_mem_size)) { -- printf("Unknown workload memory size '%s'.\n\n", optarg); -- exit(1); -- } -- break; -- case 's': -- /* -- * Only use one core for pre-heat. Then if --bias is used, the -- * bias will be exactly the min value of the pre-heat core. -- */ -- g.single_preheat_thread = true; -- break; -- case 'v': -- /* -- * Because we always dump the version even before parsing options, -- * what we need to do is to quit.. -- */ -- exit(0); -- break; -- case 'z': -- g.output_omit_zero_buckets = 1; -- break; -- default: -- usage(); -- break; -- } -- } -+ while (1) { -+ static struct option options[] = { -+ { "bucket-size", required_argument, NULL, 'b' }, -+ { "cpu-list", required_argument, NULL, 'c' }, -+ { "cpu-main-thread", required_argument, NULL, 'C'}, -+ { "runtime", required_argument, NULL, 't' }, -+ { "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'}, -+ { NULL, 0, NULL, 0 }, -+ }; -+ int i, c = getopt_long(argc, argv, "b:Bc:C:f:hm:st:w:T:vz", -+ options, NULL); -+ long ncores; -+ -+ if (c == -1) -+ break; -+ -+ switch (c) { -+ case 'b': -+ g.bucket_size = strtol(optarg, NULL, 10); -+ if (g.bucket_size > 1024 || g.bucket_size <= 4) { -+ printf("Illegal bucket size: %s (should be: 4-1024)\n", -+ optarg); -+ exit(1); -+ } -+ break; -+ case 'B': -+ g.enable_bias = 1; -+ break; -+ case 'c': -+ g.cpu_list = strdup(optarg); -+ break; -+ case 'C': -+ ncores = sysconf(_SC_NPROCESSORS_CONF); -+ g.cpu_main_thread = strtol(optarg, NULL, 10); -+ if (g.cpu_main_thread < 0 || g.cpu_main_thread > ncores) { -+ printf("Illegal core for main thread: %s (should be: 0-%ld)\n", -+ optarg, ncores); -+ exit(1); -+ } -+ break; -+ case 't': -+ g.runtime = parse_runtime(optarg); -+ if (!g.runtime) { -+ printf("Illegal runtime: %s\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'f': -+ g.rtprio = strtol(optarg, NULL, 10); -+ if (g.rtprio < 1 || g.rtprio > 99) { -+ printf("Illegal RT priority: %s (should be: 1-99)\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'T': -+ g.trace_threshold = strtol(optarg, NULL, 10); -+ if (g.trace_threshold <= 0) { -+ printf("Parameter --trace-threshold needs to be positive\n"); -+ exit(1); -+ } -+ enable_trace_mark(); -+ break; -+ case 'w': -+ if (workload_select(optarg)) { -+ printf("Unknown workload '%s'. Please choose from: ", optarg); -+ for (i = 0; i < WORKLOAD_NUM; i++) { -+ printf("'%s'", workload_list[i].w_name); -+ if (i != WORKLOAD_NUM - 1) -+ printf(", "); -+ } -+ printf("\n\n"); -+ exit(1); -+ } -+ break; -+ case 'm': -+ if (parse_mem_size(optarg, &g.workload_mem_size)) { -+ printf("Unknown workload memory size '%s'.\n\n", optarg); -+ exit(1); -+ } -+ break; -+ case 's': -+ /* -+ * Only use one core for pre-heat. Then if --bias is used, the -+ * bias will be exactly the min value of the pre-heat core. -+ */ -+ g.single_preheat_thread = true; -+ break; -+ case 'v': -+ /* -+ * Because we always dump the version even before parsing options, -+ * what we need to do is to quit.. -+ */ -+ exit(0); -+ break; -+ case 'z': -+ g.output_omit_zero_buckets = 1; -+ break; -+ default: -+ usage(); -+ break; -+ } -+ } - } - - void dump_globals(void) - { -- printf("Total runtime: \t\t%d seconds\n", g.runtime); -- printf("Thread priority: \t"); -- if (g.rtprio) { -- printf("SCHED_FIFO:%d\n", g.rtprio); -- } else { -- printf("default\n"); -- } -- printf("CPU list: \t\t%s\n", g.cpu_list ?: "(all cores)"); -- printf("CPU for main thread: \t%d\n", g.cpu_main_thread); -- printf("Workload: \t\t%s\n", g.workload->w_name); -- printf("Workload mem: \t\t%"PRIu64" (KiB)\n", -- (g.workload->w_flags & WORK_NEED_MEM) ? -- (g.workload_mem_size / 1024) : 0); -- printf("Preheat cores: \t\t%d\n", g.single_preheat_thread ? -- 1 : g.n_threads_total); -- printf("\n"); -+ printf("Total runtime: \t\t%d seconds\n", g.runtime); -+ printf("Thread priority: \t"); -+ if (g.rtprio) -+ printf("SCHED_FIFO:%d\n", g.rtprio); -+ else -+ printf("default\n"); -+ printf("CPU list: \t\t%s\n", g.cpu_list ?: "(all cores)"); -+ printf("CPU for main thread: \t%d\n", g.cpu_main_thread); -+ printf("Workload: \t\t%s\n", g.workload->w_name); -+ printf("Workload mem: \t\t%"PRIu64" (KiB)\n", -+ (g.workload->w_flags & WORK_NEED_MEM) ? -+ (g.workload_mem_size / 1024) : 0); -+ printf("Preheat cores: \t\t%d\n", g.single_preheat_thread ? -+ 1 : g.n_threads_total); -+ printf("\n"); - } - - static void record_bias(struct thread *t) - { -- int i; -- uint64_t bias = (uint64_t)-1; -- -- if (!g.enable_bias) { -- return; -- } -- -- /* Record the min value of minlat on all the threads */ -- for( i = 0; i < g.n_threads; ++i ) { -- if (t[i].minlat < bias) { -- bias = t[i].minlat; -- } -- } -- g.bias = bias; -- printf("Global bias set to %" PRId64 " (us)\n", bias); -+ int i; -+ uint64_t bias = (uint64_t)-1; -+ -+ if (!g.enable_bias) -+ return; -+ -+ /* Record the min value of minlat on all the threads */ -+ for (i = 0; i < g.n_threads; ++i) { -+ if (t[i].minlat < bias) -+ bias = t[i].minlat; -+ } -+ g.bias = bias; -+ printf("Global bias set to %" PRId64 " (us)\n", bias); - } - --int main(int argc, char* argv[]) -+int main(int argc, char *argv[]) - { -- struct thread* threads; -- int i, n_cores; -- cpu_set_t cpu_set; -+ struct thread *threads; -+ int i, n_cores; -+ cpu_set_t cpu_set; - -- CPU_ZERO(&cpu_set); -+ CPU_ZERO(&cpu_set); - -- g.app_name = argv[0]; -- g.rtprio = 0; -- g.bucket_size = BUCKET_SIZE; -- g.runtime = 1; -- g.workload = &workload_list[WORKLOAD_DEFUALT]; -- g.workload_mem_size = WORKLOAD_MEM_SIZE; -- /* Run the main thread on cpu0 by default */ -- g.cpu_main_thread = 0; -+ g.app_name = argv[0]; -+ g.rtprio = 0; -+ g.bucket_size = BUCKET_SIZE; -+ g.runtime = 1; -+ g.workload = &workload_list[WORKLOAD_DEFAULT]; -+ g.workload_mem_size = WORKLOAD_MEM_SIZE; -+ /* Run the main thread on cpu0 by default */ -+ g.cpu_main_thread = 0; - -- printf("\nVersion: %1.2f\n\n", VERSION); -+ printf("\nVersion: %1.2f\n\n", VERSION); - -- parse_options(argc, argv); -+ parse_options(argc, argv); - -- TEST(mlockall(MCL_CURRENT | MCL_FUTURE) == 0); -+ TEST(mlockall(MCL_CURRENT | MCL_FUTURE) == 0); - -- n_cores = parse_cpu_list(g.cpu_list, &cpu_set); -+ n_cores = parse_cpu_list(g.cpu_list, &cpu_set); - -- TEST( threads = calloc(1, CPU_COUNT(&cpu_set) * sizeof(threads[0])) ); -- for( i = 0; i < n_cores; ++i ) -- if (CPU_ISSET(i, &cpu_set) && move_to_core(i) == 0) -- threads[g.n_threads_total++].core_i = i; -+ TEST(threads = calloc(1, CPU_COUNT(&cpu_set) * sizeof(threads[0]))); -+ for (i = 0; i < n_cores; ++i) -+ if (CPU_ISSET(i, &cpu_set) && move_to_core(i) == 0) -+ threads[g.n_threads_total++].core_i = i; - -- if (CPU_ISSET(0, &cpu_set) && g.rtprio) { -- printf("WARNING: Running SCHED_FIFO workload on CPU 0 " -- "may hang the main thread\n"); -- } -+ if (CPU_ISSET(0, &cpu_set) && g.rtprio) -+ printf("WARNING: Running SCHED_FIFO workload on CPU 0 may hang the thread\n"); - -- TEST(move_to_core(g.cpu_main_thread) == 0); -+ TEST(move_to_core(g.cpu_main_thread) == 0); - -- signal(SIGALRM, handle_alarm); -- signal(SIGINT, handle_alarm); -- signal(SIGTERM, handle_alarm); -+ signal(SIGALRM, handle_alarm); -+ signal(SIGINT, handle_alarm); -+ signal(SIGTERM, handle_alarm); - -- dump_globals(); -+ dump_globals(); - -- printf("Pre-heat for 1 seconds...\n"); -- if (g.single_preheat_thread) { -- g.n_threads = 1; -- } else { -- g.n_threads = g.n_threads_total; -- } -- run_expt(threads, 1); -- record_bias(threads); -+ printf("Pre-heat for 1 seconds...\n"); -+ if (g.single_preheat_thread) -+ g.n_threads = 1; -+ else -+ g.n_threads = g.n_threads_total; -+ run_expt(threads, 1); -+ record_bias(threads); - -- 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 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"); -+ printf("Test completed.\n\n"); - -- write_summary(threads); -+ write_summary(threads); - -- if (g.cpu_list) { -- free(g.cpu_list); -- g.cpu_list = NULL; -- } -+ if (g.cpu_list) { -+ free(g.cpu_list); -+ g.cpu_list = NULL; -+ } - -- return 0; -+ return 0; - } --- -2.26.2 - diff --git a/SOURCES/rt-tests-oslat-print-version-string.patch b/SOURCES/rt-tests-oslat-print-version-string.patch new file mode 100644 index 0000000..ee1fd6b --- /dev/null +++ b/SOURCES/rt-tests-oslat-print-version-string.patch @@ -0,0 +1,54 @@ +From 2f4d564fb5557f7a420c183ddd3938647c231a8c Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Wed, 10 Feb 2021 22:18:41 -0500 +Subject: [PATCH 1/3] rt-tests: oslat: print version string + +During the streamlining of the command line options something went awry +with the version. The author of oslat wishes to always print the version +string. This allows us to just exit in the case of -v + +Fixes e411219d27b1 + +Reported-by: Pradipta Kumar Sahoo +Reported-by: Reported-by: Peter Xu + +Signed-off-by: John Kacur +--- + src/oslat/oslat.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c +index 5b7e0d5b5d5c..7826c277f26d 100644 +--- a/src/oslat/oslat.c ++++ b/src/oslat/oslat.c +@@ -512,7 +512,6 @@ static void handle_alarm(int code) + + static void usage(int error) + { +- printf("oslat V %1.2f\n", VERSION); + printf("Usage:\n" + "oslat \n\n" + "This is an OS latency detector by running busy loops on specified cores.\n" +@@ -657,8 +656,8 @@ static void parse_options(int argc, char *argv[]) + break; + case 'v': + /* +- * Because we always dump the version even before parsing options, +- * what we need to do is to quit.. ++ * We always print the version before parsing options ++ * so just exit + */ + exit(0); + break; +@@ -736,7 +735,7 @@ int main(int argc, char *argv[]) + g.workload_mem_size = WORKLOAD_MEM_SIZE; + /* Run the main thread on cpu0 by default */ + g.cpu_main_thread = 0; +- ++ printf("oslat V %1.2f\n", VERSION); + parse_options(argc, argv); + + TEST(mlockall(MCL_CURRENT | MCL_FUTURE) == 0); +-- +2.26.2 + diff --git a/SOURCES/rt-tests-pi_stress.8-Remove-unused-t-n-from-the-manp.patch b/SOURCES/rt-tests-pi_stress.8-Remove-unused-t-n-from-the-manp.patch deleted file mode 100644 index 17aba2f..0000000 --- a/SOURCES/rt-tests-pi_stress.8-Remove-unused-t-n-from-the-manp.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 868ee948b626dced91bb98207ebd6b3a52f9fcfc Mon Sep 17 00:00:00 2001 -From: John Kacur -Date: Fri, 3 Jul 2020 13:28:39 -0400 -Subject: [PATCH 2/7] rt-tests: pi_stress.8: Remove unused -t n from the - manpage - -The -t option was replaced with the -D, --duration=TIME option -Remove it from the manpage as well. - -Signed-off-by: John Kacur ---- - src/pi_tests/pi_stress.8 | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/src/pi_tests/pi_stress.8 b/src/pi_tests/pi_stress.8 -index 5e2af6189ca1..ed03ad6187e7 100644 ---- a/src/pi_tests/pi_stress.8 -+++ b/src/pi_tests/pi_stress.8 -@@ -15,8 +15,6 @@ pi_stress \- a stress test for POSIX Priority Inheritance mutexes - .B pi_stress - .RB [ \-i|\-\-inversions - .IR inversions ] --.RB [ \-t|\-\-duration --.IR seconds ] - .RB [ \-g|\-\-groups - .IR groups - .RB [ \-d|\-\-debug ] -@@ -50,10 +48,6 @@ Run for - .I n - number of inversion conditions. This is the total number of inversions - for all inversion groups. Default is \-1 for infinite. --.IP "\-t n|\-\-duration=n" --Run the test for --.I n --seconds and then terminate. - .IP "\-g n|\-\-groups=n" - The number of inversion groups to run. Defaults to 10. - .IP \-d|\-\-debug --- -2.21.3 - diff --git a/SOURCES/rt-tests-ptsematest.8-Update-the-ptsematest-man-page.patch b/SOURCES/rt-tests-ptsematest.8-Update-the-ptsematest-man-page.patch deleted file mode 100644 index 566d8c7..0000000 --- a/SOURCES/rt-tests-ptsematest.8-Update-the-ptsematest-man-page.patch +++ /dev/null @@ -1,41 +0,0 @@ -From e554f3d5d95330ba0b961bc7e7ecf3a19485b1c9 Mon Sep 17 00:00:00 2001 -From: John Kacur -Date: Fri, 3 Jul 2020 19:15:41 -0400 -Subject: [PATCH 3/7] rt-tests: ptsematest.8: Update the ptsematest man page - -The smp option should be a capital (-S) -Also fix the update synopsis to include missing and options - -Signed-off-by: John Kacur ---- - src/ptsematest/ptsematest.8 | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/ptsematest/ptsematest.8 b/src/ptsematest/ptsematest.8 -index 8f76bca4b6a8..5ee7d694d50d 100644 ---- a/src/ptsematest/ptsematest.8 -+++ b/src/ptsematest/ptsematest.8 -@@ -2,9 +2,9 @@ - .SH "NAME" - .LP - \fBptsematest\fR \- Start two threads and measure the latency of interprocess communication with POSIX mutex. --.SH "SYNTAX" -+.SH "SYNOPSIS" - .LP --ptsematest [-a|-a PROC] [-b USEC] [-d DIST] [-i INTV] [-l loops] [-p PRIO] [-t|-t NUM] -+ptsematest [-a|--affinity [PROC]] [-b|--breaktrace USEC] [-d|--distance DIST] [-D|--duration TIME][-i|--interval INTV] [-l|--loops LOOPS] [-p|--prio PRIO] [-S|--smp] [-t|--threads [NUM]] - .br - .SH "DESCRIPTION" - .LP -@@ -35,7 +35,7 @@ Set the number of loops. The default is 0 (endless). This option is useful for a - .B \-p, \-\-prio=PRIO - Set the priority of the process. - .TP --.B \-s, \-\-smp -+.B \-S, \-\-smp - SMP testing: options -a -t and same priority - .TP - .B \-t, \-\-threads[=NUM] --- -2.21.3 - diff --git a/SOURCES/rt-tests-queuelat-Fix-storing-unsigned-long-long-int.patch b/SOURCES/rt-tests-queuelat-Fix-storing-unsigned-long-long-int.patch deleted file mode 100644 index c3be1d2..0000000 --- a/SOURCES/rt-tests-queuelat-Fix-storing-unsigned-long-long-int.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 41a3f9e53920d50b48c04593bfa3eb0e87fcf49f Mon Sep 17 00:00:00 2001 -From: John Kacur -Date: Tue, 12 May 2020 11:02:39 -0400 -Subject: [PATCH] rt-tests: queuelat: Fix storing unsigned long long in int - -queuelat can occassionally hang because of overflow mixing -unsigned long long and int - -Attaching to process 173912 -Reading symbols from /root/rt-tests/queuelat...done. -Reading symbols from /lib64/librt.so.1...Reading symbols from /usr/lib/debug/usr/lib64/librt-2.28.so.debug...done. -done. -Reading symbols from /lib64/libpthread.so.0...Reading symbols from /usr/lib/debug/usr/lib64/libpthread-2.28.so.debug...done. -done. -[Thread debugging using libthread_db enabled] -Using host libthread_db library "/lib64/libthread_db.so.1". -Reading symbols from /lib64/libc.so.6...Reading symbols from /usr/lib/debug/usr/lib64/libc-2.28.so.debug...done. -done. -Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/usr/lib64/ld-2.28.so.debug...done. -done. -__memmove_avx_unaligned_erms () - at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:254 -254 rep movsb -(gdb) c -Continuing. - -Program received signal SIGSEGV, Segmentation fault. -0x0000000000400c02 in account (val=18446744071562067968) - at src/queuelat/queuelat.c:93 -93 buckets[bucket_nr]++; -(gdb) bt full - at src/queuelat/queuelat.c:93 - bucket_nr = -193273529 - a = 825932047802952 - b = 825925371232340 - dest = 0xf322b0 - src = 0xf4e3f0 - i = 45749 - delta = -2147483648 - loops = 50000 - time = 6500 - bucket_nr = 65 - n = 115000 - delta = 3500 - at src/queuelat/queuelat.c:671 - tsc_freq_mhz = 2398.5039999999999 - max_queue_len_f = 159.900284 - mvalue = 0x7ffc99d3021c "20000" - cvalue = 0x7ffc99d30225 "300" - pvalue = 0x7ffc99d30238 "6.1" - fvalue = 0x7ffc99d3022c "2398.504" - tvalue = 0x7ffc99d3023f "30" - qvalue = 0x0 - index = 0 - c = -1 - -Fix the above by declaring delta as an unsigned long long - -Signed-off-by: John Kacur ---- - src/queuelat/queuelat.c | 11 +++++------ - 1 file changed, 5 insertions(+), 6 deletions(-) - -diff --git a/src/queuelat/queuelat.c b/src/queuelat/queuelat.c -index 7e5e35768a8b..22b68a84d6ae 100644 ---- a/src/queuelat/queuelat.c -+++ b/src/queuelat/queuelat.c -@@ -354,9 +354,9 @@ static void trace_write(char *buf, int len) - - static void run_n(int n) - { -- u64 a, b; -+ u64 a, b, delta; - void *dest, *src; -- int i, delta, loops = 50000; -+ int i, loops = 50000; - - init_buckets(); - -@@ -445,9 +445,8 @@ static void print_exit_info(void) - - void main_loop(void) - { -- u64 a, b; -+ u64 a, b, delta; - void *dest, *src; -- int delta; - int queue_size = 0; - - trace_open(); -@@ -500,7 +499,7 @@ void main_loop(void) - continue; - - ret = sprintf(buf, "memmove block queue_size=%d queue_dec=%d" -- " queue_inc=%d delta=%d ns\n", queue_size, -+ " queue_inc=%d delta=%llu ns\n", queue_size, - nr_packets_drain_per_block, - nr_packets_fill, delta); - trace_write(buf, ret); -@@ -536,7 +535,7 @@ static void install_signals(void) - - int calculate_nr_packets_drain_per_block(void) - { -- int maxcount; -+ unsigned long long maxcount; - int i, time; - int found = 0; - int bucket_nr = find_highest_count_bucket(); --- -2.21.3 - diff --git a/SPECS/rt-tests.spec b/SPECS/rt-tests.spec index c5c45e3..c798bc2 100644 --- a/SPECS/rt-tests.spec +++ b/SPECS/rt-tests.spec @@ -5,8 +5,8 @@ Name: rt-tests # BuildRequires: numactl-devel # Numa argument to make: NUMA=1 # -Version: 1.8 -Release: 11%{?dist} +Version: 1.10 +Release: 3%{?dist} License: GPLv2 Group: Development/Tools URL: git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git @@ -14,25 +14,17 @@ Source0: https://www.kernel.org/pub/linux/utils/rt-tests/%{name}-%{version}.tar. BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root ExclusiveArch: x86_64 -BuildRequires: numactl-devel python3-devel +BuildRequires: gcc +BuildRequires: numactl-devel +BuildRequires: python3-devel %{?__python3:Requires: %{__python3}} Requires: bash bc #Patches -Patch1: cyclictest-Fix-setaffinity-error-on-large-NUMA-machines.patch -Patch2: rt-tests-queuelat-Fix-storing-unsigned-long-long-int.patch -Patch3: rt-tests-cyclictest-remove-the-debug-log-pid-xxx-in-.patch -Patch4: rt-tests-improvements-to-the-python-style-in-get_cyc.patch -Patch5: rt-tests-pi_stress.8-Remove-unused-t-n-from-the-manp.patch -Patch6: rt-tests-ptsematest.8-Update-the-ptsematest-man-page.patch -Patch7: rt-tests-Add-a-man-page-for-get_cyclictest_snapshot.patch -Patch8: rt-tests-Tweak-the-cyclictest-man-page.patch -Patch9: rt-tests-get_cyclictest_snapshot-Warn-if-no-cyclicte.patch -Patch10: rt-tests-Install-new-man-page-get_cyclictest_snapshot.patch -Patch11: pi_stress-limit-the-number-of-inversion-groups-to-th.patch -Patch12: rt-tests-cyclictest-Move-ftrace-helpers-into-rt-util.patch -Patch13: rt-tests-oslat-Init-commit.patch -Patch14: rt-tests-oslat-Proper-reformat-of-code.patch +Patch1: rt-tests-oslat-print-version-string.patch +Patch2: oslat-Use-cpuset-size-as-upper-bound.patch +Patch3: rt-tests-oslat-Allocate-memory-for-cpu_set.patch +Patch4: oslat-allow-scheduling-on-all-possible-cores.patch %description rt-tests is a set of programs that test and measure various components of @@ -40,84 +32,99 @@ real-time kernel behavior. This package measures timer, signal, and hardware latency. It also tests the functioning of priority-inheritance mutexes. %prep -%setup -q +%setup -q -n %{name}-%{version} %patch1 -p1 %patch2 -p1 %patch3 -p1 %patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 %build -make NUMA=1 HAVE_PARSE_CPUSTRING_ALL=1 +%set_build_flags +%make_build %install -rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT/%{python3_sitelib} -make DESTDIR=$RPM_BUILD_ROOT prefix=/usr install - -%clean -rm -rf $RPM_BUILD_ROOT +rm -rf ${build_root} +%make_install prefix=%{_prefix} %files %defattr(-,root,root,-) %{python3_sitelib}/hwlatdetect.py* %{python3_sitelib}/__pycache__/hwlatdetect* %caps(cap_sys_rawio+ep) /usr/bin/cyclictest -/usr/bin/pi_stress -/usr/bin/signaltest -/usr/bin/hwlatdetect -/usr/bin/rt-migrate-test -/usr/bin/pip_stress -/usr/bin/ptsematest -/usr/bin/sigwaittest -/usr/bin/svsematest -/usr/bin/pmqtest -/usr/bin/hackbench -/usr/bin/cyclicdeadline -/usr/bin/deadline_test -/usr/bin/queuelat -/usr/bin/ssdd -/usr/bin/oslat -/usr/bin/determine_maximum_mpps.sh -/usr/bin/get_cpuinfo_mhz.sh -/usr/bin/get_cyclictest_snapshot +%{_bindir}/pi_stress +%{_bindir}/signaltest +%{_bindir}/hwlatdetect +%{_bindir}/rt-migrate-test +%{_bindir}/pip_stress +%{_bindir}/ptsematest +%{_bindir}/sigwaittest +%{_bindir}/svsematest +%{_bindir}/pmqtest +%{_bindir}/hackbench +%{_bindir}/cyclicdeadline +%{_bindir}/deadline_test +%{_bindir}/queuelat +%{_bindir}/ssdd +%{_bindir}/oslat +%{_bindir}/determine_maximum_mpps.sh +%{_bindir}/get_cyclictest_snapshot %{python3_sitelib}/get_cyclictest_snapshot.py* %{python3_sitelib}/__pycache__/get_cyclictest_snapshot* %doc -/usr/share/man/man8/cyclictest.8.gz -/usr/share/man/man8/hackbench.8.gz -/usr/share/man/man8/hwlatdetect.8.gz -/usr/share/man/man8/pi_stress.8.gz -/usr/share/man/man8/pmqtest.8.gz -/usr/share/man/man8/ptsematest.8.gz -/usr/share/man/man8/rt-migrate-test.8.gz -/usr/share/man/man8/signaltest.8.gz -/usr/share/man/man8/sigwaittest.8.gz -/usr/share/man/man8/svsematest.8.gz -/usr/share/man/man8/pip_stress.8.gz -/usr/share/man/man8/queuelat.8.gz -/usr/share/man/man8/deadline_test.8.gz -/usr/share/man/man8/cyclicdeadline.8.gz -/usr/share/man/man8/ssdd.8.gz -/usr/share/man/man8/oslat.8.gz -/usr/share/man/man8/get_cyclictest_snapshot.8.gz +%{_mandir}/man8/cyclictest.8.* +%{_mandir}/man8/hackbench.8.* +%{_mandir}/man8/hwlatdetect.8.* +%{_mandir}/man8/pi_stress.8.* +%{_mandir}/man8/pmqtest.8.* +%{_mandir}/man8/ptsematest.8.* +%{_mandir}/man8/rt-migrate-test.8.* +%{_mandir}/man8/signaltest.8.* +%{_mandir}/man8/sigwaittest.8.* +%{_mandir}/man8/svsematest.8.* +%{_mandir}/man8/pip_stress.8.* +%{_mandir}/man8/queuelat.8.* +%{_mandir}/man8/deadline_test.8.* +%{_mandir}/man8/cyclicdeadline.8.* +%{_mandir}/man8/ssdd.8.* +%{_mandir}/man8/oslat.8.* +%{_mandir}/man8/get_cyclictest_snapshot.8.* +%{_mandir}/man8/determine_maximum_mpps.8.* %changelog -* Thu Aug 20 2020 John Kacur - 1.8.11 +* Fri Feb 19 2021 John Kacur - 1.10-3 +- parse_cpumask() is too strict for oslat, allow all possible cores +Resolves: rhbz#1926578 + +* Thu Feb 18 2021 John Kacur - 1.10-2 +- print the version number in oslat everytime. +- use cpuset size as upper bound in loop in oslat +- allocate memory for cpu_set in oslat +Resolves: rhbz#1926578 + +* Mon Jan 11 2021 John Kacur - 1.10-1 +- Upgrade to upstream rt-tests-1.10 +Resolves: rhbz#1890556 + +* Wed Dec 09 2020 John Kacur - 1.9-2 +- Don't compress manpages by default in the makefile +- Add a menu to determine_maximum_mpps.sh +- Add determine_maximum_mmps.8 manpage +- Remove get_cpuinfo_mhz.sh and old Makefile in queuelat dir +Resolves: rhbz#1906104 + +* Tue Nov 24 2020 John Kacur - 1.9-1 +- Update to upstream rt-tests-1.9 +- Add BuildRequires for gcc +- use set_build_flags +- use macros _bindir, _mandir and _prefix where possible +- remove unnecessary clean section, simply build and install sections +Resolves: rhbz#1894615 + +* Thu Aug 20 2020 John Kacur - 1.8-11 - Add SPDX license to oslat, and reformat source code to match suite Resolves: rhbz#1870666 -* Wed Aug 19 2020 John Kacur - 1.8.10 +* Wed Aug 19 2020 John Kacur - 1.8-10 - Remove undated Obsoletes from the specfile Resolves: rhbz#1870212 @@ -721,7 +728,7 @@ Sebastian Andrzej Siewior (1): * Tue Mar 16 2010 Clark Williams - 0.67-1 - modified specfile to add hackbench - modified internal ftrace logic for correct tracing -- Changed rpm %description field to be more descriptive (BZ# 572323) +- Changed rpm %%description field to be more descriptive (BZ# 572323) - from Carsten Emde - added smp option to svsematest - fixed policy display in cyclictest