gettime_perf.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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. #include "log.h"
  14. #include "timens.h"
  15. typedef int (*vgettime_t)(clockid_t, struct timespec *);
  16. vgettime_t vdso_clock_gettime;
  17. static void fill_function_pointers(void)
  18. {
  19. void *vdso = dlopen("linux-vdso.so.1",
  20. RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  21. if (!vdso)
  22. vdso = dlopen("linux-gate.so.1",
  23. RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  24. if (!vdso)
  25. vdso = dlopen("linux-vdso32.so.1",
  26. RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  27. if (!vdso)
  28. vdso = dlopen("linux-vdso64.so.1",
  29. RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
  30. if (!vdso) {
  31. pr_err("[WARN]\tfailed to find vDSO\n");
  32. return;
  33. }
  34. vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime");
  35. if (!vdso_clock_gettime)
  36. vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__kernel_clock_gettime");
  37. if (!vdso_clock_gettime)
  38. pr_err("Warning: failed to find clock_gettime in vDSO\n");
  39. }
  40. static void test(clock_t clockid, char *clockstr, bool in_ns)
  41. {
  42. struct timespec tp, start;
  43. long i = 0;
  44. const int timeout = 3;
  45. vdso_clock_gettime(clockid, &start);
  46. tp = start;
  47. for (tp = start; start.tv_sec + timeout > tp.tv_sec ||
  48. (start.tv_sec + timeout == tp.tv_sec &&
  49. start.tv_nsec > tp.tv_nsec); i++) {
  50. vdso_clock_gettime(clockid, &tp);
  51. }
  52. ksft_test_result_pass("%s:\tclock: %10s\tcycles:\t%10ld\n",
  53. in_ns ? "ns" : "host", clockstr, i);
  54. }
  55. int main(int argc, char *argv[])
  56. {
  57. time_t offset = 10;
  58. int nsfd;
  59. ksft_set_plan(8);
  60. fill_function_pointers();
  61. test(CLOCK_MONOTONIC, "monotonic", false);
  62. test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", false);
  63. test(CLOCK_MONOTONIC_RAW, "monotonic-raw", false);
  64. test(CLOCK_BOOTTIME, "boottime", false);
  65. nscheck();
  66. if (unshare_timens())
  67. return 1;
  68. nsfd = open("/proc/self/ns/time_for_children", O_RDONLY);
  69. if (nsfd < 0)
  70. return pr_perror("Can't open a time namespace");
  71. if (_settime(CLOCK_MONOTONIC, offset))
  72. return 1;
  73. if (_settime(CLOCK_BOOTTIME, offset))
  74. return 1;
  75. if (setns(nsfd, CLONE_NEWTIME))
  76. return pr_perror("setns");
  77. test(CLOCK_MONOTONIC, "monotonic", true);
  78. test(CLOCK_MONOTONIC_COARSE, "monotonic-coarse", true);
  79. test(CLOCK_MONOTONIC_RAW, "monotonic-raw", true);
  80. test(CLOCK_BOOTTIME, "boottime", true);
  81. ksft_exit_pass();
  82. return 0;
  83. }