summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKerin Millar <kfm@plushkava.net>2024-06-08 16:44:32 +0100
committerKerin Millar <kfm@plushkava.net>2024-06-14 01:27:42 +0100
commit72b754bb11066b10ae14b8f017f93ad5c62e7467 (patch)
tree6a3567c8907d71a9c57a47052dad8fa5cd33aa63
parentHave _eend() assume 80 columns in the absence of a smart terminal (diff)
downloadgentoo-functions-72b754bb11066b10ae14b8f017f93ad5c62e7467.tar.gz
gentoo-functions-72b754bb11066b10ae14b8f017f93ad5c62e7467.tar.bz2
gentoo-functions-72b754bb11066b10ae14b8f017f93ad5c62e7467.zip
Throttle the rate at which genfun_cols may be refreshed
Limit the rate at which genfun_cols can be refreshed to intervals that are no shorter than 5 decisconds (half a second). Doing so renders repeated calls to the _eend() function at short intervals faster by an order of magnitude. On one of my fastest available machines, I performed the following benchmark with bash 5.2.26. $ time for ((i=0; i<50000; i++)); do ebegin "$i"; eend; done The results were as follows. BEFORE real 0m56.897s user 0m16.990s sys 0m28.540s AFTER real 0m6.663s user 0m6.435s sys 0m0.191s On one of my slowest available machines, I performed the following benchmark with bash 5.2.26. $ time for ((i=0; i<15000; i++)); do ebegin "$i"; eend; done The results were as follows. BEFORE real 0m52.557s user 0m34.484s sys 0m18.231s AFTER real 0m11.422s user 0m10.654s sys 0m0.535s On that same (slow) machine, I performed the following benchmark with dash 0.5.12. $ time dash -c ' . ./functions.sh while :; do ebegin $((i+=1)); eend; [ $i -eq 15000 ] && exit; done' The results were as follows. BEFORE real 0m43.762s user 0m22.202s sys 0m21.415s AFTER real 0m3.470s user 0m2.535s sys 0m0.736s Signed-off-by: Kerin Millar <kfm@plushkava.net>
-rw-r--r--functions.sh81
1 files changed, 78 insertions, 3 deletions
diff --git a/functions.sh b/functions.sh
index fcba801..52224a5 100644
--- a/functions.sh
+++ b/functions.sh
@@ -19,6 +19,7 @@
# EINFO_LOG : whether printing functions should call esyslog()
# EINFO_QUIET : whether info message printing functions should be silenced
# EINFO_VERBOSE : whether v-prefixed functions should do anything
+# EPOCHREALTIME : potentially used by _update_time() to get the time
# IFS : multiple message operands are joined by its first character
# INSIDE_EMACS : whether to work around an emacs-specific bug in _eend()
# NO_COLOR : whether colored output should be suppressed
@@ -920,15 +921,36 @@ _select_by_mtime() {
}
#
+# Considers the first parameter as a number of deciseconds and determines
+# whether fewer have elapsed since the last occasion on which the function was
+# called.
+#
+_should_throttle()
+{
+ _update_time || return
+ if [ "$(( genfun_time - genfun_last_time > $1 ))" -eq 1 ]; then
+ genfun_last_time=${genfun_time}
+ false
+ fi
+}
+
+#
# Determines whether the terminal on STDIN is able to report its dimensions.
# Upon success, the number of columns shall be stored in genfun_cols.
#
_update_columns()
{
- # Command substitutions are rather slow in bash. Using the COLUMNS
- # variable helps but checkwinsize won't work properly in subshells.
+ # Two optimisations are applied. Firstly, the rate at which updates can
+ # be performed is throttled to intervals of 5 deciseconds. Secondly, if
+ # running on bash then the COLUMNS variable may be gauged, albeit only
+ # in situations where doing so can be expected to work reliably; not if
+ # in a subshell. Note that executing true(1) is faster than executing
+ # stty(1) within a comsub.
# shellcheck disable=3028,3044
- if [ "$$" = "${BASHPID}" ] && shopt -q checkwinsize; then
+ if _should_throttle 5; then
+ test "${genfun_cols}"
+ return
+ elif [ "$$" = "${BASHPID}" ] && shopt -q checkwinsize; then
"${genfun_bin_true}"
set -- 0 "${COLUMNS}"
else
@@ -943,6 +965,59 @@ _update_columns()
}
#
+# Determines either the number of deciseconds elapsed since the unix epoch or
+# the number of deciseconds that the operating system has been online, depending
+# on the capabilities of the shell and/or platform. Upon success, the obtained
+# value shall be assigned to genfun_time. Otherwise, the return value shall be
+# greater than 0.
+#
+_update_time()
+{
+ genfun_last_time=0
+
+ # shellcheck disable=3028
+ if [ "${BASH_VERSINFO:-0}" -ge 5 ]; then
+ # shellcheck disable=2034,3045
+ _update_time()
+ {
+ local ds s timeval
+
+ timeval=${EPOCHREALTIME}
+ s=${timeval%.*}
+ printf -v ds '%.1f' ".${timeval#*.}"
+ if [ "${ds}" = "1.0" ]; then
+ ds=10
+ else
+ ds=${ds#0.}
+ fi
+ genfun_time=$(( s * 10 + ds ))
+ }
+ elif [ -f /proc/uptime ]; then
+ _update_time()
+ {
+ local ds s timeval
+
+ IFS=' ' read -r timeval _ < /proc/uptime || return
+ s=${timeval%.*}
+ printf -v ds '%.1f' ".${timeval#*.}"
+ if [ "${ds}" = "1.0" ]; then
+ ds=10
+ else
+ ds=${ds#0.}
+ fi
+ genfun_time=$(( s * 10 + ds ))
+ }
+ else
+ _update_time()
+ {
+ false
+ }
+ fi
+
+ _update_time
+}
+
+#
# Grades the capability of the terminal attached to STDIN, assigning the level
# to genfun_tty. If no terminal is detected, the level shall be 0. If a dumb
# terminal is detected, the level shall be 1. If a smart terminal is detected,