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 static int cmt_setup(struct resctrl_val_param *p)
20 {
21 	/* Run NUM_OF_RUNS times */
22 	if (p->num_of_runs >= NUM_OF_RUNS)
23 		return END_OF_TESTS;
24 
25 	p->num_of_runs++;
26 
27 	return 0;
28 }
29 
30 static int check_results(struct resctrl_val_param *param, size_t span, int no_of_bits)
31 {
32 	char *token_array[8], temp[512];
33 	unsigned long sum_llc_occu_resc = 0;
34 	int runs = 0;
35 	FILE *fp;
36 
37 	ksft_print_msg("Checking for pass/fail\n");
38 	fp = fopen(param->filename, "r");
39 	if (!fp) {
40 		ksft_perror("Error in opening file");
41 
42 		return errno;
43 	}
44 
45 	while (fgets(temp, sizeof(temp), fp)) {
46 		char *token = strtok(temp, ":\t");
47 		int fields = 0;
48 
49 		while (token) {
50 			token_array[fields++] = token;
51 			token = strtok(NULL, ":\t");
52 		}
53 
54 		/* Field 3 is llc occ resc value */
55 		if (runs > 0)
56 			sum_llc_occu_resc += strtoul(token_array[3], NULL, 0);
57 		runs++;
58 	}
59 	fclose(fp);
60 
61 	return show_cache_info(sum_llc_occu_resc, no_of_bits, span,
62 			       MAX_DIFF, MAX_DIFF_PERCENT, runs - 1,
63 			       true, true);
64 }
65 
66 void cmt_test_cleanup(void)
67 {
68 	remove(RESULT_FILE_NAME);
69 }
70 
71 int cmt_resctrl_val(int cpu_no, int n, const char * const *benchmark_cmd)
72 {
73 	const char * const *cmd = benchmark_cmd;
74 	const char *new_cmd[BENCHMARK_ARGS];
75 	unsigned long cache_size = 0;
76 	unsigned long long_mask;
77 	char *span_str = NULL;
78 	char cbm_mask[256];
79 	int count_of_bits;
80 	size_t span;
81 	int ret, i;
82 
83 	ret = get_cbm_mask("L3", cbm_mask);
84 	if (ret)
85 		return ret;
86 
87 	long_mask = strtoul(cbm_mask, NULL, 16);
88 
89 	ret = get_cache_size(cpu_no, "L3", &cache_size);
90 	if (ret)
91 		return ret;
92 	ksft_print_msg("Cache size :%lu\n", cache_size);
93 
94 	count_of_bits = count_bits(long_mask);
95 
96 	if (n < 1 || n > count_of_bits) {
97 		ksft_print_msg("Invalid input value for numbr_of_bits n!\n");
98 		ksft_print_msg("Please enter value in range 1 to %d\n", count_of_bits);
99 		return -1;
100 	}
101 
102 	struct resctrl_val_param param = {
103 		.resctrl_val	= CMT_STR,
104 		.ctrlgrp	= "c1",
105 		.mongrp		= "m1",
106 		.cpu_no		= cpu_no,
107 		.filename	= RESULT_FILE_NAME,
108 		.mask		= ~(long_mask << n) & long_mask,
109 		.num_of_runs	= 0,
110 		.setup		= cmt_setup,
111 	};
112 
113 	span = cache_size * n / count_of_bits;
114 
115 	if (strcmp(cmd[0], "fill_buf") == 0) {
116 		/* Duplicate the command to be able to replace span in it */
117 		for (i = 0; benchmark_cmd[i]; i++)
118 			new_cmd[i] = benchmark_cmd[i];
119 		new_cmd[i] = NULL;
120 
121 		ret = asprintf(&span_str, "%zu", span);
122 		if (ret < 0)
123 			return -1;
124 		new_cmd[1] = span_str;
125 		cmd = new_cmd;
126 	}
127 
128 	remove(RESULT_FILE_NAME);
129 
130 	ret = resctrl_val(cmd, &param);
131 	if (ret)
132 		goto out;
133 
134 	ret = check_results(&param, span, n);
135 
136 out:
137 	cmt_test_cleanup();
138 	free(span_str);
139 
140 	return ret;
141 }
142