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