Loading...
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
19#include "resctrl.h"
20
21#define CL_SIZE (64)
22#define PAGE_SIZE (4 * 1024)
23#define MB (1024 * 1024)
24
25static void sb(void)
26{
27#if defined(__i386) || defined(__x86_64)
28 asm volatile("sfence\n\t"
29 : : : "memory");
30#endif
31}
32
33static void cl_flush(void *p)
34{
35#if defined(__i386) || defined(__x86_64)
36 asm volatile("clflush (%0)\n\t"
37 : : "r"(p) : "memory");
38#endif
39}
40
41void mem_flush(unsigned char *buf, size_t buf_size)
42{
43 unsigned char *cp = buf;
44 size_t i = 0;
45
46 buf_size = buf_size / CL_SIZE; /* mem size in cache lines */
47
48 for (i = 0; i < buf_size; i++)
49 cl_flush(&cp[i * CL_SIZE]);
50
51 sb();
52}
53
54/*
55 * Buffer index step advance to workaround HW prefetching interfering with
56 * the measurements.
57 *
58 * Must be a prime to step through all indexes of the buffer.
59 *
60 * Some primes work better than others on some architectures (from MBA/MBM
61 * result stability point of view).
62 */
63#define FILL_IDX_MULT 23
64
65static int fill_one_span_read(unsigned char *buf, size_t buf_size)
66{
67 unsigned int size = buf_size / (CL_SIZE / 2);
68 unsigned int i, idx = 0;
69 unsigned char sum = 0;
70
71 /*
72 * Read the buffer in an order that is unexpected by HW prefetching
73 * optimizations to prevent them interfering with the caching pattern.
74 *
75 * The read order is (in terms of halves of cachelines):
76 * i * FILL_IDX_MULT % size
77 * The formula is open-coded below to avoiding modulo inside the loop
78 * as it improves MBA/MBM result stability on some architectures.
79 */
80 for (i = 0; i < size; i++) {
81 sum += buf[idx * (CL_SIZE / 2)];
82
83 idx += FILL_IDX_MULT;
84 while (idx >= size)
85 idx -= size;
86 }
87
88 return sum;
89}
90
91void fill_cache_read(unsigned char *buf, size_t buf_size, bool once)
92{
93 int ret = 0;
94
95 while (1) {
96 ret = fill_one_span_read(buf, buf_size);
97 if (once)
98 break;
99 }
100
101 /* Consume read result so that reading memory is not optimized out. */
102 *value_sink = ret;
103}
104
105unsigned char *alloc_buffer(size_t buf_size, bool memflush)
106{
107 void *buf = NULL;
108 uint64_t *p64;
109 ssize_t s64;
110 int ret;
111
112 ret = posix_memalign(&buf, PAGE_SIZE, buf_size);
113 if (ret < 0)
114 return NULL;
115
116 /* Initialize the buffer */
117 p64 = buf;
118 s64 = buf_size / sizeof(uint64_t);
119
120 while (s64 > 0) {
121 *p64 = (uint64_t)rand();
122 p64 += (CL_SIZE / sizeof(uint64_t));
123 s64 -= (CL_SIZE / sizeof(uint64_t));
124 }
125
126 /* Flush the memory before using to avoid "cache hot pages" effect */
127 if (memflush)
128 mem_flush(buf, buf_size);
129
130 return buf;
131}
132
133ssize_t get_fill_buf_size(int cpu_no, const char *cache_type)
134{
135 unsigned long cache_total_size = 0;
136 int ret;
137
138 ret = get_cache_size(cpu_no, cache_type, &cache_total_size);
139 if (ret)
140 return ret;
141
142 return cache_total_size * 2 > MINIMUM_SPAN ?
143 cache_total_size * 2 : MINIMUM_SPAN;
144}
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 <malloc.h>
18#include <string.h>
19
20#include "resctrl.h"
21
22#define CL_SIZE (64)
23#define PAGE_SIZE (4 * 1024)
24#define MB (1024 * 1024)
25
26static unsigned char *startptr;
27
28static void sb(void)
29{
30#if defined(__i386) || defined(__x86_64)
31 asm volatile("sfence\n\t"
32 : : : "memory");
33#endif
34}
35
36static void ctrl_handler(int signo)
37{
38 free(startptr);
39 printf("\nEnding\n");
40 sb();
41 exit(EXIT_SUCCESS);
42}
43
44static void cl_flush(void *p)
45{
46#if defined(__i386) || defined(__x86_64)
47 asm volatile("clflush (%0)\n\t"
48 : : "r"(p) : "memory");
49#endif
50}
51
52static void mem_flush(void *p, size_t s)
53{
54 char *cp = (char *)p;
55 size_t i = 0;
56
57 s = s / CL_SIZE; /* mem size in cache llines */
58
59 for (i = 0; i < s; i++)
60 cl_flush(&cp[i * CL_SIZE]);
61
62 sb();
63}
64
65static void *malloc_and_init_memory(size_t s)
66{
67 uint64_t *p64;
68 size_t s64;
69
70 void *p = memalign(PAGE_SIZE, s);
71
72 p64 = (uint64_t *)p;
73 s64 = s / sizeof(uint64_t);
74
75 while (s64 > 0) {
76 *p64 = (uint64_t)rand();
77 p64 += (CL_SIZE / sizeof(uint64_t));
78 s64 -= (CL_SIZE / sizeof(uint64_t));
79 }
80
81 return p;
82}
83
84static int fill_one_span_read(unsigned char *start_ptr, unsigned char *end_ptr)
85{
86 unsigned char sum, *p;
87
88 sum = 0;
89 p = start_ptr;
90 while (p < end_ptr) {
91 sum += *p;
92 p += (CL_SIZE / 2);
93 }
94
95 return sum;
96}
97
98static
99void fill_one_span_write(unsigned char *start_ptr, unsigned char *end_ptr)
100{
101 unsigned char *p;
102
103 p = start_ptr;
104 while (p < end_ptr) {
105 *p = '1';
106 p += (CL_SIZE / 2);
107 }
108}
109
110static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
111 char *resctrl_val)
112{
113 int ret = 0;
114 FILE *fp;
115
116 while (1) {
117 ret = fill_one_span_read(start_ptr, end_ptr);
118 if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)))
119 break;
120 }
121
122 /* Consume read result so that reading memory is not optimized out. */
123 fp = fopen("/dev/null", "w");
124 if (!fp) {
125 perror("Unable to write to /dev/null");
126 return -1;
127 }
128 fprintf(fp, "Sum: %d ", ret);
129 fclose(fp);
130
131 return 0;
132}
133
134static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr,
135 char *resctrl_val)
136{
137 while (1) {
138 fill_one_span_write(start_ptr, end_ptr);
139 if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)))
140 break;
141 }
142
143 return 0;
144}
145
146static int
147fill_cache(unsigned long long buf_size, int malloc_and_init, int memflush,
148 int op, char *resctrl_val)
149{
150 unsigned char *start_ptr, *end_ptr;
151 unsigned long long i;
152 int ret;
153
154 if (malloc_and_init)
155 start_ptr = malloc_and_init_memory(buf_size);
156 else
157 start_ptr = malloc(buf_size);
158
159 if (!start_ptr)
160 return -1;
161
162 startptr = start_ptr;
163 end_ptr = start_ptr + buf_size;
164
165 /*
166 * It's better to touch the memory once to avoid any compiler
167 * optimizations
168 */
169 if (!malloc_and_init) {
170 for (i = 0; i < buf_size; i++)
171 *start_ptr++ = (unsigned char)rand();
172 }
173
174 start_ptr = startptr;
175
176 /* Flush the memory before using to avoid "cache hot pages" effect */
177 if (memflush)
178 mem_flush(start_ptr, buf_size);
179
180 if (op == 0)
181 ret = fill_cache_read(start_ptr, end_ptr, resctrl_val);
182 else
183 ret = fill_cache_write(start_ptr, end_ptr, resctrl_val);
184
185 if (ret) {
186 printf("\n Error in fill cache read/write...\n");
187 return -1;
188 }
189
190 free(startptr);
191
192 return 0;
193}
194
195int run_fill_buf(unsigned long span, int malloc_and_init_memory,
196 int memflush, int op, char *resctrl_val)
197{
198 unsigned long long cache_size = span;
199 int ret;
200
201 /* set up ctrl-c handler */
202 if (signal(SIGINT, ctrl_handler) == SIG_ERR)
203 printf("Failed to catch SIGINT!\n");
204 if (signal(SIGHUP, ctrl_handler) == SIG_ERR)
205 printf("Failed to catch SIGHUP!\n");
206
207 ret = fill_cache(cache_size, malloc_and_init_memory, memflush, op,
208 resctrl_val);
209 if (ret) {
210 printf("\n Error in fill cache\n");
211 return -1;
212 }
213
214 return 0;
215}