From 238cd5133fc23f0af52d4c79df2b0cf638be2e97 Mon Sep 17 00:00:00 2001 From: John Kacur Date: Tue, 26 Mar 2024 11:43:47 -0400 Subject: [PATCH] Sync realtime-tests in rhel10 with rhel-9.5 Added the following upstream patches rt-tests-Fix-warnings.patch rt-tests-cyclictest-Remove-histogram-totals.patch rt-tests-cyclictest-Replace-histogram-code-with-libr.patch rt-tests-cyclicdeadline-Add-histogram-support.patch rt-tests-cyclics-Fix-json-segfault-when-not-using-hi.patch rt-tests-cyclicdeadline-Print-the-histogram-regardle.patch rt-tests-cyclicdeadline-Remove-dead-verbose-code-in-.patch rt-tests-oslat-should-use-MHz-not-Mhz.patch rt-tests-oslat-convert-to-nanoseconds-correctly.patch Added gating.yaml Added tests dir Resolves: RHEL-30184 Signed-off-by: John Kacur --- gating.yaml | 6 + realtime-tests.spec | 32 +- ...> rt-tests-Add-missing-SPDX-licenses.patch | 6 +- rt-tests-Fix-warnings.patch | 170 +++++++ ...e-Restore-support-for-Exuberant-Ctag.patch | 2 +- ...s-Remove-remaining-unnecessary-texts.patch | 2 +- ...cyclicdeadline-Add-histogram-support.patch | 254 ++++++++++ ...eadline-Print-the-histogram-regardle.patch | 49 ++ ...eadline-Remove-dead-verbose-code-in-.patch | 107 +++++ ...-Fix-json-segfault-when-not-using-hi.patch | 62 +++ ...s-cyclictest-Remove-histogram-totals.patch | 60 +++ ...est-Replace-histogram-code-with-libr.patch | 448 ++++++++++++++++++ ...lat-convert-to-nanoseconds-correctly.patch | 42 ++ rt-tests-oslat-should-use-MHz-not-Mhz.patch | 34 ++ tests/scripts/run_tests.sh | 45 ++ tests/tests.yml | 11 + 16 files changed, 1323 insertions(+), 7 deletions(-) create mode 100644 gating.yaml rename 0002-rt-tests-Add-missing-SPDX-licenses.patch => rt-tests-Add-missing-SPDX-licenses.patch (99%) create mode 100644 rt-tests-Fix-warnings.patch rename 0001-rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch => rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch (99%) rename 0003-rt-tests-Remove-remaining-unnecessary-texts-after-ad.patch => rt-tests-Remove-remaining-unnecessary-texts.patch (99%) create mode 100644 rt-tests-cyclicdeadline-Add-histogram-support.patch create mode 100644 rt-tests-cyclicdeadline-Print-the-histogram-regardle.patch create mode 100644 rt-tests-cyclicdeadline-Remove-dead-verbose-code-in-.patch create mode 100644 rt-tests-cyclics-Fix-json-segfault-when-not-using-hi.patch create mode 100644 rt-tests-cyclictest-Remove-histogram-totals.patch create mode 100644 rt-tests-cyclictest-Replace-histogram-code-with-libr.patch create mode 100644 rt-tests-oslat-convert-to-nanoseconds-correctly.patch create mode 100644 rt-tests-oslat-should-use-MHz-not-Mhz.patch create mode 100755 tests/scripts/run_tests.sh create mode 100644 tests/tests.yml diff --git a/gating.yaml b/gating.yaml new file mode 100644 index 0000000..648918d --- /dev/null +++ b/gating.yaml @@ -0,0 +1,6 @@ +--- !Policy +product_versions: + - rhel-9 +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional} diff --git a/realtime-tests.spec b/realtime-tests.spec index ad247de..4120af7 100644 --- a/realtime-tests.spec +++ b/realtime-tests.spec @@ -1,7 +1,7 @@ Name: realtime-tests Summary: Programs that test various rt-features Version: 2.6 -Release: 4%{?dist} +Release: 5%{?dist} License: GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-only AND LGPL-2.1-or-later URL: https://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git Source0: https://www.kernel.org/pub/linux/utils/rt-tests/rt-tests-%{version}.tar.xz @@ -15,9 +15,18 @@ Requires: bash Requires: bc #Patches -Patch1: 0001-rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch -Patch2: 0002-rt-tests-Add-missing-SPDX-licenses.patch -Patch3: 0003-rt-tests-Remove-remaining-unnecessary-texts-after-ad.patch +Patch1: rt-tests-Add-missing-SPDX-licenses.patch +Patch2: rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch +Patch3: rt-tests-Remove-remaining-unnecessary-texts.patch +Patch4: rt-tests-Fix-warnings.patch +Patch5: rt-tests-cyclictest-Remove-histogram-totals.patch +Patch6: rt-tests-cyclictest-Replace-histogram-code-with-libr.patch +Patch7: rt-tests-cyclicdeadline-Add-histogram-support.patch +Patch8: rt-tests-cyclics-Fix-json-segfault-when-not-using-hi.patch +Patch9: rt-tests-cyclicdeadline-Print-the-histogram-regardle.patch +Patch10: rt-tests-cyclicdeadline-Remove-dead-verbose-code-in-.patch +Patch11: rt-tests-oslat-should-use-MHz-not-Mhz.patch +Patch12: rt-tests-oslat-convert-to-nanoseconds-correctly.patch %description realtime-tests is a set of programs that test and measure various components of @@ -76,6 +85,21 @@ latency. It also tests the functioning of priority-inheritance mutexes. %{_mandir}/man8/determine_maximum_mpps.8.* %changelog +* Tue Mar 26 2024 John Kacur - 2.6-5 +- Added the following upstream patches + rt-tests-Fix-warnings.patch + rt-tests-cyclictest-Remove-histogram-totals.patch + rt-tests-cyclictest-Replace-histogram-code-with-libr.patch + rt-tests-cyclicdeadline-Add-histogram-support.patch + rt-tests-cyclics-Fix-json-segfault-when-not-using-hi.patch + rt-tests-cyclicdeadline-Print-the-histogram-regardle.patch + rt-tests-cyclicdeadline-Remove-dead-verbose-code-in-.patch + rt-tests-oslat-should-use-MHz-not-Mhz.patch + rt-tests-oslat-convert-to-nanoseconds-correctly.patch +- Added gating.yaml +- Added tests dir +Resolves: RHEL-30184 + * Fri Jan 26 2024 Fedora Release Engineering - 2.6-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild diff --git a/0002-rt-tests-Add-missing-SPDX-licenses.patch b/rt-tests-Add-missing-SPDX-licenses.patch similarity index 99% rename from 0002-rt-tests-Add-missing-SPDX-licenses.patch rename to rt-tests-Add-missing-SPDX-licenses.patch index cecc3ca..0d77122 100644 --- a/0002-rt-tests-Add-missing-SPDX-licenses.patch +++ b/rt-tests-Add-missing-SPDX-licenses.patch @@ -33,6 +33,10 @@ Signed-off-by: John Kacur src/svsematest/svsematest.8 | 1 + 25 files changed, 25 insertions(+), 14 deletions(-) ++# SPDX-License-Identifier: GPL-2.0-or-later + *~ + .* + *.o diff --git a/Makefile b/Makefile index 8d3268d19901..2808c212058a 100644 --- a/Makefile @@ -298,5 +302,5 @@ index 93abf55f3d4d..7865ed0550e9 100644 .LP \fBsvsematest\fR \- Start two threads or fork two processes and measure the latency of SYSV semaphores -- -2.42.0 +2.41.0 diff --git a/rt-tests-Fix-warnings.patch b/rt-tests-Fix-warnings.patch new file mode 100644 index 0000000..ffd8fc7 --- /dev/null +++ b/rt-tests-Fix-warnings.patch @@ -0,0 +1,170 @@ +From d13b57f72f0c8b8e058f9aa4322641d5c15a2618 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Wed, 6 Dec 2023 14:55:05 -0600 +Subject: [PATCH] rt-tests: Fix warnings + +Numerous places threw sign comparison warnings; we could fix them but +it's kind of an obnoxious warning that requires casts to deal with things +such as ARRAY_SIZE() while still being able to check for the user +entering a negative number. + +-Wunused-parameter is another obnoxious warning as it flags perfectly +reasonable code that takes unneeded parameters in order to comply with +a function pointer interface or similar; however, all of the instances +that were flagged here were actual dead parameters, so just fix them. + +Add volatile to timer_started in hackbench so that it doesn't get +clobbered by longjmp(). + +Signed-off-by: Crystal Wood +-- +Let me know if you'd rather I fix the sign warnings. +Signed-off-by: John Kacur +--- + Makefile | 2 +- + src/hackbench/hackbench.c | 2 +- + src/sched_deadline/cyclicdeadline.c | 6 +++--- + src/sched_deadline/deadline_test.c | 10 +++++----- + src/sigwaittest/sigwaittest.c | 6 +++--- + 5 files changed, 13 insertions(+), 13 deletions(-) + +diff --git a/Makefile b/Makefile +index 2808c212058a..ad481a73cf93 100644 +--- a/Makefile ++++ b/Makefile +@@ -31,7 +31,7 @@ prefix ?= /usr/local + bindir ?= $(prefix)/bin + mandir ?= $(prefix)/share/man + +-CFLAGS ?= -Wall -Wno-nonnull -Wextra ++CFLAGS ?= -Wall -Wno-nonnull -Wextra -Wno-sign-compare + CPPFLAGS += -D_GNU_SOURCE -Isrc/include + LDFLAGS ?= + +diff --git a/src/hackbench/hackbench.c b/src/hackbench/hackbench.c +index 69dd5f087fb6..4430db0e4ed6 100644 +--- a/src/hackbench/hackbench.c ++++ b/src/hackbench/hackbench.c +@@ -494,7 +494,7 @@ int main(int argc, char *argv[]) + struct timeval start, stop, diff; + int readyfds[2], wakefds[2]; + char dummy; +- int timer_started = 0; ++ volatile int timer_started = 0; + struct sched_param sp; + + process_options (argc, argv); +diff --git a/src/sched_deadline/cyclicdeadline.c b/src/sched_deadline/cyclicdeadline.c +index 9bdc4b5deaf1..097e2e5d4580 100644 +--- a/src/sched_deadline/cyclicdeadline.c ++++ b/src/sched_deadline/cyclicdeadline.c +@@ -750,7 +750,7 @@ static void print_stat(FILE *fp, struct sched_data *sd, int index, int verbose, + } + } + +-static u64 do_runtime(long tid, struct sched_data *sd, u64 period) ++static u64 do_runtime(struct sched_data *sd, u64 period) + { + struct thread_stat *stat = &sd->stat; + u64 next_period = period + sd->deadline_us; +@@ -833,7 +833,7 @@ void *run_deadline(void *data) + period = get_time_us(); + + while (!shutdown) { +- period = do_runtime(tid, sd, period); ++ period = do_runtime(sd, period); + if (tracelimit && (stat->max > tracelimit)) { + shutdown++; + pthread_mutex_lock(&break_thread_id_lock); +@@ -1266,7 +1266,7 @@ int main(int argc, char **argv) + + /* Make sure that we can make our deadlines */ + start_period = get_time_us(); +- do_runtime(gettid(), sd, start_period); ++ do_runtime(sd, start_period); + end_period = get_time_us(); + if (end_period - start_period > sd->runtime_us) + fatal("Failed to perform task within runtime: Missed by %lld us\n", +diff --git a/src/sched_deadline/deadline_test.c b/src/sched_deadline/deadline_test.c +index cd8ef01f7d68..ca2da476ec95 100644 +--- a/src/sched_deadline/deadline_test.c ++++ b/src/sched_deadline/deadline_test.c +@@ -1181,7 +1181,7 @@ static int read_ctx_switches(int *vol, int *nonvol, int *migrate) + * @data->total_time - Total time it took to complete all loops + * @data->nr_periods - Number of periods that were executed. + */ +-static u64 do_runtime(long tid, struct sched_data *data, u64 period) ++static u64 do_runtime(struct sched_data *data, u64 period) + { + u64 next_period = period + data->deadline_us; + u64 now = get_time_us(); +@@ -1354,7 +1354,7 @@ void *run_deadline(void *data) + period = get_time_us(); + + while (!done) { +- period = do_runtime(tid, sched_data, period); ++ period = do_runtime(sched_data, period); + sched_yield(); + } + ret = sched_getattr(0, &attr, sizeof(attr), 0); +@@ -1714,7 +1714,7 @@ static u64 calculate_loops_per_ms(u64 *overhead) + do_sleep(1000); + + start = get_time_us(); +- do_runtime(0, &sd, start + sd.deadline_us); ++ do_runtime(&sd, start + sd.deadline_us); + end = get_time_us(); + + diff = end - start; +@@ -1743,7 +1743,7 @@ static u64 calculate_loops_per_ms(u64 *overhead) + do_sleep(1000); + + start = get_time_us(); +- do_runtime(0, &sd, start + sd.deadline_us); ++ do_runtime(&sd, start + sd.deadline_us); + end = get_time_us(); + + odiff = end - start; +@@ -1962,7 +1962,7 @@ int main(int argc, char **argv) + + /* Make sure that we can make our deadlines */ + start_period = get_time_us(); +- do_runtime(gettid(), sd, start_period); ++ do_runtime(sd, start_period); + end_period = get_time_us(); + if (end_period - start_period > sd->runtime_us) { + printf("Failed to perform task within runtime: Missed by %lld us\n", +diff --git a/src/sigwaittest/sigwaittest.c b/src/sigwaittest/sigwaittest.c +index 55855769c63b..8c1c16fb3081 100644 +--- a/src/sigwaittest/sigwaittest.c ++++ b/src/sigwaittest/sigwaittest.c +@@ -375,7 +375,7 @@ static void sighand(int sig __attribute__ ((unused))) + mustshutdown = 1; + } + +-static void print_stat(FILE *fp, struct params *receiver, struct params *sender, ++static void print_stat(struct params *receiver, struct params *sender, + int verbose __attribute__ ((unused)), int quiet) + { + int i; +@@ -644,7 +644,7 @@ int main(int argc, char *argv[]) + sender[i].shutdown; + + if (receiver[0].samples > oldsamples || mustshutdown) { +- print_stat(stdout, receiver, sender, 0, quiet); ++ print_stat(receiver, sender, 0, quiet); + if (!quiet) + printf("\033[%dA", num_threads*2); + } +@@ -664,7 +664,7 @@ int main(int argc, char *argv[]) + if (!quiet) + printf("\033[%dB", num_threads*2 + 2); + else +- print_stat(stdout, receiver, sender, 0, 0); ++ print_stat(receiver, sender, 0, 0); + + for (i = 0; i < num_threads; i++) { + receiver[i].shutdown = 1; +-- +2.43.0 + diff --git a/0001-rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch b/rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch similarity index 99% rename from 0001-rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch rename to rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch index 07b6675..39500af 100644 --- a/0001-rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch +++ b/rt-tests-Makefile-Restore-support-for-Exuberant-Ctag.patch @@ -33,5 +33,5 @@ index 223a839151ec..8d3268d19901 100644 - ctags -R --extras=+f --c-kinds=+p --exclude=tmp --exclude=BUILD * + $(CTAGS_BIN) -R --$(CTAGS_EXTRA)=+f --c-kinds=+p --exclude=tmp --exclude=BUILD * -- -2.42.0 +2.41.0 diff --git a/0003-rt-tests-Remove-remaining-unnecessary-texts-after-ad.patch b/rt-tests-Remove-remaining-unnecessary-texts.patch similarity index 99% rename from 0003-rt-tests-Remove-remaining-unnecessary-texts-after-ad.patch rename to rt-tests-Remove-remaining-unnecessary-texts.patch index 97b36fa..30770f3 100644 --- a/0003-rt-tests-Remove-remaining-unnecessary-texts-after-ad.patch +++ b/rt-tests-Remove-remaining-unnecessary-texts.patch @@ -53,5 +53,5 @@ index 818e3a8e680a..55855769c63b 100644 #include -- -2.42.0 +2.41.0 diff --git a/rt-tests-cyclicdeadline-Add-histogram-support.patch b/rt-tests-cyclicdeadline-Add-histogram-support.patch new file mode 100644 index 0000000..a54e89a --- /dev/null +++ b/rt-tests-cyclicdeadline-Add-histogram-support.patch @@ -0,0 +1,254 @@ +From dba4231b17f3515c0278938d571a53a5dfa925d7 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Mon, 18 Dec 2023 21:37:50 -0600 +Subject: [PATCH 3/3] rt-tests: cyclicdeadline: Add histogram support + +Add support for the --histogram and --histfile options as in cyclictest. +The short -h option is not supported, as cyclicdeadline already uses that +for help. -H/--histofall is not supported but could be easily added. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + src/sched_deadline/cyclicdeadline.c | 114 +++++++++++++++++++++++++--- + 1 file changed, 104 insertions(+), 10 deletions(-) + +diff --git a/src/sched_deadline/cyclicdeadline.c b/src/sched_deadline/cyclicdeadline.c +index 9bdc4b5deaf1..d84da732a991 100644 +--- a/src/sched_deadline/cyclicdeadline.c ++++ b/src/sched_deadline/cyclicdeadline.c +@@ -33,6 +33,7 @@ + #include "rt-utils.h" + #include "rt-sched.h" + #include "rt-error.h" ++#include "histogram.h" + + #define _STR(x) #x + #define STR(x) _STR(x) +@@ -40,6 +41,8 @@ + #define MAXPATH 1024 + #endif + ++#define HIST_MAX 1000000 ++ + #define CPUSET_ALL "my_cpuset_all" + #define CPUSET_LOCAL "my_cpuset" + +@@ -56,16 +59,13 @@ struct thread_stat { + long act; + double avg; + long *values; +- long *hist_array; +- long *outliers; ++ struct histogram *hist; + pthread_t thread; + int threadstarted; + int tid; + long reduce; + long redmax; + long cycleofmax; +- long hist_overflow; +- long num_outliers; + }; + + struct sched_data { +@@ -84,6 +84,8 @@ static int info_enable; + static int debug_enable; + static int tracelimit; + static int trace_marker; ++static int histogram; ++static FILE *histfile; + static pthread_mutex_t break_thread_id_lock = PTHREAD_MUTEX_INITIALIZER; + static pid_t break_thread_id; + static uint64_t break_thread_value; +@@ -97,6 +99,8 @@ static int mark_fd; + static int quiet; + static char jsonfile[MAX_PATH]; + ++static struct histoset hset; ++ + static int find_mount(const char *mount, char *debugfs) + { + char type[100]; +@@ -691,6 +695,10 @@ static void usage(int error) + " Append 'm', 'h', or 'd' to specify minutes, hours or\n" + " days\n" + "-h --help Show this help menu.\n" ++ " --histogram=US dump a latency histogram to stdout after the run\n" ++ " US is the max latency time to be tracked in microseconds\n" ++ " This option runs all threads at the same priority.\n" ++ " --histfile= dump the latency histogram to instead of stdout\n" + "-i INTV --interval The shortest deadline for the tasks in us\n" + " (default 1000us).\n" + " --json=FILENAME write final results into FILENAME, JSON formatted\n" +@@ -718,6 +726,55 @@ static u64 get_time_us(void) + return time; + } + ++static void print_hist(FILE *fp, struct sched_data *sd, int nthreads) ++{ ++ int i; ++ unsigned long maxmax, alloverflows; ++ ++ fprintf(fp, "# Histogram\n"); ++ for (i = 0; i < histogram; i++) { ++ unsigned long flags = 0; ++ ++ fprintf(fp, "%06d ", i); ++ ++ hset_print_bucket(&hset, fp, i, flags); ++ fprintf(fp, "\n"); ++ } ++ fprintf(fp, "# Min Latencies:"); ++ for (i = 0; i < nthreads; i++) ++ fprintf(fp, " %05lu", sd[i].stat.min); ++ fprintf(fp, "\n"); ++ fprintf(fp, "# Avg Latencies:"); ++ for (i = 0; i < nthreads; i++) ++ fprintf(fp, " %05lu", sd[i].stat.cycles ? ++ (long)(sd[i].stat.avg/sd[i].stat.cycles) : 0); ++ fprintf(fp, "\n"); ++ fprintf(fp, "# Max Latencies:"); ++ maxmax = 0; ++ for (i = 0; i < nthreads; i++) { ++ fprintf(fp, " %05lu", sd[i].stat.max); ++ if (sd[i].stat.max > maxmax) ++ maxmax = sd[i].stat.max; ++ } ++ fprintf(fp, "\n"); ++ fprintf(fp, "# Histogram Overflows:"); ++ alloverflows = 0; ++ for (i = 0; i < nthreads; i++) { ++ fprintf(fp, " %05lu", sd[i].stat.hist->oflow_count); ++ alloverflows += sd[i].stat.hist->oflow_count; ++ } ++ fprintf(fp, "\n"); ++ ++ fprintf(fp, "# Histogram Overflow at cycle number:\n"); ++ for (i = 0; i < nthreads; i++) { ++ fprintf(fp, "# Thread %d: ", i); ++ hist_print_oflows(sd[i].stat.hist, fp); ++ fprintf(fp, "\n"); ++ } ++ ++ fprintf(fp, "\n"); ++} ++ + static void print_stat(FILE *fp, struct sched_data *sd, int index, int verbose, int quiet) + { + struct thread_stat *stat = &sd->stat; +@@ -784,6 +841,9 @@ static u64 do_runtime(long tid, struct sched_data *sd, u64 period) + stat->act = diff; + stat->avg += (double) diff; + ++ if (histogram) ++ hist_sample(stat->hist, diff); ++ + stat->cycles++; + + return next_period; +@@ -1058,8 +1118,14 @@ static void loop(struct sched_data *sched_data, int nr_threads) + if (!quiet) { + printf("\033[%dB", nr_threads + 2); + } else { +- for (i = 0; i < nr_threads; ++i) +- print_stat(stdout, &sched_data[i], i, 0, 0); ++ if (histogram) { ++ FILE *out = histfile ? histfile : stdout; ++ ++ print_hist(out, sched_data, nr_threads); ++ } else { ++ for (i = 0; i < nr_threads; ++i) ++ print_stat(stdout, &sched_data[i], i, 0, 0); ++ } + } + } + +@@ -1075,10 +1141,14 @@ static void write_stats(FILE *f, void *data) + for (i = 0; i < nr_threads; i++) { + s = &sd[i].stat; + fprintf(f, " \"%u\": {\n", i); +- fprintf(f, " \"cycles\": %ld,\n", s->cycles); +- fprintf(f, " \"min\": %ld,\n", s->min); +- fprintf(f, " \"max\": %ld,\n", s->max); +- fprintf(f, " \"avg\": %.2f\n", s->avg/s->cycles); ++ ++ fprintf(f, " \"histogram\": {"); ++ hist_print_json(s->hist, f); ++ fprintf(f, " },\n"); ++ fprintf(f, " \"cycles\": %ld,\n", s->cycles); ++ fprintf(f, " \"min\": %ld,\n", s->min); ++ fprintf(f, " \"max\": %ld,\n", s->max); ++ fprintf(f, " \"avg\": %.2f\n", s->avg/s->cycles); + fprintf(f, " }%s\n", i == nr_threads - 1 ? "" : ","); + } + fprintf(f, " }\n"); +@@ -1088,6 +1158,7 @@ enum options_values { + OPT_AFFINITY=1, OPT_DURATION, OPT_HELP, OPT_INTERVAL, + OPT_JSON, OPT_STEP, OPT_THREADS, OPT_QUIET, + OPT_BREAKTRACE, OPT_TRACEMARK, OPT_INFO, OPT_DEBUG, ++ OPT_HISTOGRAM, OPT_HISTFILE + }; + + int main(int argc, char **argv) +@@ -1130,6 +1201,8 @@ int main(int argc, char **argv) + { "tracemark", no_argument, NULL, OPT_TRACEMARK }, + { "verbose", no_argument, NULL, OPT_INFO}, + { "debug", no_argument, NULL, OPT_DEBUG}, ++ { "histogram", required_argument, NULL, OPT_HISTOGRAM }, ++ { "histfile", required_argument, NULL, OPT_HISTFILE }, + { NULL, 0, NULL, 0 }, + }; + c = getopt_long(argc, argv, "a::c:D:hi:s:t:b:q", options, NULL); +@@ -1188,6 +1261,17 @@ int main(int argc, char **argv) + case OPT_DEBUG: + debug_enable = 1; + break; ++ case OPT_HISTOGRAM: ++ histogram = atoi(optarg); ++ if (histogram <= 0 || histogram > HIST_MAX) ++ usage(1); ++ break; ++ case OPT_HISTFILE: ++ histfile = fopen(optarg, "w"); ++ if (!histfile) ++ fatal("Couldn\'t open histfile %s: %s\n", ++ optarg, strerror(errno)); ++ break; + default: + usage(1); + } +@@ -1233,6 +1317,10 @@ int main(int argc, char **argv) + if (!thread || !sched_data) + fatal("allocating threads"); + ++ if (histogram && hset_init(&hset, nr_threads, 1, histogram, histogram)) ++ fatal("failed to allocate histogram of size %d for %d threads\n", ++ histogram, nr_threads); ++ + if (nr_threads > nr_cpus) { + /* + * More threads than CPUs, then have the total be +@@ -1262,6 +1350,9 @@ int main(int argc, char **argv) + sd->runtime_us = runtime; + sd->deadline_us = interval; + ++ if (histogram) ++ sd->stat.hist = &hset.histos[i]; ++ + info(info_enable, "interval: %lld:%lld\n", sd->runtime_us, sd->deadline_us); + + /* Make sure that we can make our deadlines */ +@@ -1356,6 +1447,9 @@ int main(int argc, char **argv) + free(setcpu_buf); + free(thread); + free(sched_data); ++ if (histfile) ++ fclose(histfile); ++ hset_destroy(&hset); + + return 0; + } +-- +2.43.0 + diff --git a/rt-tests-cyclicdeadline-Print-the-histogram-regardle.patch b/rt-tests-cyclicdeadline-Print-the-histogram-regardle.patch new file mode 100644 index 0000000..f838684 --- /dev/null +++ b/rt-tests-cyclicdeadline-Print-the-histogram-regardle.patch @@ -0,0 +1,49 @@ +From 8f05671597898ffc9f2f310bbf71e0b9c7b4dec3 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Mon, 22 Jan 2024 16:13:20 -0600 +Subject: [PATCH 2/3] rt-tests: cyclicdeadline: Print the histogram regardless + of quiet + +The histogram printing code should not have been gated by !quiet, +even though other summary printing code is. + +The non-histogram output also should not have been gated based on +the presence of the histogram. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + src/sched_deadline/cyclicdeadline.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/src/sched_deadline/cyclicdeadline.c b/src/sched_deadline/cyclicdeadline.c +index b3155547b9bb..3cb8f714b788 100644 +--- a/src/sched_deadline/cyclicdeadline.c ++++ b/src/sched_deadline/cyclicdeadline.c +@@ -1117,15 +1117,15 @@ static void loop(struct sched_data *sched_data, int nr_threads) + usleep(10000); + if (!quiet) { + printf("\033[%dB", nr_threads + 2); +- } else { +- if (histogram) { +- FILE *out = histfile ? histfile : stdout; ++ } else if (!histogram) { ++ for (i = 0; i < nr_threads; ++i) ++ print_stat(stdout, &sched_data[i], i, 0, 0); ++ } + +- print_hist(out, sched_data, nr_threads); +- } else { +- for (i = 0; i < nr_threads; ++i) +- print_stat(stdout, &sched_data[i], i, 0, 0); +- } ++ if (histogram) { ++ FILE *out = histfile ? histfile : stdout; ++ ++ print_hist(out, sched_data, nr_threads); + } + } + +-- +2.43.0 + diff --git a/rt-tests-cyclicdeadline-Remove-dead-verbose-code-in-.patch b/rt-tests-cyclicdeadline-Remove-dead-verbose-code-in-.patch new file mode 100644 index 0000000..2815f64 --- /dev/null +++ b/rt-tests-cyclicdeadline-Remove-dead-verbose-code-in-.patch @@ -0,0 +1,107 @@ +From 326e7c65f07a6caee814eb1e385704aa1b5b129e Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Mon, 22 Jan 2024 16:13:21 -0600 +Subject: [PATCH 3/3] rt-tests: cyclicdeadline: Remove dead "verbose" code in + print_stat() + +print_stat() isn't and has never been called with verbose set, and +that codepath doesn't even print anything. Remove it. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + src/sched_deadline/cyclicdeadline.c | 46 ++++++++++------------------- + 1 file changed, 15 insertions(+), 31 deletions(-) + +diff --git a/src/sched_deadline/cyclicdeadline.c b/src/sched_deadline/cyclicdeadline.c +index 3cb8f714b788..7525ad136d2c 100644 +--- a/src/sched_deadline/cyclicdeadline.c ++++ b/src/sched_deadline/cyclicdeadline.c +@@ -53,7 +53,6 @@ typedef int s32; + /* Struct for statistics */ + struct thread_stat { + unsigned long cycles; +- unsigned long cyclesread; + long min; + long max; + long act; +@@ -64,8 +63,6 @@ struct thread_stat { + int threadstarted; + int tid; + long reduce; +- long redmax; +- long cycleofmax; + }; + + struct sched_data { +@@ -775,36 +772,23 @@ static void print_hist(FILE *fp, struct sched_data *sd, int nthreads) + fprintf(fp, "\n"); + } + +-static void print_stat(FILE *fp, struct sched_data *sd, int index, int verbose, int quiet) ++static void print_stat(FILE *fp, struct sched_data *sd, int index, int quiet) + { + struct thread_stat *stat = &sd->stat; ++ char *fmt; + +- if (!verbose) { +- if (quiet != 1) { +- char *fmt; +- if (use_nsecs) +- fmt = "T:%2d (%5d) I:%ld C:%7lu " +- "Min:%7ld Act:%8ld Avg:%8ld Max:%8ld\n"; +- else +- fmt = "T:%2d (%5d) I:%ld C:%7lu " +- "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld\n"; +- fprintf(fp, fmt, index, stat->tid, +- sd->deadline_us, stat->cycles, stat->min, stat->act, +- stat->cycles ? +- (long)(stat->avg/stat->cycles) : 0, stat->max); +- } +- } else { +- while (stat->cycles != stat->cyclesread) { +- long diff = stat->values +- [stat->cyclesread & sd->bufmsk]; ++ if (quiet) ++ return; + +- if (diff > stat->redmax) { +- stat->redmax = diff; +- stat->cycleofmax = stat->cyclesread; +- } +- stat->cyclesread++; +- } +- } ++ if (use_nsecs) ++ fmt = "T:%2d (%5d) I:%ld C:%7lu Min:%7ld Act:%8ld Avg:%8ld Max:%8ld\n"; ++ else ++ fmt = "T:%2d (%5d) I:%ld C:%7lu Min:%7ld Act:%5ld Avg:%5ld Max:%8ld\n"; ++ ++ fprintf(fp, fmt, index, stat->tid, ++ sd->deadline_us, stat->cycles, stat->min, stat->act, ++ stat->cycles ? ++ (long)(stat->avg/stat->cycles) : 0, stat->max); + } + + static u64 do_runtime(struct sched_data *sd, u64 period) +@@ -1109,7 +1093,7 @@ static void loop(struct sched_data *sched_data, int nr_threads) + + while (!shutdown) { + for (i = 0; i < nr_threads; i++) +- print_stat(stdout, &sched_data[i], i, 0, quiet); ++ print_stat(stdout, &sched_data[i], i, quiet); + usleep(10000); + if (!quiet) + printf("\033[%dA", nr_threads); +@@ -1119,7 +1103,7 @@ static void loop(struct sched_data *sched_data, int nr_threads) + printf("\033[%dB", nr_threads + 2); + } else if (!histogram) { + for (i = 0; i < nr_threads; ++i) +- print_stat(stdout, &sched_data[i], i, 0, 0); ++ print_stat(stdout, &sched_data[i], i, 0); + } + + if (histogram) { +-- +2.43.0 + diff --git a/rt-tests-cyclics-Fix-json-segfault-when-not-using-hi.patch b/rt-tests-cyclics-Fix-json-segfault-when-not-using-hi.patch new file mode 100644 index 0000000..2963a1e --- /dev/null +++ b/rt-tests-cyclics-Fix-json-segfault-when-not-using-hi.patch @@ -0,0 +1,62 @@ +From 36f634cf8853e00558512b5b48ce600b629402bb Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Mon, 22 Jan 2024 16:13:19 -0600 +Subject: [PATCH 1/3] rt-tests: cyclics: Fix json segfault when not using + histogram + +If we're not generating a histogram, don't call the histogram code with +a NULL pointer. Also don't print the rest of the histogram json node. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + src/cyclictest/cyclictest.c | 11 ++++++----- + src/sched_deadline/cyclicdeadline.c | 9 +++++---- + 2 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c +index 6169170fc66d..33fac3b95f5d 100644 +--- a/src/cyclictest/cyclictest.c ++++ b/src/cyclictest/cyclictest.c +@@ -1778,12 +1778,13 @@ static void write_stats(FILE *f, void *data __attribute__ ((unused))) + fprintf(f, " \"resolution_in_ns\": %u,\n", use_nsecs); + fprintf(f, " \"thread\": {\n"); + for (i = 0; i < num_threads; i++) { +- fprintf(f, " \"%u\": {\n", i); +- +- fprintf(f, " \"histogram\": {"); + s = par[i]->stats; +- hist_print_json(par[i]->stats->hist, f); +- fprintf(f, " },\n"); ++ fprintf(f, " \"%u\": {\n", i); ++ if (s->hist) { ++ fprintf(f, " \"histogram\": {"); ++ hist_print_json(s->hist, f); ++ fprintf(f, " },\n"); ++ } + fprintf(f, " \"cycles\": %ld,\n", s->cycles); + fprintf(f, " \"min\": %ld,\n", s->min); + fprintf(f, " \"max\": %ld,\n", s->max); +diff --git a/src/sched_deadline/cyclicdeadline.c b/src/sched_deadline/cyclicdeadline.c +index e449be57870e..b3155547b9bb 100644 +--- a/src/sched_deadline/cyclicdeadline.c ++++ b/src/sched_deadline/cyclicdeadline.c +@@ -1141,10 +1141,11 @@ static void write_stats(FILE *f, void *data) + for (i = 0; i < nr_threads; i++) { + s = &sd[i].stat; + fprintf(f, " \"%u\": {\n", i); +- +- fprintf(f, " \"histogram\": {"); +- hist_print_json(s->hist, f); +- fprintf(f, " },\n"); ++ if (s->hist) { ++ fprintf(f, " \"histogram\": {"); ++ hist_print_json(s->hist, f); ++ fprintf(f, " },\n"); ++ } + fprintf(f, " \"cycles\": %ld,\n", s->cycles); + fprintf(f, " \"min\": %ld,\n", s->min); + fprintf(f, " \"max\": %ld,\n", s->max); +-- +2.43.0 + diff --git a/rt-tests-cyclictest-Remove-histogram-totals.patch b/rt-tests-cyclictest-Remove-histogram-totals.patch new file mode 100644 index 0000000..1259301 --- /dev/null +++ b/rt-tests-cyclictest-Remove-histogram-totals.patch @@ -0,0 +1,60 @@ +From 0c5bc44d844807691da69abf8a2aad5acd8f0de5 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Wed, 6 Dec 2023 14:55:06 -0600 +Subject: [PATCH 1/3] rt-tests: cyclictest: Remove histogram totals + +The Total: line does not seem to contribute much value, as it should just +be the number of cycles minus the number of overflows. Unless someone +complains, remove it to simplify moving to common histogram code. + +Signed-off-by: Crystal Wood +- Tested in rteval +- Edited commit message to say "cycles" instead of buckets +Signed-off-by: John Kacur +--- + src/cyclictest/cyclictest.c | 14 +------------- + 1 file changed, 1 insertion(+), 13 deletions(-) + +diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c +index a8039b49feb6..93ce201e9fca 100644 +--- a/src/cyclictest/cyclictest.c ++++ b/src/cyclictest/cyclictest.c +@@ -1407,12 +1407,9 @@ static void print_tids(struct thread_param *par[], int nthreads) + static void print_hist(struct thread_param *par[], int nthreads) + { + int i, j; +- unsigned long long int log_entries[nthreads+1]; + unsigned long maxmax, alloverflows; + FILE *fd; + +- bzero(log_entries, sizeof(log_entries)); +- + if (use_histfile) { + fd = fopen(histfile, "w"); + if (!fd) { +@@ -1434,21 +1431,12 @@ static void print_hist(struct thread_param *par[], int nthreads) + fprintf(fd, "%06lu", curr_latency); + if (j < nthreads - 1) + fprintf(fd, "\t"); +- log_entries[j] += curr_latency; + allthreads += curr_latency; + } +- if (histofall && nthreads > 1) { ++ if (histofall && nthreads > 1) + fprintf(fd, "\t%06llu", allthreads); +- log_entries[nthreads] += allthreads; +- } + fprintf(fd, "\n"); + } +- fprintf(fd, "# Total:"); +- for (j = 0; j < nthreads; j++) +- fprintf(fd, " %09llu", log_entries[j]); +- if (histofall && nthreads > 1) +- fprintf(fd, " %09llu", log_entries[nthreads]); +- fprintf(fd, "\n"); + fprintf(fd, "# Min Latencies:"); + for (j = 0; j < nthreads; j++) + fprintf(fd, " %05lu", par[j]->stats->min); +-- +2.43.0 + diff --git a/rt-tests-cyclictest-Replace-histogram-code-with-libr.patch b/rt-tests-cyclictest-Replace-histogram-code-with-libr.patch new file mode 100644 index 0000000..a5af06b --- /dev/null +++ b/rt-tests-cyclictest-Replace-histogram-code-with-libr.patch @@ -0,0 +1,448 @@ +From 8adfb00d4694e2d4440eba44f8d275d585fd725d Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Mon, 18 Dec 2023 21:37:49 -0600 +Subject: [PATCH 2/3] rt-tests: cyclictest: Replace histogram code with library + +The new code is also intended to be used by cyclicdeadline, and possibly +oslat and other tests. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + Makefile | 3 +- + src/cyclictest/cyclictest.c | 82 +++++------------ + src/include/histogram.h | 42 +++++++++ + src/lib/histogram.c | 172 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 239 insertions(+), 60 deletions(-) + create mode 100644 src/include/histogram.h + create mode 100644 src/lib/histogram.c + +diff --git a/Makefile b/Makefile +index 223a839151ec..a278ca0dfbc0 100644 +--- a/Makefile ++++ b/Makefile +@@ -177,7 +177,8 @@ oslat: $(OBJDIR)/oslat.o $(OBJDIR)/librttest.a $(OBJDIR)/librttestnuma.a + %.8.bz2: %.8 + bzip2 -c $< > $@ + +-LIBOBJS =$(addprefix $(OBJDIR)/,rt-error.o rt-get_cpu.o rt-sched.o rt-utils.o) ++LIBOBJS =$(addprefix $(OBJDIR)/,rt-error.o rt-get_cpu.o rt-sched.o rt-utils.o \ ++ histogram.o) + $(OBJDIR)/librttest.a: $(LIBOBJS) + $(AR) rcs $@ $^ + +diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c +index 93ce201e9fca..6169170fc66d 100644 +--- a/src/cyclictest/cyclictest.c ++++ b/src/cyclictest/cyclictest.c +@@ -35,6 +35,7 @@ + #include "rt-utils.h" + #include "rt-numa.h" + #include "rt-error.h" ++#include "histogram.h" + + #include + +@@ -133,16 +134,13 @@ struct thread_stat { + double avg; + long *values; + long *smis; +- long *hist_array; +- long *outliers; ++ struct histogram *hist; + pthread_t thread; + int threadstarted; + int tid; + long reduce; + long redmax; + long cycleofmax; +- long hist_overflow; +- long num_outliers; + unsigned long smi_count; + }; + +@@ -216,6 +214,7 @@ static char jsonfile[MAX_PATH]; + + static struct thread_param **parameters; + static struct thread_stat **statistics; ++static struct histoset hset; + + static void print_stat(FILE *fp, struct thread_param *par, int index, int verbose, int quiet); + static void rstat_print_stat(struct thread_param *par, int index, int verbose, int quiet); +@@ -777,15 +776,8 @@ static void *timerthread(void *param) + } + + /* Update the histogram */ +- if (histogram) { +- if (diff >= histogram) { +- stat->hist_overflow++; +- if (stat->num_outliers < histogram) +- stat->outliers[stat->num_outliers++] = stat->cycles; +- } else { +- stat->hist_array[diff]++; +- } +- } ++ if (histogram) ++ hist_sample(stat->hist, diff); + + stat->cycles++; + +@@ -1422,19 +1414,13 @@ static void print_hist(struct thread_param *par[], int nthreads) + + fprintf(fd, "# Histogram\n"); + for (i = 0; i < histogram; i++) { +- unsigned long long int allthreads = 0; ++ unsigned long flags = 0; + + fprintf(fd, "%06d ", i); + +- for (j = 0; j < nthreads; j++) { +- unsigned long curr_latency=par[j]->stats->hist_array[i]; +- fprintf(fd, "%06lu", curr_latency); +- if (j < nthreads - 1) +- fprintf(fd, "\t"); +- allthreads += curr_latency; +- } +- if (histofall && nthreads > 1) +- fprintf(fd, "\t%06llu", allthreads); ++ if (histofall) ++ flags |= HSET_PRINT_SUM; ++ hset_print_bucket(&hset, fd, i, flags); + fprintf(fd, "\n"); + } + fprintf(fd, "# Min Latencies:"); +@@ -1459,8 +1445,8 @@ static void print_hist(struct thread_param *par[], int nthreads) + fprintf(fd, "# Histogram Overflows:"); + alloverflows = 0; + for (j = 0; j < nthreads; j++) { +- fprintf(fd, " %05lu", par[j]->stats->hist_overflow); +- alloverflows += par[j]->stats->hist_overflow; ++ fprintf(fd, " %05lu", par[j]->stats->hist->oflow_count); ++ alloverflows += par[j]->stats->hist->oflow_count; + } + if (histofall && nthreads > 1) + fprintf(fd, " %05lu", alloverflows); +@@ -1468,11 +1454,8 @@ static void print_hist(struct thread_param *par[], int nthreads) + + fprintf(fd, "# Histogram Overflow at cycle number:\n"); + for (i = 0; i < nthreads; i++) { +- fprintf(fd, "# Thread %d:", i); +- for (j = 0; j < par[i]->stats->num_outliers; j++) +- fprintf(fd, " %05lu", par[i]->stats->outliers[j]); +- if (par[i]->stats->num_outliers < par[i]->stats->hist_overflow) +- fprintf(fd, " # %05lu others", par[i]->stats->hist_overflow - par[i]->stats->num_outliers); ++ fprintf(fd, "# Thread %d: ", i); ++ hist_print_oflows(par[i]->stats->hist, fd); + fprintf(fd, "\n"); + } + if (smi) { +@@ -1788,8 +1771,7 @@ rstat_err: + static void write_stats(FILE *f, void *data __attribute__ ((unused))) + { + struct thread_param **par = parameters; +- int i, j; +- unsigned comma; ++ int i; + struct thread_stat *s; + + fprintf(f, " \"num_threads\": %d,\n", num_threads); +@@ -1800,15 +1782,7 @@ static void write_stats(FILE *f, void *data __attribute__ ((unused))) + + fprintf(f, " \"histogram\": {"); + s = par[i]->stats; +- for (j = 0, comma = 0; j < histogram; j++) { +- if (s->hist_array[j] == 0) +- continue; +- fprintf(f, "%s", comma ? ",\n" : "\n"); +- fprintf(f, " \"%u\": %ld", j, s->hist_array[j]); +- comma = 1; +- } +- if (comma) +- fprintf(f, "\n"); ++ hist_print_json(par[i]->stats->hist, f); + fprintf(f, " },\n"); + fprintf(f, " \"cycles\": %ld,\n", s->cycles); + fprintf(f, " \"min\": %ld,\n", s->min); +@@ -1991,6 +1965,10 @@ int main(int argc, char **argv) + /* Set-up shm */ + rstat_setup(); + ++ if (histogram && hset_init(&hset, num_threads, 1, histogram, histogram)) ++ fatal("failed to allocate histogram of size %d for %d threads\n", ++ histogram, num_threads); ++ + parameters = calloc(num_threads, sizeof(struct thread_param *)); + if (!parameters) + goto out; +@@ -2066,18 +2044,8 @@ int main(int argc, char **argv) + fatal("error allocating thread status struct for thread %d\n", i); + memset(stat, 0, sizeof(struct thread_stat)); + +- /* allocate the histogram if requested */ +- if (histogram) { +- int bufsize = histogram * sizeof(long); +- +- stat->hist_array = threadalloc(bufsize, node); +- stat->outliers = threadalloc(bufsize, node); +- if (stat->hist_array == NULL || stat->outliers == NULL) +- fatal("failed to allocate histogram of size %d on node %d\n", +- histogram, i); +- memset(stat->hist_array, 0, bufsize); +- memset(stat->outliers, 0, bufsize); +- } ++ if (histogram) ++ stat->hist = &hset.histos[i]; + + if (verbose) { + int bufsize = VALBUF_SIZE * sizeof(long); +@@ -2215,13 +2183,8 @@ int main(int argc, char **argv) + if (trigger) + trigger_print(); + +- if (histogram) { ++ if (histogram) + print_hist(parameters, num_threads); +- for (i = 0; i < num_threads; i++) { +- threadfree(statistics[i]->hist_array, histogram*sizeof(long), parameters[i]->node); +- threadfree(statistics[i]->outliers, histogram*sizeof(long), parameters[i]->node); +- } +- } + + if (tracelimit) { + print_tids(parameters, num_threads); +@@ -2263,5 +2226,6 @@ int main(int argc, char **argv) + if (rstat_fd >= 0) + shm_unlink(shm_name); + ++ hset_destroy(&hset); + exit(ret); + } +diff --git a/src/include/histogram.h b/src/include/histogram.h +new file mode 100644 +index 000000000000..c7aba68ffb99 +--- /dev/null ++++ b/src/include/histogram.h +@@ -0,0 +1,42 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++#include ++#include ++ ++struct histogram { ++ unsigned long *buckets; ++ unsigned long width; // interval covered by one bucket ++ unsigned long num; // number of buckets ++ unsigned long events; // number of events logged ++ ++ unsigned long *oflows; // events when overflow happened ++ unsigned long oflow_bufsize; // number of overflows that can be logged ++ unsigned long oflow_count; // number of events that overflowed ++ uint64_t oflow_magnitude; // sum of how many buckets overflowed by ++}; ++ ++struct histoset { ++ struct histogram *histos; // Group of related histograms (e.g. per cpu) ++ struct histogram *sum; // Accumulates events from all histos ++ unsigned long num_histos; // Not including sum ++ unsigned long num_buckets; ++}; ++ ++#define HIST_OVERFLOW 1 ++#define HIST_OVERFLOW_MAG 2 ++#define HIST_OVERFLOW_LOG 4 ++ ++int hist_init(struct histogram *h, unsigned long width, unsigned long num); ++int hist_init_oflow(struct histogram *h, unsigned long num); ++void hist_destroy(struct histogram *h); ++int hist_sample(struct histogram *h, uint64_t sample); ++ ++#define HSET_PRINT_SUM 1 ++#define HSET_PRINT_JSON 2 ++ ++int hset_init(struct histoset *hs, unsigned long histos, unsigned long bucket_width, ++ unsigned long num_buckets, unsigned long overflow); ++void hset_destroy(struct histoset *hs); ++void hset_print_bucket(struct histoset *hs, FILE *f, unsigned long bucket, ++ unsigned long flags); ++void hist_print_json(struct histogram *h, FILE *f); ++void hist_print_oflows(struct histogram *h, FILE *f); +diff --git a/src/lib/histogram.c b/src/lib/histogram.c +new file mode 100644 +index 000000000000..35a9d604da86 +--- /dev/null ++++ b/src/lib/histogram.c +@@ -0,0 +1,172 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Latency histograms ++ * ++ * Copyright 2023 Red Hat Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "histogram.h" ++ ++int hist_init(struct histogram *h, unsigned long width, unsigned long num) ++{ ++ memset(h, 0, sizeof(*h)); ++ h->width = width; ++ h->num = num; ++ ++ h->buckets = calloc(num, sizeof(unsigned long)); ++ if (!h->buckets) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++int hist_init_oflow(struct histogram *h, unsigned long num) ++{ ++ h->oflow_bufsize = num; ++ h->oflows = calloc(num, sizeof(unsigned long)); ++ if (!h->oflows) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++void hist_destroy(struct histogram *h) ++{ ++ free(h->oflows); ++ h->oflows = NULL; ++ free(h->buckets); ++ h->buckets = NULL; ++} ++ ++int hist_sample(struct histogram *h, uint64_t sample) ++{ ++ unsigned long bucket = sample / h->width; ++ unsigned long extra; ++ unsigned long event = h->events++; ++ int ret; ++ ++ if (bucket < h->num) { ++ h->buckets[bucket]++; ++ return 0; ++ } ++ ++ ret = HIST_OVERFLOW; ++ extra = bucket - h->num; ++ if (h->oflow_magnitude + extra > h->oflow_magnitude) ++ h->oflow_magnitude += extra; ++ else ++ ret |= HIST_OVERFLOW_MAG; ++ ++ if (h->oflows) { ++ if (h->oflow_count < h->oflow_bufsize) ++ h->oflows[h->oflow_count] = event; ++ else ++ ret |= HIST_OVERFLOW_LOG; ++ } ++ ++ h->oflow_count++; ++ return ret; ++} ++ ++int hset_init(struct histoset *hs, unsigned long num_histos, ++ unsigned long bucket_width, unsigned long num_buckets, ++ unsigned long overflow) ++{ ++ unsigned long i; ++ ++ if (num_histos == 0) ++ return -EINVAL; ++ ++ hs->num_histos = num_histos; ++ hs->num_buckets = num_buckets; ++ hs->histos = calloc(num_histos, sizeof(struct histogram)); ++ if (!hs->histos) ++ return -ENOMEM; ++ ++ for (i = 0; i < num_histos; i++) { ++ if (hist_init(&hs->histos[i], bucket_width, num_buckets)) ++ goto fail; ++ if (overflow && hist_init_oflow(&hs->histos[i], overflow)) ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ hset_destroy(hs); ++ return -ENOMEM; ++} ++ ++void hset_destroy(struct histoset *hs) ++{ ++ unsigned long i; ++ ++ if (hs->histos) { ++ for (i = 0; i < hs->num_histos; i++) ++ hist_destroy(&hs->histos[i]); ++ } ++ ++ free(hs->histos); ++ hs->histos = NULL; ++} ++ ++void hset_print_bucket(struct histoset *hs, FILE *f, unsigned long bucket, ++ unsigned long flags) ++{ ++ unsigned long long sum = 0; ++ unsigned long i; ++ ++ if (bucket >= hs->num_buckets) ++ return; ++ ++ for (i = 0; i < hs->num_histos; i++) { ++ unsigned long val = hs->histos[i].buckets[bucket]; ++ ++ sum += val; ++ if (i != 0) ++ fprintf(f, "\t"); ++ fprintf(f, "%06lu", val); ++ } ++ ++ if (flags & HSET_PRINT_SUM) ++ fprintf(f, "\t%06llu", sum); ++} ++ ++void hist_print_json(struct histogram *h, FILE *f) ++{ ++ unsigned long i; ++ bool comma = false; ++ ++ for (i = 0; i < h->num; i++) { ++ unsigned long val = h->buckets[i]; ++ ++ if (val != 0) { ++ if (comma) ++ fprintf(f, ","); ++ fprintf(f, "\n \"%lu\": %lu", i, val); ++ comma = true; ++ } ++ } ++ ++ fprintf(f, "\n"); ++} ++ ++void hist_print_oflows(struct histogram *h, FILE *f) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < h->oflow_count; i++) { ++ if (i >= h->oflow_bufsize) ++ break; ++ if (i != 0) ++ fprintf(f, " "); ++ fprintf(f, "%05lu", h->oflows[i]); ++ } ++ ++ if (i >= h->oflow_bufsize) ++ fprintf(f, " # %05lu others", h->oflow_count - h->oflow_bufsize); ++} +-- +2.43.0 + diff --git a/rt-tests-oslat-convert-to-nanoseconds-correctly.patch b/rt-tests-oslat-convert-to-nanoseconds-correctly.patch new file mode 100644 index 0000000..cff3ed0 --- /dev/null +++ b/rt-tests-oslat-convert-to-nanoseconds-correctly.patch @@ -0,0 +1,42 @@ +From 4aeacf722cee26a3f88ab7f631c9ab9ba6ecdb49 Mon Sep 17 00:00:00 2001 +From: Marcelo Tosatti +Date: Thu, 1 Feb 2024 14:50:54 -0300 +Subject: [PATCH 2/2] rt-tests: oslat: convert to nanoseconds correctly + +With buckets of size 1us, accounting for measurements in the +[1ns, 999ns] range are done to the 2us bucket (while they +should be accounted in the 1us bucket): + + 001 (us): 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 002 (us): 41916187 41937649 41938461 42029055 ... + 003 (us): 969 985 958 972 964 986 970 961 973 ... + +Fix this by doing a plain cycles -> nanoseconds convertion: + + 001 (us): 43287555 43086678 43087427 43109974 ... + 002 (us): 983 987 985 975 982 960 993 961 992 ... + 003 (us): 9 6 7 13 9 22 3 21 3 3 8 8 10 11 3 55 + +Signed-off-by: Marcelo Tosatti +Reported-by: Chuck Newman +Signed-off-by: John Kacur +--- + src/oslat/oslat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c +index e398f205b40a..0863297f2cf1 100644 +--- a/src/oslat/oslat.c ++++ b/src/oslat/oslat.c +@@ -334,7 +334,7 @@ static void insert_bucket(struct thread *t, stamp_t value) + uint64_t extra; + double us; + +- lat = (value * g.unit_per_us + t->counter_mhz - 1) / t->counter_mhz; ++ lat = (value * g.unit_per_us) / t->counter_mhz; + us = (double)lat / g.unit_per_us; + if (!g.preheat && g.trace_threshold && us >= g.trace_threshold) { + char *line = "%s: Trace threshold (%d us) triggered on cpu %d with %.*f us!\n"; +-- +2.43.0 + diff --git a/rt-tests-oslat-should-use-MHz-not-Mhz.patch b/rt-tests-oslat-should-use-MHz-not-Mhz.patch new file mode 100644 index 0000000..354baa5 --- /dev/null +++ b/rt-tests-oslat-should-use-MHz-not-Mhz.patch @@ -0,0 +1,34 @@ +From 251d082403b371098c8420c01d1b058b12a9cc78 Mon Sep 17 00:00:00 2001 +From: Marcelo Tosatti +Date: Thu, 1 Feb 2024 13:05:38 -0300 +Subject: [PATCH 1/2] rt-tests: oslat should use MHz, not Mhz + +Usage of Mhz, in oslat, is incorrect: + +From https://www.nist.gov/pml/owm/writing-si-metric-system-units#:~:text=NOT%20250%20mms.-,Capitalization,the%20beginning%20of%20the%20sentence: + +"When the unit is derived from the name of a person, the symbol or the first letter of the symbol is an uppercase letter (W for the unit "watt" or Pa for the unit "pascal")." + +Signed-off-by: Marcelo Tosatti +Reported-by: Chuck Newman +Signed-off-by: John Kacur +--- + src/oslat/oslat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c +index 4bdca643da72..e398f205b40a 100644 +--- a/src/oslat/oslat.c ++++ b/src/oslat/oslat.c +@@ -501,7 +501,7 @@ static void write_summary(struct thread *t) + calculate(t); + + putfield("Core", t[i].core_i, "d", ""); +- putfield("Counter Freq", t[i].counter_mhz, "u", " (Mhz)"); ++ putfield("Counter Freq", t[i].counter_mhz, "u", " (MHz)"); + + for (j = 0; j < g.bucket_size; j++) { + if (j < g.bucket_size-1 && g.output_omit_zero_buckets) { +-- +2.43.0 + diff --git a/tests/scripts/run_tests.sh b/tests/scripts/run_tests.sh new file mode 100755 index 0000000..6aa833b --- /dev/null +++ b/tests/scripts/run_tests.sh @@ -0,0 +1,45 @@ +#!/usr/bin/bash + +# make sure we have rt-tests installed +if rpm -q --quiet realtime-tests; then + : +else + sudo dnf install -y realtime-tests + if [[ $? != 0 ]]; then + echo "install of realtime-tests failed!" + exit 1 + fi +fi + +progs="/usr/bin/cyclicdeadline +/usr/bin/cyclictest +/usr/bin/deadline_test +/usr/bin/determine_maximum_mpps.sh +/usr/bin/get_cyclictest_snapshot +/usr/bin/hackbench +/usr/bin/hwlatdetect +/usr/bin/oslat +/usr/bin/pi_stress +/usr/bin/pip_stress +/usr/bin/pmqtest +/usr/bin/ptsematest +/usr/bin/queuelat +/usr/bin/rt-migrate-test +/usr/bin/signaltest +/usr/bin/sigwaittest +/usr/bin/ssdd +/usr/bin/svsematest" + +# check bins +for prog in ${progs}; do + if [[ ! -f $prog ]]; then + echo "$prog: not found" + exit 2 + fi + if [[ ! -e $prog ]]; then + echo "$prog: not executable" + exit 3 + fi +done + +exit 0 diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..cf6a85c --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,11 @@ +- hosts: localhost + roles: + - role: standard-test-basic + tags: + - classic + tests: + - simple: + dir: scripts + run: ./run_tests.sh + required_packages: + - realtime-tests