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