1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Memory Bandwidth Monitoring (MBM) 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 | |
13 | #define RESULT_FILE_NAME "result_mbm" |
14 | #define MAX_DIFF_PERCENT 8 |
15 | #define NUM_OF_RUNS 5 |
16 | |
17 | static int |
18 | show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, size_t span) |
19 | { |
20 | unsigned long avg_bw_imc = 0, avg_bw_resc = 0; |
21 | unsigned long sum_bw_imc = 0, sum_bw_resc = 0; |
22 | int runs, ret, avg_diff_per; |
23 | float avg_diff = 0; |
24 | |
25 | /* |
26 | * Discard the first value which is inaccurate due to monitoring setup |
27 | * transition phase. |
28 | */ |
29 | for (runs = 1; runs < NUM_OF_RUNS ; runs++) { |
30 | sum_bw_imc += bw_imc[runs]; |
31 | sum_bw_resc += bw_resc[runs]; |
32 | } |
33 | |
34 | avg_bw_imc = sum_bw_imc / 4; |
35 | avg_bw_resc = sum_bw_resc / 4; |
36 | avg_diff = (float)labs(avg_bw_resc - avg_bw_imc) / avg_bw_imc; |
37 | avg_diff_per = (int)(avg_diff * 100); |
38 | |
39 | ret = avg_diff_per > MAX_DIFF_PERCENT; |
40 | ksft_print_msg(msg: "%s Check MBM diff within %d%%\n" , |
41 | ret ? "Fail:" : "Pass:" , MAX_DIFF_PERCENT); |
42 | ksft_print_msg(msg: "avg_diff_per: %d%%\n" , avg_diff_per); |
43 | ksft_print_msg(msg: "Span (MB): %zu\n" , span / MB); |
44 | ksft_print_msg(msg: "avg_bw_imc: %lu\n" , avg_bw_imc); |
45 | ksft_print_msg(msg: "avg_bw_resc: %lu\n" , avg_bw_resc); |
46 | |
47 | return ret; |
48 | } |
49 | |
50 | static int check_results(size_t span) |
51 | { |
52 | unsigned long bw_imc[NUM_OF_RUNS], bw_resc[NUM_OF_RUNS]; |
53 | char temp[1024], *token_array[8]; |
54 | char output[] = RESULT_FILE_NAME; |
55 | int runs, ret; |
56 | FILE *fp; |
57 | |
58 | ksft_print_msg(msg: "Checking for pass/fail\n" ); |
59 | |
60 | fp = fopen(output, "r" ); |
61 | if (!fp) { |
62 | ksft_perror(msg: output); |
63 | |
64 | return -1; |
65 | } |
66 | |
67 | runs = 0; |
68 | while (fgets(temp, sizeof(temp), fp)) { |
69 | char *token = strtok(temp, ":\t" ); |
70 | int i = 0; |
71 | |
72 | while (token) { |
73 | token_array[i++] = token; |
74 | token = strtok(NULL, ":\t" ); |
75 | } |
76 | |
77 | bw_resc[runs] = strtoul(token_array[5], NULL, 0); |
78 | bw_imc[runs] = strtoul(token_array[3], NULL, 0); |
79 | runs++; |
80 | } |
81 | |
82 | ret = show_bw_info(bw_imc, bw_resc, span); |
83 | |
84 | fclose(fp); |
85 | |
86 | return ret; |
87 | } |
88 | |
89 | static int mbm_setup(const struct resctrl_test *test, |
90 | const struct user_params *uparams, |
91 | struct resctrl_val_param *p) |
92 | { |
93 | int ret = 0; |
94 | |
95 | /* Run NUM_OF_RUNS times */ |
96 | if (p->num_of_runs >= NUM_OF_RUNS) |
97 | return END_OF_TESTS; |
98 | |
99 | /* Set up shemata with 100% allocation on the first run. */ |
100 | if (p->num_of_runs == 0 && resctrl_resource_exists(resource: "MB" )) |
101 | ret = write_schemata(ctrlgrp: p->ctrlgrp, schemata: "100" , cpu_no: uparams->cpu, resource: test->resource); |
102 | |
103 | p->num_of_runs++; |
104 | |
105 | return ret; |
106 | } |
107 | |
108 | void mbm_test_cleanup(void) |
109 | { |
110 | remove(RESULT_FILE_NAME); |
111 | } |
112 | |
113 | static int mbm_run_test(const struct resctrl_test *test, const struct user_params *uparams) |
114 | { |
115 | struct resctrl_val_param param = { |
116 | .resctrl_val = MBM_STR, |
117 | .ctrlgrp = "c1" , |
118 | .mongrp = "m1" , |
119 | .filename = RESULT_FILE_NAME, |
120 | .bw_report = "reads" , |
121 | .setup = mbm_setup |
122 | }; |
123 | int ret; |
124 | |
125 | remove(RESULT_FILE_NAME); |
126 | |
127 | ret = resctrl_val(test, uparams, benchmark_cmd: uparams->benchmark_cmd, param: ¶m); |
128 | if (ret) |
129 | goto out; |
130 | |
131 | ret = check_results(DEFAULT_SPAN); |
132 | if (ret && (get_vendor() == ARCH_INTEL)) |
133 | ksft_print_msg(msg: "Intel MBM may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n" ); |
134 | |
135 | out: |
136 | mbm_test_cleanup(); |
137 | |
138 | return ret; |
139 | } |
140 | |
141 | static bool mbm_feature_check(const struct resctrl_test *test) |
142 | { |
143 | return resctrl_mon_feature_exists(resource: "L3_MON" , feature: "mbm_total_bytes" ) && |
144 | resctrl_mon_feature_exists(resource: "L3_MON" , feature: "mbm_local_bytes" ); |
145 | } |
146 | |
147 | struct resctrl_test mbm_test = { |
148 | .name = "MBM" , |
149 | .resource = "MB" , |
150 | .vendor_specific = ARCH_INTEL, |
151 | .feature_check = mbm_feature_check, |
152 | .run_test = mbm_run_test, |
153 | }; |
154 | |