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 sum_llc_occu_resc += strtoul(token_array[3], NULL, 0); 103 runs++; 104 } 105 fclose(fp); 106 107 return show_results_info(sum_llc_occu_resc, no_of_bits, span, 108 MAX_DIFF, MAX_DIFF_PERCENT, runs, true); 109 } 110 111 static void cmt_test_cleanup(void) 112 { 113 remove(RESULT_FILE_NAME); 114 } 115 116 static int cmt_run_test(const struct resctrl_test *test, const struct user_params *uparams) 117 { 118 struct fill_buf_param fill_buf = {}; 119 unsigned long cache_total_size = 0; 120 int n = uparams->bits ? : 5; 121 unsigned long long_mask; 122 int count_of_bits; 123 size_t span; 124 int ret; 125 126 ret = get_full_cbm("L3", &long_mask); 127 if (ret) 128 return ret; 129 130 ret = get_cache_size(uparams->cpu, "L3", &cache_total_size); 131 if (ret) 132 return ret; 133 ksft_print_msg("Cache size :%lu\n", cache_total_size); 134 135 count_of_bits = count_bits(long_mask); 136 137 if (n < 1 || n > count_of_bits) { 138 ksft_print_msg("Invalid input value for numbr_of_bits n!\n"); 139 ksft_print_msg("Please enter value in range 1 to %d\n", count_of_bits); 140 return -1; 141 } 142 143 struct resctrl_val_param param = { 144 .ctrlgrp = "c1", 145 .filename = RESULT_FILE_NAME, 146 .mask = ~(long_mask << n) & long_mask, 147 .num_of_runs = 0, 148 .init = cmt_init, 149 .setup = cmt_setup, 150 .measure = cmt_measure, 151 }; 152 153 span = cache_portion_size(cache_total_size, param.mask, long_mask); 154 155 if (uparams->fill_buf) { 156 fill_buf.buf_size = span; 157 fill_buf.memflush = uparams->fill_buf->memflush; 158 param.fill_buf = &fill_buf; 159 } else if (!uparams->benchmark_cmd[0]) { 160 fill_buf.buf_size = span; 161 fill_buf.memflush = true; 162 param.fill_buf = &fill_buf; 163 } 164 165 remove(RESULT_FILE_NAME); 166 167 ret = resctrl_val(test, uparams, ¶m); 168 if (ret) 169 return ret; 170 171 ret = check_results(¶m, span, n); 172 if (ret && (get_vendor() == ARCH_INTEL)) 173 ksft_print_msg("Intel CMT may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n"); 174 175 return ret; 176 } 177 178 static bool cmt_feature_check(const struct resctrl_test *test) 179 { 180 return test_resource_feature_check(test) && 181 resctrl_mon_feature_exists("L3_MON", "llc_occupancy"); 182 } 183 184 struct resctrl_test cmt_test = { 185 .name = "CMT", 186 .resource = "L3", 187 .feature_check = cmt_feature_check, 188 .run_test = cmt_run_test, 189 .cleanup = cmt_test_cleanup, 190 }; 191