1
0

rfi_flush.c 3.4 KB

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