Skip to content

Commit 6f3c671

Browse files
committed
Split CPU collect logic (long-running) and CPU metric printing (quick) to make status bar refresh behavior more predictable
1 parent a81b74e commit 6f3c671

File tree

3 files changed

+85
-32
lines changed

3 files changed

+85
-32
lines changed

scripts/cpu.sh

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,7 @@ LC_NUMERIC=C
88
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
99
source "$CURRENT_DIR/helpers.sh"
1010

11-
refresh_interval=$(get_tmux_option "status-interval" "5")
12-
13-
# reduce interval by 1 second, so command has time to complete within tmux status refresh interval. Otherwise, tmux will use stale previous command result for 2 times in a row
14-
if [ "$refresh_interval" -gt "1" ]; then
15-
refresh_interval="$(($refresh_interval - 1))"
16-
fi
11+
cpu_tmp_dir=$(tmux show-option -gqv "@sysstat_cpu_tmp_dir")
1712

1813
cpu_view_tmpl=$(get_tmux_option "@sysstat_cpu_view_tmpl" 'CPU:#[fg=#{cpu.color}]#{cpu.pused}#[default]')
1914

@@ -36,33 +31,8 @@ get_cpu_color(){
3631
fi
3732
}
3833

39-
get_cpu_usage() {
40-
if is_osx; then
41-
if command_exists "iostat"; then
42-
iostat -c 2 -w "$refresh_interval" | tail -n 1 | awk '{ print 100-$(NF-3) }'
43-
else
44-
top -l 2 -s "$refresh_interval" -n 0 | sed -nr '/CPU usage/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)%[[:space:]]*idle.*/\1/p' | tail -n 1 | awk '{ print 100-$0 }'
45-
fi
46-
else
47-
if command_exists "vmstat"; then
48-
if is_freebsd; then
49-
vmstat -n "$refresh_interval" -c 2 | tail -n 1 | awk '{print 100-$(NF-0)}'
50-
else
51-
vmstat -n "$refresh_interval" 2 | tail -n 1 | awk '{print 100-$(NF-2)}'
52-
fi
53-
else
54-
if is_freebsd; then
55-
top -d2 | sed -nr '/CPU:/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)%[[:space:]]*id.*/\1/p' | tail -n 1 | awk '{ print 100-$0 }'
56-
else
57-
top -b -n 2 -d "$refresh_interval" | sed -nr '/%Cpu/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)[[:space:]]*id.*/\1/p' | tail -n 1 | awk '{ print 100-$0 }'
58-
fi
59-
fi
60-
fi
61-
}
62-
6334
print_cpu_usage() {
64-
local cpu_pused=$(get_cpu_usage)
65-
35+
local cpu_pused=$(get_cpu_usage_or_collect)
6636
local cpu_color=$(get_cpu_color "$cpu_pused")
6737

6838
local cpu_view="$cpu_view_tmpl"
@@ -74,6 +44,33 @@ print_cpu_usage() {
7444
echo "$cpu_view"
7545
}
7646

47+
get_cpu_usage_or_collect() {
48+
local collect_cpu_metric="$cpu_tmp_dir/cpu_collect.metric"
49+
50+
# read cpu metric from file, otherwise 0 as a temporary null value, until first cpu metric is collected
51+
[ -f "$collect_cpu_metric" ] && cat "$collect_cpu_metric" || echo "0.0"
52+
53+
start_cpu_collect_if_required >/dev/null 2>&1
54+
}
55+
56+
start_cpu_collect_if_required() {
57+
local collect_cpu_pidfile="$cpu_tmp_dir/cpu_collect.pid"
58+
59+
# check if cpu collect process is running, otherwise start it in background
60+
if [ -f "$collect_cpu_pidfile" ] && ps -p "$(cat "$collect_cpu_pidfile")" > /dev/null 2>&1; then
61+
return;
62+
fi
63+
64+
jobs >/dev/null 2>&1
65+
"$CURRENT_DIR/cpu_collect.sh" &>/dev/null &
66+
if [ -n "$(jobs -n)" ]; then
67+
echo "$!" > "${collect_cpu_pidfile}"
68+
else
69+
echo "Failed to start CPU collect job" >&2
70+
exit 1
71+
fi
72+
}
73+
7774
main(){
7875
print_cpu_usage
7976
}

scripts/cpu_collect.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env bash
2+
3+
LC_NUMERIC=C
4+
5+
set -u
6+
set -e
7+
8+
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
9+
source "$CURRENT_DIR/helpers.sh"
10+
11+
refresh_interval=$(get_tmux_option "status-interval" "5")
12+
samples_count="60"
13+
cpu_metric_file="$(get_tmux_option "@sysstat_cpu_tmp_dir" "/dev/null")/cpu_collect.metric"
14+
15+
get_cpu_usage() {
16+
if is_osx; then
17+
if command_exists "iostat"; then
18+
iostat -w "$refresh_interval" -c "$samples_count" \
19+
| stdbuf -o0 awk 'NR > 2 { print 100-$(NF-3); }'
20+
else
21+
top -l "$samples_count" -s "$refresh_interval" -n 0 \
22+
| sed -u -nr '/CPU usage/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)%[[:space:]]*idle.*/\1/p' \
23+
| stdbuf -o0 awk '{ print 100-$0 }'
24+
fi
25+
elif ! command_exists "vmstat"; then
26+
if is_freebsd; then
27+
vmstat -n "$refresh_interval" -c "$samples_count" \
28+
| stdbuf -o0 awk 'NR>2 {print 100-$(NF-0)}'
29+
else
30+
vmstat -n "$refresh_interval" "$samples_count" \
31+
| stdbuf -o0 awk 'NR>2 {print 100-$(NF-2)}'
32+
fi
33+
else
34+
if is_freebsd; then
35+
top -d"$samples_count" \
36+
| sed -u -nr '/CPU:/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)%[[:space:]]*id.*/\1/p' \
37+
| stdbuf -o0 awk '{ print 100-$0 }'
38+
else
39+
top -b -n "$samples_count" -d "$refresh_interval" \
40+
| sed -u -nr '/%Cpu/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)[[:space:]]*id.*/\1/p' \
41+
| stdbuf -o0 awk '{ print 100-$0 }'
42+
fi
43+
fi
44+
}
45+
46+
main() {
47+
get_cpu_usage | while read -r value; do
48+
echo "$value" | tee "$cpu_metric_file"
49+
done
50+
}
51+
52+
main
53+

sysstat.tmux

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ update_tmux_option() {
3333
}
3434

3535
main() {
36+
cpu_tmp_dir=$(mktemp -d)
37+
tmux set-option -gq "@sysstat_cpu_tmp_dir" "$cpu_tmp_dir"
38+
3639
update_tmux_option "status-right"
3740
update_tmux_option "status-left"
3841
}

0 commit comments

Comments
 (0)