uaccess_flush.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2018 IBM Corporation.
  4. * Copyright 2020 Canonical Ltd.
  5. */
  6. #define __SANE_USERSPACE_TYPES__
  7. #include <sys/types.h>
  8. #include <stdint.h>
  9. #include <malloc.h>
  10. #include <unistd.h>
  11. #include <signal.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include "utils.h"
  16. #include "flush_utils.h"
  17. int uaccess_flush_test(void)
  18. {
  19. char *p;
  20. int repetitions = 10;
  21. int fd, passes = 0, iter, rc = 0;
  22. struct perf_event_read v;
  23. __u64 l1d_misses_total = 0;
  24. unsigned long iterations = 100000, zero_size = 24 * 1024;
  25. unsigned long l1d_misses_expected;
  26. int rfi_flush_orig;
  27. int entry_flush_orig;
  28. int uaccess_flush, uaccess_flush_orig;
  29. SKIP_IF(geteuid() != 0);
  30. // The PMU event we use only works on Power7 or later
  31. SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
  32. if (read_debugfs_int("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
  33. perror("Unable to read powerpc/rfi_flush debugfs file");
  34. SKIP_IF(1);
  35. }
  36. if (read_debugfs_int("powerpc/entry_flush", &entry_flush_orig) < 0) {
  37. perror("Unable to read powerpc/entry_flush debugfs file");
  38. SKIP_IF(1);
  39. }
  40. if (read_debugfs_int("powerpc/uaccess_flush", &uaccess_flush_orig) < 0) {
  41. perror("Unable to read powerpc/entry_flush debugfs file");
  42. SKIP_IF(1);
  43. }
  44. if (rfi_flush_orig != 0) {
  45. if (write_debugfs_int("powerpc/rfi_flush", 0) < 0) {
  46. perror("error writing to powerpc/rfi_flush debugfs file");
  47. FAIL_IF(1);
  48. }
  49. }
  50. if (entry_flush_orig != 0) {
  51. if (write_debugfs_int("powerpc/entry_flush", 0) < 0) {
  52. perror("error writing to powerpc/entry_flush debugfs file");
  53. FAIL_IF(1);
  54. }
  55. }
  56. uaccess_flush = uaccess_flush_orig;
  57. fd = perf_event_open_counter(PERF_TYPE_HW_CACHE, PERF_L1D_READ_MISS_CONFIG, -1);
  58. FAIL_IF(fd < 0);
  59. p = (char *)memalign(zero_size, CACHELINE_SIZE);
  60. FAIL_IF(perf_event_enable(fd));
  61. // disable L1 prefetching
  62. set_dscr(1);
  63. iter = repetitions;
  64. /*
  65. * We expect to see l1d miss for each cacheline access when entry_flush
  66. * is set. Allow a small variation on this.
  67. */
  68. l1d_misses_expected = iterations * (zero_size / CACHELINE_SIZE - 2);
  69. again:
  70. FAIL_IF(perf_event_reset(fd));
  71. syscall_loop_uaccess(p, iterations, zero_size);
  72. FAIL_IF(read(fd, &v, sizeof(v)) != sizeof(v));
  73. if (uaccess_flush && v.l1d_misses >= l1d_misses_expected)
  74. passes++;
  75. else if (!uaccess_flush && v.l1d_misses < (l1d_misses_expected / 2))
  76. passes++;
  77. l1d_misses_total += v.l1d_misses;
  78. while (--iter)
  79. goto again;
  80. if (passes < repetitions) {
  81. printf("FAIL (L1D misses with uaccess_flush=%d: %llu %c %lu) [%d/%d failures]\n",
  82. uaccess_flush, l1d_misses_total, uaccess_flush ? '<' : '>',
  83. uaccess_flush ? repetitions * l1d_misses_expected :
  84. repetitions * l1d_misses_expected / 2,
  85. repetitions - passes, repetitions);
  86. rc = 1;
  87. } else {
  88. printf("PASS (L1D misses with uaccess_flush=%d: %llu %c %lu) [%d/%d pass]\n",
  89. uaccess_flush, l1d_misses_total, uaccess_flush ? '>' : '<',
  90. uaccess_flush ? repetitions * l1d_misses_expected :
  91. repetitions * l1d_misses_expected / 2,
  92. passes, repetitions);
  93. }
  94. if (uaccess_flush == uaccess_flush_orig) {
  95. uaccess_flush = !uaccess_flush_orig;
  96. if (write_debugfs_int("powerpc/uaccess_flush", uaccess_flush) < 0) {
  97. perror("error writing to powerpc/uaccess_flush debugfs file");
  98. return 1;
  99. }
  100. iter = repetitions;
  101. l1d_misses_total = 0;
  102. passes = 0;
  103. goto again;
  104. }
  105. perf_event_disable(fd);
  106. close(fd);
  107. set_dscr(0);
  108. if (write_debugfs_int("powerpc/rfi_flush", rfi_flush_orig) < 0) {
  109. perror("unable to restore original value of powerpc/rfi_flush debugfs file");
  110. return 1;
  111. }
  112. if (write_debugfs_int("powerpc/entry_flush", entry_flush_orig) < 0) {
  113. perror("unable to restore original value of powerpc/entry_flush debugfs file");
  114. return 1;
  115. }
  116. if (write_debugfs_int("powerpc/uaccess_flush", uaccess_flush_orig) < 0) {
  117. perror("unable to restore original value of powerpc/uaccess_flush debugfs file");
  118. return 1;
  119. }
  120. return rc;
  121. }
  122. int main(int argc, char *argv[])
  123. {
  124. return test_harness(uaccess_flush_test, "uaccess_flush_test");
  125. }