LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
@ 2019-02-10  2:50 Fenghua Yu
  2019-02-10  2:50 ` [PATCH v7 01/13] selftests/resctrl: Add README for resctrl tests Fenghua Yu
                   ` (15 more replies)
  0 siblings, 16 replies; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

With more and more resctrl features are being added by Intel, AMD
and ARM, a test tool is becoming more and more useful to validate
that both hardware and software functionalities work as expected.

We introduce resctrl selftest to cover resctrl features on both
X86 and ARM architectures. It first implements MBM (Memory Bandwidth
Monitoring), MBA (Memory Bandwidth Allocation), L3 CAT (Cache Allocation
Technology), and CQM (Cache QoS Monitoring)  tests. We can enhance
the selftest tool to include more functionality tests in future.

The tool has been tested on both Intel RDT and AMD QoS.

There is an existing resctrl test suite 'intel_cmt_cat'. But the major
purpose of the tool is to test Intel(R) RDT hardware via writing and
reading MSR registers. It does access resctrl file system; but the
functionalities are very limited. And it doesn't support automatic test
and a lot of manual verifications are involved.

So the selftest tool we are introducing here provides a convenient
tool which does automatic resctrl testing, is easily available in kernel
tree, and will be extended to AMD QoS and ARM MPAM.

The selftest tool is in tools/testing/selftests/resctrl in order to have
generic test code for all architectures.

Changelog:
v7:
- Fix a few warnings when compiling patches separately, pointed by Babu 

v6:
- Fix a benchmark reading optimized out issue in newer GCC.
- Fix a few coding style issues.
- Re-arrange code among patches to make cleaner code. No change in patches
structure.

v5:
- Based the v4 patches submitted by Fenghua Yu and added changes to support
  AMD.
- Changed the function name get_sock_num to get_resource_id. Intel uses
  socket number for schemata and AMD uses l3 index id. To generalize,
  changed the function name to get_resource_id.
- Added the code to detect vendor.
- Disabled the few tests for AMD where the test results are not clear.
  Also AMD does not have IMC.
- Fixed few compile issues.
- Some cleanup to make each patch independent.
- Tested the patches on AMD system. Fenghua, Need your help to test on
  Intel box. Please feel free to change and resubmit if something
   broken.
- Here is the link for previous version.
  https://lore.kernel.org/lkml/1545438038-75107-1-git-send-email-fenghua.yu=
@intel.com/

v4:
- address comments from Balu and Randy
- Add CAT and CQM tests

v3:
- Change code based on comments from Babu Moger
- Remove some unnessary code and use pipe to communicate b/w processes

v2:
- Change code based on comments from Babu Moger
- Clean up other places.

Arshiya Hayatkhan Pathan (4):
  selftests/resctrl: Add MBM test
  selftests/resctrl: Add MBA test
  selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest
  selftests/resctrl: Add Cache Allocation Technology (CAT) selftest

Babu Moger (3):
  selftests/resctrl: Add vendor detection mechanism
  selftests/resctrl: Use cache index3 id for AMD schemata masks
  selftests/resctrl: Disable MBA and MBM tests for AMD

Fenghua Yu (2):
  selftests/resctrl: Add README for resctrl tests
  selftests/resctrl: Add the test in MAINTAINERS

Sai Praneeth Prakhya (4):
  selftests/resctrl: Add basic resctrl file system operations and data
  selftests/resctrl: Read memory bandwidth from perf IMC counter and
    from resctrl file system
  selftests/resctrl: Add callback to start a benchmark
  selftests/resctrl: Add built in benchmark

 MAINTAINERS                                     |   1 +
 tools/testing/selftests/resctrl/Makefile        |  16 +
 tools/testing/selftests/resctrl/README          |  54 ++
 tools/testing/selftests/resctrl/cache.c         | 274 +++++++++
 tools/testing/selftests/resctrl/cat_test.c      | 242 ++++++++
 tools/testing/selftests/resctrl/cqm_test.c      | 173 ++++++
 tools/testing/selftests/resctrl/fill_buf.c      | 210 +++++++
 tools/testing/selftests/resctrl/mba_test.c      | 178 ++++++
 tools/testing/selftests/resctrl/mbm_test.c      | 150 +++++
 tools/testing/selftests/resctrl/resctrl.h       | 117 ++++
 tools/testing/selftests/resctrl/resctrl_tests.c | 238 ++++++++
 tools/testing/selftests/resctrl/resctrl_val.c   | 723 ++++++++++++++++++++++++
 tools/testing/selftests/resctrl/resctrlfs.c     | 668 ++++++++++++++++++++++
 13 files changed, 3044 insertions(+)
 create mode 100644 tools/testing/selftests/resctrl/Makefile
 create mode 100644 tools/testing/selftests/resctrl/README
 create mode 100644 tools/testing/selftests/resctrl/cache.c
 create mode 100644 tools/testing/selftests/resctrl/cat_test.c
 create mode 100644 tools/testing/selftests/resctrl/cqm_test.c
 create mode 100644 tools/testing/selftests/resctrl/fill_buf.c
 create mode 100644 tools/testing/selftests/resctrl/mba_test.c
 create mode 100644 tools/testing/selftests/resctrl/mbm_test.c
 create mode 100644 tools/testing/selftests/resctrl/resctrl.h
 create mode 100644 tools/testing/selftests/resctrl/resctrl_tests.c
 create mode 100644 tools/testing/selftests/resctrl/resctrl_val.c
 create mode 100644 tools/testing/selftests/resctrl/resctrlfs.c

-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 01/13] selftests/resctrl: Add README for resctrl tests
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-02-10  2:50 ` [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data Fenghua Yu
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

resctrl tests will be implemented. README is added for the tool first.

Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/README | 54 ++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 tools/testing/selftests/resctrl/README

diff --git a/tools/testing/selftests/resctrl/README b/tools/testing/selftests/resctrl/README
new file mode 100644
index 000000000000..2bcd8739f1c6
--- /dev/null
+++ b/tools/testing/selftests/resctrl/README
@@ -0,0 +1,54 @@
+resctrl_tests - resctrl file system test suit
+
+Authors:
+	Fenghua Yu <fenghua.yu@intel.com>
+	Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
+	Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+
+resctrl_tests tests various resctrl functionalities and interfaces including
+both software and hardware.
+
+Currently it supports Memory Bandwidth Monitoring test and Memory Bandwidth
+Allocation test on Intel RDT hardware. More tests will be added in the future.
+And the test suit can be extended to cover AMD QoS and ARM MPAM hardware
+as well.
+
+BUILD
+-----
+
+Run "make" to build executable file "resctrl_tests".
+
+RUN
+---
+
+To use resctrl_tests, root or sudoer privileges are required. This is because
+the test needs to mount resctrl file system and change contents in the file
+system.
+
+Executing the test without any parameter will run all supported tests:
+
+	sudo ./resctrl_tests
+
+OVERVIEW OF EXECUTION
+---------------------
+
+A test case has four stages:
+
+  - setup: mount resctrl file system, create group, setup schemata, move test
+    process pids to tasks, start benchmark.
+  - execute: let benchmark run
+  - verify: get resctrl data and verify the data with another source, e.g.
+    perf event.
+  - teardown: umount resctrl and clear temporary files.
+
+ARGUMENTS
+---------
+
+Parameter '-h' shows usage information.
+
+usage: resctrl_tests [-h] [-b "benchmark_cmd [options]"] [-t test list] [-n no_of_bits]
+        -b benchmark_cmd [options]: run specified benchmark for MBM, MBA and CQM default benchmark is builtin fill_buf
+        -t test list: run tests specified in the test list, e.g. -t mbm, mba, cqm, cat
+        -n no_of_bits: run cache tests using specified no of bits in cache bit mask
+        -p cpu_no: specify CPU number to run the test. 1 is default
+        -h: help
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
  2019-02-10  2:50 ` [PATCH v7 01/13] selftests/resctrl: Add README for resctrl tests Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:36   ` Andre Przywara
  2019-05-10 17:41   ` Borislav Petkov
  2019-02-10  2:50 ` [PATCH v7 03/13] selftests/resctrl: Read memory bandwidth from perf IMC counter and from resctrl file system Fenghua Yu
                   ` (13 subsequent siblings)
  15 siblings, 2 replies; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>

The basic resctrl file system operations and data are added for future
usage by resctrl selftest tool.

Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/Makefile    |  10 +
 tools/testing/selftests/resctrl/resctrl.h   |  48 +++
 tools/testing/selftests/resctrl/resctrlfs.c | 464 ++++++++++++++++++++++++++++
 3 files changed, 522 insertions(+)
 create mode 100644 tools/testing/selftests/resctrl/Makefile
 create mode 100644 tools/testing/selftests/resctrl/resctrl.h
 create mode 100644 tools/testing/selftests/resctrl/resctrlfs.c

diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
new file mode 100644
index 000000000000..bd5c5418961e
--- /dev/null
+++ b/tools/testing/selftests/resctrl/Makefile
@@ -0,0 +1,10 @@
+CC = gcc
+CFLAGS = -g -Wall
+
+*.o: *.c
+	$(CC) $(CFLAGS) -c *.c
+
+.PHONY: clean
+
+clean:
+	$(RM) *.o *~
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
new file mode 100644
index 000000000000..2e112934d48a
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#define _GNU_SOURCE
+#ifndef RESCTRL_H
+#define RESCTRL_H
+#include <stdio.h>
+#include <errno.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <dirent.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <asm/unistd.h>
+#include <linux/perf_event.h>
+
+#define RESCTRL_PATH		"/sys/fs/resctrl"
+#define PHYS_ID_PATH		"/sys/devices/system/cpu/cpu"
+
+#define PARENT_EXIT(err_msg)			\
+	do {					\
+		perror(err_msg);		\
+		kill(ppid, SIGKILL);		\
+		exit(EXIT_FAILURE);		\
+	} while (0)
+
+pid_t bm_pid, ppid;
+
+int remount_resctrlfs(bool mum_resctrlfs);
+int get_resource_id(int cpu_no, int *resource_id);
+int validate_bw_report_request(char *bw_report);
+int validate_resctrl_feature_request(char *resctrl_val);
+int taskset_benchmark(pid_t bm_pid, int cpu_no);
+void run_benchmark(int signum, siginfo_t *info, void *ucontext);
+int write_schemata(char *ctrlgrp, char *schemata, int cpu_no,
+		   char *resctrl_val);
+int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
+			    char *resctrl_val);
+int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
+		    int group_fd, unsigned long flags);
+int run_fill_buf(unsigned long span, int malloc_and_init_memory, int memflush,
+		 int op, char *resctrl_va);
+
+#endif /* RESCTRL_H */
diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
new file mode 100644
index 000000000000..5afcaa89f418
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrlfs.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Basic resctrl file system operations
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+ *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ */
+#include "resctrl.h"
+
+#define RESCTRL_MBM		"L3 monitoring detected"
+#define RESCTRL_MBA		"MB allocation detected"
+enum {
+	RESCTRL_FEATURE_MBM,
+	RESCTRL_FEATURE_MBA,
+	MAX_RESCTRL_FEATURES
+};
+
+/*
+ * remount_resctrlfs - Remount resctrl FS at /sys/fs/resctrl
+ * @mum_resctrlfs:	Should the resctrl FS be remounted?
+ *
+ * If not mounted, mount it.
+ * If mounted and mum_resctrlfs then remount resctrl FS.
+ * If mounted and !mum_resctrlfs then noop
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int remount_resctrlfs(bool mum_resctrlfs)
+{
+	DIR *dp;
+	struct dirent *ep;
+	unsigned int count = 0;
+
+	/*
+	 * If kernel is built with CONFIG_RESCTRL, then /sys/fs/resctrl should
+	 * be present by default
+	 */
+	dp = opendir(RESCTRL_PATH);
+	if (dp) {
+		while ((ep = readdir(dp)) != NULL)
+			count++;
+		closedir(dp);
+	} else {
+		perror("Unable to read /sys/fs/resctrl");
+
+		return -1;
+	}
+
+	/*
+	 * If resctrl FS has more than two entries, it means that resctrl FS has
+	 * already been mounted. The two default entries are "." and "..", these
+	 * are present even when resctrl FS is not mounted
+	 */
+	if (count > 2) {
+		if (mum_resctrlfs) {
+			if (umount(RESCTRL_PATH) != 0) {
+				perror("Unable to umount resctrl");
+
+				return errno;
+			}
+			printf("Remount: done!\n");
+		} else {
+			printf("Mounted already. Not remounting!\n");
+
+			return 0;
+		}
+	}
+
+	if (mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL) != 0) {
+		perror("Unable to mount resctrl FS at /sys/fs/resctrl");
+
+		return errno;
+	}
+
+	return 0;
+}
+
+int umount_resctrlfs(void)
+{
+	if (umount(RESCTRL_PATH)) {
+		perror("Unable to umount resctrl");
+
+		return errno;
+	}
+
+	return 0;
+}
+
+/*
+ * get_resource_id - Get socket number/l3 id for a specified CPU
+ * @cpu_no:	CPU number
+ * @resource_id: Socket number or l3_id
+ *
+ * Return: >= 0 on success, < 0 on failure.
+ */
+int get_resource_id(int cpu_no, int *resource_id)
+{
+	char phys_pkg_path[1024];
+	FILE *fp;
+
+	sprintf(phys_pkg_path, "%s%d/topology/physical_package_id",
+		PHYS_ID_PATH, cpu_no);
+	fp = fopen(phys_pkg_path, "r");
+	if (!fp) {
+		perror("Failed to open physical_package_id");
+
+		return -1;
+	}
+	if (fscanf(fp, "%d", resource_id) <= 0) {
+		perror("Could not get socket number or l3 id");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	return 0;
+}
+
+/*
+ * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
+ * @bm_pid:	PID that should be binded
+ * @cpu_no:	CPU number at which the PID would be binded
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int taskset_benchmark(pid_t bm_pid, int cpu_no)
+{
+	cpu_set_t my_set;
+
+	CPU_ZERO(&my_set);
+	CPU_SET(cpu_no, &my_set);
+
+	if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {
+		perror("Unable to taskset benchmark");
+
+		return -1;
+	}
+
+	printf("Taskset benchmark: done!\n");
+
+	return 0;
+}
+
+/*
+ * run_benchmark - Run a specified benchmark or fill_buf (default benchmark)
+ *		   in specified signal. Direct benchmark stdio to /dev/null.
+ * @signum:	signal number
+ * @info:	signal info
+ * @ucontext:	user context in signal handling
+ *
+ * Return: void
+ */
+void run_benchmark(int signum, siginfo_t *info, void *ucontext)
+{
+	unsigned long long span;
+	int operation, ret;
+	char **benchmark_cmd;
+	FILE *fp;
+
+	benchmark_cmd = info->si_ptr;
+
+	/*
+	 * Direct stdio of child to /dev/null, so that only parent writes to
+	 * stdio (console)
+	 */
+	fp = freopen("/dev/null", "w", stdout);
+	if (!fp)
+		PARENT_EXIT("Unable to direct benchmark status to /dev/null");
+
+	if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
+		/* Execute default fill_buf benchmark */
+		span = strtoul(benchmark_cmd[1], NULL, 10);
+		operation = atoi(benchmark_cmd[4]);
+		if (run_fill_buf(span, 1, 1, operation, NULL))
+			fprintf(stderr, "Error in running fill buffer\n");
+	} else {
+		/* Execute specified benchmark */
+		ret = execvp(benchmark_cmd[0], benchmark_cmd);
+		if (ret)
+			perror("wrong\n");
+	}
+
+	fclose(stdout);
+	PARENT_EXIT("Unable to run specified benchmark");
+}
+
+/*
+ * create_grp - Create a group only if one doesn't exist
+ * @grp_name:	Name of the group
+ * @grp:	Full path and name of the group
+ * @parent_grp:	Full path and name of the parent group
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
+{
+	int found_grp = 0;
+	struct dirent *ep;
+	DIR *dp;
+
+	/* Check if requested grp exists or not */
+	dp = opendir(parent_grp);
+	if (dp) {
+		while ((ep = readdir(dp)) != NULL) {
+			if (strcmp(ep->d_name, grp_name) == 0)
+				found_grp = 1;
+		}
+		closedir(dp);
+	} else {
+		perror("Unable to open resctrl for group");
+
+		return -1;
+	}
+
+	/* Requested grp doesn't exist, hence create it */
+	if (found_grp == 0) {
+		if (mkdir(grp, 0) == -1) {
+			perror("Unable to create group");
+
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int write_pid_to_tasks(char *tasks, pid_t pid)
+{
+	FILE *fp;
+
+	fp = fopen(tasks, "w");
+	if (!fp) {
+		perror("Failed to open tasks file");
+
+		return -1;
+	}
+	if (fprintf(fp, "%d\n", pid) < 0) {
+		perror("Failed to wr pid to tasks file");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	return 0;
+}
+
+/*
+ * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS
+ * @bm_pid:		PID that should be written
+ * @ctrlgrp:		Name of the control monitor group (con_mon grp)
+ * @mongrp:		Name of the monitor group (mon grp)
+ * @resctrl_val:	Resctrl feature (Eg: mbm, mba.. etc)
+ *
+ * If a con_mon grp is requested, create it and write pid to it, otherwise
+ * write pid to root con_mon grp.
+ * If a mon grp is requested, create it and write pid to it, otherwise
+ * pid is not written, this means that pid is in con_mon grp and hence
+ * should consult con_mon grp's mon_data directory for results.
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
+			    char *resctrl_val)
+{
+	char controlgroup[256], monitorgroup[256], monitorgroup_p[256];
+	char tasks[256];
+	int ret;
+
+	if (ctrlgrp)
+		sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
+	else
+		sprintf(controlgroup, "%s", RESCTRL_PATH);
+
+	/* Create control and monitoring group and write pid into it */
+	ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH);
+	if (ret)
+		return ret;
+	sprintf(tasks, "%s/tasks", controlgroup);
+	ret = write_pid_to_tasks(tasks, bm_pid);
+	if (ret)
+		return ret;
+
+	/* Create mon grp and write pid into it for "mbm" test */
+	if ((strcmp(resctrl_val, "mbm") == 0)) {
+		if (mongrp) {
+			sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
+			sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
+			ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
+			if (ret)
+				return ret;
+
+			sprintf(tasks, "%s/mon_groups/%s/tasks",
+				controlgroup, mongrp);
+			ret = write_pid_to_tasks(tasks, bm_pid);
+			if (ret)
+				return ret;
+		}
+	}
+
+	printf("Write benchmark to resctrl FS: done!\n");
+
+	return 0;
+}
+
+/*
+ * write_schemata - Update schemata of a con_mon grp
+ * @ctrlgrp:		Name of the con_mon grp
+ * @schemata:		Schemata that should be updated to
+ * @cpu_no:		CPU number that the benchmark PID is binded to
+ * @resctrl_val:	Resctrl feature (Eg: mbm, mba.. etc)
+ *
+ * Update schemata of a con_mon grp *only* if requested resctrl feature is
+ * allocation type
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
+{
+	char controlgroup[1024], schema[1024];
+	int resource_id;
+	FILE *fp;
+
+	if (strcmp(resctrl_val, "mba") == 0) {
+		if (!schemata) {
+			printf("Schemata empty, so not updating\n");
+
+			return 0;
+		}
+		if (get_resource_id(cpu_no, &resource_id) < 0) {
+			perror("Failed to get resource id");
+			return -1;
+		}
+
+		if (ctrlgrp)
+			sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH,
+				ctrlgrp);
+		else
+			sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
+		sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=', schemata);
+
+		fp = fopen(controlgroup, "w");
+		if (!fp) {
+			perror("Failed to open control group");
+
+			return -1;
+		}
+
+		if (fprintf(fp, "%s\n", schema) < 0) {
+			perror("Failed to write schemata in control group");
+			fclose(fp);
+
+			return -1;
+		}
+		fclose(fp);
+
+		printf("Write schemata to resctrl FS: done!\n");
+	}
+
+	return 0;
+}
+
+/*
+ * validate_resctrl_feature_request - Check if requested feature is valid.
+ * @resctrl_val:	Requested feature
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int validate_resctrl_feature_request(char *resctrl_val)
+{
+	int resctrl_features_supported[MAX_RESCTRL_FEATURES];
+	const char *resctrl_features_list[MAX_RESCTRL_FEATURES] = {
+			"mbm", "mba"};
+	int i, valid_resctrl_feature = -1;
+	char line[1024];
+	FILE *fp;
+
+	if (!resctrl_val) {
+		fprintf(stderr, "resctrl feature cannot be NULL\n");
+
+		return -1;
+	}
+
+	for (i = 0; i < MAX_RESCTRL_FEATURES; i++)
+		resctrl_features_supported[i] = 0;
+
+	/* Is the resctrl feature request valid? */
+	for (i = 0; i < MAX_RESCTRL_FEATURES; i++) {
+		if (strcmp(resctrl_features_list[i], resctrl_val) == 0)
+			valid_resctrl_feature = i;
+	}
+	if (valid_resctrl_feature == -1) {
+		fprintf(stderr, "Not a valid resctrl feature request\n");
+
+		return -1;
+	}
+
+	/* Enumerate resctrl features supported by this platform */
+	if (system("dmesg > dmesg") != 0) {
+		perror("Could not create custom dmesg file");
+
+		return -1;
+	}
+
+	fp = fopen("dmesg", "r");
+	if (!fp) {
+		perror("Could not read custom created dmesg");
+
+		return -1;
+	}
+
+	while (fgets(line, 1024, fp)) {
+		if ((strstr(line, RESCTRL_MBM)) != NULL)
+			resctrl_features_supported[RESCTRL_FEATURE_MBM] = 1;
+		if ((strstr(line, RESCTRL_MBA)) != NULL)
+			resctrl_features_supported[RESCTRL_FEATURE_MBA] = 1;
+	}
+	fclose(fp);
+
+	if (system("rm -rf dmesg") != 0)
+		perror("Unable to remove 'dmesg' file");
+
+	/* Is the resctrl feature request supported? */
+	if (!resctrl_features_supported[valid_resctrl_feature]) {
+		fprintf(stderr, "resctrl feature not supported!");
+
+		return -1;
+	}
+
+	return 0;
+}
+
+int validate_bw_report_request(char *bw_report)
+{
+	if (strcmp(bw_report, "reads") == 0)
+		return 0;
+	if (strcmp(bw_report, "writes") == 0)
+		return 0;
+	if (strcmp(bw_report, "nt-writes") == 0) {
+		strcpy(bw_report, "writes");
+		return 0;
+	}
+	if (strcmp(bw_report, "total") == 0)
+		return 0;
+
+	fprintf(stderr, "Requested iMC B/W report type unavailable\n");
+
+	return -1;
+}
+
+int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
+		    int group_fd, unsigned long flags)
+{
+	int ret;
+
+	ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
+		      group_fd, flags);
+	return ret;
+}
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 03/13] selftests/resctrl: Read memory bandwidth from perf IMC counter and from resctrl file system
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
  2019-02-10  2:50 ` [PATCH v7 01/13] selftests/resctrl: Add README for resctrl tests Fenghua Yu
  2019-02-10  2:50 ` [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-02-10  2:50 ` [PATCH v7 04/13] selftests/resctrl: Add callback to start a benchmark Fenghua Yu
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>

Total memory bandwidth can be monitored from perf IMC counter and from
resctrl file system. Later the two will be compared to verify the total
memory bandwidth read from resctrl is correct.

Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/resctrl_val.c | 118 ++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 tools/testing/selftests/resctrl/resctrl_val.c

diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
new file mode 100644
index 000000000000..2bb317715a2a
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl_val.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Memory bandwidth monitoring and allocation library
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+ *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ */
+#include "resctrl.h"
+
+#define UNCORE_IMC		"uncore_imc"
+#define READ_FILE_NAME		"events/cas_count_read"
+#define WRITE_FILE_NAME		"events/cas_count_write"
+#define DYN_PMU_PATH		"/sys/bus/event_source/devices"
+#define SCALE			0.00006103515625
+#define MAX_IMCS		20
+#define MAX_TOKENS		5
+#define READ			0
+#define WRITE			1
+#define CON_MON_MBM_LOCAL_BYTES_PATH				\
+	"%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
+
+#define CON_MBM_LOCAL_BYTES_PATH		\
+	"%s/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
+
+#define MON_MBM_LOCAL_BYTES_PATH		\
+	"%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
+
+#define MBM_LOCAL_BYTES_PATH			\
+	"%s/mon_data/mon_L3_%02d/mbm_local_bytes"
+
+struct membw_read_format {
+	__u64 value;         /* The value of the event */
+	__u64 time_enabled;  /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
+	__u64 time_running;  /* if PERF_FORMAT_TOTAL_TIME_RUNNING */
+	__u64 id;            /* if PERF_FORMAT_ID */
+};
+
+struct imc_counter_config {
+	__u32 type;
+	__u64 event;
+	__u64 umask;
+	struct perf_event_attr pe;
+	struct membw_read_format return_value;
+	int fd;
+};
+
+static struct imc_counter_config imc_counters_config[MAX_IMCS][2];
+
+void membw_initialize_perf_event_attr(int i, int j)
+{
+	memset(&imc_counters_config[i][j].pe, 0,
+	       sizeof(struct perf_event_attr));
+	imc_counters_config[i][j].pe.type = imc_counters_config[i][j].type;
+	imc_counters_config[i][j].pe.size = sizeof(struct perf_event_attr);
+	imc_counters_config[i][j].pe.disabled = 1;
+	imc_counters_config[i][j].pe.inherit = 1;
+	imc_counters_config[i][j].pe.exclude_guest = 1;
+	imc_counters_config[i][j].pe.config =
+		imc_counters_config[i][j].umask << 8 |
+		imc_counters_config[i][j].event;
+	imc_counters_config[i][j].pe.sample_type = PERF_SAMPLE_IDENTIFIER;
+	imc_counters_config[i][j].pe.read_format =
+		PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
+}
+
+void membw_ioctl_perf_event_ioc_reset_enable(int i, int j)
+{
+	ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_RESET, 0);
+	ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_ENABLE, 0);
+}
+
+void membw_ioctl_perf_event_ioc_disable(int i, int j)
+{
+	ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_DISABLE, 0);
+}
+
+/*
+ * get_event_and_umask:	Parse config into event and umask
+ * @cas_count_cfg:	Config
+ * @count:		iMC number
+ * @op:			Operation (read/write)
+ */
+void get_event_and_umask(char *cas_count_cfg, int count, bool op)
+{
+	char *token[MAX_TOKENS];
+	int i = 0;
+
+	strcat(cas_count_cfg, ",");
+	token[0] = strtok(cas_count_cfg, "=,");
+
+	for (i = 1; i < MAX_TOKENS; i++)
+		token[i] = strtok(NULL, "=,");
+
+	for (i = 0; i < MAX_TOKENS; i++) {
+		if (!token[i])
+			break;
+		if (strcmp(token[i], "event") == 0) {
+			if (op == READ)
+				imc_counters_config[count][READ].event =
+				strtol(token[i + 1], NULL, 16);
+			else
+				imc_counters_config[count][WRITE].event =
+				strtol(token[i + 1], NULL, 16);
+		}
+		if (strcmp(token[i], "umask") == 0) {
+			if (op == READ)
+				imc_counters_config[count][READ].umask =
+				strtol(token[i + 1], NULL, 16);
+			else
+				imc_counters_config[count][WRITE].umask =
+				strtol(token[i + 1], NULL, 16);
+		}
+	}
+}
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 04/13] selftests/resctrl: Add callback to start a benchmark
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (2 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 03/13] selftests/resctrl: Read memory bandwidth from perf IMC counter and from resctrl file system Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:37   ` Andre Przywara
  2019-02-10  2:50 ` [PATCH v7 05/13] selftests/resctrl: Add built in benchmark Fenghua Yu
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>

The callback starts a child process and puts the child pid in created
resctrl group with specified memory bandwidth in schemata. The child
starts running benchmark.

Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/resctrl.h     |  27 ++
 tools/testing/selftests/resctrl/resctrl_val.c | 582 ++++++++++++++++++++++++++
 2 files changed, 609 insertions(+)

diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index 2e112934d48a..c286790ba24d 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -3,6 +3,7 @@
 #ifndef RESCTRL_H
 #define RESCTRL_H
 #include <stdio.h>
+#include <stdarg.h>
 #include <errno.h>
 #include <sched.h>
 #include <stdlib.h>
@@ -28,10 +29,35 @@
 		exit(EXIT_FAILURE);		\
 	} while (0)
 
+/*
+ * resctrl_val_param:	resctrl test parameters
+ * @resctrl_val:	Resctrl feature (Eg: mbm, mba.. etc)
+ * @ctrlgrp:		Name of the control monitor group (con_mon grp)
+ * @mongrp:		Name of the monitor group (mon grp)
+ * @cpu_no:		CPU number to which the benchmark would be binded
+ * @span:		Memory bytes accessed in each benchmark iteration
+ * @mum_resctrlfs:	Should the resctrl FS be remounted?
+ * @filename:		Name of file to which the o/p should be written
+ * @bw_report:		Bandwidth report type (reads vs writes)
+ * @setup:		Call back function to setup test environment
+ */
+struct resctrl_val_param {
+	char	*resctrl_val;
+	char	ctrlgrp[64];
+	char	mongrp[64];
+	int	cpu_no;
+	int	span;
+	int	mum_resctrlfs;
+	char	filename[64];
+	char	*bw_report;
+	int	(*setup)(int num, ...);
+};
+
 pid_t bm_pid, ppid;
 
 int remount_resctrlfs(bool mum_resctrlfs);
 int get_resource_id(int cpu_no, int *resource_id);
+int umount_resctrlfs(void);
 int validate_bw_report_request(char *bw_report);
 int validate_resctrl_feature_request(char *resctrl_val);
 int taskset_benchmark(pid_t bm_pid, int cpu_no);
@@ -44,5 +70,6 @@ int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
 		    int group_fd, unsigned long flags);
 int run_fill_buf(unsigned long span, int malloc_and_init_memory, int memflush,
 		 int op, char *resctrl_va);
+int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param);
 
 #endif /* RESCTRL_H */
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
index 2bb317715a2a..43c15e382892 100644
--- a/tools/testing/selftests/resctrl/resctrl_val.c
+++ b/tools/testing/selftests/resctrl/resctrl_val.c
@@ -11,6 +11,7 @@
  */
 #include "resctrl.h"
 
+#define MB			(1024 * 1024)
 #define UNCORE_IMC		"uncore_imc"
 #define READ_FILE_NAME		"events/cas_count_read"
 #define WRITE_FILE_NAME		"events/cas_count_write"
@@ -48,6 +49,8 @@ struct imc_counter_config {
 	int fd;
 };
 
+static char mbm_total_path[1024];
+static int imcs;
 static struct imc_counter_config imc_counters_config[MAX_IMCS][2];
 
 void membw_initialize_perf_event_attr(int i, int j)
@@ -116,3 +119,582 @@ void get_event_and_umask(char *cas_count_cfg, int count, bool op)
 		}
 	}
 }
+
+static int open_perf_event(int i, int cpu_no, int j)
+{
+	imc_counters_config[i][j].fd =
+		perf_event_open(&imc_counters_config[i][j].pe, -1, cpu_no, -1,
+				PERF_FLAG_FD_CLOEXEC);
+
+	if (imc_counters_config[i][j].fd == -1) {
+		fprintf(stderr, "Error opening leader %llx\n",
+			imc_counters_config[i][j].pe.config);
+
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Get type and config (read and write) of an iMC counter */
+static int read_from_imc_dir(char *imc_dir, int count)
+{
+	char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024];
+	FILE *fp;
+
+	/* Get type of iMC counter */
+	sprintf(imc_counter_type, "%s%s", imc_dir, "type");
+	fp = fopen(imc_counter_type, "r");
+	if (!fp) {
+		perror("Failed to open imc counter type file");
+
+		return -1;
+	}
+	if (fscanf(fp, "%u", &imc_counters_config[count][READ].type) <= 0) {
+		perror("Could not get imc type");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	imc_counters_config[count][WRITE].type =
+				imc_counters_config[count][READ].type;
+
+	/* Get read config */
+	sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME);
+	fp = fopen(imc_counter_cfg, "r");
+	if (!fp) {
+		perror("Failed to open imc config file");
+
+		return -1;
+	}
+	if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
+		perror("Could not get imc cas count read");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	get_event_and_umask(cas_count_cfg, count, READ);
+
+	/* Get write config */
+	sprintf(imc_counter_cfg, "%s%s", imc_dir, WRITE_FILE_NAME);
+	fp = fopen(imc_counter_cfg, "r");
+	if (!fp) {
+		perror("Failed to open imc config file");
+
+		return -1;
+	}
+	if  (fscanf(fp, "%s", cas_count_cfg) <= 0) {
+		perror("Could not get imc cas count write");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	get_event_and_umask(cas_count_cfg, count, WRITE);
+
+	return 0;
+}
+
+/*
+ * A system can have 'n' number of iMC (Integrated Memory Controller)
+ * counters, get that 'n'. For each iMC counter get it's type and config.
+ * Also, each counter has two configs, one for read and the other for write.
+ * A config again has two parts, event and umask.
+ * Enumerate all these details into an array of structures.
+ *
+ * Return: >= 0 on success. < 0 on failure.
+ */
+static int num_of_imcs(void)
+{
+	unsigned int count = 0;
+	char imc_dir[1024];
+	struct dirent *ep;
+	int ret;
+	DIR *dp;
+
+	dp = opendir(DYN_PMU_PATH);
+	if (dp) {
+		while ((ep = readdir(dp))) {
+			if (strstr(ep->d_name, UNCORE_IMC)) {
+				sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH,
+					ep->d_name);
+				ret = read_from_imc_dir(imc_dir, count);
+				if (ret) {
+					closedir(dp);
+
+					return ret;
+				}
+				count++;
+			}
+		}
+		closedir(dp);
+		if (count == 0) {
+			perror("Unable find iMC counters!\n");
+
+			return -1;
+		}
+	} else {
+		perror("Unable to open PMU directory!\n");
+
+		return -1;
+	}
+
+	return count;
+}
+
+static int initialize_mem_bw_imc(void)
+{
+	int imc, j;
+
+	imcs = num_of_imcs();
+	if (imcs <= 0)
+		return imcs;
+
+	/* Initialize perf_event_attr structures for all iMC's */
+	for (imc = 0; imc < imcs; imc++) {
+		for (j = 0; j < 2; j++)
+			membw_initialize_perf_event_attr(imc, j);
+	}
+
+	return 0;
+}
+
+/*
+ * get_mem_bw_imc:	Memory band width as reported by iMC counters
+ * @cpu_no:		CPU number that the benchmark PID is binded to
+ * @bw_report:		Bandwidth report type (reads, writes)
+ *
+ * Memory B/W utilized by a process on a socket can be calculated using
+ * iMC counters. Perf events are used to read these counters.
+ *
+ * Return: >= 0 on success. < 0 on failure.
+ */
+static float get_mem_bw_imc(int cpu_no, char *bw_report)
+{
+	float reads, writes, of_mul_read, of_mul_write;
+	int imc, j, ret;
+
+	/* Start all iMC counters to log values (both read and write) */
+	reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1;
+	for (imc = 0; imc < imcs; imc++) {
+		for (j = 0; j < 2; j++) {
+			ret = open_perf_event(imc, cpu_no, j);
+			if (ret)
+				return -1;
+		}
+		for (j = 0; j < 2; j++)
+			membw_ioctl_perf_event_ioc_reset_enable(imc, j);
+	}
+
+	sleep(1);
+
+	/* Stop counters after a second to get results (both read and write) */
+	for (imc = 0; imc < imcs; imc++) {
+		for (j = 0; j < 2; j++)
+			membw_ioctl_perf_event_ioc_disable(imc, j);
+	}
+
+	/*
+	 * Get results which are stored in struct type imc_counter_config
+	 * Take over flow into consideration before calculating total b/w
+	 */
+	for (imc = 0; imc < imcs; imc++) {
+		struct imc_counter_config *r =
+			&imc_counters_config[imc][READ];
+		struct imc_counter_config *w =
+			&imc_counters_config[imc][WRITE];
+
+		if (read(r->fd, &r->return_value,
+			 sizeof(struct membw_read_format)) == -1) {
+			perror("Couldn't get read b/w through iMC");
+
+			return -1;
+		}
+
+		if (read(w->fd, &w->return_value,
+			 sizeof(struct membw_read_format)) == -1) {
+			perror("Couldn't get write bw through iMC");
+
+			return -1;
+		}
+
+		__u64 r_time_enabled = r->return_value.time_enabled;
+		__u64 r_time_running = r->return_value.time_running;
+
+		if (r_time_enabled != r_time_running)
+			of_mul_read = (float)r_time_enabled /
+					(float)r_time_running;
+
+		__u64 w_time_enabled = w->return_value.time_enabled;
+		__u64 w_time_running = w->return_value.time_running;
+
+		if (w_time_enabled != w_time_running)
+			of_mul_write = (float)w_time_enabled /
+					(float)w_time_running;
+		reads += r->return_value.value * of_mul_read * SCALE;
+		writes += w->return_value.value * of_mul_write * SCALE;
+	}
+
+	for (imc = 0; imc < imcs; imc++) {
+		close(imc_counters_config[imc][READ].fd);
+		close(imc_counters_config[imc][WRITE].fd);
+	}
+
+	if (strcmp(bw_report, "reads") == 0)
+		return reads;
+
+	if (strcmp(bw_report, "writes") == 0)
+		return writes;
+
+	return (reads + writes);
+}
+
+void set_mbm_path(const char *ctrlgrp, const char *mongrp, int resource_id)
+{
+	if (ctrlgrp && mongrp)
+		sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH,
+			RESCTRL_PATH, ctrlgrp, mongrp, resource_id);
+	else if (!ctrlgrp && mongrp)
+		sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
+			mongrp, resource_id);
+	else if (ctrlgrp && !mongrp)
+		sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
+			ctrlgrp, resource_id);
+	else if (!ctrlgrp && !mongrp)
+		sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
+			resource_id);
+}
+
+/*
+ * initialize_mem_bw_resctrl:	Appropriately populate "mbm_total_path"
+ * @ctrlgrp:			Name of the control monitor group (con_mon grp)
+ * @mongrp:			Name of the monitor group (mon grp)
+ * @cpu_no:			CPU number that the benchmark PID is binded to
+ * @resctrl_val:		Resctrl feature (Eg: mbm, mba.. etc)
+ */
+static void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp,
+				      int cpu_no, char *resctrl_val)
+{
+	int resource_id;
+
+	if (get_resource_id(cpu_no, &resource_id) < 0) {
+		perror("Could not get resource_id");
+		return;
+	}
+
+	if (strcmp(resctrl_val, "mbm") == 0)
+		set_mbm_path(ctrlgrp, mongrp, resource_id);
+
+	if ((strcmp(resctrl_val, "mba") == 0)) {
+		if (ctrlgrp)
+			sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH,
+				RESCTRL_PATH, ctrlgrp, resource_id);
+		else
+			sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH,
+				RESCTRL_PATH, resource_id);
+	}
+}
+
+/*
+ * Get MBM Local bytes as reported by resctrl FS
+ * For MBM,
+ * 1. If con_mon grp and mon grp are given, then read from con_mon grp's mon grp
+ * 2. If only con_mon grp is given, then read from con_mon grp
+ * 3. If both are not given, then read from root con_mon grp
+ * For MBA,
+ * 1. If con_mon grp is given, then read from it
+ * 2. If con_mon grp is not given, then read from root con_mon grp
+ */
+static unsigned long get_mem_bw_resctrl(void)
+{
+	unsigned long mbm_total = 0;
+	FILE *fp;
+
+	fp = fopen(mbm_total_path, "r");
+	if (!fp) {
+		perror("Failed to open total bw file");
+
+		return -1;
+	}
+	if (fscanf(fp, "%lu", &mbm_total) <= 0) {
+		perror("Could not get mbm local bytes");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	return mbm_total;
+}
+
+pid_t bm_pid, ppid;
+
+static void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
+{
+	kill(bm_pid, SIGKILL);
+	printf("Ending\n\n");
+
+	exit(EXIT_SUCCESS);
+}
+
+/*
+ * print_results_bw:	the memory bandwidth results are stored in a file
+ * @filename:		file that stores the results
+ * @bm_pid:		child pid that runs benchmark
+ * @bw_imc:		perf imc counter value
+ * @bw_resc:		memory bandwidth value
+ *
+ * Return:		0 on success. non-zero on failure.
+ */
+static int print_results_bw(char *filename,  int bm_pid, float bw_imc,
+			    unsigned long bw_resc)
+{
+	unsigned long diff = labs(bw_imc - bw_resc);
+	FILE *fp;
+
+	if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) {
+		printf("Pid: %d \t Mem_BW_iMC: %f \t ", bm_pid, bw_imc);
+		printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff);
+	} else {
+		fp = fopen(filename, "a");
+		if (!fp) {
+			perror("Cannot open results file");
+
+			return errno;
+		}
+		if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n",
+			    bm_pid, bw_imc, bw_resc, diff) <= 0) {
+			fclose(fp);
+			perror("Could not log results.");
+
+			return errno;
+		}
+		fclose(fp);
+	}
+
+	return 0;
+}
+
+static int
+measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
+{
+	unsigned long bw_imc, bw_resc, bw_resc_end;
+	int ret;
+
+	/*
+	 * Measure memory bandwidth from resctrl and from
+	 * another source which is perf imc value or could
+	 * be something else if perf imc event is not available.
+	 * Compare the two values to validate resctrl value.
+	 * It takes 1sec to measure the data.
+	 */
+	bw_imc = get_mem_bw_imc(param->cpu_no, param->bw_report);
+	if (bw_imc <= 0)
+		return bw_imc;
+
+	bw_resc_end = get_mem_bw_resctrl();
+	if (bw_resc_end <= 0)
+		return bw_resc_end;
+
+	bw_resc = (bw_resc_end - *bw_resc_start) / MB;
+	ret = print_results_bw(param->filename, bm_pid, bw_imc, bw_resc);
+	if (ret)
+		return ret;
+
+	*bw_resc_start = bw_resc_end;
+
+	return 0;
+}
+
+/*
+ * resctrl_val:	execute benchmark and measure memory bandwidth on
+ *			the benchmark
+ * @benchmark_cmd:	benchmark command and its arguments
+ * @param:		parameters passed to resctrl_val()
+ *
+ * Return:		0 on success. non-zero on failure.
+ */
+int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
+{
+	int ret = 0, pipefd[2], pipe_message = 0;
+	char *resctrl_val = param->resctrl_val;
+	unsigned long bw_resc_start = 0;
+	struct sigaction sigact;
+	union sigval value;
+	FILE *fp;
+
+	if (strcmp(param->filename, "") == 0)
+		sprintf(param->filename, "stdio");
+
+	if (strcmp(param->bw_report, "") == 0)
+		param->bw_report = "total";
+
+	if ((strcmp(resctrl_val, "mba")) == 0 ||
+	    (strcmp(resctrl_val, "mbm")) == 0) {
+		ret = validate_bw_report_request(param->bw_report);
+		if (ret)
+			return ret;
+	}
+
+	ret = remount_resctrlfs(param->mum_resctrlfs);
+	if (ret)
+		return ret;
+
+	/*
+	 * If benchmark wasn't successfully started by child, then child should
+	 * kill parent, so save parent's pid
+	 */
+	ppid = getpid();
+
+	/* File based synchronization between parent and child */
+	fp = fopen("sig", "w");
+	if (!fp) {
+		perror("Failed to open sig file");
+
+		return -1;
+	}
+	if (fprintf(fp, "%d\n", 0) <= 0) {
+		perror("Unable to establish sync bw parent & child");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	if (pipe(pipefd)) {
+		perror("Unable to create pipe");
+
+		return -1;
+	}
+
+	/*
+	 * Fork to start benchmark, save child's pid so that it can be killed
+	 * when needed
+	 */
+	bm_pid = fork();
+	if (bm_pid == -1) {
+		perror("Unable to fork");
+
+		return -1;
+	}
+
+	if (bm_pid == 0) {
+		/*
+		 * Mask all signals except SIGUSR1, parent uses SIGUSR1 to
+		 * start benchmark
+		 */
+		sigfillset(&sigact.sa_mask);
+		sigdelset(&sigact.sa_mask, SIGUSR1);
+
+		sigact.sa_sigaction = run_benchmark;
+		sigact.sa_flags = SA_SIGINFO;
+
+		/* Register for "SIGUSR1" signal from parent */
+		if (sigaction(SIGUSR1, &sigact, NULL))
+			PARENT_EXIT("Can't register child for signal");
+
+		/* Tell parent that child is ready */
+		close(pipefd[0]);
+		pipe_message = 1;
+		write(pipefd[1], &pipe_message, sizeof(pipe_message));
+		close(pipefd[1]);
+
+		/* Suspend child until delivery of "SIGUSR1" from parent */
+		sigsuspend(&sigact.sa_mask);
+
+		PARENT_EXIT("Child is done");
+	}
+
+	printf("Benchmark PID: %d\n", bm_pid);
+
+	/*
+	 * Register CTRL-C handler for parent, as it has to kill benchmark
+	 * before exiting
+	 */
+	sigact.sa_sigaction = ctrlc_handler;
+	sigemptyset(&sigact.sa_mask);
+	sigact.sa_flags = SA_SIGINFO;
+	if (sigaction(SIGINT, &sigact, NULL) ||
+	    sigaction(SIGHUP, &sigact, NULL)) {
+		perror("Can't register parent for CTRL-C handler");
+		ret = errno;
+		goto out;
+	}
+
+	value.sival_ptr = benchmark_cmd;
+
+	/* Taskset benchmark to specified cpu */
+	ret = taskset_benchmark(bm_pid, param->cpu_no);
+	if (ret)
+		goto out;
+
+	/* Write benchmark to specified control&monitoring grp in resctrl FS */
+	ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
+				      resctrl_val);
+	if (ret)
+		goto out;
+
+	if ((strcmp(resctrl_val, "mbm") == 0) ||
+	    (strcmp(resctrl_val, "mba") == 0)) {
+		ret = initialize_mem_bw_imc();
+		if (ret)
+			goto out;
+
+		initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
+					  param->cpu_no, resctrl_val);
+	}
+
+	/* Parent waits for child to be ready. */
+	close(pipefd[1]);
+	while (pipe_message != 1)
+		read(pipefd[0], &pipe_message, sizeof(pipe_message));
+	close(pipefd[0]);
+
+	/* Signal child to start benchmark */
+	if (sigqueue(bm_pid, SIGUSR1, value) == -1) {
+		perror("Unable to signal child to start execution");
+		ret = errno;
+		goto out;
+	}
+
+	/* Give benchmark enough time to fully run */
+	sleep(1);
+
+	/* Test runs until the callback setup() tells the test to stop. */
+	while (1) {
+		if (strcmp(resctrl_val, "mbm") == 0) {
+			ret = param->setup(1, param);
+			if (ret) {
+				ret = 0;
+				break;
+			}
+
+			ret = measure_vals(param, &bw_resc_start);
+			if (ret)
+				break;
+		} else if ((strcmp(resctrl_val, "mba") == 0)) {
+			ret = param->setup(1, param);
+			if (ret) {
+				ret = 0;
+				break;
+			}
+
+			ret = measure_vals(param, &bw_resc_start);
+			if (ret)
+				break;
+		} else {
+			break;
+		}
+	}
+
+out:
+	kill(bm_pid, SIGKILL);
+	umount_resctrlfs();
+
+	return ret;
+}
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 05/13] selftests/resctrl: Add built in benchmark
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (3 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 04/13] selftests/resctrl: Add callback to start a benchmark Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:37   ` Andre Przywara
  2019-02-10  2:50 ` [PATCH v7 06/13] selftests/resctrl: Add MBM test Fenghua Yu
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>

Built-in benchmark fill_buf generates stressful memory bandwidth
and cache traffic.

Later it will be used as a default benchmark by various resctrl tests
such as MBA (Memory Bandwidth Allocation) and MBM (Memory Bandwidth
Monitoring) tests.

Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/fill_buf.c | 204 +++++++++++++++++++++++++++++
 1 file changed, 204 insertions(+)
 create mode 100644 tools/testing/selftests/resctrl/fill_buf.c

diff --git a/tools/testing/selftests/resctrl/fill_buf.c b/tools/testing/selftests/resctrl/fill_buf.c
new file mode 100644
index 000000000000..792a5c40a32a
--- /dev/null
+++ b/tools/testing/selftests/resctrl/fill_buf.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fill_buf benchmark
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+ *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <inttypes.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "resctrl.h"
+
+#define CL_SIZE			(64)
+#define PAGE_SIZE		(4 * 1024)
+#define MB			(1024 * 1024)
+
+static unsigned char *startptr;
+
+static void sb(void)
+{
+	asm volatile("sfence\n\t"
+		     : : : "memory");
+}
+
+static void ctrl_handler(int signo)
+{
+	free(startptr);
+	printf("\nEnding\n");
+	sb();
+	exit(EXIT_SUCCESS);
+}
+
+static void cl_flush(void *p)
+{
+	asm volatile("clflush (%0)\n\t"
+		     : : "r"(p) : "memory");
+}
+
+static void mem_flush(void *p, size_t s)
+{
+	char *cp = (char *)p;
+	size_t i = 0;
+
+	s = s / CL_SIZE; /* mem size in cache llines */
+
+	for (i = 0; i < s; i++)
+		cl_flush(&cp[i * CL_SIZE]);
+
+	sb();
+}
+
+static void *malloc_and_init_memory(size_t s)
+{
+	uint64_t *p64;
+	size_t s64;
+
+	void *p = memalign(PAGE_SIZE, s);
+
+	p64 = (uint64_t *)p;
+	s64 = s / sizeof(uint64_t);
+
+	while (s64 > 0) {
+		*p64 = (uint64_t)rand();
+		p64 += (CL_SIZE / sizeof(uint64_t));
+		s64 -= (CL_SIZE / sizeof(uint64_t));
+	}
+
+	return p;
+}
+
+static int fill_one_span_read(unsigned char *start_ptr, unsigned char *end_ptr)
+{
+	unsigned char sum, *p;
+
+	sum = 0;
+	p = start_ptr;
+	while (p < end_ptr) {
+		sum += *p;
+		p += (CL_SIZE / 2);
+	}
+
+	return sum;
+}
+
+static
+void fill_one_span_write(unsigned char *start_ptr, unsigned char *end_ptr)
+{
+	unsigned char *p;
+
+	p = start_ptr;
+	while (p < end_ptr) {
+		*p = '1';
+		p += (CL_SIZE / 2);
+	}
+}
+
+static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
+			   char *resctrl_val)
+{
+	int ret = 0;
+	FILE *fp;
+
+	while (1)
+		ret = fill_one_span_read(start_ptr, end_ptr);
+
+	/* Consume read result so that reading memory is not optimized out. */
+	fp = fopen("/dev/null", "w");
+	if (!fp)
+		perror("Unable to write to /dev/null");
+	fprintf(fp, "Sum: %d ", ret);
+	fclose(fp);
+
+	return 0;
+}
+
+static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr,
+			    char *resctrl_val)
+{
+	while (1)
+		fill_one_span_write(start_ptr, end_ptr);
+
+	return 0;
+}
+
+static int
+fill_cache(unsigned long long buf_size, int malloc_and_init, int memflush,
+	   int op, char *resctrl_val)
+{
+	unsigned char *start_ptr, *end_ptr;
+	unsigned long long i;
+	int ret;
+
+	if (malloc_and_init)
+		start_ptr = malloc_and_init_memory(buf_size);
+	else
+		start_ptr = malloc(buf_size);
+
+	if (!start_ptr)
+		return -1;
+
+	startptr = start_ptr;
+	end_ptr = start_ptr + buf_size;
+
+	/*
+	 * It's better to touch the memory once to avoid any compiler
+	 * optimizations
+	 */
+	if (!malloc_and_init) {
+		for (i = 0; i < buf_size; i++)
+			*start_ptr++ = (unsigned char)rand();
+	}
+
+	start_ptr = startptr;
+
+	/* Flush the memory before using to avoid "cache hot pages" effect */
+	if (memflush)
+		mem_flush(start_ptr, buf_size);
+
+	if (op == 0)
+		ret = fill_cache_read(start_ptr, end_ptr, resctrl_val);
+	else
+		ret = fill_cache_write(start_ptr, end_ptr, resctrl_val);
+
+	if (ret) {
+		printf("\n Errror in fill cache read/write...\n");
+		return -1;
+	}
+
+	free(startptr);
+
+	return 0;
+}
+
+int run_fill_buf(unsigned long span, int malloc_and_init_memory,
+		 int memflush, int op, char *resctrl_val)
+{
+	unsigned long long cache_size = span;
+	int ret;
+
+	/* set up ctrl-c handler */
+	if (signal(SIGINT, ctrl_handler) == SIG_ERR)
+		printf("Failed to catch SIGINT!\n");
+	if (signal(SIGHUP, ctrl_handler) == SIG_ERR)
+		printf("Failed to catch SIGHUP!\n");
+
+	ret = fill_cache(cache_size, malloc_and_init_memory, memflush, op,
+			 resctrl_val);
+	if (ret) {
+		printf("\n Errror in fill cache\n");
+		return -1;
+	}
+
+	return 0;
+}
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 06/13] selftests/resctrl: Add MBM test
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (4 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 05/13] selftests/resctrl: Add built in benchmark Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:37   ` Andre Przywara
  2019-02-10  2:50 ` [PATCH v7 07/13] selftests/resctrl: Add MBA test Fenghua Yu
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>

MBM (Memory Bandwidth Monitoring) test is the first implemented selftest.
It starts a stressful memory bandwidth benchmark and assigns the
bandwidth pid in a resctrl monitoring group. Read and compare perf IMC
counter and MBM total bytes for the benchmark. The numbers should be
close enough to pass the test.

Default benchmark is built-in fill_buf. But users can specify their
own benchmark by option "-b".

We can add memory bandwidth monitoring for multiple processes in the
future.

Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/Makefile        |   8 +-
 tools/testing/selftests/resctrl/mbm_test.c      | 149 ++++++++++++++++++++++++
 tools/testing/selftests/resctrl/resctrl.h       |   3 +
 tools/testing/selftests/resctrl/resctrl_tests.c | 114 ++++++++++++++++++
 tools/testing/selftests/resctrl/resctrl_val.c   |   2 +
 5 files changed, 275 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/resctrl/mbm_test.c
 create mode 100644 tools/testing/selftests/resctrl/resctrl_tests.c

diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
index bd5c5418961e..eaa8b45de10d 100644
--- a/tools/testing/selftests/resctrl/Makefile
+++ b/tools/testing/selftests/resctrl/Makefile
@@ -1,10 +1,16 @@
 CC = gcc
 CFLAGS = -g -Wall
 
+all: resctrl_tests
+
 *.o: *.c
 	$(CC) $(CFLAGS) -c *.c
 
+resctrl_tests: *.o
+	$(CC) $(CFLAGS) -o resctrl_tests resctrl_tests.o resctrlfs.o \
+		 resctrl_val.o fill_buf.o mbm_test.o
+
 .PHONY: clean
 
 clean:
-	$(RM) *.o *~
+	$(RM) *.o *~ resctrl_tests
diff --git a/tools/testing/selftests/resctrl/mbm_test.c b/tools/testing/selftests/resctrl/mbm_test.c
new file mode 100644
index 000000000000..dba981c562ff
--- /dev/null
+++ b/tools/testing/selftests/resctrl/mbm_test.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Memory Bandwidth Monitoring (MBM) test
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+ *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ */
+#include "resctrl.h"
+
+#define RESULT_FILE_NAME	"result_mbm"
+#define MAX_DIFF		300
+#define NUM_OF_RUNS		5
+
+static void
+show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, int span)
+{
+	unsigned long avg_bw_imc = 0, avg_bw_resc = 0;
+	unsigned long sum_bw_imc = 0, sum_bw_resc = 0;
+	long avg_diff = 0;
+	int runs;
+
+	/*
+	 * Discard the first value which is inaccurate due to monitoring setup
+	 * transition phase.
+	 */
+	for (runs = 1; runs < NUM_OF_RUNS ; runs++) {
+		sum_bw_imc += bw_imc[runs];
+		sum_bw_resc += bw_resc[runs];
+	}
+
+	avg_bw_imc = sum_bw_imc / 4;
+	avg_bw_resc = sum_bw_resc / 4;
+	avg_diff = avg_bw_resc - avg_bw_imc;
+
+	printf("\nSpan (MB): %d \t", span);
+	printf("avg_bw_imc: %lu\t", avg_bw_imc);
+	printf("avg_bw_resc: %lu\t", avg_bw_resc);
+	printf("avg_diff: %lu\t", labs(avg_diff));
+
+	if (labs(avg_diff) > MAX_DIFF)
+		printf(" failed\n");
+	else
+		printf(" passed\n");
+}
+
+static int check_results(int span)
+{
+	unsigned long bw_imc[NUM_OF_RUNS], bw_resc[NUM_OF_RUNS];
+	char temp[1024], *token_array[8];
+	char output[] = RESULT_FILE_NAME;
+	int runs;
+	FILE *fp;
+
+	printf("\nChecking for pass/fail\n");
+
+	fp = fopen(output, "r");
+	if (!fp) {
+		perror("Error in opening file\n");
+
+		return errno;
+	}
+
+	runs = 0;
+	while (fgets(temp, 1024, fp)) {
+		char *token = strtok(temp, ":\t");
+		int i = 0;
+
+		while (token) {
+			token_array[i++] = token;
+			token = strtok(NULL, ":\t");
+		}
+
+		bw_resc[runs] = strtoul(token_array[5], NULL, 0);
+		bw_imc[runs] = strtoul(token_array[3], NULL, 0);
+		runs++;
+	}
+
+	show_bw_info(bw_imc, bw_resc, span);
+
+	fclose(fp);
+
+	return 0;
+}
+
+static int mbm_setup(int num, ...)
+{
+	struct resctrl_val_param *p;
+	static int num_of_runs;
+	va_list param;
+	int ret = 0;
+
+	/* Run NUM_OF_RUNS times */
+	if (num_of_runs++ >= NUM_OF_RUNS)
+		return -1;
+
+	va_start(param, num);
+	p = va_arg(param, struct resctrl_val_param *);
+	va_end(param);
+
+	/* Set up shemata with 100% allocation on the first run. */
+	if (num_of_runs == 0)
+		ret = write_schemata(p->ctrlgrp, "100", p->cpu_no,
+				     p->resctrl_val);
+
+	return ret;
+}
+
+void mbm_test_cleanup(void)
+{
+	remove(RESULT_FILE_NAME);
+}
+
+int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd)
+{
+	struct resctrl_val_param param = {
+		.resctrl_val	= "mbm",
+		.ctrlgrp	= "c1",
+		.mongrp		= "m1",
+		.span		= span,
+		.cpu_no		= cpu_no,
+		.mum_resctrlfs	= 1,
+		.filename	= RESULT_FILE_NAME,
+		.bw_report	=  bw_report,
+		.setup		= mbm_setup
+	};
+	int ret;
+
+	remove(RESULT_FILE_NAME);
+
+	ret = validate_resctrl_feature_request("mbm");
+	if (ret)
+		return ret;
+
+	ret = resctrl_val(benchmark_cmd, &param);
+	if (ret)
+		return ret;
+
+	ret = check_results(span);
+	if (ret)
+		return ret;
+
+	mbm_test_cleanup();
+
+	return 0;
+}
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index c286790ba24d..7f7ea180478c 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -71,5 +71,8 @@ int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
 int run_fill_buf(unsigned long span, int malloc_and_init_memory, int memflush,
 		 int op, char *resctrl_va);
 int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param);
+int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd);
+void tests_cleanup(void);
+void mbm_test_cleanup(void);
 
 #endif /* RESCTRL_H */
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
new file mode 100644
index 000000000000..a51780d28ff1
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Resctrl tests
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+ *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ */
+#include "resctrl.h"
+
+#define BENCHMARK_ARGS		64
+#define BENCHMARK_ARG_SIZE	64
+
+static void cmd_help(void)
+{
+	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list]\n");
+	printf("\t-b benchmark_cmd [options]: run specified benchmark\n");
+	printf("\t default benchmark is builtin fill_buf\n");
+	printf("\t-t test list: run tests specified in the test list, ");
+	printf("e.g. -t mbm,mba\n");
+	printf("\t-h: help\n");
+}
+
+void tests_cleanup(void)
+{
+	mbm_test_cleanup();
+}
+
+int main(int argc, char **argv)
+{
+	char benchmark_cmd_area[BENCHMARK_ARGS][BENCHMARK_ARG_SIZE];
+	int res, c, cpu_no = 1, span = 250, argc_new = argc, i;
+	int ben_ind;
+	bool has_ben = false, mbm_test = true;
+	char *benchmark_cmd[BENCHMARK_ARGS];
+	char bw_report[64], bm_type[64];
+
+	for (i = 0; i < argc; i++) {
+		if (strcmp(argv[i], "-b") == 0) {
+			ben_ind = i + 1;
+			argc_new = ben_ind - 1;
+			has_ben = 1;
+			break;
+		}
+	}
+
+	while ((c = getopt(argc_new, argv, "ht:b:")) != -1) {
+		char *token;
+
+		switch (c) {
+		case 't':
+			token = strtok(optarg, ",");
+
+			mbm_test = false;
+			while (token) {
+				if (!strcmp(token, "mbm")) {
+					mbm_test = true;
+				} else {
+					printf("invalid argument\n");
+
+					return -1;
+				}
+				token = strtok(NULL, ":\t");
+			}
+			break;
+		case 'h':
+			cmd_help();
+
+			return 0;
+		default:
+			printf("invalid argument\n");
+
+			return -1;
+		}
+	}
+
+	/*
+	 * We need root privileges to run because
+	 * 1. We write to resctrl FS
+	 * 2. We execute perf commands
+	 */
+	if (geteuid() != 0) {
+		perror("Please run this program as root\n");
+
+		return errno;
+	}
+
+	if (!has_ben) {
+		/* If no benchmark is given by "-b" argument, use fill_buf. */
+		for (i = 0; i < 5; i++)
+			benchmark_cmd[i] = benchmark_cmd_area[i];
+		strcpy(benchmark_cmd[0], "fill_buf");
+		sprintf(benchmark_cmd[1], "%d", span);
+		strcpy(benchmark_cmd[2], "1");
+		strcpy(benchmark_cmd[3], "1");
+		strcpy(benchmark_cmd[4], "0");
+		benchmark_cmd[5] = NULL;
+	}
+
+	sprintf(bw_report, "reads");
+	sprintf(bm_type, "fill_buf");
+
+	if (mbm_test) {
+		printf("\nMBM BW Change Starting..\n");
+		res = mbm_bw_change(span, cpu_no, bw_report, benchmark_cmd);
+		if (res)
+			printf("Error in running tests for mbm bw change!\n");
+	}
+
+	return 0;
+}
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
index 43c15e382892..200a5b6756da 100644
--- a/tools/testing/selftests/resctrl/resctrl_val.c
+++ b/tools/testing/selftests/resctrl/resctrl_val.c
@@ -437,6 +437,8 @@ pid_t bm_pid, ppid;
 static void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
 {
 	kill(bm_pid, SIGKILL);
+	umount_resctrlfs();
+	tests_cleanup();
 	printf("Ending\n\n");
 
 	exit(EXIT_SUCCESS);
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 07/13] selftests/resctrl: Add MBA test
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (5 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 06/13] selftests/resctrl: Add MBM test Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:37   ` Andre Przywara
  2019-02-10  2:50 ` [PATCH v7 08/13] selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest Fenghua Yu
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>

MBA (Memory Bandwidth Allocation) test starts a stressful memory
bandwidth benchmark and allocates memory bandwidth from 100% down
to 10% for the benchmark process. For each allocation, compare
perf IMC counter and mbm total bytes from resctrl. The difference
between the two values should be within a threshold to pass the test.

Default benchmark is built-in fill_buf. But users can specify their
own benchmark by option "-b".

We can add memory bandwidth allocation for multiple processes in the
future.

Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/Makefile        |   2 +-
 tools/testing/selftests/resctrl/mba_test.c      | 177 ++++++++++++++++++++++++
 tools/testing/selftests/resctrl/resctrl.h       |   2 +
 tools/testing/selftests/resctrl/resctrl_tests.c |  15 +-
 4 files changed, 194 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/resctrl/mba_test.c

diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
index eaa8b45de10d..141cbdb619af 100644
--- a/tools/testing/selftests/resctrl/Makefile
+++ b/tools/testing/selftests/resctrl/Makefile
@@ -8,7 +8,7 @@ all: resctrl_tests
 
 resctrl_tests: *.o
 	$(CC) $(CFLAGS) -o resctrl_tests resctrl_tests.o resctrlfs.o \
-		 resctrl_val.o fill_buf.o mbm_test.o
+		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o
 
 .PHONY: clean
 
diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c
new file mode 100644
index 000000000000..71d8feb93ac8
--- /dev/null
+++ b/tools/testing/selftests/resctrl/mba_test.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Memory Bandwidth Allocation (MBA) test
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+ *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ */
+#include "resctrl.h"
+
+#define RESULT_FILE_NAME	"result_mba"
+#define NUM_OF_RUNS		5
+#define MAX_DIFF		300
+#define ALLOCATION_MAX		100
+#define ALLOCATION_MIN		10
+#define ALLOCATION_STEP		10
+
+/*
+ * Change schemata percentage from 100 to 10%. Write schemata to specified
+ * con_mon grp, mon_grp in resctrl FS.
+ * For each allocation, run 5 times in order to get average values.
+ */
+static int mba_setup(int num, ...)
+{
+	static int runs_per_allocation, allocation = 100;
+	struct resctrl_val_param *p;
+	char allocation_str[64];
+	va_list param;
+
+	va_start(param, num);
+	p = va_arg(param, struct resctrl_val_param *);
+	va_end(param);
+
+	if (runs_per_allocation >= NUM_OF_RUNS)
+		runs_per_allocation = 0;
+
+	/* Only set up schemata once every NUM_OF_RUNS of allocations */
+	if (runs_per_allocation++ != 0)
+		return 0;
+
+	if (allocation < ALLOCATION_MIN || allocation > ALLOCATION_MAX)
+		return -1;
+
+	sprintf(allocation_str, "%d", allocation);
+
+	write_schemata(p->ctrlgrp, allocation_str, p->cpu_no, p->resctrl_val);
+	printf("changed schemata to : %d\n", allocation);
+	allocation -= ALLOCATION_STEP;
+
+	return 0;
+}
+
+static void show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc)
+{
+	int allocation, failed = 0, runs;
+
+	/* Memory bandwidth from 100% down to 10% */
+	for (allocation = 0; allocation < ALLOCATION_MAX / ALLOCATION_STEP;
+	     allocation++) {
+		unsigned long avg_bw_imc = 0, avg_bw_resc = 0;
+		unsigned long sum_bw_imc = 0, sum_bw_resc = 0;
+		long  avg_diff = 0;
+
+		/*
+		 * The first run is discarded due to inaccurate value from
+		 * phase transition.
+		 */
+		for (runs = NUM_OF_RUNS * allocation + 1;
+		     runs < NUM_OF_RUNS * allocation + NUM_OF_RUNS ; runs++) {
+			sum_bw_imc += bw_imc[runs];
+			sum_bw_resc += bw_resc[runs];
+		}
+
+		avg_bw_imc = sum_bw_imc / (NUM_OF_RUNS - 1);
+		avg_bw_resc = sum_bw_resc / (NUM_OF_RUNS - 1);
+		avg_diff = avg_bw_resc - avg_bw_imc;
+
+		printf("\nschemata percentage: %d \t",
+		       ALLOCATION_MAX - ALLOCATION_STEP * allocation);
+		printf("avg_bw_imc: %lu\t", avg_bw_imc);
+		printf("avg_bw_resc: %lu\t", avg_bw_resc);
+		printf("avg_diff: %lu\t", labs(avg_diff));
+		if (labs(avg_diff) > MAX_DIFF) {
+			printf("failed\n");
+			failed = 1;
+		} else {
+			printf("passed\n");
+		}
+	}
+
+	if (failed) {
+		printf("\nTest for schemata change using MBA failed");
+		printf("as atleast one test failed!\n");
+	} else {
+		printf("\nTests for changing schemata using MBA passed!\n\n");
+	}
+}
+
+static int check_results(void)
+{
+	char *token_array[8], output[] = RESULT_FILE_NAME, temp[512];
+	unsigned long bw_imc[1024], bw_resc[1024];
+	int runs;
+	FILE *fp;
+
+	printf("\nchecking for pass/fail\n");
+	fp = fopen(output, "r");
+	if (!fp) {
+		perror("Error in opening file\n");
+
+		return errno;
+	}
+
+	runs = 0;
+	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 perf imc value */
+		bw_imc[runs] = strtoul(token_array[3], NULL, 0);
+		/* Field 5 is resctrl value */
+		bw_resc[runs] = strtoul(token_array[5], NULL, 0);
+		runs++;
+	}
+
+	fclose(fp);
+
+	show_mba_info(bw_imc, bw_resc);
+
+	return 0;
+}
+
+void mba_test_cleanup(void)
+{
+	remove(RESULT_FILE_NAME);
+}
+
+int mba_schemata_change(int cpu_no, char *bw_report, char **benchmark_cmd)
+{
+	struct resctrl_val_param param = {
+		.resctrl_val	= "mba",
+		.ctrlgrp	= "c1",
+		.mongrp		= "m1",
+		.cpu_no		= cpu_no,
+		.mum_resctrlfs	= 1,
+		.filename	= RESULT_FILE_NAME,
+		.bw_report	= bw_report,
+		.setup		= mba_setup
+	};
+	int ret;
+
+	remove(RESULT_FILE_NAME);
+
+	ret = validate_resctrl_feature_request("mba");
+	if (ret)
+		return ret;
+
+	ret = resctrl_val(benchmark_cmd, &param);
+	if (ret)
+		return ret;
+
+	ret = check_results();
+	if (ret)
+		return ret;
+
+	mba_test_cleanup();
+
+	return 0;
+}
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index 7f7ea180478c..92e5f2930c68 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -74,5 +74,7 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param);
 int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd);
 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);
 
 #endif /* RESCTRL_H */
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index a51780d28ff1..5fbfa8685b58 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -27,6 +27,7 @@ static void cmd_help(void)
 void tests_cleanup(void)
 {
 	mbm_test_cleanup();
+	mba_test_cleanup();
 }
 
 int main(int argc, char **argv)
@@ -34,7 +35,7 @@ int main(int argc, char **argv)
 	char benchmark_cmd_area[BENCHMARK_ARGS][BENCHMARK_ARG_SIZE];
 	int res, c, cpu_no = 1, span = 250, argc_new = argc, i;
 	int ben_ind;
-	bool has_ben = false, mbm_test = true;
+	bool has_ben = false, mbm_test = true, mba_test = true;
 	char *benchmark_cmd[BENCHMARK_ARGS];
 	char bw_report[64], bm_type[64];
 
@@ -55,9 +56,12 @@ int main(int argc, char **argv)
 			token = strtok(optarg, ",");
 
 			mbm_test = false;
+			mba_test = false;
 			while (token) {
 				if (!strcmp(token, "mbm")) {
 					mbm_test = true;
+				} else if (!strcmp(token, "mba")) {
+					mba_test = true;
 				} else {
 					printf("invalid argument\n");
 
@@ -110,5 +114,14 @@ int main(int argc, char **argv)
 			printf("Error in running tests for mbm bw change!\n");
 	}
 
+	if (mba_test) {
+		printf("\nMBA Schemata Change Starting..\n");
+		if (!has_ben)
+			sprintf(benchmark_cmd[1], "%d", span);
+		res = mba_schemata_change(cpu_no, bw_report, benchmark_cmd);
+		if (res)
+			printf("Error in tests for mba-change-schemata!\n");
+	}
+
 	return 0;
 }
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 08/13] selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (6 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 07/13] selftests/resctrl: Add MBA test Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:38   ` Andre Przywara
  2019-02-10  2:50 ` [PATCH v7 09/13] selftests/resctrl: Add Cache Allocation Technology (CAT) selftest Fenghua Yu
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>

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.

Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/Makefile        |   2 +-
 tools/testing/selftests/resctrl/cache.c         | 101 +++++++++++
 tools/testing/selftests/resctrl/cqm_test.c      | 173 ++++++++++++++++++
 tools/testing/selftests/resctrl/mba_test.c      |   1 +
 tools/testing/selftests/resctrl/mbm_test.c      |   1 +
 tools/testing/selftests/resctrl/resctrl.h       |  23 ++-
 tools/testing/selftests/resctrl/resctrl_tests.c |  56 ++++--
 tools/testing/selftests/resctrl/resctrl_val.c   |  95 ++++++----
 tools/testing/selftests/resctrl/resctrlfs.c     | 227 ++++++++++++++++++++++--
 9 files changed, 614 insertions(+), 65 deletions(-)
 create mode 100644 tools/testing/selftests/resctrl/cache.c
 create mode 100644 tools/testing/selftests/resctrl/cqm_test.c

diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
index 141cbdb619af..664561cd76e6 100644
--- a/tools/testing/selftests/resctrl/Makefile
+++ b/tools/testing/selftests/resctrl/Makefile
@@ -8,7 +8,7 @@ all: resctrl_tests
 
 resctrl_tests: *.o
 	$(CC) $(CFLAGS) -o resctrl_tests resctrl_tests.o resctrlfs.o \
-		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o
+		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o cache.o cqm_test.o
 
 .PHONY: clean
 
diff --git a/tools/testing/selftests/resctrl/cache.c b/tools/testing/selftests/resctrl/cache.c
new file mode 100644
index 000000000000..876dc647b3ca
--- /dev/null
+++ b/tools/testing/selftests/resctrl/cache.c
@@ -0,0 +1,101 @@
+// 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 cbm_mask[256];
+unsigned long long_mask;
+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;
+}
diff --git a/tools/testing/selftests/resctrl/cqm_test.c b/tools/testing/selftests/resctrl/cqm_test.c
new file mode 100644
index 000000000000..a81946ad11d1
--- /dev/null
+++ b/tools/testing/selftests/resctrl/cqm_test.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cache Monitoring Technology (CQM) test
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+ *    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;
+	long avg_diff = 0;
+	float diff_percent;
+
+	avg_llc_occu_resc = sum_llc_occu_resc / (NUM_OF_RUNS - 1);
+	avg_diff = (long)abs(span - avg_llc_occu_resc);
+
+	printf("\nResults are displayed in (Bytes)\n");
+	printf("\nNumber of bits: %d \t", no_of_bits);
+	printf("Avg_llc_occu_resc: %lu \t", avg_llc_occu_resc);
+	printf("llc_occu_exp (span): %lu \t", span);
+
+	diff_percent = (((float)span - avg_llc_occu_resc) / span) * 100;
+
+	printf("Diff: %ld \t", avg_diff);
+	printf("Percent diff=%d\t", abs((int)diff_percent));
+
+	if ((abs((int)diff_percent) <= MAX_DIFF_PERCENT) ||
+	    (abs(avg_diff) <= MAX_DIFF))
+		printf("Passed\n");
+	else
+		printf("Failed\n");
+}
+
+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("\nchecking 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;
+
+	ret = validate_resctrl_feature_request("cqm");
+	if (ret)
+		return ret;
+
+	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], "%llu", 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;
+}
diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c
index 71d8feb93ac8..329d1c84c82c 100644
--- a/tools/testing/selftests/resctrl/mba_test.c
+++ b/tools/testing/selftests/resctrl/mba_test.c
@@ -57,6 +57,7 @@ static void show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc)
 {
 	int allocation, failed = 0, runs;
 
+	printf("\nResults are displayed in (MB)\n");
 	/* Memory bandwidth from 100% down to 10% */
 	for (allocation = 0; allocation < ALLOCATION_MAX / ALLOCATION_STEP;
 	     allocation++) {
diff --git a/tools/testing/selftests/resctrl/mbm_test.c b/tools/testing/selftests/resctrl/mbm_test.c
index dba981c562ff..726e3a8fb98f 100644
--- a/tools/testing/selftests/resctrl/mbm_test.c
+++ b/tools/testing/selftests/resctrl/mbm_test.c
@@ -36,6 +36,7 @@ show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, int span)
 	avg_bw_resc = sum_bw_resc / 4;
 	avg_diff = avg_bw_resc - avg_bw_imc;
 
+	printf("\nResults are displayed in (MB)\n");
 	printf("\nSpan (MB): %d \t", span);
 	printf("avg_bw_imc: %lu\t", avg_bw_imc);
 	printf("avg_bw_resc: %lu\t", avg_bw_resc);
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index 92e5f2930c68..2097b02a356d 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -16,11 +16,18 @@
 #include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/types.h>
+#include <sys/select.h>
 #include <asm/unistd.h>
 #include <linux/perf_event.h>
+#include <sys/time.h>
+#include <math.h>
+#include <sys/wait.h>
+#include <sys/eventfd.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 {					\
@@ -46,14 +53,20 @@ struct resctrl_val_param {
 	char	ctrlgrp[64];
 	char	mongrp[64];
 	int	cpu_no;
-	int	span;
+	unsigned long long span;
 	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;
+extern char cbm_mask[256];
+extern unsigned long long_mask;
+extern char llc_occup_path[1024];
 
 int remount_resctrlfs(bool mum_resctrlfs);
 int get_resource_id(int cpu_no, int *resource_id);
@@ -76,5 +89,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 */
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index 5fbfa8685b58..5a9af019b5e5 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -16,11 +16,13 @@
 
 static void cmd_help(void)
 {
-	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list]\n");
-	printf("\t-b benchmark_cmd [options]: run specified benchmark\n");
+	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list] [-n no_of_bits]\n");
+	printf("\t-b benchmark_cmd [options]: run specified benchmark for MBM, MBA and CQM");
 	printf("\t default benchmark is builtin fill_buf\n");
 	printf("\t-t test list: run tests specified in the test list, ");
-	printf("e.g. -t mbm,mba\n");
+	printf("e.g. -t mbm, mba, cqm\n");
+	printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n");
+	printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n");
 	printf("\t-h: help\n");
 }
 
@@ -28,20 +30,22 @@ void tests_cleanup(void)
 {
 	mbm_test_cleanup();
 	mba_test_cleanup();
+	cqm_test_cleanup();
 }
 
 int main(int argc, char **argv)
 {
 	char benchmark_cmd_area[BENCHMARK_ARGS][BENCHMARK_ARG_SIZE];
-	int res, c, cpu_no = 1, span = 250, argc_new = argc, i;
-	int ben_ind;
-	bool has_ben = false, mbm_test = true, mba_test = true;
+	int res, c, cpu_no = 1, span = 250, argc_new = argc, i, no_of_bits = 5;
+	int ben_ind, ben_count;
+	bool has_ben = false, mbm_test = true, mba_test = true, cqm_test = true;
 	char *benchmark_cmd[BENCHMARK_ARGS];
 	char bw_report[64], bm_type[64];
 
 	for (i = 0; i < argc; i++) {
 		if (strcmp(argv[i], "-b") == 0) {
 			ben_ind = i + 1;
+			ben_count = argc - ben_ind;
 			argc_new = ben_ind - 1;
 			has_ben = 1;
 			break;
@@ -57,11 +61,14 @@ int main(int argc, char **argv)
 
 			mbm_test = false;
 			mba_test = false;
+			cqm_test = false;
 			while (token) {
 				if (!strcmp(token, "mbm")) {
 					mbm_test = true;
 				} else if (!strcmp(token, "mba")) {
 					mba_test = true;
+				} else if (!strcmp(token, "cqm")) {
+					cqm_test = true;
 				} else {
 					printf("invalid argument\n");
 
@@ -70,6 +77,12 @@ int main(int argc, char **argv)
 				token = strtok(NULL, ":\t");
 			}
 			break;
+		case 'n':
+			no_of_bits = atoi(optarg);
+			break;
+		case 'p':
+			cpu_no = atoi(optarg);
+			break;
 		case 'h':
 			cmd_help();
 
@@ -92,16 +105,25 @@ int main(int argc, char **argv)
 		return errno;
 	}
 
-	if (!has_ben) {
+	if (has_ben) {
+		/* Extract benchmark command from command line. */
+		for (i = ben_ind; i < argc; i++) {
+			benchmark_cmd[i - ben_ind] = benchmark_cmd_area[i];
+			sprintf(benchmark_cmd[i - ben_ind], "%s", argv[i]);
+		}
+		benchmark_cmd[ben_count] = NULL;
+	} else {
 		/* If no benchmark is given by "-b" argument, use fill_buf. */
-		for (i = 0; i < 5; i++)
+		for (i = 0; i < 6; i++)
 			benchmark_cmd[i] = benchmark_cmd_area[i];
+
 		strcpy(benchmark_cmd[0], "fill_buf");
 		sprintf(benchmark_cmd[1], "%d", span);
 		strcpy(benchmark_cmd[2], "1");
 		strcpy(benchmark_cmd[3], "1");
 		strcpy(benchmark_cmd[4], "0");
-		benchmark_cmd[5] = NULL;
+		strcpy(benchmark_cmd[5], "");
+		benchmark_cmd[6] = NULL;
 	}
 
 	sprintf(bw_report, "reads");
@@ -109,18 +131,32 @@ int main(int argc, char **argv)
 
 	if (mbm_test) {
 		printf("\nMBM BW Change Starting..\n");
+		if (!has_ben)
+			sprintf(benchmark_cmd[5], "%s", "mbm");
 		res = mbm_bw_change(span, cpu_no, bw_report, benchmark_cmd);
 		if (res)
 			printf("Error in running tests for mbm bw change!\n");
+		mbm_test_cleanup();
 	}
 
 	if (mba_test) {
 		printf("\nMBA Schemata Change Starting..\n");
 		if (!has_ben)
-			sprintf(benchmark_cmd[1], "%d", span);
+			sprintf(benchmark_cmd[5], "%s", "mba");
 		res = mba_schemata_change(cpu_no, bw_report, benchmark_cmd);
 		if (res)
 			printf("Error in tests for mba-change-schemata!\n");
+		mba_test_cleanup();
+	}
+
+	if (cqm_test) {
+		printf("\nCQM Test Starting..\n");
+		if (!has_ben)
+			sprintf(benchmark_cmd[5], "%s", "cqm");
+		res = cqm_resctrl_val(cpu_no, no_of_bits, benchmark_cmd);
+		if (res)
+			printf("Error in CQM test!\n");
+		cqm_test_cleanup();
 	}
 
 	return 0;
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
index 200a5b6756da..edf6a38d6457 100644
--- a/tools/testing/selftests/resctrl/resctrl_val.c
+++ b/tools/testing/selftests/resctrl/resctrl_val.c
@@ -11,7 +11,6 @@
  */
 #include "resctrl.h"
 
-#define MB			(1024 * 1024)
 #define UNCORE_IMC		"uncore_imc"
 #define READ_FILE_NAME		"events/cas_count_read"
 #define WRITE_FILE_NAME		"events/cas_count_write"
@@ -33,6 +32,18 @@
 #define MBM_LOCAL_BYTES_PATH			\
 	"%s/mon_data/mon_L3_%02d/mbm_local_bytes"
 
+#define CON_MON_LCC_OCCUP_PATH		\
+	"%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
+
+#define CON_LCC_OCCUP_PATH		\
+	"%s/%s/mon_data/mon_L3_%02d/llc_occupancy"
+
+#define MON_LCC_OCCUP_PATH		\
+	"%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
+
+#define LCC_OCCUP_PATH			\
+	"%s/mon_data/mon_L3_%02d/llc_occupancy"
+
 struct membw_read_format {
 	__u64 value;         /* The value of the event */
 	__u64 time_enabled;  /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
@@ -207,12 +218,12 @@ static int read_from_imc_dir(char *imc_dir, int count)
  * A config again has two parts, event and umask.
  * Enumerate all these details into an array of structures.
  *
- * Return: >= 0 on success. < 0 on failure.
+ * Return: > 0 on success. <= 0 on failure.
  */
 static int num_of_imcs(void)
 {
 	unsigned int count = 0;
-	char imc_dir[1024];
+	char imc_dir[512];
 	struct dirent *ep;
 	int ret;
 	DIR *dp;
@@ -434,16 +445,6 @@ static unsigned long get_mem_bw_resctrl(void)
 
 pid_t bm_pid, ppid;
 
-static void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
-{
-	kill(bm_pid, SIGKILL);
-	umount_resctrlfs();
-	tests_cleanup();
-	printf("Ending\n\n");
-
-	exit(EXIT_SUCCESS);
-}
-
 /*
  * print_results_bw:	the memory bandwidth results are stored in a file
  * @filename:		file that stores the results
@@ -482,6 +483,42 @@ static int print_results_bw(char *filename,  int bm_pid, float bw_imc,
 	return 0;
 }
 
+static void set_cqm_path(const char *ctrlgrp, const char *mongrp, char sock_num)
+{
+	if (strlen(ctrlgrp) && strlen(mongrp))
+		sprintf(llc_occup_path,	CON_MON_LCC_OCCUP_PATH,	RESCTRL_PATH,
+			ctrlgrp, mongrp, sock_num);
+	else if (!strlen(ctrlgrp) && strlen(mongrp))
+		sprintf(llc_occup_path,	MON_LCC_OCCUP_PATH, RESCTRL_PATH,
+			mongrp, sock_num);
+	else if (strlen(ctrlgrp) && !strlen(mongrp))
+		sprintf(llc_occup_path,	CON_LCC_OCCUP_PATH, RESCTRL_PATH,
+			ctrlgrp, sock_num);
+	else if (!strlen(ctrlgrp) && !strlen(mongrp))
+		sprintf(llc_occup_path, LCC_OCCUP_PATH,	RESCTRL_PATH, sock_num);
+}
+
+/*
+ * initialize_llc_occu_resctrl:	Appropriately populate "llc_occup_path"
+ * @ctrlgrp:			Name of the control monitor group (con_mon grp)
+ * @mongrp:			Name of the monitor group (mon grp)
+ * @cpu_no:			CPU number that the benchmark PID is binded to
+ * @resctrl_val:		Resctrl feature (Eg: cat, cqm.. etc)
+ */
+static void initialize_llc_occu_resctrl(const char *ctrlgrp, const char *mongrp,
+					int cpu_no, char *resctrl_val)
+{
+	int resource_id;
+
+	if (get_resource_id(cpu_no, &resource_id) < 0) {
+		perror("Unable to resource_id");
+		return;
+	}
+
+	if (strcmp(resctrl_val, "cqm") == 0)
+		set_cqm_path(ctrlgrp, mongrp, resource_id);
+}
+
 static int
 measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
 {
@@ -528,14 +565,10 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
 	unsigned long bw_resc_start = 0;
 	struct sigaction sigact;
 	union sigval value;
-	FILE *fp;
 
 	if (strcmp(param->filename, "") == 0)
 		sprintf(param->filename, "stdio");
 
-	if (strcmp(param->bw_report, "") == 0)
-		param->bw_report = "total";
-
 	if ((strcmp(resctrl_val, "mba")) == 0 ||
 	    (strcmp(resctrl_val, "mbm")) == 0) {
 		ret = validate_bw_report_request(param->bw_report);
@@ -553,21 +586,6 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
 	 */
 	ppid = getpid();
 
-	/* File based synchronization between parent and child */
-	fp = fopen("sig", "w");
-	if (!fp) {
-		perror("Failed to open sig file");
-
-		return -1;
-	}
-	if (fprintf(fp, "%d\n", 0) <= 0) {
-		perror("Unable to establish sync bw parent & child");
-		fclose(fp);
-
-		return -1;
-	}
-	fclose(fp);
-
 	if (pipe(pipefd)) {
 		perror("Unable to create pipe");
 
@@ -649,7 +667,9 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
 
 		initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
 					  param->cpu_no, resctrl_val);
-	}
+	} else if (strcmp(resctrl_val, "cqm") == 0)
+		initialize_llc_occu_resctrl(param->ctrlgrp, param->mongrp,
+					    param->cpu_no, resctrl_val);
 
 	/* Parent waits for child to be ready. */
 	close(pipefd[1]);
@@ -669,7 +689,8 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
 
 	/* Test runs until the callback setup() tells the test to stop. */
 	while (1) {
-		if (strcmp(resctrl_val, "mbm") == 0) {
+		if ((strcmp(resctrl_val, "mbm") == 0) ||
+		    (strcmp(resctrl_val, "mba") == 0)) {
 			ret = param->setup(1, param);
 			if (ret) {
 				ret = 0;
@@ -679,14 +700,14 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
 			ret = measure_vals(param, &bw_resc_start);
 			if (ret)
 				break;
-		} else if ((strcmp(resctrl_val, "mba") == 0)) {
+		} else if (strcmp(resctrl_val, "cqm") == 0) {
 			ret = param->setup(1, param);
 			if (ret) {
 				ret = 0;
 				break;
 			}
-
-			ret = measure_vals(param, &bw_resc_start);
+			sleep(1);
+			ret = measure_cache_vals(param, bm_pid);
 			if (ret)
 				break;
 		} else {
diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
index 5afcaa89f418..6dacd215ace6 100644
--- a/tools/testing/selftests/resctrl/resctrlfs.c
+++ b/tools/testing/selftests/resctrl/resctrlfs.c
@@ -13,12 +13,18 @@
 
 #define RESCTRL_MBM		"L3 monitoring detected"
 #define RESCTRL_MBA		"MB allocation detected"
+#define RESCTRL_CQM		"L3 monitoring detected"
+#define CORE_SIBLINGS_PATH	"/sys/bus/cpu/devices/cpu"
+
 enum {
 	RESCTRL_FEATURE_MBM,
 	RESCTRL_FEATURE_MBA,
+	RESCTRL_FEATURE_CQM,
 	MAX_RESCTRL_FEATURES
 };
 
+char cbm_mask[256];
+
 /*
  * remount_resctrlfs - Remount resctrl FS at /sys/fs/resctrl
  * @mum_resctrlfs:	Should the resctrl FS be remounted?
@@ -62,7 +68,7 @@ int remount_resctrlfs(bool mum_resctrlfs)
 
 				return errno;
 			}
-			printf("Remount: done!\n");
+			printf("umount: done!\n");
 		} else {
 			printf("Mounted already. Not remounting!\n");
 
@@ -122,6 +128,143 @@ int get_resource_id(int cpu_no, int *resource_id)
 }
 
 /*
+ * get_cache_size - Get cache size for a specified CPU
+ * @cpu_no:	CPU number
+ * @cache_type:	Cache level L2/L3
+ * @cache_size:	pointer to cache_size
+ *
+ * Return: = 0 on success, < 0 on failure.
+ */
+int get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size)
+{
+	char cache_path[1024], cache_str[64];
+	int length, i, cache_num;
+	FILE *fp;
+
+	if (!strcmp(cache_type, "L3")) {
+		cache_num = 3;
+	} else if (!strcmp(cache_type, "L2")) {
+		cache_num = 2;
+	} else {
+		perror("Invalid cache level");
+		return -1;
+	}
+
+	sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size",
+		cpu_no, cache_num);
+	fp = fopen(cache_path, "r");
+	if (!fp) {
+		perror("Failed to open cache size");
+
+		return -1;
+	}
+	if (fscanf(fp, "%s", cache_str) <= 0) {
+		perror("Could not get cache_size");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	length = (int)strlen(cache_str);
+
+	*cache_size = 0;
+
+	for (i = 0; i < length; i++) {
+		if ((cache_str[i] >= '0') && (cache_str[i] <= '9'))
+
+			*cache_size = *cache_size * 10 + (cache_str[i] - '0');
+
+		else if (cache_str[i] == 'K')
+
+			*cache_size = *cache_size * 1024;
+
+		else if (cache_str[i] == 'M')
+
+			*cache_size = *cache_size * 1024 * 1024;
+
+		else
+			break;
+	}
+
+	return 0;
+}
+
+/*
+ * get_cbm_mask - Get cbm mask for given cache
+ * @cache_type:	Cache level L2/L3
+ *
+ * Mask is stored in cbm_mask which is global variable.
+ *
+ * Return: = 0 on success, < 0 on failure.
+ */
+int get_cbm_mask(char *cache_type)
+{
+	char cbm_mask_path[1024];
+	FILE *fp;
+
+	sprintf(cbm_mask_path, "%s/%s/cbm_mask", CBM_MASK_PATH, cache_type);
+
+	fp = fopen(cbm_mask_path, "r");
+	if (!fp) {
+		perror("Failed to open cache level");
+
+		return -1;
+	}
+	if (fscanf(fp, "%s", cbm_mask) <= 0) {
+		perror("Could not get max cbm_mask");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	return 0;
+}
+
+/*
+ * get_core_sibling - Get sibling core id from the same socket for given CPU
+ * @cpu_no:	CPU number
+ *
+ * Return:	> 0 on success, < 0 on failure.
+ */
+int get_core_sibling(int cpu_no)
+{
+	char core_siblings_path[1024], cpu_list_str[64];
+	int sibling_cpu_no = -1;
+	FILE *fp;
+
+	sprintf(core_siblings_path, "%s%d/topology/core_siblings_list",
+		CORE_SIBLINGS_PATH, cpu_no);
+
+	fp = fopen(core_siblings_path, "r");
+	if (!fp) {
+		perror("Failed to open core siblings path");
+
+		return -1;
+	}
+	if (fscanf(fp, "%s", cpu_list_str) <= 0) {
+		perror("Could not get core_siblings list");
+		fclose(fp);
+
+		return -1;
+	}
+	fclose(fp);
+
+	char *token = strtok(cpu_list_str, "-,");
+
+	while (token) {
+		sibling_cpu_no = atoi(token);
+		/* Skipping core 0 as we don't want to run test on core 0 */
+		if (sibling_cpu_no != 0)
+			break;
+		token = strtok(NULL, "-,");
+	}
+
+	return sibling_cpu_no;
+}
+
+/*
  * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
  * @bm_pid:	PID that should be binded
  * @cpu_no:	CPU number at which the PID would be binded
@@ -157,9 +300,10 @@ int taskset_benchmark(pid_t bm_pid, int cpu_no)
  */
 void run_benchmark(int signum, siginfo_t *info, void *ucontext)
 {
-	unsigned long long span;
-	int operation, ret;
+	int operation, ret, malloc_and_init_memory, memflush;
+	unsigned long long span, buffer_span;
 	char **benchmark_cmd;
+	char resctrl_val[64];
 	FILE *fp;
 
 	benchmark_cmd = info->si_ptr;
@@ -175,8 +319,18 @@ void run_benchmark(int signum, siginfo_t *info, void *ucontext)
 	if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
 		/* Execute default fill_buf benchmark */
 		span = strtoul(benchmark_cmd[1], NULL, 10);
+		malloc_and_init_memory = atoi(benchmark_cmd[2]);
+		memflush =  atoi(benchmark_cmd[3]);
 		operation = atoi(benchmark_cmd[4]);
-		if (run_fill_buf(span, 1, 1, operation, NULL))
+		sprintf(resctrl_val, "%s", benchmark_cmd[5]);
+
+		if (strcmp(resctrl_val, "cqm") != 0)
+			buffer_span = span * MB;
+		else
+			buffer_span = span;
+
+		if (run_fill_buf(buffer_span, malloc_and_init_memory, memflush,
+				 operation, resctrl_val))
 			fprintf(stderr, "Error in running fill buffer\n");
 	} else {
 		/* Execute specified benchmark */
@@ -203,6 +357,14 @@ static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
 	struct dirent *ep;
 	DIR *dp;
 
+	/*
+	 * At this point, we are guaranteed to have resctrl FS mounted and if
+	 * length of grp_name == 0, it means, user wants to use root con_mon
+	 * grp, so do nothing
+	 */
+	if (strlen(grp_name) == 0)
+		return 0;
+
 	/* Check if requested grp exists or not */
 	dp = opendir(parent_grp);
 	if (dp) {
@@ -268,11 +430,11 @@ static int write_pid_to_tasks(char *tasks, pid_t pid)
 int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
 			    char *resctrl_val)
 {
-	char controlgroup[256], monitorgroup[256], monitorgroup_p[256];
-	char tasks[256];
+	char controlgroup[128], monitorgroup[512], monitorgroup_p[256];
+	char tasks[1024];
 	int ret;
 
-	if (ctrlgrp)
+	if (strlen(ctrlgrp))
 		sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
 	else
 		sprintf(controlgroup, "%s", RESCTRL_PATH);
@@ -286,9 +448,10 @@ int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
 	if (ret)
 		return ret;
 
-	/* Create mon grp and write pid into it for "mbm" test */
-	if ((strcmp(resctrl_val, "mbm") == 0)) {
-		if (mongrp) {
+	/* Create mon grp and write pid into it for "mbm" and "cqm" test */
+	if ((strcmp(resctrl_val, "cqm") == 0) ||
+	    (strcmp(resctrl_val, "mbm") == 0)) {
+		if (strlen(mongrp)) {
 			sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
 			sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
 			ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
@@ -326,7 +489,8 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
 	int resource_id;
 	FILE *fp;
 
-	if (strcmp(resctrl_val, "mba") == 0) {
+	if ((strcmp(resctrl_val, "mba") == 0) ||
+	    (strcmp(resctrl_val, "cqm") == 0)) {
 		if (!schemata) {
 			printf("Schemata empty, so not updating\n");
 
@@ -337,12 +501,18 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
 			return -1;
 		}
 
-		if (ctrlgrp)
+		if (strlen(ctrlgrp) != 0)
 			sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH,
 				ctrlgrp);
 		else
 			sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
-		sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=', schemata);
+
+		if (!strcmp(resctrl_val, "cqm"))
+			sprintf(schema, "%s%d%c%s", "L3:", resource_id, '=',
+				schemata);
+		if (strcmp(resctrl_val, "mba") == 0)
+			sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=',
+				schemata);
 
 		fp = fopen(controlgroup, "w");
 		if (!fp) {
@@ -359,7 +529,7 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
 		}
 		fclose(fp);
 
-		printf("Write schemata to resctrl FS: done!\n");
+		printf("Write schemata with %s to resctrl FS: done!\n", schema);
 	}
 
 	return 0;
@@ -375,7 +545,7 @@ int validate_resctrl_feature_request(char *resctrl_val)
 {
 	int resctrl_features_supported[MAX_RESCTRL_FEATURES];
 	const char *resctrl_features_list[MAX_RESCTRL_FEATURES] = {
-			"mbm", "mba"};
+			"mbm", "mba", "cqm"};
 	int i, valid_resctrl_feature = -1;
 	char line[1024];
 	FILE *fp;
@@ -419,6 +589,9 @@ int validate_resctrl_feature_request(char *resctrl_val)
 			resctrl_features_supported[RESCTRL_FEATURE_MBM] = 1;
 		if ((strstr(line, RESCTRL_MBA)) != NULL)
 			resctrl_features_supported[RESCTRL_FEATURE_MBA] = 1;
+		if ((strstr(line, RESCTRL_CQM)) != NULL)
+			resctrl_features_supported[RESCTRL_FEATURE_CQM] = 1;
+
 	}
 	fclose(fp);
 
@@ -427,7 +600,7 @@ int validate_resctrl_feature_request(char *resctrl_val)
 
 	/* Is the resctrl feature request supported? */
 	if (!resctrl_features_supported[valid_resctrl_feature]) {
-		fprintf(stderr, "resctrl feature not supported!");
+		fprintf(stderr, "resctrl feature not supported!\n");
 
 		return -1;
 	}
@@ -462,3 +635,25 @@ int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
 		      group_fd, flags);
 	return ret;
 }
+
+void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
+{
+	kill(bm_pid, SIGKILL);
+	umount_resctrlfs();
+	tests_cleanup();
+	printf("Ending\n\n");
+
+	exit(EXIT_SUCCESS);
+}
+
+unsigned int count_bits(unsigned long n)
+{
+	unsigned int count = 0;
+
+	while (n) {
+		count += n & 1;
+		n >>= 1;
+	}
+
+	return count;
+}
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 09/13] selftests/resctrl: Add Cache Allocation Technology (CAT) selftest
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (7 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 08/13] selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:38   ` Andre Przywara
  2019-02-10  2:50 ` [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism Fenghua Yu
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>

Cache Allocation Technology (CAT) selftest allocates a portion of
last level cache and starts a benchmark to read each cache
line in this portion of cache. Measure the cache misses in perf and
the misses should be equal to the number of cache lines in this
portion of cache.

We don't use CQM to calculate cache usage because some CAT enabled
platforms don't have CQM.

Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 tools/testing/selftests/resctrl/Makefile        |   2 +-
 tools/testing/selftests/resctrl/cache.c         | 175 ++++++++++++++++-
 tools/testing/selftests/resctrl/cat_test.c      | 242 ++++++++++++++++++++++++
 tools/testing/selftests/resctrl/fill_buf.c      |  10 +-
 tools/testing/selftests/resctrl/resctrl.h       |   3 +
 tools/testing/selftests/resctrl/resctrl_tests.c |  14 +-
 tools/testing/selftests/resctrl/resctrlfs.c     |  10 +-
 7 files changed, 448 insertions(+), 8 deletions(-)
 create mode 100644 tools/testing/selftests/resctrl/cat_test.c

diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
index 664561cd76e6..0282222b4c22 100644
--- a/tools/testing/selftests/resctrl/Makefile
+++ b/tools/testing/selftests/resctrl/Makefile
@@ -8,7 +8,7 @@ all: resctrl_tests
 
 resctrl_tests: *.o
 	$(CC) $(CFLAGS) -o resctrl_tests resctrl_tests.o resctrlfs.o \
-		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o cache.o cqm_test.o
+		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o cache.o cqm_test.o cat_test.o
 
 .PHONY: clean
 
diff --git a/tools/testing/selftests/resctrl/cache.c b/tools/testing/selftests/resctrl/cache.c
index 876dc647b3ca..04b7aafdb409 100644
--- a/tools/testing/selftests/resctrl/cache.c
+++ b/tools/testing/selftests/resctrl/cache.c
@@ -10,10 +10,107 @@ struct read_format {
 	} values[2];
 };
 
+static struct perf_event_attr pea_llc_miss;
+static struct read_format rf_cqm;
+static int fd_lm;
 char cbm_mask[256];
 unsigned long long_mask;
 char llc_occup_path[1024];
 
+static void initialize_perf_event_attr(void)
+{
+	pea_llc_miss.type = PERF_TYPE_HARDWARE;
+	pea_llc_miss.size = sizeof(struct perf_event_attr);
+	pea_llc_miss.read_format = PERF_FORMAT_GROUP;
+	pea_llc_miss.exclude_kernel = 1;
+	pea_llc_miss.exclude_hv = 1;
+	pea_llc_miss.exclude_idle = 1;
+	pea_llc_miss.exclude_callchain_kernel = 1;
+	pea_llc_miss.inherit = 1;
+	pea_llc_miss.exclude_guest = 1;
+	pea_llc_miss.disabled = 1;
+}
+
+static void ioctl_perf_event_ioc_reset_enable(void)
+{
+	ioctl(fd_lm, PERF_EVENT_IOC_RESET, 0);
+	ioctl(fd_lm, PERF_EVENT_IOC_ENABLE, 0);
+}
+
+static int perf_event_open_llc_miss(pid_t pid, int cpu_no)
+{
+	fd_lm = perf_event_open(&pea_llc_miss, pid, cpu_no, -1,
+				PERF_FLAG_FD_CLOEXEC);
+	if (fd_lm == -1) {
+		perror("Error opening leader");
+		ctrlc_handler(0, NULL, NULL);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int initialize_llc_perf(void)
+{
+	memset(&pea_llc_miss, 0, sizeof(struct perf_event_attr));
+	memset(&rf_cqm, 0, sizeof(struct read_format));
+
+	/* Initialize perf_event_attr structures for HW_CACHE_MISSES */
+	initialize_perf_event_attr();
+
+	pea_llc_miss.config = PERF_COUNT_HW_CACHE_MISSES;
+
+	rf_cqm.nr = 1;
+
+	return 0;
+}
+
+static int reset_enable_llc_perf(pid_t pid, int cpu_no)
+{
+	int ret = 0;
+
+	ret = perf_event_open_llc_miss(pid, cpu_no);
+	if (ret < 0)
+		return ret;
+
+	/* Start counters to log values */
+	ioctl_perf_event_ioc_reset_enable();
+
+	return 0;
+}
+
+/*
+ * get_llc_perf:	llc cache miss through perf events
+ * @cpu_no:		CPU number that the benchmark PID is binded to
+ *
+ * Perf events like HW_CACHE_MISSES could be used to validate number of
+ * cache lines allocated.
+ *
+ * Return: =0 on success.  <0 on failure.
+ */
+static int get_llc_perf(unsigned long *llc_perf_miss)
+{
+	__u64 total_misses;
+
+	/* Stop counters after one span to get miss rate */
+
+	ioctl(fd_lm, PERF_EVENT_IOC_DISABLE, 0);
+
+	if (read(fd_lm, &rf_cqm, sizeof(struct read_format)) == -1) {
+		perror("Could not get llc misses through perf");
+
+		return -1;
+	}
+
+	total_misses = rf_cqm.values[0].value;
+
+	close(fd_lm);
+
+	*llc_perf_miss = total_misses;
+
+	return 0;
+}
+
 /*
  * Get LLC Occupancy as reported by RESCTRL FS
  * For CQM,
@@ -81,10 +178,20 @@ static int print_results_cache(char *filename, int bm_pid,
 
 int measure_cache_vals(struct resctrl_val_param *param, int bm_pid)
 {
-	unsigned long llc_occu_resc = 0, llc_value = 0;
+	unsigned long llc_perf_miss = 0, llc_occu_resc = 0, llc_value = 0;
 	int ret;
 
 	/*
+	 * Measure cache miss from perf.
+	 */
+	if (!strcmp(param->resctrl_val, "cat")) {
+		ret = get_llc_perf(&llc_perf_miss);
+		if (ret < 0)
+			return ret;
+		llc_value = llc_perf_miss;
+	}
+
+	/*
 	 * Measure llc occupancy from resctrl.
 	 */
 	if (!strcmp(param->resctrl_val, "cqm")) {
@@ -99,3 +206,69 @@ int measure_cache_vals(struct resctrl_val_param *param, int bm_pid)
 
 	return 0;
 }
+
+/*
+ * cache_val:		execute benchmark and measure LLC occupancy resctrl
+ * and perf cache miss for the benchmark
+ * @param:		parameters passed to cache_val()
+ *
+ * Return:		0 on success. non-zero on failure.
+ */
+int cat_val(struct resctrl_val_param *param)
+{
+	int malloc_and_init_memory = 1, memflush = 1, operation = 0, ret = 0;
+	char *resctrl_val = param->resctrl_val;
+	pid_t bm_pid;
+
+	if (strcmp(param->filename, "") == 0)
+		sprintf(param->filename, "stdio");
+
+	bm_pid = getpid();
+
+	/* Taskset benchmark to specified cpu */
+	ret = taskset_benchmark(bm_pid, param->cpu_no);
+	if (ret)
+		return ret;
+
+	/* Write benchmark to specified con_mon grp, mon_grp in resctrl FS*/
+	ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
+				      resctrl_val);
+	if (ret)
+		return ret;
+
+	if ((strcmp(resctrl_val, "cat") == 0)) {
+		ret = initialize_llc_perf();
+		if (ret)
+			return ret;
+	}
+
+	/* Test runs until the callback setup() tells the test to stop. */
+	while (1) {
+		if (strcmp(resctrl_val, "cat") == 0) {
+			ret = param->setup(1, param);
+			if (ret) {
+				ret = 0;
+				break;
+			}
+			ret = reset_enable_llc_perf(bm_pid, param->cpu_no);
+			if (ret)
+				break;
+
+			if (run_fill_buf(param->span, malloc_and_init_memory,
+					 memflush, operation, resctrl_val)) {
+				fprintf(stderr, "Error-running fill buffer\n");
+				ret = -1;
+				break;
+			}
+
+			sleep(1);
+			ret = measure_cache_vals(param, bm_pid);
+			if (ret)
+				break;
+		} else {
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c
new file mode 100644
index 000000000000..1a0f77e4f7bf
--- /dev/null
+++ b/tools/testing/selftests/resctrl/cat_test.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Cache Allocation Technology (CAT) test
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
+ *    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
+
+int count_of_bits;
+char cbm_mask[256];
+unsigned long long_mask;
+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 void show_cache_info(unsigned long sum_llc_perf_miss, int no_of_bits,
+			    unsigned long span)
+{
+	unsigned long allocated_cache_lines = span / 64;
+	unsigned long avg_llc_perf_miss = 0;
+	float diff_percent;
+
+	avg_llc_perf_miss = sum_llc_perf_miss / (NUM_OF_RUNS - 1);
+	diff_percent = ((float)allocated_cache_lines - avg_llc_perf_miss) /
+				allocated_cache_lines * 100;
+	printf("Results are displayed in (Bytes)\n");
+	printf("\nNumber of bits: %d \t", no_of_bits);
+	printf("Avg_llc_perf_miss: %lu \t", avg_llc_perf_miss);
+	printf("Allocated cache lines: %lu \t", allocated_cache_lines);
+	printf("Percent diff=%d \t", abs((int)diff_percent));
+
+	if (abs((int)diff_percent) > MAX_DIFF_PERCENT)
+		printf("Failed\n");
+	else
+		printf("Passed\n");
+}
+
+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;
+
+	printf("\nChecking 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");
+		}
+		/*
+		 * 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);
+
+	show_cache_info(sum_llc_perf_miss, no_of_bits, param->span);
+
+	return 0;
+}
+
+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], pipe_message, mum_resctrlfs, sibling_cpu_no;
+	pid_t bm_pid;
+
+	cache_size = 0;
+	mum_resctrlfs = 1;
+
+	ret = remount_resctrlfs(mum_resctrlfs);
+	if (ret)
+		return ret;
+
+	ret = validate_resctrl_feature_request("cat");
+	if (ret)
+		return ret;
+
+	/* Get default cbm mask for L3/L2 cache */
+	ret = get_cbm_mask(cache_type);
+	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;
+	printf("cache size :%lu\n", cache_size);
+
+	/* Get max number of bits from default-cabm mask */
+	count_of_bits = count_bits(long_mask);
+
+	if (n < 1 || n > count_of_bits - 1) {
+		printf("Invalid input value for no_of_bits n!\n");
+		printf("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",
+		.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 -1;
+	}
+
+	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;
+		write(pipefd[1], &pipe_message, sizeof(pipe_message));
+		close(pipefd[1]);
+		while (1)
+			;
+	} else {
+		/* Parent waits for child to be ready. */
+		close(pipefd[1]);
+		pipe_message = 0;
+		while (pipe_message != 1)
+			read(pipefd[0], &pipe_message, sizeof(pipe_message));
+		close(pipefd[0]);
+		kill(bm_pid, SIGKILL);
+	}
+
+	cat_test_cleanup();
+	if (bm_pid)
+		umount_resctrlfs();
+
+	return 0;
+}
diff --git a/tools/testing/selftests/resctrl/fill_buf.c b/tools/testing/selftests/resctrl/fill_buf.c
index 792a5c40a32a..3244620d3676 100644
--- a/tools/testing/selftests/resctrl/fill_buf.c
+++ b/tools/testing/selftests/resctrl/fill_buf.c
@@ -110,8 +110,11 @@ static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
 	int ret = 0;
 	FILE *fp;
 
-	while (1)
+	while (1) {
 		ret = fill_one_span_read(start_ptr, end_ptr);
+		if (!strcmp(resctrl_val, "cat"))
+			break;
+	}
 
 	/* Consume read result so that reading memory is not optimized out. */
 	fp = fopen("/dev/null", "w");
@@ -126,8 +129,11 @@ static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
 static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr,
 			    char *resctrl_val)
 {
-	while (1)
+	while (1) {
 		fill_one_span_write(start_ptr, end_ptr);
+		if (!strcmp(resctrl_val, "cat"))
+			break;
+	}
 
 	return 0;
 }
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index 2097b02a356d..dadbb3d0cad8 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -92,6 +92,9 @@ 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 cat_val(struct resctrl_val_param *param);
+void cat_test_cleanup(void);
+int cat_perf_miss_val(int cpu_no, int no_of_bits, char *cache_type);
 int cqm_resctrl_val(int cpu_no, int n, char **benchmark_cmd);
 unsigned int count_bits(unsigned long n);
 void cqm_test_cleanup(void);
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index 5a9af019b5e5..3959b2b0671a 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -20,7 +20,7 @@ static void cmd_help(void)
 	printf("\t-b benchmark_cmd [options]: run specified benchmark for MBM, MBA and CQM");
 	printf("\t default benchmark is builtin fill_buf\n");
 	printf("\t-t test list: run tests specified in the test list, ");
-	printf("e.g. -t mbm, mba, cqm\n");
+	printf("e.g. -t mbm, mba, cqm, cat\n");
 	printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n");
 	printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n");
 	printf("\t-h: help\n");
@@ -31,6 +31,7 @@ void tests_cleanup(void)
 	mbm_test_cleanup();
 	mba_test_cleanup();
 	cqm_test_cleanup();
+	cat_test_cleanup();
 }
 
 int main(int argc, char **argv)
@@ -39,6 +40,7 @@ int main(int argc, char **argv)
 	int res, c, cpu_no = 1, span = 250, argc_new = argc, i, no_of_bits = 5;
 	int ben_ind, ben_count;
 	bool has_ben = false, mbm_test = true, mba_test = true, cqm_test = true;
+	bool cat_test = true;
 	char *benchmark_cmd[BENCHMARK_ARGS];
 	char bw_report[64], bm_type[64];
 
@@ -62,6 +64,7 @@ int main(int argc, char **argv)
 			mbm_test = false;
 			mba_test = false;
 			cqm_test = false;
+			cat_test = false;
 			while (token) {
 				if (!strcmp(token, "mbm")) {
 					mbm_test = true;
@@ -69,6 +72,8 @@ int main(int argc, char **argv)
 					mba_test = true;
 				} else if (!strcmp(token, "cqm")) {
 					cqm_test = true;
+				} else if (!strcmp(token, "cat")) {
+					cat_test = true;
 				} else {
 					printf("invalid argument\n");
 
@@ -158,6 +163,13 @@ int main(int argc, char **argv)
 			printf("Error in CQM test!\n");
 		cqm_test_cleanup();
 	}
+	if (cat_test) {
+		printf("\nCAT Test Starting..\n");
+		res = cat_perf_miss_val(cpu_no, no_of_bits, "L3");
+		if (res)
+			printf("Error in CAT test!\n");
+		cat_test_cleanup();
+	}
 
 	return 0;
 }
diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
index 6dacd215ace6..137b926955ca 100644
--- a/tools/testing/selftests/resctrl/resctrlfs.c
+++ b/tools/testing/selftests/resctrl/resctrlfs.c
@@ -14,12 +14,14 @@
 #define RESCTRL_MBM		"L3 monitoring detected"
 #define RESCTRL_MBA		"MB allocation detected"
 #define RESCTRL_CQM		"L3 monitoring detected"
+#define RESCTRL_L3_CAT		"L3 allocation detected"
 #define CORE_SIBLINGS_PATH	"/sys/bus/cpu/devices/cpu"
 
 enum {
 	RESCTRL_FEATURE_MBM,
 	RESCTRL_FEATURE_MBA,
 	RESCTRL_FEATURE_CQM,
+	RESCTRL_FEATURE_L3_CAT,
 	MAX_RESCTRL_FEATURES
 };
 
@@ -490,6 +492,7 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
 	FILE *fp;
 
 	if ((strcmp(resctrl_val, "mba") == 0) ||
+	    (strcmp(resctrl_val, "cat") == 0) ||
 	    (strcmp(resctrl_val, "cqm") == 0)) {
 		if (!schemata) {
 			printf("Schemata empty, so not updating\n");
@@ -507,7 +510,7 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
 		else
 			sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
 
-		if (!strcmp(resctrl_val, "cqm"))
+		if (!strcmp(resctrl_val, "cat") || !strcmp(resctrl_val, "cqm"))
 			sprintf(schema, "%s%d%c%s", "L3:", resource_id, '=',
 				schemata);
 		if (strcmp(resctrl_val, "mba") == 0)
@@ -545,7 +548,7 @@ int validate_resctrl_feature_request(char *resctrl_val)
 {
 	int resctrl_features_supported[MAX_RESCTRL_FEATURES];
 	const char *resctrl_features_list[MAX_RESCTRL_FEATURES] = {
-			"mbm", "mba", "cqm"};
+			"mbm", "mba", "cat", "cqm"};
 	int i, valid_resctrl_feature = -1;
 	char line[1024];
 	FILE *fp;
@@ -591,7 +594,8 @@ int validate_resctrl_feature_request(char *resctrl_val)
 			resctrl_features_supported[RESCTRL_FEATURE_MBA] = 1;
 		if ((strstr(line, RESCTRL_CQM)) != NULL)
 			resctrl_features_supported[RESCTRL_FEATURE_CQM] = 1;
-
+		if ((strstr(line, RESCTRL_L3_CAT)) != NULL)
+			resctrl_features_supported[RESCTRL_FEATURE_L3_CAT] = 1;
 	}
 	fclose(fp);
 
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (8 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 09/13] selftests/resctrl: Add Cache Allocation Technology (CAT) selftest Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:39   ` Andre Przywara
  2019-02-10  2:50 ` [PATCH v7 11/13] selftests/resctrl: Use cache index3 id for AMD schemata masks Fenghua Yu
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Babu Moger <babu.moger@amd.com>

RESCTRL feature is supported both on Intel and AMD now. Some features
are implemented differently. Add vendor detection mechanism. Use the vendor
check where there are differences.

Signed-off-by: Babu Moger <babu.moger@amd.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---
 tools/testing/selftests/resctrl/resctrl.h       | 13 +++++
 tools/testing/selftests/resctrl/resctrl_tests.c | 63 +++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index dadbb3d0cad8..974ec2de5fee 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -63,10 +63,23 @@ struct resctrl_val_param {
 
 };
 
+/**
+ * Results of CPUID operation are stored in this structure.
+ * It consists of 4x32bits IA registers: EAX, EBX, ECX and EDX.
+ */
+struct cpuid_out {
+	uint32_t eax;
+	uint32_t ebx;
+	uint32_t ecx;
+	uint32_t edx;
+};
+
 pid_t bm_pid, ppid;
 extern char cbm_mask[256];
 extern unsigned long long_mask;
 extern char llc_occup_path[1024];
+extern int genuine_intel;
+extern int authentic_amd;
 
 int remount_resctrlfs(bool mum_resctrlfs);
 int get_resource_id(int cpu_no, int *resource_id);
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index 3959b2b0671a..1d9adcfbdb4c 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -14,6 +14,66 @@
 #define BENCHMARK_ARGS		64
 #define BENCHMARK_ARG_SIZE	64
 
+/**
+ * This variables provides information about the vendor
+ */
+int genuine_intel;
+int authentic_amd;
+
+void lcpuid(const unsigned int leaf, const unsigned int subleaf,
+	    struct cpuid_out *out)
+{
+	if (!out)
+		return;
+
+#ifdef __x86_64__
+	asm volatile("mov %4, %%eax\n\t"
+		     "mov %5, %%ecx\n\t"
+		     "cpuid\n\t"
+		     "mov %%eax, %0\n\t"
+		     "mov %%ebx, %1\n\t"
+		     "mov %%ecx, %2\n\t"
+		     "mov %%edx, %3\n\t"
+		     : "=g" (out->eax), "=g" (out->ebx), "=g" (out->ecx),
+		     "=g" (out->edx)
+		     : "g" (leaf), "g" (subleaf)
+		     : "%eax", "%ebx", "%ecx", "%edx");
+#else
+	asm volatile("push %%ebx\n\t"
+		     "mov %4, %%eax\n\t"
+		     "mov %5, %%ecx\n\t"
+		     "cpuid\n\t"
+		     "mov %%eax, %0\n\t"
+		     "mov %%ebx, %1\n\t"
+		     "mov %%ecx, %2\n\t"
+		     "mov %%edx, %3\n\t"
+		     "pop %%ebx\n\t"
+		     : "=g" (out->eax), "=g" (out->ebx), "=g" (out->ecx),
+		     "=g" (out->edx)
+		     : "g" (leaf), "g" (subleaf)
+		     : "%eax", "%ecx", "%edx");
+#endif
+}
+
+int detect_vendor(void)
+{
+	struct cpuid_out vendor;
+	int ret = 0;
+
+	lcpuid(0x0, 0x0, &vendor);
+	if (vendor.ebx == 0x756e6547 && vendor.edx == 0x49656e69 &&
+	    vendor.ecx == 0x6c65746e) {
+		genuine_intel = 1;
+	} else if (vendor.ebx == 0x68747541 && vendor.edx == 0x69746E65 &&
+		   vendor.ecx ==   0x444D4163) {
+		authentic_amd = 1;
+	} else {
+		ret = -EFAULT;
+	}
+
+	return ret;
+}
+
 static void cmd_help(void)
 {
 	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list] [-n no_of_bits]\n");
@@ -110,6 +170,9 @@ int main(int argc, char **argv)
 		return errno;
 	}
 
+	/* Detect vendor */
+	detect_vendor();
+
 	if (has_ben) {
 		/* Extract benchmark command from command line. */
 		for (i = ben_ind; i < argc; i++) {
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 11/13] selftests/resctrl: Use cache index3 id for AMD schemata masks
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (9 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-02-10  2:50 ` [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests for AMD Fenghua Yu
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Babu Moger <babu.moger@amd.com>

AMD uses the cache l3 boundary for schemata masks. Update it accordigly.

Signed-off-by: Babu Moger <babu.moger@amd.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---
 tools/testing/selftests/resctrl/resctrlfs.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
index 137b926955ca..0f834a7aad49 100644
--- a/tools/testing/selftests/resctrl/resctrlfs.c
+++ b/tools/testing/selftests/resctrl/resctrlfs.c
@@ -110,8 +110,13 @@ int get_resource_id(int cpu_no, int *resource_id)
 	char phys_pkg_path[1024];
 	FILE *fp;
 
-	sprintf(phys_pkg_path, "%s%d/topology/physical_package_id",
-		PHYS_ID_PATH, cpu_no);
+	if (authentic_amd)
+		sprintf(phys_pkg_path, "%s%d/cache/index3/id",
+			PHYS_ID_PATH, cpu_no);
+	else
+		sprintf(phys_pkg_path, "%s%d/topology/physical_package_id",
+			PHYS_ID_PATH, cpu_no);
+
 	fp = fopen(phys_pkg_path, "r");
 	if (!fp) {
 		perror("Failed to open physical_package_id");
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests for AMD
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (10 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 11/13] selftests/resctrl: Use cache index3 id for AMD schemata masks Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-05-10 17:40   ` Andre Przywara
  2019-02-10  2:50 ` [PATCH v7 13/13] selftests/resctrl: Add the test in MAINTAINERS Fenghua Yu
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

From: Babu Moger <babu.moger@amd.com>

For now, disable MBA and MBM tests for AMD. Deciding test pass/fail
is not clear right now. We can enable when we have some clarity.

Signed-off-by: Babu Moger <babu.moger@amd.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---
 tools/testing/selftests/resctrl/cat_test.c      | 2 +-
 tools/testing/selftests/resctrl/resctrl_tests.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c
index 1a0f77e4f7bf..264bf2325f9e 100644
--- a/tools/testing/selftests/resctrl/cat_test.c
+++ b/tools/testing/selftests/resctrl/cat_test.c
@@ -69,7 +69,7 @@ static void show_cache_info(unsigned long sum_llc_perf_miss, int no_of_bits,
 	printf("Allocated cache lines: %lu \t", allocated_cache_lines);
 	printf("Percent diff=%d \t", abs((int)diff_percent));
 
-	if (abs((int)diff_percent) > MAX_DIFF_PERCENT)
+	if (genuine_intel && (abs((int)diff_percent) > MAX_DIFF_PERCENT))
 		printf("Failed\n");
 	else
 		printf("Passed\n");
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index 1d9adcfbdb4c..620be40b8c01 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -197,7 +197,7 @@ int main(int argc, char **argv)
 	sprintf(bw_report, "reads");
 	sprintf(bm_type, "fill_buf");
 
-	if (mbm_test) {
+	if (genuine_intel && mbm_test) {
 		printf("\nMBM BW Change Starting..\n");
 		if (!has_ben)
 			sprintf(benchmark_cmd[5], "%s", "mbm");
@@ -207,7 +207,7 @@ int main(int argc, char **argv)
 		mbm_test_cleanup();
 	}
 
-	if (mba_test) {
+	if (genuine_intel && mba_test) {
 		printf("\nMBA Schemata Change Starting..\n");
 		if (!has_ben)
 			sprintf(benchmark_cmd[5], "%s", "mba");
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH v7 13/13] selftests/resctrl: Add the test in MAINTAINERS
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (11 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests for AMD Fenghua Yu
@ 2019-02-10  2:50 ` Fenghua Yu
  2019-02-14 14:56 ` [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 38+ messages in thread
From: Fenghua Yu @ 2019-02-10  2:50 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel, Fenghua Yu

The resctrl selftest will be maintained by RDT maintainers.

Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9919840d54cd..40893bf1a083 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12826,6 +12826,7 @@ S:	Supported
 F:	arch/x86/kernel/cpu/resctrl/
 F:	arch/x86/include/asm/resctrl_sched.h
 F:	Documentation/x86/resctrl*
+F:	tools/testing/selftests/resctrl/
 
 READ-COPY UPDATE (RCU)
 M:	"Paul E. McKenney" <paulmck@linux.ibm.com>
-- 
2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (12 preceding siblings ...)
  2019-02-10  2:50 ` [PATCH v7 13/13] selftests/resctrl: Add the test in MAINTAINERS Fenghua Yu
@ 2019-02-14 14:56 ` Fenghua Yu
  2019-03-06 20:55   ` Moger, Babu
  2019-02-27 18:07 ` Moger, Babu
  2019-05-10 17:35 ` Andre Przywara
  15 siblings, 1 reply; 38+ messages in thread
From: Fenghua Yu @ 2019-02-14 14:56 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger
  Cc: linux-kernel

On Sat, Feb 09, 2019 at 06:50:29PM -0800, Fenghua Yu wrote:
> With more and more resctrl features are being added by Intel, AMD
> and ARM, a test tool is becoming more and more useful to validate
> that both hardware and software functionalities work as expected.

Hi, Thomas, Ingo, and Borislav,

Do you have any comments on the resctrl selftest tool?

Do you have any plan to push the patches to upstream?

The tool has been tested on both Intel RDT and AMD QoS.

Thanks.

-Fenghua

^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (13 preceding siblings ...)
  2019-02-14 14:56 ` [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
@ 2019-02-27 18:07 ` Moger, Babu
  2019-05-10 17:35 ` Andre Przywara
  15 siblings, 0 replies; 38+ messages in thread
From: Moger, Babu @ 2019-02-27 18:07 UTC (permalink / raw)
  To: Fenghua Yu, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H Peter Anvin, Tony Luck, Reinette Chatre, Ravi V Shankar,
	Xiaochen Shen, Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya
  Cc: linux-kernel

Patches look good. Tested v7 again on AMD system. Thanks


> -----Original Message-----
> From: Fenghua Yu <fenghua.yu@intel.com>
> Sent: Saturday, February 9, 2019 8:50 PM
> To: Thomas Gleixner <tglx@linutronix.de>; Ingo Molnar
> <mingo@redhat.com>; Borislav Petkov <bp@alien8.de>; H Peter Anvin
> <hpa@zytor.com>; Tony Luck <tony.luck@intel.com>; Reinette Chatre
> <reinette.chatre@intel.com>; Ravi V Shankar <ravi.v.shankar@intel.com>;
> Xiaochen Shen <xiaochen.shen@intel.com>; Arshiya Hayatkhan Pathan
> <arshiya.hayatkhan.pathan@intel.com>; Sai Praneeth Prakhya
> <sai.praneeth.prakhya@intel.com>; Moger, Babu <Babu.Moger@amd.com>
> Cc: linux-kernel <linux-kernel@vger.kernel.org>; Fenghua Yu
> <fenghua.yu@intel.com>
> Subject: [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
> 
> With more and more resctrl features are being added by Intel, AMD
> and ARM, a test tool is becoming more and more useful to validate
> that both hardware and software functionalities work as expected.
> 
> We introduce resctrl selftest to cover resctrl features on both
> X86 and ARM architectures. It first implements MBM (Memory Bandwidth
> Monitoring), MBA (Memory Bandwidth Allocation), L3 CAT (Cache Allocation
> Technology), and CQM (Cache QoS Monitoring)  tests. We can enhance
> the selftest tool to include more functionality tests in future.
> 
> The tool has been tested on both Intel RDT and AMD QoS.
> 
> There is an existing resctrl test suite 'intel_cmt_cat'. But the major
> purpose of the tool is to test Intel(R) RDT hardware via writing and
> reading MSR registers. It does access resctrl file system; but the
> functionalities are very limited. And it doesn't support automatic test
> and a lot of manual verifications are involved.
> 
> So the selftest tool we are introducing here provides a convenient
> tool which does automatic resctrl testing, is easily available in kernel
> tree, and will be extended to AMD QoS and ARM MPAM.
> 
> The selftest tool is in tools/testing/selftests/resctrl in order to have
> generic test code for all architectures.
> 
> Changelog:
> v7:
> - Fix a few warnings when compiling patches separately, pointed by Babu
> 
> v6:
> - Fix a benchmark reading optimized out issue in newer GCC.
> - Fix a few coding style issues.
> - Re-arrange code among patches to make cleaner code. No change in
> patches
> structure.
> 
> v5:
> - Based the v4 patches submitted by Fenghua Yu and added changes to
> support
>   AMD.
> - Changed the function name get_sock_num to get_resource_id. Intel uses
>   socket number for schemata and AMD uses l3 index id. To generalize,
>   changed the function name to get_resource_id.
> - Added the code to detect vendor.
> - Disabled the few tests for AMD where the test results are not clear.
>   Also AMD does not have IMC.
> - Fixed few compile issues.
> - Some cleanup to make each patch independent.
> - Tested the patches on AMD system. Fenghua, Need your help to test on
>   Intel box. Please feel free to change and resubmit if something
>    broken.
> - Here is the link for previous version.
>   https://lore.kernel.org/lkml/1545438038-75107-1-git-send-email-
> fenghua.yu=
> @intel.com/
> 
> v4:
> - address comments from Balu and Randy
> - Add CAT and CQM tests
> 
> v3:
> - Change code based on comments from Babu Moger
> - Remove some unnessary code and use pipe to communicate b/w processes
> 
> v2:
> - Change code based on comments from Babu Moger
> - Clean up other places.
> 
> Arshiya Hayatkhan Pathan (4):
>   selftests/resctrl: Add MBM test
>   selftests/resctrl: Add MBA test
>   selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest
>   selftests/resctrl: Add Cache Allocation Technology (CAT) selftest
> 
> Babu Moger (3):
>   selftests/resctrl: Add vendor detection mechanism
>   selftests/resctrl: Use cache index3 id for AMD schemata masks
>   selftests/resctrl: Disable MBA and MBM tests for AMD
> 
> Fenghua Yu (2):
>   selftests/resctrl: Add README for resctrl tests
>   selftests/resctrl: Add the test in MAINTAINERS
> 
> Sai Praneeth Prakhya (4):
>   selftests/resctrl: Add basic resctrl file system operations and data
>   selftests/resctrl: Read memory bandwidth from perf IMC counter and
>     from resctrl file system
>   selftests/resctrl: Add callback to start a benchmark
>   selftests/resctrl: Add built in benchmark
> 
>  MAINTAINERS                                     |   1 +
>  tools/testing/selftests/resctrl/Makefile        |  16 +
>  tools/testing/selftests/resctrl/README          |  54 ++
>  tools/testing/selftests/resctrl/cache.c         | 274 +++++++++
>  tools/testing/selftests/resctrl/cat_test.c      | 242 ++++++++
>  tools/testing/selftests/resctrl/cqm_test.c      | 173 ++++++
>  tools/testing/selftests/resctrl/fill_buf.c      | 210 +++++++
>  tools/testing/selftests/resctrl/mba_test.c      | 178 ++++++
>  tools/testing/selftests/resctrl/mbm_test.c      | 150 +++++
>  tools/testing/selftests/resctrl/resctrl.h       | 117 ++++
>  tools/testing/selftests/resctrl/resctrl_tests.c | 238 ++++++++
>  tools/testing/selftests/resctrl/resctrl_val.c   | 723
> ++++++++++++++++++++++++
>  tools/testing/selftests/resctrl/resctrlfs.c     | 668
> ++++++++++++++++++++++
>  13 files changed, 3044 insertions(+)
>  create mode 100644 tools/testing/selftests/resctrl/Makefile
>  create mode 100644 tools/testing/selftests/resctrl/README
>  create mode 100644 tools/testing/selftests/resctrl/cache.c
>  create mode 100644 tools/testing/selftests/resctrl/cat_test.c
>  create mode 100644 tools/testing/selftests/resctrl/cqm_test.c
>  create mode 100644 tools/testing/selftests/resctrl/fill_buf.c
>  create mode 100644 tools/testing/selftests/resctrl/mba_test.c
>  create mode 100644 tools/testing/selftests/resctrl/mbm_test.c
>  create mode 100644 tools/testing/selftests/resctrl/resctrl.h
>  create mode 100644 tools/testing/selftests/resctrl/resctrl_tests.c
>  create mode 100644 tools/testing/selftests/resctrl/resctrl_val.c
>  create mode 100644 tools/testing/selftests/resctrl/resctrlfs.c
> 
> --
> 2.7.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
  2019-02-14 14:56 ` [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
@ 2019-03-06 20:55   ` Moger, Babu
  0 siblings, 0 replies; 38+ messages in thread
From: Moger, Babu @ 2019-03-06 20:55 UTC (permalink / raw)
  To: Fenghua Yu, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H Peter Anvin, Tony Luck, Reinette Chatre, Ravi V Shankar,
	Xiaochen Shen, Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya
  Cc: linux-kernel

Hi Maintainers,
  Ping again. Any concerns with these patches?
Thanks
Babu
> -----Original Message-----
> From: Fenghua Yu <fenghua.yu@intel.com>
> Sent: Thursday, February 14, 2019 8:56 AM
> To: Thomas Gleixner <tglx@linutronix.de>; Ingo Molnar
> <mingo@redhat.com>; Borislav Petkov <bp@alien8.de>; H Peter Anvin
> <hpa@zytor.com>; Tony Luck <tony.luck@intel.com>; Reinette Chatre
> <reinette.chatre@intel.com>; Ravi V Shankar <ravi.v.shankar@intel.com>;
> Xiaochen Shen <xiaochen.shen@intel.com>; Arshiya Hayatkhan Pathan
> <arshiya.hayatkhan.pathan@intel.com>; Sai Praneeth Prakhya
> <sai.praneeth.prakhya@intel.com>; Moger, Babu <Babu.Moger@amd.com>
> Cc: linux-kernel <linux-kernel@vger.kernel.org>
> Subject: Re: [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
> 
> On Sat, Feb 09, 2019 at 06:50:29PM -0800, Fenghua Yu wrote:
> > With more and more resctrl features are being added by Intel, AMD
> > and ARM, a test tool is becoming more and more useful to validate
> > that both hardware and software functionalities work as expected.
> 
> Hi, Thomas, Ingo, and Borislav,
> 
> Do you have any comments on the resctrl selftest tool?
> 
> Do you have any plan to push the patches to upstream?
> 
> The tool has been tested on both Intel RDT and AMD QoS.
> 
> Thanks.
> 
> -Fenghua

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
  2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
                   ` (14 preceding siblings ...)
  2019-02-27 18:07 ` Moger, Babu
@ 2019-05-10 17:35 ` Andre Przywara
  2019-05-10 19:20   ` Yu, Fenghua
  15 siblings, 1 reply; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:35 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:29 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi Fenghua, Babu,

> With more and more resctrl features are being added by Intel, AMD
> and ARM, a test tool is becoming more and more useful to validate
> that both hardware and software functionalities work as expected.

That's very much appreciated! We decided to use that tool here to detect
regressions in James' upcoming resctrl rework series. While doing so we
spotted some shortcomings:
- There is some unconditional x86 inline assembly which obviously breaks
the build on ARM.
- The result output is somewhat confusing, I find it hard to see whether a
test succeeded or not, also it's not easily parseable by scripts.
- There are some basic tests missing (does the filesystem exist? Is the
mount point visible?)
- Some tests create files in the current directory. This is somewhat
confusing if you happen to be in some sysfs directory, for instance. I
don't think we really need temporary files (pipes should cover most of the
cases), but in case we do, we should create them in some /tmp directory,
probably by using a glibc function for this.
- There were some problems that newer GCC and clang complained about.

For now I didn't look too closely at the actual test algorithms, but
decided to fix those things first. I replied to some of the smaller issues
I spotted on the way in the individual patch mails.

For the bigger things (new tests, result formatting) I just went ahead and
fixed them in my own branch [1] (work in progress!). I went with TAP
formatting, because this is both readable by humans and can be processed
by the "prove" tool (or any other simple UNIX tool, for that matter).

I used this amended version to do some regression testing on James'
resctrl rework series, which involved boot testing more than 100 patches,
so automation is key here. The result looks like this:
===================
TAP version 13
ok kernel supports resctrl filesystem
ok resctrl mountpoint "/sys/fs/resctrl" exists
# resctrl filesystem not mounted
# Starting MBM BW change ...
ok MBM: bw change # SKIP memory bandwidth not supported
# Starting MBA Schemata Change ...
ok MBA: change-schemata # SKIP memory bandwidth not supported
# Starting CQM test ...
ok mounting resctrl to "/sys/fs/resctrl"
ok CQM: test # SKIP L3 not supported
# Starting CAT test ...
ok mounting resctrl to "/sys/fs/resctrl"
cache size :31457280
ok writing benchmark parameters to resctrl FS
ok Write schema "L3:0=7fff" to resctrl FS
ok cache difference more than 4 %
# Percent diff=16
# Number of bits: 15
# Avg_llc_perf_miss: 306994
# Allocated cache lines: 368640
ok CAT: test
1..11
=================

Appreciate any feedback on this!

Cheers,
Andre.

[1] http://linux-arm.org/git?p=linux-ap.git;a=shortlog;h=refs/heads/resctrl-selftests-wip
git://linux-arm.org/linux-ap.git    branch: resctrl-selftests-wip

> We introduce resctrl selftest to cover resctrl features on both
> X86 and ARM architectures. It first implements MBM (Memory Bandwidth
> Monitoring), MBA (Memory Bandwidth Allocation), L3 CAT (Cache Allocation
> Technology), and CQM (Cache QoS Monitoring)  tests. We can enhance
> the selftest tool to include more functionality tests in future.
> 
> The tool has been tested on both Intel RDT and AMD QoS.
> 
> There is an existing resctrl test suite 'intel_cmt_cat'. But the major
> purpose of the tool is to test Intel(R) RDT hardware via writing and
> reading MSR registers. It does access resctrl file system; but the
> functionalities are very limited. And it doesn't support automatic test
> and a lot of manual verifications are involved.
> 
> So the selftest tool we are introducing here provides a convenient
> tool which does automatic resctrl testing, is easily available in kernel
> tree, and will be extended to AMD QoS and ARM MPAM.
> 
> The selftest tool is in tools/testing/selftests/resctrl in order to have
> generic test code for all architectures.
> 
> Changelog:
> v7:
> - Fix a few warnings when compiling patches separately, pointed by Babu 
> 
> v6:
> - Fix a benchmark reading optimized out issue in newer GCC.
> - Fix a few coding style issues.
> - Re-arrange code among patches to make cleaner code. No change in patches
> structure.
> 
> v5:
> - Based the v4 patches submitted by Fenghua Yu and added changes to support
>   AMD.
> - Changed the function name get_sock_num to get_resource_id. Intel uses
>   socket number for schemata and AMD uses l3 index id. To generalize,
>   changed the function name to get_resource_id.
> - Added the code to detect vendor.
> - Disabled the few tests for AMD where the test results are not clear.
>   Also AMD does not have IMC.
> - Fixed few compile issues.
> - Some cleanup to make each patch independent.
> - Tested the patches on AMD system. Fenghua, Need your help to test on
>   Intel box. Please feel free to change and resubmit if something
>    broken.
> - Here is the link for previous version.
>   https://lore.kernel.org/lkml/1545438038-75107-1-git-send-email-fenghua.yu=
> @intel.com/
> 
> v4:
> - address comments from Balu and Randy
> - Add CAT and CQM tests
> 
> v3:
> - Change code based on comments from Babu Moger
> - Remove some unnessary code and use pipe to communicate b/w processes
> 
> v2:
> - Change code based on comments from Babu Moger
> - Clean up other places.
> 
> Arshiya Hayatkhan Pathan (4):
>   selftests/resctrl: Add MBM test
>   selftests/resctrl: Add MBA test
>   selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest
>   selftests/resctrl: Add Cache Allocation Technology (CAT) selftest
> 
> Babu Moger (3):
>   selftests/resctrl: Add vendor detection mechanism
>   selftests/resctrl: Use cache index3 id for AMD schemata masks
>   selftests/resctrl: Disable MBA and MBM tests for AMD
> 
> Fenghua Yu (2):
>   selftests/resctrl: Add README for resctrl tests
>   selftests/resctrl: Add the test in MAINTAINERS
> 
> Sai Praneeth Prakhya (4):
>   selftests/resctrl: Add basic resctrl file system operations and data
>   selftests/resctrl: Read memory bandwidth from perf IMC counter and
>     from resctrl file system
>   selftests/resctrl: Add callback to start a benchmark
>   selftests/resctrl: Add built in benchmark
> 
>  MAINTAINERS                                     |   1 +
>  tools/testing/selftests/resctrl/Makefile        |  16 +
>  tools/testing/selftests/resctrl/README          |  54 ++
>  tools/testing/selftests/resctrl/cache.c         | 274 +++++++++
>  tools/testing/selftests/resctrl/cat_test.c      | 242 ++++++++
>  tools/testing/selftests/resctrl/cqm_test.c      | 173 ++++++
>  tools/testing/selftests/resctrl/fill_buf.c      | 210 +++++++
>  tools/testing/selftests/resctrl/mba_test.c      | 178 ++++++
>  tools/testing/selftests/resctrl/mbm_test.c      | 150 +++++
>  tools/testing/selftests/resctrl/resctrl.h       | 117 ++++
>  tools/testing/selftests/resctrl/resctrl_tests.c | 238 ++++++++
>  tools/testing/selftests/resctrl/resctrl_val.c   | 723 ++++++++++++++++++++++++
>  tools/testing/selftests/resctrl/resctrlfs.c     | 668 ++++++++++++++++++++++
>  13 files changed, 3044 insertions(+)
>  create mode 100644 tools/testing/selftests/resctrl/Makefile
>  create mode 100644 tools/testing/selftests/resctrl/README
>  create mode 100644 tools/testing/selftests/resctrl/cache.c
>  create mode 100644 tools/testing/selftests/resctrl/cat_test.c
>  create mode 100644 tools/testing/selftests/resctrl/cqm_test.c
>  create mode 100644 tools/testing/selftests/resctrl/fill_buf.c
>  create mode 100644 tools/testing/selftests/resctrl/mba_test.c
>  create mode 100644 tools/testing/selftests/resctrl/mbm_test.c
>  create mode 100644 tools/testing/selftests/resctrl/resctrl.h
>  create mode 100644 tools/testing/selftests/resctrl/resctrl_tests.c
>  create mode 100644 tools/testing/selftests/resctrl/resctrl_val.c
>  create mode 100644 tools/testing/selftests/resctrl/resctrlfs.c
> 


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data
  2019-02-10  2:50 ` [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data Fenghua Yu
@ 2019-05-10 17:36   ` Andre Przywara
  2019-05-10 19:00     ` Yu, Fenghua
  2019-05-10 17:41   ` Borislav Petkov
  1 sibling, 1 reply; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:36 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:31 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

some comments inline.

> From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> 
> The basic resctrl file system operations and data are added for future
> usage by resctrl selftest tool.
> 
> Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> ---
>  tools/testing/selftests/resctrl/Makefile    |  10 +
>  tools/testing/selftests/resctrl/resctrl.h   |  48 +++
>  tools/testing/selftests/resctrl/resctrlfs.c | 464 ++++++++++++++++++++++++++++
>  3 files changed, 522 insertions(+)
>  create mode 100644 tools/testing/selftests/resctrl/Makefile
>  create mode 100644 tools/testing/selftests/resctrl/resctrl.h
>  create mode 100644 tools/testing/selftests/resctrl/resctrlfs.c
> 
> diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
> new file mode 100644
> index 000000000000..bd5c5418961e
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/Makefile
> @@ -0,0 +1,10 @@
> +CC = gcc

Changing this to
CC = $(CROSS_COMPILE)gcc
make this cross compileable.

> +CFLAGS = -g -Wall

Can we add -O here? For once -O0 generates horrible code, but also -O
tends to catch more bugs.

> +
> +*.o: *.c
> +	$(CC) $(CFLAGS) -c *.c

This is a built-in rule in make, so you can remove it here:
https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html#Catalogue-of-Rules

> +
> +.PHONY: clean
> +
> +clean:
> +	$(RM) *.o *~
> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
> new file mode 100644
> index 000000000000..2e112934d48a
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/resctrl.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#define _GNU_SOURCE
> +#ifndef RESCTRL_H
> +#define RESCTRL_H
> +#include <stdio.h>
> +#include <errno.h>
> +#include <sched.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <signal.h>
> +#include <dirent.h>
> +#include <stdbool.h>
> +#include <sys/stat.h>
> +#include <sys/ioctl.h>
> +#include <sys/mount.h>
> +#include <sys/types.h>
> +#include <asm/unistd.h>
> +#include <linux/perf_event.h>
> +
> +#define RESCTRL_PATH		"/sys/fs/resctrl"
> +#define PHYS_ID_PATH		"/sys/devices/system/cpu/cpu"
> +
> +#define PARENT_EXIT(err_msg)			\
> +	do {					\
> +		perror(err_msg);		\
> +		kill(ppid, SIGKILL);		\
> +		exit(EXIT_FAILURE);		\
> +	} while (0)
> +
> +pid_t bm_pid, ppid;
> +
> +int remount_resctrlfs(bool mum_resctrlfs);
> +int get_resource_id(int cpu_no, int *resource_id);
> +int validate_bw_report_request(char *bw_report);
> +int validate_resctrl_feature_request(char *resctrl_val);
> +int taskset_benchmark(pid_t bm_pid, int cpu_no);
> +void run_benchmark(int signum, siginfo_t *info, void *ucontext);
> +int write_schemata(char *ctrlgrp, char *schemata, int cpu_no,
> +		   char *resctrl_val);
> +int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
> +			    char *resctrl_val);
> +int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
> +		    int group_fd, unsigned long flags);
> +int run_fill_buf(unsigned long span, int malloc_and_init_memory, int memflush,
> +		 int op, char *resctrl_va);
> +
> +#endif /* RESCTRL_H */
> diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
> new file mode 100644
> index 000000000000..5afcaa89f418
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/resctrlfs.c
> @@ -0,0 +1,464 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Basic resctrl file system operations
> + *
> + * Copyright (C) 2018 Intel Corporation
> + *
> + * Authors:
> + *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> + *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
> + *    Fenghua Yu <fenghua.yu@intel.com>
> + */
> +#include "resctrl.h"
> +
> +#define RESCTRL_MBM		"L3 monitoring detected"
> +#define RESCTRL_MBA		"MB allocation detected"
> +enum {
> +	RESCTRL_FEATURE_MBM,
> +	RESCTRL_FEATURE_MBA,
> +	MAX_RESCTRL_FEATURES
> +};
> +
> +/*
> + * remount_resctrlfs - Remount resctrl FS at /sys/fs/resctrl
> + * @mum_resctrlfs:	Should the resctrl FS be remounted?
> + *
> + * If not mounted, mount it.
> + * If mounted and mum_resctrlfs then remount resctrl FS.
> + * If mounted and !mum_resctrlfs then noop
> + *
> + * Return: 0 on success, non-zero on failure
> + */
> +int remount_resctrlfs(bool mum_resctrlfs)
> +{
> +	DIR *dp;
> +	struct dirent *ep;
> +	unsigned int count = 0;
> +
> +	/*
> +	 * If kernel is built with CONFIG_RESCTRL, then /sys/fs/resctrl should
> +	 * be present by default
> +	 */
> +	dp = opendir(RESCTRL_PATH);
> +	if (dp) {
> +		while ((ep = readdir(dp)) != NULL)
> +			count++;
> +		closedir(dp);
> +	} else {
> +		perror("Unable to read /sys/fs/resctrl");
> +
> +		return -1;
> +	}
> +
> +	/*
> +	 * If resctrl FS has more than two entries, it means that resctrl FS has
> +	 * already been mounted. The two default entries are "." and "..", these
> +	 * are present even when resctrl FS is not mounted
> +	 */
> +	if (count > 2) {
> +		if (mum_resctrlfs) {
> +			if (umount(RESCTRL_PATH) != 0) {
> +				perror("Unable to umount resctrl");
> +
> +				return errno;
> +			}
> +			printf("Remount: done!\n");
> +		} else {
> +			printf("Mounted already. Not remounting!\n");
> +
> +			return 0;
> +		}
> +	}
> +
> +	if (mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL) != 0) {

Don't we need to consider mount options at some point? According to
Documentation/x86/resctrl_ui.txt there is cdp, cdpl2 and mba_MBps, which
we need to set to get certain features.

> +		perror("Unable to mount resctrl FS at /sys/fs/resctrl");
> +
> +		return errno;
> +	}
> +
> +	return 0;
> +}
> +
> +int umount_resctrlfs(void)
> +{
> +	if (umount(RESCTRL_PATH)) {
> +		perror("Unable to umount resctrl");
> +
> +		return errno;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * get_resource_id - Get socket number/l3 id for a specified CPU
> + * @cpu_no:	CPU number
> + * @resource_id: Socket number or l3_id
> + *
> + * Return: >= 0 on success, < 0 on failure.
> + */
> +int get_resource_id(int cpu_no, int *resource_id)
> +{
> +	char phys_pkg_path[1024];
> +	FILE *fp;
> +
> +	sprintf(phys_pkg_path, "%s%d/topology/physical_package_id",
> +		PHYS_ID_PATH, cpu_no);
> +	fp = fopen(phys_pkg_path, "r");
> +	if (!fp) {
> +		perror("Failed to open physical_package_id");
> +
> +		return -1;
> +	}
> +	if (fscanf(fp, "%d", resource_id) <= 0) {
> +		perror("Could not get socket number or l3 id");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	return 0;
> +}
> +
> +/*
> + * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
> + * @bm_pid:	PID that should be binded
> + * @cpu_no:	CPU number at which the PID would be binded
> + *
> + * Return: 0 on success, non-zero on failure
> + */
> +int taskset_benchmark(pid_t bm_pid, int cpu_no)
> +{
> +	cpu_set_t my_set;
> +
> +	CPU_ZERO(&my_set);
> +	CPU_SET(cpu_no, &my_set);
> +
> +	if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {
> +		perror("Unable to taskset benchmark");
> +
> +		return -1;
> +	}
> +
> +	printf("Taskset benchmark: done!\n");
> +
> +	return 0;
> +}
> +
> +/*
> + * run_benchmark - Run a specified benchmark or fill_buf (default benchmark)
> + *		   in specified signal. Direct benchmark stdio to /dev/null.
> + * @signum:	signal number
> + * @info:	signal info
> + * @ucontext:	user context in signal handling
> + *
> + * Return: void
> + */
> +void run_benchmark(int signum, siginfo_t *info, void *ucontext)
> +{
> +	unsigned long long span;
> +	int operation, ret;
> +	char **benchmark_cmd;
> +	FILE *fp;
> +
> +	benchmark_cmd = info->si_ptr;
> +
> +	/*
> +	 * Direct stdio of child to /dev/null, so that only parent writes to
> +	 * stdio (console)
> +	 */
> +	fp = freopen("/dev/null", "w", stdout);
> +	if (!fp)
> +		PARENT_EXIT("Unable to direct benchmark status to /dev/null");
> +
> +	if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
> +		/* Execute default fill_buf benchmark */
> +		span = strtoul(benchmark_cmd[1], NULL, 10);
> +		operation = atoi(benchmark_cmd[4]);
> +		if (run_fill_buf(span, 1, 1, operation, NULL))
> +			fprintf(stderr, "Error in running fill buffer\n");
> +	} else {
> +		/* Execute specified benchmark */
> +		ret = execvp(benchmark_cmd[0], benchmark_cmd);
> +		if (ret)
> +			perror("wrong\n");
> +	}
> +
> +	fclose(stdout);
> +	PARENT_EXIT("Unable to run specified benchmark");
> +}
> +
> +/*
> + * create_grp - Create a group only if one doesn't exist
> + * @grp_name:	Name of the group
> + * @grp:	Full path and name of the group
> + * @parent_grp:	Full path and name of the parent group
> + *
> + * Return: 0 on success, non-zero on failure
> + */
> +static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
> +{
> +	int found_grp = 0;
> +	struct dirent *ep;
> +	DIR *dp;
> +
> +	/* Check if requested grp exists or not */
> +	dp = opendir(parent_grp);
> +	if (dp) {
> +		while ((ep = readdir(dp)) != NULL) {
> +			if (strcmp(ep->d_name, grp_name) == 0)
> +				found_grp = 1;
> +		}
> +		closedir(dp);
> +	} else {
> +		perror("Unable to open resctrl for group");
> +
> +		return -1;
> +	}
> +
> +	/* Requested grp doesn't exist, hence create it */
> +	if (found_grp == 0) {
> +		if (mkdir(grp, 0) == -1) {
> +			perror("Unable to create group");
> +
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int write_pid_to_tasks(char *tasks, pid_t pid)
> +{
> +	FILE *fp;
> +
> +	fp = fopen(tasks, "w");
> +	if (!fp) {
> +		perror("Failed to open tasks file");
> +
> +		return -1;
> +	}
> +	if (fprintf(fp, "%d\n", pid) < 0) {
> +		perror("Failed to wr pid to tasks file");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	return 0;
> +}
> +
> +/*
> + * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS
> + * @bm_pid:		PID that should be written
> + * @ctrlgrp:		Name of the control monitor group (con_mon grp)
> + * @mongrp:		Name of the monitor group (mon grp)
> + * @resctrl_val:	Resctrl feature (Eg: mbm, mba.. etc)
> + *
> + * If a con_mon grp is requested, create it and write pid to it, otherwise
> + * write pid to root con_mon grp.
> + * If a mon grp is requested, create it and write pid to it, otherwise
> + * pid is not written, this means that pid is in con_mon grp and hence
> + * should consult con_mon grp's mon_data directory for results.
> + *
> + * Return: 0 on success, non-zero on failure
> + */
> +int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
> +			    char *resctrl_val)
> +{
> +	char controlgroup[256], monitorgroup[256], monitorgroup_p[256];
> +	char tasks[256];
> +	int ret;
> +
> +	if (ctrlgrp)
> +		sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
> +	else
> +		sprintf(controlgroup, "%s", RESCTRL_PATH);
> +
> +	/* Create control and monitoring group and write pid into it */
> +	ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH);
> +	if (ret)
> +		return ret;
> +	sprintf(tasks, "%s/tasks", controlgroup);
> +	ret = write_pid_to_tasks(tasks, bm_pid);
> +	if (ret)
> +		return ret;
> +
> +	/* Create mon grp and write pid into it for "mbm" test */
> +	if ((strcmp(resctrl_val, "mbm") == 0)) {
> +		if (mongrp) {
> +			sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
> +			sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
> +			ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
> +			if (ret)
> +				return ret;
> +
> +			sprintf(tasks, "%s/mon_groups/%s/tasks",
> +				controlgroup, mongrp);
> +			ret = write_pid_to_tasks(tasks, bm_pid);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	printf("Write benchmark to resctrl FS: done!\n");
> +
> +	return 0;
> +}
> +
> +/*
> + * write_schemata - Update schemata of a con_mon grp
> + * @ctrlgrp:		Name of the con_mon grp
> + * @schemata:		Schemata that should be updated to
> + * @cpu_no:		CPU number that the benchmark PID is binded to
> + * @resctrl_val:	Resctrl feature (Eg: mbm, mba.. etc)
> + *
> + * Update schemata of a con_mon grp *only* if requested resctrl feature is
> + * allocation type
> + *
> + * Return: 0 on success, non-zero on failure
> + */
> +int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
> +{
> +	char controlgroup[1024], schema[1024];
> +	int resource_id;
> +	FILE *fp;
> +
> +	if (strcmp(resctrl_val, "mba") == 0) {
> +		if (!schemata) {
> +			printf("Schemata empty, so not updating\n");
> +
> +			return 0;
> +		}
> +		if (get_resource_id(cpu_no, &resource_id) < 0) {
> +			perror("Failed to get resource id");
> +			return -1;
> +		}
> +
> +		if (ctrlgrp)
> +			sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH,
> +				ctrlgrp);
> +		else
> +			sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
> +		sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=', schemata);
> +
> +		fp = fopen(controlgroup, "w");
> +		if (!fp) {
> +			perror("Failed to open control group");
> +
> +			return -1;
> +		}
> +
> +		if (fprintf(fp, "%s\n", schema) < 0) {
> +			perror("Failed to write schemata in control group");
> +			fclose(fp);
> +
> +			return -1;
> +		}
> +		fclose(fp);
> +
> +		printf("Write schemata to resctrl FS: done!\n");
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * validate_resctrl_feature_request - Check if requested feature is valid.
> + * @resctrl_val:	Requested feature
> + *
> + * Return: 0 on success, non-zero on failure
> + */
> +int validate_resctrl_feature_request(char *resctrl_val)
> +{
> +	int resctrl_features_supported[MAX_RESCTRL_FEATURES];
> +	const char *resctrl_features_list[MAX_RESCTRL_FEATURES] = {
> +			"mbm", "mba"};
> +	int i, valid_resctrl_feature = -1;
> +	char line[1024];
> +	FILE *fp;
> +
> +	if (!resctrl_val) {
> +		fprintf(stderr, "resctrl feature cannot be NULL\n");
> +
> +		return -1;
> +	}
> +
> +	for (i = 0; i < MAX_RESCTRL_FEATURES; i++)
> +		resctrl_features_supported[i] = 0;
> +
> +	/* Is the resctrl feature request valid? */
> +	for (i = 0; i < MAX_RESCTRL_FEATURES; i++) {
> +		if (strcmp(resctrl_features_list[i], resctrl_val) == 0)
> +			valid_resctrl_feature = i;
> +	}
> +	if (valid_resctrl_feature == -1) {
> +		fprintf(stderr, "Not a valid resctrl feature request\n");
> +
> +		return -1;
> +	}
> +
> +	/* Enumerate resctrl features supported by this platform */
> +	if (system("dmesg > dmesg") != 0) {
> +		perror("Could not create custom dmesg file");

This fails horribly if the local directory is not writable. Creating a
pipe (similar to how we communicate between the benchmark processes) and
reading from there avoid this.

> +
> +		return -1;
> +	}
> +
> +	fp = fopen("dmesg", "r");
> +	if (!fp) {
> +		perror("Could not read custom created dmesg");
> +
> +		return -1;
> +	}
> +
> +	while (fgets(line, 1024, fp)) {
> +		if ((strstr(line, RESCTRL_MBM)) != NULL)
> +			resctrl_features_supported[RESCTRL_FEATURE_MBM] = 1;

In general this approach is not very reliable, as the beginning of the
kernel log could have been overwritten already in the dmesg buffer.
Also this is not the way we should detect features: I think the content
of /sys/fs/resctrl/info should be used for that purpose.

Cheers,
Andre.

> +		if ((strstr(line, RESCTRL_MBA)) != NULL)
> +			resctrl_features_supported[RESCTRL_FEATURE_MBA] = 1;
> +	}
> +	fclose(fp);
> +
> +	if (system("rm -rf dmesg") != 0)
> +		perror("Unable to remove 'dmesg' file");
> +
> +	/* Is the resctrl feature request supported? */
> +	if (!resctrl_features_supported[valid_resctrl_feature]) {
> +		fprintf(stderr, "resctrl feature not supported!");
> +
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +int validate_bw_report_request(char *bw_report)
> +{
> +	if (strcmp(bw_report, "reads") == 0)
> +		return 0;
> +	if (strcmp(bw_report, "writes") == 0)
> +		return 0;
> +	if (strcmp(bw_report, "nt-writes") == 0) {
> +		strcpy(bw_report, "writes");
> +		return 0;
> +	}
> +	if (strcmp(bw_report, "total") == 0)
> +		return 0;
> +
> +	fprintf(stderr, "Requested iMC B/W report type unavailable\n");
> +
> +	return -1;
> +}
> +
> +int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
> +		    int group_fd, unsigned long flags)
> +{
> +	int ret;
> +
> +	ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
> +		      group_fd, flags);
> +	return ret;
> +}




^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 04/13] selftests/resctrl: Add callback to start a benchmark
  2019-02-10  2:50 ` [PATCH v7 04/13] selftests/resctrl: Add callback to start a benchmark Fenghua Yu
@ 2019-05-10 17:37   ` Andre Przywara
  0 siblings, 0 replies; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:37 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:33 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> 
> The callback starts a child process and puts the child pid in created
> resctrl group with specified memory bandwidth in schemata. The child
> starts running benchmark.
> 
> Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> ---
>  tools/testing/selftests/resctrl/resctrl.h     |  27 ++
>  tools/testing/selftests/resctrl/resctrl_val.c | 582 ++++++++++++++++++++++++++
>  2 files changed, 609 insertions(+)
> 
> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
> index 2e112934d48a..c286790ba24d 100644
> --- a/tools/testing/selftests/resctrl/resctrl.h
> +++ b/tools/testing/selftests/resctrl/resctrl.h
> @@ -3,6 +3,7 @@
>  #ifndef RESCTRL_H
>  #define RESCTRL_H
>  #include <stdio.h>
> +#include <stdarg.h>
>  #include <errno.h>
>  #include <sched.h>
>  #include <stdlib.h>
> @@ -28,10 +29,35 @@
>  		exit(EXIT_FAILURE);		\
>  	} while (0)
>  
> +/*
> + * resctrl_val_param:	resctrl test parameters
> + * @resctrl_val:	Resctrl feature (Eg: mbm, mba.. etc)
> + * @ctrlgrp:		Name of the control monitor group (con_mon grp)
> + * @mongrp:		Name of the monitor group (mon grp)
> + * @cpu_no:		CPU number to which the benchmark would be binded
> + * @span:		Memory bytes accessed in each benchmark iteration
> + * @mum_resctrlfs:	Should the resctrl FS be remounted?
> + * @filename:		Name of file to which the o/p should be written
> + * @bw_report:		Bandwidth report type (reads vs writes)
> + * @setup:		Call back function to setup test environment
> + */
> +struct resctrl_val_param {
> +	char	*resctrl_val;
> +	char	ctrlgrp[64];
> +	char	mongrp[64];
> +	int	cpu_no;
> +	int	span;
> +	int	mum_resctrlfs;
> +	char	filename[64];
> +	char	*bw_report;
> +	int	(*setup)(int num, ...);
> +};
> +
>  pid_t bm_pid, ppid;
>  
>  int remount_resctrlfs(bool mum_resctrlfs);
>  int get_resource_id(int cpu_no, int *resource_id);
> +int umount_resctrlfs(void);
>  int validate_bw_report_request(char *bw_report);
>  int validate_resctrl_feature_request(char *resctrl_val);
>  int taskset_benchmark(pid_t bm_pid, int cpu_no);
> @@ -44,5 +70,6 @@ int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
>  		    int group_fd, unsigned long flags);
>  int run_fill_buf(unsigned long span, int malloc_and_init_memory, int memflush,
>  		 int op, char *resctrl_va);
> +int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param);
>  
>  #endif /* RESCTRL_H */
> diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
> index 2bb317715a2a..43c15e382892 100644
> --- a/tools/testing/selftests/resctrl/resctrl_val.c
> +++ b/tools/testing/selftests/resctrl/resctrl_val.c
> @@ -11,6 +11,7 @@
>   */
>  #include "resctrl.h"
>  
> +#define MB			(1024 * 1024)
>  #define UNCORE_IMC		"uncore_imc"
>  #define READ_FILE_NAME		"events/cas_count_read"
>  #define WRITE_FILE_NAME		"events/cas_count_write"
> @@ -48,6 +49,8 @@ struct imc_counter_config {
>  	int fd;
>  };
>  
> +static char mbm_total_path[1024];
> +static int imcs;
>  static struct imc_counter_config imc_counters_config[MAX_IMCS][2];
>  
>  void membw_initialize_perf_event_attr(int i, int j)
> @@ -116,3 +119,582 @@ void get_event_and_umask(char *cas_count_cfg, int count, bool op)
>  		}
>  	}
>  }
> +
> +static int open_perf_event(int i, int cpu_no, int j)
> +{
> +	imc_counters_config[i][j].fd =
> +		perf_event_open(&imc_counters_config[i][j].pe, -1, cpu_no, -1,
> +				PERF_FLAG_FD_CLOEXEC);
> +
> +	if (imc_counters_config[i][j].fd == -1) {
> +		fprintf(stderr, "Error opening leader %llx\n",
> +			imc_counters_config[i][j].pe.config);
> +
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Get type and config (read and write) of an iMC counter */
> +static int read_from_imc_dir(char *imc_dir, int count)
> +{
> +	char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024];
> +	FILE *fp;
> +
> +	/* Get type of iMC counter */
> +	sprintf(imc_counter_type, "%s%s", imc_dir, "type");
> +	fp = fopen(imc_counter_type, "r");
> +	if (!fp) {
> +		perror("Failed to open imc counter type file");
> +
> +		return -1;
> +	}
> +	if (fscanf(fp, "%u", &imc_counters_config[count][READ].type) <= 0) {
> +		perror("Could not get imc type");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	imc_counters_config[count][WRITE].type =
> +				imc_counters_config[count][READ].type;
> +
> +	/* Get read config */
> +	sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME);
> +	fp = fopen(imc_counter_cfg, "r");
> +	if (!fp) {
> +		perror("Failed to open imc config file");
> +
> +		return -1;
> +	}
> +	if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
> +		perror("Could not get imc cas count read");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	get_event_and_umask(cas_count_cfg, count, READ);
> +
> +	/* Get write config */
> +	sprintf(imc_counter_cfg, "%s%s", imc_dir, WRITE_FILE_NAME);
> +	fp = fopen(imc_counter_cfg, "r");
> +	if (!fp) {
> +		perror("Failed to open imc config file");
> +
> +		return -1;
> +	}
> +	if  (fscanf(fp, "%s", cas_count_cfg) <= 0) {
> +		perror("Could not get imc cas count write");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	get_event_and_umask(cas_count_cfg, count, WRITE);
> +
> +	return 0;
> +}
> +
> +/*
> + * A system can have 'n' number of iMC (Integrated Memory Controller)
> + * counters, get that 'n'. For each iMC counter get it's type and config.
> + * Also, each counter has two configs, one for read and the other for write.
> + * A config again has two parts, event and umask.
> + * Enumerate all these details into an array of structures.
> + *
> + * Return: >= 0 on success. < 0 on failure.
> + */
> +static int num_of_imcs(void)
> +{
> +	unsigned int count = 0;
> +	char imc_dir[1024];
> +	struct dirent *ep;
> +	int ret;
> +	DIR *dp;
> +
> +	dp = opendir(DYN_PMU_PATH);
> +	if (dp) {

Changing this to: if (!dp) {
and handling the error case first makes this more readable and avoids the indentation.

> +		while ((ep = readdir(dp))) {
> +			if (strstr(ep->d_name, UNCORE_IMC)) {
> +				sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH,
> +					ep->d_name);
> +				ret = read_from_imc_dir(imc_dir, count);
> +				if (ret) {
> +					closedir(dp);
> +
> +					return ret;
> +				}
> +				count++;
> +			}
> +		}
> +		closedir(dp);
> +		if (count == 0) {
> +			perror("Unable find iMC counters!\n");
> +
> +			return -1;
> +		}
> +	} else {
> +		perror("Unable to open PMU directory!\n");
> +
> +		return -1;
> +	}
> +
> +	return count;
> +}
> +
> +static int initialize_mem_bw_imc(void)
> +{
> +	int imc, j;
> +
> +	imcs = num_of_imcs();
> +	if (imcs <= 0)
> +		return imcs;
> +
> +	/* Initialize perf_event_attr structures for all iMC's */
> +	for (imc = 0; imc < imcs; imc++) {
> +		for (j = 0; j < 2; j++)
> +			membw_initialize_perf_event_attr(imc, j);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * get_mem_bw_imc:	Memory band width as reported by iMC counters
> + * @cpu_no:		CPU number that the benchmark PID is binded to
> + * @bw_report:		Bandwidth report type (reads, writes)
> + *
> + * Memory B/W utilized by a process on a socket can be calculated using
> + * iMC counters. Perf events are used to read these counters.
> + *
> + * Return: >= 0 on success. < 0 on failure.
> + */
> +static float get_mem_bw_imc(int cpu_no, char *bw_report)
> +{
> +	float reads, writes, of_mul_read, of_mul_write;
> +	int imc, j, ret;
> +
> +	/* Start all iMC counters to log values (both read and write) */
> +	reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1;
> +	for (imc = 0; imc < imcs; imc++) {
> +		for (j = 0; j < 2; j++) {
> +			ret = open_perf_event(imc, cpu_no, j);
> +			if (ret)
> +				return -1;
> +		}
> +		for (j = 0; j < 2; j++)
> +			membw_ioctl_perf_event_ioc_reset_enable(imc, j);
> +	}
> +
> +	sleep(1);
> +
> +	/* Stop counters after a second to get results (both read and write) */
> +	for (imc = 0; imc < imcs; imc++) {
> +		for (j = 0; j < 2; j++)
> +			membw_ioctl_perf_event_ioc_disable(imc, j);
> +	}
> +
> +	/*
> +	 * Get results which are stored in struct type imc_counter_config
> +	 * Take over flow into consideration before calculating total b/w
> +	 */
> +	for (imc = 0; imc < imcs; imc++) {
> +		struct imc_counter_config *r =
> +			&imc_counters_config[imc][READ];
> +		struct imc_counter_config *w =
> +			&imc_counters_config[imc][WRITE];
> +
> +		if (read(r->fd, &r->return_value,
> +			 sizeof(struct membw_read_format)) == -1) {
> +			perror("Couldn't get read b/w through iMC");
> +
> +			return -1;
> +		}
> +
> +		if (read(w->fd, &w->return_value,
> +			 sizeof(struct membw_read_format)) == -1) {
> +			perror("Couldn't get write bw through iMC");
> +
> +			return -1;
> +		}
> +
> +		__u64 r_time_enabled = r->return_value.time_enabled;
> +		__u64 r_time_running = r->return_value.time_running;
> +
> +		if (r_time_enabled != r_time_running)
> +			of_mul_read = (float)r_time_enabled /
> +					(float)r_time_running;
> +
> +		__u64 w_time_enabled = w->return_value.time_enabled;
> +		__u64 w_time_running = w->return_value.time_running;
> +
> +		if (w_time_enabled != w_time_running)
> +			of_mul_write = (float)w_time_enabled /
> +					(float)w_time_running;
> +		reads += r->return_value.value * of_mul_read * SCALE;
> +		writes += w->return_value.value * of_mul_write * SCALE;
> +	}
> +
> +	for (imc = 0; imc < imcs; imc++) {
> +		close(imc_counters_config[imc][READ].fd);
> +		close(imc_counters_config[imc][WRITE].fd);
> +	}
> +
> +	if (strcmp(bw_report, "reads") == 0)
> +		return reads;
> +
> +	if (strcmp(bw_report, "writes") == 0)
> +		return writes;
> +
> +	return (reads + writes);
> +}
> +
> +void set_mbm_path(const char *ctrlgrp, const char *mongrp, int resource_id)
> +{
> +	if (ctrlgrp && mongrp)
> +		sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH,
> +			RESCTRL_PATH, ctrlgrp, mongrp, resource_id);
> +	else if (!ctrlgrp && mongrp)
> +		sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
> +			mongrp, resource_id);
> +	else if (ctrlgrp && !mongrp)
> +		sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
> +			ctrlgrp, resource_id);
> +	else if (!ctrlgrp && !mongrp)
> +		sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
> +			resource_id);
> +}
> +
> +/*
> + * initialize_mem_bw_resctrl:	Appropriately populate "mbm_total_path"
> + * @ctrlgrp:			Name of the control monitor group (con_mon grp)
> + * @mongrp:			Name of the monitor group (mon grp)
> + * @cpu_no:			CPU number that the benchmark PID is binded to
> + * @resctrl_val:		Resctrl feature (Eg: mbm, mba.. etc)
> + */
> +static void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp,
> +				      int cpu_no, char *resctrl_val)
> +{
> +	int resource_id;
> +
> +	if (get_resource_id(cpu_no, &resource_id) < 0) {
> +		perror("Could not get resource_id");
> +		return;
> +	}
> +
> +	if (strcmp(resctrl_val, "mbm") == 0)
> +		set_mbm_path(ctrlgrp, mongrp, resource_id);
> +
> +	if ((strcmp(resctrl_val, "mba") == 0)) {
> +		if (ctrlgrp)
> +			sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH,
> +				RESCTRL_PATH, ctrlgrp, resource_id);
> +		else
> +			sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH,
> +				RESCTRL_PATH, resource_id);
> +	}
> +}
> +
> +/*
> + * Get MBM Local bytes as reported by resctrl FS
> + * For MBM,
> + * 1. If con_mon grp and mon grp are given, then read from con_mon grp's mon grp
> + * 2. If only con_mon grp is given, then read from con_mon grp
> + * 3. If both are not given, then read from root con_mon grp
> + * For MBA,
> + * 1. If con_mon grp is given, then read from it
> + * 2. If con_mon grp is not given, then read from root con_mon grp
> + */
> +static unsigned long get_mem_bw_resctrl(void)
> +{
> +	unsigned long mbm_total = 0;
> +	FILE *fp;
> +
> +	fp = fopen(mbm_total_path, "r");
> +	if (!fp) {
> +		perror("Failed to open total bw file");
> +
> +		return -1;
> +	}
> +	if (fscanf(fp, "%lu", &mbm_total) <= 0) {
> +		perror("Could not get mbm local bytes");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	return mbm_total;
> +}
> +
> +pid_t bm_pid, ppid;
> +
> +static void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
> +{
> +	kill(bm_pid, SIGKILL);
> +	printf("Ending\n\n");
> +
> +	exit(EXIT_SUCCESS);
> +}
> +
> +/*
> + * print_results_bw:	the memory bandwidth results are stored in a file
> + * @filename:		file that stores the results
> + * @bm_pid:		child pid that runs benchmark
> + * @bw_imc:		perf imc counter value
> + * @bw_resc:		memory bandwidth value
> + *
> + * Return:		0 on success. non-zero on failure.
> + */
> +static int print_results_bw(char *filename,  int bm_pid, float bw_imc,
> +			    unsigned long bw_resc)
> +{
> +	unsigned long diff = labs(bw_imc - bw_resc);

Since bw_imc is float (why, actually?) this should be fabs(). clang
complains about it.

> +	FILE *fp;
> +
> +	if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) {
> +		printf("Pid: %d \t Mem_BW_iMC: %f \t ", bm_pid, bw_imc);
> +		printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff);
> +	} else {
> +		fp = fopen(filename, "a");
> +		if (!fp) {
> +			perror("Cannot open results file");
> +
> +			return errno;
> +		}
> +		if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n",
> +			    bm_pid, bw_imc, bw_resc, diff) <= 0) {
> +			fclose(fp);
> +			perror("Could not log results.");
> +
> +			return errno;
> +		}
> +		fclose(fp);
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
> +{
> +	unsigned long bw_imc, bw_resc, bw_resc_end;
> +	int ret;
> +
> +	/*
> +	 * Measure memory bandwidth from resctrl and from
> +	 * another source which is perf imc value or could
> +	 * be something else if perf imc event is not available.
> +	 * Compare the two values to validate resctrl value.
> +	 * It takes 1sec to measure the data.
> +	 */
> +	bw_imc = get_mem_bw_imc(param->cpu_no, param->bw_report);
> +	if (bw_imc <= 0)
> +		return bw_imc;
> +
> +	bw_resc_end = get_mem_bw_resctrl();
> +	if (bw_resc_end <= 0)
> +		return bw_resc_end;
> +
> +	bw_resc = (bw_resc_end - *bw_resc_start) / MB;
> +	ret = print_results_bw(param->filename, bm_pid, bw_imc, bw_resc);
> +	if (ret)
> +		return ret;
> +
> +	*bw_resc_start = bw_resc_end;
> +
> +	return 0;
> +}
> +
> +/*
> + * resctrl_val:	execute benchmark and measure memory bandwidth on
> + *			the benchmark
> + * @benchmark_cmd:	benchmark command and its arguments
> + * @param:		parameters passed to resctrl_val()
> + *
> + * Return:		0 on success. non-zero on failure.
> + */
> +int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
> +{
> +	int ret = 0, pipefd[2], pipe_message = 0;

If I get this correctly, we just need to pipe for asynchronous signalling.
So can't we actually use a signal() call here? At least we should make
this pipe_message a single char. This avoids some nasty problems with
read() and write() possibly returning early.

> +	char *resctrl_val = param->resctrl_val;
> +	unsigned long bw_resc_start = 0;
> +	struct sigaction sigact;
> +	union sigval value;
> +	FILE *fp;
> +
> +	if (strcmp(param->filename, "") == 0)
> +		sprintf(param->filename, "stdio");
> +
> +	if (strcmp(param->bw_report, "") == 0)
> +		param->bw_report = "total";
> +
> +	if ((strcmp(resctrl_val, "mba")) == 0 ||
> +	    (strcmp(resctrl_val, "mbm")) == 0) {
> +		ret = validate_bw_report_request(param->bw_report);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	ret = remount_resctrlfs(param->mum_resctrlfs);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * If benchmark wasn't successfully started by child, then child should
> +	 * kill parent, so save parent's pid
> +	 */
> +	ppid = getpid();
> +
> +	/* File based synchronization between parent and child */
> +	fp = fopen("sig", "w");
> +	if (!fp) {
> +		perror("Failed to open sig file");
> +
> +		return -1;
> +	}
> +	if (fprintf(fp, "%d\n", 0) <= 0) {
> +		perror("Unable to establish sync bw parent & child");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	if (pipe(pipefd)) {
> +		perror("Unable to create pipe");
> +
> +		return -1;
> +	}
> +
> +	/*
> +	 * Fork to start benchmark, save child's pid so that it can be killed
> +	 * when needed
> +	 */
> +	bm_pid = fork();
> +	if (bm_pid == -1) {
> +		perror("Unable to fork");
> +
> +		return -1;
> +	}
> +
> +	if (bm_pid == 0) {
> +		/*
> +		 * Mask all signals except SIGUSR1, parent uses SIGUSR1 to
> +		 * start benchmark
> +		 */
> +		sigfillset(&sigact.sa_mask);
> +		sigdelset(&sigact.sa_mask, SIGUSR1);
> +
> +		sigact.sa_sigaction = run_benchmark;
> +		sigact.sa_flags = SA_SIGINFO;
> +
> +		/* Register for "SIGUSR1" signal from parent */
> +		if (sigaction(SIGUSR1, &sigact, NULL))
> +			PARENT_EXIT("Can't register child for signal");
> +
> +		/* Tell parent that child is ready */
> +		close(pipefd[0]);
> +		pipe_message = 1;
> +		write(pipefd[1], &pipe_message, sizeof(pipe_message));

gcc -O complains about an unchecked return value of write() here.
We could just compare against sizeof(pipe_message) and bail out if it's smaller.

> +		close(pipefd[1]);
> +
> +		/* Suspend child until delivery of "SIGUSR1" from parent */
> +		sigsuspend(&sigact.sa_mask);
> +
> +		PARENT_EXIT("Child is done");
> +	}
> +
> +	printf("Benchmark PID: %d\n", bm_pid);
> +
> +	/*
> +	 * Register CTRL-C handler for parent, as it has to kill benchmark
> +	 * before exiting
> +	 */
> +	sigact.sa_sigaction = ctrlc_handler;
> +	sigemptyset(&sigact.sa_mask);
> +	sigact.sa_flags = SA_SIGINFO;
> +	if (sigaction(SIGINT, &sigact, NULL) ||
> +	    sigaction(SIGHUP, &sigact, NULL)) {
> +		perror("Can't register parent for CTRL-C handler");
> +		ret = errno;
> +		goto out;
> +	}
> +
> +	value.sival_ptr = benchmark_cmd;
> +
> +	/* Taskset benchmark to specified cpu */
> +	ret = taskset_benchmark(bm_pid, param->cpu_no);
> +	if (ret)
> +		goto out;
> +
> +	/* Write benchmark to specified control&monitoring grp in resctrl FS */
> +	ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
> +				      resctrl_val);
> +	if (ret)
> +		goto out;
> +
> +	if ((strcmp(resctrl_val, "mbm") == 0) ||
> +	    (strcmp(resctrl_val, "mba") == 0)) {
> +		ret = initialize_mem_bw_imc();
> +		if (ret)
> +			goto out;
> +
> +		initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
> +					  param->cpu_no, resctrl_val);
> +	}
> +
> +	/* Parent waits for child to be ready. */
> +	close(pipefd[1]);
> +	while (pipe_message != 1)
> +		read(pipefd[0], &pipe_message, sizeof(pipe_message));

Same thing with checking the return value here.

Cheers,
Andre.

> +	close(pipefd[0]);
> +
> +	/* Signal child to start benchmark */
> +	if (sigqueue(bm_pid, SIGUSR1, value) == -1) {
> +		perror("Unable to signal child to start execution");
> +		ret = errno;
> +		goto out;
> +	}
> +
> +	/* Give benchmark enough time to fully run */
> +	sleep(1);
> +
> +	/* Test runs until the callback setup() tells the test to stop. */
> +	while (1) {
> +		if (strcmp(resctrl_val, "mbm") == 0) {
> +			ret = param->setup(1, param);
> +			if (ret) {
> +				ret = 0;
> +				break;
> +			}
> +
> +			ret = measure_vals(param, &bw_resc_start);
> +			if (ret)
> +				break;
> +		} else if ((strcmp(resctrl_val, "mba") == 0)) {
> +			ret = param->setup(1, param);
> +			if (ret) {
> +				ret = 0;
> +				break;
> +			}
> +
> +			ret = measure_vals(param, &bw_resc_start);
> +			if (ret)
> +				break;
> +		} else {
> +			break;
> +		}
> +	}
> +
> +out:
> +	kill(bm_pid, SIGKILL);
> +	umount_resctrlfs();
> +
> +	return ret;
> +}


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 05/13] selftests/resctrl: Add built in benchmark
  2019-02-10  2:50 ` [PATCH v7 05/13] selftests/resctrl: Add built in benchmark Fenghua Yu
@ 2019-05-10 17:37   ` Andre Przywara
  0 siblings, 0 replies; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:37 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:34 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> 
> Built-in benchmark fill_buf generates stressful memory bandwidth
> and cache traffic.
> 
> Later it will be used as a default benchmark by various resctrl tests
> such as MBA (Memory Bandwidth Allocation) and MBM (Memory Bandwidth
> Monitoring) tests.
> 
> Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> ---
>  tools/testing/selftests/resctrl/fill_buf.c | 204 +++++++++++++++++++++++++++++
>  1 file changed, 204 insertions(+)
>  create mode 100644 tools/testing/selftests/resctrl/fill_buf.c
> 
> diff --git a/tools/testing/selftests/resctrl/fill_buf.c b/tools/testing/selftests/resctrl/fill_buf.c
> new file mode 100644
> index 000000000000..792a5c40a32a
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/fill_buf.c
> @@ -0,0 +1,204 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * fill_buf benchmark
> + *
> + * Copyright (C) 2018 Intel Corporation
> + *
> + * Authors:
> + *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> + *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
> + *    Fenghua Yu <fenghua.yu@intel.com>
> + */
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <inttypes.h>
> +#include <malloc.h>
> +#include <string.h>
> +
> +#include "resctrl.h"
> +
> +#define CL_SIZE			(64)
> +#define PAGE_SIZE		(4 * 1024)

This is not really true everywhere. I have definitely seen systems with
cache line sizes of 32 and 128 bytes, also arm64 supports 64KB pages.
There should be POSIX/glibc functions to read those values at runtime.

> +#define MB			(1024 * 1024)
> +
> +static unsigned char *startptr;
> +
> +static void sb(void)
> +{
> +	asm volatile("sfence\n\t"
> +		     : : : "memory");

Please don't have inline x86 assembly without protecting this code on other architectures.
#if defined(__i386) || defined(__x86_64)
does the trick for me.
But aren't there already defined function for those barriers somewhere?

> +}
> +
> +static void ctrl_handler(int signo)
> +{
> +	free(startptr);
> +	printf("\nEnding\n");
> +	sb();
> +	exit(EXIT_SUCCESS);
> +}
> +
> +static void cl_flush(void *p)
> +{
> +	asm volatile("clflush (%0)\n\t"
> +		     : : "r"(p) : "memory");

Same comment about the usage of inline assembly here. This breaks compilation on arm/arm64.
In general I am a bit suspicious about using this instruction in a benchmark here, since we have no guarantee that it has an effect on the performance. The CPU could speculatively fetch in data right after this instruction. Shouldn't we iterate multiple times over the benchmark and let the average remove the effect of a hot or cold caches?

Cheers,
Andre.

> +}
> +
> +static void mem_flush(void *p, size_t s)
> +{
> +	char *cp = (char *)p;
> +	size_t i = 0;
> +
> +	s = s / CL_SIZE; /* mem size in cache llines */
> +
> +	for (i = 0; i < s; i++)
> +		cl_flush(&cp[i * CL_SIZE]);
> +
> +	sb();
> +}
> +
> +static void *malloc_and_init_memory(size_t s)
> +{
> +	uint64_t *p64;
> +	size_t s64;
> +
> +	void *p = memalign(PAGE_SIZE, s);
> +
> +	p64 = (uint64_t *)p;
> +	s64 = s / sizeof(uint64_t);
> +
> +	while (s64 > 0) {
> +		*p64 = (uint64_t)rand();
> +		p64 += (CL_SIZE / sizeof(uint64_t));
> +		s64 -= (CL_SIZE / sizeof(uint64_t));
> +	}
> +
> +	return p;
> +}
> +
> +static int fill_one_span_read(unsigned char *start_ptr, unsigned char *end_ptr)
> +{
> +	unsigned char sum, *p;
> +
> +	sum = 0;
> +	p = start_ptr;
> +	while (p < end_ptr) {
> +		sum += *p;
> +		p += (CL_SIZE / 2);
> +	}
> +
> +	return sum;
> +}
> +
> +static
> +void fill_one_span_write(unsigned char *start_ptr, unsigned char *end_ptr)
> +{
> +	unsigned char *p;
> +
> +	p = start_ptr;
> +	while (p < end_ptr) {
> +		*p = '1';
> +		p += (CL_SIZE / 2);
> +	}
> +}
> +
> +static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
> +			   char *resctrl_val)
> +{
> +	int ret = 0;
> +	FILE *fp;
> +
> +	while (1)
> +		ret = fill_one_span_read(start_ptr, end_ptr);
> +
> +	/* Consume read result so that reading memory is not optimized out. */
> +	fp = fopen("/dev/null", "w");
> +	if (!fp)
> +		perror("Unable to write to /dev/null");
> +	fprintf(fp, "Sum: %d ", ret);
> +	fclose(fp);
> +
> +	return 0;
> +}
> +
> +static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr,
> +			    char *resctrl_val)
> +{
> +	while (1)
> +		fill_one_span_write(start_ptr, end_ptr);
> +
> +	return 0;
> +}
> +
> +static int
> +fill_cache(unsigned long long buf_size, int malloc_and_init, int memflush,
> +	   int op, char *resctrl_val)
> +{
> +	unsigned char *start_ptr, *end_ptr;
> +	unsigned long long i;
> +	int ret;
> +
> +	if (malloc_and_init)
> +		start_ptr = malloc_and_init_memory(buf_size);
> +	else
> +		start_ptr = malloc(buf_size);
> +
> +	if (!start_ptr)
> +		return -1;
> +
> +	startptr = start_ptr;
> +	end_ptr = start_ptr + buf_size;
> +
> +	/*
> +	 * It's better to touch the memory once to avoid any compiler
> +	 * optimizations
> +	 */
> +	if (!malloc_and_init) {
> +		for (i = 0; i < buf_size; i++)
> +			*start_ptr++ = (unsigned char)rand();
> +	}
> +
> +	start_ptr = startptr;
> +
> +	/* Flush the memory before using to avoid "cache hot pages" effect */
> +	if (memflush)
> +		mem_flush(start_ptr, buf_size);
> +
> +	if (op == 0)
> +		ret = fill_cache_read(start_ptr, end_ptr, resctrl_val);
> +	else
> +		ret = fill_cache_write(start_ptr, end_ptr, resctrl_val);
> +
> +	if (ret) {
> +		printf("\n Errror in fill cache read/write...\n");
> +		return -1;
> +	}
> +
> +	free(startptr);
> +
> +	return 0;
> +}
> +
> +int run_fill_buf(unsigned long span, int malloc_and_init_memory,
> +		 int memflush, int op, char *resctrl_val)
> +{
> +	unsigned long long cache_size = span;
> +	int ret;
> +
> +	/* set up ctrl-c handler */
> +	if (signal(SIGINT, ctrl_handler) == SIG_ERR)
> +		printf("Failed to catch SIGINT!\n");
> +	if (signal(SIGHUP, ctrl_handler) == SIG_ERR)
> +		printf("Failed to catch SIGHUP!\n");
> +
> +	ret = fill_cache(cache_size, malloc_and_init_memory, memflush, op,
> +			 resctrl_val);
> +	if (ret) {
> +		printf("\n Errror in fill cache\n");
> +		return -1;
> +	}
> +
> +	return 0;
> +}


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 06/13] selftests/resctrl: Add MBM test
  2019-02-10  2:50 ` [PATCH v7 06/13] selftests/resctrl: Add MBM test Fenghua Yu
@ 2019-05-10 17:37   ` Andre Przywara
  0 siblings, 0 replies; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:37 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:35 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> 
> MBM (Memory Bandwidth Monitoring) test is the first implemented selftest.
> It starts a stressful memory bandwidth benchmark and assigns the
> bandwidth pid in a resctrl monitoring group. Read and compare perf IMC
> counter and MBM total bytes for the benchmark. The numbers should be
> close enough to pass the test.
> 
> Default benchmark is built-in fill_buf. But users can specify their
> own benchmark by option "-b".
> 
> We can add memory bandwidth monitoring for multiple processes in the
> future.
> 
> Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> ---
>  tools/testing/selftests/resctrl/Makefile        |   8 +-
>  tools/testing/selftests/resctrl/mbm_test.c      | 149 ++++++++++++++++++++++++
>  tools/testing/selftests/resctrl/resctrl.h       |   3 +
>  tools/testing/selftests/resctrl/resctrl_tests.c | 114 ++++++++++++++++++
>  tools/testing/selftests/resctrl/resctrl_val.c   |   2 +
>  5 files changed, 275 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/resctrl/mbm_test.c
>  create mode 100644 tools/testing/selftests/resctrl/resctrl_tests.c
> 
> diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
> index bd5c5418961e..eaa8b45de10d 100644
> --- a/tools/testing/selftests/resctrl/Makefile
> +++ b/tools/testing/selftests/resctrl/Makefile
> @@ -1,10 +1,16 @@
>  CC = gcc
>  CFLAGS = -g -Wall
>  
> +all: resctrl_tests
> +
>  *.o: *.c
>  	$(CC) $(CFLAGS) -c *.c
>  
> +resctrl_tests: *.o
> +	$(CC) $(CFLAGS) -o resctrl_tests resctrl_tests.o resctrlfs.o \
> +		 resctrl_val.o fill_buf.o mbm_test.o

This is a somewhat non-standard way of specifying things in a Makefile.
What about:

OBJS = resctrl_tests.o resctrlfs.o resctrl_val.o fill_buf.o mbm_test.o
resctrl_tests: $(OBJS)
	$(CC) $(LDFLAGS) -o $@ $^

> +
>  .PHONY: clean
>  
>  clean:
> -	$(RM) *.o *~
> +	$(RM) *.o *~ resctrl_tests
> diff --git a/tools/testing/selftests/resctrl/mbm_test.c b/tools/testing/selftests/resctrl/mbm_test.c
> new file mode 100644
> index 000000000000..dba981c562ff
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/mbm_test.c
> @@ -0,0 +1,149 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Memory Bandwidth Monitoring (MBM) test
> + *
> + * Copyright (C) 2018 Intel Corporation
> + *
> + * Authors:
> + *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> + *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
> + *    Fenghua Yu <fenghua.yu@intel.com>
> + */
> +#include "resctrl.h"
> +
> +#define RESULT_FILE_NAME	"result_mbm"
> +#define MAX_DIFF		300

What is that value? 300 MB/s? Is that some heuristic? Shouldn't that be
relative, like in the other benchmarks?

> +#define NUM_OF_RUNS		5
> +
> +static void
> +show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, int span)
> +{
> +	unsigned long avg_bw_imc = 0, avg_bw_resc = 0;

Why do you initialise those if they are overwritten below?

> +	unsigned long sum_bw_imc = 0, sum_bw_resc = 0;
> +	long avg_diff = 0;

Same here.

> +	int runs;
> +
> +	/*
> +	 * Discard the first value which is inaccurate due to monitoring setup
> +	 * transition phase.
> +	 */
> +	for (runs = 1; runs < NUM_OF_RUNS ; runs++) {
> +		sum_bw_imc += bw_imc[runs];
> +		sum_bw_resc += bw_resc[runs];
> +	}
> +
> +	avg_bw_imc = sum_bw_imc / 4;
> +	avg_bw_resc = sum_bw_resc / 4;
> +	avg_diff = avg_bw_resc - avg_bw_imc;

You could make avg_diff unsigned and use the labs() call already here.

Cheers,
Andre.

> +
> +	printf("\nSpan (MB): %d \t", span);
> +	printf("avg_bw_imc: %lu\t", avg_bw_imc);
> +	printf("avg_bw_resc: %lu\t", avg_bw_resc);
> +	printf("avg_diff: %lu\t", labs(avg_diff));
> +
> +	if (labs(avg_diff) > MAX_DIFF)
> +		printf(" failed\n");
> +	else
> +		printf(" passed\n");
> +}
> +
> +static int check_results(int span)
> +{
> +	unsigned long bw_imc[NUM_OF_RUNS], bw_resc[NUM_OF_RUNS];
> +	char temp[1024], *token_array[8];
> +	char output[] = RESULT_FILE_NAME;
> +	int runs;
> +	FILE *fp;
> +
> +	printf("\nChecking for pass/fail\n");
> +
> +	fp = fopen(output, "r");
> +	if (!fp) {
> +		perror("Error in opening file\n");
> +
> +		return errno;
> +	}
> +
> +	runs = 0;
> +	while (fgets(temp, 1024, fp)) {
> +		char *token = strtok(temp, ":\t");
> +		int i = 0;
> +
> +		while (token) {
> +			token_array[i++] = token;
> +			token = strtok(NULL, ":\t");
> +		}
> +
> +		bw_resc[runs] = strtoul(token_array[5], NULL, 0);
> +		bw_imc[runs] = strtoul(token_array[3], NULL, 0);
> +		runs++;
> +	}
> +
> +	show_bw_info(bw_imc, bw_resc, span);
> +
> +	fclose(fp);
> +
> +	return 0;
> +}
> +
> +static int mbm_setup(int num, ...)
> +{
> +	struct resctrl_val_param *p;
> +	static int num_of_runs;
> +	va_list param;
> +	int ret = 0;
> +
> +	/* Run NUM_OF_RUNS times */
> +	if (num_of_runs++ >= NUM_OF_RUNS)
> +		return -1;
> +
> +	va_start(param, num);
> +	p = va_arg(param, struct resctrl_val_param *);
> +	va_end(param);
> +
> +	/* Set up shemata with 100% allocation on the first run. */
> +	if (num_of_runs == 0)
> +		ret = write_schemata(p->ctrlgrp, "100", p->cpu_no,
> +				     p->resctrl_val);
> +
> +	return ret;
> +}
> +
> +void mbm_test_cleanup(void)
> +{
> +	remove(RESULT_FILE_NAME);
> +}
> +
> +int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd)
> +{
> +	struct resctrl_val_param param = {
> +		.resctrl_val	= "mbm",
> +		.ctrlgrp	= "c1",
> +		.mongrp		= "m1",
> +		.span		= span,
> +		.cpu_no		= cpu_no,
> +		.mum_resctrlfs	= 1,
> +		.filename	= RESULT_FILE_NAME,
> +		.bw_report	=  bw_report,
> +		.setup		= mbm_setup
> +	};
> +	int ret;
> +
> +	remove(RESULT_FILE_NAME);
> +
> +	ret = validate_resctrl_feature_request("mbm");
> +	if (ret)
> +		return ret;
> +
> +	ret = resctrl_val(benchmark_cmd, &param);
> +	if (ret)
> +		return ret;
> +
> +	ret = check_results(span);
> +	if (ret)
> +		return ret;
> +
> +	mbm_test_cleanup();
> +
> +	return 0;
> +}
> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
> index c286790ba24d..7f7ea180478c 100644
> --- a/tools/testing/selftests/resctrl/resctrl.h
> +++ b/tools/testing/selftests/resctrl/resctrl.h
> @@ -71,5 +71,8 @@ int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
>  int run_fill_buf(unsigned long span, int malloc_and_init_memory, int memflush,
>  		 int op, char *resctrl_va);
>  int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param);
> +int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd);
> +void tests_cleanup(void);
> +void mbm_test_cleanup(void);
>  
>  #endif /* RESCTRL_H */
> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
> new file mode 100644
> index 000000000000..a51780d28ff1
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Resctrl tests
> + *
> + * Copyright (C) 2018 Intel Corporation
> + *
> + * Authors:
> + *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> + *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
> + *    Fenghua Yu <fenghua.yu@intel.com>
> + */
> +#include "resctrl.h"
> +
> +#define BENCHMARK_ARGS		64
> +#define BENCHMARK_ARG_SIZE	64
> +
> +static void cmd_help(void)
> +{
> +	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list]\n");
> +	printf("\t-b benchmark_cmd [options]: run specified benchmark\n");
> +	printf("\t default benchmark is builtin fill_buf\n");
> +	printf("\t-t test list: run tests specified in the test list, ");
> +	printf("e.g. -t mbm,mba\n");
> +	printf("\t-h: help\n");
> +}
> +
> +void tests_cleanup(void)
> +{
> +	mbm_test_cleanup();
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	char benchmark_cmd_area[BENCHMARK_ARGS][BENCHMARK_ARG_SIZE];
> +	int res, c, cpu_no = 1, span = 250, argc_new = argc, i;
> +	int ben_ind;
> +	bool has_ben = false, mbm_test = true;
> +	char *benchmark_cmd[BENCHMARK_ARGS];
> +	char bw_report[64], bm_type[64];
> +
> +	for (i = 0; i < argc; i++) {
> +		if (strcmp(argv[i], "-b") == 0) {
> +			ben_ind = i + 1;
> +			argc_new = ben_ind - 1;
> +			has_ben = 1;
> +			break;
> +		}
> +	}
> +
> +	while ((c = getopt(argc_new, argv, "ht:b:")) != -1) {
> +		char *token;
> +
> +		switch (c) {
> +		case 't':
> +			token = strtok(optarg, ",");
> +
> +			mbm_test = false;
> +			while (token) {
> +				if (!strcmp(token, "mbm")) {
> +					mbm_test = true;
> +				} else {
> +					printf("invalid argument\n");
> +
> +					return -1;
> +				}
> +				token = strtok(NULL, ":\t");
> +			}
> +			break;
> +		case 'h':
> +			cmd_help();
> +
> +			return 0;
> +		default:
> +			printf("invalid argument\n");
> +
> +			return -1;
> +		}
> +	}
> +
> +	/*
> +	 * We need root privileges to run because
> +	 * 1. We write to resctrl FS
> +	 * 2. We execute perf commands
> +	 */
> +	if (geteuid() != 0) {
> +		perror("Please run this program as root\n");
> +
> +		return errno;
> +	}
> +
> +	if (!has_ben) {
> +		/* If no benchmark is given by "-b" argument, use fill_buf. */
> +		for (i = 0; i < 5; i++)
> +			benchmark_cmd[i] = benchmark_cmd_area[i];
> +		strcpy(benchmark_cmd[0], "fill_buf");
> +		sprintf(benchmark_cmd[1], "%d", span);
> +		strcpy(benchmark_cmd[2], "1");
> +		strcpy(benchmark_cmd[3], "1");
> +		strcpy(benchmark_cmd[4], "0");
> +		benchmark_cmd[5] = NULL;
> +	}
> +
> +	sprintf(bw_report, "reads");
> +	sprintf(bm_type, "fill_buf");
> +
> +	if (mbm_test) {
> +		printf("\nMBM BW Change Starting..\n");
> +		res = mbm_bw_change(span, cpu_no, bw_report, benchmark_cmd);
> +		if (res)
> +			printf("Error in running tests for mbm bw change!\n");
> +	}
> +
> +	return 0;
> +}
> diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
> index 43c15e382892..200a5b6756da 100644
> --- a/tools/testing/selftests/resctrl/resctrl_val.c
> +++ b/tools/testing/selftests/resctrl/resctrl_val.c
> @@ -437,6 +437,8 @@ pid_t bm_pid, ppid;
>  static void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
>  {
>  	kill(bm_pid, SIGKILL);
> +	umount_resctrlfs();
> +	tests_cleanup();
>  	printf("Ending\n\n");
>  
>  	exit(EXIT_SUCCESS);


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 07/13] selftests/resctrl: Add MBA test
  2019-02-10  2:50 ` [PATCH v7 07/13] selftests/resctrl: Add MBA test Fenghua Yu
@ 2019-05-10 17:37   ` Andre Przywara
  0 siblings, 0 replies; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:37 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:36 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> 
> MBA (Memory Bandwidth Allocation) test starts a stressful memory
> bandwidth benchmark and allocates memory bandwidth from 100% down
> to 10% for the benchmark process. For each allocation, compare
> perf IMC counter and mbm total bytes from resctrl. The difference
> between the two values should be within a threshold to pass the test.
> 
> Default benchmark is built-in fill_buf. But users can specify their
> own benchmark by option "-b".
> 
> We can add memory bandwidth allocation for multiple processes in the
> future.
> 
> Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> ---
>  tools/testing/selftests/resctrl/Makefile        |   2 +-
>  tools/testing/selftests/resctrl/mba_test.c      | 177 ++++++++++++++++++++++++
>  tools/testing/selftests/resctrl/resctrl.h       |   2 +
>  tools/testing/selftests/resctrl/resctrl_tests.c |  15 +-
>  4 files changed, 194 insertions(+), 2 deletions(-)
>  create mode 100644 tools/testing/selftests/resctrl/mba_test.c
> 
> diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
> index eaa8b45de10d..141cbdb619af 100644
> --- a/tools/testing/selftests/resctrl/Makefile
> +++ b/tools/testing/selftests/resctrl/Makefile
> @@ -8,7 +8,7 @@ all: resctrl_tests
>  
>  resctrl_tests: *.o
>  	$(CC) $(CFLAGS) -o resctrl_tests resctrl_tests.o resctrlfs.o \
> -		 resctrl_val.o fill_buf.o mbm_test.o
> +		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o
>  
>  .PHONY: clean
>  
> diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c
> new file mode 100644
> index 000000000000..71d8feb93ac8
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/mba_test.c
> @@ -0,0 +1,177 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Memory Bandwidth Allocation (MBA) test
> + *
> + * Copyright (C) 2018 Intel Corporation
> + *
> + * Authors:
> + *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> + *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
> + *    Fenghua Yu <fenghua.yu@intel.com>
> + */
> +#include "resctrl.h"
> +
> +#define RESULT_FILE_NAME	"result_mba"
> +#define NUM_OF_RUNS		5
> +#define MAX_DIFF		300

What is the unit here? MB/s?

> +#define ALLOCATION_MAX		100
> +#define ALLOCATION_MIN		10
> +#define ALLOCATION_STEP		10
> +
> +/*
> + * Change schemata percentage from 100 to 10%. Write schemata to specified
> + * con_mon grp, mon_grp in resctrl FS.
> + * For each allocation, run 5 times in order to get average values.
> + */
> +static int mba_setup(int num, ...)
> +{
> +	static int runs_per_allocation, allocation = 100;
> +	struct resctrl_val_param *p;
> +	char allocation_str[64];
> +	va_list param;
> +
> +	va_start(param, num);
> +	p = va_arg(param, struct resctrl_val_param *);
> +	va_end(param);
> +
> +	if (runs_per_allocation >= NUM_OF_RUNS)
> +		runs_per_allocation = 0;
> +
> +	/* Only set up schemata once every NUM_OF_RUNS of allocations */
> +	if (runs_per_allocation++ != 0)
> +		return 0;
> +
> +	if (allocation < ALLOCATION_MIN || allocation > ALLOCATION_MAX)
> +		return -1;
> +
> +	sprintf(allocation_str, "%d", allocation);
> +
> +	write_schemata(p->ctrlgrp, allocation_str, p->cpu_no, p->resctrl_val);
> +	printf("changed schemata to : %d\n", allocation);
> +	allocation -= ALLOCATION_STEP;
> +
> +	return 0;
> +}
> +
> +static void show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc)
> +{
> +	int allocation, failed = 0, runs;
> +
> +	/* Memory bandwidth from 100% down to 10% */
> +	for (allocation = 0; allocation < ALLOCATION_MAX / ALLOCATION_STEP;
> +	     allocation++) {
> +		unsigned long avg_bw_imc = 0, avg_bw_resc = 0;

No need to initialise those.

> +		unsigned long sum_bw_imc = 0, sum_bw_resc = 0;
> +		long  avg_diff = 0;

... and this one.

> +
> +		/*
> +		 * The first run is discarded due to inaccurate value from
> +		 * phase transition.
> +		 */
> +		for (runs = NUM_OF_RUNS * allocation + 1;
> +		     runs < NUM_OF_RUNS * allocation + NUM_OF_RUNS ; runs++) {
> +			sum_bw_imc += bw_imc[runs];
> +			sum_bw_resc += bw_resc[runs];
> +		}
> +
> +		avg_bw_imc = sum_bw_imc / (NUM_OF_RUNS - 1);
> +		avg_bw_resc = sum_bw_resc / (NUM_OF_RUNS - 1);
> +		avg_diff = avg_bw_resc - avg_bw_imc;

Same comment as in the last patch: use labs() here already.

Cheers,
Andre.

> +
> +		printf("\nschemata percentage: %d \t",
> +		       ALLOCATION_MAX - ALLOCATION_STEP * allocation);
> +		printf("avg_bw_imc: %lu\t", avg_bw_imc);
> +		printf("avg_bw_resc: %lu\t", avg_bw_resc);
> +		printf("avg_diff: %lu\t", labs(avg_diff));
> +		if (labs(avg_diff) > MAX_DIFF) {
> +			printf("failed\n");
> +			failed = 1;
> +		} else {
> +			printf("passed\n");
> +		}
> +	}
> +
> +	if (failed) {
> +		printf("\nTest for schemata change using MBA failed");
> +		printf("as atleast one test failed!\n");
> +	} else {
> +		printf("\nTests for changing schemata using MBA passed!\n\n");
> +	}
> +}
> +
> +static int check_results(void)
> +{
> +	char *token_array[8], output[] = RESULT_FILE_NAME, temp[512];

The size of temp[] does not match below the usage ...

> +	unsigned long bw_imc[1024], bw_resc[1024];
> +	int runs;
> +	FILE *fp;
> +
> +	printf("\nchecking for pass/fail\n");
> +	fp = fopen(output, "r");
> +	if (!fp) {
> +		perror("Error in opening file\n");
> +
> +		return errno;
> +	}
> +
> +	runs = 0;
> +	while (fgets(temp, 1024, fp)) {

... here. You could just use sizeof(temp) here.

> +		char *token = strtok(temp, ":\t");
> +		int fields = 0;
> +
> +		while (token) {
> +			token_array[fields++] = token;
> +			token = strtok(NULL, ":\t");
> +		}
> +
> +		/* Field 3 is perf imc value */
> +		bw_imc[runs] = strtoul(token_array[3], NULL, 0);
> +		/* Field 5 is resctrl value */
> +		bw_resc[runs] = strtoul(token_array[5], NULL, 0);
> +		runs++;
> +	}
> +
> +	fclose(fp);
> +
> +	show_mba_info(bw_imc, bw_resc);
> +
> +	return 0;
> +}
> +
> +void mba_test_cleanup(void)
> +{
> +	remove(RESULT_FILE_NAME);
> +}
> +
> +int mba_schemata_change(int cpu_no, char *bw_report, char **benchmark_cmd)
> +{
> +	struct resctrl_val_param param = {
> +		.resctrl_val	= "mba",
> +		.ctrlgrp	= "c1",
> +		.mongrp		= "m1",
> +		.cpu_no		= cpu_no,
> +		.mum_resctrlfs	= 1,
> +		.filename	= RESULT_FILE_NAME,
> +		.bw_report	= bw_report,
> +		.setup		= mba_setup
> +	};
> +	int ret;
> +
> +	remove(RESULT_FILE_NAME);
> +
> +	ret = validate_resctrl_feature_request("mba");
> +	if (ret)
> +		return ret;
> +
> +	ret = resctrl_val(benchmark_cmd, &param);
> +	if (ret)
> +		return ret;
> +
> +	ret = check_results();
> +	if (ret)
> +		return ret;
> +
> +	mba_test_cleanup();
> +
> +	return 0;
> +}
> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
> index 7f7ea180478c..92e5f2930c68 100644
> --- a/tools/testing/selftests/resctrl/resctrl.h
> +++ b/tools/testing/selftests/resctrl/resctrl.h
> @@ -74,5 +74,7 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param);
>  int mbm_bw_change(int span, int cpu_no, char *bw_report, char **benchmark_cmd);
>  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);
>  
>  #endif /* RESCTRL_H */
> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
> index a51780d28ff1..5fbfa8685b58 100644
> --- a/tools/testing/selftests/resctrl/resctrl_tests.c
> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
> @@ -27,6 +27,7 @@ static void cmd_help(void)
>  void tests_cleanup(void)
>  {
>  	mbm_test_cleanup();
> +	mba_test_cleanup();
>  }
>  
>  int main(int argc, char **argv)
> @@ -34,7 +35,7 @@ int main(int argc, char **argv)
>  	char benchmark_cmd_area[BENCHMARK_ARGS][BENCHMARK_ARG_SIZE];
>  	int res, c, cpu_no = 1, span = 250, argc_new = argc, i;
>  	int ben_ind;
> -	bool has_ben = false, mbm_test = true;
> +	bool has_ben = false, mbm_test = true, mba_test = true;
>  	char *benchmark_cmd[BENCHMARK_ARGS];
>  	char bw_report[64], bm_type[64];
>  
> @@ -55,9 +56,12 @@ int main(int argc, char **argv)
>  			token = strtok(optarg, ",");
>  
>  			mbm_test = false;
> +			mba_test = false;
>  			while (token) {
>  				if (!strcmp(token, "mbm")) {
>  					mbm_test = true;
> +				} else if (!strcmp(token, "mba")) {
> +					mba_test = true;
>  				} else {
>  					printf("invalid argument\n");
>  
> @@ -110,5 +114,14 @@ int main(int argc, char **argv)
>  			printf("Error in running tests for mbm bw change!\n");
>  	}
>  
> +	if (mba_test) {
> +		printf("\nMBA Schemata Change Starting..\n");
> +		if (!has_ben)
> +			sprintf(benchmark_cmd[1], "%d", span);
> +		res = mba_schemata_change(cpu_no, bw_report, benchmark_cmd);
> +		if (res)
> +			printf("Error in tests for mba-change-schemata!\n");
> +	}
> +
>  	return 0;
>  }


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 08/13] selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest
  2019-02-10  2:50 ` [PATCH v7 08/13] selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest Fenghua Yu
@ 2019-05-10 17:38   ` Andre Przywara
  0 siblings, 0 replies; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:38 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:37 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> 
> 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.
> 
> Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> ---
>  tools/testing/selftests/resctrl/Makefile        |   2 +-
>  tools/testing/selftests/resctrl/cache.c         | 101 +++++++++++
>  tools/testing/selftests/resctrl/cqm_test.c      | 173 ++++++++++++++++++
>  tools/testing/selftests/resctrl/mba_test.c      |   1 +
>  tools/testing/selftests/resctrl/mbm_test.c      |   1 +
>  tools/testing/selftests/resctrl/resctrl.h       |  23 ++-
>  tools/testing/selftests/resctrl/resctrl_tests.c |  56 ++++--
>  tools/testing/selftests/resctrl/resctrl_val.c   |  95 ++++++----
>  tools/testing/selftests/resctrl/resctrlfs.c     | 227 ++++++++++++++++++++++--
>  9 files changed, 614 insertions(+), 65 deletions(-)
>  create mode 100644 tools/testing/selftests/resctrl/cache.c
>  create mode 100644 tools/testing/selftests/resctrl/cqm_test.c
> 
> diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
> index 141cbdb619af..664561cd76e6 100644
> --- a/tools/testing/selftests/resctrl/Makefile
> +++ b/tools/testing/selftests/resctrl/Makefile
> @@ -8,7 +8,7 @@ all: resctrl_tests
>  
>  resctrl_tests: *.o
>  	$(CC) $(CFLAGS) -o resctrl_tests resctrl_tests.o resctrlfs.o \
> -		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o
> +		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o cache.o cqm_test.o
>  
>  .PHONY: clean
>  
> diff --git a/tools/testing/selftests/resctrl/cache.c b/tools/testing/selftests/resctrl/cache.c
> new file mode 100644
> index 000000000000..876dc647b3ca
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/cache.c
> @@ -0,0 +1,101 @@
> +// 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 cbm_mask[256];
> +unsigned long long_mask;
> +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;
> +}
> diff --git a/tools/testing/selftests/resctrl/cqm_test.c b/tools/testing/selftests/resctrl/cqm_test.c
> new file mode 100644
> index 000000000000..a81946ad11d1
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/cqm_test.c
> @@ -0,0 +1,173 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Cache Monitoring Technology (CQM) test
> + *
> + * Copyright (C) 2018 Intel Corporation
> + *
> + * Authors:
> + *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> + *    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

What unit is this?

> +#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;

No need to initialise.

> +	long avg_diff = 0;
> +	float diff_percent;

Why is this a float?

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

This looks strange to me. First: abs() is definitely wrong, it should be labs(). But this cast seems pointless, I think you want to have:
	avg_diff = labs((long int)(span - avg_llc_occu_resc));

The cast should not be necessary (unsigned - unsigned can be signed), but gcc warns about it without that.

> +
> +	printf("\nResults are displayed in (Bytes)\n");
> +	printf("\nNumber of bits: %d \t", no_of_bits);
> +	printf("Avg_llc_occu_resc: %lu \t", avg_llc_occu_resc);
> +	printf("llc_occu_exp (span): %lu \t", span);
> +
> +	diff_percent = (((float)span - avg_llc_occu_resc) / span) * 100;

I would just write this as:

	diff_percent = avg_diff * 100 / span;

> +
> +	printf("Diff: %ld \t", avg_diff);
> +	printf("Percent diff=%d\t", abs((int)diff_percent));
> +
> +	if ((abs((int)diff_percent) <= MAX_DIFF_PERCENT) ||
> +	    (abs(avg_diff) <= MAX_DIFF))

... which allows you to get rid of all those fancy casts and abs() calls
here.


> +		printf("Passed\n");
> +	else
> +		printf("Failed\n");
> +}
> +
> +static int check_results(struct resctrl_val_param *param, int no_of_bits)
> +{
> +	char *token_array[8], temp[512];

This size here does not match ....

> +	unsigned long sum_llc_occu_resc = 0;
> +	int runs = 0;
> +	FILE *fp;
> +
> +	printf("\nchecking for pass/fail\n");
> +	fp = fopen(param->filename, "r");
> +	if (!fp) {
> +		perror("Error in opening file\n");
> +
> +		return errno;
> +	}
> +
> +	while (fgets(temp, 1024, fp)) {

this user. Just use sizeof(temp).

Cheers,
Andre.

> +		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;
> +
> +	ret = validate_resctrl_feature_request("cqm");
> +	if (ret)
> +		return ret;
> +
> +	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], "%llu", 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;
> +}
> diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c
> index 71d8feb93ac8..329d1c84c82c 100644
> --- a/tools/testing/selftests/resctrl/mba_test.c
> +++ b/tools/testing/selftests/resctrl/mba_test.c
> @@ -57,6 +57,7 @@ static void show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc)
>  {
>  	int allocation, failed = 0, runs;
>  
> +	printf("\nResults are displayed in (MB)\n");
>  	/* Memory bandwidth from 100% down to 10% */
>  	for (allocation = 0; allocation < ALLOCATION_MAX / ALLOCATION_STEP;
>  	     allocation++) {
> diff --git a/tools/testing/selftests/resctrl/mbm_test.c b/tools/testing/selftests/resctrl/mbm_test.c
> index dba981c562ff..726e3a8fb98f 100644
> --- a/tools/testing/selftests/resctrl/mbm_test.c
> +++ b/tools/testing/selftests/resctrl/mbm_test.c
> @@ -36,6 +36,7 @@ show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, int span)
>  	avg_bw_resc = sum_bw_resc / 4;
>  	avg_diff = avg_bw_resc - avg_bw_imc;
>  
> +	printf("\nResults are displayed in (MB)\n");
>  	printf("\nSpan (MB): %d \t", span);
>  	printf("avg_bw_imc: %lu\t", avg_bw_imc);
>  	printf("avg_bw_resc: %lu\t", avg_bw_resc);
> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
> index 92e5f2930c68..2097b02a356d 100644
> --- a/tools/testing/selftests/resctrl/resctrl.h
> +++ b/tools/testing/selftests/resctrl/resctrl.h
> @@ -16,11 +16,18 @@
>  #include <sys/ioctl.h>
>  #include <sys/mount.h>
>  #include <sys/types.h>
> +#include <sys/select.h>
>  #include <asm/unistd.h>
>  #include <linux/perf_event.h>
> +#include <sys/time.h>
> +#include <math.h>
> +#include <sys/wait.h>
> +#include <sys/eventfd.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 {					\
> @@ -46,14 +53,20 @@ struct resctrl_val_param {
>  	char	ctrlgrp[64];
>  	char	mongrp[64];
>  	int	cpu_no;
> -	int	span;
> +	unsigned long long span;
>  	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;
> +extern char cbm_mask[256];
> +extern unsigned long long_mask;
> +extern char llc_occup_path[1024];
>  
>  int remount_resctrlfs(bool mum_resctrlfs);
>  int get_resource_id(int cpu_no, int *resource_id);
> @@ -76,5 +89,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 */
> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
> index 5fbfa8685b58..5a9af019b5e5 100644
> --- a/tools/testing/selftests/resctrl/resctrl_tests.c
> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
> @@ -16,11 +16,13 @@
>  
>  static void cmd_help(void)
>  {
> -	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list]\n");
> -	printf("\t-b benchmark_cmd [options]: run specified benchmark\n");
> +	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list] [-n no_of_bits]\n");
> +	printf("\t-b benchmark_cmd [options]: run specified benchmark for MBM, MBA and CQM");
>  	printf("\t default benchmark is builtin fill_buf\n");
>  	printf("\t-t test list: run tests specified in the test list, ");
> -	printf("e.g. -t mbm,mba\n");
> +	printf("e.g. -t mbm, mba, cqm\n");
> +	printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n");
> +	printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n");
>  	printf("\t-h: help\n");
>  }
>  
> @@ -28,20 +30,22 @@ void tests_cleanup(void)
>  {
>  	mbm_test_cleanup();
>  	mba_test_cleanup();
> +	cqm_test_cleanup();
>  }
>  
>  int main(int argc, char **argv)
>  {
>  	char benchmark_cmd_area[BENCHMARK_ARGS][BENCHMARK_ARG_SIZE];
> -	int res, c, cpu_no = 1, span = 250, argc_new = argc, i;
> -	int ben_ind;
> -	bool has_ben = false, mbm_test = true, mba_test = true;
> +	int res, c, cpu_no = 1, span = 250, argc_new = argc, i, no_of_bits = 5;
> +	int ben_ind, ben_count;
> +	bool has_ben = false, mbm_test = true, mba_test = true, cqm_test = true;
>  	char *benchmark_cmd[BENCHMARK_ARGS];
>  	char bw_report[64], bm_type[64];
>  
>  	for (i = 0; i < argc; i++) {
>  		if (strcmp(argv[i], "-b") == 0) {
>  			ben_ind = i + 1;
> +			ben_count = argc - ben_ind;
>  			argc_new = ben_ind - 1;
>  			has_ben = 1;
>  			break;
> @@ -57,11 +61,14 @@ int main(int argc, char **argv)
>  
>  			mbm_test = false;
>  			mba_test = false;
> +			cqm_test = false;
>  			while (token) {
>  				if (!strcmp(token, "mbm")) {
>  					mbm_test = true;
>  				} else if (!strcmp(token, "mba")) {
>  					mba_test = true;
> +				} else if (!strcmp(token, "cqm")) {
> +					cqm_test = true;
>  				} else {
>  					printf("invalid argument\n");
>  
> @@ -70,6 +77,12 @@ int main(int argc, char **argv)
>  				token = strtok(NULL, ":\t");
>  			}
>  			break;
> +		case 'n':
> +			no_of_bits = atoi(optarg);
> +			break;
> +		case 'p':
> +			cpu_no = atoi(optarg);
> +			break;
>  		case 'h':
>  			cmd_help();
>  
> @@ -92,16 +105,25 @@ int main(int argc, char **argv)
>  		return errno;
>  	}
>  
> -	if (!has_ben) {
> +	if (has_ben) {
> +		/* Extract benchmark command from command line. */
> +		for (i = ben_ind; i < argc; i++) {
> +			benchmark_cmd[i - ben_ind] = benchmark_cmd_area[i];
> +			sprintf(benchmark_cmd[i - ben_ind], "%s", argv[i]);
> +		}
> +		benchmark_cmd[ben_count] = NULL;
> +	} else {
>  		/* If no benchmark is given by "-b" argument, use fill_buf. */
> -		for (i = 0; i < 5; i++)
> +		for (i = 0; i < 6; i++)
>  			benchmark_cmd[i] = benchmark_cmd_area[i];
> +
>  		strcpy(benchmark_cmd[0], "fill_buf");
>  		sprintf(benchmark_cmd[1], "%d", span);
>  		strcpy(benchmark_cmd[2], "1");
>  		strcpy(benchmark_cmd[3], "1");
>  		strcpy(benchmark_cmd[4], "0");
> -		benchmark_cmd[5] = NULL;
> +		strcpy(benchmark_cmd[5], "");
> +		benchmark_cmd[6] = NULL;
>  	}
>  
>  	sprintf(bw_report, "reads");
> @@ -109,18 +131,32 @@ int main(int argc, char **argv)
>  
>  	if (mbm_test) {
>  		printf("\nMBM BW Change Starting..\n");
> +		if (!has_ben)
> +			sprintf(benchmark_cmd[5], "%s", "mbm");
>  		res = mbm_bw_change(span, cpu_no, bw_report, benchmark_cmd);
>  		if (res)
>  			printf("Error in running tests for mbm bw change!\n");
> +		mbm_test_cleanup();
>  	}
>  
>  	if (mba_test) {
>  		printf("\nMBA Schemata Change Starting..\n");
>  		if (!has_ben)
> -			sprintf(benchmark_cmd[1], "%d", span);
> +			sprintf(benchmark_cmd[5], "%s", "mba");
>  		res = mba_schemata_change(cpu_no, bw_report, benchmark_cmd);
>  		if (res)
>  			printf("Error in tests for mba-change-schemata!\n");
> +		mba_test_cleanup();
> +	}
> +
> +	if (cqm_test) {
> +		printf("\nCQM Test Starting..\n");
> +		if (!has_ben)
> +			sprintf(benchmark_cmd[5], "%s", "cqm");
> +		res = cqm_resctrl_val(cpu_no, no_of_bits, benchmark_cmd);
> +		if (res)
> +			printf("Error in CQM test!\n");
> +		cqm_test_cleanup();
>  	}
>  
>  	return 0;
> diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
> index 200a5b6756da..edf6a38d6457 100644
> --- a/tools/testing/selftests/resctrl/resctrl_val.c
> +++ b/tools/testing/selftests/resctrl/resctrl_val.c
> @@ -11,7 +11,6 @@
>   */
>  #include "resctrl.h"
>  
> -#define MB			(1024 * 1024)
>  #define UNCORE_IMC		"uncore_imc"
>  #define READ_FILE_NAME		"events/cas_count_read"
>  #define WRITE_FILE_NAME		"events/cas_count_write"
> @@ -33,6 +32,18 @@
>  #define MBM_LOCAL_BYTES_PATH			\
>  	"%s/mon_data/mon_L3_%02d/mbm_local_bytes"
>  
> +#define CON_MON_LCC_OCCUP_PATH		\
> +	"%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
> +
> +#define CON_LCC_OCCUP_PATH		\
> +	"%s/%s/mon_data/mon_L3_%02d/llc_occupancy"
> +
> +#define MON_LCC_OCCUP_PATH		\
> +	"%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
> +
> +#define LCC_OCCUP_PATH			\
> +	"%s/mon_data/mon_L3_%02d/llc_occupancy"
> +
>  struct membw_read_format {
>  	__u64 value;         /* The value of the event */
>  	__u64 time_enabled;  /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
> @@ -207,12 +218,12 @@ static int read_from_imc_dir(char *imc_dir, int count)
>   * A config again has two parts, event and umask.
>   * Enumerate all these details into an array of structures.
>   *
> - * Return: >= 0 on success. < 0 on failure.
> + * Return: > 0 on success. <= 0 on failure.
>   */
>  static int num_of_imcs(void)
>  {
>  	unsigned int count = 0;
> -	char imc_dir[1024];
> +	char imc_dir[512];
>  	struct dirent *ep;
>  	int ret;
>  	DIR *dp;
> @@ -434,16 +445,6 @@ static unsigned long get_mem_bw_resctrl(void)
>  
>  pid_t bm_pid, ppid;
>  
> -static void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
> -{
> -	kill(bm_pid, SIGKILL);
> -	umount_resctrlfs();
> -	tests_cleanup();
> -	printf("Ending\n\n");
> -
> -	exit(EXIT_SUCCESS);
> -}
> -
>  /*
>   * print_results_bw:	the memory bandwidth results are stored in a file
>   * @filename:		file that stores the results
> @@ -482,6 +483,42 @@ static int print_results_bw(char *filename,  int bm_pid, float bw_imc,
>  	return 0;
>  }
>  
> +static void set_cqm_path(const char *ctrlgrp, const char *mongrp, char sock_num)
> +{
> +	if (strlen(ctrlgrp) && strlen(mongrp))
> +		sprintf(llc_occup_path,	CON_MON_LCC_OCCUP_PATH,	RESCTRL_PATH,
> +			ctrlgrp, mongrp, sock_num);
> +	else if (!strlen(ctrlgrp) && strlen(mongrp))
> +		sprintf(llc_occup_path,	MON_LCC_OCCUP_PATH, RESCTRL_PATH,
> +			mongrp, sock_num);
> +	else if (strlen(ctrlgrp) && !strlen(mongrp))
> +		sprintf(llc_occup_path,	CON_LCC_OCCUP_PATH, RESCTRL_PATH,
> +			ctrlgrp, sock_num);
> +	else if (!strlen(ctrlgrp) && !strlen(mongrp))
> +		sprintf(llc_occup_path, LCC_OCCUP_PATH,	RESCTRL_PATH, sock_num);
> +}
> +
> +/*
> + * initialize_llc_occu_resctrl:	Appropriately populate "llc_occup_path"
> + * @ctrlgrp:			Name of the control monitor group (con_mon grp)
> + * @mongrp:			Name of the monitor group (mon grp)
> + * @cpu_no:			CPU number that the benchmark PID is binded to
> + * @resctrl_val:		Resctrl feature (Eg: cat, cqm.. etc)
> + */
> +static void initialize_llc_occu_resctrl(const char *ctrlgrp, const char *mongrp,
> +					int cpu_no, char *resctrl_val)
> +{
> +	int resource_id;
> +
> +	if (get_resource_id(cpu_no, &resource_id) < 0) {
> +		perror("Unable to resource_id");
> +		return;
> +	}
> +
> +	if (strcmp(resctrl_val, "cqm") == 0)
> +		set_cqm_path(ctrlgrp, mongrp, resource_id);
> +}
> +
>  static int
>  measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
>  {
> @@ -528,14 +565,10 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
>  	unsigned long bw_resc_start = 0;
>  	struct sigaction sigact;
>  	union sigval value;
> -	FILE *fp;
>  
>  	if (strcmp(param->filename, "") == 0)
>  		sprintf(param->filename, "stdio");
>  
> -	if (strcmp(param->bw_report, "") == 0)
> -		param->bw_report = "total";
> -
>  	if ((strcmp(resctrl_val, "mba")) == 0 ||
>  	    (strcmp(resctrl_val, "mbm")) == 0) {
>  		ret = validate_bw_report_request(param->bw_report);
> @@ -553,21 +586,6 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
>  	 */
>  	ppid = getpid();
>  
> -	/* File based synchronization between parent and child */
> -	fp = fopen("sig", "w");
> -	if (!fp) {
> -		perror("Failed to open sig file");
> -
> -		return -1;
> -	}
> -	if (fprintf(fp, "%d\n", 0) <= 0) {
> -		perror("Unable to establish sync bw parent & child");
> -		fclose(fp);
> -
> -		return -1;
> -	}
> -	fclose(fp);
> -
>  	if (pipe(pipefd)) {
>  		perror("Unable to create pipe");
>  
> @@ -649,7 +667,9 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
>  
>  		initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
>  					  param->cpu_no, resctrl_val);
> -	}
> +	} else if (strcmp(resctrl_val, "cqm") == 0)
> +		initialize_llc_occu_resctrl(param->ctrlgrp, param->mongrp,
> +					    param->cpu_no, resctrl_val);
>  
>  	/* Parent waits for child to be ready. */
>  	close(pipefd[1]);
> @@ -669,7 +689,8 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
>  
>  	/* Test runs until the callback setup() tells the test to stop. */
>  	while (1) {
> -		if (strcmp(resctrl_val, "mbm") == 0) {
> +		if ((strcmp(resctrl_val, "mbm") == 0) ||
> +		    (strcmp(resctrl_val, "mba") == 0)) {
>  			ret = param->setup(1, param);
>  			if (ret) {
>  				ret = 0;
> @@ -679,14 +700,14 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
>  			ret = measure_vals(param, &bw_resc_start);
>  			if (ret)
>  				break;
> -		} else if ((strcmp(resctrl_val, "mba") == 0)) {
> +		} else if (strcmp(resctrl_val, "cqm") == 0) {
>  			ret = param->setup(1, param);
>  			if (ret) {
>  				ret = 0;
>  				break;
>  			}
> -
> -			ret = measure_vals(param, &bw_resc_start);
> +			sleep(1);
> +			ret = measure_cache_vals(param, bm_pid);
>  			if (ret)
>  				break;
>  		} else {
> diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
> index 5afcaa89f418..6dacd215ace6 100644
> --- a/tools/testing/selftests/resctrl/resctrlfs.c
> +++ b/tools/testing/selftests/resctrl/resctrlfs.c
> @@ -13,12 +13,18 @@
>  
>  #define RESCTRL_MBM		"L3 monitoring detected"
>  #define RESCTRL_MBA		"MB allocation detected"
> +#define RESCTRL_CQM		"L3 monitoring detected"
> +#define CORE_SIBLINGS_PATH	"/sys/bus/cpu/devices/cpu"
> +
>  enum {
>  	RESCTRL_FEATURE_MBM,
>  	RESCTRL_FEATURE_MBA,
> +	RESCTRL_FEATURE_CQM,
>  	MAX_RESCTRL_FEATURES
>  };
>  
> +char cbm_mask[256];
> +
>  /*
>   * remount_resctrlfs - Remount resctrl FS at /sys/fs/resctrl
>   * @mum_resctrlfs:	Should the resctrl FS be remounted?
> @@ -62,7 +68,7 @@ int remount_resctrlfs(bool mum_resctrlfs)
>  
>  				return errno;
>  			}
> -			printf("Remount: done!\n");
> +			printf("umount: done!\n");
>  		} else {
>  			printf("Mounted already. Not remounting!\n");
>  
> @@ -122,6 +128,143 @@ int get_resource_id(int cpu_no, int *resource_id)
>  }
>  
>  /*
> + * get_cache_size - Get cache size for a specified CPU
> + * @cpu_no:	CPU number
> + * @cache_type:	Cache level L2/L3
> + * @cache_size:	pointer to cache_size
> + *
> + * Return: = 0 on success, < 0 on failure.
> + */
> +int get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size)
> +{
> +	char cache_path[1024], cache_str[64];
> +	int length, i, cache_num;
> +	FILE *fp;
> +
> +	if (!strcmp(cache_type, "L3")) {
> +		cache_num = 3;
> +	} else if (!strcmp(cache_type, "L2")) {
> +		cache_num = 2;
> +	} else {
> +		perror("Invalid cache level");
> +		return -1;
> +	}
> +
> +	sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size",
> +		cpu_no, cache_num);
> +	fp = fopen(cache_path, "r");
> +	if (!fp) {
> +		perror("Failed to open cache size");
> +
> +		return -1;
> +	}
> +	if (fscanf(fp, "%s", cache_str) <= 0) {
> +		perror("Could not get cache_size");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	length = (int)strlen(cache_str);
> +
> +	*cache_size = 0;
> +
> +	for (i = 0; i < length; i++) {
> +		if ((cache_str[i] >= '0') && (cache_str[i] <= '9'))
> +
> +			*cache_size = *cache_size * 10 + (cache_str[i] - '0');
> +
> +		else if (cache_str[i] == 'K')
> +
> +			*cache_size = *cache_size * 1024;
> +
> +		else if (cache_str[i] == 'M')
> +
> +			*cache_size = *cache_size * 1024 * 1024;
> +
> +		else
> +			break;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * get_cbm_mask - Get cbm mask for given cache
> + * @cache_type:	Cache level L2/L3
> + *
> + * Mask is stored in cbm_mask which is global variable.
> + *
> + * Return: = 0 on success, < 0 on failure.
> + */
> +int get_cbm_mask(char *cache_type)
> +{
> +	char cbm_mask_path[1024];
> +	FILE *fp;
> +
> +	sprintf(cbm_mask_path, "%s/%s/cbm_mask", CBM_MASK_PATH, cache_type);
> +
> +	fp = fopen(cbm_mask_path, "r");
> +	if (!fp) {
> +		perror("Failed to open cache level");
> +
> +		return -1;
> +	}
> +	if (fscanf(fp, "%s", cbm_mask) <= 0) {
> +		perror("Could not get max cbm_mask");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	return 0;
> +}
> +
> +/*
> + * get_core_sibling - Get sibling core id from the same socket for given CPU
> + * @cpu_no:	CPU number
> + *
> + * Return:	> 0 on success, < 0 on failure.
> + */
> +int get_core_sibling(int cpu_no)
> +{
> +	char core_siblings_path[1024], cpu_list_str[64];
> +	int sibling_cpu_no = -1;
> +	FILE *fp;
> +
> +	sprintf(core_siblings_path, "%s%d/topology/core_siblings_list",
> +		CORE_SIBLINGS_PATH, cpu_no);
> +
> +	fp = fopen(core_siblings_path, "r");
> +	if (!fp) {
> +		perror("Failed to open core siblings path");
> +
> +		return -1;
> +	}
> +	if (fscanf(fp, "%s", cpu_list_str) <= 0) {
> +		perror("Could not get core_siblings list");
> +		fclose(fp);
> +
> +		return -1;
> +	}
> +	fclose(fp);
> +
> +	char *token = strtok(cpu_list_str, "-,");
> +
> +	while (token) {
> +		sibling_cpu_no = atoi(token);
> +		/* Skipping core 0 as we don't want to run test on core 0 */
> +		if (sibling_cpu_no != 0)
> +			break;
> +		token = strtok(NULL, "-,");
> +	}
> +
> +	return sibling_cpu_no;
> +}
> +
> +/*
>   * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
>   * @bm_pid:	PID that should be binded
>   * @cpu_no:	CPU number at which the PID would be binded
> @@ -157,9 +300,10 @@ int taskset_benchmark(pid_t bm_pid, int cpu_no)
>   */
>  void run_benchmark(int signum, siginfo_t *info, void *ucontext)
>  {
> -	unsigned long long span;
> -	int operation, ret;
> +	int operation, ret, malloc_and_init_memory, memflush;
> +	unsigned long long span, buffer_span;
>  	char **benchmark_cmd;
> +	char resctrl_val[64];
>  	FILE *fp;
>  
>  	benchmark_cmd = info->si_ptr;
> @@ -175,8 +319,18 @@ void run_benchmark(int signum, siginfo_t *info, void *ucontext)
>  	if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
>  		/* Execute default fill_buf benchmark */
>  		span = strtoul(benchmark_cmd[1], NULL, 10);
> +		malloc_and_init_memory = atoi(benchmark_cmd[2]);
> +		memflush =  atoi(benchmark_cmd[3]);
>  		operation = atoi(benchmark_cmd[4]);
> -		if (run_fill_buf(span, 1, 1, operation, NULL))
> +		sprintf(resctrl_val, "%s", benchmark_cmd[5]);
> +
> +		if (strcmp(resctrl_val, "cqm") != 0)
> +			buffer_span = span * MB;
> +		else
> +			buffer_span = span;
> +
> +		if (run_fill_buf(buffer_span, malloc_and_init_memory, memflush,
> +				 operation, resctrl_val))
>  			fprintf(stderr, "Error in running fill buffer\n");
>  	} else {
>  		/* Execute specified benchmark */
> @@ -203,6 +357,14 @@ static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
>  	struct dirent *ep;
>  	DIR *dp;
>  
> +	/*
> +	 * At this point, we are guaranteed to have resctrl FS mounted and if
> +	 * length of grp_name == 0, it means, user wants to use root con_mon
> +	 * grp, so do nothing
> +	 */
> +	if (strlen(grp_name) == 0)
> +		return 0;
> +
>  	/* Check if requested grp exists or not */
>  	dp = opendir(parent_grp);
>  	if (dp) {
> @@ -268,11 +430,11 @@ static int write_pid_to_tasks(char *tasks, pid_t pid)
>  int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
>  			    char *resctrl_val)
>  {
> -	char controlgroup[256], monitorgroup[256], monitorgroup_p[256];
> -	char tasks[256];
> +	char controlgroup[128], monitorgroup[512], monitorgroup_p[256];
> +	char tasks[1024];
>  	int ret;
>  
> -	if (ctrlgrp)
> +	if (strlen(ctrlgrp))
>  		sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
>  	else
>  		sprintf(controlgroup, "%s", RESCTRL_PATH);
> @@ -286,9 +448,10 @@ int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
>  	if (ret)
>  		return ret;
>  
> -	/* Create mon grp and write pid into it for "mbm" test */
> -	if ((strcmp(resctrl_val, "mbm") == 0)) {
> -		if (mongrp) {
> +	/* Create mon grp and write pid into it for "mbm" and "cqm" test */
> +	if ((strcmp(resctrl_val, "cqm") == 0) ||
> +	    (strcmp(resctrl_val, "mbm") == 0)) {
> +		if (strlen(mongrp)) {
>  			sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
>  			sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
>  			ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
> @@ -326,7 +489,8 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
>  	int resource_id;
>  	FILE *fp;
>  
> -	if (strcmp(resctrl_val, "mba") == 0) {
> +	if ((strcmp(resctrl_val, "mba") == 0) ||
> +	    (strcmp(resctrl_val, "cqm") == 0)) {
>  		if (!schemata) {
>  			printf("Schemata empty, so not updating\n");
>  
> @@ -337,12 +501,18 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
>  			return -1;
>  		}
>  
> -		if (ctrlgrp)
> +		if (strlen(ctrlgrp) != 0)
>  			sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH,
>  				ctrlgrp);
>  		else
>  			sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
> -		sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=', schemata);
> +
> +		if (!strcmp(resctrl_val, "cqm"))
> +			sprintf(schema, "%s%d%c%s", "L3:", resource_id, '=',
> +				schemata);
> +		if (strcmp(resctrl_val, "mba") == 0)
> +			sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=',
> +				schemata);
>  
>  		fp = fopen(controlgroup, "w");
>  		if (!fp) {
> @@ -359,7 +529,7 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
>  		}
>  		fclose(fp);
>  
> -		printf("Write schemata to resctrl FS: done!\n");
> +		printf("Write schemata with %s to resctrl FS: done!\n", schema);
>  	}
>  
>  	return 0;
> @@ -375,7 +545,7 @@ int validate_resctrl_feature_request(char *resctrl_val)
>  {
>  	int resctrl_features_supported[MAX_RESCTRL_FEATURES];
>  	const char *resctrl_features_list[MAX_RESCTRL_FEATURES] = {
> -			"mbm", "mba"};
> +			"mbm", "mba", "cqm"};
>  	int i, valid_resctrl_feature = -1;
>  	char line[1024];
>  	FILE *fp;
> @@ -419,6 +589,9 @@ int validate_resctrl_feature_request(char *resctrl_val)
>  			resctrl_features_supported[RESCTRL_FEATURE_MBM] = 1;
>  		if ((strstr(line, RESCTRL_MBA)) != NULL)
>  			resctrl_features_supported[RESCTRL_FEATURE_MBA] = 1;
> +		if ((strstr(line, RESCTRL_CQM)) != NULL)
> +			resctrl_features_supported[RESCTRL_FEATURE_CQM] = 1;
> +
>  	}
>  	fclose(fp);
>  
> @@ -427,7 +600,7 @@ int validate_resctrl_feature_request(char *resctrl_val)
>  
>  	/* Is the resctrl feature request supported? */
>  	if (!resctrl_features_supported[valid_resctrl_feature]) {
> -		fprintf(stderr, "resctrl feature not supported!");
> +		fprintf(stderr, "resctrl feature not supported!\n");
>  
>  		return -1;
>  	}
> @@ -462,3 +635,25 @@ int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
>  		      group_fd, flags);
>  	return ret;
>  }
> +
> +void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
> +{
> +	kill(bm_pid, SIGKILL);
> +	umount_resctrlfs();
> +	tests_cleanup();
> +	printf("Ending\n\n");
> +
> +	exit(EXIT_SUCCESS);
> +}
> +
> +unsigned int count_bits(unsigned long n)
> +{
> +	unsigned int count = 0;
> +
> +	while (n) {
> +		count += n & 1;
> +		n >>= 1;
> +	}
> +
> +	return count;
> +}


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 09/13] selftests/resctrl: Add Cache Allocation Technology (CAT) selftest
  2019-02-10  2:50 ` [PATCH v7 09/13] selftests/resctrl: Add Cache Allocation Technology (CAT) selftest Fenghua Yu
@ 2019-05-10 17:38   ` Andre Przywara
  0 siblings, 0 replies; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:38 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:38 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> 
> Cache Allocation Technology (CAT) selftest allocates a portion of
> last level cache and starts a benchmark to read each cache
> line in this portion of cache. Measure the cache misses in perf and
> the misses should be equal to the number of cache lines in this
> portion of cache.
> 
> We don't use CQM to calculate cache usage because some CAT enabled
> platforms don't have CQM.
> 
> Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> ---
>  tools/testing/selftests/resctrl/Makefile        |   2 +-
>  tools/testing/selftests/resctrl/cache.c         | 175 ++++++++++++++++-
>  tools/testing/selftests/resctrl/cat_test.c      | 242 ++++++++++++++++++++++++
>  tools/testing/selftests/resctrl/fill_buf.c      |  10 +-
>  tools/testing/selftests/resctrl/resctrl.h       |   3 +
>  tools/testing/selftests/resctrl/resctrl_tests.c |  14 +-
>  tools/testing/selftests/resctrl/resctrlfs.c     |  10 +-
>  7 files changed, 448 insertions(+), 8 deletions(-)
>  create mode 100644 tools/testing/selftests/resctrl/cat_test.c
> 
> diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
> index 664561cd76e6..0282222b4c22 100644
> --- a/tools/testing/selftests/resctrl/Makefile
> +++ b/tools/testing/selftests/resctrl/Makefile
> @@ -8,7 +8,7 @@ all: resctrl_tests
>  
>  resctrl_tests: *.o
>  	$(CC) $(CFLAGS) -o resctrl_tests resctrl_tests.o resctrlfs.o \
> -		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o cache.o cqm_test.o
> +		 resctrl_val.o fill_buf.o mbm_test.o mba_test.o cache.o cqm_test.o cat_test.o
>  
>  .PHONY: clean
>  
> diff --git a/tools/testing/selftests/resctrl/cache.c b/tools/testing/selftests/resctrl/cache.c
> index 876dc647b3ca..04b7aafdb409 100644
> --- a/tools/testing/selftests/resctrl/cache.c
> +++ b/tools/testing/selftests/resctrl/cache.c
> @@ -10,10 +10,107 @@ struct read_format {
>  	} values[2];
>  };
>  
> +static struct perf_event_attr pea_llc_miss;
> +static struct read_format rf_cqm;
> +static int fd_lm;
>  char cbm_mask[256];
>  unsigned long long_mask;
>  char llc_occup_path[1024];
>  
> +static void initialize_perf_event_attr(void)
> +{
> +	pea_llc_miss.type = PERF_TYPE_HARDWARE;
> +	pea_llc_miss.size = sizeof(struct perf_event_attr);
> +	pea_llc_miss.read_format = PERF_FORMAT_GROUP;
> +	pea_llc_miss.exclude_kernel = 1;
> +	pea_llc_miss.exclude_hv = 1;
> +	pea_llc_miss.exclude_idle = 1;
> +	pea_llc_miss.exclude_callchain_kernel = 1;
> +	pea_llc_miss.inherit = 1;
> +	pea_llc_miss.exclude_guest = 1;
> +	pea_llc_miss.disabled = 1;
> +}
> +
> +static void ioctl_perf_event_ioc_reset_enable(void)
> +{
> +	ioctl(fd_lm, PERF_EVENT_IOC_RESET, 0);
> +	ioctl(fd_lm, PERF_EVENT_IOC_ENABLE, 0);
> +}
> +
> +static int perf_event_open_llc_miss(pid_t pid, int cpu_no)
> +{
> +	fd_lm = perf_event_open(&pea_llc_miss, pid, cpu_no, -1,
> +				PERF_FLAG_FD_CLOEXEC);
> +	if (fd_lm == -1) {
> +		perror("Error opening leader");
> +		ctrlc_handler(0, NULL, NULL);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int initialize_llc_perf(void)
> +{
> +	memset(&pea_llc_miss, 0, sizeof(struct perf_event_attr));
> +	memset(&rf_cqm, 0, sizeof(struct read_format));
> +
> +	/* Initialize perf_event_attr structures for HW_CACHE_MISSES */
> +	initialize_perf_event_attr();
> +
> +	pea_llc_miss.config = PERF_COUNT_HW_CACHE_MISSES;
> +
> +	rf_cqm.nr = 1;
> +
> +	return 0;
> +}
> +
> +static int reset_enable_llc_perf(pid_t pid, int cpu_no)
> +{
> +	int ret = 0;
> +
> +	ret = perf_event_open_llc_miss(pid, cpu_no);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Start counters to log values */
> +	ioctl_perf_event_ioc_reset_enable();
> +
> +	return 0;
> +}
> +
> +/*
> + * get_llc_perf:	llc cache miss through perf events
> + * @cpu_no:		CPU number that the benchmark PID is binded to
> + *
> + * Perf events like HW_CACHE_MISSES could be used to validate number of
> + * cache lines allocated.
> + *
> + * Return: =0 on success.  <0 on failure.
> + */
> +static int get_llc_perf(unsigned long *llc_perf_miss)
> +{
> +	__u64 total_misses;
> +
> +	/* Stop counters after one span to get miss rate */
> +
> +	ioctl(fd_lm, PERF_EVENT_IOC_DISABLE, 0);
> +
> +	if (read(fd_lm, &rf_cqm, sizeof(struct read_format)) == -1) {
> +		perror("Could not get llc misses through perf");
> +
> +		return -1;
> +	}
> +
> +	total_misses = rf_cqm.values[0].value;
> +
> +	close(fd_lm);
> +
> +	*llc_perf_miss = total_misses;
> +
> +	return 0;
> +}
> +
>  /*
>   * Get LLC Occupancy as reported by RESCTRL FS
>   * For CQM,
> @@ -81,10 +178,20 @@ static int print_results_cache(char *filename, int bm_pid,
>  
>  int measure_cache_vals(struct resctrl_val_param *param, int bm_pid)
>  {
> -	unsigned long llc_occu_resc = 0, llc_value = 0;
> +	unsigned long llc_perf_miss = 0, llc_occu_resc = 0, llc_value = 0;
>  	int ret;
>  
>  	/*
> +	 * Measure cache miss from perf.
> +	 */
> +	if (!strcmp(param->resctrl_val, "cat")) {
> +		ret = get_llc_perf(&llc_perf_miss);
> +		if (ret < 0)
> +			return ret;
> +		llc_value = llc_perf_miss;
> +	}
> +
> +	/*
>  	 * Measure llc occupancy from resctrl.
>  	 */
>  	if (!strcmp(param->resctrl_val, "cqm")) {
> @@ -99,3 +206,69 @@ int measure_cache_vals(struct resctrl_val_param *param, int bm_pid)
>  
>  	return 0;
>  }
> +
> +/*
> + * cache_val:		execute benchmark and measure LLC occupancy resctrl
> + * and perf cache miss for the benchmark
> + * @param:		parameters passed to cache_val()
> + *
> + * Return:		0 on success. non-zero on failure.
> + */
> +int cat_val(struct resctrl_val_param *param)
> +{
> +	int malloc_and_init_memory = 1, memflush = 1, operation = 0, ret = 0;
> +	char *resctrl_val = param->resctrl_val;
> +	pid_t bm_pid;
> +
> +	if (strcmp(param->filename, "") == 0)
> +		sprintf(param->filename, "stdio");
> +
> +	bm_pid = getpid();
> +
> +	/* Taskset benchmark to specified cpu */
> +	ret = taskset_benchmark(bm_pid, param->cpu_no);
> +	if (ret)
> +		return ret;
> +
> +	/* Write benchmark to specified con_mon grp, mon_grp in resctrl FS*/
> +	ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
> +				      resctrl_val);
> +	if (ret)
> +		return ret;
> +
> +	if ((strcmp(resctrl_val, "cat") == 0)) {
> +		ret = initialize_llc_perf();
> +		if (ret)
> +			return ret;
> +	}
> +
> +	/* Test runs until the callback setup() tells the test to stop. */
> +	while (1) {
> +		if (strcmp(resctrl_val, "cat") == 0) {
> +			ret = param->setup(1, param);
> +			if (ret) {
> +				ret = 0;
> +				break;
> +			}
> +			ret = reset_enable_llc_perf(bm_pid, param->cpu_no);
> +			if (ret)
> +				break;
> +
> +			if (run_fill_buf(param->span, malloc_and_init_memory,
> +					 memflush, operation, resctrl_val)) {
> +				fprintf(stderr, "Error-running fill buffer\n");
> +				ret = -1;
> +				break;
> +			}
> +
> +			sleep(1);
> +			ret = measure_cache_vals(param, bm_pid);
> +			if (ret)
> +				break;
> +		} else {
> +			break;
> +		}
> +	}
> +
> +	return ret;
> +}
> diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c
> new file mode 100644
> index 000000000000..1a0f77e4f7bf
> --- /dev/null
> +++ b/tools/testing/selftests/resctrl/cat_test.c
> @@ -0,0 +1,242 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Cache Allocation Technology (CAT) test
> + *
> + * Copyright (C) 2018 Intel Corporation
> + *
> + * Authors:
> + *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> + *    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
> +
> +int count_of_bits;
> +char cbm_mask[256];
> +unsigned long long_mask;
> +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 void show_cache_info(unsigned long sum_llc_perf_miss, int no_of_bits,
> +			    unsigned long span)
> +{
> +	unsigned long allocated_cache_lines = span / 64;
> +	unsigned long avg_llc_perf_miss = 0;

No need to initialise.

> +	float diff_percent;

Please not floats for no reason. Should be an int, saves you some nasty
casts below.

> +
> +	avg_llc_perf_miss = sum_llc_perf_miss / (NUM_OF_RUNS - 1);
> +	diff_percent = ((float)allocated_cache_lines - avg_llc_perf_miss) /
> +				allocated_cache_lines * 100;

That looks confusing. Shouldn't it be:

	diff_percent = avg_llc_perf_miss * 100 / allocated_cache_lines;

Otherwise I have a hard time to see how this matches the check below.

> +	printf("Results are displayed in (Bytes)\n");
> +	printf("\nNumber of bits: %d \t", no_of_bits);
> +	printf("Avg_llc_perf_miss: %lu \t", avg_llc_perf_miss);
> +	printf("Allocated cache lines: %lu \t", allocated_cache_lines);
> +	printf("Percent diff=%d \t", abs((int)diff_percent));
> +
> +	if (abs((int)diff_percent) > MAX_DIFF_PERCENT)
> +		printf("Failed\n");
> +	else
> +		printf("Passed\n");
> +}
> +
> +static int check_results(struct resctrl_val_param *param)
> +{
> +	char *token_array[8], temp[512];

The size of temp[] here does not match ...

> +	unsigned long sum_llc_perf_miss = 0;
> +	int runs = 0, no_of_bits = 0;
> +	FILE *fp;
> +
> +	printf("\nChecking for pass/fail\n");
> +	fp = fopen(param->filename, "r");
> +	if (!fp) {
> +		perror("Error in opening file\n");
> +
> +		return errno;
> +	}
> +
> +	while (fgets(temp, 1024, fp)) {

... the user here. sizeof(temp) for the rescue!

Cheers,
Andre.

> +		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);
> +
> +	show_cache_info(sum_llc_perf_miss, no_of_bits, param->span);
> +
> +	return 0;
> +}
> +
> +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], pipe_message, mum_resctrlfs, sibling_cpu_no;
> +	pid_t bm_pid;
> +
> +	cache_size = 0;
> +	mum_resctrlfs = 1;
> +
> +	ret = remount_resctrlfs(mum_resctrlfs);
> +	if (ret)
> +		return ret;
> +
> +	ret = validate_resctrl_feature_request("cat");
> +	if (ret)
> +		return ret;
> +
> +	/* Get default cbm mask for L3/L2 cache */
> +	ret = get_cbm_mask(cache_type);
> +	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;
> +	printf("cache size :%lu\n", cache_size);
> +
> +	/* Get max number of bits from default-cabm mask */
> +	count_of_bits = count_bits(long_mask);
> +
> +	if (n < 1 || n > count_of_bits - 1) {
> +		printf("Invalid input value for no_of_bits n!\n");
> +		printf("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",
> +		.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 -1;
> +	}
> +
> +	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;
> +		write(pipefd[1], &pipe_message, sizeof(pipe_message));
> +		close(pipefd[1]);
> +		while (1)
> +			;
> +	} else {
> +		/* Parent waits for child to be ready. */
> +		close(pipefd[1]);
> +		pipe_message = 0;
> +		while (pipe_message != 1)
> +			read(pipefd[0], &pipe_message, sizeof(pipe_message));
> +		close(pipefd[0]);
> +		kill(bm_pid, SIGKILL);
> +	}
> +
> +	cat_test_cleanup();
> +	if (bm_pid)
> +		umount_resctrlfs();
> +
> +	return 0;
> +}
> diff --git a/tools/testing/selftests/resctrl/fill_buf.c b/tools/testing/selftests/resctrl/fill_buf.c
> index 792a5c40a32a..3244620d3676 100644
> --- a/tools/testing/selftests/resctrl/fill_buf.c
> +++ b/tools/testing/selftests/resctrl/fill_buf.c
> @@ -110,8 +110,11 @@ static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
>  	int ret = 0;
>  	FILE *fp;
>  
> -	while (1)
> +	while (1) {
>  		ret = fill_one_span_read(start_ptr, end_ptr);
> +		if (!strcmp(resctrl_val, "cat"))
> +			break;
> +	}
>  
>  	/* Consume read result so that reading memory is not optimized out. */
>  	fp = fopen("/dev/null", "w");
> @@ -126,8 +129,11 @@ static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
>  static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr,
>  			    char *resctrl_val)
>  {
> -	while (1)
> +	while (1) {
>  		fill_one_span_write(start_ptr, end_ptr);
> +		if (!strcmp(resctrl_val, "cat"))
> +			break;
> +	}
>  
>  	return 0;
>  }
> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
> index 2097b02a356d..dadbb3d0cad8 100644
> --- a/tools/testing/selftests/resctrl/resctrl.h
> +++ b/tools/testing/selftests/resctrl/resctrl.h
> @@ -92,6 +92,9 @@ 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 cat_val(struct resctrl_val_param *param);
> +void cat_test_cleanup(void);
> +int cat_perf_miss_val(int cpu_no, int no_of_bits, char *cache_type);
>  int cqm_resctrl_val(int cpu_no, int n, char **benchmark_cmd);
>  unsigned int count_bits(unsigned long n);
>  void cqm_test_cleanup(void);
> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
> index 5a9af019b5e5..3959b2b0671a 100644
> --- a/tools/testing/selftests/resctrl/resctrl_tests.c
> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
> @@ -20,7 +20,7 @@ static void cmd_help(void)
>  	printf("\t-b benchmark_cmd [options]: run specified benchmark for MBM, MBA and CQM");
>  	printf("\t default benchmark is builtin fill_buf\n");
>  	printf("\t-t test list: run tests specified in the test list, ");
> -	printf("e.g. -t mbm, mba, cqm\n");
> +	printf("e.g. -t mbm, mba, cqm, cat\n");
>  	printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n");
>  	printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n");
>  	printf("\t-h: help\n");
> @@ -31,6 +31,7 @@ void tests_cleanup(void)
>  	mbm_test_cleanup();
>  	mba_test_cleanup();
>  	cqm_test_cleanup();
> +	cat_test_cleanup();
>  }
>  
>  int main(int argc, char **argv)
> @@ -39,6 +40,7 @@ int main(int argc, char **argv)
>  	int res, c, cpu_no = 1, span = 250, argc_new = argc, i, no_of_bits = 5;
>  	int ben_ind, ben_count;
>  	bool has_ben = false, mbm_test = true, mba_test = true, cqm_test = true;
> +	bool cat_test = true;
>  	char *benchmark_cmd[BENCHMARK_ARGS];
>  	char bw_report[64], bm_type[64];
>  
> @@ -62,6 +64,7 @@ int main(int argc, char **argv)
>  			mbm_test = false;
>  			mba_test = false;
>  			cqm_test = false;
> +			cat_test = false;
>  			while (token) {
>  				if (!strcmp(token, "mbm")) {
>  					mbm_test = true;
> @@ -69,6 +72,8 @@ int main(int argc, char **argv)
>  					mba_test = true;
>  				} else if (!strcmp(token, "cqm")) {
>  					cqm_test = true;
> +				} else if (!strcmp(token, "cat")) {
> +					cat_test = true;
>  				} else {
>  					printf("invalid argument\n");
>  
> @@ -158,6 +163,13 @@ int main(int argc, char **argv)
>  			printf("Error in CQM test!\n");
>  		cqm_test_cleanup();
>  	}
> +	if (cat_test) {
> +		printf("\nCAT Test Starting..\n");
> +		res = cat_perf_miss_val(cpu_no, no_of_bits, "L3");
> +		if (res)
> +			printf("Error in CAT test!\n");
> +		cat_test_cleanup();
> +	}
>  
>  	return 0;
>  }
> diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
> index 6dacd215ace6..137b926955ca 100644
> --- a/tools/testing/selftests/resctrl/resctrlfs.c
> +++ b/tools/testing/selftests/resctrl/resctrlfs.c
> @@ -14,12 +14,14 @@
>  #define RESCTRL_MBM		"L3 monitoring detected"
>  #define RESCTRL_MBA		"MB allocation detected"
>  #define RESCTRL_CQM		"L3 monitoring detected"
> +#define RESCTRL_L3_CAT		"L3 allocation detected"
>  #define CORE_SIBLINGS_PATH	"/sys/bus/cpu/devices/cpu"
>  
>  enum {
>  	RESCTRL_FEATURE_MBM,
>  	RESCTRL_FEATURE_MBA,
>  	RESCTRL_FEATURE_CQM,
> +	RESCTRL_FEATURE_L3_CAT,
>  	MAX_RESCTRL_FEATURES
>  };
>  
> @@ -490,6 +492,7 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
>  	FILE *fp;
>  
>  	if ((strcmp(resctrl_val, "mba") == 0) ||
> +	    (strcmp(resctrl_val, "cat") == 0) ||
>  	    (strcmp(resctrl_val, "cqm") == 0)) {
>  		if (!schemata) {
>  			printf("Schemata empty, so not updating\n");
> @@ -507,7 +510,7 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
>  		else
>  			sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
>  
> -		if (!strcmp(resctrl_val, "cqm"))
> +		if (!strcmp(resctrl_val, "cat") || !strcmp(resctrl_val, "cqm"))
>  			sprintf(schema, "%s%d%c%s", "L3:", resource_id, '=',
>  				schemata);
>  		if (strcmp(resctrl_val, "mba") == 0)
> @@ -545,7 +548,7 @@ int validate_resctrl_feature_request(char *resctrl_val)
>  {
>  	int resctrl_features_supported[MAX_RESCTRL_FEATURES];
>  	const char *resctrl_features_list[MAX_RESCTRL_FEATURES] = {
> -			"mbm", "mba", "cqm"};
> +			"mbm", "mba", "cat", "cqm"};
>  	int i, valid_resctrl_feature = -1;
>  	char line[1024];
>  	FILE *fp;
> @@ -591,7 +594,8 @@ int validate_resctrl_feature_request(char *resctrl_val)
>  			resctrl_features_supported[RESCTRL_FEATURE_MBA] = 1;
>  		if ((strstr(line, RESCTRL_CQM)) != NULL)
>  			resctrl_features_supported[RESCTRL_FEATURE_CQM] = 1;
> -
> +		if ((strstr(line, RESCTRL_L3_CAT)) != NULL)
> +			resctrl_features_supported[RESCTRL_FEATURE_L3_CAT] = 1;
>  	}
>  	fclose(fp);
>  


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism
  2019-02-10  2:50 ` [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism Fenghua Yu
@ 2019-05-10 17:39   ` Andre Przywara
  2019-05-10 17:40     ` Andre Przywara
  2019-05-14 17:20     ` James Morse
  0 siblings, 2 replies; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:39 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:39 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Babu Moger <babu.moger@amd.com>
> 
> RESCTRL feature is supported both on Intel and AMD now. Some features
> are implemented differently. Add vendor detection mechanism. Use the vendor
> check where there are differences.

I don't think vendor detection is the right approach. The Linux userland
interface should be even architecture agnostic, not to speak of different
vendors.

But even if we need this for some reason ...

> 
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> ---
>  tools/testing/selftests/resctrl/resctrl.h       | 13 +++++
>  tools/testing/selftests/resctrl/resctrl_tests.c | 63 +++++++++++++++++++++++++
>  2 files changed, 76 insertions(+)
> 
> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
> index dadbb3d0cad8..974ec2de5fee 100644
> --- a/tools/testing/selftests/resctrl/resctrl.h
> +++ b/tools/testing/selftests/resctrl/resctrl.h
> @@ -63,10 +63,23 @@ struct resctrl_val_param {
>  
>  };
>  
> +/**
> + * Results of CPUID operation are stored in this structure.
> + * It consists of 4x32bits IA registers: EAX, EBX, ECX and EDX.
> + */
> +struct cpuid_out {
> +	uint32_t eax;
> +	uint32_t ebx;
> +	uint32_t ecx;
> +	uint32_t edx;
> +};
> +
>  pid_t bm_pid, ppid;
>  extern char cbm_mask[256];
>  extern unsigned long long_mask;
>  extern char llc_occup_path[1024];
> +extern int genuine_intel;
> +extern int authentic_amd;

There are more CPU vendors than that ;-)
And to not encourage this kind of vendor specific tests, I'd keep this exposure to a minimum.

In my version I have a simple is_amd() function, to cover the L3 vs. physical pacakges differences.

>  
>  int remount_resctrlfs(bool mum_resctrlfs);
>  int get_resource_id(int cpu_no, int *resource_id);
> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
> index 3959b2b0671a..1d9adcfbdb4c 100644
> --- a/tools/testing/selftests/resctrl/resctrl_tests.c
> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
> @@ -14,6 +14,66 @@
>  #define BENCHMARK_ARGS		64
>  #define BENCHMARK_ARG_SIZE	64
>  
> +/**
> + * This variables provides information about the vendor
> + */
> +int genuine_intel;
> +int authentic_amd;
> +
> +void lcpuid(const unsigned int leaf, const unsigned int subleaf,
> +	    struct cpuid_out *out)

There is a much easier way to detect the vendor, without resorting to
(unchecked) inline assembly in userland:
I changed this to scan /proc/cpuinfo for a line starting with vendor_id,
then use the information there. This should work everywhere.

Cheers,
Andre

> +{
> +	if (!out)
> +		return;
> +
> +#ifdef __x86_64__
> +	asm volatile("mov %4, %%eax\n\t"
> +		     "mov %5, %%ecx\n\t"
> +		     "cpuid\n\t"
> +		     "mov %%eax, %0\n\t"
> +		     "mov %%ebx, %1\n\t"
> +		     "mov %%ecx, %2\n\t"
> +		     "mov %%edx, %3\n\t"
> +		     : "=g" (out->eax), "=g" (out->ebx), "=g" (out->ecx),
> +		     "=g" (out->edx)
> +		     : "g" (leaf), "g" (subleaf)
> +		     : "%eax", "%ebx", "%ecx", "%edx");
> +#else
> +	asm volatile("push %%ebx\n\t"
> +		     "mov %4, %%eax\n\t"
> +		     "mov %5, %%ecx\n\t"
> +		     "cpuid\n\t"
> +		     "mov %%eax, %0\n\t"
> +		     "mov %%ebx, %1\n\t"
> +		     "mov %%ecx, %2\n\t"
> +		     "mov %%edx, %3\n\t"
> +		     "pop %%ebx\n\t"
> +		     : "=g" (out->eax), "=g" (out->ebx), "=g" (out->ecx),
> +		     "=g" (out->edx)
> +		     : "g" (leaf), "g" (subleaf)
> +		     : "%eax", "%ecx", "%edx");
> +#endif
> +}
> +
> +int detect_vendor(void)
> +{
> +	struct cpuid_out vendor;
> +	int ret = 0;
> +
> +	lcpuid(0x0, 0x0, &vendor);
> +	if (vendor.ebx == 0x756e6547 && vendor.edx == 0x49656e69 &&
> +	    vendor.ecx == 0x6c65746e) {
> +		genuine_intel = 1;
> +	} else if (vendor.ebx == 0x68747541 && vendor.edx == 0x69746E65 &&
> +		   vendor.ecx ==   0x444D4163) {
> +		authentic_amd = 1;
> +	} else {
> +		ret = -EFAULT;
> +	}
> +
> +	return ret;
> +}
> +
>  static void cmd_help(void)
>  {
>  	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list] [-n no_of_bits]\n");
> @@ -110,6 +170,9 @@ int main(int argc, char **argv)
>  		return errno;
>  	}
>  
> +	/* Detect vendor */
> +	detect_vendor();
> +
>  	if (has_ben) {
>  		/* Extract benchmark command from command line. */
>  		for (i = ben_ind; i < argc; i++) {


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism
  2019-05-10 17:39   ` Andre Przywara
@ 2019-05-10 17:40     ` Andre Przywara
  2019-05-14 17:20     ` James Morse
  1 sibling, 0 replies; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:40 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:39 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Babu Moger <babu.moger@amd.com>
> 
> RESCTRL feature is supported both on Intel and AMD now. Some features
> are implemented differently. Add vendor detection mechanism. Use the vendor
> check where there are differences.

I don't think vendor detection is the right approach. The Linux userland
interface should be even architecture agnostic, not to speak of different
vendors.

But even if we need this for some reason ...

> 
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> ---
>  tools/testing/selftests/resctrl/resctrl.h       | 13 +++++
>  tools/testing/selftests/resctrl/resctrl_tests.c | 63 +++++++++++++++++++++++++
>  2 files changed, 76 insertions(+)
> 
> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
> index dadbb3d0cad8..974ec2de5fee 100644
> --- a/tools/testing/selftests/resctrl/resctrl.h
> +++ b/tools/testing/selftests/resctrl/resctrl.h
> @@ -63,10 +63,23 @@ struct resctrl_val_param {
>  
>  };
>  
> +/**
> + * Results of CPUID operation are stored in this structure.
> + * It consists of 4x32bits IA registers: EAX, EBX, ECX and EDX.
> + */
> +struct cpuid_out {
> +	uint32_t eax;
> +	uint32_t ebx;
> +	uint32_t ecx;
> +	uint32_t edx;
> +};
> +
>  pid_t bm_pid, ppid;
>  extern char cbm_mask[256];
>  extern unsigned long long_mask;
>  extern char llc_occup_path[1024];
> +extern int genuine_intel;
> +extern int authentic_amd;

There are more CPU vendors than that ;-)
And to not encourage this kind of vendor specific tests, I'd keep this exposure to a minimum.

In my version I have a simple is_amd() function, to cover the L3 vs. physical pacakges differences.

>  
>  int remount_resctrlfs(bool mum_resctrlfs);
>  int get_resource_id(int cpu_no, int *resource_id);
> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
> index 3959b2b0671a..1d9adcfbdb4c 100644
> --- a/tools/testing/selftests/resctrl/resctrl_tests.c
> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
> @@ -14,6 +14,66 @@
>  #define BENCHMARK_ARGS		64
>  #define BENCHMARK_ARG_SIZE	64
>  
> +/**
> + * This variables provides information about the vendor
> + */
> +int genuine_intel;
> +int authentic_amd;
> +
> +void lcpuid(const unsigned int leaf, const unsigned int subleaf,
> +	    struct cpuid_out *out)

There is a much easier way to detect the vendor, without resorting to
(unchecked) inline assembly in userland:
I changed this to scan /proc/cpuinfo for a line starting with vendor_id,
then use the information there. This should work everywhere.
http://linux-arm.org/git?p=linux-ap.git;a=commitdiff;h=ce9c9f3a40e52

Cheers,
Andre

> +{
> +	if (!out)
> +		return;
> +
> +#ifdef __x86_64__
> +	asm volatile("mov %4, %%eax\n\t"
> +		     "mov %5, %%ecx\n\t"
> +		     "cpuid\n\t"
> +		     "mov %%eax, %0\n\t"
> +		     "mov %%ebx, %1\n\t"
> +		     "mov %%ecx, %2\n\t"
> +		     "mov %%edx, %3\n\t"
> +		     : "=g" (out->eax), "=g" (out->ebx), "=g" (out->ecx),
> +		     "=g" (out->edx)
> +		     : "g" (leaf), "g" (subleaf)
> +		     : "%eax", "%ebx", "%ecx", "%edx");
> +#else
> +	asm volatile("push %%ebx\n\t"
> +		     "mov %4, %%eax\n\t"
> +		     "mov %5, %%ecx\n\t"
> +		     "cpuid\n\t"
> +		     "mov %%eax, %0\n\t"
> +		     "mov %%ebx, %1\n\t"
> +		     "mov %%ecx, %2\n\t"
> +		     "mov %%edx, %3\n\t"
> +		     "pop %%ebx\n\t"
> +		     : "=g" (out->eax), "=g" (out->ebx), "=g" (out->ecx),
> +		     "=g" (out->edx)
> +		     : "g" (leaf), "g" (subleaf)
> +		     : "%eax", "%ecx", "%edx");
> +#endif
> +}
> +
> +int detect_vendor(void)
> +{
> +	struct cpuid_out vendor;
> +	int ret = 0;
> +
> +	lcpuid(0x0, 0x0, &vendor);
> +	if (vendor.ebx == 0x756e6547 && vendor.edx == 0x49656e69 &&
> +	    vendor.ecx == 0x6c65746e) {
> +		genuine_intel = 1;
> +	} else if (vendor.ebx == 0x68747541 && vendor.edx == 0x69746E65 &&
> +		   vendor.ecx ==   0x444D4163) {
> +		authentic_amd = 1;
> +	} else {
> +		ret = -EFAULT;
> +	}
> +
> +	return ret;
> +}
> +
>  static void cmd_help(void)
>  {
>  	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list] [-n no_of_bits]\n");
> @@ -110,6 +170,9 @@ int main(int argc, char **argv)
>  		return errno;
>  	}
>  
> +	/* Detect vendor */
> +	detect_vendor();
> +
>  	if (has_ben) {
>  		/* Extract benchmark command from command line. */
>  		for (i = ben_ind; i < argc; i++) {


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests for AMD
  2019-02-10  2:50 ` [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests for AMD Fenghua Yu
@ 2019-05-10 17:40   ` Andre Przywara
  2019-05-10 19:29     ` Yu, Fenghua
  0 siblings, 1 reply; 38+ messages in thread
From: Andre Przywara @ 2019-05-10 17:40 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Tony Luck, Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel, James Morse

On Sat,  9 Feb 2019 18:50:41 -0800
Fenghua Yu <fenghua.yu@intel.com> wrote:

Hi,

> From: Babu Moger <babu.moger@amd.com>
> 
> For now, disable MBA and MBM tests for AMD. Deciding test pass/fail
> is not clear right now. We can enable when we have some clarity.

I don't think this is the right way. The availability of features should
be queryable, for instance by looking into /sys/fs/resctrl/info. Checking
for a certain vendor to skip tests just sounds wrong to me, and is
definitely not scalable or future proof.

We should really check the availability of a feature, then skip the whole
subsystem test in resctrl_tests.c.

Cheers,
Andre.

> 
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> ---
>  tools/testing/selftests/resctrl/cat_test.c      | 2 +-
>  tools/testing/selftests/resctrl/resctrl_tests.c | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c
> index 1a0f77e4f7bf..264bf2325f9e 100644
> --- a/tools/testing/selftests/resctrl/cat_test.c
> +++ b/tools/testing/selftests/resctrl/cat_test.c
> @@ -69,7 +69,7 @@ static void show_cache_info(unsigned long sum_llc_perf_miss, int no_of_bits,
>  	printf("Allocated cache lines: %lu \t", allocated_cache_lines);
>  	printf("Percent diff=%d \t", abs((int)diff_percent));
>  
> -	if (abs((int)diff_percent) > MAX_DIFF_PERCENT)
> +	if (genuine_intel && (abs((int)diff_percent) > MAX_DIFF_PERCENT))
>  		printf("Failed\n");
>  	else
>  		printf("Passed\n");
> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
> index 1d9adcfbdb4c..620be40b8c01 100644
> --- a/tools/testing/selftests/resctrl/resctrl_tests.c
> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
> @@ -197,7 +197,7 @@ int main(int argc, char **argv)
>  	sprintf(bw_report, "reads");
>  	sprintf(bm_type, "fill_buf");
>  
> -	if (mbm_test) {
> +	if (genuine_intel && mbm_test) {
>  		printf("\nMBM BW Change Starting..\n");
>  		if (!has_ben)
>  			sprintf(benchmark_cmd[5], "%s", "mbm");
> @@ -207,7 +207,7 @@ int main(int argc, char **argv)
>  		mbm_test_cleanup();
>  	}
>  
> -	if (mba_test) {
> +	if (genuine_intel && mba_test) {
>  		printf("\nMBA Schemata Change Starting..\n");
>  		if (!has_ben)
>  			sprintf(benchmark_cmd[5], "%s", "mba");


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data
  2019-02-10  2:50 ` [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data Fenghua Yu
  2019-05-10 17:36   ` Andre Przywara
@ 2019-05-10 17:41   ` Borislav Petkov
  2019-05-10 19:01     ` Yu, Fenghua
  1 sibling, 1 reply; 38+ messages in thread
From: Borislav Petkov @ 2019-05-10 17:41 UTC (permalink / raw)
  To: Fenghua Yu
  Cc: Thomas Gleixner, Ingo Molnar, H Peter Anvin, Tony Luck,
	Reinette Chatre, Ravi V Shankar, Xiaochen Shen,
	Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya, Babu Moger,
	linux-kernel

On Sat, Feb 09, 2019 at 06:50:31PM -0800, Fenghua Yu wrote:
> From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> 
> The basic resctrl file system operations and data are added for future
> usage by resctrl selftest tool.
> 
> Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> Signed-off-by: Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> Signed-off-by: Babu Moger <babu.moger@amd.com>

And while feedback from Andre is being addressed, you those SOB chains
need to be fixed.

Thx.

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data
  2019-05-10 17:36   ` Andre Przywara
@ 2019-05-10 19:00     ` Yu, Fenghua
  0 siblings, 0 replies; 38+ messages in thread
From: Yu, Fenghua @ 2019-05-10 19:00 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Luck, Tony, Chatre, Reinette, Shankar, Ravi V, Shen, Xiaochen,
	Pathan, Arshiya Hayatkhan, Prakhya, Sai Praneeth, Babu Moger,
	linux-kernel, James Morse

> From: Andre Przywara [mailto:andre.przywara@arm.com]
> On Sat,  9 Feb 2019 18:50:31 -0800
> Fenghua Yu <fenghua.yu@intel.com> wrote:
> 
> Hi,
> 
> some comments inline.
> 
> > From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> >
> > The basic resctrl file system operations and data are added for future
> > usage by resctrl selftest tool.
> >
> > Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> > Signed-off-by: Arshiya Hayatkhan Pathan
> > <arshiya.hayatkhan.pathan@intel.com>
> > Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> > Signed-off-by: Babu Moger <babu.moger@amd.com>
> > ---
> >  tools/testing/selftests/resctrl/Makefile    |  10 +
> >  tools/testing/selftests/resctrl/resctrl.h   |  48 +++
> >  tools/testing/selftests/resctrl/resctrlfs.c | 464
> > ++++++++++++++++++++++++++++
> >  3 files changed, 522 insertions(+)
> >  create mode 100644 tools/testing/selftests/resctrl/Makefile
> >  create mode 100644 tools/testing/selftests/resctrl/resctrl.h
> >  create mode 100644 tools/testing/selftests/resctrl/resctrlfs.c
> >
> > diff --git a/tools/testing/selftests/resctrl/Makefile
> > b/tools/testing/selftests/resctrl/Makefile
> > new file mode 100644
> > index 000000000000..bd5c5418961e
> > --- /dev/null
> > +++ b/tools/testing/selftests/resctrl/Makefile
> > @@ -0,0 +1,10 @@
> > +CC = gcc
> 
> Changing this to
> CC = $(CROSS_COMPILE)gcc
> make this cross compileable.
> 
> > +CFLAGS = -g -Wall
> 
> Can we add -O here? For once -O0 generates horrible code, but also -O
> tends to catch more bugs.
Sure.

> 
> > +
> > +*.o: *.c
> > +	$(CC) $(CFLAGS) -c *.c
> 
> This is a built-in rule in make, so you can remove it here:
> https://www.gnu.org/software/make/manual/html_node/Catalogue-of-
> Rules.html#Catalogue-of-Rules
Will do.

> 
> > +
> > +.PHONY: clean
> > +
> > +clean:
> > +	$(RM) *.o *~
> > diff --git a/tools/testing/selftests/resctrl/resctrl.h
> > b/tools/testing/selftests/resctrl/resctrl.h
> > new file mode 100644
> > index 000000000000..2e112934d48a
> > --- /dev/null
> > +++ b/tools/testing/selftests/resctrl/resctrl.h
> > @@ -0,0 +1,48 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */ #define _GNU_SOURCE #ifndef
> > +RESCTRL_H #define RESCTRL_H #include <stdio.h> #include <errno.h>
> > +#include <sched.h> #include <stdlib.h> #include <unistd.h> #include
> > +<string.h> #include <signal.h> #include <dirent.h> #include
> > +<stdbool.h> #include <sys/stat.h> #include <sys/ioctl.h> #include
> > +<sys/mount.h> #include <sys/types.h> #include <asm/unistd.h> #include
> > +<linux/perf_event.h>
> > +
> > +#define RESCTRL_PATH		"/sys/fs/resctrl"
> > +#define PHYS_ID_PATH		"/sys/devices/system/cpu/cpu"
> > +
> > +#define PARENT_EXIT(err_msg)			\
> > +	do {					\
> > +		perror(err_msg);		\
> > +		kill(ppid, SIGKILL);		\
> > +		exit(EXIT_FAILURE);		\
> > +	} while (0)
> > +
> > +pid_t bm_pid, ppid;
> > +
> > +int remount_resctrlfs(bool mum_resctrlfs); int get_resource_id(int
> > +cpu_no, int *resource_id); int validate_bw_report_request(char
> > +*bw_report); int validate_resctrl_feature_request(char *resctrl_val);
> > +int taskset_benchmark(pid_t bm_pid, int cpu_no); void
> > +run_benchmark(int signum, siginfo_t *info, void *ucontext); int
> > +write_schemata(char *ctrlgrp, char *schemata, int cpu_no,
> > +		   char *resctrl_val);
> > +int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
> > +			    char *resctrl_val);
> > +int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int
> cpu,
> > +		    int group_fd, unsigned long flags); int
> run_fill_buf(unsigned
> > +long span, int malloc_and_init_memory, int memflush,
> > +		 int op, char *resctrl_va);
> > +
> > +#endif /* RESCTRL_H */
> > diff --git a/tools/testing/selftests/resctrl/resctrlfs.c
> > b/tools/testing/selftests/resctrl/resctrlfs.c
> > new file mode 100644
> > index 000000000000..5afcaa89f418
> > --- /dev/null
> > +++ b/tools/testing/selftests/resctrl/resctrlfs.c
> > @@ -0,0 +1,464 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Basic resctrl file system operations
> > + *
> > + * Copyright (C) 2018 Intel Corporation
> > + *
> > + * Authors:
> > + *    Arshiya Hayatkhan Pathan <arshiya.hayatkhan.pathan@intel.com>
> > + *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
> > + *    Fenghua Yu <fenghua.yu@intel.com>
> > + */
> > +#include "resctrl.h"
> > +
> > +#define RESCTRL_MBM		"L3 monitoring detected"
> > +#define RESCTRL_MBA		"MB allocation detected"
> > +enum {
> > +	RESCTRL_FEATURE_MBM,
> > +	RESCTRL_FEATURE_MBA,
> > +	MAX_RESCTRL_FEATURES
> > +};
> > +
> > +/*
> > + * remount_resctrlfs - Remount resctrl FS at /sys/fs/resctrl
> > + * @mum_resctrlfs:	Should the resctrl FS be remounted?
> > + *
> > + * If not mounted, mount it.
> > + * If mounted and mum_resctrlfs then remount resctrl FS.
> > + * If mounted and !mum_resctrlfs then noop
> > + *
> > + * Return: 0 on success, non-zero on failure  */ int
> > +remount_resctrlfs(bool mum_resctrlfs) {
> > +	DIR *dp;
> > +	struct dirent *ep;
> > +	unsigned int count = 0;
> > +
> > +	/*
> > +	 * If kernel is built with CONFIG_RESCTRL, then /sys/fs/resctrl should
> > +	 * be present by default
> > +	 */
> > +	dp = opendir(RESCTRL_PATH);
> > +	if (dp) {
> > +		while ((ep = readdir(dp)) != NULL)
> > +			count++;
> > +		closedir(dp);
> > +	} else {
> > +		perror("Unable to read /sys/fs/resctrl");
> > +
> > +		return -1;
> > +	}
> > +
> > +	/*
> > +	 * If resctrl FS has more than two entries, it means that resctrl FS
> has
> > +	 * already been mounted. The two default entries are "." and "..",
> these
> > +	 * are present even when resctrl FS is not mounted
> > +	 */
> > +	if (count > 2) {
> > +		if (mum_resctrlfs) {
> > +			if (umount(RESCTRL_PATH) != 0) {
> > +				perror("Unable to umount resctrl");
> > +
> > +				return errno;
> > +			}
> > +			printf("Remount: done!\n");
> > +		} else {
> > +			printf("Mounted already. Not remounting!\n");
> > +
> > +			return 0;
> > +		}
> > +	}
> > +
> > +	if (mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL) != 0) {
> 
> Don't we need to consider mount options at some point? According to
> Documentation/x86/resctrl_ui.txt there is cdp, cdpl2 and mba_MBps, which
> we need to set to get certain features.

As said in the cover patch, there more tests in the future to cover cdp, mba, etc.
We will use mount options in those future tests.

It's good to mount without any parameter for the tests in the current patch set.

> 
> > +		perror("Unable to mount resctrl FS at /sys/fs/resctrl");
> > +
> > +		return errno;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int umount_resctrlfs(void)
> > +{
> > +	if (umount(RESCTRL_PATH)) {
> > +		perror("Unable to umount resctrl");
> > +
> > +		return errno;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * get_resource_id - Get socket number/l3 id for a specified CPU
> > + * @cpu_no:	CPU number
> > + * @resource_id: Socket number or l3_id
> > + *
> > + * Return: >= 0 on success, < 0 on failure.
> > + */
> > +int get_resource_id(int cpu_no, int *resource_id) {
> > +	char phys_pkg_path[1024];
> > +	FILE *fp;
> > +
> > +	sprintf(phys_pkg_path, "%s%d/topology/physical_package_id",
> > +		PHYS_ID_PATH, cpu_no);
> > +	fp = fopen(phys_pkg_path, "r");
> > +	if (!fp) {
> > +		perror("Failed to open physical_package_id");
> > +
> > +		return -1;
> > +	}
> > +	if (fscanf(fp, "%d", resource_id) <= 0) {
> > +		perror("Could not get socket number or l3 id");
> > +		fclose(fp);
> > +
> > +		return -1;
> > +	}
> > +	fclose(fp);
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
> > + * @bm_pid:	PID that should be binded
> > + * @cpu_no:	CPU number at which the PID would be binded
> > + *
> > + * Return: 0 on success, non-zero on failure  */ int
> > +taskset_benchmark(pid_t bm_pid, int cpu_no) {
> > +	cpu_set_t my_set;
> > +
> > +	CPU_ZERO(&my_set);
> > +	CPU_SET(cpu_no, &my_set);
> > +
> > +	if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {
> > +		perror("Unable to taskset benchmark");
> > +
> > +		return -1;
> > +	}
> > +
> > +	printf("Taskset benchmark: done!\n");
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * run_benchmark - Run a specified benchmark or fill_buf (default
> benchmark)
> > + *		   in specified signal. Direct benchmark stdio to /dev/null.
> > + * @signum:	signal number
> > + * @info:	signal info
> > + * @ucontext:	user context in signal handling
> > + *
> > + * Return: void
> > + */
> > +void run_benchmark(int signum, siginfo_t *info, void *ucontext) {
> > +	unsigned long long span;
> > +	int operation, ret;
> > +	char **benchmark_cmd;
> > +	FILE *fp;
> > +
> > +	benchmark_cmd = info->si_ptr;
> > +
> > +	/*
> > +	 * Direct stdio of child to /dev/null, so that only parent writes to
> > +	 * stdio (console)
> > +	 */
> > +	fp = freopen("/dev/null", "w", stdout);
> > +	if (!fp)
> > +		PARENT_EXIT("Unable to direct benchmark status to
> /dev/null");
> > +
> > +	if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
> > +		/* Execute default fill_buf benchmark */
> > +		span = strtoul(benchmark_cmd[1], NULL, 10);
> > +		operation = atoi(benchmark_cmd[4]);
> > +		if (run_fill_buf(span, 1, 1, operation, NULL))
> > +			fprintf(stderr, "Error in running fill buffer\n");
> > +	} else {
> > +		/* Execute specified benchmark */
> > +		ret = execvp(benchmark_cmd[0], benchmark_cmd);
> > +		if (ret)
> > +			perror("wrong\n");
> > +	}
> > +
> > +	fclose(stdout);
> > +	PARENT_EXIT("Unable to run specified benchmark"); }
> > +
> > +/*
> > + * create_grp - Create a group only if one doesn't exist
> > + * @grp_name:	Name of the group
> > + * @grp:	Full path and name of the group
> > + * @parent_grp:	Full path and name of the parent group
> > + *
> > + * Return: 0 on success, non-zero on failure  */ static int
> > +create_grp(const char *grp_name, char *grp, const char *parent_grp) {
> > +	int found_grp = 0;
> > +	struct dirent *ep;
> > +	DIR *dp;
> > +
> > +	/* Check if requested grp exists or not */
> > +	dp = opendir(parent_grp);
> > +	if (dp) {
> > +		while ((ep = readdir(dp)) != NULL) {
> > +			if (strcmp(ep->d_name, grp_name) == 0)
> > +				found_grp = 1;
> > +		}
> > +		closedir(dp);
> > +	} else {
> > +		perror("Unable to open resctrl for group");
> > +
> > +		return -1;
> > +	}
> > +
> > +	/* Requested grp doesn't exist, hence create it */
> > +	if (found_grp == 0) {
> > +		if (mkdir(grp, 0) == -1) {
> > +			perror("Unable to create group");
> > +
> > +			return -1;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int write_pid_to_tasks(char *tasks, pid_t pid) {
> > +	FILE *fp;
> > +
> > +	fp = fopen(tasks, "w");
> > +	if (!fp) {
> > +		perror("Failed to open tasks file");
> > +
> > +		return -1;
> > +	}
> > +	if (fprintf(fp, "%d\n", pid) < 0) {
> > +		perror("Failed to wr pid to tasks file");
> > +		fclose(fp);
> > +
> > +		return -1;
> > +	}
> > +	fclose(fp);
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS
> > + * @bm_pid:		PID that should be written
> > + * @ctrlgrp:		Name of the control monitor group (con_mon grp)
> > + * @mongrp:		Name of the monitor group (mon grp)
> > + * @resctrl_val:	Resctrl feature (Eg: mbm, mba.. etc)
> > + *
> > + * If a con_mon grp is requested, create it and write pid to it,
> > +otherwise
> > + * write pid to root con_mon grp.
> > + * If a mon grp is requested, create it and write pid to it,
> > +otherwise
> > + * pid is not written, this means that pid is in con_mon grp and
> > +hence
> > + * should consult con_mon grp's mon_data directory for results.
> > + *
> > + * Return: 0 on success, non-zero on failure  */ int
> > +write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
> > +			    char *resctrl_val)
> > +{
> > +	char controlgroup[256], monitorgroup[256], monitorgroup_p[256];
> > +	char tasks[256];
> > +	int ret;
> > +
> > +	if (ctrlgrp)
> > +		sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
> > +	else
> > +		sprintf(controlgroup, "%s", RESCTRL_PATH);
> > +
> > +	/* Create control and monitoring group and write pid into it */
> > +	ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH);
> > +	if (ret)
> > +		return ret;
> > +	sprintf(tasks, "%s/tasks", controlgroup);
> > +	ret = write_pid_to_tasks(tasks, bm_pid);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Create mon grp and write pid into it for "mbm" test */
> > +	if ((strcmp(resctrl_val, "mbm") == 0)) {
> > +		if (mongrp) {
> > +			sprintf(monitorgroup_p, "%s/mon_groups",
> controlgroup);
> > +			sprintf(monitorgroup, "%s/%s", monitorgroup_p,
> mongrp);
> > +			ret = create_grp(mongrp, monitorgroup,
> monitorgroup_p);
> > +			if (ret)
> > +				return ret;
> > +
> > +			sprintf(tasks, "%s/mon_groups/%s/tasks",
> > +				controlgroup, mongrp);
> > +			ret = write_pid_to_tasks(tasks, bm_pid);
> > +			if (ret)
> > +				return ret;
> > +		}
> > +	}
> > +
> > +	printf("Write benchmark to resctrl FS: done!\n");
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * write_schemata - Update schemata of a con_mon grp
> > + * @ctrlgrp:		Name of the con_mon grp
> > + * @schemata:		Schemata that should be updated to
> > + * @cpu_no:		CPU number that the benchmark PID is
> binded to
> > + * @resctrl_val:	Resctrl feature (Eg: mbm, mba.. etc)
> > + *
> > + * Update schemata of a con_mon grp *only* if requested resctrl
> > +feature is
> > + * allocation type
> > + *
> > + * Return: 0 on success, non-zero on failure  */ int
> > +write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char
> > +*resctrl_val) {
> > +	char controlgroup[1024], schema[1024];
> > +	int resource_id;
> > +	FILE *fp;
> > +
> > +	if (strcmp(resctrl_val, "mba") == 0) {
> > +		if (!schemata) {
> > +			printf("Schemata empty, so not updating\n");
> > +
> > +			return 0;
> > +		}
> > +		if (get_resource_id(cpu_no, &resource_id) < 0) {
> > +			perror("Failed to get resource id");
> > +			return -1;
> > +		}
> > +
> > +		if (ctrlgrp)
> > +			sprintf(controlgroup, "%s/%s/schemata",
> RESCTRL_PATH,
> > +				ctrlgrp);
> > +		else
> > +			sprintf(controlgroup, "%s/schemata",
> RESCTRL_PATH);
> > +		sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=',
> schemata);
> > +
> > +		fp = fopen(controlgroup, "w");
> > +		if (!fp) {
> > +			perror("Failed to open control group");
> > +
> > +			return -1;
> > +		}
> > +
> > +		if (fprintf(fp, "%s\n", schema) < 0) {
> > +			perror("Failed to write schemata in control group");
> > +			fclose(fp);
> > +
> > +			return -1;
> > +		}
> > +		fclose(fp);
> > +
> > +		printf("Write schemata to resctrl FS: done!\n");
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +/*
> > + * validate_resctrl_feature_request - Check if requested feature is valid.
> > + * @resctrl_val:	Requested feature
> > + *
> > + * Return: 0 on success, non-zero on failure  */ int
> > +validate_resctrl_feature_request(char *resctrl_val) {
> > +	int resctrl_features_supported[MAX_RESCTRL_FEATURES];
> > +	const char *resctrl_features_list[MAX_RESCTRL_FEATURES] = {
> > +			"mbm", "mba"};
> > +	int i, valid_resctrl_feature = -1;
> > +	char line[1024];
> > +	FILE *fp;
> > +
> > +	if (!resctrl_val) {
> > +		fprintf(stderr, "resctrl feature cannot be NULL\n");
> > +
> > +		return -1;
> > +	}
> > +
> > +	for (i = 0; i < MAX_RESCTRL_FEATURES; i++)
> > +		resctrl_features_supported[i] = 0;
> > +
> > +	/* Is the resctrl feature request valid? */
> > +	for (i = 0; i < MAX_RESCTRL_FEATURES; i++) {
> > +		if (strcmp(resctrl_features_list[i], resctrl_val) == 0)
> > +			valid_resctrl_feature = i;
> > +	}
> > +	if (valid_resctrl_feature == -1) {
> > +		fprintf(stderr, "Not a valid resctrl feature request\n");
> > +
> > +		return -1;
> > +	}
> > +
> > +	/* Enumerate resctrl features supported by this platform */
> > +	if (system("dmesg > dmesg") != 0) {
> > +		perror("Could not create custom dmesg file");
> 
> This fails horribly if the local directory is not writable. Creating a pipe
> (similar to how we communicate between the benchmark processes) and
> reading from there avoid this.
> 
> > +
> > +		return -1;
> > +	}
> > +
> > +	fp = fopen("dmesg", "r");
> > +	if (!fp) {
> > +		perror("Could not read custom created dmesg");
> > +
> > +		return -1;
> > +	}
> > +
> > +	while (fgets(line, 1024, fp)) {
> > +		if ((strstr(line, RESCTRL_MBM)) != NULL)
> > +
> 	resctrl_features_supported[RESCTRL_FEATURE_MBM] = 1;
> 
> In general this approach is not very reliable, as the beginning of the kernel
> log could have been overwritten already in the dmesg buffer.
> Also this is not the way we should detect features: I think the content of
> /sys/fs/resctrl/info should be used for that purpose.

Agree with you. We will use /sys/fs/resctrl/info directory to enumerate features
instead of dmesg.

Thanks.

-Fenghua


^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data
  2019-05-10 17:41   ` Borislav Petkov
@ 2019-05-10 19:01     ` Yu, Fenghua
  0 siblings, 0 replies; 38+ messages in thread
From: Yu, Fenghua @ 2019-05-10 19:01 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Thomas Gleixner, Ingo Molnar, H Peter Anvin, Luck, Tony, Chatre,
	Reinette, Shankar, Ravi V, Shen, Xiaochen, Pathan,
	Arshiya Hayatkhan, Prakhya, Sai Praneeth, Babu Moger,
	linux-kernel

> From: Borislav Petkov [mailto:bp@alien8.de]
> On Sat, Feb 09, 2019 at 06:50:31PM -0800, Fenghua Yu wrote:
> > From: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> >
> > The basic resctrl file system operations and data are added for future
> > usage by resctrl selftest tool.
> >
> > Signed-off-by: Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>
> > Signed-off-by: Arshiya Hayatkhan Pathan
> > <arshiya.hayatkhan.pathan@intel.com>
> > Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
> > Signed-off-by: Babu Moger <babu.moger@amd.com>
> 
> And while feedback from Andre is being addressed, you those SOB chains
> need to be fixed.

Will fix the SOB chains.

Thanks.

-Fenghua

^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
  2019-05-10 17:35 ` Andre Przywara
@ 2019-05-10 19:20   ` Yu, Fenghua
  2019-05-14 17:20     ` James Morse
  0 siblings, 1 reply; 38+ messages in thread
From: Yu, Fenghua @ 2019-05-10 19:20 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Luck, Tony, Chatre, Reinette, Shankar, Ravi V, Shen, Xiaochen,
	Pathan, Arshiya Hayatkhan, Prakhya, Sai Praneeth, Babu Moger,
	linux-kernel, James Morse

>On Friday, May 10, 2019 10:36 AM
>Andre Przywara [mailto:andre.przywara@arm.com] wrote:
> On Sat,  9 Feb 2019 18:50:29 -0800
> Fenghua Yu <fenghua.yu@intel.com> wrote:
> 
> Hi Fenghua, Babu,
> 
> > With more and more resctrl features are being added by Intel, AMD and
> > ARM, a test tool is becoming more and more useful to validate that
> > both hardware and software functionalities work as expected.
> 
> That's very much appreciated! We decided to use that tool here to detect
> regressions in James' upcoming resctrl rework series. While doing so we
> spotted some shortcomings:

This is great!

> - There is some unconditional x86 inline assembly which obviously breaks
> the build on ARM.

Will fix this as much as possible.

BTW, does ARM support perf imc_count events which are used in CAT tests?

> - The result output is somewhat confusing, I find it hard to see whether a
> test succeeded or not, also it's not easily parseable by scripts.
> - There are some basic tests missing (does the filesystem exist? Is the
> mount point visible?)

Is it OK to fold the basic tests into bigger tests? E.g. the filesystem and mount point
tests are actually part of CAT test and we just dump the sub-test results during CAT test.
Seems your test results show the sub-test results during CAT test.

> - Some tests create files in the current directory. This is somewhat confusing
> if you happen to be in some sysfs directory, for instance. I don't think we
> really need temporary files (pipes should cover most of the cases), but in
> case we do, we should create them in some /tmp directory, probably by
> using a glibc function for this.

You are right. Will generate the temp file in /tmp.

> - There were some problems that newer GCC and clang complained about.

Which GCC do you use to see the issues? We use 8.2.1 and no compilation issue is reported.

> 
> For now I didn't look too closely at the actual test algorithms, but decided
> to fix those things first. I replied to some of the smaller issues I spotted on
> the way in the individual patch mails.
> 
> For the bigger things (new tests, result formatting) I just went ahead and
> fixed them in my own branch [1] (work in progress!). I went with TAP
> formatting, because this is both readable by humans and can be processed
> by the "prove" tool (or any other simple UNIX tool, for that matter).
> 
> I used this amended version to do some regression testing on James'
> resctrl rework series, which involved boot testing more than 100 patches, so
> automation is key here. The result looks like this:
> ===================
> TAP version 13
> ok kernel supports resctrl filesystem
> ok resctrl mountpoint "/sys/fs/resctrl" exists # resctrl filesystem not
> mounted # Starting MBM BW change ...
> ok MBM: bw change # SKIP memory bandwidth not supported # Starting
> MBA Schemata Change ...
> ok MBA: change-schemata # SKIP memory bandwidth not supported #
> Starting CQM test ...
> ok mounting resctrl to "/sys/fs/resctrl"
> ok CQM: test # SKIP L3 not supported
> # Starting CAT test ...
> ok mounting resctrl to "/sys/fs/resctrl"
> cache size :31457280
> ok writing benchmark parameters to resctrl FS ok Write schema "L3:0=7fff"
> to resctrl FS ok cache difference more than 4 % # Percent diff=16 # Number
> of bits: 15 # Avg_llc_perf_miss: 306994 # Allocated cache lines: 368640 ok
> CAT: test
> 1..11
> =================
> 
> Appreciate any feedback on this!
> 
> Cheers,
> Andre.
> 
> [1] http://linux-arm.org/git?p=linux-ap.git;a=shortlog;h=refs/heads/resctrl-
> selftests-wip
> git://linux-arm.org/linux-ap.git    branch: resctrl-selftests-wip



^ permalink raw reply	[flat|nested] 38+ messages in thread

* RE: [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests for AMD
  2019-05-10 17:40   ` Andre Przywara
@ 2019-05-10 19:29     ` Yu, Fenghua
  2019-05-14 17:17       ` Moger, Babu
  0 siblings, 1 reply; 38+ messages in thread
From: Yu, Fenghua @ 2019-05-10 19:29 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Luck, Tony, Chatre, Reinette, Shankar, Ravi V, Shen, Xiaochen,
	Pathan, Arshiya Hayatkhan, Prakhya, Sai Praneeth, Babu Moger,
	linux-kernel, James Morse

> On Friday, May 10, 2019 10:40 AM
> Andre Przywara [mailto:andre.przywara@arm.com] wrote:
> To: Yu, Fenghua <fenghua.yu@intel.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>; Ingo Molnar
> <mingo@redhat.com>; Borislav Petkov <bp@alien8.de>; H Peter Anvin
> <hpa@zytor.com>; Luck, Tony <tony.luck@intel.com>; Chatre, Reinette
> <reinette.chatre@intel.com>; Shankar, Ravi V <ravi.v.shankar@intel.com>;
> Shen, Xiaochen <xiaochen.shen@intel.com>; Pathan, Arshiya Hayatkhan
> <arshiya.hayatkhan.pathan@intel.com>; Prakhya, Sai Praneeth
> <sai.praneeth.prakhya@intel.com>; Babu Moger <babu.moger@amd.com>;
> linux-kernel <linux-kernel@vger.kernel.org>; James Morse
> <James.Morse@arm.com>
> Subject: Re: [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests
> for AMD
> 
> On Sat,  9 Feb 2019 18:50:41 -0800
> Fenghua Yu <fenghua.yu@intel.com> wrote:
> 
> Hi,
> 
> > From: Babu Moger <babu.moger@amd.com>
> >
> > For now, disable MBA and MBM tests for AMD. Deciding test pass/fail is
> > not clear right now. We can enable when we have some clarity.
> 
> I don't think this is the right way. The availability of features should be
> queryable, for instance by looking into /sys/fs/resctrl/info. Checking for a
> certain vendor to skip tests just sounds wrong to me, and is definitely not
> scalable or future proof.
> 
> We should really check the availability of a feature, then skip the whole
> subsystem test in resctrl_tests.c.

Babu may correct if I'm wrong: AMD does support the MBA and MBM features. So if querying the info directory, the features are there. But AMD doesn't want to support the testing for the features in the current patch set. They may support the testing in the future.

Thanks.

-Fenghua

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests for AMD
  2019-05-10 19:29     ` Yu, Fenghua
@ 2019-05-14 17:17       ` Moger, Babu
  0 siblings, 0 replies; 38+ messages in thread
From: Moger, Babu @ 2019-05-14 17:17 UTC (permalink / raw)
  To: Yu, Fenghua, Andre Przywara
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H Peter Anvin,
	Luck, Tony, Chatre, Reinette, Shankar, Ravi V, Shen, Xiaochen,
	Pathan, Arshiya Hayatkhan, Prakhya, Sai Praneeth, linux-kernel,
	James Morse

Fenghua/Andre,


On 5/10/19 2:29 PM, Yu, Fenghua wrote:
> [CAUTION: External Email]
> 
>> On Friday, May 10, 2019 10:40 AM
>> Andre Przywara [mailto:andre.przywara@arm.com] wrote:
>> To: Yu, Fenghua <fenghua.yu@intel.com>
>> Cc: Thomas Gleixner <tglx@linutronix.de>; Ingo Molnar
>> <mingo@redhat.com>; Borislav Petkov <bp@alien8.de>; H Peter Anvin
>> <hpa@zytor.com>; Luck, Tony <tony.luck@intel.com>; Chatre, Reinette
>> <reinette.chatre@intel.com>; Shankar, Ravi V <ravi.v.shankar@intel.com>;
>> Shen, Xiaochen <xiaochen.shen@intel.com>; Pathan, Arshiya Hayatkhan
>> <arshiya.hayatkhan.pathan@intel.com>; Prakhya, Sai Praneeth
>> <sai.praneeth.prakhya@intel.com>; Babu Moger <babu.moger@amd.com>;
>> linux-kernel <linux-kernel@vger.kernel.org>; James Morse
>> <James.Morse@arm.com>
>> Subject: Re: [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests
>> for AMD
>>
>> On Sat,  9 Feb 2019 18:50:41 -0800
>> Fenghua Yu <fenghua.yu@intel.com> wrote:
>>
>> Hi,
>>
>>> From: Babu Moger <babu.moger@amd.com>
>>>
>>> For now, disable MBA and MBM tests for AMD. Deciding test pass/fail is
>>> not clear right now. We can enable when we have some clarity.
>>
>> I don't think this is the right way. The availability of features should be
>> queryable, for instance by looking into /sys/fs/resctrl/info. Checking for a
>> certain vendor to skip tests just sounds wrong to me, and is definitely not
>> scalable or future proof.
>>
>> We should really check the availability of a feature, then skip the whole
>> subsystem test in resctrl_tests.c.
> 
> Babu may correct if I'm wrong: AMD does support the MBA and MBM features. So if querying the info directory, the features are there. But AMD doesn't want to support the testing for the features in the current patch set. They may support the testing in the future.

Yes. AMD supports the MBA and MBM features. But, deciding the test
pass/fail was not clear to me. That is why I decided to disable the test
for now. Right now, it reports the test result as "fail". We can add the
test in the future with some modifications.

> 
> Thanks.
> 
> -Fenghua
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism
  2019-05-10 17:39   ` Andre Przywara
  2019-05-10 17:40     ` Andre Przywara
@ 2019-05-14 17:20     ` James Morse
  2019-05-14 19:40       ` André Przywara
  1 sibling, 1 reply; 38+ messages in thread
From: James Morse @ 2019-05-14 17:20 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Fenghua Yu, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H Peter Anvin, Tony Luck, Reinette Chatre, Ravi V Shankar,
	Xiaochen Shen, Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya,
	Babu Moger, linux-kernel

Hi Andre,

(thanks for digging into this!)

On 10/05/2019 18:39, Andre Przywara wrote:
> On Sat,  9 Feb 2019 18:50:39 -0800
> Fenghua Yu <fenghua.yu@intel.com> wrote:
>> From: Babu Moger <babu.moger@amd.com>
>>
>> RESCTRL feature is supported both on Intel and AMD now. Some features
>> are implemented differently. Add vendor detection mechanism. Use the vendor
>> check where there are differences.
> 
> I don't think vendor detection is the right approach. The Linux userland
> interface should be even architecture agnostic, not to speak of different
> vendors.
> 
> But even if we need this for some reason ...

>> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
>> index 3959b2b0671a..1d9adcfbdb4c 100644
>> --- a/tools/testing/selftests/resctrl/resctrl_tests.c
>> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
>> @@ -14,6 +14,66 @@
>>  #define BENCHMARK_ARGS		64
>>  #define BENCHMARK_ARG_SIZE	64
>>  
>> +/**
>> + * This variables provides information about the vendor
>> + */
>> +int genuine_intel;
>> +int authentic_amd;
>> +
>> +void lcpuid(const unsigned int leaf, const unsigned int subleaf,
>> +	    struct cpuid_out *out)
> 
> There is a much easier way to detect the vendor, without resorting to
> (unchecked) inline assembly in userland:

> I changed this to scan /proc/cpuinfo for a line starting with vendor_id,
> then use the information there. This should work everywhere.

Everywhere x86. /proc/cpuinfo is unfortunately arch specific, arm64 spells that field 'CPU
implementer'. Short of invoking lscpu, I don't know a portable way of finding this string.

What do we need it for? Surely it indicates something is wrong with the kernel interface
if you need to know which flavour of CPU this is.

The only differences I've spotted are the 'MAX_MBA_BW' on Intel is a percentage, on AMD
its a number between 1 and 2K. If user-space needs to know we could add another file with
the 'max_bandwidth'. (I haven't spotted how the MBA default_ctrl gets exposed).

The other one is the non-contiguous CBM values, where user-space is expected to try it and
see [0]. If user-space needs to know, we could expose some 'sparse_bitmaps=[0 1]', unaware
user-space keeps working.


Thanks,

James

[0] https://lore.kernel.org/patchwork/patch/991236/#1179944

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest
  2019-05-10 19:20   ` Yu, Fenghua
@ 2019-05-14 17:20     ` James Morse
  0 siblings, 0 replies; 38+ messages in thread
From: James Morse @ 2019-05-14 17:20 UTC (permalink / raw)
  To: Yu, Fenghua
  Cc: Andre Przywara, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H Peter Anvin, Luck, Tony, Chatre, Reinette, Shankar, Ravi V,
	Shen, Xiaochen, Pathan, Arshiya Hayatkhan, Prakhya, Sai Praneeth,
	Babu Moger, linux-kernel

Hi Fenghua,

On 10/05/2019 20:20, Yu, Fenghua wrote:
>> On Friday, May 10, 2019 10:36 AM
>> Andre Przywara [mailto:andre.przywara@arm.com] wrote:
>> On Sat,  9 Feb 2019 18:50:29 -0800
>> Fenghua Yu <fenghua.yu@intel.com> wrote:

>>> With more and more resctrl features are being added by Intel, AMD and
>>> ARM, a test tool is becoming more and more useful to validate that
>>> both hardware and software functionalities work as expected.
>>
>> That's very much appreciated! We decided to use that tool here to detect
>> regressions in James' upcoming resctrl rework series. While doing so we
>> spotted some shortcomings:

>> - There is some unconditional x86 inline assembly which obviously breaks
>> the build on ARM.
> 
> Will fix this as much as possible.
> 
> BTW, does ARM support perf imc_count events which are used in CAT tests?

I've never heard of these. git-grep says its a powerpc pmu...

(after a quick chat with Andre), is this a cache-miss counter?
If so, its a bit murky, (and beware, I don't know much about perf).
The arch code's armv8_pmu has a 'PERF_COUNT_HW_CACHE_MISSES' map entry, so yes...
... but if we're measuring this on a cache outside the CPU, we'd need an 'uncore' pmu
driver, so it would depend on what the manufacturer implemented.


I should admit that I'm expecting this selftest to test resctrl, and not depend on a lot
else. Couldn't it use the llc_occupancy value, 50% bitmap gives ~50% lower occupancy. Or
(some combination of) the mbm byte counters, (which would require a seeky workload to
cause repeat re-fills of the same line)...


Thanks,

James

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism
  2019-05-14 17:20     ` James Morse
@ 2019-05-14 19:40       ` André Przywara
  2019-05-15  9:08         ` James Morse
  0 siblings, 1 reply; 38+ messages in thread
From: André Przywara @ 2019-05-14 19:40 UTC (permalink / raw)
  To: James Morse
  Cc: Fenghua Yu, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H Peter Anvin, Tony Luck, Reinette Chatre, Ravi V Shankar,
	Xiaochen Shen, Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya,
	Babu Moger, linux-kernel

On 14/05/2019 18:20, James Morse wrote:

Hi James,

> (thanks for digging into this!)
> 
> On 10/05/2019 18:39, Andre Przywara wrote:
>> On Sat,  9 Feb 2019 18:50:39 -0800
>> Fenghua Yu <fenghua.yu@intel.com> wrote:
>>> From: Babu Moger <babu.moger@amd.com>
>>>
>>> RESCTRL feature is supported both on Intel and AMD now. Some features
>>> are implemented differently. Add vendor detection mechanism. Use the vendor
>>> check where there are differences.
>>
>> I don't think vendor detection is the right approach. The Linux userland
>> interface should be even architecture agnostic, not to speak of different
>> vendors.
>>
>> But even if we need this for some reason ...
> 
>>> diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
>>> index 3959b2b0671a..1d9adcfbdb4c 100644
>>> --- a/tools/testing/selftests/resctrl/resctrl_tests.c
>>> +++ b/tools/testing/selftests/resctrl/resctrl_tests.c
>>> @@ -14,6 +14,66 @@
>>>  #define BENCHMARK_ARGS		64
>>>  #define BENCHMARK_ARG_SIZE	64
>>>  
>>> +/**
>>> + * This variables provides information about the vendor
>>> + */
>>> +int genuine_intel;
>>> +int authentic_amd;
>>> +
>>> +void lcpuid(const unsigned int leaf, const unsigned int subleaf,
>>> +	    struct cpuid_out *out)
>>
>> There is a much easier way to detect the vendor, without resorting to
>> (unchecked) inline assembly in userland:
> 
>> I changed this to scan /proc/cpuinfo for a line starting with vendor_id,
>> then use the information there. This should work everywhere.
> 
> Everywhere x86. /proc/cpuinfo is unfortunately arch specific, arm64 spells that field 'CPU
> implementer'. Short of invoking lscpu, I don't know a portable way of finding this string.

Well, what I meant is: It works everywhere to tell whether this box has
an x86 AMD CPU. Yes, it probably won't match anything on other
architectures, but that's fine, as at least it will compile and won't crash.

> What do we need it for? Surely it indicates something is wrong with the kernel interface
> if you need to know which flavour of CPU this is.

As you mentioned, we should not need it. I just couldn't find a better
way (yet) to differentiate between L3 cache ID and physical package ID
(see patch 11/13). So this is a kludge for now to not break this
particular code.

Out of curiosity: Is there any userland tool meant to control the
resources? I guess poking around in sysfs is not how admins are expected
to use this?
This tool would surely run into the same problems, which somewhat tell
me that the interface is not really right.

Cheers,
Andre.

> The only differences I've spotted are the 'MAX_MBA_BW' on Intel is a percentage, on AMD
> its a number between 1 and 2K. If user-space needs to know we could add another file with
> the 'max_bandwidth'. (I haven't spotted how the MBA default_ctrl gets exposed).
> 
> The other one is the non-contiguous CBM values, where user-space is expected to try it and
> see [0]. If user-space needs to know, we could expose some 'sparse_bitmaps=[0 1]', unaware
> user-space keeps working.
> 
> 
> Thanks,
> 
> James
> 
> [0] https://lore.kernel.org/patchwork/patch/991236/#1179944
> 


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism
  2019-05-14 19:40       ` André Przywara
@ 2019-05-15  9:08         ` James Morse
  0 siblings, 0 replies; 38+ messages in thread
From: James Morse @ 2019-05-15  9:08 UTC (permalink / raw)
  To: André Przywara
  Cc: Fenghua Yu, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H Peter Anvin, Tony Luck, Reinette Chatre, Ravi V Shankar,
	Xiaochen Shen, Arshiya Hayatkhan Pathan, Sai Praneeth Prakhya,
	Babu Moger, linux-kernel

Hi André,

On 14/05/2019 20:40, André Przywara wrote:
> On 14/05/2019 18:20, James Morse wrote:
>> On 10/05/2019 18:39, Andre Przywara wrote:
>>> On Sat,  9 Feb 2019 18:50:39 -0800
>>> Fenghua Yu <fenghua.yu@intel.com> wrote:
>>>> From: Babu Moger <babu.moger@amd.com>
>>>>
>>>> RESCTRL feature is supported both on Intel and AMD now. Some features
>>>> are implemented differently. Add vendor detection mechanism. Use the vendor
>>>> check where there are differences.
>>>
>>> I don't think vendor detection is the right approach. The Linux userland
>>> interface should be even architecture agnostic, not to speak of different
>>> vendors.
>>>
>>> But even if we need this for some reason ...

>> What do we need it for? Surely it indicates something is wrong with the kernel interface
>> if you need to know which flavour of CPU this is.
> 
> As you mentioned, we should not need it. I just couldn't find a better
> way (yet) to differentiate between L3 cache ID and physical package ID
> (see patch 11/13). So this is a kludge for now to not break this
> particular code.

[0]? That's broken. It needs to take the 'cache/index?/id' field, and not hard-code '3',
search each 'cache/index?/level' instead.


Documentation/x86/resctrl_ui.rst's "Cache IDs" section says:
| On current generation systems there is one L3 cache per socket and L2
| caches are generally just shared by the hyperthreads on a core, but this
| isn't an architectural requirement.
[...]
| So instead of using "socket" or "core" to define the set of logical cpus
| sharing a resource we use a "Cache ID"
[...]
| To find the ID for each logical CPU look in
| /sys/devices/system/cpu/cpu*/cache/index*/id

arch/x86/kernel/cpu/restrl/core.c:domain_add_cpu() pulls the domain-id out of struct
cacheinfo:
|	int id = get_cache_id(cpu, r->cache_level);

drivers/base/cacheinfo.c has some macro-foliage that exports this same field via sysfs,
and arch/x86/kernel/cpu/restrl/ctrlmondata.c:parse_line() matches that id against the
value user-space provides in the schemata.

(we've got some horrible code for arm64 to make this work without 'cache id' as a hardware
property!)

On x86 these numbers are of the order 0,1,2, so its very likely physical_package_id and
cache_id alias, and you get away with it.


> Out of curiosity: Is there any userland tool meant to control the
> resources? I guess poking around in sysfs is not how admins are expected
> to use this?

I've come across:
https://github.com/intel/intel-cmt-cat/

but I've never even cloned it. The rdtset man page has:
| With --iface-os (-I) parameter, rdtset uses resctrl filesystem (/sys/fs/resctrl)
| instead of accessing MSRs directly.


> This tool would surely run into the same problems, which somewhat tell
> me that the interface is not really right.

At the moment its not as-documented or as the kernel is using those numbers.

I assume this is something that changed in resctrl when it was merged, and this selftest
tool just needs updating.


Thanks,

James

[0] https://lkml.org/lkml/2019/2/9/384

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2019-05-15  9:08 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-10  2:50 [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
2019-02-10  2:50 ` [PATCH v7 01/13] selftests/resctrl: Add README for resctrl tests Fenghua Yu
2019-02-10  2:50 ` [PATCH v7 02/13] selftests/resctrl: Add basic resctrl file system operations and data Fenghua Yu
2019-05-10 17:36   ` Andre Przywara
2019-05-10 19:00     ` Yu, Fenghua
2019-05-10 17:41   ` Borislav Petkov
2019-05-10 19:01     ` Yu, Fenghua
2019-02-10  2:50 ` [PATCH v7 03/13] selftests/resctrl: Read memory bandwidth from perf IMC counter and from resctrl file system Fenghua Yu
2019-02-10  2:50 ` [PATCH v7 04/13] selftests/resctrl: Add callback to start a benchmark Fenghua Yu
2019-05-10 17:37   ` Andre Przywara
2019-02-10  2:50 ` [PATCH v7 05/13] selftests/resctrl: Add built in benchmark Fenghua Yu
2019-05-10 17:37   ` Andre Przywara
2019-02-10  2:50 ` [PATCH v7 06/13] selftests/resctrl: Add MBM test Fenghua Yu
2019-05-10 17:37   ` Andre Przywara
2019-02-10  2:50 ` [PATCH v7 07/13] selftests/resctrl: Add MBA test Fenghua Yu
2019-05-10 17:37   ` Andre Przywara
2019-02-10  2:50 ` [PATCH v7 08/13] selftests/resctrl: Add Cache QoS Monitoring (CQM) selftest Fenghua Yu
2019-05-10 17:38   ` Andre Przywara
2019-02-10  2:50 ` [PATCH v7 09/13] selftests/resctrl: Add Cache Allocation Technology (CAT) selftest Fenghua Yu
2019-05-10 17:38   ` Andre Przywara
2019-02-10  2:50 ` [PATCH v7 10/13] selftests/resctrl: Add vendor detection mechanism Fenghua Yu
2019-05-10 17:39   ` Andre Przywara
2019-05-10 17:40     ` Andre Przywara
2019-05-14 17:20     ` James Morse
2019-05-14 19:40       ` André Przywara
2019-05-15  9:08         ` James Morse
2019-02-10  2:50 ` [PATCH v7 11/13] selftests/resctrl: Use cache index3 id for AMD schemata masks Fenghua Yu
2019-02-10  2:50 ` [PATCH v7 12/13] selftests/resctrl: Disable MBA and MBM tests for AMD Fenghua Yu
2019-05-10 17:40   ` Andre Przywara
2019-05-10 19:29     ` Yu, Fenghua
2019-05-14 17:17       ` Moger, Babu
2019-02-10  2:50 ` [PATCH v7 13/13] selftests/resctrl: Add the test in MAINTAINERS Fenghua Yu
2019-02-14 14:56 ` [PATCH v7 00/13] selftests/resctrl: Add resctrl selftest Fenghua Yu
2019-03-06 20:55   ` Moger, Babu
2019-02-27 18:07 ` Moger, Babu
2019-05-10 17:35 ` Andre Przywara
2019-05-10 19:20   ` Yu, Fenghua
2019-05-14 17:20     ` James Morse

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).