diff options
author | Paul E. McKenney <paulmck@kernel.org> | 2023-12-13 18:01:03 -0800 |
---|---|---|
committer | Paul E. McKenney <paulmck@kernel.org> | 2023-12-14 09:59:25 -0800 |
commit | fc34c929d7734606c7a73ddbb0580bba619dc50a (patch) | |
tree | 730c8163ce5d6dd10162740b2200759d9d21e005 | |
parent | eeeaebac158cf5cd08886c1263aac11f85d6c568 (diff) | |
download | perfbook-fc34c929d7734606c7a73ddbb0580bba619dc50a.tar.gz |
CodeSamples/cpu: Add tscalibrate.c to calibrary get_timestamp()
Result in nanoseconds.
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
-rw-r--r-- | CodeSamples/cpu/.gitignore | 1 | ||||
-rw-r--r-- | CodeSamples/cpu/Makefile | 5 | ||||
-rw-r--r-- | CodeSamples/cpu/tscalibrate.c | 167 |
3 files changed, 172 insertions, 1 deletions
diff --git a/CodeSamples/cpu/.gitignore b/CodeSamples/cpu/.gitignore index 09c58115..501bd091 100644 --- a/CodeSamples/cpu/.gitignore +++ b/CodeSamples/cpu/.gitignore @@ -1,2 +1,3 @@ cachetorture temporal +tscalibrate diff --git a/CodeSamples/cpu/Makefile b/CodeSamples/cpu/Makefile index 13eaff69..1b3fcff4 100644 --- a/CodeSamples/cpu/Makefile +++ b/CodeSamples/cpu/Makefile @@ -17,7 +17,7 @@ include ../Makefile.arch -PROGS = cachetorture temporal +PROGS = cachetorture temporal tscalibrate top := .. include $(top)/depends.mk @@ -39,5 +39,8 @@ cachetorture: cachetorture.c ../api.h temporal: temporal.c ../api.h $(CC) $(GCC_ARGS) $(CFLAGS) -o temporal temporal.c -lpthread +tscalibrate: tscalibrate.c ../api.h + $(CC) $(GCC_ARGS) $(CFLAGS) -o tscalibrate tscalibrate.c + clean: rm -f $(PROGS) diff --git a/CodeSamples/cpu/tscalibrate.c b/CodeSamples/cpu/tscalibrate.c new file mode 100644 index 00000000..b5ba9637 --- /dev/null +++ b/CodeSamples/cpu/tscalibrate.c @@ -0,0 +1,167 @@ +/* + * tscalibrate.c: Calibrate the get_timestamp() function + * + * @@@ This test produces output as follows: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + * Copyright (c) 2023 Paul E. McKenney, Meta Platforms Inc. + */ + +#include "../api.h" +#include <time.h> +#include <stdarg.h> +#include <stdbool.h> + +struct sample { + long long s_cgtdur; + long long s_tsdur; +}; + +/* + * Test variables. + */ + +static int duration = 100; +static int maxlatency = 5; +static int nsamples = 24; + +// Collect one timestamp. +bool ts1read(struct sample *sp) +{ + long long cgt1; + long long cgt2; + + cgt1 = get_microseconds(); + sp->s_tsdur = get_timestamp(); + cgt2 = get_microseconds(); + if (cgt2 < cgt1 || cgt2 - cgt1 > maxlatency) + return false; + sp->s_cgtdur = (cgt1 + cgt2) / 2ULL; + return true; +} + +// Collect one timestamp calibration sample. +void ts1sample(struct sample *sp) +{ + int i = 0; + struct sample s1; + struct sample s2; + + for (;;) { + BUG_ON(++i > 10); + if (!ts1read(&s1)) + continue; + poll(NULL, 0, duration); + if (ts1read(&s2)) + break; + } + sp->s_cgtdur = s2.s_cgtdur - s1.s_cgtdur; + sp->s_tsdur = s2.s_tsdur - s1.s_tsdur; +} + +// Collect timestamp calibration samples. +void tscollectsamples(struct sample *sp) +{ + int i; + + for (i = 0; i < nsamples; i++) + ts1sample(&sp[i]); +} + +// Collect the samples, compute the statistics, and print the results. +void tscalibrate(void) +{ + double avg_cgt; + double avg_ts; + double cur; + int i; + double max; + double min; + struct sample *sp = calloc(nsamples, sizeof(*sp)); + struct sample sum = {}; + + BUG_ON(!sp); + tscollectsamples(sp); + + sum = sp[0]; + min = sp[0].s_cgtdur * 1000. / (double)sp[0].s_tsdur; + max = sp[0].s_cgtdur * 1000. / (double)sp[0].s_tsdur; + for (i = 1; i < nsamples; i++) { + sum.s_cgtdur += sp[i].s_cgtdur; + sum.s_tsdur += sp[i].s_tsdur; + cur = sp[i].s_cgtdur * 1000. / (double)sp[i].s_tsdur; + if (cur < min) + min = cur; + if (cur > max) + max = cur; + } + avg_cgt = sum.s_cgtdur / (double)nsamples; + avg_ts = sum.s_tsdur / (double)nsamples; + printf("duration: %d maxlatency: %d nsamples: %d min: %g max: %g avg: %g (ns per timestamp unit)\n", + duration, maxlatency, nsamples, min, max, avg_cgt * 1000. / avg_ts); +} + + +/* + * Mainprogram. + */ + +void usage(char *progname, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, "Usage: %s\n", progname); + fprintf(stderr, "\t --duration\n"); + fprintf(stderr, "\t\tDuration of run in milliseconds (default 100).\n"); + fprintf(stderr, "\t --maxlatency\n"); + fprintf(stderr, "\t\tMaximum timestamp latency (default 5us).\n"); + fprintf(stderr, "\t --nsamples\n"); + fprintf(stderr, "\t\tNumber of samples (default 24).\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int i = 1; + + while (i < argc) { + if (strcmp(argv[i], "--duration") == 0) { + duration = atoi(argv[++i]); + if (duration <= 0) + usage(argv[0], "%s: --duration argument must be positive.\n", argv[i]); + ++i; + } else if (strcmp(argv[i], "--maxlatency") == 0) { + maxlatency = atoi(argv[++i]); + if (maxlatency <= 0) + usage(argv[0], "%s: --maxlatency argument must be positive.\n", argv[i]); + ++i; + } else if (strcmp(argv[i], "--nsamples") == 0) { + nsamples = atoi(argv[++i]); + if (nsamples <= 1) + usage(argv[0], "%s: --nsamples argument must be positive.\n", argv[i]); + ++i; + } else { + usage(argv[0], "Unrecognized argument: %s\n", argv[i]); + } + } + + tscalibrate(); + + return 0; +} |