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) and MBA (Memory Bandwidth Allocation) tests. We can enhance
the selftest tool to include more functionality tests in future.
The tests are in tools/testing/selftests/resctrl in order to have
generic test code for all architectures.
Arshiya Hayatkhan Pathan (2):
selftests/resctrl: Add mbm test
selftests/resctrl: Add mba test
Fenghua Yu (1):
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/fill_buf.c | 178 ++++++++++++
tools/testing/selftests/resctrl/mba.c | 144 ++++++++++
tools/testing/selftests/resctrl/mbm.c | 113 ++++++++
tools/testing/selftests/resctrl/resctrl.c | 367 ++++++++++++++++++++++++
tools/testing/selftests/resctrl/resctrl.h | 107 +++++++
tools/testing/selftests/resctrl/resctrl_membw.c | 328 +++++++++++++++++++++
tools/testing/selftests/resctrl/resctrl_membw.h | 49 ++++
tools/testing/selftests/resctrl/resctrl_tests.c | 104 +++++++
tools/testing/selftests/resctrl/resctrl_val.c | 192 +++++++++++++
11 files changed, 1599 insertions(+)
create mode 100644 tools/testing/selftests/resctrl/Makefile
create mode 100644 tools/testing/selftests/resctrl/fill_buf.c
create mode 100644 tools/testing/selftests/resctrl/mba.c
create mode 100644 tools/testing/selftests/resctrl/mbm.c
create mode 100644 tools/testing/selftests/resctrl/resctrl.c
create mode 100644 tools/testing/selftests/resctrl/resctrl.h
create mode 100644 tools/testing/selftests/resctrl/resctrl_membw.c
create mode 100644 tools/testing/selftests/resctrl/resctrl_membw.h
create mode 100644 tools/testing/selftests/resctrl/resctrl_tests.c
create mode 100644 tools/testing/selftests/resctrl/resctrl_val.c
--
2.5.0
From: Arshiya Hayatkhan Pathan <[email protected]>
mbm 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 "-ben".
We can add memory bandwidth monitoring for multiple processes in the
future.
Signed-off-by: Arshiya Hayatkhan Pathan <[email protected]>
Signed-off-by: Sai Praneeth Prakhya <[email protected]>,
Signed-off-by: Fenghua Yu <[email protected]>
---
tools/testing/selftests/resctrl/Makefile | 8 +-
tools/testing/selftests/resctrl/mbm.c | 113 ++++++++++++++++++++++++
tools/testing/selftests/resctrl/resctrl.h | 3 +
tools/testing/selftests/resctrl/resctrl_tests.c | 94 ++++++++++++++++++++
4 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/resctrl/mbm.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..c5a69a2a5a6e 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 resctrl.o \
+ resctrl_val.o resctrl_membw.o fill_buf.o mbm.o
+
.PHONY: clean
clean:
- $(RM) *.o *~
+ $(RM) *.o *~ resctrl_tests
diff --git a/tools/testing/selftests/resctrl/mbm.c b/tools/testing/selftests/resctrl/mbm.c
new file mode 100644
index 000000000000..9edf9bd58bf5
--- /dev/null
+++ b/tools/testing/selftests/resctrl/mbm.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Memory Bandwidth Monitoring (MBM) test
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ * Arshiya Hayatkhan Pathan <[email protected]>
+ * Sai Praneeth Prakhya <[email protected]>,
+ * Fenghua Yu <[email protected]>
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "resctrl.h"
+
+
+static void
+show_bw_info(unsigned long long *bw_imc, unsigned long long *bw_resc, int span)
+{
+ float avg_bw_imc = 0.0, avg_bw_resc = 0.0, avg_diff = 0.0;
+ int i, sum_bw_imc = 0, sum_bw_resc = 0;
+
+ for (i = 1; i < 5 ; i++) {
+ sum_bw_imc += bw_imc[i];
+ sum_bw_resc += bw_resc[i];
+ }
+
+ avg_bw_imc = sum_bw_imc/4.0;
+ avg_bw_resc = sum_bw_resc/4.0;
+ avg_diff = avg_bw_resc - avg_bw_imc;
+
+ printf("\n Span (MB): %d \t", span);
+ printf("avg_bw_imc: %.2f\t", avg_bw_imc);
+ printf("avg_bw_resc: %.2f\t", avg_bw_resc);
+ printf("avg_diff: %d \t", abs(avg_diff));
+
+ if (abs(avg_diff) > 300)
+ printf(" failed\n");
+ else
+ printf(" passed\n");
+}
+
+int mbm_bw_change(char *resctrl_val_type, int core_id, int span,
+ char *bw_report, char *bm_type, char **benchmark_cmd)
+{
+ char temp[512], *token_array[8], *allocation_str;
+ unsigned long long bw_imc[1024], bw_resc[1024];
+ struct resctrl_val_param param = {
+ .resctrl_val = resctrl_val_type,
+ .ctrlgrp = "c1",
+ .mongrp = "m1",
+ .cpu_no = core_id,
+ .mum_resctrlfs = 1,
+ .num_of_runs = 5,
+ .filename = "result1",
+ .bw_report = bw_report,
+ .bm_type = bm_type
+ };
+ int allocation, x, length, status;
+ char *output = "result1";
+ pid_t bm_pid;
+ FILE *fp;
+
+ allocation = 100;
+ length = snprintf(NULL, 0, "%d", allocation);
+ allocation_str = malloc(length + 1);
+ snprintf(allocation_str, length + 1, "%d", allocation);
+ param.schemata = allocation_str;
+
+ bm_pid = fork();
+
+ if (bm_pid == 0) {
+ resctrl_val(benchmark_cmd, ¶m);
+ PARENT_EXIT("Unable to run benchmark\n");
+ } else if (bm_pid < 0)
+ PERR_EXIT("Failed to fork\n");
+
+ waitpid(bm_pid, &status, 0);
+
+ printf("\n Checking for pass/fail\n");
+
+ fp = fopen(output, "r");
+ if (fp == NULL)
+ PERR_EXIT("Error in opening file\n");
+
+ x = 0;
+ while (fgets(temp, 1024, fp) != NULL) {
+ char *token = strtok(temp, ":\t");
+ int i = 0;
+
+ while (token != NULL) {
+ token_array[i++] = token;
+ token = strtok(NULL, ":\t");
+ }
+
+ bw_resc[x] = atoll(token_array[5]);
+ bw_imc[x] = atoll(token_array[3]);
+ x++;
+ }
+
+ show_bw_info(bw_imc, bw_resc, span);
+
+ fclose(fp);
+ if (remove(output))
+ printf("Unable to delete the file\n");
+
+ return 0;
+}
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index ab65bdd0a96f..349abf0502f5 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -98,4 +98,7 @@ int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
int run_fill_buf(int span, int malloc_and_init_memory, int memflush, int op);
void resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param);
+int mbm_bw_change(char *resctrl_val_type, int core_id, int span,
+ char *bw_report, char *bm_type, char **benchmark_cmd);
+
#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..b9d1665bb101
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Resctrl tests
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ * Arshiya Hayatkhan Pathan <[email protected]>
+ * Sai Praneeth Prakhya <[email protected]>,
+ * Fenghua Yu <[email protected]>
+ */
+#include "resctrl.h"
+
+int ben_count;
+
+int main(int argc, char **argv)
+{
+ int res, c, ben_ind, core_id, span, argc_new, has_ben;
+ char *bw_report = NULL, *bm_type = NULL;
+ char **benchmark_cmd = NULL;
+
+ ben_ind = 0, core_id = 0, span = 250, argc_new = argc;
+ has_ben = 0;
+
+ /*
+ * We need root privileges to run because
+ * 1. We write to resctrl FS
+ * 2. We execute perf commands
+ */
+ if (geteuid() != 0)
+ FPRINTF_EXIT("Please run this program as root\n");
+
+ /*
+ * Extract benchmark command from command line.
+ */
+ for (int i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "-ben") == 0) {
+ ben_ind = i + 1;
+ printf("ben_id:%d\n", ben_ind);
+ ben_count = argc - ben_ind;
+ argc_new = ben_ind - 1;
+ has_ben = 1;
+ break;
+ }
+ }
+
+ while ((c = getopt(argc_new, argv, "p:s:")) != -1) {
+ switch (c) {
+ case 'p':
+ core_id = atoi(optarg);
+ break;
+ case 's':
+ span = atoi(optarg);
+ break;
+ }
+ }
+
+ benchmark_cmd = malloc(10 * sizeof(char *));
+ if (!benchmark_cmd)
+ return -1;
+
+ if (has_ben) {
+ for (int i = ben_ind; i < argc; i++) {
+ benchmark_cmd[i - ben_ind] = malloc(1024 *
+ sizeof(char));
+ if (benchmark_cmd[i - ben_ind] == NULL)
+ return -1;
+ sprintf(benchmark_cmd[i - ben_ind], "%s",
+ argv[i]);
+ }
+ } else {
+ for (int i = 0; i < 5; i++) {
+ benchmark_cmd[i] = malloc(1024 * sizeof(char));
+ if (benchmark_cmd[i] == NULL)
+ return -1;
+ }
+ 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");
+ }
+
+ bw_report = "reads";
+ bm_type = "fill_buf";
+
+ printf("\nTest 1 : MBM BW Change Starting..\n");
+ res = mbm_bw_change("mbm", core_id, span, bw_report, bm_type,
+ benchmark_cmd);
+ if (res)
+ printf("Error in running tests for mbm bw change!\n");
+
+ return 0;
+}
--
2.5.0
The resctrl selftests will be maintained by RDT maintainers.
Signed-off-by: Fenghua Yu <[email protected]>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 6ac000cc006d..07d597c68edc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12271,6 +12271,7 @@ S: Supported
F: arch/x86/kernel/cpu/intel_rdt*
F: arch/x86/include/asm/intel_rdt_sched.h
F: Documentation/x86/intel_rdt*
+F: tools/testing/selftests/resctrl
READ-COPY UPDATE (RCU)
M: "Paul E. McKenney" <[email protected]>
--
2.5.0
From: Arshiya Hayatkhan Pathan <[email protected]>
mba 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 "-ben".
We can add memory bandwidth allocation for multiple processes in the
future.
Signed-off-by: Arshiya Hayatkhan Pathan <[email protected]>
Signed-off-by: Sai Praneeth Prakhya <[email protected]>,
Signed-off-by: Fenghua Yu <[email protected]>
---
tools/testing/selftests/resctrl/Makefile | 2 +-
tools/testing/selftests/resctrl/mba.c | 144 ++++++++++++++++++++++++
tools/testing/selftests/resctrl/resctrl.h | 3 +
tools/testing/selftests/resctrl/resctrl_tests.c | 10 ++
4 files changed, 158 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/resctrl/mba.c
diff --git a/tools/testing/selftests/resctrl/Makefile b/tools/testing/selftests/resctrl/Makefile
index c5a69a2a5a6e..5ba73435b659 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 resctrl.o \
- resctrl_val.o resctrl_membw.o fill_buf.o mbm.o
+ resctrl_val.o resctrl_membw.o fill_buf.o mbm.o mba.o
.PHONY: clean
diff --git a/tools/testing/selftests/resctrl/mba.c b/tools/testing/selftests/resctrl/mba.c
new file mode 100644
index 000000000000..4a3f8b156657
--- /dev/null
+++ b/tools/testing/selftests/resctrl/mba.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Memory Bandwidth Allocation (MBA) test
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ * Arshiya Hayatkhan Pathan <[email protected]>
+ * Sai Praneeth Prakhya <[email protected]>,
+ * Fenghua Yu <[email protected]>
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "resctrl.h"
+
+int mba_schemata_change(char *resctrl_val_type, int core_id, int span,
+ char *bw_report, char *bm_type,
+ char **benchmark_cmd)
+{
+ char *token_array[8], output[] = "result", *allocation_str, temp[512];
+ unsigned long long bw_imc[1024], bw_resc[1024];
+ struct resctrl_val_param param = {
+ .resctrl_val = resctrl_val_type,
+ .ctrlgrp = "c1",
+ .mongrp = "m1",
+ .cpu_no = core_id,
+ .mum_resctrlfs = 1,
+ .num_of_runs = -1,
+ .filename = "result",
+ .bw_report = bw_report,
+ .bm_type = bm_type
+ };
+ int allocation, x, failed, length;
+ pid_t bm_pid;
+ FILE *fp;
+
+ allocation = 100;
+ length = snprintf(NULL, 0, "%d", allocation);
+ allocation_str = malloc(length + 1);
+ snprintf(allocation_str, length + 1, "%d", allocation);
+ param.schemata = allocation_str;
+
+ bm_pid = fork();
+ printf("Bm_pid is : %d\n", bm_pid);
+
+ if (bm_pid == 0) {
+ resctrl_val(benchmark_cmd, ¶m);
+ PARENT_EXIT("Unable to run benchmark\n");
+ } else if (bm_pid < 0)
+ PERR_EXIT("Failed to fork\n");
+ else {
+ sleep(1);
+ /*
+ * Change schemata percentage from 100 to 10%
+ * Write schemata to specified con_mon grp, mon_grp in
+ * resctrl FS
+ */
+ for (int i = 0; i < 10; i++) {
+ allocation = 100 - 10*i;
+
+ if (strcmp(resctrl_val_type, "mba") == 0) {
+ length = snprintf(NULL, 0, "%d",
+ allocation);
+ allocation_str = malloc(length + 1);
+ snprintf(allocation_str, length + 1,
+ "%d", allocation);
+ write_schemata("c1", allocation_str,
+ core_id, resctrl_val_type);
+ printf("changed schemata to : %d\n",
+ allocation);
+ }
+ sleep(5);
+ }
+ free(allocation_str);
+ kill(bm_pid, SIGINT);
+ }
+
+ printf("\nchecking for pass/fail\n");
+ fp = fopen(output, "r");
+ if (fp == NULL)
+ PERR_EXIT("Error in opening file\n");
+
+ x = 0;
+ while (fgets(temp, 1024, fp) != NULL) {
+ int i = 0;
+ char *token = strtok(temp, ":\t");
+
+ while (token != NULL) {
+ token_array[i++] = token;
+ token = strtok(NULL, ":\t");
+ }
+
+ bw_resc[x] = atoll(token_array[5]);
+ bw_imc[x] = atoll(token_array[3]);
+ x++;
+ }
+
+ if (fclose(fp) == EOF)
+ PERR_EXIT("Error in closing file\n");
+
+ failed = 0;
+ /* Memory bandwidth from 100% down to 10% */
+ for (int i = 0; i < 10; i++) {
+ float avg_bw_imc = 0.0, avg_bw_resc = 0.0;
+ int sum_bw_imc = 0, sum_bw_resc = 0;
+ float avg_diff = 0.0;
+
+ for (int j = 5 * i + 1; j < 5*i+5 ; j++) {
+ sum_bw_imc += bw_imc[j];
+ sum_bw_resc += bw_resc[j];
+ }
+
+ avg_bw_imc = sum_bw_imc / 4.0;
+ avg_bw_resc = sum_bw_resc / 4.0;
+ avg_diff = avg_bw_resc - avg_bw_imc;
+
+ printf("\nschemata percentage: %d \t", 100 - 10 * i);
+ printf("avg_bw_imc: %.2f\t", avg_bw_imc);
+ printf("avg_bw_resc: %.2f\t", avg_bw_resc);
+ printf("avg_diff: %d \t", abs(avg_diff));
+ if (abs(avg_diff) > 300) {
+ 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");
+
+ if (remove(output))
+ printf("Unable to delete the file\n");
+
+ return 0;
+}
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index 349abf0502f5..41dc4b172672 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -100,5 +100,8 @@ void resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param);
int mbm_bw_change(char *resctrl_val_type, int core_id, int span,
char *bw_report, char *bm_type, char **benchmark_cmd);
+int mba_schemata_change(char *resctrl_val_type, int core_id, int span,
+ char *bw_report, char *bm_type,
+ char **benchmark_cmd);
#endif /* RESCTRL_H */
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index b9d1665bb101..93d25355cee4 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -90,5 +90,15 @@ int main(int argc, char **argv)
if (res)
printf("Error in running tests for mbm bw change!\n");
+ printf("\nTest 2: MBA Schemata Change Starting..\n");
+ if (!has_ben) {
+ span = 250;
+ sprintf(benchmark_cmd[1], "%d", span);
+ }
+ res = mba_schemata_change("mba", core_id, span, bw_report,
+ bm_type, benchmark_cmd);
+ if (res)
+ printf("Error in running tests for mba-change-schemata!\n");
+
return 0;
}
--
2.5.0
From: Sai Praneeth Prakhya <[email protected]>
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 <[email protected]>
Signed-off-by: Arshiya Hayatkhan Pathan <[email protected]>
Signed-off-by: Fenghua Yu <[email protected]>
---
tools/testing/selftests/resctrl/fill_buf.c | 178 +++++++++++++++++++++++++++++
1 file changed, 178 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..a94d1e83a736
--- /dev/null
+++ b/tools/testing/selftests/resctrl/fill_buf.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fill_buf benchmark
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ * Arshiya Hayatkhan Pathan <[email protected]>
+ * Sai Praneeth Prakhya <[email protected]>,
+ * Fenghua Yu <[email protected]>
+ */
+#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 void fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr)
+{
+ while (1) {
+ unsigned char sum, *p;
+
+ p = start_ptr;
+ /* Read two chars in each cache line to stress cache */
+ while (p < (end_ptr - 1024)) {
+ sum += p[0] + p[32] + p[64] + p[96] + p[128] +
+ p[160] + p[192] + p[224] + p[256] + p[288] +
+ p[320] + p[352] + p[384] + p[416] + p[448] +
+ p[480] + p[512] + p[544] + p[576] + p[608] +
+ p[640] + p[672] + p[704] + p[736] + p[768] +
+ p[800] + p[832] + p[864] + p[896] + p[928] +
+ p[960] + p[992];
+ p += 1024;
+ }
+ }
+}
+
+static void fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr)
+{
+ while (1) {
+ while (start_ptr < end_ptr) {
+ *start_ptr = '1';
+ start_ptr += (CL_SIZE / 2);
+ }
+ start_ptr = startptr;
+ }
+}
+
+static void
+fill_cache(unsigned long long buf_size, int malloc_and_init,
+ int memflush, int op)
+{
+ unsigned char *start_ptr, *end_ptr;
+ unsigned long long i;
+
+ if (malloc_and_init) {
+ start_ptr = malloc_and_init_memory(buf_size);
+ printf("Started benchmark with memalign\n");
+ } else {
+ start_ptr = malloc(buf_size);
+ printf("Started benchmark with malloc\n");
+ }
+
+ if (start_ptr == NULL)
+ return;
+
+ 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);
+ printf("Started benchmark with memflush\n");
+ } else {
+ printf("Started benchmark *without* memflush\n");
+ }
+
+ if (op == 0)
+ fill_cache_read(start_ptr, end_ptr);
+ else
+ fill_cache_write(start_ptr, end_ptr);
+
+ free(startptr);
+
+ exit(EXIT_FAILURE);
+}
+
+int run_fill_buf(int span, int malloc_and_init_memory, int memflush, int op)
+{
+ unsigned long long cache_size = span * MB;
+
+ /* 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");
+
+ printf("Cache size in Bytes = %llu\n", cache_size);
+
+ fill_cache(cache_size, malloc_and_init_memory, memflush, op);
+ printf("Unable to allocate memory\n");
+
+ exit(EXIT_FAILURE);
+}
--
2.5.0
From: Sai Praneeth Prakhya <[email protected]>
The callback starts a child and puts the child pid in created
resctrl group with specified memory bandwidth in schemata. The child
starts running benchmark. Later the callback will be used by tests
to start the benchmark.
Signed-off-by: Sai Praneeth Prakhya <[email protected]>
Signed-off-by: Arshiya Hayatkhan Pathan <[email protected]>
Signed-off-by: Fenghua Yu <[email protected]>
---
tools/testing/selftests/resctrl/resctrl.h | 27 ++++
tools/testing/selftests/resctrl/resctrl_val.c | 192 ++++++++++++++++++++++++++
2 files changed, 219 insertions(+)
create mode 100644 tools/testing/selftests/resctrl/resctrl_val.c
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index 1da8f871a01a..ab65bdd0a96f 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -51,6 +51,32 @@
exit(EXIT_FAILURE); \
} while (0)
+/*
+ * resctrl_val: Functional validation of resctrl features
+ * @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)
+ * @schemata: Schemata while validating allocation type features
+ * @cpu_no: CPU number to which the benchmark would be binded
+ * @mum_resctrlfs: Should the resctrl FS be remounted?
+ * @num_of_runs: Number of runs before exiting
+ * @filename: Name of file to which the o/p should be written
+ * @bw_report: Bandwidth report type (reads vs writes)
+ */
+struct resctrl_val_param {
+ char *resctrl_val;
+ char ctrlgrp[64];
+ char mongrp[64];
+ char *schemata;
+ int cpu_no;
+ int span;
+ int mum_resctrlfs;
+ int num_of_runs;
+ char filename[64];
+ char *bw_report;
+ char *bm_type;
+};
+
pid_t bm_pid, ppid;
int ben_count;
@@ -70,5 +96,6 @@ void write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
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(int span, int malloc_and_init_memory, int memflush, int op);
+void 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
new file mode 100644
index 000000000000..6d5f9e7f5421
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl_val.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Core controller to start benchmark and memory bandwidth tests
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ * Arshiya Hayatkhan Pathan <[email protected]>
+ * Sai Praneeth Prakhya <[email protected]>,
+ * Fenghua Yu <[email protected]>
+ */
+#include "resctrl_membw.h"
+#include "resctrl.h"
+
+pid_t bm_pid, ppid;
+
+static void print_results_bw(char *filename, int bm_pid, float bw_imc,
+ unsigned long long bw_resc)
+{
+ int diff = abs(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: %llu \t Difference: %d\n", bw_resc, diff);
+ } else {
+ fp = fopen(filename, "a");
+ if (!fp)
+ CHILD_EXIT("Cannot open file 'a'");
+ if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t ",
+ bm_pid, bw_imc) <= 0 ||
+ fprintf(fp, "Mem_BW_resc: %llu \t Difference: %d\n",
+ bw_resc, diff) <= 0) {
+ fclose(fp);
+ CHILD_EXIT("Could not log results.");
+ }
+ fclose(fp);
+ }
+}
+
+void resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
+{
+ unsigned long long bw_resc, bw_resc_start, bw_resc_end;
+ char *resctrl_val = param->resctrl_val;
+ int runs_flag, count_of_run, sig;
+ struct sigaction sigact;
+ union sigval value;
+ float bw_imc;
+ FILE *fp;
+
+ bw_resc_start = 0, count_of_run = 0, sig = 0;
+
+ if (strcmp(param->filename, "") == 0)
+ sprintf(param->filename, "stdio");
+
+ if (strcmp(param->bw_report, "") == 0)
+ param->bw_report = "total";
+
+ if (param->num_of_runs > 0)
+ runs_flag = 1;
+ else
+ runs_flag = 0;
+
+ validate_resctrl_feature_request(resctrl_val);
+
+ if ((strcmp(resctrl_val, "mba")) == 0 ||
+ (strcmp(resctrl_val, "mbm")) == 0)
+ validate_bw_report_request(param->bw_report);
+
+ if ((runs_flag) && (param->num_of_runs <= 0))
+ FPRINTF_EXIT("Num of runs should be a real no > 0\n");
+
+ remount_resctrlfs(param->mum_resctrlfs);
+
+ /*
+ * 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 || (fprintf(fp, "%d\n", 0) <= 0) || (fclose(fp) == EOF))
+ PERR_EXIT("Unable to establish sync bw parent & child");
+
+ /*
+ * Fork to start benchmark, save child's pid so that it can be killed
+ * when needed
+ */
+ bm_pid = fork();
+ if (bm_pid == -1)
+ PERR_EXIT("Unable to fork");
+
+ 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");
+
+ /* Signal parent that child is ready */
+ fp = fopen("sig", "w");
+ if ((fp == NULL) || (fprintf(fp, "%d\n", 1) <= 0) ||
+ (fclose(fp) == EOF))
+ PARENT_EXIT("can't signal that child is ready");
+
+ /* Suspend child until delivery of "SIGUSR1" from parent */
+ sigsuspend(&sigact.sa_mask);
+ }
+
+ 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))
+ CHILD_EXIT("Can't register parent for CTRL-C handler");
+
+ value.sival_ptr = benchmark_cmd;
+
+ /* Taskset benchmark to specified cpu */
+ taskset_benchmark(bm_pid, param->cpu_no);
+
+ /* Write benchmark to specified con_mon grp, mon_grp in resctrl FS*/
+ write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
+ resctrl_val);
+
+ /* Write schemata to specified con_mon grp, mon_grp in resctrl FS */
+ write_schemata(param->ctrlgrp, param->schemata, param->cpu_no,
+ resctrl_val);
+
+ if ((strcmp(resctrl_val, "mbm") == 0) ||
+ (strcmp(resctrl_val, "mba") == 0)) {
+ initialize_mem_bw_imc();
+ initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
+ param->cpu_no, resctrl_val);
+ }
+
+ /*
+ * Parent should signal child to start executing benchmark only upon
+ * receiving a signal from child saying that it's ready
+ */
+ while (sig == 0) {
+ fp = fopen("sig", "r");
+ if (!fp)
+ CHILD_EXIT("Unable to open 'sig' file");
+ fscanf(fp, "%d\n", &sig);
+ if (fclose(fp) == EOF)
+ CHILD_EXIT("Unable to close 'sig' file");
+ }
+ if (system(RM_SIG_FILE) != 0)
+ perror("Unable to remove 'sig' file");
+
+ /* Signal child to start benchmark */
+ if (sigqueue(bm_pid, SIGUSR1, value) == -1)
+ CHILD_EXIT("Unable to signal child to start execution");
+
+ while (1) {
+ if (param->num_of_runs != -1 &&
+ count_of_run >= param->num_of_runs) {
+ ctrlc_handler(0, NULL, NULL);
+ break;
+ }
+
+ if ((strcmp(resctrl_val, "mbm") == 0) ||
+ (strcmp(resctrl_val, "mba") == 0)) {
+ bw_imc = get_mem_bw_imc(param->cpu_no,
+ param->bw_report);
+ bw_resc_end = get_mem_bw_resctrl();
+ bw_resc = (bw_resc_end - bw_resc_start) / MB;
+ print_results_bw(param->filename, bm_pid, bw_imc,
+ bw_resc);
+ bw_resc_start = bw_resc_end;
+ }
+ count_of_run++;
+ }
+
+ exit(EXIT_SUCCESS);
+}
--
2.5.0
From: Sai Praneeth Prakhya <[email protected]>
The basic resctrl file system operations and data are added for future
usage by resctrl selftest tool.
Signed-off-by: Sai Praneeth Prakhya <[email protected]>
Signed-off-by: Arshiya Hayatkhan Pathan <[email protected]>
Signed-off-by: Fenghua Yu <[email protected]>
---
tools/testing/selftests/resctrl/Makefile | 10 +
tools/testing/selftests/resctrl/resctrl.c | 367 ++++++++++++++++++++++++++++++
tools/testing/selftests/resctrl/resctrl.h | 74 ++++++
3 files changed, 451 insertions(+)
create mode 100644 tools/testing/selftests/resctrl/Makefile
create mode 100644 tools/testing/selftests/resctrl/resctrl.c
create mode 100644 tools/testing/selftests/resctrl/resctrl.h
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.c b/tools/testing/selftests/resctrl/resctrl.c
new file mode 100644
index 000000000000..61014228ea24
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Basic resctrl file system operations
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ * Arshiya Hayatkhan Pathan <[email protected]>
+ * Sai Praneeth Prakhya <[email protected]>,
+ * Fenghua Yu <[email protected]>
+ */
+#include "resctrl.h"
+
+/*
+ * 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
+ */
+void 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 != NULL) {
+ while ((ep = readdir(dp)) != NULL)
+ count++;
+ closedir(dp);
+ } else {
+ PERR_EXIT("Unable to read /sys/fs/resctrl");
+ }
+
+ /*
+ * 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)
+ PERR_EXIT("Unable to umount resctrl");
+ printf("Remount: done!\n");
+ } else {
+ printf("Not remounting!\n");
+ return;
+ }
+ }
+
+ if (mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL) != 0)
+ PERR_EXIT("Unable to mount resctrl FS at /sys/fs/resctrl");
+}
+
+char get_sock_num(int cpu_no)
+{
+ char sock_num, 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 || fscanf(fp, "%c", &sock_num) <= 0 || fclose(fp) == EOF)
+ CHILD_EXIT("Could not get socket number");
+
+ return sock_num;
+}
+
+/*
+ * 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
+ */
+void 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))
+ CHILD_EXIT("Unable to taskset benchmark");
+
+ printf("Taskset benchmark: done!\n");
+}
+
+/*
+ * Run a specified benchmark or fill buffer (default benchmark) by directing
+ * benchmark stdio to /dev/null
+ */
+void run_benchmark(int signum, siginfo_t *info, void *ucontext)
+{
+ char **benchmark_cmd = info->si_ptr;
+ int span, operation;
+
+ /*
+ * Direct stdio of child to /dev/null, so that only parent writes to
+ * stdio (console)
+ */
+ if (freopen("/dev/null", "w", stdout) == NULL)
+ PARENT_EXIT("Unable to direct BM op to /dev/null");
+
+ if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
+ span = atoi(benchmark_cmd[1]);
+ operation = atoi(benchmark_cmd[4]);
+ if (run_fill_buf(span, 1, 1, operation))
+ printf("Error in running fill buffer\n");
+ } else {
+ benchmark_cmd[ben_count] = malloc(1024 * sizeof(char));
+ sprintf(benchmark_cmd[ben_count], "%s", "NULL");
+ /* Replace child with specified benchmark */
+ execvp(benchmark_cmd[0], benchmark_cmd);
+ }
+
+ PARENT_EXIT("Unable to run specified benchmark");
+}
+
+/*
+ * create_con_mon_grp: Create a con_mon group *only* if one doesn't exist
+ * @ctrlgrp: Name of the con_mon group
+ * @controlgroup: Path at which it should be created
+ */
+void create_con_mon_grp(const char *ctrlgrp, const char *controlgroup)
+{
+ int found_ctrl_grp = 0;
+ struct dirent *ep;
+ DIR *dp;
+
+ /*
+ * At this point, we are guaranteed to have resctrl FS mounted and if
+ * ctrlgrp == NULL, it means, user wants to use root con_mon grp, so do
+ * nothing
+ */
+ if (!ctrlgrp)
+ return;
+
+ /* Check if requested con_mon grp exists or not */
+ dp = opendir(RESCTRL_PATH);
+ if (dp != NULL) {
+ while ((ep = readdir(dp)) != NULL) {
+ if (strcmp(ep->d_name, ctrlgrp) == 0)
+ found_ctrl_grp = 1;
+ }
+ closedir(dp);
+ } else {
+ CHILD_EXIT("Unable to open resctrlfs for con_mon grp");
+ }
+
+ /* Requested con_mon grp doesn't exist, hence create it */
+ if (found_ctrl_grp == 0) {
+ if (mkdir(controlgroup, 0) == -1)
+ CHILD_EXIT("Unable to create con_mon group");
+ }
+}
+
+/*
+ * create_mon_grp: Create a monitor group *only* if one doesn't exist
+ * @mongrp: Name of the monitor group
+ * @controlgroup: Path of con_mon grp at which the mon grp will be created
+ */
+void create_mon_grp(const char *mongrp, const char *controlgroup)
+{
+ char monitorgroup[1024];
+ int found_mon_grp = 0;
+ struct dirent *ep;
+ DIR *dp;
+
+ /* Check if requested mon grp exists or not */
+ sprintf(monitorgroup, "%s/mon_groups", controlgroup);
+ dp = opendir(monitorgroup);
+ if (dp != NULL) {
+ while ((ep = readdir(dp)) != NULL) {
+ if (strcmp(ep->d_name, mongrp) == 0)
+ found_mon_grp = 1;
+ }
+ closedir(dp);
+ } else {
+ CHILD_EXIT("Unable to open resctrl FS for mon group");
+ }
+
+ /* Requested mon grp doesn't exist, hence create it */
+ sprintf(monitorgroup, "%s/mon_groups/%s", controlgroup, mongrp);
+ if (found_mon_grp == 0) {
+ if (mkdir(monitorgroup, 0) == -1)
+ CHILD_EXIT("Unable to create mon group");
+ }
+}
+
+/*
+ * 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.
+ */
+void write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
+ char *resctrl_val)
+{
+ char controlgroup[1024], monitorgroup[1024];
+ FILE *fp;
+
+ if (ctrlgrp)
+ sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
+ else
+ sprintf(controlgroup, "%s", RESCTRL_PATH);
+
+ create_con_mon_grp(ctrlgrp, controlgroup);
+
+ /* Create mon grp, only for monitoring features like "mbm" */
+ if ((strcmp(resctrl_val, "mbm") == 0)) {
+ if (mongrp) {
+ create_mon_grp(mongrp, controlgroup);
+ sprintf(monitorgroup, "%s/mon_groups/%s/tasks",
+ controlgroup, mongrp);
+ }
+ }
+
+ strcat(controlgroup, "/tasks");
+
+ /* Write child pid to con_mon grp */
+ fp = fopen(controlgroup, "w");
+ if (!fp || fprintf(fp, "%d\n", bm_pid) <= 0 || fclose(fp) == EOF)
+ CHILD_EXIT("Failed to write child to con_mon grp");
+
+ /* Write child pid to mon grp, only for "mbm" */
+ if ((strcmp(resctrl_val, "mbm") == 0)) {
+ if (mongrp) {
+ fp = fopen(monitorgroup, "w");
+ if (!fp || fprintf(fp, "%d\n", bm_pid) <= 0 ||
+ fclose(fp) == EOF)
+ CHILD_EXIT("Failed to write child to mon grp");
+ }
+ }
+ printf("Write benchmark to resctrl FS: done!\n");
+}
+
+/*
+ * 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
+ */
+void write_schemata(char *ctrlgrp, char *schemata, int cpu_no,
+ char *resctrl_val)
+{
+ char sock_num, controlgroup[1024], schema[1024];
+ FILE *fp;
+
+ if (strcmp(resctrl_val, "mba") == 0) {
+
+ if (!schemata) {
+ fprintf(stderr, "Schemata empty, so not updating\n");
+ return;
+ }
+ sock_num = get_sock_num(cpu_no);
+ if (ctrlgrp)
+ sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH,
+ ctrlgrp);
+ else
+ sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
+ sprintf(schema, "%s%c%c%s", "MB:", sock_num, '=', schemata);
+
+ fp = fopen(controlgroup, "w");
+ if (!fp || fprintf(fp, "%s\n", schema) <= 0 ||
+ fclose(fp) == EOF)
+ CHILD_EXIT("Unable to write schemata to con_mon grp");
+ printf("Write schemata to resctrl FS: done!\n");
+ }
+}
+
+/*
+ * Check if the requested feature is a valid resctrl feature or not.
+ * If yes, check if it's supported by this platform or not.
+ */
+void validate_resctrl_feature_request(char *resctrl_val)
+{
+ const char *resctrl_features_list[MAX_RESCTRL_FEATURES] = {
+ "mbm", "mba"};
+ int resctrl_features_supported[MAX_RESCTRL_FEATURES] = {0, 0};
+ int i, valid_resctrl_feature = -1;
+ char line[1024];
+ FILE *fp;
+
+ if (!resctrl_val)
+ FPRINTF_EXIT("resctrl feature cannot be NULL\n");
+
+ /* 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_EXIT("Not a valid resctrl feature request\n");
+
+ /* Enumerate resctrl features supported by this platform */
+ if (system("dmesg > dmesg") != 0)
+ PERR_EXIT("Could not create custom dmesg file");
+
+ fp = fopen("dmesg", "r");
+ if (!fp)
+ PERR_EXIT("Could not read custom created dmesg");
+
+ while (fgets(line, 1024, fp) != NULL) {
+ if ((strstr(line, RESCTRL_MBM)) != NULL)
+ resctrl_features_supported[0] = 1;
+ if ((strstr(line, RESCTRL_MBA)) != NULL)
+ resctrl_features_supported[1] = 1;
+ }
+ if (fclose(fp) == EOF)
+ PERR_EXIT("Error in closing file");
+
+ 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_EXIT("resctrl feature not supported!");
+}
+
+void validate_bw_report_request(char *bw_report)
+{
+ if (strcmp(bw_report, "reads") == 0)
+ return;
+ if (strcmp(bw_report, "writes") == 0)
+ return;
+ if (strcmp(bw_report, "nt-writes") == 0) {
+ strcpy(bw_report, "writes");
+ return;
+ }
+ if (strcmp(bw_report, "total") == 0)
+ return;
+
+ FPRINTF_EXIT("Requested iMC B/W report type unavailable\n");
+}
+
+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;
+}
+
+void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
+{
+ kill(bm_pid, SIGKILL);
+ printf("Ending\n\n");
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
new file mode 100644
index 000000000000..1da8f871a01a
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -0,0 +1,74 @@
+/* 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 MB (1024 * 1024)
+#define RESCTRL_PATH "/sys/fs/resctrl"
+#define PHYS_ID_PATH "/sys/devices/system/cpu/cpu"
+#define RESCTRL_MBM "L3 monitoring detected"
+#define RESCTRL_MBA "MB allocation detected"
+#define MAX_RESCTRL_FEATURES 2
+#define RM_SIG_FILE "rm -rf sig"
+
+#define CHILD_EXIT(err_msg) \
+ do { \
+ perror(err_msg); \
+ ctrlc_handler(0, NULL, NULL); \
+ } while (0)
+
+#define PARENT_EXIT(err_msg) \
+ do { \
+ perror(err_msg); \
+ kill(ppid, SIGKILL); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+
+#define PERR_EXIT(err_msg) \
+ do { \
+ perror(err_msg); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+
+#define FPRINTF_EXIT(err_msg) \
+ do { \
+ fprintf(stderr, err_msg); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+
+pid_t bm_pid, ppid;
+int ben_count;
+
+void remount_resctrlfs(bool mum_resctrlfs);
+char get_sock_num(int cpu_no);
+void validate_bw_report_request(char *bw_report);
+void validate_resctrl_feature_request(char *resctrl_val);
+void taskset_benchmark(pid_t bm_pid, int cpu_no);
+void ctrlc_handler(int signum, siginfo_t *info, void *ptr);
+void run_benchmark(int signum, siginfo_t *info, void *ucontext);
+void create_mon_grp(const char *mongrp, const char *controlgroup);
+void create_con_mon_grp(const char *ctrlgrp, const char *controlgroup);
+void write_schemata(char *ctrlgrp, char *schemata, int cpu_no,
+ char *resctrl_val);
+void 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(int span, int malloc_and_init_memory, int memflush, int op);
+
+#endif /* RESCTRL_H */
--
2.5.0
From: Sai Praneeth Prakhya <[email protected]>
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 <[email protected]>
Signed-off-by: Arshiya Hayatkhan Pathan <[email protected]>
Signed-off-by: Fenghua Yu <[email protected]>
---
tools/testing/selftests/resctrl/resctrl_membw.c | 328 ++++++++++++++++++++++++
tools/testing/selftests/resctrl/resctrl_membw.h | 49 ++++
2 files changed, 377 insertions(+)
create mode 100644 tools/testing/selftests/resctrl/resctrl_membw.c
create mode 100644 tools/testing/selftests/resctrl/resctrl_membw.h
diff --git a/tools/testing/selftests/resctrl/resctrl_membw.c b/tools/testing/selftests/resctrl/resctrl_membw.c
new file mode 100644
index 000000000000..b0480834994c
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl_membw.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Memory bandwidth monitoring library
+ *
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Authors:
+ * Arshiya Hayatkhan Pathan <[email protected]>
+ * Sai Praneeth Prakhya <[email protected]>,
+ * Fenghua Yu <[email protected]>
+ */
+#include "resctrl_membw.h"
+
+static struct imc_counter_config imc_counters_config[MAX_IMCs][2];
+static char mbm_total_path[1024];
+static int imcs;
+
+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 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);
+ ctrlc_handler(0, NULL, NULL);
+
+ exit(EXIT_FAILURE);
+ }
+}
+
+void membw_ioctl_perf_event_ioc_resest_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 = malloc(MAX_TOKENS * sizeof(char *));
+ int i = 0;
+
+ strcat(cas_count_cfg, ",");
+ token[0] = malloc(10 * sizeof(char));
+ token[0] = strtok(cas_count_cfg, "=,");
+
+ for (i = 1; i < MAX_TOKENS; i++) {
+ token[i] = malloc(10 * sizeof(char));
+ token[i] = strtok(NULL, "=,");
+ if (token[i] == NULL)
+ break;
+ }
+
+ for (i = 0; i < MAX_TOKENS; i++) {
+ if (token[i] == NULL)
+ 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);
+ }
+ }
+}
+
+/* Get type and config (read and write) of an iMC counter */
+void 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 || fscanf(fp, "%u",
+ &imc_counters_config[count][READ].type) <= 0 || fclose(fp) == EOF)
+ CHILD_EXIT("Could not get imc type");
+
+ 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 || fscanf(fp, "%s", cas_count_cfg) <= 0 || fclose(fp) == EOF)
+ CHILD_EXIT("Could not get imc cas count read");
+
+ 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 || fscanf(fp, "%s", cas_count_cfg) <= 0 || fclose(fp) == EOF)
+ CHILD_EXIT("Could not get imc cas count write");
+
+ get_event_and_umask(cas_count_cfg, count, WRITE);
+}
+
+/*
+ * 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.
+ */
+static int num_of_imcs(void)
+{
+ char imc_dir[1024];
+ struct dirent *ep;
+ unsigned int count = 0;
+ DIR *dp;
+
+ dp = opendir(DYN_PMU_PATH);
+ if (dp != NULL) {
+ while ((ep = readdir(dp)) != NULL) {
+ if (strstr(ep->d_name, UNCORE_IMC) != NULL) {
+ sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH,
+ ep->d_name);
+ read_from_imc_dir(imc_dir, count);
+ count++;
+ }
+ }
+ closedir(dp);
+ if (count == 0)
+ CHILD_EXIT("Unable find iMC counters!\n");
+ } else {
+ CHILD_EXIT("Unable to open PMU directory!\n");
+ }
+
+ return count;
+}
+
+void initialize_mem_bw_imc(void)
+{
+ int imc;
+
+ imcs = num_of_imcs();
+
+ /* Initialize perf_event_attr structures for all iMC's */
+ for (imc = 0; imc < imcs; imc++) {
+ for (int j = 0; j < 2; j++)
+ membw_initialize_perf_event_attr(imc, j);
+ }
+}
+
+/*
+ * 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.
+ */
+float get_mem_bw_imc(int cpu_no, char *bw_report)
+{
+ float reads, writes, of_mul_read, of_mul_write;
+ int imc;
+
+ /* 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 (int j = 0; j < 2; j++)
+ open_perf_event(imc, cpu_no, j);
+ for (int j = 0; j < 2; j++)
+ membw_ioctl_perf_event_ioc_resest_enable(imc, j);
+ }
+
+ sleep(1);
+
+ /* Stop counters after a second to get results (both read and write) */
+ for (imc = 0; imc < imcs; imc++) {
+ for (int 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)
+ CHILD_EXIT("Couldn't get read b/w through iMC");
+
+ if (read(w->fd, &w->return_value,
+ sizeof(struct membw_read_format)) == -1)
+ CHILD_EXIT("Couldn't get write bw through iMC");
+
+ __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, char sock_num)
+{
+ if (ctrlgrp && mongrp)
+ sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH,
+ RESCTRL_PATH, ctrlgrp, mongrp, sock_num);
+ else if (!ctrlgrp && mongrp)
+ sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
+ mongrp, sock_num);
+ else if (ctrlgrp && !mongrp)
+ sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
+ ctrlgrp, sock_num);
+ else if (!ctrlgrp && !mongrp)
+ sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
+ sock_num);
+
+}
+
+/*
+ * 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)
+ */
+void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp,
+ int cpu_no, char *resctrl_val)
+{
+ char sock_num;
+
+ sock_num = get_sock_num(cpu_no);
+
+ if (strcmp(resctrl_val, "mbm") == 0)
+ set_mbm_path(ctrlgrp, mongrp, sock_num);
+
+ if ((strcmp(resctrl_val, "mba") == 0)) {
+ if (ctrlgrp)
+ sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH,
+ RESCTRL_PATH, ctrlgrp, sock_num);
+ else
+ sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH,
+ RESCTRL_PATH, sock_num);
+ }
+}
+
+/*
+ * 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
+ */
+unsigned long long get_mem_bw_resctrl(void)
+{
+ unsigned long long mbm_total = 0;
+ FILE *fp;
+
+ fp = fopen(mbm_total_path, "r");
+ if (!fp || fscanf(fp, "%llu", &mbm_total) <= 0 || fclose(fp) == EOF)
+ CHILD_EXIT("Could not get mbm local bytes");
+
+ return mbm_total;
+}
diff --git a/tools/testing/selftests/resctrl/resctrl_membw.h b/tools/testing/selftests/resctrl/resctrl_membw.h
new file mode 100644
index 000000000000..87ec585b8dd4
--- /dev/null
+++ b/tools/testing/selftests/resctrl/resctrl_membw.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef RESCTRL_MEMBW_H
+#define RESCTRL_MEMBW_H
+#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_0%c/mbm_local_bytes"
+
+#define CON_MBM_LOCAL_BYTES_PATH \
+ "%s/%s/mon_data/mon_L3_0%c/mbm_local_bytes"
+
+#define MON_MBM_LOCAL_BYTES_PATH \
+ "%s/mon_groups/%s/mon_data/mon_L3_0%c/mbm_local_bytes"
+
+#define MBM_LOCAL_BYTES_PATH \
+ "%s/mon_data/mon_L3_0%c/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;
+};
+
+void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp,
+ int cpu_no, char *resctrl_val);
+float get_mem_bw_imc(int cpu_no, char *bw_report);
+unsigned long long get_mem_bw_resctrl(void);
+void initialize_mem_bw_imc(void);
+#endif /* RESCTRL_MEMBW_H */
--
2.5.0
Hi Fenghua,
On 10/16/2018 11:56 AM, 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.
I like the initiative here. It is always good to have a single code base.
One question. I see that there is a tool at
https://github.com/intel/intel-cmt-cat to test and verify the
functionality of resctrl feature. I also see some of the distros have this
tool already. Is this tool going to replace intel-cmt-cat? I have not
looked at the patches closely yet.
>
> We introduce resctrl selftest to cover resctrl features on both
> X86 and ARM architectures. It first implements MBM (Memory Bandwidth
> Monitoring) and MBA (Memory Bandwidth Allocation) tests. We can enhance
> the selftest tool to include more functionality tests in future.
>
> The tests are in tools/testing/selftests/resctrl in order to have
> generic test code for all architectures.
>
> Arshiya Hayatkhan Pathan (2):
> selftests/resctrl: Add mbm test
> selftests/resctrl: Add mba test
>
> Fenghua Yu (1):
> 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/fill_buf.c | 178 ++++++++++++
> tools/testing/selftests/resctrl/mba.c | 144 ++++++++++
> tools/testing/selftests/resctrl/mbm.c | 113 ++++++++
> tools/testing/selftests/resctrl/resctrl.c | 367 ++++++++++++++++++++++++
> tools/testing/selftests/resctrl/resctrl.h | 107 +++++++
> tools/testing/selftests/resctrl/resctrl_membw.c | 328 +++++++++++++++++++++
> tools/testing/selftests/resctrl/resctrl_membw.h | 49 ++++
> tools/testing/selftests/resctrl/resctrl_tests.c | 104 +++++++
> tools/testing/selftests/resctrl/resctrl_val.c | 192 +++++++++++++
> 11 files changed, 1599 insertions(+)
> create mode 100644 tools/testing/selftests/resctrl/Makefile
> create mode 100644 tools/testing/selftests/resctrl/fill_buf.c
> create mode 100644 tools/testing/selftests/resctrl/mba.c
> create mode 100644 tools/testing/selftests/resctrl/mbm.c
> create mode 100644 tools/testing/selftests/resctrl/resctrl.c
> create mode 100644 tools/testing/selftests/resctrl/resctrl.h
> create mode 100644 tools/testing/selftests/resctrl/resctrl_membw.c
> create mode 100644 tools/testing/selftests/resctrl/resctrl_membw.h
> create mode 100644 tools/testing/selftests/resctrl/resctrl_tests.c
> create mode 100644 tools/testing/selftests/resctrl/resctrl_val.c
>
> From: Moger, Babu [mailto:[email protected]]
> On 10/16/2018 11:56 AM, 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.
>
> I like the initiative here. It is always good to have a single code base.
>
> One question. I see that there is a tool at https://github.com/intel/intel-cmt-cat to test and verify the functionality of resctrl feature. I also see some of the distros have this tool already.
> Is this tool going to replace intel-cmt-cat? I have not looked at the
> patches closely yet.
No, the selftest in this patch set will not replace intel-cmt-cat or
vice versa.
The selftest in this patch set has a different purpose from intel-cmt-cat:
the selftest is a test tool which validates resctrl functionalities while
intel-cmt-cat is mainly a utility that provides base library for higher
level applications including performance analysis tools, benchmark measurement
tools, and potential resctrl tests. For example, running MBA test in the
selftests tells MBA working or not working (fail/pass) right way. The
intel-cmt-cat doesn't have this testing capability unless we extend the
tool.
And intel-cmt-cat is maintained and developed by Intel. I don't think it's
easy to extend it to AMD and ARM features. The selftest will be maintained
and developed by the community and will hopefully cover all architectures.
We have seen a few issues recently in resctrl and may see more issues
while expending the features. A convevient selftest may be useful to help
identify and fix those potential issues.
Thanks.
-Fenghua
On 10/16/2018 03:32 PM, Fenghua Yu wrote:
>> From: Moger, Babu [mailto:[email protected]]
>> On 10/16/2018 11:56 AM, 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.
>>
>> I like the initiative here. It is always good to have a single code base.
>>
>> One question. I see that there is a tool at https://github.com/intel/intel-cmt-cat to test and verify the functionality of resctrl feature. I also see some of the distros have this tool already.
>> Is this tool going to replace intel-cmt-cat? I have not looked at the
>> patches closely yet.
>
> No, the selftest in this patch set will not replace intel-cmt-cat or
> vice versa.
>
> The selftest in this patch set has a different purpose from intel-cmt-cat:
> the selftest is a test tool which validates resctrl functionalities while
> intel-cmt-cat is mainly a utility that provides base library for higher
> level applications including performance analysis tools, benchmark measurement
> tools, and potential resctrl tests. For example, running MBA test in the
> selftests tells MBA working or not working (fail/pass) right way. The
Ok. Sure. Let me take a look at selftest closely. Will send my feedback soon.
> intel-cmt-cat doesn't have this testing capability unless we extend the
> tool.
>
> And intel-cmt-cat is maintained and developed by Intel. I don't think it's
> easy to extend it to AMD and ARM features. The selftest will be maintained
We1l.. We were hoping to have a common tool across. It makes it easy for
distros. Probably, we can have a separate discussion on this.
> and developed by the community and will hopefully cover all architectures.
>
> We have seen a few issues recently in resctrl and may see more issues
> while expending the features. A convevient selftest may be useful to help
> identify and fix those potential issues.
>
> Thanks.
>
> -Fenghua
>
>
> > No, the selftest in this patch set will not replace intel-cmt-cat or
> > vice versa.
> >
> > The selftest in this patch set has a different purpose from intel-cmt-cat:
> > the selftest is a test tool which validates resctrl functionalities
> > while intel-cmt-cat is mainly a utility that provides base library for
> > higher level applications including performance analysis tools,
> > benchmark measurement tools, and potential resctrl tests. For example,
> > running MBA test in the selftests tells MBA working or not working
> > (fail/pass) right way. The
>
> Ok. Sure. Let me take a look at selftest closely. Will send my feedback soon.
Great!
>
> > intel-cmt-cat doesn't have this testing capability unless we extend
> > the tool.
> >
> > And intel-cmt-cat is maintained and developed by Intel. I don't think
> > it's easy to extend it to AMD and ARM features. The selftest will be
> > maintained
>
> We1l.. We were hoping to have a common tool across. It makes it easy for
> distros. Probably, we can have a separate discussion on this.
>
The main goal of this test suite is to validate values reported by resctrl features
i.e. we need _some_way_ to check if values reported by resctrl features are
correct or not.
For (Intel) Memory Bandwidth features like MBA and MBM, perf iMC
(Integrated Memory Controller) is used for validation. As a part of test, we run a
benchmark (eg: fill_buf) and get memory bandwidth values from MBM and iMC
and verify if the difference between both the reported values are in a reasonable range.
To make this common across x86, could you please let us know if similar things
(i.e. perf iMC) exist on AMD? If so, you could add it in. The same applies for ARM.
Regards,
Sai
Hi Fenghua,
My few comments.
On 10/17/2018 09:40 AM, Moger, Babu wrote:
>
>
> On 10/16/2018 03:32 PM, Fenghua Yu wrote:
>>> From: Moger, Babu [mailto:[email protected]]
>>> On 10/16/2018 11:56 AM, 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.
>>>
>>> I like the initiative here. It is always good to have a single code base.
>>>
>>> One question. I see that there is a tool at https://github.com/intel/intel-cmt-cat to test and verify the functionality of resctrl feature. I also see some of the distros have this tool already.
>>> Is this tool going to replace intel-cmt-cat? I have not looked at the
>>> patches closely yet.
>>
>> No, the selftest in this patch set will not replace intel-cmt-cat or
>> vice versa.
>>
>> The selftest in this patch set has a different purpose from intel-cmt-cat:
>> the selftest is a test tool which validates resctrl functionalities while
>> intel-cmt-cat is mainly a utility that provides base library for higher
>> level applications including performance analysis tools, benchmark measurement
>> tools, and potential resctrl tests. For example, running MBA test in the
>> selftests tells MBA working or not working (fail/pass) right way. The
>
> Ok. Sure. Let me take a look at selftest closely. Will send my feedback soon.
>
>> intel-cmt-cat doesn't have this testing capability unless we extend the
>> tool.
>>
>> And intel-cmt-cat is maintained and developed by Intel. I don't think it's
>> easy to extend it to AMD and ARM features. The selftest will be maintained
>
> We1l.. We were hoping to have a common tool across. It makes it easy for
> distros. Probably, we can have a separate discussion on this.
>
>> and developed by the community and will hopefully cover all architectures.
>>
>> We have seen a few issues recently in resctrl and may see more issues
>> while expending the features. A convevient selftest may be useful to help
>> identify and fix those potential issues.
I don't know the rules for selftest. Here are my general comments.
1. File names are not consistent.
# ls *.c
fill_buf.c mba.c mbm.c resctrl.c resctrl_membw.c resctrl_tests.c
Few files start with resctrl_ prefix and others don't.
2. Do we need README(or USAGE) here? I had too
3. I saw lots of these errors.
"mba.c:111:2: error: ‘for’ loop initial declarations are only allowed
in C99 mode"
for (int i = 0; i < 10; i++) {
^
I had to change it to
int i;
for (i = 0; i < 10; i++) {
>>
>> Thanks.
>>
>> -Fenghua
>>
>>
On 10/17/2018 01:03 PM, Moger, Babu wrote:
> Hi Fenghua,
> My few comments.
>
> On 10/17/2018 09:40 AM, Moger, Babu wrote:
>>
>>
>> On 10/16/2018 03:32 PM, Fenghua Yu wrote:
>>>> From: Moger, Babu [mailto:[email protected]]
>>>> On 10/16/2018 11:56 AM, 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.
>>>>
>>>> I like the initiative here. It is always good to have a single code base.
>>>>
>>>> One question. I see that there is a tool at https://github.com/intel/intel-cmt-cat to test and verify the functionality of resctrl feature. I also see some of the distros have this tool already.
>>>> Is this tool going to replace intel-cmt-cat? I have not looked at the
>>>> patches closely yet.
>>>
>>> No, the selftest in this patch set will not replace intel-cmt-cat or
>>> vice versa.
>>>
>>> The selftest in this patch set has a different purpose from intel-cmt-cat:
>>> the selftest is a test tool which validates resctrl functionalities while
>>> intel-cmt-cat is mainly a utility that provides base library for higher
>>> level applications including performance analysis tools, benchmark measurement
>>> tools, and potential resctrl tests. For example, running MBA test in the
>>> selftests tells MBA working or not working (fail/pass) right way. The
>>
>> Ok. Sure. Let me take a look at selftest closely. Will send my feedback soon.
>>
>>> intel-cmt-cat doesn't have this testing capability unless we extend the
>>> tool.
>>>
>>> And intel-cmt-cat is maintained and developed by Intel. I don't think it's
>>> easy to extend it to AMD and ARM features. The selftest will be maintained
>>
>> We1l.. We were hoping to have a common tool across. It makes it easy for
>> distros. Probably, we can have a separate discussion on this.
>>
>>> and developed by the community and will hopefully cover all architectures.
>>>
>>> We have seen a few issues recently in resctrl and may see more issues
>>> while expending the features. A convevient selftest may be useful to help
>>> identify and fix those potential issues.
>
> I don't know the rules for selftest. Here are my general comments.
>
> 1. File names are not consistent.
> # ls *.c
> fill_buf.c mba.c mbm.c resctrl.c resctrl_membw.c resctrl_tests.c
> Few files start with resctrl_ prefix and others don't.
>
> 2. Do we need README(or USAGE) here? I had too
>
Correction..
2. Do we need README(or USAGE) here? I had too look at the code to check
on "usage options" to run this utility.
> 3. I saw lots of these errors.
> "mba.c:111:2: error: ‘for’ loop initial declarations are only allowed
> in C99 mode"
> for (int i = 0; i < 10; i++) {
> ^
>
> I had to change it to
> int i;
> for (i = 0; i < 10; i++) {
>
>
>
>>>
>>> Thanks.
>>>
>>> -Fenghua
>>>
>>>
On 10/17/2018 12:28 PM, Prakhya, Sai Praneeth wrote:
>>> No, the selftest in this patch set will not replace intel-cmt-cat or
>>> vice versa.
>>>
>>> The selftest in this patch set has a different purpose from intel-cmt-cat:
>>> the selftest is a test tool which validates resctrl functionalities
>>> while intel-cmt-cat is mainly a utility that provides base library for
>>> higher level applications including performance analysis tools,
>>> benchmark measurement tools, and potential resctrl tests. For example,
>>> running MBA test in the selftests tells MBA working or not working
>>> (fail/pass) right way. The
>>
>> Ok. Sure. Let me take a look at selftest closely. Will send my feedback soon.
>
> Great!
>
>>
>>> intel-cmt-cat doesn't have this testing capability unless we extend
>>> the tool.
>>>
>>> And intel-cmt-cat is maintained and developed by Intel. I don't think
>>> it's easy to extend it to AMD and ARM features. The selftest will be
>>> maintained
>>
>> We1l.. We were hoping to have a common tool across. It makes it easy for
>> distros. Probably, we can have a separate discussion on this.
>>
>
> The main goal of this test suite is to validate values reported by resctrl features
> i.e. we need _some_way_ to check if values reported by resctrl features are
> correct or not.
>
> For (Intel) Memory Bandwidth features like MBA and MBM, perf iMC
> (Integrated Memory Controller) is used for validation. As a part of test, we run a
> benchmark (eg: fill_buf) and get memory bandwidth values from MBM and iMC
> and verify if the difference between both the reported values are in a reasonable range.
>
> To make this common across x86, could you please let us know if similar things
> (i.e. perf iMC) exist on AMD? If so, you could add it in. The same applies for ARM.
We dont have iMC. You can go ahead with what you have right now. We can
add those details later if required.
>
> Regards,
> Sai
>
> > For (Intel) Memory Bandwidth features like MBA and MBM, perf iMC
> > (Integrated Memory Controller) is used for validation. As a part of
> > test, we run a benchmark (eg: fill_buf) and get memory bandwidth
> > values from MBM and iMC and verify if the difference between both the
> reported values are in a reasonable range.
> >
> > To make this common across x86, could you please let us know if
> > similar things (i.e. perf iMC) exist on AMD? If so, you could add it in. The same
> applies for ARM.
>
> We dont have iMC. You can go ahead with what you have right now. We can
> add those details later if required.
Sure! Makes sense to me.
Regards,
Sai
On Wed, Oct 17, 2018 at 11:04 AM Moger, Babu <[email protected]> wrote:
>
> Hi Fenghua,
> My few comments.
>
> On 10/17/2018 09:40 AM, Moger, Babu wrote:
> > On 10/16/2018 03:32 PM, Fenghua Yu wrote:
> >>> From: Moger, Babu [mailto:[email protected]]
> >>> On 10/16/2018 11:56 AM, 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.
> >>>
> >>> I like the initiative here. It is always good to have a single code
> base.
> >>>
> >>> One question. I see that there is a tool at https://github.com/intel/
> intel-cmt-cat to test and verify the functionality of resctrl feature. I
> also see some of the distros have this tool already.
> >>> Is this tool going to replace intel-cmt-cat? I have not looked at the
> >>> patches closely yet.
> >>
> >> No, the selftest in this patch set will not replace intel-cmt-cat or
> >> vice versa.
> >>
> >> The selftest in this patch set has a different purpose from
> intel-cmt-cat:
> >> the selftest is a test tool which validates resctrl functionalities
> while
> >> intel-cmt-cat is mainly a utility that provides base library for higher
> >> level applications including performance analysis tools, benchmark
> measurement
> >> tools, and potential resctrl tests. For example, running MBA test in the
> >> selftests tells MBA working or not working (fail/pass) right way. The
> >
> > Ok. Sure. Let me take a look at selftest closely. Will send my feedback
> soon.
Thanks.
> >
> >> intel-cmt-cat doesn't have this testing capability unless we extend the
> >> tool.
> >>
> >> And intel-cmt-cat is maintained and developed by Intel. I don't think
> it's
> >> easy to extend it to AMD and ARM features. The selftest will be
> maintained
> >
> > We1l.. We were hoping to have a common tool across. It makes it easy for
> > distros. Probably, we can have a separate discussion on this.
> >
> >> and developed by the community and will hopefully cover all
> architectures.
> >>
> >> We have seen a few issues recently in resctrl and may see more issues
> >> while expending the features. A convevient selftest may be useful to
> help
> >> identify and fix those potential issues.
>
> I don't know the rules for selftest. Here are my general comments.
>
> 1. File names are not consistent.
> # ls *.c
> fill_buf.c mba.c mbm.c resctrl.c resctrl_membw.c resctrl_tests.c
> Few files start with resctrl_ prefix and others don't.
All files are in resctrl directory. It's redundant to have resctrl prefix for
each file. Probably we will remove the resctrl prefix for all files to
keep uniform naming style.
>
> 2. Do we need README(or USAGE) here? I had too
We can add that in next version.
>
> 3. I saw lots of these errors.
> "mba.c:111:2: error: ‘for’ loop initial declarations are only allowed
> in C99 mode"
> for (int i = 0; i < 10; i++) {
> ^
>
> I had to change it to
> int i;
> for (i = 0; i < 10; i++) {
Will fix the issues.
Thanks.
-Fenghua