1790bf585SFenghua Yu // SPDX-License-Identifier: GPL-2.0 2790bf585SFenghua Yu /* 3790bf585SFenghua Yu * Cache Allocation Technology (CAT) test 4790bf585SFenghua Yu * 5790bf585SFenghua Yu * Copyright (C) 2018 Intel Corporation 6790bf585SFenghua Yu * 7790bf585SFenghua Yu * Authors: 8790bf585SFenghua Yu * Sai Praneeth Prakhya <[email protected]>, 9790bf585SFenghua Yu * Fenghua Yu <[email protected]> 10790bf585SFenghua Yu */ 11790bf585SFenghua Yu #include "resctrl.h" 12790bf585SFenghua Yu #include <unistd.h> 13790bf585SFenghua Yu 14790bf585SFenghua Yu #define RESULT_FILE_NAME1 "result_cat1" 15790bf585SFenghua Yu #define RESULT_FILE_NAME2 "result_cat2" 16790bf585SFenghua Yu #define NUM_OF_RUNS 5 17790bf585SFenghua Yu #define MAX_DIFF_PERCENT 4 18790bf585SFenghua Yu #define MAX_DIFF 1000000 19790bf585SFenghua Yu 208236c51dSFenghua Yu static int count_of_bits; 218236c51dSFenghua Yu static char cbm_mask[256]; 228236c51dSFenghua Yu static unsigned long long_mask; 238236c51dSFenghua Yu static unsigned long cache_size; 24790bf585SFenghua Yu 25790bf585SFenghua Yu /* 26790bf585SFenghua Yu * Change schemata. Write schemata to specified 27790bf585SFenghua Yu * con_mon grp, mon_grp in resctrl FS. 28790bf585SFenghua Yu * Run 5 times in order to get average values. 29790bf585SFenghua Yu */ 30790bf585SFenghua Yu static int cat_setup(int num, ...) 31790bf585SFenghua Yu { 32790bf585SFenghua Yu struct resctrl_val_param *p; 33790bf585SFenghua Yu char schemata[64]; 34790bf585SFenghua Yu va_list param; 35790bf585SFenghua Yu int ret = 0; 36790bf585SFenghua Yu 37790bf585SFenghua Yu va_start(param, num); 38790bf585SFenghua Yu p = va_arg(param, struct resctrl_val_param *); 39790bf585SFenghua Yu va_end(param); 40790bf585SFenghua Yu 41790bf585SFenghua Yu /* Run NUM_OF_RUNS times */ 42790bf585SFenghua Yu if (p->num_of_runs >= NUM_OF_RUNS) 43790bf585SFenghua Yu return -1; 44790bf585SFenghua Yu 45790bf585SFenghua Yu if (p->num_of_runs == 0) { 46790bf585SFenghua Yu sprintf(schemata, "%lx", p->mask); 47790bf585SFenghua Yu ret = write_schemata(p->ctrlgrp, schemata, p->cpu_no, 48790bf585SFenghua Yu p->resctrl_val); 49790bf585SFenghua Yu } 50790bf585SFenghua Yu p->num_of_runs++; 51790bf585SFenghua Yu 52790bf585SFenghua Yu return ret; 53790bf585SFenghua Yu } 54790bf585SFenghua Yu 55*ca2f4214SFenghua Yu static int show_cache_info(unsigned long sum_llc_perf_miss, int no_of_bits, 56790bf585SFenghua Yu unsigned long span) 57790bf585SFenghua Yu { 58790bf585SFenghua Yu unsigned long allocated_cache_lines = span / 64; 59790bf585SFenghua Yu unsigned long avg_llc_perf_miss = 0; 60790bf585SFenghua Yu float diff_percent; 61*ca2f4214SFenghua Yu int ret; 62790bf585SFenghua Yu 63790bf585SFenghua Yu avg_llc_perf_miss = sum_llc_perf_miss / (NUM_OF_RUNS - 1); 64790bf585SFenghua Yu diff_percent = ((float)allocated_cache_lines - avg_llc_perf_miss) / 65790bf585SFenghua Yu allocated_cache_lines * 100; 66790bf585SFenghua Yu 67*ca2f4214SFenghua Yu ret = !is_amd && abs((int)diff_percent) > MAX_DIFF_PERCENT; 68*ca2f4214SFenghua Yu ksft_print_msg("Cache miss rate %swithin %d%%\n", 69*ca2f4214SFenghua Yu ret ? "not " : "", MAX_DIFF_PERCENT); 70*ca2f4214SFenghua Yu 71*ca2f4214SFenghua Yu ksft_print_msg("Percent diff=%d\n", abs((int)diff_percent)); 72*ca2f4214SFenghua Yu ksft_print_msg("Number of bits: %d\n", no_of_bits); 73*ca2f4214SFenghua Yu ksft_print_msg("Avg_llc_perf_miss: %lu\n", avg_llc_perf_miss); 74*ca2f4214SFenghua Yu ksft_print_msg("Allocated cache lines: %lu\n", allocated_cache_lines); 75*ca2f4214SFenghua Yu 76*ca2f4214SFenghua Yu return ret; 77790bf585SFenghua Yu } 78790bf585SFenghua Yu 79790bf585SFenghua Yu static int check_results(struct resctrl_val_param *param) 80790bf585SFenghua Yu { 81790bf585SFenghua Yu char *token_array[8], temp[512]; 82790bf585SFenghua Yu unsigned long sum_llc_perf_miss = 0; 83790bf585SFenghua Yu int runs = 0, no_of_bits = 0; 84790bf585SFenghua Yu FILE *fp; 85790bf585SFenghua Yu 86*ca2f4214SFenghua Yu ksft_print_msg("Checking for pass/fail\n"); 87790bf585SFenghua Yu fp = fopen(param->filename, "r"); 88790bf585SFenghua Yu if (!fp) { 89790bf585SFenghua Yu perror("# Cannot open file"); 90790bf585SFenghua Yu 91790bf585SFenghua Yu return errno; 92790bf585SFenghua Yu } 93790bf585SFenghua Yu 94790bf585SFenghua Yu while (fgets(temp, sizeof(temp), fp)) { 95790bf585SFenghua Yu char *token = strtok(temp, ":\t"); 96790bf585SFenghua Yu int fields = 0; 97790bf585SFenghua Yu 98790bf585SFenghua Yu while (token) { 99790bf585SFenghua Yu token_array[fields++] = token; 100790bf585SFenghua Yu token = strtok(NULL, ":\t"); 101790bf585SFenghua Yu } 102790bf585SFenghua Yu /* 103790bf585SFenghua Yu * Discard the first value which is inaccurate due to monitoring 104790bf585SFenghua Yu * setup transition phase. 105790bf585SFenghua Yu */ 106790bf585SFenghua Yu if (runs > 0) 107790bf585SFenghua Yu sum_llc_perf_miss += strtoul(token_array[3], NULL, 0); 108790bf585SFenghua Yu runs++; 109790bf585SFenghua Yu } 110790bf585SFenghua Yu 111790bf585SFenghua Yu fclose(fp); 112790bf585SFenghua Yu no_of_bits = count_bits(param->mask); 113790bf585SFenghua Yu 114*ca2f4214SFenghua Yu return show_cache_info(sum_llc_perf_miss, no_of_bits, param->span); 115790bf585SFenghua Yu } 116790bf585SFenghua Yu 117790bf585SFenghua Yu void cat_test_cleanup(void) 118790bf585SFenghua Yu { 119790bf585SFenghua Yu remove(RESULT_FILE_NAME1); 120790bf585SFenghua Yu remove(RESULT_FILE_NAME2); 121790bf585SFenghua Yu } 122790bf585SFenghua Yu 123790bf585SFenghua Yu int cat_perf_miss_val(int cpu_no, int n, char *cache_type) 124790bf585SFenghua Yu { 125790bf585SFenghua Yu unsigned long l_mask, l_mask_1; 126790bf585SFenghua Yu int ret, pipefd[2], sibling_cpu_no; 127790bf585SFenghua Yu char pipe_message; 128790bf585SFenghua Yu pid_t bm_pid; 129790bf585SFenghua Yu 130790bf585SFenghua Yu cache_size = 0; 131790bf585SFenghua Yu 132790bf585SFenghua Yu ret = remount_resctrlfs(true); 133790bf585SFenghua Yu if (ret) 134790bf585SFenghua Yu return ret; 135790bf585SFenghua Yu 136790bf585SFenghua Yu if (!validate_resctrl_feature_request("cat")) 137790bf585SFenghua Yu return -1; 138790bf585SFenghua Yu 139790bf585SFenghua Yu /* Get default cbm mask for L3/L2 cache */ 1408236c51dSFenghua Yu ret = get_cbm_mask(cache_type, cbm_mask); 141790bf585SFenghua Yu if (ret) 142790bf585SFenghua Yu return ret; 143790bf585SFenghua Yu 144790bf585SFenghua Yu long_mask = strtoul(cbm_mask, NULL, 16); 145790bf585SFenghua Yu 146790bf585SFenghua Yu /* Get L3/L2 cache size */ 147790bf585SFenghua Yu ret = get_cache_size(cpu_no, cache_type, &cache_size); 148790bf585SFenghua Yu if (ret) 149790bf585SFenghua Yu return ret; 150*ca2f4214SFenghua Yu ksft_print_msg("Cache size :%lu\n", cache_size); 151790bf585SFenghua Yu 152790bf585SFenghua Yu /* Get max number of bits from default-cabm mask */ 153790bf585SFenghua Yu count_of_bits = count_bits(long_mask); 154790bf585SFenghua Yu 155790bf585SFenghua Yu if (n < 1 || n > count_of_bits - 1) { 156*ca2f4214SFenghua Yu ksft_print_msg("Invalid input value for no_of_bits n!\n"); 157*ca2f4214SFenghua Yu ksft_print_msg("Please enter value in range 1 to %d\n", 158790bf585SFenghua Yu count_of_bits - 1); 159790bf585SFenghua Yu return -1; 160790bf585SFenghua Yu } 161790bf585SFenghua Yu 162790bf585SFenghua Yu /* Get core id from same socket for running another thread */ 163790bf585SFenghua Yu sibling_cpu_no = get_core_sibling(cpu_no); 164790bf585SFenghua Yu if (sibling_cpu_no < 0) 165790bf585SFenghua Yu return -1; 166790bf585SFenghua Yu 167790bf585SFenghua Yu struct resctrl_val_param param = { 16824286736SFenghua Yu .resctrl_val = CAT_STR, 169790bf585SFenghua Yu .cpu_no = cpu_no, 170790bf585SFenghua Yu .mum_resctrlfs = 0, 171790bf585SFenghua Yu .setup = cat_setup, 172790bf585SFenghua Yu }; 173790bf585SFenghua Yu 174790bf585SFenghua Yu l_mask = long_mask >> n; 175790bf585SFenghua Yu l_mask_1 = ~l_mask & long_mask; 176790bf585SFenghua Yu 177790bf585SFenghua Yu /* Set param values for parent thread which will be allocated bitmask 178790bf585SFenghua Yu * with (max_bits - n) bits 179790bf585SFenghua Yu */ 180790bf585SFenghua Yu param.span = cache_size * (count_of_bits - n) / count_of_bits; 181790bf585SFenghua Yu strcpy(param.ctrlgrp, "c2"); 182790bf585SFenghua Yu strcpy(param.mongrp, "m2"); 183790bf585SFenghua Yu strcpy(param.filename, RESULT_FILE_NAME2); 184790bf585SFenghua Yu param.mask = l_mask; 185790bf585SFenghua Yu param.num_of_runs = 0; 186790bf585SFenghua Yu 187790bf585SFenghua Yu if (pipe(pipefd)) { 188790bf585SFenghua Yu perror("# Unable to create pipe"); 189790bf585SFenghua Yu return errno; 190790bf585SFenghua Yu } 191790bf585SFenghua Yu 192790bf585SFenghua Yu bm_pid = fork(); 193790bf585SFenghua Yu 194790bf585SFenghua Yu /* Set param values for child thread which will be allocated bitmask 195790bf585SFenghua Yu * with n bits 196790bf585SFenghua Yu */ 197790bf585SFenghua Yu if (bm_pid == 0) { 198790bf585SFenghua Yu param.mask = l_mask_1; 199790bf585SFenghua Yu strcpy(param.ctrlgrp, "c1"); 200790bf585SFenghua Yu strcpy(param.mongrp, "m1"); 201790bf585SFenghua Yu param.span = cache_size * n / count_of_bits; 202790bf585SFenghua Yu strcpy(param.filename, RESULT_FILE_NAME1); 203790bf585SFenghua Yu param.num_of_runs = 0; 204790bf585SFenghua Yu param.cpu_no = sibling_cpu_no; 205790bf585SFenghua Yu } 206790bf585SFenghua Yu 207790bf585SFenghua Yu remove(param.filename); 208790bf585SFenghua Yu 209790bf585SFenghua Yu ret = cat_val(¶m); 210790bf585SFenghua Yu if (ret) 211790bf585SFenghua Yu return ret; 212790bf585SFenghua Yu 213790bf585SFenghua Yu ret = check_results(¶m); 214790bf585SFenghua Yu if (ret) 215790bf585SFenghua Yu return ret; 216790bf585SFenghua Yu 217790bf585SFenghua Yu if (bm_pid == 0) { 218790bf585SFenghua Yu /* Tell parent that child is ready */ 219790bf585SFenghua Yu close(pipefd[0]); 220790bf585SFenghua Yu pipe_message = 1; 221790bf585SFenghua Yu if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) < 222790bf585SFenghua Yu sizeof(pipe_message)) { 223790bf585SFenghua Yu close(pipefd[1]); 224790bf585SFenghua Yu perror("# failed signaling parent process"); 225790bf585SFenghua Yu return errno; 226790bf585SFenghua Yu } 227790bf585SFenghua Yu 228790bf585SFenghua Yu close(pipefd[1]); 229790bf585SFenghua Yu while (1) 230790bf585SFenghua Yu ; 231790bf585SFenghua Yu } else { 232790bf585SFenghua Yu /* Parent waits for child to be ready. */ 233790bf585SFenghua Yu close(pipefd[1]); 234790bf585SFenghua Yu pipe_message = 0; 235790bf585SFenghua Yu while (pipe_message != 1) { 236790bf585SFenghua Yu if (read(pipefd[0], &pipe_message, 237790bf585SFenghua Yu sizeof(pipe_message)) < sizeof(pipe_message)) { 238790bf585SFenghua Yu perror("# failed reading from child process"); 239790bf585SFenghua Yu break; 240790bf585SFenghua Yu } 241790bf585SFenghua Yu } 242790bf585SFenghua Yu close(pipefd[0]); 243790bf585SFenghua Yu kill(bm_pid, SIGKILL); 244790bf585SFenghua Yu } 245790bf585SFenghua Yu 246790bf585SFenghua Yu cat_test_cleanup(); 247790bf585SFenghua Yu if (bm_pid) 248790bf585SFenghua Yu umount_resctrlfs(); 249790bf585SFenghua Yu 250790bf585SFenghua Yu return 0; 251790bf585SFenghua Yu } 252