Commit 0434dbe3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux_kselftest-next-6.11-rc1' of...

Merge tag 'linux_kselftest-next-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kselftest updates from Shuah Khan:

 - change resctrl test to cleanup resctrl_val() and generalize it by
   removing test name specific handling from the function.

 - several clang build failure fixes to framework and tests

 - add tests to verify IFS (In Field Scan) driver functionality

 - cleanups to remove unused variables and document changes

* tag 'linux_kselftest-next-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (33 commits)
  selftests: ifs: verify IFS ARRAY BIST functionality
  selftests: ifs: verify IFS scan test functionality
  selftests: ifs: verify test image loading functionality
  selftests: ifs: verify test interfaces are created by the driver
  selftests/dma:remove unused variable
  selftests/breakpoints:Remove unused variable
  selftests/x86: fix printk warnings reported by clang
  selftests/x86: remove (or use) unused variables and functions
  selftests/x86: avoid -no-pie warnings from clang during compilation
  selftests/x86: build sysret_rip.c with clang
  selftests/x86: build fsgsbase_restore.c with clang
  selftests: x86: test_FISTTP: use fisttps instead of ambiguous fisttp
  selftests/x86: fix Makefile dependencies to work with clang
  selftests/timers: remove unused irqcount variable
  selftests: Add information about TAP conformance in tests
  selftests/resctrl: Remove test name comparing from write_bm_pid_to_resctrl()
  selftests/resctrl: Remove mongrp from CMT test
  selftests/resctrl: Remove mongrp from MBA test
  selftests/resctrl: Convert ctrlgrp & mongrp to pointers
  selftests/resctrl: Make some strings passed to resctrlfs functions const
  ...
parents f8d22a31 bb408dae
......@@ -228,6 +228,13 @@ In general, the rules for selftests are
* Don't cause the top-level "make run_tests" to fail if your feature is
unconfigured.
* The output of tests must conform to the TAP standard to ensure high
testing quality and to capture failures/errors with specific details.
The kselftest.h and kselftest_harness.h headers provide wrappers for
outputting test results. These wrappers should be used for pass,
fail, exit, and skip messages. CI systems can easily parse TAP output
messages to detect test results.
Contributing new tests (details)
================================
......
......@@ -11216,6 +11216,7 @@ R: Tony Luck <tony.luck@intel.com>
S: Maintained
F: drivers/platform/x86/intel/ifs
F: include/trace/events/intel_ifs.h
F: tools/testing/selftests/drivers/platform/x86/intel/ifs/
INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
......
......@@ -21,6 +21,7 @@ TARGETS += drivers/net
TARGETS += drivers/net/bonding
TARGETS += drivers/net/team
TARGETS += drivers/net/virtio_net
TARGETS += drivers/platform/x86/intel/ifs
TARGETS += dt
TARGETS += efivarfs
TARGETS += exec
......
......@@ -130,7 +130,6 @@ int run_test(int cpu)
void suspend(void)
{
int power_state_fd;
struct sigevent event = {};
int timerfd;
int err;
struct itimerspec spec = {};
......
......@@ -33,7 +33,6 @@ int main(int argc, char **argv)
int granule = 1;
int cmd = DMA_MAP_BENCHMARK;
char *p;
while ((opt = getopt(argc, argv, "t:s:n:b:d:x:g:")) != -1) {
switch (opt) {
......
# SPDX-License-Identifier: GPL-2.0
# Makefile for ifs(In Field Scan) selftests
TEST_PROGS := test_ifs.sh
include ../../../../../lib.mk
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Test the functionality of the Intel IFS(In Field Scan) driver.
#
# Matched with kselftest framework: tools/testing/selftests/kselftest.h
readonly KSFT_PASS=0
readonly KSFT_FAIL=1
readonly KSFT_XFAIL=2
readonly KSFT_SKIP=4
readonly CPU_SYSFS="/sys/devices/system/cpu"
readonly CPU_OFFLINE_SYSFS="${CPU_SYSFS}/offline"
readonly IMG_PATH="/lib/firmware/intel/ifs_0"
readonly IFS_SCAN_MODE="0"
readonly IFS_ARRAY_BIST_SCAN_MODE="1"
readonly IFS_PATH="/sys/devices/virtual/misc/intel_ifs"
readonly IFS_SCAN_SYSFS_PATH="${IFS_PATH}_${IFS_SCAN_MODE}"
readonly IFS_ARRAY_BIST_SYSFS_PATH="${IFS_PATH}_${IFS_ARRAY_BIST_SCAN_MODE}"
readonly RUN_TEST="run_test"
readonly STATUS="status"
readonly DETAILS="details"
readonly STATUS_PASS="pass"
readonly PASS="PASS"
readonly FAIL="FAIL"
readonly INFO="INFO"
readonly XFAIL="XFAIL"
readonly SKIP="SKIP"
readonly IFS_NAME="intel_ifs"
readonly ALL="all"
readonly SIBLINGS="siblings"
# Matches arch/x86/include/asm/intel-family.h and
# drivers/platform/x86/intel/ifs/core.c requirement as follows
readonly SAPPHIRERAPIDS_X="8f"
readonly EMERALDRAPIDS_X="cf"
readonly INTEL_FAM6="06"
LOOP_TIMES=3
FML=""
MODEL=""
STEPPING=""
CPU_FMS=""
TRUE="true"
FALSE="false"
RESULT=$KSFT_PASS
IMAGE_NAME=""
INTERVAL_TIME=1
OFFLINE_CPUS=""
# For IFS cleanup tags
ORIGIN_IFS_LOADED=""
IFS_IMAGE_NEED_RESTORE=$FALSE
IFS_LOG="/tmp/ifs_logs.$$"
RANDOM_CPU=""
DEFAULT_IMG_ID=""
append_log()
{
echo -e "$1" | tee -a "$IFS_LOG"
}
online_offline_cpu_list()
{
local on_off=$1
local target_cpus=$2
local cpu=""
local cpu_start=""
local cpu_end=""
local i=""
if [[ -n "$target_cpus" ]]; then
for cpu in $(echo "$target_cpus" | tr ',' ' '); do
if [[ "$cpu" == *"-"* ]]; then
cpu_start=""
cpu_end=""
i=""
cpu_start=$(echo "$cpu" | cut -d "-" -f 1)
cpu_end=$(echo "$cpu" | cut -d "-" -f 2)
for((i=cpu_start;i<=cpu_end;i++)); do
append_log "[$INFO] echo $on_off > \
${CPU_SYSFS}/cpu${i}/online"
echo "$on_off" > "$CPU_SYSFS"/cpu"$i"/online
done
else
set_target_cpu "$on_off" "$cpu"
fi
done
fi
}
ifs_scan_result_summary()
{
local failed_info pass_num skip_num fail_num
if [[ -e "$IFS_LOG" ]]; then
failed_info=$(grep ^"\[${FAIL}\]" "$IFS_LOG")
fail_num=$(grep -c ^"\[${FAIL}\]" "$IFS_LOG")
skip_num=$(grep -c ^"\[${SKIP}\]" "$IFS_LOG")
pass_num=$(grep -c ^"\[${PASS}\]" "$IFS_LOG")
if [[ "$fail_num" -ne 0 ]]; then
RESULT=$KSFT_FAIL
echo "[$INFO] IFS test failure summary:"
echo "$failed_info"
elif [[ "$skip_num" -ne 0 ]]; then
RESULT=$KSFT_SKIP
fi
echo "[$INFO] IFS test pass:$pass_num, skip:$skip_num, fail:$fail_num"
else
echo "[$INFO] No file $IFS_LOG for IFS scan summary"
fi
}
ifs_cleanup()
{
echo "[$INFO] Restore environment after IFS test"
# Restore ifs origin image if origin image backup step is needed
[[ "$IFS_IMAGE_NEED_RESTORE" == "$TRUE" ]] && {
mv -f "$IMG_PATH"/"$IMAGE_NAME"_origin "$IMG_PATH"/"$IMAGE_NAME"
}
# Restore the CPUs to the state before testing
[[ -z "$OFFLINE_CPUS" ]] || online_offline_cpu_list "0" "$OFFLINE_CPUS"
lsmod | grep -q "$IFS_NAME" && [[ "$ORIGIN_IFS_LOADED" == "$FALSE" ]] && {
echo "[$INFO] modprobe -r $IFS_NAME"
modprobe -r "$IFS_NAME"
}
ifs_scan_result_summary
[[ -e "$IFS_LOG" ]] && rm -rf "$IFS_LOG"
echo "[RESULT] IFS test exit with $RESULT"
exit "$RESULT"
}
do_cmd()
{
local cmd=$*
local ret=""
append_log "[$INFO] $cmd"
eval "$cmd"
ret=$?
if [[ $ret -ne 0 ]]; then
append_log "[$FAIL] $cmd failed. Return code is $ret"
RESULT=$KSFT_XFAIL
ifs_cleanup
fi
}
test_exit()
{
local info=$1
RESULT=$2
declare -A EXIT_MAP
EXIT_MAP[$KSFT_PASS]=$PASS
EXIT_MAP[$KSFT_FAIL]=$FAIL
EXIT_MAP[$KSFT_XFAIL]=$XFAIL
EXIT_MAP[$KSFT_SKIP]=$SKIP
append_log "[${EXIT_MAP[$RESULT]}] $info"
ifs_cleanup
}
online_all_cpus()
{
local off_cpus=""
OFFLINE_CPUS=$(cat "$CPU_OFFLINE_SYSFS")
online_offline_cpu_list "1" "$OFFLINE_CPUS"
off_cpus=$(cat "$CPU_OFFLINE_SYSFS")
if [[ -z "$off_cpus" ]]; then
append_log "[$INFO] All CPUs are online."
else
append_log "[$XFAIL] There is offline cpu:$off_cpus after online all cpu!"
RESULT=$KSFT_XFAIL
ifs_cleanup
fi
}
get_cpu_fms()
{
FML=$(grep -m 1 "family" /proc/cpuinfo | awk -F ":" '{printf "%02x",$2;}')
MODEL=$(grep -m 1 "model" /proc/cpuinfo | awk -F ":" '{printf "%02x",$2;}')
STEPPING=$(grep -m 1 "stepping" /proc/cpuinfo | awk -F ":" '{printf "%02x",$2;}')
CPU_FMS="${FML}-${MODEL}-${STEPPING}"
}
check_cpu_ifs_support_interval_time()
{
get_cpu_fms
if [[ "$FML" != "$INTEL_FAM6" ]]; then
test_exit "CPU family:$FML does not support IFS" "$KSFT_SKIP"
fi
# Ucode has time interval requirement for IFS scan on same CPU as follows:
case $MODEL in
"$SAPPHIRERAPIDS_X")
INTERVAL_TIME=180;
;;
"$EMERALDRAPIDS_X")
INTERVAL_TIME=30;
;;
*)
# Set default interval time for other platforms
INTERVAL_TIME=1;
append_log "[$INFO] CPU FML:$FML model:0x$MODEL, default: 1s interval time"
;;
esac
}
check_ifs_loaded()
{
local ifs_info=""
ifs_info=$(lsmod | grep "$IFS_NAME")
if [[ -z "$ifs_info" ]]; then
append_log "[$INFO] modprobe $IFS_NAME"
modprobe "$IFS_NAME" || {
test_exit "Check if CONFIG_INTEL_IFS is set to m or \
platform doesn't support ifs" "$KSFT_SKIP"
}
ifs_info=$(lsmod | grep "$IFS_NAME")
[[ -n "$ifs_info" ]] || test_exit "No ifs module listed by lsmod" "$KSFT_FAIL"
fi
}
test_ifs_scan_entry()
{
local ifs_info=""
ifs_info=$(lsmod | grep "$IFS_NAME")
if [[ -z "$ifs_info" ]]; then
ORIGIN_IFS_LOADED="$FALSE"
check_ifs_loaded
else
ORIGIN_IFS_LOADED="$TRUE"
append_log "[$INFO] Module $IFS_NAME is already loaded"
fi
if [[ -d "$IFS_SCAN_SYSFS_PATH" ]]; then
append_log "[$PASS] IFS sysfs $IFS_SCAN_SYSFS_PATH entry is created\n"
else
test_exit "No sysfs entry in $IFS_SCAN_SYSFS_PATH" "$KSFT_FAIL"
fi
}
load_image()
{
local image_id=$1
local image_info=""
local ret=""
check_ifs_loaded
if [[ -e "${IMG_PATH}/${IMAGE_NAME}" ]]; then
append_log "[$INFO] echo 0x$image_id > ${IFS_SCAN_SYSFS_PATH}/current_batch"
echo "0x$image_id" > "$IFS_SCAN_SYSFS_PATH"/current_batch 2>/dev/null
ret=$?
[[ "$ret" -eq 0 ]] || {
append_log "[$FAIL] Load ifs image $image_id failed with ret:$ret\n"
return "$ret"
}
image_info=$(cat ${IFS_SCAN_SYSFS_PATH}/current_batch)
if [[ "$image_info" == 0x"$image_id" ]]; then
append_log "[$PASS] load IFS current_batch:$image_info"
else
append_log "[$FAIL] current_batch:$image_info is not expected:$image_id"
return "$KSFT_FAIL"
fi
else
append_log "[$FAIL] No IFS image file ${IMG_PATH}/${IMAGE_NAME}"\
return "$KSFT_FAIL"
fi
return 0
}
test_load_origin_ifs_image()
{
local image_id=$1
IMAGE_NAME="${CPU_FMS}-${image_id}.scan"
load_image "$image_id" || return $?
return 0
}
test_load_bad_ifs_image()
{
local image_id=$1
IMAGE_NAME="${CPU_FMS}-${image_id}.scan"
do_cmd "mv -f ${IMG_PATH}/${IMAGE_NAME} ${IMG_PATH}/${IMAGE_NAME}_origin"
# Set IFS_IMAGE_NEED_RESTORE to true before corrupt the origin ifs image file
IFS_IMAGE_NEED_RESTORE=$TRUE
do_cmd "dd if=/dev/urandom of=${IMG_PATH}/${IMAGE_NAME} bs=1K count=6 2>/dev/null"
# Use the specified judgment for negative testing
append_log "[$INFO] echo 0x$image_id > ${IFS_SCAN_SYSFS_PATH}/current_batch"
echo "0x$image_id" > "$IFS_SCAN_SYSFS_PATH"/current_batch 2>/dev/null
ret=$?
if [[ "$ret" -ne 0 ]]; then
append_log "[$PASS] Load invalid ifs image failed with ret:$ret not 0 as expected"
else
append_log "[$FAIL] Load invalid ifs image ret:$ret unexpectedly"
fi
do_cmd "mv -f ${IMG_PATH}/${IMAGE_NAME}_origin ${IMG_PATH}/${IMAGE_NAME}"
IFS_IMAGE_NEED_RESTORE=$FALSE
}
test_bad_and_origin_ifs_image()
{
local image_id=$1
append_log "[$INFO] Test loading bad and then loading original IFS image:"
test_load_origin_ifs_image "$image_id" || return $?
test_load_bad_ifs_image "$image_id"
# Load origin image again and make sure it's worked
test_load_origin_ifs_image "$image_id" || return $?
append_log "[$INFO] Loading invalid IFS image and then loading initial image passed.\n"
}
ifs_test_cpu()
{
local ifs_mode=$1
local cpu_num=$2
local image_id status details ret result result_info
echo "$cpu_num" > "$IFS_PATH"_"$ifs_mode"/"$RUN_TEST"
ret=$?
status=$(cat "${IFS_PATH}_${ifs_mode}/${STATUS}")
details=$(cat "${IFS_PATH}_${ifs_mode}/${DETAILS}")
if [[ "$ret" -eq 0 && "$status" == "$STATUS_PASS" ]]; then
result="$PASS"
else
result="$FAIL"
fi
cpu_num=$(cat "${CPU_SYSFS}/cpu${cpu_num}/topology/thread_siblings_list")
# There is no image file for IFS ARRAY BIST scan
if [[ -e "${IFS_PATH}_${ifs_mode}/current_batch" ]]; then
image_id=$(cat "${IFS_PATH}_${ifs_mode}/current_batch")
result_info=$(printf "[%s] ifs_%1d cpu(s):%s, current_batch:0x%02x, \
ret:%2d, status:%s, details:0x%016x" \
"$result" "$ifs_mode" "$cpu_num" "$image_id" "$ret" \
"$status" "$details")
else
result_info=$(printf "[%s] ifs_%1d cpu(s):%s, ret:%2d, status:%s, details:0x%016x" \
"$result" "$ifs_mode" "$cpu_num" "$ret" "$status" "$details")
fi
append_log "$result_info"
}
ifs_test_cpus()
{
local cpus_type=$1
local ifs_mode=$2
local image_id=$3
local cpu_max_num=""
local cpu_num=""
case "$cpus_type" in
"$ALL")
cpu_max_num=$(($(nproc) - 1))
cpus=$(seq 0 $cpu_max_num)
;;
"$SIBLINGS")
cpus=$(cat ${CPU_SYSFS}/cpu*/topology/thread_siblings_list \
| sed -e 's/,.*//' \
| sed -e 's/-.*//' \
| sort -n \
| uniq)
;;
*)
test_exit "Invalid cpus_type:$cpus_type" "$KSFT_XFAIL"
;;
esac
for cpu_num in $cpus; do
ifs_test_cpu "$ifs_mode" "$cpu_num"
done
if [[ -z "$image_id" ]]; then
append_log "[$INFO] ifs_$ifs_mode test $cpus_type cpus completed\n"
else
append_log "[$INFO] ifs_$ifs_mode $cpus_type cpus with $CPU_FMS-$image_id.scan \
completed\n"
fi
}
test_ifs_same_cpu_loop()
{
local ifs_mode=$1
local cpu_num=$2
local loop_times=$3
append_log "[$INFO] Test ifs mode $ifs_mode on CPU:$cpu_num for $loop_times rounds:"
[[ "$ifs_mode" == "$IFS_SCAN_MODE" ]] && {
load_image "$DEFAULT_IMG_ID" || return $?
}
for (( i=1; i<=loop_times; i++ )); do
append_log "[$INFO] Loop iteration: $i in total of $loop_times"
# Only IFS scan needs the interval time
if [[ "$ifs_mode" == "$IFS_SCAN_MODE" ]]; then
do_cmd "sleep $INTERVAL_TIME"
elif [[ "$ifs_mode" == "$IFS_ARRAY_BIST_SCAN_MODE" ]]; then
true
else
test_exit "Invalid ifs_mode:$ifs_mode" "$KSFT_XFAIL"
fi
ifs_test_cpu "$ifs_mode" "$cpu_num"
done
append_log "[$INFO] $loop_times rounds of ifs_$ifs_mode test on CPU:$cpu_num completed.\n"
}
test_ifs_scan_available_imgs()
{
local image_ids=""
local image_id=""
append_log "[$INFO] Test ifs scan with available images:"
image_ids=$(find "$IMG_PATH" -maxdepth 1 -name "${CPU_FMS}-[0-9a-fA-F][0-9a-fA-F].scan" \
2>/dev/null \
| sort \
| awk -F "-" '{print $NF}' \
| cut -d "." -f 1)
for image_id in $image_ids; do
load_image "$image_id" || return $?
ifs_test_cpus "$SIBLINGS" "$IFS_SCAN_MODE" "$image_id"
# IFS scan requires time interval for the scan on the same CPU
do_cmd "sleep $INTERVAL_TIME"
done
}
prepare_ifs_test_env()
{
local max_cpu=""
check_cpu_ifs_support_interval_time
online_all_cpus
max_cpu=$(($(nproc) - 1))
RANDOM_CPU=$(shuf -i 0-$max_cpu -n 1)
DEFAULT_IMG_ID=$(find $IMG_PATH -maxdepth 1 -name "${CPU_FMS}-[0-9a-fA-F][0-9a-fA-F].scan" \
2>/dev/null \
| sort \
| head -n 1 \
| awk -F "-" '{print $NF}' \
| cut -d "." -f 1)
}
test_ifs()
{
prepare_ifs_test_env
test_ifs_scan_entry
if [[ -z "$DEFAULT_IMG_ID" ]]; then
append_log "[$SKIP] No proper ${IMG_PATH}/${CPU_FMS}-*.scan, skip ifs_0 scan"
else
test_bad_and_origin_ifs_image "$DEFAULT_IMG_ID"
test_ifs_scan_available_imgs
test_ifs_same_cpu_loop "$IFS_SCAN_MODE" "$RANDOM_CPU" "$LOOP_TIMES"
fi
if [[ -d "$IFS_ARRAY_BIST_SYSFS_PATH" ]]; then
ifs_test_cpus "$SIBLINGS" "$IFS_ARRAY_BIST_SCAN_MODE"
test_ifs_same_cpu_loop "$IFS_ARRAY_BIST_SCAN_MODE" "$RANDOM_CPU" "$LOOP_TIMES"
else
append_log "[$SKIP] No $IFS_ARRAY_BIST_SYSFS_PATH, skip IFS ARRAY BIST scan"
fi
}
trap ifs_cleanup SIGTERM SIGINT
test_ifs
ifs_cleanup
......@@ -38,6 +38,14 @@ else
CLANG_FLAGS += --target=$(notdir $(CROSS_COMPILE:%-=%))
endif # CROSS_COMPILE
# gcc defaults to silence (off) for the following warnings, but clang defaults
# to the opposite. The warnings are not useful for the kernel itself, which is
# why they have remained disabled in gcc for the main kernel build. And it is
# only due to including kernel data structures in the selftests, that we get the
# warnings from clang. Therefore, disable the warnings for clang builds.
CFLAGS += -Wno-address-of-packed-member
CFLAGS += -Wno-gnu-variable-sized-type-not-at-end
CC := $(CLANG) $(CLANG_FLAGS) -fintegrated-as
else
CC := $(CROSS_COMPILE)gcc
......
......@@ -101,12 +101,12 @@ static int get_llc_occu_resctrl(unsigned long *llc_occupancy)
*
* Return: 0 on success, < 0 on error.
*/
static int print_results_cache(const char *filename, int bm_pid, __u64 llc_value)
static int print_results_cache(const char *filename, pid_t bm_pid, __u64 llc_value)
{
FILE *fp;
if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) {
printf("Pid: %d \t LLC_value: %llu\n", bm_pid, llc_value);
printf("Pid: %d \t LLC_value: %llu\n", (int)bm_pid, llc_value);
} else {
fp = fopen(filename, "a");
if (!fp) {
......@@ -114,7 +114,7 @@ static int print_results_cache(const char *filename, int bm_pid, __u64 llc_value
return -1;
}
fprintf(fp, "Pid: %d \t llc_value: %llu\n", bm_pid, llc_value);
fprintf(fp, "Pid: %d \t llc_value: %llu\n", (int)bm_pid, llc_value);
fclose(fp);
}
......@@ -133,7 +133,7 @@ static int print_results_cache(const char *filename, int bm_pid, __u64 llc_value
* Return: =0 on success. <0 on failure.
*/
int perf_event_measure(int pe_fd, struct perf_event_read *pe_read,
const char *filename, int bm_pid)
const char *filename, pid_t bm_pid)
{
int ret;
......@@ -161,7 +161,7 @@ int perf_event_measure(int pe_fd, struct perf_event_read *pe_read,
*
* Return: =0 on success. <0 on failure.
*/
int measure_llc_resctrl(const char *filename, int bm_pid)
int measure_llc_resctrl(const char *filename, pid_t bm_pid)
{
unsigned long llc_occu_resc = 0;
int ret;
......
......@@ -158,7 +158,6 @@ static int cat_test(const struct resctrl_test *test,
struct resctrl_val_param *param,
size_t span, unsigned long current_mask)
{
char *resctrl_val = param->resctrl_val;
struct perf_event_read pe_read;
struct perf_event_attr pea;
cpu_set_t old_affinity;
......@@ -178,8 +177,7 @@ static int cat_test(const struct resctrl_test *test,
return ret;
/* Write benchmark to specified con_mon grp, mon_grp in resctrl FS*/
ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
resctrl_val);
ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp);
if (ret)
goto reset_affinity;
......@@ -272,7 +270,6 @@ static int cat_run_test(const struct resctrl_test *test, const struct user_param
start_mask = create_bit_mask(start, n);
struct resctrl_val_param param = {
.resctrl_val = CAT_STR,
.ctrlgrp = "c1",
.filename = RESULT_FILE_NAME,
.num_of_runs = 0,
......
......@@ -16,6 +16,17 @@
#define MAX_DIFF 2000000
#define MAX_DIFF_PERCENT 15
#define CON_MON_LCC_OCCUP_PATH \
"%s/%s/mon_data/mon_L3_%02d/llc_occupancy"
static int cmt_init(const struct resctrl_val_param *param, int domain_id)
{
sprintf(llc_occup_path, CON_MON_LCC_OCCUP_PATH, RESCTRL_PATH,
param->ctrlgrp, domain_id);
return 0;
}
static int cmt_setup(const struct resctrl_test *test,
const struct user_params *uparams,
struct resctrl_val_param *p)
......@@ -29,6 +40,13 @@ static int cmt_setup(const struct resctrl_test *test,
return 0;
}
static int cmt_measure(const struct user_params *uparams,
struct resctrl_val_param *param, pid_t bm_pid)
{
sleep(1);
return measure_llc_resctrl(param->filename, bm_pid);
}
static int show_results_info(unsigned long sum_llc_val, int no_of_bits,
unsigned long cache_span, unsigned long max_diff,
unsigned long max_diff_percent, unsigned long num_of_runs,
......@@ -126,13 +144,13 @@ static int cmt_run_test(const struct resctrl_test *test, const struct user_param
}
struct resctrl_val_param param = {
.resctrl_val = CMT_STR,
.ctrlgrp = "c1",
.mongrp = "m1",
.filename = RESULT_FILE_NAME,
.mask = ~(long_mask << n) & long_mask,
.num_of_runs = 0,
.init = cmt_init,
.setup = cmt_setup,
.measure = cmt_measure,
};
span = cache_portion_size(cache_total_size, param.mask, long_mask);
......
......@@ -17,6 +17,19 @@
#define ALLOCATION_MIN 10
#define ALLOCATION_STEP 10
static int mba_init(const struct resctrl_val_param *param, int domain_id)
{
int ret;
ret = initialize_mem_bw_imc();
if (ret)
return ret;
initialize_mem_bw_resctrl(param, domain_id);
return 0;
}
/*
* Change schemata percentage from 100 to 10%. Write schemata to specified
* con_mon grp, mon_grp in resctrl FS.
......@@ -51,6 +64,12 @@ static int mba_setup(const struct resctrl_test *test,
return 0;
}
static int mba_measure(const struct user_params *uparams,
struct resctrl_val_param *param, pid_t bm_pid)
{
return measure_mem_bw(uparams, param, bm_pid, "reads");
}
static bool show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc)
{
int allocation, runs;
......@@ -145,12 +164,11 @@ static void mba_test_cleanup(void)
static int mba_run_test(const struct resctrl_test *test, const struct user_params *uparams)
{
struct resctrl_val_param param = {
.resctrl_val = MBA_STR,
.ctrlgrp = "c1",
.mongrp = "m1",
.filename = RESULT_FILE_NAME,
.bw_report = "reads",
.setup = mba_setup
.init = mba_init,
.setup = mba_setup,
.measure = mba_measure,
};
int ret;
......
......@@ -86,6 +86,19 @@ static int check_results(size_t span)
return ret;
}
static int mbm_init(const struct resctrl_val_param *param, int domain_id)
{
int ret;
ret = initialize_mem_bw_imc();
if (ret)
return ret;
initialize_mem_bw_resctrl(param, domain_id);
return 0;
}
static int mbm_setup(const struct resctrl_test *test,
const struct user_params *uparams,
struct resctrl_val_param *p)
......@@ -105,6 +118,12 @@ static int mbm_setup(const struct resctrl_test *test,
return ret;
}
static int mbm_measure(const struct user_params *uparams,
struct resctrl_val_param *param, pid_t bm_pid)
{
return measure_mem_bw(uparams, param, bm_pid, "reads");
}
static void mbm_test_cleanup(void)
{
remove(RESULT_FILE_NAME);
......@@ -113,12 +132,11 @@ static void mbm_test_cleanup(void)
static int mbm_run_test(const struct resctrl_test *test, const struct user_params *uparams)
{
struct resctrl_val_param param = {
.resctrl_val = MBM_STR,
.ctrlgrp = "c1",
.mongrp = "m1",
.filename = RESULT_FILE_NAME,
.bw_report = "reads",
.setup = mbm_setup
.init = mbm_init,
.setup = mbm_setup,
.measure = mbm_measure,
};
int ret;
......
......@@ -43,13 +43,6 @@
#define DEFAULT_SPAN (250 * MB)
#define PARENT_EXIT() \
do { \
kill(ppid, SIGKILL); \
umount_resctrlfs(); \
exit(EXIT_FAILURE); \
} while (0)
/*
* user_params: User supplied parameters
* @cpu: CPU number to which the benchmark will be bound to
......@@ -88,24 +81,27 @@ struct resctrl_test {
/*
* resctrl_val_param: resctrl test parameters
* @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc)
* @ctrlgrp: Name of the control monitor group (con_mon grp)
* @mongrp: Name of the monitor group (mon grp)
* @filename: Name of file to which the o/p should be written
* @bw_report: Bandwidth report type (reads vs writes)
* @setup: Call back function to setup test environment
* @init: Callback function to initialize test environment
* @setup: Callback function to setup per test run environment
* @measure: Callback that performs the measurement (a single test)
*/
struct resctrl_val_param {
char *resctrl_val;
char ctrlgrp[64];
char mongrp[64];
const char *ctrlgrp;
const char *mongrp;
char filename[64];
char *bw_report;
unsigned long mask;
int num_of_runs;
int (*init)(const struct resctrl_val_param *param,
int domain_id);
int (*setup)(const struct resctrl_test *test,
const struct user_params *uparams,
struct resctrl_val_param *param);
int (*measure)(const struct user_params *uparams,
struct resctrl_val_param *param,
pid_t bm_pid);
};
struct perf_event_read {
......@@ -115,11 +111,6 @@ struct perf_event_read {
} values[2];
};
#define MBM_STR "mbm"
#define MBA_STR "mba"
#define CMT_STR "cmt"
#define CAT_STR "cat"
/*
* Memory location that consumes values compiler must not optimize away.
* Volatile ensures writes to this location cannot be optimized away by
......@@ -127,8 +118,6 @@ struct perf_event_read {
*/
extern volatile int *value_sink;
extern pid_t bm_pid, ppid;
extern char llc_occup_path[1024];
int get_vendor(void);
......@@ -137,7 +126,7 @@ int filter_dmesg(void);
int get_domain_id(const char *resource, int cpu_no, int *domain_id);
int mount_resctrlfs(void);
int umount_resctrlfs(void);
int validate_bw_report_request(char *bw_report);
const char *get_bw_report_type(const char *bw_report);
bool resctrl_resource_exists(const char *resource);
bool resctrl_mon_feature_exists(const char *resource, const char *feature);
bool resource_info_file_exists(const char *resource, const char *file);
......@@ -145,15 +134,21 @@ bool test_resource_feature_check(const struct resctrl_test *test);
char *fgrep(FILE *inf, const char *str);
int taskset_benchmark(pid_t bm_pid, int cpu_no, cpu_set_t *old_affinity);
int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity);
int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, const char *resource);
int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
char *resctrl_val);
int write_schemata(const char *ctrlgrp, char *schemata, int cpu_no,
const char *resource);
int write_bm_pid_to_resctrl(pid_t bm_pid, const char *ctrlgrp, const char *mongrp);
int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
int group_fd, unsigned long flags);
unsigned char *alloc_buffer(size_t buf_size, int memflush);
void mem_flush(unsigned char *buf, size_t buf_size);
void fill_cache_read(unsigned char *buf, size_t buf_size, bool once);
int run_fill_buf(size_t buf_size, int memflush, int op, bool once);
int initialize_mem_bw_imc(void);
int measure_mem_bw(const struct user_params *uparams,
struct resctrl_val_param *param, pid_t bm_pid,
const char *bw_report);
void initialize_mem_bw_resctrl(const struct resctrl_val_param *param,
int domain_id);
int resctrl_val(const struct resctrl_test *test,
const struct user_params *uparams,
const char * const *benchmark_cmd,
......@@ -174,8 +169,8 @@ void perf_event_initialize_read_format(struct perf_event_read *pe_read);
int perf_open(struct perf_event_attr *pea, pid_t pid, int cpu_no);
int perf_event_reset_enable(int pe_fd);
int perf_event_measure(int pe_fd, struct perf_event_read *pe_read,
const char *filename, int bm_pid);
int measure_llc_resctrl(const char *filename, int bm_pid);
const char *filename, pid_t bm_pid);
int measure_llc_resctrl(const char *filename, pid_t bm_pid);
void show_cache_info(int no_of_bits, __u64 avg_llc_val, size_t cache_span, bool lines);
/*
......
......@@ -19,30 +19,10 @@
#define MAX_TOKENS 5
#define READ 0
#define WRITE 1
#define CON_MON_MBM_LOCAL_BYTES_PATH \
"%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
#define CON_MBM_LOCAL_BYTES_PATH \
"%s/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
#define MON_MBM_LOCAL_BYTES_PATH \
"%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
#define MBM_LOCAL_BYTES_PATH \
"%s/mon_data/mon_L3_%02d/mbm_local_bytes"
#define CON_MON_LCC_OCCUP_PATH \
"%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
#define CON_LCC_OCCUP_PATH \
"%s/%s/mon_data/mon_L3_%02d/llc_occupancy"
#define MON_LCC_OCCUP_PATH \
"%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
#define LCC_OCCUP_PATH \
"%s/mon_data/mon_L3_%02d/llc_occupancy"
struct membw_read_format {
__u64 value; /* The value of the event */
__u64 time_enabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
......@@ -276,7 +256,7 @@ static int num_of_imcs(void)
return count;
}
static int initialize_mem_bw_imc(void)
int initialize_mem_bw_imc(void)
{
int imc, j;
......@@ -293,44 +273,93 @@ static int initialize_mem_bw_imc(void)
return 0;
}
static void perf_close_imc_mem_bw(void)
{
int mc;
for (mc = 0; mc < imcs; mc++) {
if (imc_counters_config[mc][READ].fd != -1)
close(imc_counters_config[mc][READ].fd);
if (imc_counters_config[mc][WRITE].fd != -1)
close(imc_counters_config[mc][WRITE].fd);
}
}
/*
* 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.
* perf_open_imc_mem_bw - Open perf fds for IMCs
* @cpu_no: CPU number that the benchmark PID is bound to
*
* Return: = 0 on success. < 0 on failure.
*/
static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc)
static int perf_open_imc_mem_bw(int cpu_no)
{
float reads, writes, of_mul_read, of_mul_write;
int imc, j, ret;
int imc, ret;
for (imc = 0; imc < imcs; imc++) {
imc_counters_config[imc][READ].fd = -1;
imc_counters_config[imc][WRITE].fd = -1;
}
/* Start all iMC counters to log values (both read and write) */
reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1;
for (imc = 0; imc < imcs; imc++) {
for (j = 0; j < 2; j++) {
ret = open_perf_event(imc, cpu_no, j);
ret = open_perf_event(imc, cpu_no, READ);
if (ret)
return -1;
goto close_fds;
ret = open_perf_event(imc, cpu_no, WRITE);
if (ret)
goto close_fds;
}
for (j = 0; j < 2; j++)
membw_ioctl_perf_event_ioc_reset_enable(imc, j);
return 0;
close_fds:
perf_close_imc_mem_bw();
return -1;
}
/*
* do_mem_bw_test - Perform memory bandwidth test
*
* Runs memory bandwidth test over one second period. Also, handles starting
* and stopping of the IMC perf counters around the test.
*/
static void do_imc_mem_bw_test(void)
{
int imc;
for (imc = 0; imc < imcs; imc++) {
membw_ioctl_perf_event_ioc_reset_enable(imc, READ);
membw_ioctl_perf_event_ioc_reset_enable(imc, WRITE);
}
sleep(1);
/* Stop counters after a second to get results (both read and write) */
for (imc = 0; imc < imcs; imc++) {
for (j = 0; j < 2; j++)
membw_ioctl_perf_event_ioc_disable(imc, j);
membw_ioctl_perf_event_ioc_disable(imc, READ);
membw_ioctl_perf_event_ioc_disable(imc, WRITE);
}
}
/*
* get_mem_bw_imc - Memory bandwidth as reported by iMC counters
* @bw_report: Bandwidth report type (reads, writes)
*
* Memory bandwidth utilized by a process on a socket can be calculated
* using iMC counters. Perf events are used to read these counters.
*
* Return: = 0 on success. < 0 on failure.
*/
static int get_mem_bw_imc(const char *bw_report, float *bw_imc)
{
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;
/*
* Get results which are stored in struct type imc_counter_config
* Take over flow into consideration before calculating total b/w
* Take overflow into consideration before calculating total bandwidth.
*/
for (imc = 0; imc < imcs; imc++) {
struct imc_counter_config *r =
......@@ -340,15 +369,13 @@ static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc)
if (read(r->fd, &r->return_value,
sizeof(struct membw_read_format)) == -1) {
ksft_perror("Couldn't get read b/w through iMC");
ksft_perror("Couldn't get read bandwidth through iMC");
return -1;
}
if (read(w->fd, &w->return_value,
sizeof(struct membw_read_format)) == -1) {
ksft_perror("Couldn't get write bw through iMC");
ksft_perror("Couldn't get write bandwidth through iMC");
return -1;
}
......@@ -369,11 +396,6 @@ static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc)
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) {
*bw_imc = reads;
return 0;
......@@ -388,84 +410,45 @@ static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc)
return 0;
}
void set_mbm_path(const char *ctrlgrp, const char *mongrp, int domain_id)
/*
* initialize_mem_bw_resctrl: Appropriately populate "mbm_total_path"
* @param: Parameters passed to resctrl_val()
* @domain_id: Domain ID (cache ID; for MB, L3 cache ID)
*/
void initialize_mem_bw_resctrl(const struct resctrl_val_param *param,
int domain_id)
{
if (ctrlgrp && mongrp)
sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH,
RESCTRL_PATH, ctrlgrp, mongrp, domain_id);
else if (!ctrlgrp && mongrp)
sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
mongrp, domain_id);
else if (ctrlgrp && !mongrp)
sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
ctrlgrp, domain_id);
else if (!ctrlgrp && !mongrp)
sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
domain_id);
param->ctrlgrp, domain_id);
}
/*
* initialize_mem_bw_resctrl: Appropriately populate "mbm_total_path"
* @ctrlgrp: Name of the control monitor group (con_mon grp)
* @mongrp: Name of the monitor group (mon grp)
* @cpu_no: CPU number that the benchmark PID is binded to
* @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc)
* Open file to read MBM local bytes from resctrl FS
*/
static void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp,
int cpu_no, char *resctrl_val)
static FILE *open_mem_bw_resctrl(const char *mbm_bw_file)
{
int domain_id;
if (get_domain_id("MB", cpu_no, &domain_id) < 0) {
ksft_print_msg("Could not get domain ID\n");
return;
}
FILE *fp;
if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)))
set_mbm_path(ctrlgrp, mongrp, domain_id);
fp = fopen(mbm_bw_file, "r");
if (!fp)
ksft_perror("Failed to open total memory bandwidth file");
if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
if (ctrlgrp)
sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH,
RESCTRL_PATH, ctrlgrp, domain_id);
else
sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH,
RESCTRL_PATH, domain_id);
}
return fp;
}
/*
* Get MBM Local bytes as reported by resctrl FS
* For MBM,
* 1. If con_mon grp and mon grp are given, then read from con_mon grp's mon grp
* 2. If only con_mon grp is given, then read from con_mon grp
* 3. If both are not given, then read from root con_mon grp
* For MBA,
* 1. If con_mon grp is given, then read from it
* 2. If con_mon grp is not given, then read from root con_mon grp
*/
static int get_mem_bw_resctrl(unsigned long *mbm_total)
static int get_mem_bw_resctrl(FILE *fp, unsigned long *mbm_total)
{
FILE *fp;
fp = fopen(mbm_total_path, "r");
if (!fp) {
ksft_perror("Failed to open total bw file");
if (fscanf(fp, "%lu\n", mbm_total) <= 0) {
ksft_perror("Could not get MBM local bytes");
return -1;
}
if (fscanf(fp, "%lu", mbm_total) <= 0) {
ksft_perror("Could not get mbm local bytes");
fclose(fp);
return -1;
}
fclose(fp);
return 0;
}
pid_t bm_pid, ppid;
static pid_t bm_pid, ppid;
void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
{
......@@ -523,6 +506,13 @@ void signal_handler_unregister(void)
}
}
static void parent_exit(pid_t ppid)
{
kill(ppid, SIGKILL);
umount_resctrlfs();
exit(EXIT_FAILURE);
}
/*
* print_results_bw: the memory bandwidth results are stored in a file
* @filename: file that stores the results
......@@ -532,14 +522,14 @@ void signal_handler_unregister(void)
*
* Return: 0 on success, < 0 on error.
*/
static int print_results_bw(char *filename, int bm_pid, float bw_imc,
static int print_results_bw(char *filename, pid_t bm_pid, float bw_imc,
unsigned long bw_resc)
{
unsigned long diff = fabs(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("Pid: %d \t Mem_BW_iMC: %f \t ", (int)bm_pid, bw_imc);
printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff);
} else {
fp = fopen(filename, "a");
......@@ -549,7 +539,7 @@ static int print_results_bw(char *filename, int bm_pid, float bw_imc,
return -1;
}
if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n",
bm_pid, bw_imc, bw_resc, diff) <= 0) {
(int)bm_pid, bw_imc, bw_resc, diff) <= 0) {
ksft_print_msg("Could not log results\n");
fclose(fp);
......@@ -561,73 +551,67 @@ static int print_results_bw(char *filename, int bm_pid, float bw_imc,
return 0;
}
static void set_cmt_path(const char *ctrlgrp, const char *mongrp, char sock_num)
{
if (strlen(ctrlgrp) && strlen(mongrp))
sprintf(llc_occup_path, CON_MON_LCC_OCCUP_PATH, RESCTRL_PATH,
ctrlgrp, mongrp, sock_num);
else if (!strlen(ctrlgrp) && strlen(mongrp))
sprintf(llc_occup_path, MON_LCC_OCCUP_PATH, RESCTRL_PATH,
mongrp, sock_num);
else if (strlen(ctrlgrp) && !strlen(mongrp))
sprintf(llc_occup_path, CON_LCC_OCCUP_PATH, RESCTRL_PATH,
ctrlgrp, sock_num);
else if (!strlen(ctrlgrp) && !strlen(mongrp))
sprintf(llc_occup_path, LCC_OCCUP_PATH, RESCTRL_PATH, sock_num);
}
/*
* initialize_llc_occu_resctrl: Appropriately populate "llc_occup_path"
* @ctrlgrp: Name of the control monitor group (con_mon grp)
* @mongrp: Name of the monitor group (mon grp)
* @cpu_no: CPU number that the benchmark PID is binded to
* @resctrl_val: Resctrl feature (Eg: cat, cmt.. etc)
* measure_mem_bw - Measures memory bandwidth numbers while benchmark runs
* @uparams: User supplied parameters
* @param: Parameters passed to resctrl_val()
* @bm_pid: PID that runs the benchmark
* @bw_report: Bandwidth report type (reads, writes)
*
* Measure memory bandwidth from resctrl and from another source which is
* perf imc value or could be something else if perf imc event is not
* available. Compare the two values to validate resctrl value. It takes
* 1 sec to measure the data.
*/
static void initialize_llc_occu_resctrl(const char *ctrlgrp, const char *mongrp,
int cpu_no, char *resctrl_val)
int measure_mem_bw(const struct user_params *uparams,
struct resctrl_val_param *param, pid_t bm_pid,
const char *bw_report)
{
int domain_id;
unsigned long bw_resc, bw_resc_start, bw_resc_end;
FILE *mem_bw_fp;
float bw_imc;
int ret;
if (get_domain_id("L3", cpu_no, &domain_id) < 0) {
ksft_print_msg("Could not get domain ID\n");
return;
}
bw_report = get_bw_report_type(bw_report);
if (!bw_report)
return -1;
if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
set_cmt_path(ctrlgrp, mongrp, domain_id);
}
mem_bw_fp = open_mem_bw_resctrl(mbm_total_path);
if (!mem_bw_fp)
return -1;
static int measure_vals(const struct user_params *uparams,
struct resctrl_val_param *param,
unsigned long *bw_resc_start)
{
unsigned long bw_resc, bw_resc_end;
float bw_imc;
int ret;
ret = perf_open_imc_mem_bw(uparams->cpu);
if (ret < 0)
goto close_fp;
/*
* Measure memory bandwidth from resctrl and from
* another source which is perf imc value or could
* be something else if perf imc event is not available.
* Compare the two values to validate resctrl value.
* It takes 1sec to measure the data.
*/
ret = get_mem_bw_imc(uparams->cpu, param->bw_report, &bw_imc);
ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_start);
if (ret < 0)
return ret;
goto close_imc;
rewind(mem_bw_fp);
do_imc_mem_bw_test();
ret = get_mem_bw_resctrl(&bw_resc_end);
ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_end);
if (ret < 0)
return ret;
goto close_imc;
bw_resc = (bw_resc_end - *bw_resc_start) / MB;
ret = print_results_bw(param->filename, bm_pid, bw_imc, bw_resc);
if (ret)
return ret;
ret = get_mem_bw_imc(bw_report, &bw_imc);
if (ret < 0)
goto close_imc;
*bw_resc_start = bw_resc_end;
perf_close_imc_mem_bw();
fclose(mem_bw_fp);
return 0;
bw_resc = (bw_resc_end - bw_resc_start) / MB;
return print_results_bw(param->filename, bm_pid, bw_imc, bw_resc);
close_imc:
perf_close_imc_mem_bw();
close_fp:
fclose(mem_bw_fp);
return ret;
}
/*
......@@ -654,7 +638,7 @@ static void run_benchmark(int signum, siginfo_t *info, void *ucontext)
fp = freopen("/dev/null", "w", stdout);
if (!fp) {
ksft_perror("Unable to direct benchmark status to /dev/null");
PARENT_EXIT();
parent_exit(ppid);
}
if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
......@@ -668,7 +652,7 @@ static void run_benchmark(int signum, siginfo_t *info, void *ucontext)
once = false;
} else {
ksft_print_msg("Invalid once parameter\n");
PARENT_EXIT();
parent_exit(ppid);
}
if (run_fill_buf(span, memflush, operation, once))
......@@ -682,7 +666,7 @@ static void run_benchmark(int signum, siginfo_t *info, void *ucontext)
fclose(stdout);
ksft_print_msg("Unable to run specified benchmark\n");
PARENT_EXIT();
parent_exit(ppid);
}
/*
......@@ -700,20 +684,18 @@ int resctrl_val(const struct resctrl_test *test,
const char * const *benchmark_cmd,
struct resctrl_val_param *param)
{
char *resctrl_val = param->resctrl_val;
unsigned long bw_resc_start = 0;
struct sigaction sigact;
int ret = 0, pipefd[2];
char pipe_message = 0;
union sigval value;
int domain_id;
if (strcmp(param->filename, "") == 0)
sprintf(param->filename, "stdio");
if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) ||
!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) {
ret = validate_bw_report_request(param->bw_report);
if (ret)
ret = get_domain_id(test->resource, uparams->cpu, &domain_id);
if (ret < 0) {
ksft_print_msg("Could not get domain ID\n");
return ret;
}
......@@ -755,7 +737,7 @@ int resctrl_val(const struct resctrl_test *test,
/* Register for "SIGUSR1" signal from parent */
if (sigaction(SIGUSR1, &sigact, NULL)) {
ksft_perror("Can't register child for signal");
PARENT_EXIT();
parent_exit(ppid);
}
/* Tell parent that child is ready */
......@@ -773,10 +755,10 @@ int resctrl_val(const struct resctrl_test *test,
sigsuspend(&sigact.sa_mask);
ksft_perror("Child is done");
PARENT_EXIT();
parent_exit(ppid);
}
ksft_print_msg("Benchmark PID: %d\n", bm_pid);
ksft_print_msg("Benchmark PID: %d\n", (int)bm_pid);
/*
* The cast removes constness but nothing mutates benchmark_cmd within
......@@ -792,22 +774,15 @@ int resctrl_val(const struct resctrl_test *test,
goto out;
/* Write benchmark to specified control&monitoring grp in resctrl FS */
ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
resctrl_val);
ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp);
if (ret)
goto out;
if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
ret = initialize_mem_bw_imc();
if (param->init) {
ret = param->init(param, domain_id);
if (ret)
goto out;
initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
uparams->cpu, resctrl_val);
} else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
initialize_llc_occu_resctrl(param->ctrlgrp, param->mongrp,
uparams->cpu, resctrl_val);
}
/* Parent waits for child to be ready. */
close(pipefd[1]);
......@@ -841,17 +816,9 @@ int resctrl_val(const struct resctrl_test *test,
if (ret < 0)
break;
if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
ret = measure_vals(uparams, param, &bw_resc_start);
ret = param->measure(uparams, param, bm_pid);
if (ret)
break;
} else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) {
sleep(1);
ret = measure_llc_resctrl(param->filename, bm_pid);
if (ret)
break;
}
}
out:
......
......@@ -456,6 +456,9 @@ int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity)
* @grp: Full path and name of the group
* @parent_grp: Full path and name of the parent group
*
* Creates a group @grp_name if it does not exist yet. If @grp_name is NULL,
* it is interpreted as the root group which always results in success.
*
* Return: 0 on success, < 0 on error.
*/
static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
......@@ -464,12 +467,7 @@ static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
struct dirent *ep;
DIR *dp;
/*
* At this point, we are guaranteed to have resctrl FS mounted and if
* length of grp_name == 0, it means, user wants to use root con_mon
* grp, so do nothing
*/
if (strlen(grp_name) == 0)
if (!grp_name)
return 0;
/* Check if requested grp exists or not */
......@@ -508,7 +506,7 @@ static int write_pid_to_tasks(char *tasks, pid_t pid)
return -1;
}
if (fprintf(fp, "%d\n", pid) < 0) {
if (fprintf(fp, "%d\n", (int)pid) < 0) {
ksft_print_msg("Failed to write pid to tasks file\n");
fclose(fp);
......@@ -524,7 +522,6 @@ static int write_pid_to_tasks(char *tasks, pid_t pid)
* @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.
......@@ -534,14 +531,13 @@ static int write_pid_to_tasks(char *tasks, pid_t pid)
*
* Return: 0 on success, < 0 on error.
*/
int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
char *resctrl_val)
int write_bm_pid_to_resctrl(pid_t bm_pid, const char *ctrlgrp, const char *mongrp)
{
char controlgroup[128], monitorgroup[512], monitorgroup_p[256];
char tasks[1024];
int ret = 0;
if (strlen(ctrlgrp))
if (ctrlgrp)
sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
else
sprintf(controlgroup, "%s", RESCTRL_PATH);
......@@ -555,10 +551,8 @@ int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
if (ret)
goto out;
/* Create mon grp and write pid into it for "mbm" and "cmt" test */
if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)) ||
!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) {
if (strlen(mongrp)) {
/* Create monitor group and write pid into if it is used */
if (mongrp) {
sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
......@@ -571,7 +565,6 @@ int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
if (ret)
goto out;
}
}
out:
ksft_print_msg("Writing benchmark parameters to resctrl FS\n");
......@@ -593,7 +586,8 @@ int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
*
* Return: 0 on success, < 0 on error.
*/
int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, const char *resource)
int write_schemata(const char *ctrlgrp, char *schemata, int cpu_no,
const char *resource)
{
char controlgroup[1024], reason[128], schema[1024] = {};
int domain_id, fd, schema_len, ret = 0;
......@@ -611,7 +605,7 @@ int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, const char *resour
goto out;
}
if (strlen(ctrlgrp) != 0)
if (ctrlgrp)
sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH, ctrlgrp);
else
sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
......@@ -837,22 +831,21 @@ int filter_dmesg(void)
return 0;
}
int validate_bw_report_request(char *bw_report)
const char *get_bw_report_type(const char *bw_report)
{
if (strcmp(bw_report, "reads") == 0)
return 0;
return bw_report;
if (strcmp(bw_report, "writes") == 0)
return 0;
return bw_report;
if (strcmp(bw_report, "nt-writes") == 0) {
strcpy(bw_report, "writes");
return 0;
return "writes";
}
if (strcmp(bw_report, "total") == 0)
return 0;
return bw_report;
fprintf(stderr, "Requested iMC B/W report type unavailable\n");
fprintf(stderr, "Requested iMC bandwidth report type unavailable\n");
return -1;
return NULL;
}
int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
......
......@@ -42,11 +42,11 @@ static pid_t gettid(void)
#ifndef PR_SCHED_CORE
#define PR_SCHED_CORE 62
# define PR_SCHED_CORE_GET 0
# define PR_SCHED_CORE_CREATE 1 /* create unique core_sched cookie */
# define PR_SCHED_CORE_SHARE_TO 2 /* push core_sched cookie to pid */
# define PR_SCHED_CORE_SHARE_FROM 3 /* pull core_sched cookie to pid */
# define PR_SCHED_CORE_MAX 4
#define PR_SCHED_CORE_GET 0
#define PR_SCHED_CORE_CREATE 1 /* create unique core_sched cookie */
#define PR_SCHED_CORE_SHARE_TO 2 /* push core_sched cookie to pid */
#define PR_SCHED_CORE_SHARE_FROM 3 /* pull core_sched cookie to pid */
#define PR_SCHED_CORE_MAX 4
#endif
#define MAX_PROCESSES 128
......
......@@ -29,7 +29,7 @@ static const char default_rtc[] = "/dev/rtc0";
int main(int argc, char **argv)
{
int i, fd, retval, irqcount = 0;
int i, fd, retval;
unsigned long tmp, data, old_pie_rate;
const char *rtc = default_rtc;
struct timeval start, end, diff;
......@@ -120,7 +120,6 @@ int main(int argc, char **argv)
fprintf(stderr, " %d",i);
fflush(stderr);
irqcount++;
}
/* Disable periodic interrupts */
......
......@@ -40,6 +40,13 @@ CFLAGS := -O2 -g -std=gnu99 -pthread -Wall $(KHDR_INCLUDES)
# call32_from_64 in thunks.S uses absolute addresses.
ifeq ($(CAN_BUILD_WITH_NOPIE),1)
CFLAGS += -no-pie
ifneq ($(LLVM),)
# clang only wants to see -no-pie during linking. Here, we don't have a separate
# linking stage, so a compiler warning is unavoidable without (wastefully)
# restructuring the Makefile. Avoid this by simply disabling that warning.
CFLAGS += -Wno-unused-command-line-argument
endif
endif
define gen-target-rule-32
......@@ -73,10 +80,10 @@ all_64: $(BINARIES_64)
EXTRA_CLEAN := $(BINARIES_32) $(BINARIES_64)
$(BINARIES_32): $(OUTPUT)/%_32: %.c helpers.h
$(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -lm
$(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $< $(EXTRA_FILES) -lrt -ldl -lm
$(BINARIES_64): $(OUTPUT)/%_64: %.c helpers.h
$(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
$(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $< $(EXTRA_FILES) -lrt -ldl
# x86_64 users should be encouraged to install 32-bit libraries
ifeq ($(CAN_BUILD_I386)$(CAN_BUILD_X86_64),01)
......@@ -100,10 +107,22 @@ warn_32bit_failure:
exit 0;
endif
# Some tests have additional dependencies.
$(OUTPUT)/sysret_ss_attrs_64: thunks.S
$(OUTPUT)/ptrace_syscall_32: raw_syscall_helper_32.S
$(OUTPUT)/test_syscall_vdso_32: thunks_32.S
# Add an additional file to the source file list for a given target, and also
# add a Makefile dependency on that same file. However, do these separately, so
# that the compiler invocation ("$(CC) file1.c file2.S") is not combined with
# the dependencies ("header3.h"), because clang, unlike gcc, will not accept
# header files as an input to the compiler invocation.
define extra-files
$(OUTPUT)/$(1): EXTRA_FILES := $(2)
$(OUTPUT)/$(1): $(2)
endef
$(eval $(call extra-files,sysret_ss_attrs_64,thunks.S))
$(eval $(call extra-files,ptrace_syscall_32,raw_syscall_helper_32.S))
$(eval $(call extra-files,test_syscall_vdso_32,thunks_32.S))
$(eval $(call extra-files,fsgsbase_restore_64,clang_helpers_64.S))
$(eval $(call extra-files,fsgsbase_restore_32,clang_helpers_32.S))
$(eval $(call extra-files,sysret_rip_64,clang_helpers_64.S))
# check_initial_reg_state is special: it needs a custom entry, and it
# needs to be static so that its interpreter doesn't destroy its initial
......
......@@ -39,16 +39,6 @@ struct xsave_buffer {
};
};
static inline uint64_t xgetbv(uint32_t index)
{
uint32_t eax, edx;
asm volatile("xgetbv;"
: "=a" (eax), "=d" (edx)
: "c" (index));
return eax + ((uint64_t)edx << 32);
}
static inline void xsave(struct xsave_buffer *xbuf, uint64_t rfbm)
{
uint32_t rfbm_lo = rfbm;
......@@ -164,12 +154,6 @@ static inline void clear_xstate_header(struct xsave_buffer *buffer)
memset(&buffer->header, 0, sizeof(buffer->header));
}
static inline uint64_t get_xstatebv(struct xsave_buffer *buffer)
{
/* XSTATE_BV is at the beginning of the header: */
return *(uint64_t *)&buffer->header;
}
static inline void set_xstatebv(struct xsave_buffer *buffer, uint64_t bv)
{
/* XSTATE_BV is at the beginning of the header: */
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 32-bit assembly helpers for asm operations that lack support in both gcc and
* clang. For example, clang asm does not support segment prefixes.
*/
.global dereference_seg_base
dereference_seg_base:
mov %fs:(0), %eax
ret
.section .note.GNU-stack,"",%progbits
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 64-bit assembly helpers for asm operations that lack support in both gcc and
* clang. For example, clang asm does not support segment prefixes.
*/
.global dereference_seg_base
dereference_seg_base:
mov %gs:(0), %rax
ret
.global test_page
.global test_syscall_insn
.pushsection ".text", "ax"
.balign 4096
test_page: .globl test_page
.fill 4094,1,0xcc
test_syscall_insn:
syscall
.ifne . - test_page - 4096
.error "test page is not one page long"
.endif
.popsection
.section .note.GNU-stack,"",%progbits
......@@ -109,11 +109,6 @@ static inline void wrgsbase(unsigned long gsbase)
asm volatile("wrgsbase %0" :: "r" (gsbase) : "memory");
}
static inline void wrfsbase(unsigned long fsbase)
{
asm volatile("wrfsbase %0" :: "r" (fsbase) : "memory");
}
enum which_base { FS, GS };
static unsigned long read_base(enum which_base which)
......@@ -212,7 +207,6 @@ static void mov_0_gs(unsigned long initial_base, bool schedule)
}
static volatile unsigned long remote_base;
static volatile bool remote_hard_zero;
static volatile unsigned int ftx;
/*
......
......@@ -39,12 +39,11 @@
# define SEG "%fs"
#endif
static unsigned int dereference_seg_base(void)
{
int ret;
asm volatile ("mov %" SEG ":(0), %0" : "=rm" (ret));
return ret;
}
/*
* Defined in clang_helpers_[32|64].S, because unlike gcc, clang inline asm does
* not support segmentation prefixes.
*/
unsigned int dereference_seg_base(void);
static void init_seg(void)
{
......
......@@ -487,7 +487,7 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
greg_t asm_ss = ctx->uc_mcontext.gregs[REG_CX];
if (asm_ss != sig_ss && sig == SIGTRAP) {
/* Sanity check failure. */
printf("[FAIL]\tSIGTRAP: ss = %hx, frame ss = %hx, ax = %llx\n",
printf("[FAIL]\tSIGTRAP: ss = %hx, frame ss = %x, ax = %llx\n",
ss, *ssptr(ctx), (unsigned long long)asm_ss);
nerrs++;
}
......
......@@ -29,7 +29,6 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
err(1, "sigaction");
}
static volatile sig_atomic_t sig_traps;
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t n_errs;
......
......@@ -22,21 +22,13 @@
#include <sys/mman.h>
#include <assert.h>
asm (
".pushsection \".text\", \"ax\"\n\t"
".balign 4096\n\t"
"test_page: .globl test_page\n\t"
".fill 4094,1,0xcc\n\t"
"test_syscall_insn:\n\t"
"syscall\n\t"
".ifne . - test_page - 4096\n\t"
".error \"test page is not one page long\"\n\t"
".endif\n\t"
".popsection"
);
/*
* These items are in clang_helpers_64.S, in order to avoid clang inline asm
* limitations:
*/
void test_syscall_ins(void);
extern const char test_page[];
static void const *current_test_page_addr = test_page;
static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
......
......@@ -25,7 +25,7 @@ int test(void)
feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
asm volatile ("\n"
" fld1""\n"
" fisttp res16""\n"
" fisttps res16""\n"
" fld1""\n"
" fisttpl res32""\n"
" fld1""\n"
......@@ -45,7 +45,7 @@ int test(void)
feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
asm volatile ("\n"
" fldpi""\n"
" fisttp res16""\n"
" fisttps res16""\n"
" fldpi""\n"
" fisttpl res32""\n"
" fldpi""\n"
......@@ -66,7 +66,7 @@ int test(void)
asm volatile ("\n"
" fldpi""\n"
" fchs""\n"
" fisttp res16""\n"
" fisttps res16""\n"
" fldpi""\n"
" fchs""\n"
" fisttpl res32""\n"
......@@ -88,7 +88,7 @@ int test(void)
feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
asm volatile ("\n"
" fldln2""\n"
" fisttp res16""\n"
" fisttps res16""\n"
" fldln2""\n"
" fisttpl res32""\n"
" fldln2""\n"
......
......@@ -97,11 +97,6 @@ static inline long sys_gtod(struct timeval *tv, struct timezone *tz)
return syscall(SYS_gettimeofday, tv, tz);
}
static inline int sys_clock_gettime(clockid_t id, struct timespec *ts)
{
return syscall(SYS_clock_gettime, id, ts);
}
static inline long sys_time(time_t *t)
{
return syscall(SYS_time, t);
......@@ -252,7 +247,7 @@ static void test_getcpu(int cpu)
if (ret_sys == 0) {
if (cpu_sys != cpu)
ksft_print_msg("syscall reported CPU %hu but should be %d\n",
ksft_print_msg("syscall reported CPU %u but should be %d\n",
cpu_sys, cpu);
have_node = true;
......@@ -270,10 +265,10 @@ static void test_getcpu(int cpu)
if (cpu_vdso != cpu || node_vdso != node) {
if (cpu_vdso != cpu)
ksft_print_msg("vDSO reported CPU %hu but should be %d\n",
ksft_print_msg("vDSO reported CPU %u but should be %d\n",
cpu_vdso, cpu);
if (node_vdso != node)
ksft_print_msg("vDSO reported node %hu but should be %hu\n",
ksft_print_msg("vDSO reported node %u but should be %u\n",
node_vdso, node);
ksft_test_result_fail("Wrong values\n");
} else {
......@@ -295,10 +290,10 @@ static void test_getcpu(int cpu)
if (cpu_vsys != cpu || node_vsys != node) {
if (cpu_vsys != cpu)
ksft_print_msg("vsyscall reported CPU %hu but should be %d\n",
ksft_print_msg("vsyscall reported CPU %u but should be %d\n",
cpu_vsys, cpu);
if (node_vsys != node)
ksft_print_msg("vsyscall reported node %hu but should be %hu\n",
ksft_print_msg("vsyscall reported node %u but should be %u\n",
node_vsys, node);
ksft_test_result_fail("Wrong values\n");
} else {
......
......@@ -92,4 +92,6 @@ int main()
printf("[FAIL]\t!SA_SIGINFO handler was not called\n");
nerrs++;
}
return nerrs;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment