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
26static unsigned char *startptr;
27
28static void sb(void)
29{
30#if defined(__i386) || defined(__x86_64)
31	asm volatile("sfence\n\t"
32		     : : : "memory");
33#endif
34}
35
36static void ctrl_handler(int signo)
37{
38	free(startptr);
39	printf("\nEnding\n");
40	sb();
41	exit(EXIT_SUCCESS);
42}
43
44static 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
52static 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
65static 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
86static 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
100static
101void 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
112static 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
136static 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
148static int
149fill_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
198int 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