From 34ff636f322c6d5e4f0a52338fa63a7dff09a495 Mon Sep 17 00:00:00 2001 From: Joel Fernandes Date: Sat, 18 Jul 2026 13:15:36 -0400 Subject: scftorture: Count single_rpc offline failures in statistics output scf_torture_stats_print() aggregates each invoker thread's counters into a local scf_statistics structure before printing, but the n_single_rpc_ofl field is missing from the aggregation loop. As a result, the "single_rpc_ofl" value printed in the statistics line is always zero, even when smp_call_function_single() invocations for the RPC test have failed due to offline CPUs and been counted by the invoker threads. Add the missing accumulation so that the printed value reflects the actual counts. Signed-off-by: Joel Fernandes Signed-off-by: Paul E. McKenney --- tools/leds/.gitignore | 2 + tools/leds/Makefile | 13 +++ tools/leds/get_led_device_info.sh | 201 +++++++++++++++++++++++++++++++++++++ tools/leds/led_hw_brightness_mon.c | 85 ++++++++++++++++ tools/leds/uledmon.c | 64 ++++++++++++ 5 files changed, 365 insertions(+) create mode 100644 tools/leds/.gitignore create mode 100644 tools/leds/Makefile create mode 100755 tools/leds/get_led_device_info.sh create mode 100644 tools/leds/led_hw_brightness_mon.c create mode 100644 tools/leds/uledmon.c (limited to 'tools/leds') diff --git a/tools/leds/.gitignore b/tools/leds/.gitignore new file mode 100644 index 000000000..06bd3ee1b --- /dev/null +++ b/tools/leds/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +uledmon diff --git a/tools/leds/Makefile b/tools/leds/Makefile new file mode 100644 index 000000000..7b6bed13d --- /dev/null +++ b/tools/leds/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 +# Makefile for LEDs tools + +CFLAGS = -Wall -Wextra -g -I../../include/uapi + +all: uledmon led_hw_brightness_mon +%: %.c + $(CC) $(CFLAGS) -o $@ $^ + +clean: + $(RM) uledmon led_hw_brightness_mon + +.PHONY: all clean diff --git a/tools/leds/get_led_device_info.sh b/tools/leds/get_led_device_info.sh new file mode 100755 index 000000000..ccfa442db --- /dev/null +++ b/tools/leds/get_led_device_info.sh @@ -0,0 +1,201 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +led_common_defs_path="include/dt-bindings/leds/common.h" + +num_args=$# +if [ $num_args -eq 1 ]; then + linux_top=$(dirname `realpath $0` | awk -F/ \ + '{ \ + i=1; \ + while (i <= NF - 2) { \ + printf $i"/"; \ + i++; \ + }; \ + }') + led_defs_path=$linux_top/$led_common_defs_path +elif [ $num_args -eq 2 ]; then + led_defs_path=`realpath $2` +else + echo "Usage: get_led_device_info.sh LED_CDEV_PATH [LED_COMMON_DEFS_PATH]" + exit 1 +fi + +if [ ! -f $led_defs_path ]; then + echo "$led_defs_path doesn't exist" + exit 1 +fi + +led_cdev_path=`echo $1 | sed s'/\/$//'` + +ls "$led_cdev_path/brightness" > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "Device \"$led_cdev_path\" does not exist." + exit 1 +fi + +bus=`readlink $led_cdev_path/device/subsystem | sed s'/.*\///'` +usb_subdev=`readlink $led_cdev_path | grep usb | sed s'/\(.*usb[0-9]*\/[0-9]*-[0-9]*\)\/.*/\1/'` +ls "$led_cdev_path/device/of_node/compatible" > /dev/null 2>&1 +of_node_missing=$? + +if [ "$bus" = "input" ]; then + input_node=`readlink $led_cdev_path/device | sed s'/.*\///'` + if [ ! -z "$usb_subdev" ]; then + bus="usb" + fi +fi + +if [ "$bus" = "usb" ]; then + usb_interface=`readlink $led_cdev_path | sed s'/.*\(usb[0-9]*\)/\1/' | cut -d\/ -f3` + cd $led_cdev_path/../$usb_subdev + driver=`readlink $usb_interface/driver | sed s'/.*\///'` + if [ -d "$usb_interface/ieee80211" ]; then + wifi_phy=`ls -l $usb_interface/ieee80211 | grep phy | awk '{print $9}'` + fi + idVendor=`cat idVendor` + idProduct=`cat idProduct` + manufacturer=`cat manufacturer` + product=`cat product` +elif [ "$bus" = "input" ]; then + cd $led_cdev_path + product=`cat device/name` + driver=`cat device/device/driver/description` +elif [ $of_node_missing -eq 0 ]; then + cd $led_cdev_path + compatible=`cat device/of_node/compatible` + if [ "$compatible" = "gpio-leds" ]; then + driver="leds-gpio" + elif [ "$compatible" = "pwm-leds" ]; then + driver="leds-pwm" + else + manufacturer=`echo $compatible | awk -F, '{print $1}'` + product=`echo $compatible | awk -F, '{print $2}'` + fi +else + echo "Unknown device type." + exit 1 +fi + +printf "\n#####################################\n" +printf "# LED class device hardware details #\n" +printf "#####################################\n\n" + +printf "bus:\t\t\t$bus\n" + +if [ ! -z "$idVendor" ]; then + printf "idVendor:\t\t$idVendor\n" +fi + +if [ ! -z "$idProduct" ]; then + printf "idProduct:\t\t$idProduct\n" +fi + +if [ ! -z "$manufacturer" ]; then + printf "manufacturer:\t\t$manufacturer\n" +fi + +if [ ! -z "$product" ]; then + printf "product:\t\t$product\n" +fi + +if [ ! -z "$driver" ]; then + printf "driver:\t\t\t$driver\n" +fi + +if [ ! -z "$input_node" ]; then + printf "associated input node:\t$input_node\n" +fi + +printf "\n####################################\n" +printf "# LED class device name validation #\n" +printf "####################################\n\n" + +led_name=`echo $led_cdev_path | sed s'/.*\///'` + +num_sections=`echo $led_name | awk -F: '{print NF}'` + +if [ $num_sections -eq 1 ]; then + printf "\":\" delimiter not detected.\t[ FAILED ]\n" + exit 1 +elif [ $num_sections -eq 2 ]; then + color=`echo $led_name | cut -d: -f1` + function=`echo $led_name | cut -d: -f2` +elif [ $num_sections -eq 3 ]; then + devicename=`echo $led_name | cut -d: -f1` + color=`echo $led_name | cut -d: -f2` + function=`echo $led_name | cut -d: -f3` +else + printf "Detected %d sections in the LED class device name - should the script be updated?\n" $num_sections + exit 1 +fi + +S_DEV="devicename" +S_CLR="color " +S_FUN="function " +status_tab=20 + +print_msg_ok() +{ + local section_name="$1" + local section_val="$2" + local msg="$3" + printf "$section_name :\t%-${status_tab}.${status_tab}s %s %s\n" "$section_val" "[ OK ] " "$msg" +} + +print_msg_failed() +{ + local section_name="$1" + local section_val="$2" + local msg="$3" + printf "$section_name :\t%-${status_tab}.${status_tab}s %s %s\n" "$section_val" "[ FAILED ]" "$msg" +} + +if [ ! -z "$input_node" ]; then + expected_devname=$input_node +elif [ ! -z "$wifi_phy" ]; then + expected_devname=$wifi_phy +fi + +if [ ! -z "$devicename" ]; then + if [ ! -z "$expected_devname" ]; then + if [ "$devicename" = "$expected_devname" ]; then + print_msg_ok "$S_DEV" "$devicename" + else + print_msg_failed "$S_DEV" "$devicename" "Expected: $expected_devname" + fi + else + if [ "$devicename" = "$manufacturer" ]; then + print_msg_failed "$S_DEV" "$devicename" "Redundant: use of vendor name is discouraged" + elif [ "$devicename" = "$product" ]; then + print_msg_failed "$S_DEV" "$devicename" "Redundant: use of product name is discouraged" + else + print_msg_failed "$S_DEV" "$devicename" "Unknown devicename - should the script be updated?" + fi + fi +elif [ ! -z "$expected_devname" ]; then + print_msg_failed "$S_DEV" "blank" "Expected: $expected_devname" +fi + +if [ ! -z "$color" ]; then + color_upper=`echo $color | tr [:lower:] [:upper:]` + color_id_definition=$(cat $led_defs_path | grep "_$color_upper\s" | awk '{print $2}') + if [ ! -z "$color_id_definition" ]; then + print_msg_ok "$S_CLR" "$color" "Matching definition: $color_id_definition" + else + print_msg_failed "$S_CLR" "$color" "Definition not found in $led_defs_path" + fi + +fi + +if [ ! -z "$function" ]; then + # strip optional enumerator + function=`echo $function | sed s'/\(.*\)-[0-9]*$/\1/'` + fun_definition=$(cat $led_defs_path | grep "\"$function\"" | awk '{print $2}') + if [ ! -z "$fun_definition" ]; then + print_msg_ok "$S_FUN" "$function" "Matching definition: $fun_definition" + else + print_msg_failed "$S_FUN" "$function" "Definition not found in $led_defs_path" + fi + +fi diff --git a/tools/leds/led_hw_brightness_mon.c b/tools/leds/led_hw_brightness_mon.c new file mode 100644 index 000000000..eb65ae988 --- /dev/null +++ b/tools/leds/led_hw_brightness_mon.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * led_hw_brightness_mon.c + * + * This program monitors LED brightness level changes having its origin + * in hardware/firmware, i.e. outside of kernel control. + * A timestamp and brightness value is printed each time the brightness changes. + * + * Usage: led_hw_brightness_mon + * + * is the name of the LED class device to be monitored. Pressing + * CTRL+C will exit. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int main(int argc, char const *argv[]) +{ + int fd, ret; + char brightness_file_path[LED_MAX_NAME_SIZE + 11]; + struct pollfd pollfd; + struct timespec ts; + char buf[11]; + + if (argc != 2) { + fprintf(stderr, "Requires argument\n"); + return 1; + } + + snprintf(brightness_file_path, LED_MAX_NAME_SIZE, + "/sys/class/leds/%s/brightness_hw_changed", argv[1]); + + fd = open(brightness_file_path, O_RDONLY); + if (fd == -1) { + printf("Failed to open %s file\n", brightness_file_path); + return 1; + } + + /* + * read may fail if no hw brightness change has occurred so far, + * but it is required to avoid spurious poll notifications in + * the opposite case. + */ + read(fd, buf, sizeof(buf)); + + pollfd.fd = fd; + pollfd.events = POLLPRI; + + while (1) { + ret = poll(&pollfd, 1, -1); + if (ret == -1) { + printf("Failed to poll %s file (%d)\n", + brightness_file_path, ret); + ret = 1; + break; + } + + clock_gettime(CLOCK_MONOTONIC, &ts); + + ret = read(fd, buf, sizeof(buf)); + if (ret < 0) + break; + + ret = lseek(pollfd.fd, 0, SEEK_SET); + if (ret < 0) { + printf("lseek failed (%d)\n", ret); + break; + } + + printf("[%ld.%09ld] %d\n", ts.tv_sec, ts.tv_nsec, atoi(buf)); + } + + close(fd); + + return ret; +} diff --git a/tools/leds/uledmon.c b/tools/leds/uledmon.c new file mode 100644 index 000000000..c15a39c1f --- /dev/null +++ b/tools/leds/uledmon.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * uledmon.c + * + * This program creates a new userspace LED class device and monitors it. A + * timestamp and brightness value is printed each time the brightness changes. + * + * Usage: uledmon + * + * is the name of the LED class device to be created. Pressing + * CTRL+C will exit. + */ + +#include +#include +#include +#include +#include + +#include + +int main(int argc, char const *argv[]) +{ + struct uleds_user_dev uleds_dev; + int fd, ret; + int brightness; + struct timespec ts; + + if (argc != 2) { + fprintf(stderr, "Requires argument\n"); + return 1; + } + + strncpy(uleds_dev.name, argv[1], LED_MAX_NAME_SIZE); + uleds_dev.max_brightness = 100; + + fd = open("/dev/uleds", O_RDWR); + if (fd == -1) { + perror("Failed to open /dev/uleds"); + return 1; + } + + ret = write(fd, &uleds_dev, sizeof(uleds_dev)); + if (ret == -1) { + perror("Failed to write to /dev/uleds"); + close(fd); + return 1; + } + + while (1) { + ret = read(fd, &brightness, sizeof(brightness)); + if (ret == -1) { + perror("Failed to read from /dev/uleds"); + close(fd); + return 1; + } + clock_gettime(CLOCK_MONOTONIC, &ts); + printf("[%ld.%09ld] %u\n", ts.tv_sec, ts.tv_nsec, brightness); + } + + close(fd); + + return 0; +} -- cgit v1.3.1