linux/tools/testing/selftests/timens/gettime_perf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#define _GNU_SOURCE
   3#include <sys/types.h>
   4#include <sys/stat.h>
   5#include <errno.h>
   6#include <fcntl.h>
   7#include <sched.h>
   8#include <time.h>
   9#include <stdio.h>
  10#include <unistd.h>
  11#include <sys/syscall.h>
  12#include <dlfcn.h>
  13
  14#include "log.h"
  15#include "timens.h"
  16
  17typedef int (*vgettime_t)(clockid_t, struct timespec *);
  18
  19vgettime_t vdso_clock_gettime;
  20
  21static void fill_function_pointers(void)
  22{
  23        void *vdso = dlopen("linux-vdso.so.1",
  24                            RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  25        if (!vdso)
  26                vdso = dlopen("linux-gate.so.1",
  27                              RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  28        if (!vdso)
  29                vdso = dlopen("linux-vdso32.so.1",
  30                              RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  31        if (!vdso)
  32                vdso = dlopen("linux-vdso64.so.1",
  33                              RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  34        if (!vdso) {
  35                pr_err("[WARN]\tfailed to find vDSO\n");
  36                return;
  37        }
  38
  39        vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime");
  40        if (!vdso_clock_gettime)
  41                vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__kernel_clock_gettime");
  42        if (!vdso_clock_gettime)
  43                pr_err("Warning: failed to find clock_gettime in vDSO\n");
  44
  45}
  46
  47static void test(clock_t clockid, char *clockstr, bool in_ns)
  48{
  49        struct timespec tp, start;
  50        long i = 0;
  51        const int timeout = 3;
  52
  53        vdso_clock_gettime(clockid, &start);
  54        tp = start;
  55        for (tp = start; start.tv_sec + timeout > tp.tv_sec ||
  56                         (start.tv_sec + timeout == tp.tv_sec &&
  57                          start.tv_nsec > tp.tv_nsec); i++) {
  58                vdso_clock_gettime(clockid, &tp);
  59        }
  60
  61        ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n",
  62                              in_ns ? "ns" : "host", clockstr, i);
  63}
  64
  65int main(int argc, char *argv[])
  66{
  67        time_t offset = 10;
  68        int nsfd;
  69
  70        ksft_set_plan(8);
  71
  72        fill_function_pointers();
  73
  74        test(CLOCK_MONOTONIC, "monotonic", false);
  75        test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false);
  76        test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false);
  77        test(CLOCK_BOOTTIME, "boottime", false);
  78
  79        nscheck();
  80
  81        if (unshare_timens())
  82                return 1;
  83
  84        nsfd = open("/proc/self/ns/time_for_children", O_RDONLY);
  85        if (nsfd < 0)
  86                return pr_perror("Can't open a time namespace");
  87
  88        if (_settime(CLOCK_MONOTONIC, offset))
  89                return 1;
  90        if (_settime(CLOCK_BOOTTIME, offset))
  91                return 1;
  92
  93        if (setns(nsfd, CLONE_NEWTIME))
  94                return pr_perror("setns");
  95
  96        test(CLOCK_MONOTONIC, "monotonic", true);
  97        test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true);
  98        test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true);
  99        test(CLOCK_BOOTTIME, "boottime", true);
 100
 101        ksft_exit_pass();
 102        return 0;
 103}
 104