1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Cache Monitoring Technology (CMT) test 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 "resctrl.h" 12 #include <unistd.h> 13 14 #define RESULT_FILE_NAME "result_cmt" 15 #define NUM_OF_RUNS 5 16 #define MAX_DIFF 2000000 17 #define MAX_DIFF_PERCENT 15 18 19 #define CON_MON_LCC_OCCUP_PATH \ 20 "%s/%s/mon_data/mon_L3_%02d/llc_occupancy" 21 22 static int cmt_init(const struct resctrl_val_param *param, int domain_id) 23 { 24 sprintf(llc_occup_path, CON_MON_LCC_OCCUP_PATH, RESCTRL_PATH, 25 param->ctrlgrp, domain_id); 26 27 return 0; 28 } 29 30 static int cmt_setup(const struct resctrl_test *test, 31 const struct user_params *uparams, 32 struct resctrl_val_param *p) 33 { 34 /* Run NUM_OF_RUNS times */ 35 if (p->num_of_runs >= NUM_OF_RUNS) 36 return END_OF_TESTS; 37 38 p->num_of_runs++; 39 40 return 0; 41 } 42 43 static int cmt_measure(const struct user_params *uparams, 44 struct resctrl_val_param *param, pid_t bm_pid) 45 { 46 sleep(1); 47 return measure_llc_resctrl(param->filename, bm_pid); 48 } 49 50 static int show_results_info(unsigned long sum_llc_val, int no_of_bits, 51 unsigned long cache_span, unsigned long max_diff, 52 unsigned long max_diff_percent, unsigned long num_of_runs, 53 bool platform) 54 { 55 unsigned long avg_llc_val = 0; 56 float diff_percent; 57 long avg_diff = 0; 58 int ret; 59 60 avg_llc_val = sum_llc_val / num_of_runs; 61 avg_diff = (long)(cache_span - avg_llc_val); 62 diff_percent = ((float)cache_span - avg_llc_val) / cache_span * 100; 63 64 ret = platform && abs((int)diff_percent) > max_diff_percent && 65 labs(avg_diff) > max_diff; 66 67 ksft_print_msg("%s Check cache miss rate within %lu%%\n", 68 ret ? "Fail:" : "Pass:", max_diff_percent); 69 70 ksft_print_msg("Percent diff=%d\n", abs((int)diff_percent)); 71 72 show_cache_info(no_of_bits, avg_llc_val, cache_span, false); 73 74 return ret; 75 } 76 77 static int check_results(struct resctrl_val_param *param, size_t span, int no_of_bits) 78 { 79 char *token_array[8], temp[512]; 80 unsigned long sum_llc_occu_resc = 0; 81 int runs = 0; 82 FILE *fp; 83 84 ksft_print_msg("Checking for pass/fail\n"); 85 fp = fopen(param->filename, "r"); 86 if (!fp) { 87 ksft_perror("Error in opening file"); 88 89 return -1; 90 } 91 92 while (fgets(temp, sizeof(temp), fp)) { 93 char *token = strtok(temp, ":\t"); 94 int fields = 0; 95 96 while (token) { 97 token_array[fields++] = token; 98 token = strtok(NULL, ":\t"); 99 } 100 101 /* Field 3 is llc occ resc value */ 102 if (runs > 0) 103 sum_llc_occu_resc += strtoul(token_array[3], NULL, 0); 104 runs++; 105 } 106 fclose(fp); 107 108 return show_results_info(sum_llc_occu_resc, no_of_bits, span, 109 MAX_DIFF, MAX_DIFF_PERCENT, runs - 1, true); 110 } 111 112 static void cmt_test_cleanup(void) 113 { 114 remove(RESULT_FILE_NAME); 115 } 116 117 static int cmt_run_test(const struct resctrl_test *test, const struct user_params *uparams) 118 { 119 const char * const *cmd = uparams->benchmark_cmd; 120 const char *new_cmd[BENCHMARK_ARGS]; 121 unsigned long cache_total_size = 0; 122 int n = uparams->bits ? : 5; 123 unsigned long long_mask; 124 char *span_str = NULL; 125 int count_of_bits; 126 size_t span; 127 int ret, i; 128 129 ret = get_full_cbm("L3", &long_mask); 130 if (ret) 131 return ret; 132 133 ret = get_cache_size(uparams->cpu, "L3", &cache_total_size); 134 if (ret) 135 return ret; 136 ksft_print_msg("Cache size :%lu\n", cache_total_size); 137 138 count_of_bits = count_bits(long_mask); 139 140 if (n < 1 || n > count_of_bits) { 141 ksft_print_msg("Invalid input value for numbr_of_bits n!\n"); 142 ksft_print_msg("Please enter value in range 1 to %d\n", count_of_bits); 143 return -1; 144 } 145 146 struct resctrl_val_param param = { 147 .ctrlgrp = "c1", 148 .filename = RESULT_FILE_NAME, 149 .mask = ~(long_mask << n) & long_mask, 150 .num_of_runs = 0, 151 .init = cmt_init, 152 .setup = cmt_setup, 153 .measure = cmt_measure, 154 }; 155 156 span = cache_portion_size(cache_total_size, param.mask, long_mask); 157 158 if (strcmp(cmd[0], "fill_buf") == 0) { 159 /* Duplicate the command to be able to replace span in it */ 160 for (i = 0; uparams->benchmark_cmd[i]; i++) 161 new_cmd[i] = uparams->benchmark_cmd[i]; 162 new_cmd[i] = NULL; 163 164 ret = asprintf(&span_str, "%zu", span); 165 if (ret < 0) 166 return -1; 167 new_cmd[1] = span_str; 168 cmd = new_cmd; 169 } 170 171 remove(RESULT_FILE_NAME); 172 173 ret = resctrl_val(test, uparams, cmd, ¶m); 174 if (ret) 175 goto out; 176 177 ret = check_results(¶m, span, n); 178 if (ret && (get_vendor() == ARCH_INTEL)) 179 ksft_print_msg("Intel CMT may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n"); 180 181 out: 182 free(span_str); 183 184 return ret; 185 } 186 187 static bool cmt_feature_check(const struct resctrl_test *test) 188 { 189 return test_resource_feature_check(test) && 190 resctrl_mon_feature_exists("L3_MON", "llc_occupancy"); 191 } 192 193 struct resctrl_test cmt_test = { 194 .name = "CMT", 195 .resource = "L3", 196 .feature_check = cmt_feature_check, 197 .run_test = cmt_run_test, 198 .cleanup = cmt_test_cleanup, 199 }; 200