229 lines · 4.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Cache Allocation Technology (CAT) 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_NAME1	"result_cat1"#define RESULT_FILE_NAME2	"result_cat2"#define NUM_OF_RUNS		5#define MAX_DIFF_PERCENT	4#define MAX_DIFF		1000000 static int count_of_bits;static char cbm_mask[256];static unsigned long long_mask;static unsigned long cache_size; /* * Change schemata. Write schemata to specified * con_mon grp, mon_grp in resctrl FS. * Run 5 times in order to get average values. */static int cat_setup(int num, ...){	struct resctrl_val_param *p;	char schemata[64];	va_list param;	int ret = 0; 	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; 	if (p->num_of_runs == 0) {		sprintf(schemata, "%lx", p->mask);		ret = write_schemata(p->ctrlgrp, schemata, p->cpu_no,				     p->resctrl_val);	}	p->num_of_runs++; 	return ret;} static int check_results(struct resctrl_val_param *param){	char *token_array[8], temp[512];	unsigned long sum_llc_perf_miss = 0;	int runs = 0, no_of_bits = 0;	FILE *fp; 	ksft_print_msg("Checking for pass/fail\n");	fp = fopen(param->filename, "r");	if (!fp) {		perror("# Cannot open file"); 		return errno;	} 	while (fgets(temp, sizeof(temp), fp)) {		char *token = strtok(temp, ":\t");		int fields = 0; 		while (token) {			token_array[fields++] = token;			token = strtok(NULL, ":\t");		}		/*		 * Discard the first value which is inaccurate due to monitoring		 * setup transition phase.		 */		if (runs > 0)			sum_llc_perf_miss += strtoul(token_array[3], NULL, 0);		runs++;	} 	fclose(fp);	no_of_bits = count_bits(param->mask); 	return show_cache_info(sum_llc_perf_miss, no_of_bits, param->span / 64,			       MAX_DIFF, MAX_DIFF_PERCENT, NUM_OF_RUNS,			       !is_amd, false);} void cat_test_cleanup(void){	remove(RESULT_FILE_NAME1);	remove(RESULT_FILE_NAME2);} int cat_perf_miss_val(int cpu_no, int n, char *cache_type){	unsigned long l_mask, l_mask_1;	int ret, pipefd[2], sibling_cpu_no;	char pipe_message;	pid_t bm_pid; 	cache_size = 0; 	ret = remount_resctrlfs(true);	if (ret)		return ret; 	/* Get default cbm mask for L3/L2 cache */	ret = get_cbm_mask(cache_type, cbm_mask);	if (ret)		return ret; 	long_mask = strtoul(cbm_mask, NULL, 16); 	/* Get L3/L2 cache size */	ret = get_cache_size(cpu_no, cache_type, &cache_size);	if (ret)		return ret;	ksft_print_msg("Cache size :%lu\n", cache_size); 	/* Get max number of bits from default-cabm mask */	count_of_bits = count_bits(long_mask); 	if (!n)		n = count_of_bits / 2; 	if (n > count_of_bits - 1) {		ksft_print_msg("Invalid input value for no_of_bits n!\n");		ksft_print_msg("Please enter value in range 1 to %d\n",			       count_of_bits - 1);		return -1;	} 	/* Get core id from same socket for running another thread */	sibling_cpu_no = get_core_sibling(cpu_no);	if (sibling_cpu_no < 0)		return -1; 	struct resctrl_val_param param = {		.resctrl_val	= CAT_STR,		.cpu_no		= cpu_no,		.mum_resctrlfs	= 0,		.setup		= cat_setup,	}; 	l_mask = long_mask >> n;	l_mask_1 = ~l_mask & long_mask; 	/* Set param values for parent thread which will be allocated bitmask	 * with (max_bits - n) bits	 */	param.span = cache_size * (count_of_bits - n) / count_of_bits;	strcpy(param.ctrlgrp, "c2");	strcpy(param.mongrp, "m2");	strcpy(param.filename, RESULT_FILE_NAME2);	param.mask = l_mask;	param.num_of_runs = 0; 	if (pipe(pipefd)) {		perror("# Unable to create pipe");		return errno;	} 	bm_pid = fork(); 	/* Set param values for child thread which will be allocated bitmask	 * with n bits	 */	if (bm_pid == 0) {		param.mask = l_mask_1;		strcpy(param.ctrlgrp, "c1");		strcpy(param.mongrp, "m1");		param.span = cache_size * n / count_of_bits;		strcpy(param.filename, RESULT_FILE_NAME1);		param.num_of_runs = 0;		param.cpu_no = sibling_cpu_no;	} 	remove(param.filename); 	ret = cat_val(&param);	if (ret)		return ret; 	ret = check_results(&param);	if (ret)		return ret; 	if (bm_pid == 0) {		/* Tell parent that child is ready */		close(pipefd[0]);		pipe_message = 1;		if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) <		    sizeof(pipe_message)) {			close(pipefd[1]);			perror("# failed signaling parent process");			return errno;		} 		close(pipefd[1]);		while (1)			;	} else {		/* Parent waits for child to be ready. */		close(pipefd[1]);		pipe_message = 0;		while (pipe_message != 1) {			if (read(pipefd[0], &pipe_message,				 sizeof(pipe_message)) < sizeof(pipe_message)) {				perror("# failed reading from child process");				break;			}		}		close(pipefd[0]);		kill(bm_pid, SIGKILL);	} 	cat_test_cleanup();	if (bm_pid)		umount_resctrlfs(); 	return 0;}