Skip to content

Commit

Permalink
selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest
Browse files Browse the repository at this point in the history
Cache QoS Monitoring (CQM) selftest starts stressful cache benchmark
with specified size of memory to access the cache. Last Level cache
occupancy reported by CQM should be close to the size of the memory.

Co-developed-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Co-developed-by: Babu Moger <babu.moger@amd.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
  • Loading branch information
Fenghua Yu authored and Shuah Khan committed Feb 11, 2020
1 parent 01fee6b commit 7894118
Show file tree
Hide file tree
Showing 6 changed files with 558 additions and 20 deletions.
99 changes: 99 additions & 0 deletions tools/testing/selftests/resctrl/cache.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// SPDX-License-Identifier: GPL-2.0

#include <stdint.h>
#include "resctrl.h"

struct read_format {
__u64 nr; /* The number of events */
struct {
__u64 value; /* The value of the event */
} values[2];
};

char llc_occup_path[1024];

/*
* Get LLC Occupancy as reported by RESCTRL FS
* For CQM,
* 1. If con_mon grp and mon grp given, then read from mon grp in
* con_mon grp
* 2. If only con_mon grp given, then read from con_mon grp
* 3. If both not given, then read from root con_mon grp
* For CAT,
* 1. If con_mon grp given, then read from it
* 2. If con_mon grp not given, then read from root con_mon grp
*
* Return: =0 on success. <0 on failure.
*/
static int get_llc_occu_resctrl(unsigned long *llc_occupancy)
{
FILE *fp;

fp = fopen(llc_occup_path, "r");
if (!fp) {
perror("Failed to open results file");

return errno;
}
if (fscanf(fp, "%lu", llc_occupancy) <= 0) {
perror("Could not get llc occupancy");
fclose(fp);

return -1;
}
fclose(fp);

return 0;
}

/*
* print_results_cache: the cache results are stored in a file
* @filename: file that stores the results
* @bm_pid: child pid that runs benchmark
* @llc_value: perf miss value /
* llc occupancy value reported by resctrl FS
*
* Return: 0 on success. non-zero on failure.
*/
static int print_results_cache(char *filename, int bm_pid,
unsigned long llc_value)
{
FILE *fp;

if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) {
printf("Pid: %d \t LLC_value: %lu\n", bm_pid,
llc_value);
} else {
fp = fopen(filename, "a");
if (!fp) {
perror("Cannot open results file");

return errno;
}
fprintf(fp, "Pid: %d \t llc_value: %lu\n", bm_pid, llc_value);
fclose(fp);
}

return 0;
}

int measure_cache_vals(struct resctrl_val_param *param, int bm_pid)
{
unsigned long llc_occu_resc = 0, llc_value = 0;
int ret;

/*
* Measure llc occupancy from resctrl.
*/
if (!strcmp(param->resctrl_val, "cqm")) {
ret = get_llc_occu_resctrl(&llc_occu_resc);
if (ret < 0)
return ret;
llc_value = llc_occu_resc;
}
ret = print_results_cache(param->filename, bm_pid, llc_value);
if (ret)
return ret;

return 0;
}
176 changes: 176 additions & 0 deletions tools/testing/selftests/resctrl/cqm_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Cache Monitoring Technology (CQM) 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_cqm"
#define NUM_OF_RUNS 5
#define MAX_DIFF 2000000
#define MAX_DIFF_PERCENT 15

int count_of_bits;
char cbm_mask[256];
unsigned long long_mask;
unsigned long cache_size;

static int cqm_setup(int num, ...)
{
struct resctrl_val_param *p;
va_list param;

va_start(param, num);
p = va_arg(param, struct resctrl_val_param *);
va_end(param);

/* Run NUM_OF_RUNS times */
if (p->num_of_runs >= NUM_OF_RUNS)
return -1;

p->num_of_runs++;

return 0;
}

static void show_cache_info(unsigned long sum_llc_occu_resc, int no_of_bits,
unsigned long span)
{
unsigned long avg_llc_occu_resc = 0;
float diff_percent;
long avg_diff = 0;
bool res;

avg_llc_occu_resc = sum_llc_occu_resc / (NUM_OF_RUNS - 1);
avg_diff = (long)abs(span - avg_llc_occu_resc);

diff_percent = (((float)span - avg_llc_occu_resc) / span) * 100;

if ((abs((int)diff_percent) <= MAX_DIFF_PERCENT) ||
(abs(avg_diff) <= MAX_DIFF))
res = true;
else
res = false;

printf("%sok CQM: diff within %d, %d\%%\n", res ? "" : "not",
MAX_DIFF, (int)MAX_DIFF_PERCENT);

printf("# diff: %ld\n", avg_diff);
printf("# percent diff=%d\n", abs((int)diff_percent));
printf("# Results are displayed in (Bytes)\n");
printf("# Number of bits: %d\n", no_of_bits);
printf("# Avg_llc_occu_resc: %lu\n", avg_llc_occu_resc);
printf("# llc_occu_exp (span): %lu\n", span);

tests_run++;
}

static int check_results(struct resctrl_val_param *param, int no_of_bits)
{
char *token_array[8], temp[512];
unsigned long sum_llc_occu_resc = 0;
int runs = 0;
FILE *fp;

printf("# checking for pass/fail\n");
fp = fopen(param->filename, "r");
if (!fp) {
perror("# Error in opening file\n");

return errno;
}

while (fgets(temp, 1024, 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);
show_cache_info(sum_llc_occu_resc, no_of_bits, param->span);

return 0;
}

void cqm_test_cleanup(void)
{
remove(RESULT_FILE_NAME);
}

int cqm_resctrl_val(int cpu_no, int n, char **benchmark_cmd)
{
int ret, mum_resctrlfs;

cache_size = 0;
mum_resctrlfs = 1;

ret = remount_resctrlfs(mum_resctrlfs);
if (ret)
return ret;

if (!validate_resctrl_feature_request("cqm"))
return -1;

ret = get_cbm_mask("L3");
if (ret)
return ret;

long_mask = strtoul(cbm_mask, NULL, 16);

ret = get_cache_size(cpu_no, "L3", &cache_size);
if (ret)
return ret;
printf("cache size :%lu\n", cache_size);

count_of_bits = count_bits(long_mask);

if (n < 1 || n > count_of_bits) {
printf("Invalid input value for numbr_of_bits n!\n");
printf("Please Enter value in range 1 to %d\n", count_of_bits);
return -1;
}

struct resctrl_val_param param = {
.resctrl_val = "cqm",
.ctrlgrp = "c1",
.mongrp = "m1",
.cpu_no = cpu_no,
.mum_resctrlfs = 0,
.filename = RESULT_FILE_NAME,
.mask = ~(long_mask << n) & long_mask,
.span = cache_size * n / count_of_bits,
.num_of_runs = 0,
.setup = cqm_setup,
};

if (strcmp(benchmark_cmd[0], "fill_buf") == 0)
sprintf(benchmark_cmd[1], "%lu", param.span);

remove(RESULT_FILE_NAME);

ret = resctrl_val(benchmark_cmd, &param);
if (ret)
return ret;

ret = check_results(&param, n);
if (ret)
return ret;

cqm_test_cleanup();

return 0;
}
16 changes: 16 additions & 0 deletions tools/testing/selftests/resctrl/resctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/eventfd.h>
#include <asm/unistd.h>
#include <linux/perf_event.h>

#define MB (1024 * 1024)
#define RESCTRL_PATH "/sys/fs/resctrl"
#define PHYS_ID_PATH "/sys/devices/system/cpu/cpu"
#define CBM_MASK_PATH "/sys/fs/resctrl/info"

#define PARENT_EXIT(err_msg) \
do { \
Expand Down Expand Up @@ -53,12 +57,16 @@ struct resctrl_val_param {
int mum_resctrlfs;
char filename[64];
char *bw_report;
unsigned long mask;
int num_of_runs;
int (*setup)(int num, ...);
};

pid_t bm_pid, ppid;
int tests_run;

char llc_occup_path[1024];

bool check_resctrlfs_support(void);
int filter_dmesg(void);
int remount_resctrlfs(bool mum_resctrlfs);
Expand All @@ -83,5 +91,13 @@ void tests_cleanup(void);
void mbm_test_cleanup(void);
int mba_schemata_change(int cpu_no, char *bw_report, char **benchmark_cmd);
void mba_test_cleanup(void);
int get_cbm_mask(char *cache_type);
int get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size);
void ctrlc_handler(int signum, siginfo_t *info, void *ptr);
int cqm_resctrl_val(int cpu_no, int n, char **benchmark_cmd);
unsigned int count_bits(unsigned long n);
void cqm_test_cleanup(void);
int get_core_sibling(int cpu_no);
int measure_cache_vals(struct resctrl_val_param *param, int bm_pid);

#endif /* RESCTRL_H */
Loading

0 comments on commit 7894118

Please sign in to comment.