Because it is considerably more efficient. Maybe 10 times in your case.

It can be worthwhile to trade simplicity of shell scripting for efficiency of C. Besides, you can run shell scripts from slstatus as well and migrate away from scripts step by step.

1. Setup

First, don’t litter and test in tmpfs:

mkdir /tmp/bench && cd $_

I use my fork of slstatus, where I have (custom things in bold)

  • date
  • used+total memory and swap
  • CPU load and its average frequency
  • network traffic
  • MPD status and volume
git clone "https://github.com/ivan-boikov/slstatus"
cd slstatus && make -j && cd -

Compare it to vanilla dwmblocks trying to match most of slstatus’s functionality. Also note that all blocks will run every second as slstatus does.

git clone "https://github.com/torrinfail/dwmblocks" && cd "dwmblocks"

rm blocks.h && cp blocks.def.h blocks.h
sed -i '4,6d' blocks.h
sed -i '4i{"Mem:", "free -h | awk '\''/^Mem/ { print $3\\"/\\"$2 }'\'' | sed s/i//g", 1, 0},' blocks.h
sed -i '5i{"Swap:", "free -h | awk '\''/^Swap/ { print $3\\"/\\"$2 }'\'' | sed s/i//g", 1, 0},' blocks.h
sed -i '6i{"", "date '\''+%b %d (%a) %I:%M:%S%p'\''", 1, 0},' blocks.h
sed -i '7i{"Freq:", "awk -F \\" \\" '\''{ total += $1; count++ } END { printf \\"%.1f\\", total/count/1e6 }'\'' /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq", 1, 0},' blocks.h
sed -i '8i{"Net:", "/tmp/bench/dwmblocks/sb-nettraf", 1, 0},' blocks.h

wget "https://raw.githubusercontent.com/ivan-boikov/.dotfiles/master/scripts/.local/bin/sb-nettraf"
make -j

There is everything but the CPU use, MPD status and the volume. But it’s fine.

Here, the measurement of network traffic is too complicated for a one-liner; sb-nettraf is a trimmed version of the original by LukeSmithxyz.

2. Benchmark

Plan: run for 30 seconds using timeout from GNU core utilities and measure CPU time and a number of syscalls with strace:

strace -cf -e 'trace=!wait4' timeout 30 <executable path>

Here, -c or --summary-only will only count syscalls and CPU time. With -f strace will follow forks - crucial for dwmblocks who does everything in forks. Waiting is doing nothing, so ignore wait4 with -e. For brevity, only 5 longest syscalls will be shown.

dwmblocks does everything in scripts and uses popen to execute them. According to man popen, /bin/sh is used, which can be a symlink to another shell. So let’s compare three cases

  1. dwmblocks with bash as the default shell
  2. same, but with dash, a faster POSIX-compliant shell
  3. slstatus

Gentoo-specific I used to manually install app-shells/bash only, and sh was, in fact, bash. Hence, the first benchmark is to see how big was my mistake. A proper way is to install app-alternatives/sh with correct USE flags.

# dwmblocks+bash
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 18.09    0.041899          84       498           execve
 14.21    0.032922           3     10232           mmap
 12.50    0.028963           1     15667      2325 newfstatat
  7.78    0.018013           3      5189       186 openat
  7.18    0.016628          53       311           clone
------ ----------- ----------- --------- --------- ----------------
100.00    0.231649           2     89537      4604 total
# dwmblocks+dash
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 16.13    0.017563           2      6145           mmap
 14.77    0.016081          31       514           execve
 10.15    0.011053           3      3564       192 openat
  9.61    0.010466           1      6956      1376 newfstatat
  6.78    0.007387           1      4712           read
------ ----------- ----------- --------- --------- ----------------
100.00    0.108903           2     47135      3022 total
# slstatus
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 45.94    0.004753          12       370           read
 27.08    0.002802           8       343        30 openat
  7.85    0.000812           2       343           newfstatat
  6.79    0.000703           2       316           close
  4.39    0.000454           5        90           write
------ ----------- ----------- --------- --------- ----------------
100.00    0.010347           5      1768       108 total

3. Analysis

dwmblocks+bash dwmblocks+dash slstatus
CPU time, norm 22.4 10.5 1.0
Syscalls, norm 50.6 26.7 1.0
Mean CPU load, % 0.772 0.363 0.034

So, I was using about 1% of my CPU just for a statusbar and fixing my blunder improved the efficiency 22 times.

The thing that instigated me to do all this was powertop claiming that with just dwmblocks+bash in the background, my laptop’s CPU woke up about 600 times per second, largely due to tick_sched_timer. According to superuser it means the CPU often switches contexts. A rough measurement with

cat /proc/$(pidof dwmblocks)/status

showed that dwmblocks with bash or dash caused around 15 switches/second, while slstatus – just 1 switch/second. Now, the CPU wakes up 150 times per second.