Issue
I have a script that I run inside an oh-my-zsh prompt that shows this information:
(68% disk used) (1.48[16] cores @ 8.7%) (16G used / 16G) 100% 🔌
It seems like it's calling top
multiple times and thus it takes a LONG time (several seconds - long enough to be annoying) to display after each carriage return and therefore calling this script for the oh-my-zsh prompt. Is there any way to speed this up? When I call top
, I'm using options that only output one page of top's output - a "snapshot" of top's information that I use to display the load average, the percentage of "on time" of the processor, and the amount of RAM I'm currently using. I know for a fact that calling top -l 1 -s 0
does not take longer than even a quarter of a second, so my script must be calling it multiple times unless I'm missing something else entirely... the sysctl hw
command is also quite fast, as is pmset -g batt
and df -h
. Anyways, here's the script:
#!/bin/zsh
toplist=(top -l 1 -s 0)
sysctllist=(sysctl hw)
pmsetlist=(pmset -g batt)
storagelist=(df -h)
availablestorage=$($storagelist | grep "/dev/disk1s2" | awk '{print $2}' | sed 's/Gi//')
availablestorage=$((availablestorage * 1.073741824))
usedstorage=$($storagelist | grep "/" | awk '{print $3}' | grep "Gi" | sed 's/Gi//' | awk '{ sum += $1 } END { print sum }')
usedstorage=$((usedstorage * 1.073741824))
storagepercentused=$((100 * (usedstorage / availablestorage)))
storagepercentusedrounded=$( echo "($storagepercentused)/1" | bc)
loadavg=$($toplist | grep 'Load Avg' | awk '{print $3, $4, $5}' | tr -d , | awk '{print $2}')
ncpu=$($sysctllist | grep ".ncpu" | grep -o -E '[1-9]+')
percentidle=$($toplist | grep 'CPU usage:' | awk '{print $3, $5, $7}' | tr -d , | tr -d % | awk '{print $3}')
memoryfree=$($toplist | grep 'PhysMem' | awk '{print $2}')
totalmemory=$($sysctllist | grep .memsize | grep -oE '[1-9]+')
batterypercent=""$($pmsetlist | grep "%" | awk '{print $3}' | tr -d \;)"%"
power=""
if ($pmsetlist | grep "Battery Power") >> /dev/null then
power="🔋"
elif ($pmsetlist | grep "AC Power") >> /dev/null then
power="🔌"
fi
echo "($storagepercentusedrounded%% disk used) ("$loadavg"["$ncpu"] cores @ "$(printf '%.*f\n' 1 $((100 - $percentidle)))"%%) ("$memoryfree" used / "$(($totalmemory / 1024 / 1024 / 1024))"G)" %F{white}$batterypercent $power
Solution
Turns out, the biggest problem was the top command itself. It requires at least a second or two to average the processor percentage. So, when I switched to Python, I used psutil to get the load averages on the processor - which are stored automatically every 5 seconds and averages over 1 minute, 5 minutes, and 15 minutes. It's practically instant. Once I took out top, and used python's psutil, shutil, and os libraries, everything works swimmingly.
#!/Users/jacobjackson/repos/python_class/venv/bin/python3
import psutil
import shutil
import os
vm = psutil.virtual_memory()
memory_used = f"{round((vm.used / vm.total)*100)}%%"
du = shutil.disk_usage("/")
disk_percent = f"{round((du.used / du.total)*100)}%%"
load1, load5, load15 = psutil.getloadavg()
cpu_usage = f"{round(load5/os.cpu_count()*100)}%%"
battery_status = psutil.sensors_battery()
battery_percent = f"{battery_status.percent}%%"
ac_power = battery_status.power_plugged
if ac_power == True:
power="🔌"
else:
power="🔋"
print(f"{disk_percent} disk | {cpu_usage} cpu | {memory_used} mem | {battery_percent} {power}")
Answered By - Jacob Jackson Answer Checked By - Dawn Plyler (WPSolving Volunteer)