diff options
Diffstat (limited to 'tools/testing/selftests/resctrl/fill_buf.c')
| -rw-r--r-- | tools/testing/selftests/resctrl/fill_buf.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/tools/testing/selftests/resctrl/fill_buf.c b/tools/testing/selftests/resctrl/fill_buf.c new file mode 100644 index 000000000000..19a01a52dc1a --- /dev/null +++ b/tools/testing/selftests/resctrl/fill_buf.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * fill_buf benchmark + * + * Copyright (C) 2018 Intel Corporation + * + * Authors: + * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>, + * Fenghua Yu <fenghua.yu@intel.com> + */ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <inttypes.h> +#include <string.h> + +#include "resctrl.h" + +#define CL_SIZE (64) +#define PAGE_SIZE (4 * 1024) +#define MB (1024 * 1024) + +static void sb(void) +{ +#if defined(__i386) || defined(__x86_64) + asm volatile("sfence\n\t" + : : : "memory"); +#endif +} + +static void cl_flush(void *p) +{ +#if defined(__i386) || defined(__x86_64) + asm volatile("clflush (%0)\n\t" + : : "r"(p) : "memory"); +#endif +} + +void mem_flush(unsigned char *buf, size_t buf_size) +{ + unsigned char *cp = buf; + size_t i = 0; + + buf_size = buf_size / CL_SIZE; /* mem size in cache lines */ + + for (i = 0; i < buf_size; i++) + cl_flush(&cp[i * CL_SIZE]); + + sb(); +} + +/* + * Buffer index step advance to workaround HW prefetching interfering with + * the measurements. + * + * Must be a prime to step through all indexes of the buffer. + * + * Some primes work better than others on some architectures (from MBA/MBM + * result stability point of view). + */ +#define FILL_IDX_MULT 23 + +static int fill_one_span_read(unsigned char *buf, size_t buf_size) +{ + unsigned int size = buf_size / (CL_SIZE / 2); + unsigned int i, idx = 0; + unsigned char sum = 0; + + /* + * Read the buffer in an order that is unexpected by HW prefetching + * optimizations to prevent them interfering with the caching pattern. + * + * The read order is (in terms of halves of cachelines): + * i * FILL_IDX_MULT % size + * The formula is open-coded below to avoiding modulo inside the loop + * as it improves MBA/MBM result stability on some architectures. + */ + for (i = 0; i < size; i++) { + sum += buf[idx * (CL_SIZE / 2)]; + + idx += FILL_IDX_MULT; + while (idx >= size) + idx -= size; + } + + return sum; +} + +void fill_cache_read(unsigned char *buf, size_t buf_size, bool once) +{ + int ret = 0; + + while (1) { + ret = fill_one_span_read(buf, buf_size); + if (once) + break; + } + + /* Consume read result so that reading memory is not optimized out. */ + *value_sink = ret; +} + +unsigned char *alloc_buffer(size_t buf_size, bool memflush) +{ + void *buf = NULL; + uint64_t *p64; + ssize_t s64; + int ret; + + ret = posix_memalign(&buf, PAGE_SIZE, buf_size); + if (ret < 0) + return NULL; + + /* Initialize the buffer */ + p64 = buf; + s64 = buf_size / sizeof(uint64_t); + + while (s64 > 0) { + *p64 = (uint64_t)rand(); + p64 += (CL_SIZE / sizeof(uint64_t)); + s64 -= (CL_SIZE / sizeof(uint64_t)); + } + + /* Flush the memory before using to avoid "cache hot pages" effect */ + if (memflush) + mem_flush(buf, buf_size); + + return buf; +} + +ssize_t get_fill_buf_size(int cpu_no, const char *cache_type) +{ + unsigned long cache_total_size = 0; + int ret; + + ret = get_cache_size(cpu_no, cache_type, &cache_total_size); + if (ret) + return ret; + + return cache_total_size * 2 > MINIMUM_SPAN ? + cache_total_size * 2 : MINIMUM_SPAN; +} |
