You are not logged in.

#1 2016-06-23 22:25:59

FoxzTrot
Member
Registered: 2014-02-20
Posts: 20

[Solved] Lemonbar script uses way more CPU when run from other script.

I've been using lemonbar as my panel, and I'm trying to optimize my info script that runs it. Below is my panel script that finds all the required information and formats it. I have a few other scripts that watch for reasons to update the panel, and send a SIGUSR1 to break the read loop at the bottom of the script. When this script is run alone, it's very lightweight and uses hardly any cpu (~2 % of a core). However, to then pipe the info to lemonbar and run it with the right config, I have a second wrapper script for the panel. When I run this script, it launches the panel script which then starts to consume 100% of a core. I'd like to make that not happen, but I'm really unsure of why it is that running it one way makes resource usage very small and the other way makes it giant.

The main panel script.

#!/bin/zsh

VDBL="#458588" #Very Dark Blue
DKBL="#689d6a" #Dark Blue
DKRD="#cc241d" #Dark Red
BRRD="#fb4934" #Bright Red
BRYL="#fabd2f" #Bright Yellow
DKGR="#98971a" #Dark Green
BRGR="#b8bb26" #Bright Green
BRBL="#83a598" #Bright Blue
BKGD="#32302f"
FRGD="#ebdbb2"

function music(){
    artist=$(mpc -f %artist% current)
    title=$(mpc -f %title% current)
    printf "%%{F${BRBL}} %%{R} \ue1a6 %%{R} "
    echo " ${artist} %{F${DKBL}}- %{F${BRYL}}${title}"
}

function now(){
    time=$(date "+%I:%M:%S")
    printf "%%{F${DKBL}}%%{R} \ue015 %%{R}"
    echo " ${time}%{F-} "
}

function today(){
    date=$(date "+%y-%m-%d")
    printf "%%{F${BRRD}}%%{R} \ue26a %%{R}"
    echo " ${date}"

}

function desk(){
    CUR=$(xprop -root _NET_CURRENT_DESKTOP | awk '{print $3}')
    true="%%{F${DKBL}}\ue098"
    false="%%{F${DKRD}}\ue098"
    div="%%{F${DKGR}}\ue1b1"
    case $CUR in
        0) printf "${true}${false}${false}${div}${false}${false}${false}";;
        1) printf "${false}${true}${false}${div}${false}${false}${false}";;
        2) printf "${false}${false}${true}${div}${false}${false}${false}";;
        3) printf "${false}${false}${false}${div}${true}${false}${false}";;
        4) printf "${false}${false}${false}${div}${false}${true}${false}";;
        5) printf "${false}${false}${false}${div}${false}${false}${true}";;
    esac
    echo "%{F-}"
}

function vol(){
    vol=$(awk -F"[][]" '/dB/ { print $2}' <(amixer sget Master) | tr % "  ")
    if [[ -n $(amixer get Master | grep off) ]]; then
        printf "%%{F${BRGR}}%%{R} \ue202 %%{R}"
    else
        if [[ ${vol} -gt 49 ]]; then
            printf "%%{F${BRGR}}%%{R} \ue203 %%{R}"
        else
            printf "%%{F${BRGR}}%%{R} \ue204 %%{R}"
        fi
    fi
    echo " ${vol}"
}

function window(){
    #WID=$(pfw)
    #cur=$(wname ${WID})
    cur=$(xdotool getwindowfocus getwindowname)
    echo "%{F${VDBL}}${cur}%{F-}" | cut -c -150
}

trap 'update' SIGUSR1

function update(){
    buf=""
    buf="${buf} %{l} $(desk)"
    buf="${buf} $(music)"
    buf="${buf} %{c}$(window)"
    buf="${buf} %{r} $(vol)"
    buf="${buf}$(now)"
    buf="${buf}$(today)"
    echo "${buf}"
}

while :; do
    read
done

The wrapper script.

#!/bin/zsh

fontOne="-mplus-fxd-medium-r-semicondensed--12-120-75-75-c-60-iso8859-15"
fontTwo="-wuncon-siji-medium-r-normal--10-100-75-75-c-80-iso10646-1"
size="1920x15+0+0"

VDBL="#458588" #Very Dark Blue
DKBL="#689d6a" #Dark Blue
DKRD="#cc241d" #Dark Red
BRRD="#fb4934" #Bright Red
BRYL="#fabd2f" #Bright Yellow
DKGR="#98971a" #Dark Green
BRGR="#b8bb26" #Bright Green
BRBL="#83a598" #Bright Blue
BKGD="#e832302f"
FRGD="#ebdbb2"
panel | lemonbar -f ${fontOne} -f ${fontTwo} -g ${size} -B ${BKGD} -F ${FRGD} -o 1&

Feel free to criticize any part of the script, I'm always looking to improve it. Thanks.

Update1: If it helps, I've noticed that when run alone, htop reports the script as "Sleeping" despite still producing output, whereas when launched from the wrapper it's reported as "Running".

Last edited by FoxzTrot (2016-06-26 06:35:03)

Offline

#2 2016-06-25 19:28:57

moetunes
Member
From: A comfortable couch
Registered: 2010-10-09
Posts: 1,033

Re: [Solved] Lemonbar script uses way more CPU when run from other script.

In the panel script, you have variables named time and date when there are already programs named time and date, that's poor sripting form. Echo adds a newline to what it prints unless you use the -n switch, how many lines is lemonbar showing? I'm not suprised when it doesn't do anything because you have a read that has nothing to read, unless zsh is magic, and you never call any of the functions you wrote. If it does have output of course it'll max a cpu as you don't have it wait at all between gathering infos, add a sleep after the read.

HTH


You're just jealous because the voices only talk to me.

Offline

#3 2016-06-25 21:31:26

FoxzTrot
Member
Registered: 2014-02-20
Posts: 20

Re: [Solved] Lemonbar script uses way more CPU when run from other script.

Variable names changed, thanks for the tip. I also added the "-n" to every echo, but interestingly enough it was working fine before that, producing only one line. The script actually does work fine and produces output, the reason for that is that I have several other scripts sending SIGUSR1 signals to this script which causes the trap to run the update() function, as well as interrupt the read. That way, the panel updates every second, or whenever a specific event (song change, window change, volume change) occurs. I did it this way since it's easier than sleeping for a determined time, and then killing the sleep job when an earlier update is needed. Thanks for the input.

The problem I'm having is that running ./panel produces the output in terminal with minimal resource usage, but running ./wrapper causes ./panel to constantly use 100% of a core.

Offline

#4 2016-06-25 22:36:21

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,521
Website

Re: [Solved] Lemonbar script uses way more CPU when run from other script.

The newlines don't matter as they are inside a function and you echo the result of the function as part of a string.

Your problem is that the loop with read in it just makes absolutely no sense at all.  What on earth is that for? (I have a guess below).

When you run this from a terminal, the read blocks waiting for input from a terminal, so it's fine and the script just waits and traps any signal.  When you run the script not from a terminal, there is no stdin to read from, so read returns immediately and the loop runs out of control.  The solution is to get rid of that ridiculous loop.

I'm guessing the reason you put the loop was so your script would not exit.  There are far better ways to do this - in fact you'd be hard pressed to find a worse way that a read loop.

Edit: presumably you have yet another process just sending a signal to this every second as you are displaying time in seconds.  Get rid of the extra process and just loop every second.  You can still have the signal to update more frequently as needed.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#5 2016-06-26 06:34:25

FoxzTrot
Member
Registered: 2014-02-20
Posts: 20

Re: [Solved] Lemonbar script uses way more CPU when run from other script.

Trilby wrote:

When you run this from a terminal, the read blocks waiting for input from a terminal, so it's fine and the script just waits and traps any signal.  When you run the script not from a terminal, there is no stdin to read from, so read returns immediately and the loop runs out of control.  The solution is to get rid of that ridiculous loop.

Yeup, that was exactly right. Although you're probably not gonna like how I fixed it. I simply had the wrapper script create /tmp/nothing.fifo which generates no output, and now the line is:

read < /tmp/nothing.fifo

CPU usage is now nominal with the whole bar running, thanks for the insight!

I realize the read loop looks ridiculous, but I decided to do it that way based on these two links. It's essentially the easiest way I've found to have a script wait for an interrupt and do stuff immediately upon receiving the signal. I tried the typical

sleep 1 &
wait

but that still waits for the sleep to end before updating the panel. The read loop works really well, and even with the couple of extra scripts running in the background, it's very lightweight.

Offline

Board footer

Powered by FluxBB