mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
linux_kselftest-next-7.4-rc1
- Improves selftest build, run-time, and install framework
Installs even when some modules fail to build, prints summary of test
results at the end of the default test run, keeps the build status from
wrapping to success so build errors are reported, and optionally records
per-suite build and install results:
selftests: lib.mk: Don't fail install if no modules were built
selftests/lib.mk: run_tests: print summary at the end
selftests: keep the build status from wrapping to success
selftests: optionally record per-suite build and install results
- Adds LLVM support to kselftest_deps.sh
selftests: kselftest_deps.sh: Support LLVM
- Fixes resctrl, breakpoints suspend, ftrace, and tracing tests
selftests/resctrl: Skip L3_CAT when no exclusive cache portion exists
selftests: breakpoints: Skip step_after_suspend_test on systems
without a wakeup capable RTC
selftests/ftrace: skip gcov symbols when picking a function to probe
selftests/ftrace: Avoid unlink error on first run
selftests/ftrace: Add nice dependency
tracing/selftests: Fix incorrect invocation of exit_fail
- Fixes and enhances resctrl test use link lists to manage IMC counters
selftests/resctrl: Introduce linked list management for IMC counters
selftests/resctrl: Replace counter index references with pointers
selftests/resctrl: Enable dynamic management of IMC counters via
linked list
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmrZDRoACgkQCwJExA0N
QxxwoA//T7z5ozQJpPGxmfN6+rQK1pGSrEo6oXj/TgvfD9VYDR4/niM6lJJhpHs7
9nvm9K/whi2Rt/A2GKAwtjp12iWlZVUS0G/d1PW2RJCKT0PceXiZDoxXWXHL8IfC
qgzVimuqkbwrblXRb/NHJrTc7Ci5a6PM9XLVyO5IEWqOmJO0iZbZTKR/rxnFis9K
Ur+rBFf6o0/yu3Yt+gStl9VqU04GpRkYmGoXGm4PH1yt5MHaEs4ieuO7+3GvVpxp
UtiheJRJACPpL6EFaBNFpaR8UYfoTtQnl7g/8pk4bQlNkQBeH7/YjJ9ycxQqWV/6
BrDqiu9m0WmWMH3Sg55AQQHbqX9+pOet1VVDsJIA80/qtnutd4hEn+zNnjKjNPMp
31XYiOSJSoPmjB5OxUzjEPQSgdcV4IfOnh6+LELWQcPjZaNRxj5DHQHUP6yugkNZ
FL1tDknF0+xppUHiAhIZiexOd5RxgkcFYRtD+V9T2K0Q2P6+ntxjR34iBgj+rFpb
e3sk4K0l1VNMPfBdpLTPpvP8pSKFlHzmR4OWkbtSaSv0x6jdTs88XcB+igxEEVvQ
AXl6t+BNU4kKB9Jr5IL5n4QxvlAC6DGLNQUbYSuhVooQ4hAEbefxs1JHRWgRXpmT
a3zDBHoJjxtPo+TWflz35eBN4eJkWjfljWRmkbSmN9ZURW81p08=
=bdqO
-----END PGP SIGNATURE-----
Merge tag 'linux_kselftest-next-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull kselftest updates from Shuah Khan:
- Improve selftest build, run-time, and install framework
Install even when some modules fail to build, print summary of test
results at the end of the default test run, keep the build status
from wrapping to success so build errors are reported, and optionally
record per-suite build and install results.
- Add LLVM support to kselftest_deps.sh
- Fix resctrl, breakpoints suspend, ftrace, and tracing tests
- Fix and enhance resctrl test
* tag 'linux_kselftest-next-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
selftests: breakpoints: Skip step_after_suspend_test on systems without a wakeup capable RTC
selftests: optionally record per-suite build and install results
selftests: keep the build status from wrapping to success
selftests/ftrace: Add nice dependency
selftests: kselftest_deps.sh: Support LLVM
selftests: lib.mk: Don't fail install if no modules were built
selftests/ftrace: Avoid unlink error on first run
tracing/selftests: Fix incorrect invocation of exit_fail
selftests/lib.mk: run_tests: print summary at the end
selftests/ftrace: skip gcov symbols when picking a function to probe
selftests/resctrl: Enable dynamic management of IMC counters via linked list
selftests/resctrl: Replace counter index references with pointers
selftests/resctrl: Introduce linked list management for IMC counters
selftests/resctrl: Skip L3_CAT when no exclusive cache portion exists
This commit is contained in:
commit
968de9d179
|
|
@ -133,6 +133,44 @@ build successfully; make will abort as soon as any target fails::
|
|||
This applies to both the ``all`` and ``install`` targets and is useful in
|
||||
CI environments where a silent partial build would be misleading.
|
||||
|
||||
Recording suite build results
|
||||
=============================
|
||||
|
||||
Since the build succeeds as long as one target builds, the exit status of
|
||||
make does not show which targets failed. Set ``KSFT_BUILD_REPORT`` to the
|
||||
absolute path of a file to have the ``all`` and ``install`` targets append
|
||||
a tab-separated record for each target they process::
|
||||
|
||||
$ : > /tmp/ksft-build.tsv
|
||||
$ make -C tools/testing/selftests O=/tmp/kernel-build \
|
||||
KSFT_BUILD_REPORT=/tmp/ksft-build.tsv install
|
||||
|
||||
Each record holds the phase (``all`` or ``install``), a name and the exit
|
||||
status of that step. Recording does not change which targets are built or
|
||||
installed, or the exit status of make, also with ``FORCE_TARGETS=1``. The
|
||||
caller creates or truncates the report before a build; the rules only
|
||||
append to it. Nothing is recorded by ``make -n``, ``-t`` or ``-q``.
|
||||
|
||||
The same name can appear several times: ``install`` builds the targets
|
||||
again, and generating ``kselftest-list.txt`` is recorded as part of the
|
||||
``install`` phase. Targets that are added automatically as installation
|
||||
dependencies of other targets, such as ``net/lib``, are recorded too.
|
||||
Suites that are built from several subdirectories may also record each
|
||||
subdirectory under its path, for example ``arm64/tags``; a failure there
|
||||
means that the suite was built or installed only partially. A record
|
||||
belongs to the target with the longest name that is equal to the record
|
||||
name or followed by ``/`` in it.
|
||||
|
||||
A target was built and installed successfully only if all of its records
|
||||
have a zero status. Missing records do not show that a target was built.
|
||||
A successful target that installs no tests has no entries in
|
||||
``kselftest-list.txt``. Install the kernel headers with ``make headers``
|
||||
before building: a suite that fails because the headers are missing is
|
||||
recorded as failed even if a later step installs them.
|
||||
|
||||
``KSFT_BUILD_REPORT_VERSION`` in tools/testing/selftests/Makefile gives the
|
||||
version of this format, currently ``1``.
|
||||
|
||||
Running the full range hotplug selftests
|
||||
========================================
|
||||
|
||||
|
|
|
|||
|
|
@ -178,6 +178,10 @@ endif
|
|||
# of the targets gets built.
|
||||
FORCE_TARGETS ?=
|
||||
|
||||
# Remember dry runs for the build report before MAKEFLAGS may be cleared.
|
||||
KSFT_BUILD_REPORT_DRY_RUN := $(strip $(foreach f,n t q,$(findstring $(f),$(firstword -$(MAKEFLAGS)))))
|
||||
export KSFT_BUILD_REPORT_DRY_RUN
|
||||
|
||||
# Clear LDFLAGS and MAKEFLAGS when implicit rules are missing. This provides
|
||||
# implicit rules to sub-test Makefiles which avoids build failures in test
|
||||
# Makefile that don't have explicit build rules.
|
||||
|
|
@ -222,6 +226,10 @@ ARCH ?= $(SUBARCH)
|
|||
export BUILD
|
||||
export KHDR_INCLUDES
|
||||
|
||||
# Version of the optional KSFT_BUILD_REPORT format written by these rules.
|
||||
KSFT_BUILD_REPORT_VERSION := 1
|
||||
include $(top_srcdir)/tools/testing/selftests/build_report.mk
|
||||
|
||||
# set default goal to all, so make without a target runs all, even when
|
||||
# all isn't the first target in the file.
|
||||
.DEFAULT_GOAL := all
|
||||
|
|
@ -230,11 +238,13 @@ all:
|
|||
@ret=1; \
|
||||
for TARGET in $(TARGETS) $(INSTALL_DEP_TARGETS); do \
|
||||
BUILD_TARGET=$$BUILD/$$TARGET; \
|
||||
mkdir $$BUILD_TARGET -p; \
|
||||
mkdir -p $$BUILD_TARGET && \
|
||||
$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET \
|
||||
O=$(abs_objtree) \
|
||||
$(if $(FORCE_TARGETS),|| exit); \
|
||||
ret=$$((ret * $$?)); \
|
||||
O=$(abs_objtree); \
|
||||
status=$$?; \
|
||||
$(call ksft_record_build_status,all,$$TARGET); \
|
||||
$(if $(FORCE_TARGETS),[ $$status -eq 0 ] || exit $$status;) \
|
||||
[ $$status -eq 0 ] && ret=0; \
|
||||
done; exit $$ret;
|
||||
|
||||
run_tests: all
|
||||
|
|
@ -291,7 +301,7 @@ ifdef INSTALL_PATH
|
|||
install -m 744 kselftest/ktap_helpers.sh $(INSTALL_PATH)/kselftest/
|
||||
install -m 744 kselftest/ksft.py $(INSTALL_PATH)/kselftest/
|
||||
install -m 744 run_kselftest.sh $(INSTALL_PATH)/
|
||||
rm -f $(TEST_LIST)
|
||||
: > $(TEST_LIST)
|
||||
@ret=1; \
|
||||
for TARGET in $(TARGETS) $(INSTALL_DEP_TARGETS); do \
|
||||
BUILD_TARGET=$$BUILD/$$TARGET; \
|
||||
|
|
@ -299,9 +309,11 @@ ifdef INSTALL_PATH
|
|||
INSTALL_PATH=$(INSTALL_PATH)/$$TARGET \
|
||||
SRC_PATH=$(shell readlink -e $$(pwd)) \
|
||||
OBJ_PATH=$(INSTALL_PATH) \
|
||||
O=$(abs_objtree) \
|
||||
$(if $(FORCE_TARGETS),|| exit); \
|
||||
ret=$$((ret * $$?)); \
|
||||
O=$(abs_objtree); \
|
||||
status=$$?; \
|
||||
$(call ksft_record_build_status,install,$$TARGET); \
|
||||
$(if $(FORCE_TARGETS),[ $$status -eq 0 ] || exit $$status;) \
|
||||
[ $$status -eq 0 ] && ret=0; \
|
||||
done; exit $$ret;
|
||||
|
||||
|
||||
|
|
@ -315,6 +327,9 @@ ifdef INSTALL_PATH
|
|||
printf "Emit Tests for $$TARGET\n"; \
|
||||
$(MAKE) -s --no-print-directory OUTPUT=$$BUILD_TARGET COLLECTION=$$TARGET \
|
||||
-C $$TARGET emit_tests >> $(TEST_LIST); \
|
||||
status=$$?; \
|
||||
$(call ksft_record_build_status,install,$$TARGET); \
|
||||
(exit $$status); \
|
||||
done;
|
||||
@VERSION=$$(git describe HEAD 2>/dev/null); \
|
||||
if [ -n "$$VERSION" ]; then \
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <sys/timerfd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "kselftest.h"
|
||||
|
||||
|
|
@ -158,11 +159,21 @@ void suspend(void)
|
|||
int err;
|
||||
int count_before;
|
||||
int count_after;
|
||||
struct timespec res;
|
||||
struct itimerspec spec = {};
|
||||
|
||||
if (getuid() != 0)
|
||||
ksft_exit_skip("Please run the test as root - Exiting.\n");
|
||||
|
||||
/*
|
||||
* CLOCK_BOOTTIME_ALARM cannot wake up systems that don't have a
|
||||
* wakeup capable RTC from suspend. Check if we have a wakeup-capable
|
||||
* RTC to prevent this test from causing the system to hang after
|
||||
* it suspends.
|
||||
*/
|
||||
if (clock_getres(CLOCK_BOOTTIME_ALARM, &res) != 0)
|
||||
ksft_exit_skip("No wakeup-capable RTC for CLOCK_BOOTTIME_ALARM\n");
|
||||
|
||||
timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
|
||||
if (timerfd < 0)
|
||||
ksft_exit_fail_msg("timerfd_create() failed\n");
|
||||
|
|
|
|||
26
tools/testing/selftests/build_report.mk
Normal file
26
tools/testing/selftests/build_report.mk
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Optional per-suite build report, see "Recording suite build results" in
|
||||
# Documentation/dev-tools/kselftest.rst. Callers set KSFT_BUILD_REPORT to an
|
||||
# absolute filename and use ksft_record_build_status from a shell loop that
|
||||
# has stored the exit status of the recorded step in $status.
|
||||
|
||||
ifneq (x$(KSFT_BUILD_REPORT)x,xx)
|
||||
ifeq ($(filter x/%,$(firstword x$(KSFT_BUILD_REPORT))),)
|
||||
$(error KSFT_BUILD_REPORT must be an absolute path: '$(KSFT_BUILD_REPORT)')
|
||||
endif
|
||||
endif
|
||||
export KSFT_BUILD_REPORT
|
||||
|
||||
ksft_build_report_dry_run := $(KSFT_BUILD_REPORT_DRY_RUN) \
|
||||
$(foreach f,n t q,$(findstring $(f),$(firstword -$(MAKEFLAGS))))
|
||||
|
||||
ifneq ($(strip $(ksft_build_report_dry_run)),)
|
||||
ksft_record_build_status = :
|
||||
else
|
||||
define ksft_record_build_status
|
||||
if [ -n "$$KSFT_BUILD_REPORT" ]; then \
|
||||
printf '%s\t%s\t%d\n' '$(1)' "$(2)" "$$status" >> "$$KSFT_BUILD_REPORT" || exit 1; \
|
||||
fi
|
||||
endef
|
||||
endif
|
||||
|
|
@ -243,7 +243,7 @@ else
|
|||
mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR"
|
||||
date > $LOG_FILE
|
||||
if [ "x-$LINK_PTR" != "x-" ]; then
|
||||
unlink $LINK_PTR
|
||||
rm -f $LINK_PTR
|
||||
ln -fs $LOG_DATE $LINK_PTR
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ test_buffer() {
|
|||
# the size must be greater than or equal to page_size - data_offset
|
||||
page_size=$((page_size-data_offset))
|
||||
if [ $size -lt $page_size ]; then
|
||||
exit fail
|
||||
exit_fail
|
||||
fi
|
||||
|
||||
# Now add a little more the meta data overhead will overflow
|
||||
|
|
@ -71,14 +71,14 @@ test_buffer() {
|
|||
new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; exit}' trace`
|
||||
|
||||
if [ "$new_str" = "$str" ]; then
|
||||
exit fail;
|
||||
exit_fail
|
||||
fi
|
||||
|
||||
# Make sure the entire line can be found
|
||||
new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; }' trace`
|
||||
|
||||
if [ "$new_str" != "$str" ]; then
|
||||
exit fail;
|
||||
exit_fail
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ test_buffer() {
|
|||
new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; exit}' trace`
|
||||
|
||||
if [ "$new_str" = "$str" ]; then
|
||||
exit fail;
|
||||
exit_fail
|
||||
fi
|
||||
|
||||
# Make sure the entire line can be found
|
||||
new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; }' trace`
|
||||
|
||||
if [ "$new_str" != "$str" ]; then
|
||||
exit fail;
|
||||
exit_fail
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
:;: "Add an event on function without name" ;:
|
||||
|
||||
FUNC=`grep " [tT] .*vfs_read$" /proc/kallsyms | tail -n 1 | cut -f 3 -d " "`
|
||||
FUNC=`grep " [tT] .*vfs_read$" /proc/kallsyms | grep -v __gcov | tail -n 1 | cut -f 3 -d " "`
|
||||
[ "x" != "x$FUNC" ] || exit_unresolved
|
||||
echo "p $FUNC" > kprobe_events
|
||||
PROBE_NAME=`echo $FUNC | tr ".:" "_"`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# description: event trigger - test inter-event histogram trigger onchange action
|
||||
# requires: set_event "onchange(var)":README ping:program
|
||||
# requires: set_event "onchange(var)":README ping:program nice:program
|
||||
# flags: instance
|
||||
|
||||
fail() { #msg
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# description: event trigger - test inter-event histogram trigger snapshot action
|
||||
# requires: set_event snapshot events/sched/sched_process_fork/hist "onchange(var)":README "snapshot()":README ping:program
|
||||
# requires: set_event snapshot events/sched/sched_process_fork/hist "onchange(var)":README "snapshot()":README ping:program nice:program
|
||||
# flags: instance
|
||||
|
||||
fail() { #msg
|
||||
|
|
|
|||
|
|
@ -10,13 +10,20 @@
|
|||
usage()
|
||||
{
|
||||
|
||||
echo -e "Usage: $0 -[p] <compiler> [test_name]\n"
|
||||
echo -e "Usage: $0 -[p] <compiler> [ARCH=<arch>] [test_name]\n"
|
||||
echo -e "\tkselftest_deps.sh [-p] gcc"
|
||||
echo -e "\tkselftest_deps.sh [-p] gcc mm"
|
||||
echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc"
|
||||
echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc mm\n"
|
||||
echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc mm"
|
||||
echo -e "\tkselftest_deps.sh [-p] LLVM"
|
||||
echo -e "\tkselftest_deps.sh [-p] LLVM ARCH=arm64 mm\n"
|
||||
echo "- Should be run in selftests directory in the kernel repo."
|
||||
echo "- Checks if Kselftests can be built/cross-built on a system."
|
||||
echo "- Compiler can be given as LLVM to use clang, as with LLVM=1 in"
|
||||
echo " the kselftest build. LLVM=<prefix>/ and LLVM=-<suffix> select"
|
||||
echo " the clang binary as in the kselftest build. ARCH=<arch> selects"
|
||||
echo " the clang target architecture, defaulting to the host; it is"
|
||||
echo " ignored for other compilers."
|
||||
echo "- Parses all test/sub-test Makefile to find library dependencies."
|
||||
echo "- Runs compile test on a trivial C file with LDLIBS specified"
|
||||
echo " in the test Makefiles to identify missing library dependencies."
|
||||
|
|
@ -53,13 +60,32 @@ while getopts "p" arg; do
|
|||
esac
|
||||
done
|
||||
|
||||
# Pull an optional ARCH=<arch> out of the remaining arguments. The
|
||||
# environment is used if it is not given on the command line, as with
|
||||
# make.
|
||||
args=()
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
ARCH=*)
|
||||
ARCH=${arg#ARCH=};;
|
||||
*)
|
||||
args+=("$arg");;
|
||||
esac
|
||||
done
|
||||
set -- "${args[@]}"
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
usage
|
||||
fi
|
||||
|
||||
# Compiler
|
||||
CC=$1
|
||||
case "$1" in
|
||||
LLVM|LLVM=*)
|
||||
setup_llvm "${1#LLVM}";;
|
||||
*)
|
||||
CC=$1;;
|
||||
esac
|
||||
|
||||
tmp_file=$(mktemp).c
|
||||
trap "rm -f $tmp_file.o $tmp_file $tmp_file.bin" EXIT
|
||||
|
|
@ -178,6 +204,56 @@ exit $?
|
|||
}
|
||||
# end main()
|
||||
|
||||
# Mirror the LLVM handling in lib.mk: LLVM=<prefix>/ or LLVM=-<suffix>
|
||||
# select the clang binary, and ARCH selects the target triple with the
|
||||
# host as the default.
|
||||
setup_llvm()
|
||||
{
|
||||
local llvm=${1#=}
|
||||
local llvm_prefix=""
|
||||
local llvm_suffix=""
|
||||
local clang
|
||||
local target
|
||||
|
||||
declare -A clang_target
|
||||
clang_target[arm]=arm-linux-gnueabi
|
||||
clang_target[arm64]=aarch64-linux-gnu
|
||||
clang_target[hexagon]=hexagon-linux-musl
|
||||
clang_target[i386]=i386-linux-gnu
|
||||
clang_target[m68k]=m68k-linux-gnu
|
||||
clang_target[mips]=mipsel-linux-gnu
|
||||
clang_target[powerpc]=powerpc64le-linux-gnu
|
||||
clang_target[riscv]=riscv64-linux-gnu
|
||||
clang_target[s390]=s390x-linux-gnu
|
||||
clang_target[x86]=x86_64-linux-gnu
|
||||
clang_target[x86_64]=x86_64-linux-gnu
|
||||
|
||||
case "$llvm" in
|
||||
*/)
|
||||
llvm_prefix=$llvm;;
|
||||
-*)
|
||||
llvm_suffix=$llvm;;
|
||||
esac
|
||||
clang=${llvm_prefix}clang${llvm_suffix}
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
target=$($clang -print-target-triple 2>/dev/null)
|
||||
if [ -z "$target" ]; then
|
||||
echo -e "\tUnable to run $clang ..."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
target=${clang_target[$ARCH]}
|
||||
if [ -z "$target" ]; then
|
||||
echo -e "\tUnknown ARCH $ARCH for LLVM, supported:"
|
||||
echo -e "\t$(echo "${!clang_target[*]}" | xargs -n1 | sort | xargs)"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
CC="$clang --target=$target -fintegrated-as"
|
||||
}
|
||||
|
||||
all_tests()
|
||||
{
|
||||
for test in $l1_tests; do
|
||||
|
|
@ -285,6 +361,7 @@ print_results()
|
|||
{
|
||||
echo -e "========================================================";
|
||||
echo -e "Kselftest Dependency Check for [$0 $1 $2] results..."
|
||||
echo -e "Compiler: $CC"
|
||||
|
||||
if [ $print_targets -ne 0 ]
|
||||
then
|
||||
|
|
|
|||
|
|
@ -106,7 +106,8 @@ define RUN_TESTS
|
|||
if [ "X$(summary)" != "X" ]; then \
|
||||
per_test_logging=1; \
|
||||
fi; \
|
||||
run_many $(1)
|
||||
run_many $(1); \
|
||||
ktap_print_totals
|
||||
endef
|
||||
|
||||
define INSTALL_INCLUDES
|
||||
|
|
@ -155,7 +156,7 @@ endef
|
|||
|
||||
define INSTALL_MODS_RULE
|
||||
$(if $(INSTALL_LIST),@mkdir -p $(INSTALL_PATH)/$(INSTALL_LIST))
|
||||
$(if $(INSTALL_LIST),rsync -a --copy-unsafe-links $(INSTALL_LIST)/*.ko $(INSTALL_PATH)/$(INSTALL_LIST))
|
||||
$(if $(wildcard $(INSTALL_LIST)/*.ko),rsync -a --copy-unsafe-links $(INSTALL_LIST)/*.ko $(INSTALL_PATH)/$(INSTALL_LIST))
|
||||
endef
|
||||
|
||||
define INSTALL_RULE
|
||||
|
|
|
|||
|
|
@ -357,11 +357,32 @@ static bool noncont_cat_feature_check(const struct resctrl_test *test)
|
|||
return resource_info_file_exists(test->resource, "sparse_masks");
|
||||
}
|
||||
|
||||
static bool cat_feature_check(const struct resctrl_test *test)
|
||||
{
|
||||
unsigned long mask;
|
||||
|
||||
if (!test_resource_feature_check(test))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Test requires an exclusive cache portion. Some platforms may
|
||||
* legitimately report all bits as shareable, skip the test if that
|
||||
* is the case.
|
||||
*/
|
||||
if (get_mask_no_shareable(test->resource, &mask)) {
|
||||
ksft_print_msg("All %s bits are shareable, test requires an exclusive cache portion\n",
|
||||
test->resource);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct resctrl_test l3_cat_test = {
|
||||
.name = "L3_CAT",
|
||||
.group = "CAT",
|
||||
.resource = "L3",
|
||||
.feature_check = test_resource_feature_check,
|
||||
.feature_check = cat_feature_check,
|
||||
.run_test = cat_run_test,
|
||||
.cleanup = cat_test_cleanup,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ static int check_results(void)
|
|||
|
||||
static void mba_test_cleanup(void)
|
||||
{
|
||||
cleanup_read_mem_bw_imc();
|
||||
remove(RESULT_FILE_NAME);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ static int mbm_measure(const struct user_params *uparams,
|
|||
|
||||
static void mbm_test_cleanup(void)
|
||||
{
|
||||
cleanup_read_mem_bw_imc();
|
||||
remove(RESULT_FILE_NAME);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/perf_event.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/list.h>
|
||||
#include "kselftest.h"
|
||||
|
||||
#define MB (1024 * 1024)
|
||||
|
|
@ -183,6 +184,7 @@ void mem_flush(unsigned char *buf, size_t buf_size);
|
|||
void fill_cache_read(unsigned char *buf, size_t buf_size, bool once);
|
||||
ssize_t get_fill_buf_size(int cpu_no, const char *cache_type);
|
||||
int initialize_read_mem_bw_imc(void);
|
||||
void cleanup_read_mem_bw_imc(void);
|
||||
int measure_read_mem_bw(const struct user_params *uparams,
|
||||
struct resctrl_val_param *param, pid_t bm_pid);
|
||||
void initialize_mem_bw_resctrl(const struct resctrl_val_param *param,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#define READ_FILE_NAME "cas_count_read"
|
||||
#define DYN_PMU_PATH "/sys/bus/event_source/devices"
|
||||
#define SCALE 0.00006103515625
|
||||
#define MAX_IMCS 40
|
||||
#define MAX_TOKENS 5
|
||||
|
||||
#define CON_MBM_LOCAL_BYTES_PATH \
|
||||
|
|
@ -28,6 +27,7 @@ struct membw_read_format {
|
|||
};
|
||||
|
||||
struct imc_counter_config {
|
||||
struct list_head entry;
|
||||
__u32 type;
|
||||
__u64 event;
|
||||
__u64 umask;
|
||||
|
|
@ -36,44 +36,40 @@ struct imc_counter_config {
|
|||
};
|
||||
|
||||
static char mbm_total_path[1024];
|
||||
static int imcs;
|
||||
static struct imc_counter_config imc_counters_config[MAX_IMCS];
|
||||
LIST_HEAD(imc_counters_list);
|
||||
static const struct resctrl_test *current_test;
|
||||
|
||||
static void read_mem_bw_initialize_perf_event_attr(int i)
|
||||
static void read_mem_bw_initialize_perf_event_attr(struct imc_counter_config *imc_counter)
|
||||
{
|
||||
memset(&imc_counters_config[i].pe, 0,
|
||||
sizeof(struct perf_event_attr));
|
||||
imc_counters_config[i].pe.type = imc_counters_config[i].type;
|
||||
imc_counters_config[i].pe.size = sizeof(struct perf_event_attr);
|
||||
imc_counters_config[i].pe.disabled = 1;
|
||||
imc_counters_config[i].pe.inherit = 1;
|
||||
imc_counters_config[i].pe.exclude_guest = 0;
|
||||
imc_counters_config[i].pe.config =
|
||||
imc_counters_config[i].umask << 8 |
|
||||
imc_counters_config[i].event;
|
||||
imc_counters_config[i].pe.sample_type = PERF_SAMPLE_IDENTIFIER;
|
||||
imc_counters_config[i].pe.read_format =
|
||||
memset(&imc_counter->pe, 0, sizeof(struct perf_event_attr));
|
||||
imc_counter->pe.type = imc_counter->type;
|
||||
imc_counter->pe.size = sizeof(struct perf_event_attr);
|
||||
imc_counter->pe.disabled = 1;
|
||||
imc_counter->pe.inherit = 1;
|
||||
imc_counter->pe.exclude_guest = 0;
|
||||
imc_counter->pe.config = imc_counter->umask << 8 | imc_counter->event;
|
||||
imc_counter->pe.sample_type = PERF_SAMPLE_IDENTIFIER;
|
||||
imc_counter->pe.read_format =
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
|
||||
}
|
||||
|
||||
static void read_mem_bw_ioctl_perf_event_ioc_reset_enable(int i)
|
||||
static void read_mem_bw_ioctl_perf_event_ioc_reset_enable(struct imc_counter_config *imc_counter)
|
||||
{
|
||||
ioctl(imc_counters_config[i].fd, PERF_EVENT_IOC_RESET, 0);
|
||||
ioctl(imc_counters_config[i].fd, PERF_EVENT_IOC_ENABLE, 0);
|
||||
ioctl(imc_counter->fd, PERF_EVENT_IOC_RESET, 0);
|
||||
ioctl(imc_counter->fd, PERF_EVENT_IOC_ENABLE, 0);
|
||||
}
|
||||
|
||||
static void read_mem_bw_ioctl_perf_event_ioc_disable(int i)
|
||||
static void read_mem_bw_ioctl_perf_event_ioc_disable(struct imc_counter_config *imc_counter)
|
||||
{
|
||||
ioctl(imc_counters_config[i].fd, PERF_EVENT_IOC_DISABLE, 0);
|
||||
ioctl(imc_counter->fd, PERF_EVENT_IOC_DISABLE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_read_event_and_umask: Parse config into event and umask
|
||||
* @cas_count_cfg: Config
|
||||
* @count: iMC number
|
||||
* @imc_counter: iMC counter config
|
||||
*/
|
||||
static void get_read_event_and_umask(char *cas_count_cfg, unsigned int count)
|
||||
static void get_read_event_and_umask(char *cas_count_cfg, struct imc_counter_config *imc_counter)
|
||||
{
|
||||
char *token[MAX_TOKENS];
|
||||
int i = 0;
|
||||
|
|
@ -87,21 +83,20 @@ static void get_read_event_and_umask(char *cas_count_cfg, unsigned int count)
|
|||
if (!token[i])
|
||||
break;
|
||||
if (strcmp(token[i], "event") == 0)
|
||||
imc_counters_config[count].event = strtol(token[i + 1], NULL, 16);
|
||||
imc_counter->event = strtol(token[i + 1], NULL, 16);
|
||||
if (strcmp(token[i], "umask") == 0)
|
||||
imc_counters_config[count].umask = strtol(token[i + 1], NULL, 16);
|
||||
imc_counter->umask = strtol(token[i + 1], NULL, 16);
|
||||
}
|
||||
}
|
||||
|
||||
static int open_perf_read_event(int i, int cpu_no)
|
||||
static int open_perf_read_event(int cpu_no, struct imc_counter_config *imc_counter)
|
||||
{
|
||||
imc_counters_config[i].fd =
|
||||
perf_event_open(&imc_counters_config[i].pe, -1, cpu_no, -1,
|
||||
PERF_FLAG_FD_CLOEXEC);
|
||||
imc_counter->fd = perf_event_open(&imc_counter->pe, -1, cpu_no, -1,
|
||||
PERF_FLAG_FD_CLOEXEC);
|
||||
|
||||
if (imc_counters_config[i].fd == -1) {
|
||||
if (imc_counter->fd == -1) {
|
||||
fprintf(stderr, "Error opening leader %llx\n",
|
||||
imc_counters_config[i].pe.config);
|
||||
imc_counter->pe.config);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -109,11 +104,11 @@ static int open_perf_read_event(int i, int cpu_no)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int parse_imc_read_bw_events(char *imc_dir, unsigned int type,
|
||||
unsigned int *count)
|
||||
static int parse_imc_read_bw_events(char *imc_dir, unsigned int type)
|
||||
{
|
||||
char imc_events_dir[PATH_MAX], imc_counter_cfg[PATH_MAX];
|
||||
unsigned int orig_count = *count;
|
||||
struct imc_counter_config *imc_counter;
|
||||
bool found_event = false;
|
||||
char cas_count_cfg[1024];
|
||||
struct dirent *ep;
|
||||
int path_len;
|
||||
|
|
@ -126,13 +121,13 @@ static int parse_imc_read_bw_events(char *imc_dir, unsigned int type,
|
|||
imc_dir);
|
||||
if (path_len >= sizeof(imc_events_dir)) {
|
||||
ksft_print_msg("Unable to create path to %sevents\n", imc_dir);
|
||||
return -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dp = opendir(imc_events_dir);
|
||||
if (!dp) {
|
||||
ksft_perror("Unable to open PMU events directory");
|
||||
return -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while ((ep = readdir(dp))) {
|
||||
|
|
@ -163,28 +158,33 @@ static int parse_imc_read_bw_events(char *imc_dir, unsigned int type,
|
|||
ksft_perror("Could not get iMC cas count read");
|
||||
goto out_close;
|
||||
}
|
||||
if (*count >= MAX_IMCS) {
|
||||
ksft_print_msg("Maximum iMC count exceeded\n");
|
||||
imc_counter = calloc(1, sizeof(*imc_counter));
|
||||
if (!imc_counter) {
|
||||
ksft_perror("Unable to allocate memory for iMC counters");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
imc_counters_config[*count].type = type;
|
||||
get_read_event_and_umask(cas_count_cfg, *count);
|
||||
/* Do not fail after incrementing *count. */
|
||||
*count += 1;
|
||||
imc_counter->type = type;
|
||||
get_read_event_and_umask(cas_count_cfg, imc_counter);
|
||||
list_add(&imc_counter->entry, &imc_counters_list);
|
||||
found_event = true;
|
||||
}
|
||||
if (*count == orig_count) {
|
||||
if (!found_event) {
|
||||
ksft_print_msg("Unable to find events in %s\n", imc_events_dir);
|
||||
goto out_close;
|
||||
}
|
||||
ret = 0;
|
||||
out_close:
|
||||
closedir(dp);
|
||||
out:
|
||||
if (ret)
|
||||
cleanup_read_mem_bw_imc();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get type and config of an iMC counter's read event. */
|
||||
static int read_from_imc_dir(char *imc_dir, unsigned int *count)
|
||||
static int read_from_imc_dir(char *imc_dir)
|
||||
{
|
||||
char imc_counter_type[PATH_MAX];
|
||||
unsigned int type;
|
||||
|
|
@ -212,7 +212,7 @@ static int read_from_imc_dir(char *imc_dir, unsigned int *count)
|
|||
ksft_perror("Could not get iMC type");
|
||||
return -1;
|
||||
}
|
||||
ret = parse_imc_read_bw_events(imc_dir, type, count);
|
||||
ret = parse_imc_read_bw_events(imc_dir, type);
|
||||
if (ret) {
|
||||
ksft_print_msg("Unable to parse bandwidth event and umask\n");
|
||||
return ret;
|
||||
|
|
@ -222,21 +222,18 @@ static int read_from_imc_dir(char *imc_dir, unsigned int *count)
|
|||
}
|
||||
|
||||
/*
|
||||
* A system can have 'n' number of iMC (Integrated Memory Controller)
|
||||
* counters, get that 'n'. Discover the properties of the available
|
||||
* counters in support of needed performance measurement via perf.
|
||||
* For each iMC counter get it's type and config. Also obtain each
|
||||
* counter's event and umask for the memory read events that will be
|
||||
* measured.
|
||||
* Discover the properties of the available iMC (Integrated Memory Controller)
|
||||
* counters in support of needed performance measurement via perf. For each iMC
|
||||
* counter get it's type and config. Also obtain each counter's event and umask
|
||||
* for the memory read events that will be measured.
|
||||
*
|
||||
* Enumerate all these details into an array of structures.
|
||||
* Enumerate all these details into a linked list of structures.
|
||||
*
|
||||
* Return: >= 0 on success. < 0 on failure.
|
||||
*/
|
||||
static int num_of_imcs(void)
|
||||
static int enumerate_imcs(void)
|
||||
{
|
||||
char imc_dir[512], *temp;
|
||||
unsigned int count = 0;
|
||||
struct dirent *ep;
|
||||
int ret;
|
||||
DIR *dp;
|
||||
|
|
@ -265,7 +262,7 @@ static int num_of_imcs(void)
|
|||
if (temp[0] >= '0' && temp[0] <= '9') {
|
||||
sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH,
|
||||
ep->d_name);
|
||||
ret = read_from_imc_dir(imc_dir, &count);
|
||||
ret = read_from_imc_dir(imc_dir);
|
||||
if (ret) {
|
||||
closedir(dp);
|
||||
|
||||
|
|
@ -274,7 +271,7 @@ static int num_of_imcs(void)
|
|||
}
|
||||
}
|
||||
closedir(dp);
|
||||
if (count == 0) {
|
||||
if (list_empty(&imc_counters_list)) {
|
||||
ksft_print_msg("Unable to find iMC counters\n");
|
||||
|
||||
return -1;
|
||||
|
|
@ -285,31 +282,42 @@ static int num_of_imcs(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int initialize_read_mem_bw_imc(void)
|
||||
{
|
||||
int imc;
|
||||
struct imc_counter_config *imc_counter;
|
||||
int ret;
|
||||
|
||||
imcs = num_of_imcs();
|
||||
if (imcs <= 0)
|
||||
return imcs;
|
||||
ret = enumerate_imcs();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Initialize perf_event_attr structures for all iMC's */
|
||||
for (imc = 0; imc < imcs; imc++)
|
||||
read_mem_bw_initialize_perf_event_attr(imc);
|
||||
list_for_each_entry(imc_counter, &imc_counters_list, entry)
|
||||
read_mem_bw_initialize_perf_event_attr(imc_counter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_read_mem_bw_imc(void)
|
||||
{
|
||||
struct imc_counter_config *imc_counter, *tmp;
|
||||
|
||||
list_for_each_entry_safe(imc_counter, tmp, &imc_counters_list, entry) {
|
||||
list_del(&imc_counter->entry);
|
||||
free(imc_counter);
|
||||
}
|
||||
}
|
||||
|
||||
static void perf_close_imc_read_mem_bw(void)
|
||||
{
|
||||
int mc;
|
||||
struct imc_counter_config *imc_counter;
|
||||
|
||||
for (mc = 0; mc < imcs; mc++) {
|
||||
if (imc_counters_config[mc].fd != -1)
|
||||
close(imc_counters_config[mc].fd);
|
||||
list_for_each_entry(imc_counter, &imc_counters_list, entry) {
|
||||
if (imc_counter->fd != -1)
|
||||
close(imc_counter->fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -321,13 +329,14 @@ static void perf_close_imc_read_mem_bw(void)
|
|||
*/
|
||||
static int perf_open_imc_read_mem_bw(int cpu_no)
|
||||
{
|
||||
int imc, ret;
|
||||
struct imc_counter_config *imc_counter;
|
||||
int ret;
|
||||
|
||||
for (imc = 0; imc < imcs; imc++)
|
||||
imc_counters_config[imc].fd = -1;
|
||||
list_for_each_entry(imc_counter, &imc_counters_list, entry)
|
||||
imc_counter->fd = -1;
|
||||
|
||||
for (imc = 0; imc < imcs; imc++) {
|
||||
ret = open_perf_read_event(imc, cpu_no);
|
||||
list_for_each_entry(imc_counter, &imc_counters_list, entry) {
|
||||
ret = open_perf_read_event(cpu_no, imc_counter);
|
||||
if (ret)
|
||||
goto close_fds;
|
||||
}
|
||||
|
|
@ -347,16 +356,16 @@ static int perf_open_imc_read_mem_bw(int cpu_no)
|
|||
*/
|
||||
static void do_imc_read_mem_bw_test(void)
|
||||
{
|
||||
int imc;
|
||||
struct imc_counter_config *imc_counter;
|
||||
|
||||
for (imc = 0; imc < imcs; imc++)
|
||||
read_mem_bw_ioctl_perf_event_ioc_reset_enable(imc);
|
||||
list_for_each_entry(imc_counter, &imc_counters_list, entry)
|
||||
read_mem_bw_ioctl_perf_event_ioc_reset_enable(imc_counter);
|
||||
|
||||
sleep(1);
|
||||
|
||||
/* Stop counters after a second to get results. */
|
||||
for (imc = 0; imc < imcs; imc++)
|
||||
read_mem_bw_ioctl_perf_event_ioc_disable(imc);
|
||||
list_for_each_entry(imc_counter, &imc_counters_list, entry)
|
||||
read_mem_bw_ioctl_perf_event_ioc_disable(imc_counter);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -371,17 +380,15 @@ static void do_imc_read_mem_bw_test(void)
|
|||
static int get_read_mem_bw_imc(float *bw_imc)
|
||||
{
|
||||
float reads = 0, of_mul_read = 1;
|
||||
int imc;
|
||||
struct imc_counter_config *r;
|
||||
|
||||
/*
|
||||
* Log read event values from all iMC counters into
|
||||
* struct imc_counter_config.
|
||||
* Take overflow into consideration before calculating total bandwidth.
|
||||
*/
|
||||
for (imc = 0; imc < imcs; imc++) {
|
||||
list_for_each_entry(r, &imc_counters_list, entry) {
|
||||
struct membw_read_format measurement;
|
||||
struct imc_counter_config *r =
|
||||
&imc_counters_config[imc];
|
||||
|
||||
if (read(r->fd, &measurement, sizeof(measurement)) == -1) {
|
||||
ksft_perror("Couldn't get read bandwidth through iMC");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user