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
26 static unsigned char *startptr;
27
sb(void)28 static void sb(void)
29 {
30 #if defined(__i386) || defined(__x86_64)
31 asm volatile("sfence\n\t"
32 : : : "memory");
33 #endif
34 }
35
ctrl_handler(int signo)36 static void ctrl_handler(int signo)
37 {
38 free(startptr);
39 printf("\nEnding\n");
40 sb();
41 exit(EXIT_SUCCESS);
42 }
43
cl_flush(void * p)44 static 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
mem_flush(void * p,size_t s)52 static 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
malloc_and_init_memory(size_t s)65 static 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 if (!p)
72 return NULL;
73
74 p64 = (uint64_t *)p;
75 s64 = s / sizeof(uint64_t);
76
77 while (s64 > 0) {
78 *p64 = (uint64_t)rand();
79 p64 += (CL_SIZE / sizeof(uint64_t));
80 s64 -= (CL_SIZE / sizeof(uint64_t));
81 }
82
83 return p;
84 }
85
fill_one_span_read(unsigned char * start_ptr,unsigned char * end_ptr)86 static int fill_one_span_read(unsigned char *start_ptr, unsigned char *end_ptr)
87 {
88 unsigned char sum, *p;
89
90 sum = 0;
91 p = start_ptr;
92 while (p < end_ptr) {
93 sum += *p;
94 p += (CL_SIZE / 2);
95 }
96
97 return sum;
98 }
99
100 static
fill_one_span_write(unsigned char * start_ptr,unsigned char * end_ptr)101 void fill_one_span_write(unsigned char *start_ptr, unsigned char *end_ptr)
102 {
103 unsigned char *p;
104
105 p = start_ptr;
106 while (p < end_ptr) {
107 *p = '1';
108 p += (CL_SIZE / 2);
109 }
110 }
111
fill_cache_read(unsigned char * start_ptr,unsigned char * end_ptr,char * resctrl_val)112 static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
113 char *resctrl_val)
114 {
115 int ret = 0;
116 FILE *fp;
117
118 while (1) {
119 ret = fill_one_span_read(start_ptr, end_ptr);
120 if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)))
121 break;
122 }
123
124 /* Consume read result so that reading memory is not optimized out. */
125 fp = fopen("/dev/null", "w");
126 if (!fp) {
127 perror("Unable to write to /dev/null");
128 return -1;
129 }
130 fprintf(fp, "Sum: %d ", ret);
131 fclose(fp);
132
133 return 0;
134 }
135
fill_cache_write(unsigned char * start_ptr,unsigned char * end_ptr,char * resctrl_val)136 static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr,
137 char *resctrl_val)
138 {
139 while (1) {
140 fill_one_span_write(start_ptr, end_ptr);
141 if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)))
142 break;
143 }
144
145 return 0;
146 }
147
148 static int
fill_cache(unsigned long long buf_size,int malloc_and_init,int memflush,int op,char * resctrl_val)149 fill_cache(unsigned long long buf_size, int malloc_and_init, int memflush,
150 int op, char *resctrl_val)
151 {
152 unsigned char *start_ptr, *end_ptr;
153 unsigned long long i;
154 int ret;
155
156 if (malloc_and_init)
157 start_ptr = malloc_and_init_memory(buf_size);
158 else
159 start_ptr = malloc(buf_size);
160
161 if (!start_ptr)
162 return -1;
163
164 startptr = start_ptr;
165 end_ptr = start_ptr + buf_size;
166
167 /*
168 * It's better to touch the memory once to avoid any compiler
169 * optimizations
170 */
171 if (!malloc_and_init) {
172 for (i = 0; i < buf_size; i++)
173 *start_ptr++ = (unsigned char)rand();
174 }
175
176 start_ptr = startptr;
177
178 /* Flush the memory before using to avoid "cache hot pages" effect */
179 if (memflush)
180 mem_flush(start_ptr, buf_size);
181
182 if (op == 0)
183 ret = fill_cache_read(start_ptr, end_ptr, resctrl_val);
184 else
185 ret = fill_cache_write(start_ptr, end_ptr, resctrl_val);
186
187 free(startptr);
188
189 if (ret) {
190 printf("\n Error in fill cache read/write...\n");
191 return -1;
192 }
193
194
195 return 0;
196 }
197
run_fill_buf(unsigned long span,int malloc_and_init_memory,int memflush,int op,char * resctrl_val)198 int run_fill_buf(unsigned long span, int malloc_and_init_memory,
199 int memflush, int op, char *resctrl_val)
200 {
201 unsigned long long cache_size = span;
202 int ret;
203
204 /* set up ctrl-c handler */
205 if (signal(SIGINT, ctrl_handler) == SIG_ERR)
206 printf("Failed to catch SIGINT!\n");
207 if (signal(SIGHUP, ctrl_handler) == SIG_ERR)
208 printf("Failed to catch SIGHUP!\n");
209
210 ret = fill_cache(cache_size, malloc_and_init_memory, memflush, op,
211 resctrl_val);
212 if (ret) {
213 printf("\n Error in fill cache\n");
214 return -1;
215 }
216
217 return 0;
218 }
219