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
sb(void)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
cl_flush(void * p)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
mem_flush(unsigned char * buf,size_t buf_size)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
fill_one_span_read(unsigned char * buf,size_t buf_size)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
fill_one_span_write(unsigned char * buf,size_t buf_size)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
fill_cache_read(unsigned char * buf,size_t buf_size,bool once)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
fill_cache_write(unsigned char * buf,size_t buf_size,bool once)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
alloc_buffer(size_t buf_size,int memflush)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
run_fill_buf(size_t buf_size,int memflush,int op,bool once)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