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 20790bf585SFenghua Yu /* 21790bf585SFenghua Yu * Change schemata. Write schemata to specified 22790bf585SFenghua Yu * con_mon grp, mon_grp in resctrl FS. 23790bf585SFenghua Yu * Run 5 times in order to get average values. 24790bf585SFenghua Yu */ 258ee592a6SIlpo Järvinen static int cat_setup(struct resctrl_val_param *p) 26790bf585SFenghua Yu { 27790bf585SFenghua Yu char schemata[64]; 28790bf585SFenghua Yu int ret = 0; 29790bf585SFenghua Yu 30790bf585SFenghua Yu /* Run NUM_OF_RUNS times */ 31790bf585SFenghua Yu if (p->num_of_runs >= NUM_OF_RUNS) 32fa10366cSIlpo Järvinen return END_OF_TESTS; 33790bf585SFenghua Yu 34790bf585SFenghua Yu if (p->num_of_runs == 0) { 35790bf585SFenghua Yu sprintf(schemata, "%lx", p->mask); 36790bf585SFenghua Yu ret = write_schemata(p->ctrlgrp, schemata, p->cpu_no, 37790bf585SFenghua Yu p->resctrl_val); 38790bf585SFenghua Yu } 39790bf585SFenghua Yu p->num_of_runs++; 40790bf585SFenghua Yu 41790bf585SFenghua Yu return ret; 42790bf585SFenghua Yu } 43790bf585SFenghua Yu 44*33403bc7SIlpo Järvinen static int show_results_info(__u64 sum_llc_val, int no_of_bits, 455caf1b64SIlpo Järvinen unsigned long cache_span, unsigned long max_diff, 465caf1b64SIlpo Järvinen unsigned long max_diff_percent, unsigned long num_of_runs, 475caf1b64SIlpo Järvinen bool platform) 485caf1b64SIlpo Järvinen { 49*33403bc7SIlpo Järvinen __u64 avg_llc_val = 0; 505caf1b64SIlpo Järvinen float diff_percent; 515caf1b64SIlpo Järvinen int ret; 525caf1b64SIlpo Järvinen 535caf1b64SIlpo Järvinen avg_llc_val = sum_llc_val / num_of_runs; 545caf1b64SIlpo Järvinen diff_percent = ((float)cache_span - avg_llc_val) / cache_span * 100; 555caf1b64SIlpo Järvinen 565caf1b64SIlpo Järvinen ret = platform && abs((int)diff_percent) > max_diff_percent; 575caf1b64SIlpo Järvinen 585caf1b64SIlpo Järvinen ksft_print_msg("%s Check cache miss rate within %lu%%\n", 595caf1b64SIlpo Järvinen ret ? "Fail:" : "Pass:", max_diff_percent); 605caf1b64SIlpo Järvinen 615caf1b64SIlpo Järvinen ksft_print_msg("Percent diff=%d\n", abs((int)diff_percent)); 625caf1b64SIlpo Järvinen 635caf1b64SIlpo Järvinen show_cache_info(no_of_bits, avg_llc_val, cache_span, true); 645caf1b64SIlpo Järvinen 655caf1b64SIlpo Järvinen return ret; 665caf1b64SIlpo Järvinen } 675caf1b64SIlpo Järvinen 68b1a901e0SIlpo Järvinen static int check_results(struct resctrl_val_param *param, size_t span) 69790bf585SFenghua Yu { 70790bf585SFenghua Yu char *token_array[8], temp[512]; 71790bf585SFenghua Yu int runs = 0, no_of_bits = 0; 72*33403bc7SIlpo Järvinen __u64 sum_llc_perf_miss = 0; 73790bf585SFenghua Yu FILE *fp; 74790bf585SFenghua Yu 75ca2f4214SFenghua Yu ksft_print_msg("Checking for pass/fail\n"); 76790bf585SFenghua Yu fp = fopen(param->filename, "r"); 77790bf585SFenghua Yu if (!fp) { 78cc8ff7f5SIlpo Järvinen ksft_perror("Cannot open file"); 79790bf585SFenghua Yu 80c90fba60SIlpo Järvinen return -1; 81790bf585SFenghua Yu } 82790bf585SFenghua Yu 83790bf585SFenghua Yu while (fgets(temp, sizeof(temp), fp)) { 84790bf585SFenghua Yu char *token = strtok(temp, ":\t"); 85790bf585SFenghua Yu int fields = 0; 86790bf585SFenghua Yu 87790bf585SFenghua Yu while (token) { 88790bf585SFenghua Yu token_array[fields++] = token; 89790bf585SFenghua Yu token = strtok(NULL, ":\t"); 90790bf585SFenghua Yu } 91790bf585SFenghua Yu /* 92790bf585SFenghua Yu * Discard the first value which is inaccurate due to monitoring 93790bf585SFenghua Yu * setup transition phase. 94790bf585SFenghua Yu */ 95790bf585SFenghua Yu if (runs > 0) 96*33403bc7SIlpo Järvinen sum_llc_perf_miss += strtoull(token_array[3], NULL, 0); 97790bf585SFenghua Yu runs++; 98790bf585SFenghua Yu } 99790bf585SFenghua Yu 100790bf585SFenghua Yu fclose(fp); 101790bf585SFenghua Yu no_of_bits = count_bits(param->mask); 102790bf585SFenghua Yu 1035caf1b64SIlpo Järvinen return show_results_info(sum_llc_perf_miss, no_of_bits, span / 64, 1043dad011bSIlpo Järvinen MAX_DIFF, MAX_DIFF_PERCENT, runs - 1, 1055caf1b64SIlpo Järvinen get_vendor() == ARCH_INTEL); 106790bf585SFenghua Yu } 107790bf585SFenghua Yu 108790bf585SFenghua Yu void cat_test_cleanup(void) 109790bf585SFenghua Yu { 110790bf585SFenghua Yu remove(RESULT_FILE_NAME1); 111790bf585SFenghua Yu remove(RESULT_FILE_NAME2); 112790bf585SFenghua Yu } 113790bf585SFenghua Yu 114790bf585SFenghua Yu int cat_perf_miss_val(int cpu_no, int n, char *cache_type) 115790bf585SFenghua Yu { 116b6dfac94SIlpo Järvinen unsigned long full_cache_mask, long_mask; 117790bf585SFenghua Yu unsigned long l_mask, l_mask_1; 118790bf585SFenghua Yu int ret, pipefd[2], sibling_cpu_no; 11919e94a23SIlpo Järvinen unsigned long cache_total_size = 0; 12085b73447SIlpo Järvinen int count_of_bits; 121790bf585SFenghua Yu char pipe_message; 122b1a901e0SIlpo Järvinen size_t span; 123790bf585SFenghua Yu 124b6dfac94SIlpo Järvinen ret = get_full_cbm(cache_type, &full_cache_mask); 125b6dfac94SIlpo Järvinen if (ret) 126b6dfac94SIlpo Järvinen return ret; 127b6dfac94SIlpo Järvinen /* Get the largest contiguous exclusive portion of the cache */ 128b6dfac94SIlpo Järvinen ret = get_mask_no_shareable(cache_type, &long_mask); 129790bf585SFenghua Yu if (ret) 130790bf585SFenghua Yu return ret; 131790bf585SFenghua Yu 132790bf585SFenghua Yu /* Get L3/L2 cache size */ 13319e94a23SIlpo Järvinen ret = get_cache_size(cpu_no, cache_type, &cache_total_size); 134790bf585SFenghua Yu if (ret) 135790bf585SFenghua Yu return ret; 13619e94a23SIlpo Järvinen ksft_print_msg("Cache size :%lu\n", cache_total_size); 137790bf585SFenghua Yu 138790bf585SFenghua Yu count_of_bits = count_bits(long_mask); 139790bf585SFenghua Yu 14009a67934SFenghua Yu if (!n) 14109a67934SFenghua Yu n = count_of_bits / 2; 14209a67934SFenghua Yu 14309a67934SFenghua Yu if (n > count_of_bits - 1) { 144ca2f4214SFenghua Yu ksft_print_msg("Invalid input value for no_of_bits n!\n"); 145ca2f4214SFenghua Yu ksft_print_msg("Please enter value in range 1 to %d\n", 146790bf585SFenghua Yu count_of_bits - 1); 147790bf585SFenghua Yu return -1; 148790bf585SFenghua Yu } 149790bf585SFenghua Yu 150790bf585SFenghua Yu /* Get core id from same socket for running another thread */ 151790bf585SFenghua Yu sibling_cpu_no = get_core_sibling(cpu_no); 152790bf585SFenghua Yu if (sibling_cpu_no < 0) 153790bf585SFenghua Yu return -1; 154790bf585SFenghua Yu 155790bf585SFenghua Yu struct resctrl_val_param param = { 15624286736SFenghua Yu .resctrl_val = CAT_STR, 157790bf585SFenghua Yu .cpu_no = cpu_no, 158790bf585SFenghua Yu .setup = cat_setup, 159790bf585SFenghua Yu }; 160790bf585SFenghua Yu 161790bf585SFenghua Yu l_mask = long_mask >> n; 162790bf585SFenghua Yu l_mask_1 = ~l_mask & long_mask; 163790bf585SFenghua Yu 164790bf585SFenghua Yu /* Set param values for parent thread which will be allocated bitmask 165790bf585SFenghua Yu * with (max_bits - n) bits 166790bf585SFenghua Yu */ 167b6dfac94SIlpo Järvinen span = cache_portion_size(cache_total_size, l_mask, full_cache_mask); 168790bf585SFenghua Yu strcpy(param.ctrlgrp, "c2"); 169790bf585SFenghua Yu strcpy(param.mongrp, "m2"); 170790bf585SFenghua Yu strcpy(param.filename, RESULT_FILE_NAME2); 171790bf585SFenghua Yu param.mask = l_mask; 172790bf585SFenghua Yu param.num_of_runs = 0; 173790bf585SFenghua Yu 174790bf585SFenghua Yu if (pipe(pipefd)) { 175cc8ff7f5SIlpo Järvinen ksft_perror("Unable to create pipe"); 176c90fba60SIlpo Järvinen return -1; 177790bf585SFenghua Yu } 178790bf585SFenghua Yu 179a080b6e7SShaopeng Tan fflush(stdout); 180790bf585SFenghua Yu bm_pid = fork(); 181790bf585SFenghua Yu 182790bf585SFenghua Yu /* Set param values for child thread which will be allocated bitmask 183790bf585SFenghua Yu * with n bits 184790bf585SFenghua Yu */ 185790bf585SFenghua Yu if (bm_pid == 0) { 186790bf585SFenghua Yu param.mask = l_mask_1; 187790bf585SFenghua Yu strcpy(param.ctrlgrp, "c1"); 188790bf585SFenghua Yu strcpy(param.mongrp, "m1"); 189b6dfac94SIlpo Järvinen span = cache_portion_size(cache_total_size, l_mask_1, full_cache_mask); 190790bf585SFenghua Yu strcpy(param.filename, RESULT_FILE_NAME1); 191790bf585SFenghua Yu param.num_of_runs = 0; 192790bf585SFenghua Yu param.cpu_no = sibling_cpu_no; 193790bf585SFenghua Yu } 194790bf585SFenghua Yu 195790bf585SFenghua Yu remove(param.filename); 196790bf585SFenghua Yu 197b1a901e0SIlpo Järvinen ret = cat_val(¶m, span); 19839e34ddcSShaopeng Tan if (ret == 0) 199b1a901e0SIlpo Järvinen ret = check_results(¶m, span); 200790bf585SFenghua Yu 201790bf585SFenghua Yu if (bm_pid == 0) { 202790bf585SFenghua Yu /* Tell parent that child is ready */ 203790bf585SFenghua Yu close(pipefd[0]); 204790bf585SFenghua Yu pipe_message = 1; 205790bf585SFenghua Yu if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) < 20639e34ddcSShaopeng Tan sizeof(pipe_message)) 20739e34ddcSShaopeng Tan /* 20839e34ddcSShaopeng Tan * Just print the error message. 20939e34ddcSShaopeng Tan * Let while(1) run and wait for itself to be killed. 21039e34ddcSShaopeng Tan */ 211cc8ff7f5SIlpo Järvinen ksft_perror("Failed signaling parent process"); 212790bf585SFenghua Yu 213790bf585SFenghua Yu close(pipefd[1]); 214790bf585SFenghua Yu while (1) 215790bf585SFenghua Yu ; 216790bf585SFenghua Yu } else { 217790bf585SFenghua Yu /* Parent waits for child to be ready. */ 218790bf585SFenghua Yu close(pipefd[1]); 219790bf585SFenghua Yu pipe_message = 0; 220790bf585SFenghua Yu while (pipe_message != 1) { 221790bf585SFenghua Yu if (read(pipefd[0], &pipe_message, 222790bf585SFenghua Yu sizeof(pipe_message)) < sizeof(pipe_message)) { 223cc8ff7f5SIlpo Järvinen ksft_perror("Failed reading from child process"); 224790bf585SFenghua Yu break; 225790bf585SFenghua Yu } 226790bf585SFenghua Yu } 227790bf585SFenghua Yu close(pipefd[0]); 228790bf585SFenghua Yu kill(bm_pid, SIGKILL); 229790bf585SFenghua Yu } 230790bf585SFenghua Yu 231790bf585SFenghua Yu cat_test_cleanup(); 232790bf585SFenghua Yu 23339e34ddcSShaopeng Tan return ret; 234790bf585SFenghua Yu } 235