From 4a61cf893ee0c699f0f12dfa8bfe5f3fba153c17 Mon Sep 17 00:00:00 2001 From: David Runge Date: Wed, 5 Dec 2018 02:11:32 +0100 Subject: bin/realtime-suggestions: Adding realtime-suggestions. --- bin/realtime-suggestions | 216 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100755 bin/realtime-suggestions (limited to 'bin') diff --git a/bin/realtime-suggestions b/bin/realtime-suggestions new file mode 100755 index 0000000..4ff8722 --- /dev/null +++ b/bin/realtime-suggestions @@ -0,0 +1,216 @@ +#!/usr/bin/env bash + +set -euo pipefail + +warning="WARNING:" +info="INFO:" +kernel_config="/proc/config.gz" +sysctl_ref="(see \`man 5 sysctl.conf\`, \`man 5 sysctl.d\` or \`man 8 sysctl\` for reference)" + +check_root() { + if [ "$(id -u)" -eq 0 ]; then + echo "Use this script as an unprivileged user." + exit 1 + fi +} + +check_filesystems() { + local mount_points=() + local mount_point_data=() + local what="" + local where="" + local type="" + local options="" + mapfile -t mount_points < <( mount |grep -E "^/dev" ) + for mount_point in "${mount_points[@]}"; do + mapfile -d " " -t mount_point_data < <( echo "${mount_point}" ) + what="${mount_point_data[0]}" + where="${mount_point_data[2]}" + type="${mount_point_data[4]}" + options="${mount_point_data[5]}" + if [[ "$options" != *relatime* ]] && [[ "$options" != *noatime* ]]; then + echo "$warning $what mounted on $where (type $type) should use the relatime mount option for performance." + fi + if [[ "$type" == *fuse* ]] || [[ "$type" == *reiserfs* ]] || [[ "$type" == *vfat* ]]; then + echo "$info $what mounted on $where (type $type) is not a good filesystem for large files or realtime use." + fi + done +} + +check_groups() { + local groups="" + groups=$(groups) + if [[ "$groups" != *audio* ]]; then + echo "$warning Add your user to the audio group. It's used for access to audio devices on most distros." + fi + if [[ "$groups" != *realtime* ]]; then + echo "$info Some distributions use the realtime group for elevated resource limits." + fi +} + +check_ulimits() { + local limits_ref="(see \`man limits.conf\` for reference)" + if [[ "$(ulimit -t)" != "unlimited" ]]; then + echo "$warning The CPU limit for your user is not unlimited $limits_ref." + fi + if [[ "$(ulimit -l)" != "unlimited" ]]; then + echo "$warning The locked-in-memory limit for your user is not unlimited $limits_ref." + fi + if [ "$(ulimit -r)" -le 50 ]; then + echo "$warning The maximum rt priority for your user ($(ulimit -r)) is very low. Consider increasing it up to 98 $limits_ref." + fi +} + +check_vm_swappiness() { + local minimum=10 + local proc_file="/proc/sys/vm/swappiness" + if [ "$(cat "$proc_file")" -gt $minimum ]; then + echo "$warning Consider decreasing 'vm.swappiness<=$minimum' to prevent early write to swap $sysctl_ref." + fi +} + +check_max_user_watches() { + local minimum=524288 + local proc_file="/proc/sys/fs/inotify/max_user_watches" + if [ "$(cat "$proc_file")" -lt $minimum ]; then + echo "$warning Consider increasing 'fs.inotify.max_user_watches>$minimum' - the maximum amount of files inotify can watch $sysctl_ref" + fi +} + +check_cpu_governor() { + local cpupower_ref="(see \`man cpupower\` for reference)" + local governor="" + local policy_no="" + local cpu_no="" + for governor_file in /sys/devices/system/cpu/cpufreq/policy*/scaling_governor; do + governor="$(cat "$governor_file")" + policy_no="$(echo "$governor_file"| cut -d'/' -f7)" + cpu_no="${policy_no//policy}" + if [[ "$governor" != "performance" ]]; then + echo "$warning CPU $cpu_no has governor $governor set. Set it to 'performance' $cpupower_ref." + fi + done +} + +check_config_high_res_timers() { + local config="CONFIG_HIGH_RES_TIMERS=y" + local config_ref="(see \`man 7 time\` for reference)" + if [ -e "${kernel_config}" ]; then + if ! zgrep -q "$config" "$kernel_config"; then + echo "$warning CONFIG_HIGH_RES_TIMERS needs to be activated for your kernel $config_ref." + fi + else + echo "$warning $kernel_config could not be found or accessed." + fi +} + +check_config_no_hz() { + local config1="CONFIG_NO_HZ_IDLE=y" + local config2="CONFIG_NO_HZ=y" + local config_ref="(see https://elinux.org/Kernel_Timer_Systems#Dynamic_ticks for reference)" + if [ -e "${kernel_config}" ]; then + if ! zgrep -q "$config1" "$kernel_config"; then + echo "$warning $config1 needs to be set for your kernel for 'dynamic ticks' support $config_ref." + fi + if ! zgrep -q "$config2" "$kernel_config"; then + echo "$warning $config2 needs to be set for your kernel for 'dynamic ticks' support $config_ref." + fi + else + echo "$warning $kernel_config could not be found or accessed." + fi +} + +check_config_preempt_rt() { + local config1="CONFIG_PREEMPT_RT=y" + local config2="CONFIG_PREEMPT_RT_FULL=y" + local config_ref="(see https://wiki.linuxfoundation.org/realtime for reference)" + if [ -e "${kernel_config}" ]; then + if ! zgrep -q "$config1" "$kernel_config" && ! zgrep -q "$config2" "$kernel_config"; then + echo "$warning The PREEMPT_RT patch set is not available on your kernel $config_ref." + fi + else + echo "$warning $kernel_config could not be found or accessed." + fi +} + +check_config_irq_forced_threading() { + local config1="CONFIG_PREEMPT=y" + local config2="CONFIG_IRQ_FORCED_THREADING=y" + local config_ref="(see https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html for reference)" + if [ -e "${kernel_config}" ]; then + if zgrep -q "$config2" "$kernel_config"; then + if ! zgrep -q "$config1" "$kernel_config" && ! grep -q "threadirqs" /proc/cmdline; then + echo "$warning Without $config1 on your kernel, you can still use the threadirqs kernel parameter $config_ref." + fi + else + echo "$warning Use a kernel with $config2 $config_ref." + fi + else + echo "$warning $kernel_config could not be found or accessed." + fi +} + +check_legacy_timers() { + local hpet_file="/dev/hpet" + local rtc_file="/dev/rtc0" + local hpet_ref="(see https://wiki.linuxaudio.org/wiki/system_configuration#timers for reference)" + if [ ! -w "$hpet_file" ]; then + echo "$info $hpet_file is not writable by your user. Some legacy software requires it $hpet_ref." + fi + if [ ! -w "$rtc_file" ]; then + echo "$info $rtc_file is not writable by your user. Some legacy software requires it $hpet_ref." + fi +} + +check_cpu_dma_latency() { + local dev_file="/dev/cpu_dma_latency" + if [ ! -w "$dev_file" ]; then + echo "$warning $dev_file needs to be writable by your user to prevent deep CPU sleep states." + fi +} + +check_coupled_interrupts() { + local interrupts=() + local interrupt_delim=", " + local interrupt_number="" + local interrupt_ref="(see \`cat /proc/interrupts\` for more and consider using rtirq)" + mapfile -t interrupts < <( cat /proc/interrupts ) + for interrupt_line in "${interrupts[@]}"; do + interrupt_number="$(echo "$interrupt_line"| cut -d':' -f1)" + if [[ "$interrupt_line" == *"$interrupt_delim"* ]]; then + echo "$warning IRQ$interrupt_number has coupled interrupts $interrupt_ref." + fi + done +} + +check_irqbalance() { + if pgrep -i irqbalance >/dev/null 2>&1; then + echo "$warning The irqbalance service is running on your system. It might interfere, so consider disabling it." + fi +} + +check_for_useful_tools() { + local tools=( cyclictest htop iostat iotop rtirq schedtool tuna ) + for tool in "${tools[@]}";do + if ! command -v "$tool" >/dev/null 2>&1; then + echo "$info Consider installing and using $tool." + fi + done +} + +check_root +check_filesystems +check_groups +check_ulimits +check_max_user_watches +check_legacy_timers +check_vm_swappiness +check_cpu_governor +check_cpu_dma_latency +check_config_high_res_timers +check_config_no_hz +check_config_preempt_rt +check_config_irq_forced_threading +check_coupled_interrupts +check_irqbalance +check_for_useful_tools -- cgit v1.2.3-54-g00ecf