fill_buf.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * fill_buf benchmark
  4. *
  5. * Copyright (C) 2018 Intel Corporation
  6. *
  7. * Authors:
  8. * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
  9. * Fenghua Yu <fenghua.yu@intel.com>
  10. */
  11. #include <stdio.h>
  12. #include <unistd.h>
  13. #include <stdlib.h>
  14. #include <sys/types.h>
  15. #include <sys/wait.h>
  16. #include <inttypes.h>
  17. #include <string.h>
  18. #include "resctrl.h"
  19. #define CL_SIZE (64)
  20. #define PAGE_SIZE (4 * 1024)
  21. #define MB (1024 * 1024)
  22. static void sb(void)
  23. {
  24. #if defined(__i386) || defined(__x86_64)
  25. asm volatile("sfence\n\t"
  26. : : : "memory");
  27. #endif
  28. }
  29. static void cl_flush(void *p)
  30. {
  31. #if defined(__i386) || defined(__x86_64)
  32. asm volatile("clflush (%0)\n\t"
  33. : : "r"(p) : "memory");
  34. #endif
  35. }
  36. void mem_flush(unsigned char *buf, size_t buf_size)
  37. {
  38. unsigned char *cp = buf;
  39. size_t i = 0;
  40. buf_size = buf_size / CL_SIZE; /* mem size in cache lines */
  41. for (i = 0; i < buf_size; i++)
  42. cl_flush(&cp[i * CL_SIZE]);
  43. sb();
  44. }
  45. /*
  46. * Buffer index step advance to workaround HW prefetching interfering with
  47. * the measurements.
  48. *
  49. * Must be a prime to step through all indexes of the buffer.
  50. *
  51. * Some primes work better than others on some architectures (from MBA/MBM
  52. * result stability point of view).
  53. */
  54. #define FILL_IDX_MULT 23
  55. static int fill_one_span_read(unsigned char *buf, size_t buf_size)
  56. {
  57. unsigned int size = buf_size / (CL_SIZE / 2);
  58. unsigned int i, idx = 0;
  59. unsigned char sum = 0;
  60. /*
  61. * Read the buffer in an order that is unexpected by HW prefetching
  62. * optimizations to prevent them interfering with the caching pattern.
  63. *
  64. * The read order is (in terms of halves of cachelines):
  65. * i * FILL_IDX_MULT % size
  66. * The formula is open-coded below to avoiding modulo inside the loop
  67. * as it improves MBA/MBM result stability on some architectures.
  68. */
  69. for (i = 0; i < size; i++) {
  70. sum += buf[idx * (CL_SIZE / 2)];
  71. idx += FILL_IDX_MULT;
  72. while (idx >= size)
  73. idx -= size;
  74. }
  75. return sum;
  76. }
  77. static void fill_one_span_write(unsigned char *buf, size_t buf_size)
  78. {
  79. unsigned char *end_ptr = buf + buf_size;
  80. unsigned char *p;
  81. p = buf;
  82. while (p < end_ptr) {
  83. *p = '1';
  84. p += (CL_SIZE / 2);
  85. }
  86. }
  87. void fill_cache_read(unsigned char *buf, size_t buf_size, bool once)
  88. {
  89. int ret = 0;
  90. while (1) {
  91. ret = fill_one_span_read(buf, buf_size);
  92. if (once)
  93. break;
  94. }
  95. /* Consume read result so that reading memory is not optimized out. */
  96. *value_sink = ret;
  97. }
  98. static void fill_cache_write(unsigned char *buf, size_t buf_size, bool once)
  99. {
  100. while (1) {
  101. fill_one_span_write(buf, buf_size);
  102. if (once)
  103. break;
  104. }
  105. }
  106. unsigned char *alloc_buffer(size_t buf_size, int memflush)
  107. {
  108. void *buf = NULL;
  109. uint64_t *p64;
  110. ssize_t s64;
  111. int ret;
  112. ret = posix_memalign(&buf, PAGE_SIZE, buf_size);
  113. if (ret < 0)
  114. return NULL;
  115. /* Initialize the buffer */
  116. p64 = buf;
  117. s64 = buf_size / sizeof(uint64_t);
  118. while (s64 > 0) {
  119. *p64 = (uint64_t)rand();
  120. p64 += (CL_SIZE / sizeof(uint64_t));
  121. s64 -= (CL_SIZE / sizeof(uint64_t));
  122. }
  123. /* Flush the memory before using to avoid "cache hot pages" effect */
  124. if (memflush)
  125. mem_flush(buf, buf_size);
  126. return buf;
  127. }
  128. int run_fill_buf(size_t buf_size, int memflush, int op, bool once)
  129. {
  130. unsigned char *buf;
  131. buf = alloc_buffer(buf_size, memflush);
  132. if (!buf)
  133. return -1;
  134. if (op == 0)
  135. fill_cache_read(buf, buf_size, once);
  136. else
  137. fill_cache_write(buf, buf_size, once);
  138. free(buf);
  139. return 0;
  140. }