linux-stable/tools/testing/selftests/resctrl/cmt_test.c

182 lines
4.3 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Cache Monitoring Technology (CMT) test
*
* Copyright (C) 2018 Intel Corporation
*
* Authors:
* Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
* Fenghua Yu <fenghua.yu@intel.com>
*/
#include "resctrl.h"
#include <unistd.h>
#define RESULT_FILE_NAME "result_cmt"
#define NUM_OF_RUNS 5
#define MAX_DIFF 2000000
#define MAX_DIFF_PERCENT 15
static int cmt_setup(const struct resctrl_test *test,
const struct user_params *uparams,
struct resctrl_val_param *p)
{
/* Run NUM_OF_RUNS times */
if (p->num_of_runs >= NUM_OF_RUNS)
return END_OF_TESTS;
p->num_of_runs++;
return 0;
}
static int show_results_info(unsigned long sum_llc_val, int no_of_bits,
unsigned long cache_span, unsigned long max_diff,
unsigned long max_diff_percent, unsigned long num_of_runs,
bool platform)
{
unsigned long avg_llc_val = 0;
float diff_percent;
long avg_diff = 0;
int ret;
avg_llc_val = sum_llc_val / num_of_runs;
avg_diff = (long)abs(cache_span - avg_llc_val);
diff_percent = ((float)cache_span - avg_llc_val) / cache_span * 100;
ret = platform && abs((int)diff_percent) > max_diff_percent &&
abs(avg_diff) > max_diff;
ksft_print_msg("%s Check cache miss rate within %lu%%\n",
ret ? "Fail:" : "Pass:", max_diff_percent);
ksft_print_msg("Percent diff=%d\n", abs((int)diff_percent));
show_cache_info(no_of_bits, avg_llc_val, cache_span, false);
return ret;
}
static int check_results(struct resctrl_val_param *param, size_t span, int no_of_bits)
{
char *token_array[8], temp[512];
unsigned long sum_llc_occu_resc = 0;
int runs = 0;
FILE *fp;
ksft_print_msg("Checking for pass/fail\n");
fp = fopen(param->filename, "r");
if (!fp) {
ksft_perror("Error in opening file");
return -1;
}
selftests/resctrl: Enable gcc checks to detect buffer overflows David reported a buffer overflow error in the check_results() function of the cmt unit test and he suggested enabling _FORTIFY_SOURCE gcc compiler option to automatically detect any such errors. Feature Test Macros man page describes_FORTIFY_SOURCE as below "Defining this macro causes some lightweight checks to be performed to detect some buffer overflow errors when employing various string and memory manipulation functions (for example, memcpy, memset, stpcpy, strcpy, strncpy, strcat, strncat, sprintf, snprintf, vsprintf, vsnprintf, gets, and wide character variants thereof). For some functions, argument consistency is checked; for example, a check is made that open has been supplied with a mode argument when the specified flags include O_CREAT. Not all problems are detected, just some common cases. If _FORTIFY_SOURCE is set to 1, with compiler optimization level 1 (gcc -O1) and above, checks that shouldn't change the behavior of conforming programs are performed. With _FORTIFY_SOURCE set to 2, some more checking is added, but some conforming programs might fail. Some of the checks can be performed at compile time (via macros logic implemented in header files), and result in compiler warnings; other checks take place at run time, and result in a run-time error if the check fails. Use of this macro requires compiler support, available with gcc since version 4.0." Fix the buffer overflow error in the check_results() function of the cmt unit test and enable _FORTIFY_SOURCE gcc check to catch any future buffer overflow errors. Reported-by: David Binderman <dcb314@hotmail.com> Suggested-by: David Binderman <dcb314@hotmail.com> Tested-by: Babu Moger <babu.moger@amd.com> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2021-03-17 02:22:35 +00:00
while (fgets(temp, sizeof(temp), fp)) {
char *token = strtok(temp, ":\t");
int fields = 0;
while (token) {
token_array[fields++] = token;
token = strtok(NULL, ":\t");
}
/* Field 3 is llc occ resc value */
if (runs > 0)
sum_llc_occu_resc += strtoul(token_array[3], NULL, 0);
runs++;
}
fclose(fp);
return show_results_info(sum_llc_occu_resc, no_of_bits, span,
MAX_DIFF, MAX_DIFF_PERCENT, runs - 1, true);
}
void cmt_test_cleanup(void)
{
remove(RESULT_FILE_NAME);
}
static int cmt_run_test(const struct resctrl_test *test, const struct user_params *uparams)
{
const char * const *cmd = uparams->benchmark_cmd;
const char *new_cmd[BENCHMARK_ARGS];
unsigned long cache_total_size = 0;
int n = uparams->bits ? : 5;
unsigned long long_mask;
char *span_str = NULL;
int count_of_bits;
size_t span;
int ret, i;
ret = get_full_cbm("L3", &long_mask);
if (ret)
return ret;
ret = get_cache_size(uparams->cpu, "L3", &cache_total_size);
if (ret)
return ret;
ksft_print_msg("Cache size :%lu\n", cache_total_size);
count_of_bits = count_bits(long_mask);
if (n < 1 || n > count_of_bits) {
ksft_print_msg("Invalid input value for numbr_of_bits n!\n");
ksft_print_msg("Please enter value in range 1 to %d\n", count_of_bits);
return -1;
}
struct resctrl_val_param param = {
.resctrl_val = CMT_STR,
.ctrlgrp = "c1",
.mongrp = "m1",
.filename = RESULT_FILE_NAME,
.mask = ~(long_mask << n) & long_mask,
.num_of_runs = 0,
.setup = cmt_setup,
};
span = cache_portion_size(cache_total_size, param.mask, long_mask);
if (strcmp(cmd[0], "fill_buf") == 0) {
/* Duplicate the command to be able to replace span in it */
for (i = 0; uparams->benchmark_cmd[i]; i++)
new_cmd[i] = uparams->benchmark_cmd[i];
new_cmd[i] = NULL;
ret = asprintf(&span_str, "%zu", span);
if (ret < 0)
return -1;
new_cmd[1] = span_str;
cmd = new_cmd;
}
remove(RESULT_FILE_NAME);
ret = resctrl_val(test, uparams, cmd, &param);
if (ret)
goto out;
ret = check_results(&param, span, n);
if (ret && (get_vendor() == ARCH_INTEL))
ksft_print_msg("Intel CMT may be inaccurate when Sub-NUMA Clustering is enabled. Check BIOS configuration.\n");
out:
cmt_test_cleanup();
free(span_str);
return ret;
}
static bool cmt_feature_check(const struct resctrl_test *test)
{
return test_resource_feature_check(test) &&
resctrl_mon_feature_exists("L3_MON", "llc_occupancy");
}
struct resctrl_test cmt_test = {
.name = "CMT",
.resource = "L3",
.feature_check = cmt_feature_check,
.run_test = cmt_run_test,
};