1a2561b12SSai Praneeth Prakhya // SPDX-License-Identifier: GPL-2.0
2a2561b12SSai Praneeth Prakhya /*
3a2561b12SSai Praneeth Prakhya * fill_buf benchmark
4a2561b12SSai Praneeth Prakhya *
5a2561b12SSai Praneeth Prakhya * Copyright (C) 2018 Intel Corporation
6a2561b12SSai Praneeth Prakhya *
7a2561b12SSai Praneeth Prakhya * Authors:
8a2561b12SSai Praneeth Prakhya * Sai Praneeth Prakhya <[email protected]>,
9a2561b12SSai Praneeth Prakhya * Fenghua Yu <[email protected]>
10a2561b12SSai Praneeth Prakhya */
11a2561b12SSai Praneeth Prakhya #include <stdio.h>
12a2561b12SSai Praneeth Prakhya #include <unistd.h>
13a2561b12SSai Praneeth Prakhya #include <stdlib.h>
14a2561b12SSai Praneeth Prakhya #include <sys/types.h>
15a2561b12SSai Praneeth Prakhya #include <sys/wait.h>
16a2561b12SSai Praneeth Prakhya #include <inttypes.h>
17a2561b12SSai Praneeth Prakhya #include <string.h>
18a2561b12SSai Praneeth Prakhya
19a2561b12SSai Praneeth Prakhya #include "resctrl.h"
20a2561b12SSai Praneeth Prakhya
21a2561b12SSai Praneeth Prakhya #define CL_SIZE (64)
22a2561b12SSai Praneeth Prakhya #define PAGE_SIZE (4 * 1024)
23a2561b12SSai Praneeth Prakhya #define MB (1024 * 1024)
24a2561b12SSai Praneeth Prakhya
sb(void)25a2561b12SSai Praneeth Prakhya static void sb(void)
26a2561b12SSai Praneeth Prakhya {
27a2561b12SSai Praneeth Prakhya #if defined(__i386) || defined(__x86_64)
28a2561b12SSai Praneeth Prakhya asm volatile("sfence\n\t"
29a2561b12SSai Praneeth Prakhya : : : "memory");
30a2561b12SSai Praneeth Prakhya #endif
31a2561b12SSai Praneeth Prakhya }
32a2561b12SSai Praneeth Prakhya
cl_flush(void * p)33a2561b12SSai Praneeth Prakhya static void cl_flush(void *p)
34a2561b12SSai Praneeth Prakhya {
35a2561b12SSai Praneeth Prakhya #if defined(__i386) || defined(__x86_64)
36a2561b12SSai Praneeth Prakhya asm volatile("clflush (%0)\n\t"
37a2561b12SSai Praneeth Prakhya : : "r"(p) : "memory");
38a2561b12SSai Praneeth Prakhya #endif
39a2561b12SSai Praneeth Prakhya }
40a2561b12SSai Praneeth Prakhya
mem_flush(unsigned char * buf,size_t buf_size)41205de6ddSIlpo Järvinen void mem_flush(unsigned char *buf, size_t buf_size)
42a2561b12SSai Praneeth Prakhya {
43f4123975SIlpo Järvinen unsigned char *cp = buf;
44a2561b12SSai Praneeth Prakhya size_t i = 0;
45a2561b12SSai Praneeth Prakhya
46f4123975SIlpo Järvinen buf_size = buf_size / CL_SIZE; /* mem size in cache lines */
47a2561b12SSai Praneeth Prakhya
48f4123975SIlpo Järvinen for (i = 0; i < buf_size; i++)
49a2561b12SSai Praneeth Prakhya cl_flush(&cp[i * CL_SIZE]);
50a2561b12SSai Praneeth Prakhya
51a2561b12SSai Praneeth Prakhya sb();
52a2561b12SSai Praneeth Prakhya }
53a2561b12SSai Praneeth Prakhya
54bcdb2e9dSIlpo Järvinen /*
55bcdb2e9dSIlpo Järvinen * Buffer index step advance to workaround HW prefetching interfering with
56bcdb2e9dSIlpo Järvinen * the measurements.
57bcdb2e9dSIlpo Järvinen *
58bcdb2e9dSIlpo Järvinen * Must be a prime to step through all indexes of the buffer.
59bcdb2e9dSIlpo Järvinen *
60bcdb2e9dSIlpo Järvinen * Some primes work better than others on some architectures (from MBA/MBM
61bcdb2e9dSIlpo Järvinen * result stability point of view).
62bcdb2e9dSIlpo Järvinen */
63bcdb2e9dSIlpo Järvinen #define FILL_IDX_MULT 23
64bcdb2e9dSIlpo Järvinen
fill_one_span_read(unsigned char * buf,size_t buf_size)65f4123975SIlpo Järvinen static int fill_one_span_read(unsigned char *buf, size_t buf_size)
66a2561b12SSai Praneeth Prakhya {
67bcdb2e9dSIlpo Järvinen unsigned int size = buf_size / (CL_SIZE / 2);
68bcdb2e9dSIlpo Järvinen unsigned int i, idx = 0;
69bcdb2e9dSIlpo Järvinen unsigned char sum = 0;
70a2561b12SSai Praneeth Prakhya
71bcdb2e9dSIlpo Järvinen /*
72bcdb2e9dSIlpo Järvinen * Read the buffer in an order that is unexpected by HW prefetching
73bcdb2e9dSIlpo Järvinen * optimizations to prevent them interfering with the caching pattern.
74bcdb2e9dSIlpo Järvinen *
75bcdb2e9dSIlpo Järvinen * The read order is (in terms of halves of cachelines):
76bcdb2e9dSIlpo Järvinen * i * FILL_IDX_MULT % size
77bcdb2e9dSIlpo Järvinen * The formula is open-coded below to avoiding modulo inside the loop
78bcdb2e9dSIlpo Järvinen * as it improves MBA/MBM result stability on some architectures.
79bcdb2e9dSIlpo Järvinen */
80bcdb2e9dSIlpo Järvinen for (i = 0; i < size; i++) {
81bcdb2e9dSIlpo Järvinen sum += buf[idx * (CL_SIZE / 2)];
82bcdb2e9dSIlpo Järvinen
83bcdb2e9dSIlpo Järvinen idx += FILL_IDX_MULT;
84bcdb2e9dSIlpo Järvinen while (idx >= size)
85bcdb2e9dSIlpo Järvinen idx -= size;
86a2561b12SSai Praneeth Prakhya }
87a2561b12SSai Praneeth Prakhya
88a2561b12SSai Praneeth Prakhya return sum;
89a2561b12SSai Praneeth Prakhya }
90a2561b12SSai Praneeth Prakhya
fill_cache_read(unsigned char * buf,size_t buf_size,bool once)91205de6ddSIlpo Järvinen void fill_cache_read(unsigned char *buf, size_t buf_size, bool once)
92a2561b12SSai Praneeth Prakhya {
93a2561b12SSai Praneeth Prakhya int ret = 0;
94a2561b12SSai Praneeth Prakhya
95790bf585SFenghua Yu while (1) {
96f4123975SIlpo Järvinen ret = fill_one_span_read(buf, buf_size);
977f3c980cSIlpo Järvinen if (once)
98790bf585SFenghua Yu break;
99790bf585SFenghua Yu }
100a2561b12SSai Praneeth Prakhya
101a2561b12SSai Praneeth Prakhya /* Consume read result so that reading memory is not optimized out. */
10290a009dbSIlpo Järvinen *value_sink = ret;
103a2561b12SSai Praneeth Prakhya }
104a2561b12SSai Praneeth Prakhya
alloc_buffer(size_t buf_size,bool memflush)105e958c21eSReinette Chatre unsigned char *alloc_buffer(size_t buf_size, bool memflush)
106a2561b12SSai Praneeth Prakhya {
10724be0559SIlpo Järvinen void *buf = NULL;
10824be0559SIlpo Järvinen uint64_t *p64;
109caf02626SReinette Chatre ssize_t s64;
11024be0559SIlpo Järvinen int ret;
111a2561b12SSai Praneeth Prakhya
11224be0559SIlpo Järvinen ret = posix_memalign(&buf, PAGE_SIZE, buf_size);
11324be0559SIlpo Järvinen if (ret < 0)
114f8f66969SIlpo Järvinen return NULL;
115a2561b12SSai Praneeth Prakhya
11624be0559SIlpo Järvinen /* Initialize the buffer */
11724be0559SIlpo Järvinen p64 = buf;
11824be0559SIlpo Järvinen s64 = buf_size / sizeof(uint64_t);
11924be0559SIlpo Järvinen
12024be0559SIlpo Järvinen while (s64 > 0) {
12124be0559SIlpo Järvinen *p64 = (uint64_t)rand();
12224be0559SIlpo Järvinen p64 += (CL_SIZE / sizeof(uint64_t));
12324be0559SIlpo Järvinen s64 -= (CL_SIZE / sizeof(uint64_t));
12424be0559SIlpo Järvinen }
12524be0559SIlpo Järvinen
126a2561b12SSai Praneeth Prakhya /* Flush the memory before using to avoid "cache hot pages" effect */
127a2561b12SSai Praneeth Prakhya if (memflush)
128f4123975SIlpo Järvinen mem_flush(buf, buf_size);
129a2561b12SSai Praneeth Prakhya
130f8f66969SIlpo Järvinen return buf;
131f8f66969SIlpo Järvinen }
132*f77b9672SReinette Chatre
get_fill_buf_size(int cpu_no,const char * cache_type)133*f77b9672SReinette Chatre ssize_t get_fill_buf_size(int cpu_no, const char *cache_type)
134*f77b9672SReinette Chatre {
135*f77b9672SReinette Chatre unsigned long cache_total_size = 0;
136*f77b9672SReinette Chatre int ret;
137*f77b9672SReinette Chatre
138*f77b9672SReinette Chatre ret = get_cache_size(cpu_no, cache_type, &cache_total_size);
139*f77b9672SReinette Chatre if (ret)
140*f77b9672SReinette Chatre return ret;
141*f77b9672SReinette Chatre
142*f77b9672SReinette Chatre return cache_total_size * 2 > MINIMUM_SPAN ?
143*f77b9672SReinette Chatre cache_total_size * 2 : MINIMUM_SPAN;
144*f77b9672SReinette Chatre }
145