fill_buf.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. void fill_cache_read(unsigned char *buf, size_t buf_size, bool once)
  78. {
  79. int ret = 0;
  80. while (1) {
  81. ret = fill_one_span_read(buf, buf_size);
  82. if (once)
  83. break;
  84. }
  85. /* Consume read result so that reading memory is not optimized out. */
  86. *value_sink = ret;
  87. }
  88. unsigned char *alloc_buffer(size_t buf_size, bool memflush)
  89. {
  90. void *buf = NULL;
  91. uint64_t *p64;
  92. ssize_t s64;
  93. int ret;
  94. ret = posix_memalign(&buf, PAGE_SIZE, buf_size);
  95. if (ret < 0)
  96. return NULL;
  97. /* Initialize the buffer */
  98. p64 = buf;
  99. s64 = buf_size / sizeof(uint64_t);
  100. while (s64 > 0) {
  101. *p64 = (uint64_t)rand();
  102. p64 += (CL_SIZE / sizeof(uint64_t));
  103. s64 -= (CL_SIZE / sizeof(uint64_t));
  104. }
  105. /* Flush the memory before using to avoid "cache hot pages" effect */
  106. if (memflush)
  107. mem_flush(buf, buf_size);
  108. return buf;
  109. }
  110. ssize_t get_fill_buf_size(int cpu_no, const char *cache_type)
  111. {
  112. unsigned long cache_total_size = 0;
  113. int ret;
  114. ret = get_cache_size(cpu_no, cache_type, &cache_total_size);
  115. if (ret)
  116. return ret;
  117. return cache_total_size * 2 > MINIMUM_SPAN ?
  118. cache_total_size * 2 : MINIMUM_SPAN;
  119. }