1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Cache Monitoring Technology (CQM) 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_cqm"
15#define NUM_OF_RUNS		5
16#define MAX_DIFF		2000000
17#define MAX_DIFF_PERCENT	15
18
19static int count_of_bits;
20static char cbm_mask[256];
21static unsigned long long_mask;
22static unsigned long cache_size;
23
24static int cqm_setup(int num, ...)
25{
26	struct resctrl_val_param *p;
27	va_list param;
28
29	va_start(param, num);
30	p = va_arg(param, struct resctrl_val_param *);
31	va_end(param);
32
33	/* Run NUM_OF_RUNS times */
34	if (p->num_of_runs >= NUM_OF_RUNS)
35		return -1;
36
37	p->num_of_runs++;
38
39	return 0;
40}
41
42static void show_cache_info(unsigned long sum_llc_occu_resc, int no_of_bits,
43			    unsigned long span)
44{
45	unsigned long avg_llc_occu_resc = 0;
46	float diff_percent;
47	long avg_diff = 0;
48	bool res;
49
50	avg_llc_occu_resc = sum_llc_occu_resc / (NUM_OF_RUNS - 1);
51	avg_diff = (long)abs(span - avg_llc_occu_resc);
52
53	diff_percent = (((float)span - avg_llc_occu_resc) / span) * 100;
54
55	if ((abs((int)diff_percent) <= MAX_DIFF_PERCENT) ||
56	    (abs(avg_diff) <= MAX_DIFF))
57		res = true;
58	else
59		res = false;
60
61	printf("%sok CQM: diff within %d, %d\%%\n", res ? "" : "not",
62	       MAX_DIFF, (int)MAX_DIFF_PERCENT);
63
64	printf("# diff: %ld\n", avg_diff);
65	printf("# percent diff=%d\n", abs((int)diff_percent));
66	printf("# Results are displayed in (Bytes)\n");
67	printf("# Number of bits: %d\n", no_of_bits);
68	printf("# Avg_llc_occu_resc: %lu\n", avg_llc_occu_resc);
69	printf("# llc_occu_exp (span): %lu\n", span);
70
71	tests_run++;
72}
73
74static int check_results(struct resctrl_val_param *param, int no_of_bits)
75{
76	char *token_array[8], temp[512];
77	unsigned long sum_llc_occu_resc = 0;
78	int runs = 0;
79	FILE *fp;
80
81	printf("# checking for pass/fail\n");
82	fp = fopen(param->filename, "r");
83	if (!fp) {
84		perror("# Error in opening file\n");
85
86		return errno;
87	}
88
89	while (fgets(temp, sizeof(temp), fp)) {
90		char *token = strtok(temp, ":\t");
91		int fields = 0;
92
93		while (token) {
94			token_array[fields++] = token;
95			token = strtok(NULL, ":\t");
96		}
97
98		/* Field 3 is llc occ resc value */
99		if (runs > 0)
100			sum_llc_occu_resc += strtoul(token_array[3], NULL, 0);
101		runs++;
102	}
103	fclose(fp);
104	show_cache_info(sum_llc_occu_resc, no_of_bits, param->span);
105
106	return 0;
107}
108
109void cqm_test_cleanup(void)
110{
111	remove(RESULT_FILE_NAME);
112}
113
114int cqm_resctrl_val(int cpu_no, int n, char **benchmark_cmd)
115{
116	int ret, mum_resctrlfs;
117
118	cache_size = 0;
119	mum_resctrlfs = 1;
120
121	ret = remount_resctrlfs(mum_resctrlfs);
122	if (ret)
123		return ret;
124
125	if (!validate_resctrl_feature_request("cqm"))
126		return -1;
127
128	ret = get_cbm_mask("L3", cbm_mask);
129	if (ret)
130		return ret;
131
132	long_mask = strtoul(cbm_mask, NULL, 16);
133
134	ret = get_cache_size(cpu_no, "L3", &cache_size);
135	if (ret)
136		return ret;
137	printf("cache size :%lu\n", cache_size);
138
139	count_of_bits = count_bits(long_mask);
140
141	if (n < 1 || n > count_of_bits) {
142		printf("Invalid input value for numbr_of_bits n!\n");
143		printf("Please Enter value in range 1 to %d\n", count_of_bits);
144		return -1;
145	}
146
147	struct resctrl_val_param param = {
148		.resctrl_val	= CQM_STR,
149		.ctrlgrp	= "c1",
150		.mongrp		= "m1",
151		.cpu_no		= cpu_no,
152		.mum_resctrlfs	= 0,
153		.filename	= RESULT_FILE_NAME,
154		.mask		= ~(long_mask << n) & long_mask,
155		.span		= cache_size * n / count_of_bits,
156		.num_of_runs	= 0,
157		.setup		= cqm_setup,
158	};
159
160	if (strcmp(benchmark_cmd[0], "fill_buf") == 0)
161		sprintf(benchmark_cmd[1], "%lu", param.span);
162
163	remove(RESULT_FILE_NAME);
164
165	ret = resctrl_val(benchmark_cmd, &param);
166	if (ret)
167		return ret;
168
169	ret = check_results(&param, n);
170	if (ret)
171		return ret;
172
173	cqm_test_cleanup();
174
175	return 0;
176}
177