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
  ...
This commit is contained in:
Linus Torvalds
2024-07-16 17:45:33 -07:00
30 changed files with 901 additions and 358 deletions

View File

@@ -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

View File

@@ -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 = {};

View File

@@ -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) {

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for ifs(In Field Scan) selftests
TEST_PROGS := test_ifs.sh
include ../../../../../lib.mk

View File

@@ -0,0 +1,494 @@
#!/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

View File

@@ -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

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
/*

View File

@@ -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;
/* Start all iMC counters to log values (both read and write) */
reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1;
for (imc = 0; imc < imcs; imc++) {
for (j = 0; j < 2; j++) {
ret = open_perf_event(imc, cpu_no, j);
if (ret)
return -1;
}
for (j = 0; j < 2; j++)
membw_ioctl_perf_event_ioc_reset_enable(imc, j);
imc_counters_config[imc][READ].fd = -1;
imc_counters_config[imc][WRITE].fd = -1;
}
for (imc = 0; imc < imcs; imc++) {
ret = open_perf_event(imc, cpu_no, READ);
if (ret)
goto close_fds;
ret = open_perf_event(imc, cpu_no, WRITE);
if (ret)
goto close_fds;
}
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);
sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
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;
FILE *fp;
if (get_domain_id("MB", cpu_no, &domain_id) < 0) {
ksft_print_msg("Could not get domain ID\n");
return;
}
fp = fopen(mbm_bw_file, "r");
if (!fp)
ksft_perror("Failed to open total memory bandwidth file");
if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)))
set_mbm_path(ctrlgrp, mongrp, domain_id);
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;
if (get_domain_id("L3", cpu_no, &domain_id) < 0) {
ksft_print_msg("Could not get domain ID\n");
return;
}
if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
set_cmt_path(ctrlgrp, mongrp, domain_id);
}
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;
unsigned long bw_resc, bw_resc_start, bw_resc_end;
FILE *mem_bw_fp;
float bw_imc;
int ret;
/*
* Measure memory bandwidth from resctrl and from
* another source which is perf imc value or could
* be something else if perf imc event is not available.
* Compare the two values to validate resctrl value.
* It takes 1sec to measure the data.
*/
ret = get_mem_bw_imc(uparams->cpu, param->bw_report, &bw_imc);
bw_report = get_bw_report_type(bw_report);
if (!bw_report)
return -1;
mem_bw_fp = open_mem_bw_resctrl(mbm_total_path);
if (!mem_bw_fp)
return -1;
ret = perf_open_imc_mem_bw(uparams->cpu);
if (ret < 0)
return ret;
goto close_fp;
ret = get_mem_bw_resctrl(&bw_resc_end);
ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_start);
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;
rewind(mem_bw_fp);
*bw_resc_start = bw_resc_end;
do_imc_mem_bw_test();
return 0;
ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_end);
if (ret < 0)
goto close_imc;
ret = get_mem_bw_imc(bw_report, &bw_imc);
if (ret < 0)
goto close_imc;
perf_close_imc_mem_bw();
fclose(mem_bw_fp);
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,21 +684,19 @@ 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)
return 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);
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;
}
ret = param->measure(uparams, param, bm_pid);
if (ret)
break;
}
out:

View File

@@ -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,22 +551,19 @@ 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)) {
sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
if (ret)
goto out;
/* 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);
if (ret)
goto out;
sprintf(tasks, "%s/mon_groups/%s/tasks",
controlgroup, mongrp);
ret = write_pid_to_tasks(tasks, bm_pid);
if (ret)
goto out;
}
sprintf(tasks, "%s/mon_groups/%s/tasks",
controlgroup, mongrp);
ret = write_pid_to_tasks(tasks, bm_pid);
if (ret)
goto out;
}
out:
@@ -593,7 +586,8 @@ out:
*
* 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,

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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: */

View File

@@ -0,0 +1,11 @@
/* 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

View File

@@ -0,0 +1,28 @@
/* 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

View File

@@ -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;
/*

View File

@@ -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)
{

View File

@@ -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++;
}

View File

@@ -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;

View File

@@ -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 *),

View File

@@ -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"

View File

@@ -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 {

View File

@@ -92,4 +92,6 @@ int main()
printf("[FAIL]\t!SA_SIGINFO handler was not called\n");
nerrs++;
}
return nerrs;
}