1 // SPDX-License-Identifier: GPL-2.0
3 * Cache Allocation Technology (CAT) test
5 * Copyright (C) 2018 Intel Corporation
8 * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
9 * Fenghua Yu <fenghua.yu@intel.com>
14 #define RESULT_FILE_NAME1 "result_cat1"
15 #define RESULT_FILE_NAME2 "result_cat2"
17 #define MAX_DIFF_PERCENT 4
18 #define MAX_DIFF 1000000
22 unsigned long long_mask
;
23 unsigned long cache_size
;
26 * Change schemata. Write schemata to specified
27 * con_mon grp, mon_grp in resctrl FS.
28 * Run 5 times in order to get average values.
30 static int cat_setup(int num
, ...)
32 struct resctrl_val_param
*p
;
38 p
= va_arg(param
, struct resctrl_val_param
*);
41 /* Run NUM_OF_RUNS times */
42 if (p
->num_of_runs
>= NUM_OF_RUNS
)
45 if (p
->num_of_runs
== 0) {
46 sprintf(schemata
, "%lx", p
->mask
);
47 ret
= write_schemata(p
->ctrlgrp
, schemata
, p
->cpu_no
,
55 static void show_cache_info(unsigned long sum_llc_perf_miss
, int no_of_bits
,
58 unsigned long allocated_cache_lines
= span
/ 64;
59 unsigned long avg_llc_perf_miss
= 0;
62 avg_llc_perf_miss
= sum_llc_perf_miss
/ (NUM_OF_RUNS
- 1);
63 diff_percent
= ((float)allocated_cache_lines
- avg_llc_perf_miss
) /
64 allocated_cache_lines
* 100;
66 printf("%sok CAT: cache miss rate within %d%%\n",
67 !is_amd
&& abs((int)diff_percent
) > MAX_DIFF_PERCENT
?
68 "not " : "", MAX_DIFF_PERCENT
);
70 printf("# Percent diff=%d\n", abs((int)diff_percent
));
71 printf("# Number of bits: %d\n", no_of_bits
);
72 printf("# Avg_llc_perf_miss: %lu\n", avg_llc_perf_miss
);
73 printf("# Allocated cache lines: %lu\n", allocated_cache_lines
);
76 static int check_results(struct resctrl_val_param
*param
)
78 char *token_array
[8], temp
[512];
79 unsigned long sum_llc_perf_miss
= 0;
80 int runs
= 0, no_of_bits
= 0;
83 printf("# Checking for pass/fail\n");
84 fp
= fopen(param
->filename
, "r");
86 perror("# Cannot open file");
91 while (fgets(temp
, sizeof(temp
), fp
)) {
92 char *token
= strtok(temp
, ":\t");
96 token_array
[fields
++] = token
;
97 token
= strtok(NULL
, ":\t");
100 * Discard the first value which is inaccurate due to monitoring
101 * setup transition phase.
104 sum_llc_perf_miss
+= strtoul(token_array
[3], NULL
, 0);
109 no_of_bits
= count_bits(param
->mask
);
111 show_cache_info(sum_llc_perf_miss
, no_of_bits
, param
->span
);
116 void cat_test_cleanup(void)
118 remove(RESULT_FILE_NAME1
);
119 remove(RESULT_FILE_NAME2
);
122 int cat_perf_miss_val(int cpu_no
, int n
, char *cache_type
)
124 unsigned long l_mask
, l_mask_1
;
125 int ret
, pipefd
[2], sibling_cpu_no
;
131 ret
= remount_resctrlfs(true);
135 if (!validate_resctrl_feature_request("cat"))
138 /* Get default cbm mask for L3/L2 cache */
139 ret
= get_cbm_mask(cache_type
);
143 long_mask
= strtoul(cbm_mask
, NULL
, 16);
145 /* Get L3/L2 cache size */
146 ret
= get_cache_size(cpu_no
, cache_type
, &cache_size
);
149 printf("cache size :%lu\n", cache_size
);
151 /* Get max number of bits from default-cabm mask */
152 count_of_bits
= count_bits(long_mask
);
154 if (n
< 1 || n
> count_of_bits
- 1) {
155 printf("Invalid input value for no_of_bits n!\n");
156 printf("Please Enter value in range 1 to %d\n",
161 /* Get core id from same socket for running another thread */
162 sibling_cpu_no
= get_core_sibling(cpu_no
);
163 if (sibling_cpu_no
< 0)
166 struct resctrl_val_param param
= {
167 .resctrl_val
= "cat",
173 l_mask
= long_mask
>> n
;
174 l_mask_1
= ~l_mask
& long_mask
;
176 /* Set param values for parent thread which will be allocated bitmask
177 * with (max_bits - n) bits
179 param
.span
= cache_size
* (count_of_bits
- n
) / count_of_bits
;
180 strcpy(param
.ctrlgrp
, "c2");
181 strcpy(param
.mongrp
, "m2");
182 strcpy(param
.filename
, RESULT_FILE_NAME2
);
184 param
.num_of_runs
= 0;
187 perror("# Unable to create pipe");
193 /* Set param values for child thread which will be allocated bitmask
197 param
.mask
= l_mask_1
;
198 strcpy(param
.ctrlgrp
, "c1");
199 strcpy(param
.mongrp
, "m1");
200 param
.span
= cache_size
* n
/ count_of_bits
;
201 strcpy(param
.filename
, RESULT_FILE_NAME1
);
202 param
.num_of_runs
= 0;
203 param
.cpu_no
= sibling_cpu_no
;
206 remove(param
.filename
);
208 ret
= cat_val(¶m
);
212 ret
= check_results(¶m
);
217 /* Tell parent that child is ready */
220 if (write(pipefd
[1], &pipe_message
, sizeof(pipe_message
)) <
221 sizeof(pipe_message
)) {
223 perror("# failed signaling parent process");
231 /* Parent waits for child to be ready. */
234 while (pipe_message
!= 1) {
235 if (read(pipefd
[0], &pipe_message
,
236 sizeof(pipe_message
)) < sizeof(pipe_message
)) {
237 perror("# failed reading from child process");
242 kill(bm_pid
, SIGKILL
);