1*790bf585SFenghua Yu // SPDX-License-Identifier: GPL-2.0 2*790bf585SFenghua Yu /* 3*790bf585SFenghua Yu * Cache Allocation Technology (CAT) test 4*790bf585SFenghua Yu * 5*790bf585SFenghua Yu * Copyright (C) 2018 Intel Corporation 6*790bf585SFenghua Yu * 7*790bf585SFenghua Yu * Authors: 8*790bf585SFenghua Yu * Sai Praneeth Prakhya <[email protected]>, 9*790bf585SFenghua Yu * Fenghua Yu <[email protected]> 10*790bf585SFenghua Yu */ 11*790bf585SFenghua Yu #include "resctrl.h" 12*790bf585SFenghua Yu #include <unistd.h> 13*790bf585SFenghua Yu 14*790bf585SFenghua Yu #define RESULT_FILE_NAME1 "result_cat1" 15*790bf585SFenghua Yu #define RESULT_FILE_NAME2 "result_cat2" 16*790bf585SFenghua Yu #define NUM_OF_RUNS 5 17*790bf585SFenghua Yu #define MAX_DIFF_PERCENT 4 18*790bf585SFenghua Yu #define MAX_DIFF 1000000 19*790bf585SFenghua Yu 20*790bf585SFenghua Yu int count_of_bits; 21*790bf585SFenghua Yu char cbm_mask[256]; 22*790bf585SFenghua Yu unsigned long long_mask; 23*790bf585SFenghua Yu unsigned long cache_size; 24*790bf585SFenghua Yu 25*790bf585SFenghua Yu /* 26*790bf585SFenghua Yu * Change schemata. Write schemata to specified 27*790bf585SFenghua Yu * con_mon grp, mon_grp in resctrl FS. 28*790bf585SFenghua Yu * Run 5 times in order to get average values. 29*790bf585SFenghua Yu */ 30*790bf585SFenghua Yu static int cat_setup(int num, ...) 31*790bf585SFenghua Yu { 32*790bf585SFenghua Yu struct resctrl_val_param *p; 33*790bf585SFenghua Yu char schemata[64]; 34*790bf585SFenghua Yu va_list param; 35*790bf585SFenghua Yu int ret = 0; 36*790bf585SFenghua Yu 37*790bf585SFenghua Yu va_start(param, num); 38*790bf585SFenghua Yu p = va_arg(param, struct resctrl_val_param *); 39*790bf585SFenghua Yu va_end(param); 40*790bf585SFenghua Yu 41*790bf585SFenghua Yu /* Run NUM_OF_RUNS times */ 42*790bf585SFenghua Yu if (p->num_of_runs >= NUM_OF_RUNS) 43*790bf585SFenghua Yu return -1; 44*790bf585SFenghua Yu 45*790bf585SFenghua Yu if (p->num_of_runs == 0) { 46*790bf585SFenghua Yu sprintf(schemata, "%lx", p->mask); 47*790bf585SFenghua Yu ret = write_schemata(p->ctrlgrp, schemata, p->cpu_no, 48*790bf585SFenghua Yu p->resctrl_val); 49*790bf585SFenghua Yu } 50*790bf585SFenghua Yu p->num_of_runs++; 51*790bf585SFenghua Yu 52*790bf585SFenghua Yu return ret; 53*790bf585SFenghua Yu } 54*790bf585SFenghua Yu 55*790bf585SFenghua Yu static void show_cache_info(unsigned long sum_llc_perf_miss, int no_of_bits, 56*790bf585SFenghua Yu unsigned long span) 57*790bf585SFenghua Yu { 58*790bf585SFenghua Yu unsigned long allocated_cache_lines = span / 64; 59*790bf585SFenghua Yu unsigned long avg_llc_perf_miss = 0; 60*790bf585SFenghua Yu float diff_percent; 61*790bf585SFenghua Yu 62*790bf585SFenghua Yu avg_llc_perf_miss = sum_llc_perf_miss / (NUM_OF_RUNS - 1); 63*790bf585SFenghua Yu diff_percent = ((float)allocated_cache_lines - avg_llc_perf_miss) / 64*790bf585SFenghua Yu allocated_cache_lines * 100; 65*790bf585SFenghua Yu 66*790bf585SFenghua Yu printf("%sok CAT: cache miss rate within %d%%\n", 67*790bf585SFenghua Yu abs((int)diff_percent) > MAX_DIFF_PERCENT ? "not " : "", 68*790bf585SFenghua Yu MAX_DIFF_PERCENT); 69*790bf585SFenghua Yu tests_run++; 70*790bf585SFenghua Yu printf("# Percent diff=%d\n", abs((int)diff_percent)); 71*790bf585SFenghua Yu printf("# Number of bits: %d\n", no_of_bits); 72*790bf585SFenghua Yu printf("# Avg_llc_perf_miss: %lu\n", avg_llc_perf_miss); 73*790bf585SFenghua Yu printf("# Allocated cache lines: %lu\n", allocated_cache_lines); 74*790bf585SFenghua Yu } 75*790bf585SFenghua Yu 76*790bf585SFenghua Yu static int check_results(struct resctrl_val_param *param) 77*790bf585SFenghua Yu { 78*790bf585SFenghua Yu char *token_array[8], temp[512]; 79*790bf585SFenghua Yu unsigned long sum_llc_perf_miss = 0; 80*790bf585SFenghua Yu int runs = 0, no_of_bits = 0; 81*790bf585SFenghua Yu FILE *fp; 82*790bf585SFenghua Yu 83*790bf585SFenghua Yu printf("# Checking for pass/fail\n"); 84*790bf585SFenghua Yu fp = fopen(param->filename, "r"); 85*790bf585SFenghua Yu if (!fp) { 86*790bf585SFenghua Yu perror("# Cannot open file"); 87*790bf585SFenghua Yu 88*790bf585SFenghua Yu return errno; 89*790bf585SFenghua Yu } 90*790bf585SFenghua Yu 91*790bf585SFenghua Yu while (fgets(temp, sizeof(temp), fp)) { 92*790bf585SFenghua Yu char *token = strtok(temp, ":\t"); 93*790bf585SFenghua Yu int fields = 0; 94*790bf585SFenghua Yu 95*790bf585SFenghua Yu while (token) { 96*790bf585SFenghua Yu token_array[fields++] = token; 97*790bf585SFenghua Yu token = strtok(NULL, ":\t"); 98*790bf585SFenghua Yu } 99*790bf585SFenghua Yu /* 100*790bf585SFenghua Yu * Discard the first value which is inaccurate due to monitoring 101*790bf585SFenghua Yu * setup transition phase. 102*790bf585SFenghua Yu */ 103*790bf585SFenghua Yu if (runs > 0) 104*790bf585SFenghua Yu sum_llc_perf_miss += strtoul(token_array[3], NULL, 0); 105*790bf585SFenghua Yu runs++; 106*790bf585SFenghua Yu } 107*790bf585SFenghua Yu 108*790bf585SFenghua Yu fclose(fp); 109*790bf585SFenghua Yu no_of_bits = count_bits(param->mask); 110*790bf585SFenghua Yu 111*790bf585SFenghua Yu show_cache_info(sum_llc_perf_miss, no_of_bits, param->span); 112*790bf585SFenghua Yu 113*790bf585SFenghua Yu return 0; 114*790bf585SFenghua Yu } 115*790bf585SFenghua Yu 116*790bf585SFenghua Yu void cat_test_cleanup(void) 117*790bf585SFenghua Yu { 118*790bf585SFenghua Yu remove(RESULT_FILE_NAME1); 119*790bf585SFenghua Yu remove(RESULT_FILE_NAME2); 120*790bf585SFenghua Yu } 121*790bf585SFenghua Yu 122*790bf585SFenghua Yu int cat_perf_miss_val(int cpu_no, int n, char *cache_type) 123*790bf585SFenghua Yu { 124*790bf585SFenghua Yu unsigned long l_mask, l_mask_1; 125*790bf585SFenghua Yu int ret, pipefd[2], sibling_cpu_no; 126*790bf585SFenghua Yu char pipe_message; 127*790bf585SFenghua Yu pid_t bm_pid; 128*790bf585SFenghua Yu 129*790bf585SFenghua Yu cache_size = 0; 130*790bf585SFenghua Yu 131*790bf585SFenghua Yu ret = remount_resctrlfs(true); 132*790bf585SFenghua Yu if (ret) 133*790bf585SFenghua Yu return ret; 134*790bf585SFenghua Yu 135*790bf585SFenghua Yu if (!validate_resctrl_feature_request("cat")) 136*790bf585SFenghua Yu return -1; 137*790bf585SFenghua Yu 138*790bf585SFenghua Yu /* Get default cbm mask for L3/L2 cache */ 139*790bf585SFenghua Yu ret = get_cbm_mask(cache_type); 140*790bf585SFenghua Yu if (ret) 141*790bf585SFenghua Yu return ret; 142*790bf585SFenghua Yu 143*790bf585SFenghua Yu long_mask = strtoul(cbm_mask, NULL, 16); 144*790bf585SFenghua Yu 145*790bf585SFenghua Yu /* Get L3/L2 cache size */ 146*790bf585SFenghua Yu ret = get_cache_size(cpu_no, cache_type, &cache_size); 147*790bf585SFenghua Yu if (ret) 148*790bf585SFenghua Yu return ret; 149*790bf585SFenghua Yu printf("cache size :%lu\n", cache_size); 150*790bf585SFenghua Yu 151*790bf585SFenghua Yu /* Get max number of bits from default-cabm mask */ 152*790bf585SFenghua Yu count_of_bits = count_bits(long_mask); 153*790bf585SFenghua Yu 154*790bf585SFenghua Yu if (n < 1 || n > count_of_bits - 1) { 155*790bf585SFenghua Yu printf("Invalid input value for no_of_bits n!\n"); 156*790bf585SFenghua Yu printf("Please Enter value in range 1 to %d\n", 157*790bf585SFenghua Yu count_of_bits - 1); 158*790bf585SFenghua Yu return -1; 159*790bf585SFenghua Yu } 160*790bf585SFenghua Yu 161*790bf585SFenghua Yu /* Get core id from same socket for running another thread */ 162*790bf585SFenghua Yu sibling_cpu_no = get_core_sibling(cpu_no); 163*790bf585SFenghua Yu if (sibling_cpu_no < 0) 164*790bf585SFenghua Yu return -1; 165*790bf585SFenghua Yu 166*790bf585SFenghua Yu struct resctrl_val_param param = { 167*790bf585SFenghua Yu .resctrl_val = "cat", 168*790bf585SFenghua Yu .cpu_no = cpu_no, 169*790bf585SFenghua Yu .mum_resctrlfs = 0, 170*790bf585SFenghua Yu .setup = cat_setup, 171*790bf585SFenghua Yu }; 172*790bf585SFenghua Yu 173*790bf585SFenghua Yu l_mask = long_mask >> n; 174*790bf585SFenghua Yu l_mask_1 = ~l_mask & long_mask; 175*790bf585SFenghua Yu 176*790bf585SFenghua Yu /* Set param values for parent thread which will be allocated bitmask 177*790bf585SFenghua Yu * with (max_bits - n) bits 178*790bf585SFenghua Yu */ 179*790bf585SFenghua Yu param.span = cache_size * (count_of_bits - n) / count_of_bits; 180*790bf585SFenghua Yu strcpy(param.ctrlgrp, "c2"); 181*790bf585SFenghua Yu strcpy(param.mongrp, "m2"); 182*790bf585SFenghua Yu strcpy(param.filename, RESULT_FILE_NAME2); 183*790bf585SFenghua Yu param.mask = l_mask; 184*790bf585SFenghua Yu param.num_of_runs = 0; 185*790bf585SFenghua Yu 186*790bf585SFenghua Yu if (pipe(pipefd)) { 187*790bf585SFenghua Yu perror("# Unable to create pipe"); 188*790bf585SFenghua Yu return errno; 189*790bf585SFenghua Yu } 190*790bf585SFenghua Yu 191*790bf585SFenghua Yu bm_pid = fork(); 192*790bf585SFenghua Yu 193*790bf585SFenghua Yu /* Set param values for child thread which will be allocated bitmask 194*790bf585SFenghua Yu * with n bits 195*790bf585SFenghua Yu */ 196*790bf585SFenghua Yu if (bm_pid == 0) { 197*790bf585SFenghua Yu param.mask = l_mask_1; 198*790bf585SFenghua Yu strcpy(param.ctrlgrp, "c1"); 199*790bf585SFenghua Yu strcpy(param.mongrp, "m1"); 200*790bf585SFenghua Yu param.span = cache_size * n / count_of_bits; 201*790bf585SFenghua Yu strcpy(param.filename, RESULT_FILE_NAME1); 202*790bf585SFenghua Yu param.num_of_runs = 0; 203*790bf585SFenghua Yu param.cpu_no = sibling_cpu_no; 204*790bf585SFenghua Yu } 205*790bf585SFenghua Yu 206*790bf585SFenghua Yu remove(param.filename); 207*790bf585SFenghua Yu 208*790bf585SFenghua Yu ret = cat_val(¶m); 209*790bf585SFenghua Yu if (ret) 210*790bf585SFenghua Yu return ret; 211*790bf585SFenghua Yu 212*790bf585SFenghua Yu ret = check_results(¶m); 213*790bf585SFenghua Yu if (ret) 214*790bf585SFenghua Yu return ret; 215*790bf585SFenghua Yu 216*790bf585SFenghua Yu if (bm_pid == 0) { 217*790bf585SFenghua Yu /* Tell parent that child is ready */ 218*790bf585SFenghua Yu close(pipefd[0]); 219*790bf585SFenghua Yu pipe_message = 1; 220*790bf585SFenghua Yu if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) < 221*790bf585SFenghua Yu sizeof(pipe_message)) { 222*790bf585SFenghua Yu close(pipefd[1]); 223*790bf585SFenghua Yu perror("# failed signaling parent process"); 224*790bf585SFenghua Yu return errno; 225*790bf585SFenghua Yu } 226*790bf585SFenghua Yu 227*790bf585SFenghua Yu close(pipefd[1]); 228*790bf585SFenghua Yu while (1) 229*790bf585SFenghua Yu ; 230*790bf585SFenghua Yu } else { 231*790bf585SFenghua Yu /* Parent waits for child to be ready. */ 232*790bf585SFenghua Yu close(pipefd[1]); 233*790bf585SFenghua Yu pipe_message = 0; 234*790bf585SFenghua Yu while (pipe_message != 1) { 235*790bf585SFenghua Yu if (read(pipefd[0], &pipe_message, 236*790bf585SFenghua Yu sizeof(pipe_message)) < sizeof(pipe_message)) { 237*790bf585SFenghua Yu perror("# failed reading from child process"); 238*790bf585SFenghua Yu break; 239*790bf585SFenghua Yu } 240*790bf585SFenghua Yu } 241*790bf585SFenghua Yu close(pipefd[0]); 242*790bf585SFenghua Yu kill(bm_pid, SIGKILL); 243*790bf585SFenghua Yu } 244*790bf585SFenghua Yu 245*790bf585SFenghua Yu cat_test_cleanup(); 246*790bf585SFenghua Yu if (bm_pid) 247*790bf585SFenghua Yu umount_resctrlfs(); 248*790bf585SFenghua Yu 249*790bf585SFenghua Yu return 0; 250*790bf585SFenghua Yu } 251