mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-23 16:47:49 -04:00
Errata for Sierra Forest [1] (SRF42) and Granite Rapids [2] (GNR12) describe the problem that MBM on Intel RDT may overcount memory bandwidth measurements. The resctrl tests compare memory bandwidth reported by iMC PMU to that reported by MBM causing the tests to fail on these systems depending on the settings of the platform related to the errata. Since the resctrl tests need to run under various conditions it is not possible to ensure system settings are such that MBM will not overcount. It has been observed that the overcounting can be controlled via the buffer size used in the MBM and MBA tests that rely on comparisons between iMC PMU and MBM measurements. Running the MBM test on affected platforms with different buffer sizes it can be observed that the difference between iMC PMU and MBM counts reduce as the buffer size increases. After increasing the buffer size to more than 4X the differences between iMC PMU and MBM become insignificant. Increase the buffer size used in MBM and MBA tests to 4X L3 size to reduce possibility of tests failing due to difference in counts reported by iMC PMU and MBM. Link: https://lore.kernel.org/r/1bd4d8c5fc791234b0a9da94f29a3e278ba2f7ee.1775266384.git.reinette.chatre@intel.com Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Tested-by: Chen Yu <yu.c.chen@intel.com> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Link: https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/sierra-forest/xeon-6700-series-processor-with-e-cores-specification-update/errata-details/ # [1] Link: https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/birch-stream/xeon-6900-6700-6500-series-processors-with-p-cores-specification-update/011US/errata-details/ # [2] Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
145 lines
3.0 KiB
C
145 lines
3.0 KiB
C
// 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 * 4 > MINIMUM_SPAN ?
|
|
cache_total_size * 4 : MINIMUM_SPAN;
|
|
}
|