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