1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 /* 2 /* 3 * fill_buf benchmark 3 * fill_buf benchmark 4 * 4 * 5 * Copyright (C) 2018 Intel Corporation 5 * Copyright (C) 2018 Intel Corporation 6 * 6 * 7 * Authors: 7 * Authors: 8 * Sai Praneeth Prakhya <sai.praneeth.prakh 8 * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>, 9 * Fenghua Yu <fenghua.yu@intel.com> 9 * Fenghua Yu <fenghua.yu@intel.com> 10 */ 10 */ 11 #include <stdio.h> 11 #include <stdio.h> 12 #include <unistd.h> 12 #include <unistd.h> 13 #include <stdlib.h> 13 #include <stdlib.h> 14 #include <sys/types.h> 14 #include <sys/types.h> 15 #include <sys/wait.h> 15 #include <sys/wait.h> 16 #include <inttypes.h> 16 #include <inttypes.h> >> 17 #include <malloc.h> 17 #include <string.h> 18 #include <string.h> 18 19 19 #include "resctrl.h" 20 #include "resctrl.h" 20 21 21 #define CL_SIZE (64) 22 #define CL_SIZE (64) 22 #define PAGE_SIZE (4 * 1024) 23 #define PAGE_SIZE (4 * 1024) 23 #define MB (1024 * 1024) 24 #define MB (1024 * 1024) 24 25 >> 26 static unsigned char *startptr; >> 27 25 static void sb(void) 28 static void sb(void) 26 { 29 { 27 #if defined(__i386) || defined(__x86_64) 30 #if defined(__i386) || defined(__x86_64) 28 asm volatile("sfence\n\t" 31 asm volatile("sfence\n\t" 29 : : : "memory"); 32 : : : "memory"); 30 #endif 33 #endif 31 } 34 } 32 35 >> 36 static void ctrl_handler(int signo) >> 37 { >> 38 free(startptr); >> 39 printf("\nEnding\n"); >> 40 sb(); >> 41 exit(EXIT_SUCCESS); >> 42 } >> 43 33 static void cl_flush(void *p) 44 static void cl_flush(void *p) 34 { 45 { 35 #if defined(__i386) || defined(__x86_64) 46 #if defined(__i386) || defined(__x86_64) 36 asm volatile("clflush (%0)\n\t" 47 asm volatile("clflush (%0)\n\t" 37 : : "r"(p) : "memory"); 48 : : "r"(p) : "memory"); 38 #endif 49 #endif 39 } 50 } 40 51 41 void mem_flush(unsigned char *buf, size_t buf_ !! 52 static void mem_flush(void *p, size_t s) 42 { 53 { 43 unsigned char *cp = buf; !! 54 char *cp = (char *)p; 44 size_t i = 0; 55 size_t i = 0; 45 56 46 buf_size = buf_size / CL_SIZE; /* mem !! 57 s = s / CL_SIZE; /* mem size in cache llines */ 47 58 48 for (i = 0; i < buf_size; i++) !! 59 for (i = 0; i < s; i++) 49 cl_flush(&cp[i * CL_SIZE]); 60 cl_flush(&cp[i * CL_SIZE]); 50 61 51 sb(); 62 sb(); 52 } 63 } 53 64 54 /* !! 65 static void *malloc_and_init_memory(size_t s) 55 * Buffer index step advance to workaround HW !! 66 { 56 * the measurements. !! 67 uint64_t *p64; 57 * !! 68 size_t s64; 58 * Must be a prime to step through all indexes << 59 * << 60 * Some primes work better than others on some << 61 * result stability point of view). << 62 */ << 63 #define FILL_IDX_MULT 23 << 64 << 65 static int fill_one_span_read(unsigned char *b << 66 { << 67 unsigned int size = buf_size / (CL_SIZ << 68 unsigned int i, idx = 0; << 69 unsigned char sum = 0; << 70 69 71 /* !! 70 void *p = memalign(PAGE_SIZE, s); 72 * Read the buffer in an order that is !! 71 73 * optimizations to prevent them inter !! 72 p64 = (uint64_t *)p; 74 * !! 73 s64 = s / sizeof(uint64_t); 75 * The read order is (in terms of halv !! 74 76 * i * FILL_IDX_MULT % size !! 75 while (s64 > 0) { 77 * The formula is open-coded below to !! 76 *p64 = (uint64_t)rand(); 78 * as it improves MBA/MBM result stabi !! 77 p64 += (CL_SIZE / sizeof(uint64_t)); 79 */ !! 78 s64 -= (CL_SIZE / sizeof(uint64_t)); 80 for (i = 0; i < size; i++) { !! 79 } 81 sum += buf[idx * (CL_SIZE / 2) << 82 80 83 idx += FILL_IDX_MULT; !! 81 return p; 84 while (idx >= size) !! 82 } 85 idx -= size; !! 83 >> 84 static int fill_one_span_read(unsigned char *start_ptr, unsigned char *end_ptr) >> 85 { >> 86 unsigned char sum, *p; >> 87 >> 88 sum = 0; >> 89 p = start_ptr; >> 90 while (p < end_ptr) { >> 91 sum += *p; >> 92 p += (CL_SIZE / 2); 86 } 93 } 87 94 88 return sum; 95 return sum; 89 } 96 } 90 97 91 static void fill_one_span_write(unsigned char !! 98 static >> 99 void fill_one_span_write(unsigned char *start_ptr, unsigned char *end_ptr) 92 { 100 { 93 unsigned char *end_ptr = buf + buf_siz << 94 unsigned char *p; 101 unsigned char *p; 95 102 96 p = buf; !! 103 p = start_ptr; 97 while (p < end_ptr) { 104 while (p < end_ptr) { 98 *p = '1'; 105 *p = '1'; 99 p += (CL_SIZE / 2); 106 p += (CL_SIZE / 2); 100 } 107 } 101 } 108 } 102 109 103 void fill_cache_read(unsigned char *buf, size_ !! 110 static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr, >> 111 char *resctrl_val) 104 { 112 { 105 int ret = 0; 113 int ret = 0; >> 114 FILE *fp; 106 115 107 while (1) { 116 while (1) { 108 ret = fill_one_span_read(buf, !! 117 ret = fill_one_span_read(start_ptr, end_ptr); 109 if (once) !! 118 if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR))) 110 break; 119 break; 111 } 120 } 112 121 113 /* Consume read result so that reading 122 /* Consume read result so that reading memory is not optimized out. */ 114 *value_sink = ret; !! 123 fp = fopen("/dev/null", "w"); >> 124 if (!fp) { >> 125 perror("Unable to write to /dev/null"); >> 126 return -1; >> 127 } >> 128 fprintf(fp, "Sum: %d ", ret); >> 129 fclose(fp); >> 130 >> 131 return 0; 115 } 132 } 116 133 117 static void fill_cache_write(unsigned char *bu !! 134 static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr, >> 135 char *resctrl_val) 118 { 136 { 119 while (1) { 137 while (1) { 120 fill_one_span_write(buf, buf_s !! 138 fill_one_span_write(start_ptr, end_ptr); 121 if (once) !! 139 if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR))) 122 break; 140 break; 123 } 141 } >> 142 >> 143 return 0; 124 } 144 } 125 145 126 unsigned char *alloc_buffer(size_t buf_size, i !! 146 static int >> 147 fill_cache(unsigned long long buf_size, int malloc_and_init, int memflush, >> 148 int op, char *resctrl_val) 127 { 149 { 128 void *buf = NULL; !! 150 unsigned char *start_ptr, *end_ptr; 129 uint64_t *p64; !! 151 unsigned long long i; 130 size_t s64; << 131 int ret; 152 int ret; 132 153 133 ret = posix_memalign(&buf, PAGE_SIZE, !! 154 if (malloc_and_init) 134 if (ret < 0) !! 155 start_ptr = malloc_and_init_memory(buf_size); 135 return NULL; !! 156 else 136 !! 157 start_ptr = malloc(buf_size); 137 /* Initialize the buffer */ << 138 p64 = buf; << 139 s64 = buf_size / sizeof(uint64_t); << 140 158 141 while (s64 > 0) { !! 159 if (!start_ptr) 142 *p64 = (uint64_t)rand(); !! 160 return -1; 143 p64 += (CL_SIZE / sizeof(uint6 !! 161 144 s64 -= (CL_SIZE / sizeof(uint6 !! 162 startptr = start_ptr; >> 163 end_ptr = start_ptr + buf_size; >> 164 >> 165 /* >> 166 * It's better to touch the memory once to avoid any compiler >> 167 * optimizations >> 168 */ >> 169 if (!malloc_and_init) { >> 170 for (i = 0; i < buf_size; i++) >> 171 *start_ptr++ = (unsigned char)rand(); 145 } 172 } 146 173 >> 174 start_ptr = startptr; >> 175 147 /* Flush the memory before using to av 176 /* Flush the memory before using to avoid "cache hot pages" effect */ 148 if (memflush) 177 if (memflush) 149 mem_flush(buf, buf_size); !! 178 mem_flush(start_ptr, buf_size); >> 179 >> 180 if (op == 0) >> 181 ret = fill_cache_read(start_ptr, end_ptr, resctrl_val); >> 182 else >> 183 ret = fill_cache_write(start_ptr, end_ptr, resctrl_val); >> 184 >> 185 if (ret) { >> 186 printf("\n Error in fill cache read/write...\n"); >> 187 return -1; >> 188 } 150 189 151 return buf; !! 190 free(startptr); >> 191 >> 192 return 0; 152 } 193 } 153 194 154 int run_fill_buf(size_t buf_size, int memflush !! 195 int run_fill_buf(unsigned long span, int malloc_and_init_memory, >> 196 int memflush, int op, char *resctrl_val) 155 { 197 { 156 unsigned char *buf; !! 198 unsigned long long cache_size = span; >> 199 int ret; 157 200 158 buf = alloc_buffer(buf_size, memflush) !! 201 /* set up ctrl-c handler */ 159 if (!buf) !! 202 if (signal(SIGINT, ctrl_handler) == SIG_ERR) >> 203 printf("Failed to catch SIGINT!\n"); >> 204 if (signal(SIGHUP, ctrl_handler) == SIG_ERR) >> 205 printf("Failed to catch SIGHUP!\n"); >> 206 >> 207 ret = fill_cache(cache_size, malloc_and_init_memory, memflush, op, >> 208 resctrl_val); >> 209 if (ret) { >> 210 printf("\n Error in fill cache\n"); 160 return -1; 211 return -1; 161 !! 212 } 162 if (op == 0) << 163 fill_cache_read(buf, buf_size, << 164 else << 165 fill_cache_write(buf, buf_size << 166 free(buf); << 167 213 168 return 0; 214 return 0; 169 } 215 } 170 216
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.