xref: /openbmc/linux/tools/testing/selftests/resctrl/fill_buf.c (revision f4123975cf341fd12121e1631c4b172a190f48d4)
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(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 static void *malloc_and_init_memory(size_t buf_size)
55 {
56 	void *p = NULL;
57 	uint64_t *p64;
58 	size_t s64;
59 	int ret;
60 
61 	ret = posix_memalign(&p, PAGE_SIZE, buf_size);
62 	if (ret < 0)
63 		return NULL;
64 
65 	p64 = (uint64_t *)p;
66 	s64 = buf_size / 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 *buf, size_t buf_size)
78 {
79 	unsigned char *end_ptr = buf + buf_size;
80 	unsigned char sum, *p;
81 
82 	sum = 0;
83 	p = buf;
84 	while (p < end_ptr) {
85 		sum += *p;
86 		p += (CL_SIZE / 2);
87 	}
88 
89 	return sum;
90 }
91 
92 static void fill_one_span_write(unsigned char *buf, size_t buf_size)
93 {
94 	unsigned char *end_ptr = buf + buf_size;
95 	unsigned char *p;
96 
97 	p = buf;
98 	while (p < end_ptr) {
99 		*p = '1';
100 		p += (CL_SIZE / 2);
101 	}
102 }
103 
104 static int fill_cache_read(unsigned char *buf, size_t buf_size,
105 			   char *resctrl_val)
106 {
107 	int ret = 0;
108 	FILE *fp;
109 
110 	while (1) {
111 		ret = fill_one_span_read(buf, buf_size);
112 		if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)))
113 			break;
114 	}
115 
116 	/* Consume read result so that reading memory is not optimized out. */
117 	fp = fopen("/dev/null", "w");
118 	if (!fp) {
119 		perror("Unable to write to /dev/null");
120 		return -1;
121 	}
122 	fprintf(fp, "Sum: %d ", ret);
123 	fclose(fp);
124 
125 	return 0;
126 }
127 
128 static int fill_cache_write(unsigned char *buf, size_t buf_size,
129 			    char *resctrl_val)
130 {
131 	while (1) {
132 		fill_one_span_write(buf, buf_size);
133 		if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)))
134 			break;
135 	}
136 
137 	return 0;
138 }
139 
140 static int fill_cache(size_t buf_size, int memflush, int op, char *resctrl_val)
141 {
142 	unsigned char *buf;
143 	int ret;
144 
145 	buf = malloc_and_init_memory(buf_size);
146 	if (!buf)
147 		return -1;
148 
149 	/* Flush the memory before using to avoid "cache hot pages" effect */
150 	if (memflush)
151 		mem_flush(buf, buf_size);
152 
153 	if (op == 0)
154 		ret = fill_cache_read(buf, buf_size, resctrl_val);
155 	else
156 		ret = fill_cache_write(buf, buf_size, resctrl_val);
157 
158 	free(buf);
159 
160 	if (ret) {
161 		printf("\n Error in fill cache read/write...\n");
162 		return -1;
163 	}
164 
165 
166 	return 0;
167 }
168 
169 int run_fill_buf(size_t span, int memflush, int op, char *resctrl_val)
170 {
171 	size_t cache_size = span;
172 	int ret;
173 
174 	ret = fill_cache(cache_size, memflush, op, resctrl_val);
175 	if (ret) {
176 		printf("\n Error in fill cache\n");
177 		return -1;
178 	}
179 
180 	return 0;
181 }
182