diff options
Diffstat (limited to 'tools/testing/selftests/timens/gettime_perf.c')
-rw-r--r-- | tools/testing/selftests/timens/gettime_perf.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/tools/testing/selftests/timens/gettime_perf.c b/tools/testing/selftests/timens/gettime_perf.c new file mode 100644 index 000000000..6b13dc277 --- /dev/null +++ b/tools/testing/selftests/timens/gettime_perf.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <sched.h> +#include <time.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <dlfcn.h> + +#include "log.h" +#include "timens.h" + +typedef int (*vgettime_t)(clockid_t, struct timespec *); + +vgettime_t vdso_clock_gettime; + +static void fill_function_pointers(void) +{ + void *vdso = dlopen("linux-vdso.so.1", + RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); + if (!vdso) + vdso = dlopen("linux-gate.so.1", + RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); + if (!vdso) + vdso = dlopen("linux-vdso32.so.1", + RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); + if (!vdso) + vdso = dlopen("linux-vdso64.so.1", + RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); + if (!vdso) { + pr_err("[WARN]\tfailed to find vDSO\n"); + return; + } + + vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); + if (!vdso_clock_gettime) + vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__kernel_clock_gettime"); + if (!vdso_clock_gettime) + pr_err("Warning: failed to find clock_gettime in vDSO\n"); + +} + +static void test(clock_t clockid, char *clockstr, bool in_ns) +{ + struct timespec tp, start; + long i = 0; + const int timeout = 3; + + vdso_clock_gettime(clockid, &start); + tp = start; + for (tp = start; start.tv_sec + timeout > tp.tv_sec || + (start.tv_sec + timeout == tp.tv_sec && + start.tv_nsec > tp.tv_nsec); i++) { + vdso_clock_gettime(clockid, &tp); + } + + ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n", + in_ns ? "ns" : "host", clockstr, i); +} + +int main(int argc, char *argv[]) +{ + time_t offset = 10; + int nsfd; + + ksft_set_plan(8); + + fill_function_pointers(); + + test(CLOCK_MONOTONIC, "monotonic", false); + test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false); + test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false); + test(CLOCK_BOOTTIME, "boottime", false); + + nscheck(); + + if (unshare_timens()) + return 1; + + nsfd = open("/proc/self/ns/time_for_children", O_RDONLY); + if (nsfd < 0) + return pr_perror("Can't open a time namespace"); + + if (_settime(CLOCK_MONOTONIC, offset)) + return 1; + if (_settime(CLOCK_BOOTTIME, offset)) + return 1; + + if (setns(nsfd, CLONE_NEWTIME)) + return pr_perror("setns"); + + test(CLOCK_MONOTONIC, "monotonic", true); + test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true); + test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true); + test(CLOCK_BOOTTIME, "boottime", true); + + ksft_exit_pass(); + return 0; +} |