FocusedWolf

Arch: CPU stress test script with tmux split view of live journalctl events

Jul 12th, 2025 (edited)
858
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 9.47 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. # Version 14
  4.  
  5. # POSTED ONLINE: https://pastebin.com/4wZk0FxU
  6.  
  7. # WARNING: This script will run a CPU stress test on the processor resulting in high temperatures and power draw.
  8. #          Prolonged usage may cause system instability, degradation, or damage.
  9. #          Do not leave the system unattended during use.
  10. #          Do not run this script unless adequate cooling is in place and you understand the risks.
  11. #          You assume all responsibility for using this script.
  12.  
  13. # Installation:
  14. #     $ sudo cp /media/D/Users/Wolf/Files/Archives/Scripts/Shell/TestCpu/testcpu /usr/local/bin/
  15. #     $ sudo chmod +x /usr/local/bin/testcpu    <-- Needed to fix permission denied error.
  16. #
  17. #     NOTE: Ensure 'tmux' and 'stress-ng' are installed: $ sudo pacman -S tmux stress-ng
  18.  
  19. # Usage:
  20. #     This script stress-tests CPU cores with 'stress-ng' and displays live system logs using 'journalctl' in a split tmux session.
  21. #
  22. #     1. Run the script with: $ testcpu [CPU_LIST]
  23. #
  24. #                             NOTE: CPU_LIST is optional and specifies which logical CPUs to test.
  25. #                             It supports comma-separated values and ranges, e.g., "0-3,6,8".
  26. #                             If omitted, all logical CPUs (0 through nproc-1) are tested sequentially.
  27. #
  28. #                             Examples:
  29. #                                 $ testcpu            # Test all cores sequentially.
  30. #                                 $ testcpu 0-3,6,8    # Test cores 0 to 3, 6, and 8.
  31. #                                 $ testcpu --help     # Show help.
  32. #
  33. #   2. This script will launch a tmux session named 'cpu_test' with two panes:
  34. #      The top pane runs the stress test.
  35. #      The bottom pane displays live journalctl events.
  36. #      NOTE: This script runs continuously until manually stopped.
  37. #
  38. #   3. To stop this script:
  39. #      From inside tmux: press Ctrl+C in each pane and run $ exit
  40. #      From outside tmux: $ sudo tmux kill-session -t cpu_test
  41. #      NOTE: If tmux or stress-ng are still running then terminate them using System Monitor or any process manager you prefer.
  42.  
  43. show_help() {
  44.     cat << EOF
  45. Usage: $(basename "$0") [OPTIONS] [CPU_LIST]
  46.  
  47. Options:
  48.   -h, --help        Show this help message and exit.
  49.  
  50. CPU_LIST:
  51.   Optional comma-separated list of logical CPUs or CPU ranges to test.
  52.   Examples:
  53.     0-3            Test CPUs 0,1,2,3
  54.     1,3,5          Test CPUs 1,3,5
  55.     0-2,4,6-7      Test CPUs 0,1,2,4,6,7
  56.  
  57. If no CPU_LIST is provided, all CPUs (0 through $(nproc - 1)) are tested.
  58.  
  59. Example:
  60.   $0 0-3,5
  61.  
  62. EOF
  63. }
  64.  
  65. parse_cpu_list() {
  66.     local input=$1
  67.     local -a list=()
  68.  
  69.     IFS=',' read -ra parts <<< "$input"
  70.     for part in "${parts[@]}"; do
  71.         if [[ $part =~ ^([0-9]+)-([0-9]+)$ ]]; then
  72.             start=${BASH_REMATCH[1]}
  73.             end=${BASH_REMATCH[2]}
  74.             if (( start > end )); then
  75.                 echo "Invalid CPU range: $part"
  76.                 exit 1
  77.             fi
  78.             for ((i=start; i<=end; i++)); do
  79.                 list+=("$i")
  80.             done
  81.         elif [[ $part =~ ^[0-9]+$ ]]; then
  82.             list+=("$part")
  83.         else
  84.             echo "Invalid CPU list format: $part"
  85.             exit 1
  86.         fi
  87.     done
  88.  
  89.     # Remove duplicates and sort.
  90.     IFS=$'\n' sorted=($(sort -n <<<"${list[*]}"))
  91.     unset IFS
  92.  
  93.     # Unique filter.
  94.     cpus=()
  95.     prev=-1
  96.     for c in "${sorted[@]}"; do
  97.         if [[ $c -ne $prev ]]; then
  98.             cpus+=("$c")
  99.             prev=$c
  100.         fi
  101.     done
  102. }
  103.  
  104. # Handle help option.
  105. if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
  106.     show_help
  107.     exit 0
  108. fi
  109.  
  110. # If tmux is not installed.
  111. if ! command -v tmux >/dev/null 2>&1; then
  112.     echo -e "\e[94m::\e[0m tmux not found. Install with: $ sudo pacman -S tmux"
  113.     exit 1
  114. fi
  115.  
  116. # If stress-ng is not installed.
  117. if ! command -v stress-ng >/dev/null 2>&1; then
  118.     echo -e "\e[94m::\e[0m stress-ng not found. Install with: $ sudo pacman -S stress-ng"
  119.     exit 1
  120. fi
  121.  
  122. # Check if script is running as root, if not re-run with sudo.
  123. if [[ $EUID -ne 0 ]]; then
  124.     echo "Requesting administrative privileges . . ."
  125.     exec sudo "$0" "$@"
  126. fi
  127.  
  128. # Get total logical CPUs.
  129. max_cpu=$(( $(nproc) - 1 ))
  130.  
  131. # Determine CPU indexes to test.
  132. if [[ -n "${1:-}" ]]; then
  133.     parse_cpu_list "$1"
  134.     cpu_warning="logical CPUs: $(IFS=,; echo "${cpus[*]}")"
  135. else
  136.     cpus=($(seq 0 "$max_cpu"))
  137.     cpu_warning="all logical CPUs"
  138. fi
  139.  
  140. # Validate CPUs are within range.
  141. for cpu in "${cpus[@]}"; do
  142.     if (( cpu < 0 || cpu > max_cpu )); then
  143.         echo "ERROR: CPU number out of range: $cpu"
  144.         exit 1
  145.     fi
  146. done
  147.  
  148. while true; do
  149.     echo
  150.     echo -e "\e[91m:: WARNING: This script will run a CPU stress test on $cpu_warning resulting in high temperatures and power draw.\e[0m"
  151.     echo -e "\e[91m            Prolonged usage may cause system instability, degradation, or damage.\e[0m"
  152.     echo -e "\e[91m            Do not leave the system unattended during use.\e[0m"
  153.     echo -e "\e[91m            Do not continue unless adequate cooling is in place and you understand the risks.\e[0m"
  154.     echo -e "\e[91m            You assume all responsibility for using this script.\e[0m"
  155.     echo
  156.     read -p "Do you want to continue? [Y/N]: " response
  157.     case "$response" in
  158.         y|Y) break ;;
  159.         n|N) exit 0 ;; # Exit script with status 0 to indicate user cancellation.
  160.         *) echo ;;
  161.     esac
  162. done
  163. echo
  164.  
  165. while true; do
  166.     read -p "Do you want to include a RAM test? [Y/N]: " ram_response
  167.     case "$ram_response" in
  168.         y|Y) include_ram_test=true; break ;;
  169.         n|N) include_ram_test=false; break ;;
  170.         *) echo ;;
  171.     esac
  172. done
  173. echo
  174.  
  175. # Pass cpus array as string to embedded script.
  176. cpus_str="$(IFS=,; echo "${cpus[*]}")"
  177.  
  178. # Create a temporary file.
  179. stress_script=$(mktemp)
  180.  
  181. cleanup() {
  182.     # Delete the temporary script file.
  183.     [[ -n "$stress_script" ]] && rm -f "$stress_script"
  184. }
  185.  
  186. # Run cleanup() function on script interruption or termination.
  187. trap cleanup SIGINT SIGTERM SIGHUP SIGQUIT EXIT
  188.  
  189. # Write the contents of the temporary script.
  190. cat > "$stress_script" <<EOF
  191. #!/bin/bash
  192.  
  193. cleanup() {
  194.     [[ -n "\${stress_pid}" && "\${stress_pid}" =~ ^[0-9]+\$ ]] && kill "\${stress_pid}" 2>/dev/null
  195.     exit 1
  196. }
  197.  
  198. # Run cleanup() function on script interruption or termination.
  199. trap cleanup SIGINT SIGTERM SIGHUP SIGQUIT EXIT
  200.  
  201. seconds_per_test=15 # The duration of the cpu tests.
  202. seconds_between_tests=3 # The delay between cpu tests (gives time to read the output and for the processor to cool).
  203. max_cycles=2 # The maximum number of full test cycles to perform before exiting.
  204.  
  205. cpus_str="\$1"
  206. include_ram_test="\$2"
  207.  
  208. IFS=',' read -ra cpus <<< "\$cpus_str"
  209. num_cpus=\${#cpus[@]}
  210. total_time=\$((num_cpus * (seconds_per_test + seconds_between_tests)))
  211.  
  212. blue="\e[94m::\e[0m"
  213. yellow="\e[93m::\e[0m"
  214. red="\e[91m::\e[0m"
  215.  
  216. cycle_count=0
  217. while true; do
  218.     # Loop through the specified CPUs, stress-testing each sequentially.
  219.     for idx in "\${!cpus[@]}"; do
  220.         cpu="\${cpus[\$idx]}"
  221.         # clear # NOTE: Comment out this line if you want to retain the output from past tests instead of clearing it.
  222.  
  223.         time_elapsed=\$((idx * (seconds_per_test + seconds_between_tests)))
  224.         time_remaining=\$((total_time - time_elapsed))
  225.  
  226.         if (( num_cpus > 1 )); then
  227.             progress=\$(( idx * 100 / (num_cpus - 1) ))
  228.         else
  229.             progress=100
  230.         fi
  231.  
  232.         eta=\$(printf '%02d:%02d:%02d' \$((time_remaining / 3600)) \$(((time_remaining % 3600) / 60)) \$((time_remaining % 60)))
  233.         echo -e "\${yellow} Testing CPU \${cpu} [Progress: \${progress}% ETA: \${eta}]\n"
  234.  
  235.         if [[ "\$include_ram_test" == "true" ]]; then
  236.             taskset -c "\${cpu}" stress-ng \
  237.               --cpu 1 \
  238.               --cpu-method all \
  239.               --vm 1 \
  240.               --vm-bytes 90% \
  241.               --vm-method all \
  242.               --verify \
  243.               --vm-keep \
  244.               --metrics-brief \
  245.               --timeout "\${seconds_per_test}s" &
  246.         else
  247.             taskset -c "\${cpu}" stress-ng \
  248.               --cpu 1 \
  249.               --cpu-method all \
  250.               --metrics-brief \
  251.               --timeout "\${seconds_per_test}s" &
  252.         fi
  253.         stress_pid=\$!
  254.         wait "\${stress_pid}"
  255.         unset stress_pid
  256.  
  257.         echo -e "\n\${blue} Cooling down for \${seconds_between_tests} seconds before continuing . . .\n"
  258.         sleep "\${seconds_between_tests}"
  259.     done
  260.     ((cycle_count++))
  261.     echo -e "\${red} Completed \${cycle_count} of \${max_cycles} test cycles . . .\n"
  262.  
  263.     if (( cycle_count >= max_cycles )); then
  264.         exit 0
  265.     fi
  266. done
  267. EOF
  268. chmod +x "$stress_script"
  269.  
  270. session_name="stress_test"
  271.  
  272. # If session exists.
  273. if tmux has-session -t "$session_name" 2>/dev/null; then
  274.     tmux kill-session -t "$session_name"
  275. fi
  276.  
  277. # Start tmux session with CPU test in top pane.
  278. tmux new-session -d -s "$session_name"
  279.  
  280. # Split directly from CPU pane to create bottom pane.
  281. tmux split-window -v -t "$session_name:0"
  282. bottom_pane="$session_name:0.1"
  283.  
  284. # Run CPU test in top pane.
  285. tmux send-keys -t "$session_name:0.0" "\"$stress_script\" \"$cpus_str\" \"$include_ram_test\"" C-m
  286.  
  287. # Run journalctl in bottom pane.
  288. tmux send-keys -t "$bottom_pane" "journalctl -fk -o short-iso" C-m
  289.  
  290. # Label panes.
  291. tmux select-pane -t "$session_name:0.0" -T "CPU"
  292. tmux select-pane -t "$bottom_pane" -T "LOG"
  293.  
  294. # Set layout and attach.
  295. tmux select-layout -t "$session_name" even-vertical
  296. tmux attach -t "$session_name"
Advertisement
Comments
  • # text 0.38 KB | 0 0
    1. Great work! I really enjoyed reading your post. I’ve recently published an article on my website that covers a wide range of topics including Trending Flash News, Bangla and English news, current events, politics, entertainment, sports, job updates, international headlines, business, science, technology, and more. Feel free to check it out here: https://www.trendingflashnews.com/
    2.  
Add Comment
Please, Sign In to add comment