| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- // 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;
- }
|