6

I have a bash script which runs other cpu-intensive commands .

When I apply cpulimit on the bash script, the output of top shows processes for the commands inside the script still run without limitation by cpulimit. I wonder how I can limit the cpu usage of the commands inside the bash script?

2

According to cpulimit --help:

-i, --include-children limit also the children processes

I have not tested whether this applies to children of children, nor looked into how this is implemented.


Alternatively, you could use cgroups, which is a kernel feature.

Cgroups don't natively provide a means to limit child processes as well, but you can use the cg rules engine daemon (cgred) provided by libcgroup; the cgexec and cgclassify commands that come from the libcgroup package provide a --sticky flag to make rules apply to child processes as well.

Be aware that there is a race condition involved which could (at least theoretically) result in some child processes not being restricted correctly. However, as you're currently using cpulimit which runs in userspace anyway, you already don't have 100% reliable CPU limitations so this race condition shouldn't be a deal-breaker for you.

I wrote rather extensively about the cg rules engine daemon in my self-answer here:

1

Probably, you can't.

cpulimit's logic is pretty simple, it takes pid of process and simply sending its signal kill -STOP $PID, thereafter kill -CONT $PID, and again, and again, and again, and again......

And measuring the cpu-usage to calculate delay between STOP and CONT.

In your case, pstree of complex bash-script would take N*x screens of console.

I can suggest to you another one method to downgrade cpu-usage of any bash-script or even binary executable.

1) nice - its taking process and increasing or decreasing its priority from -20(Highest priority) to 20(Lowest priority). Probably in too low diapason, that is why, there are appears another two utils and kernel hooks:

2) ionice - may be it is second generation of nice. You could separate processes by priority from 0(Lowest priority) to 7 (Highest priority). Plus, you could separate processes by classes, real-time( Highest ), best-efforts ( Middle ), Idle ( Lowest ) and None ( Default ).

3) chrt - the highest thing that I have ever met, it is similar to cpulimit by its power and dominion on process. Here you could too meet classes of priority, idle, real-time, fifo, batch, etc... And diapason of priorities very large, from 1 to 99.

For example, you could launch one huge process with chrt -r -p 99 process - and it will eats all of your resources.

The same way, any huge daemon could soft works in "background" with chrt -r -p 0 process - it will wait for everyone other while resources of a system is busy.

Anyway, I'm highly suggest you to read man chrt and man ionice before you start.

For example, I'm using rtorrent for p2p. It is lowest priority task for my system, then I'm launching it in such way:

nice -n 20 chrt -i 0 ionice -c3 /usr/bin/rtorrent

Or, you can take the hooks&haks way. And write your own cpulimit_wrapper script. For example:

# cat bash_script.sh 
#!/bin/bash


while sleep 0; do
        find /

        dd if=/dev/random of=/tmp/random.bin bs=1M count=1000
done

plus

# cat cpulimit.sh 
#!/bin/bash


TARGET=$1

[ -z "$TARGET" ] && echo "Usage bash cpulimit.sh command" && exit 1

cpulimit -l 1 bash $TARGET

while sleep 0;do
        lsof -n -t $TARGET | xargs pstree -p | sed -e 's/(/(\n/g' | sed -e 's/)/\n)/g' | egrep -v '\(|\)' | while read i; do 
                echo $i; 
                cpulimit -l 1 -b -p $i; 
        done
done
1

Now the best way for me was to run a script that lets cpulimit control processes in background from Askubuntu:

#!/bin/bash

#The first variable is to set the number of cores in your processor. The reason that the number of cores is important is that you need to take it into consideration when setting cpulimit's -l option.  This is explained on the cpulimit project page (see http://cpulimit.sourceforge.net/):  "If your machine has one processor you can limit the percentage from 0% to 100%, which means that if you set for example 50%, your process cannot use more than 500 ms of cpu time for each second. But if your machine has four processors, percentage may vary from 0% to 400%, so setting the limit to 200% means to use no more than half of the available power."

NUM_CPU_CORES=$(nproc --all) #Automatically detects your system's number of CPU cores.

cpulimit -e "ffmpeg" -l $((50 * $NUM_CPU_CORES))& #Limit "ffmpeg" process to 50% CPU usage.
cpulimit -e "zero-k" -l $((50 * $NUM_CPU_CORES))& #Limit "zero-k" process to 50% CPU usage.
cpulimit -e "mlnet" -l $((50 * $NUM_CPU_CORES))& #Limit "mlnet" process to 50% CPU usage.
cpulimit -e "transmission-gtk" -l $((50 * $NUM_CPU_CORES))& #Limit "transmission-gtk" process to 50% CPU usage.
cpulimit -e "chrome" -l $((40 * $NUM_CPU_CORES))& #Limit "chrome" process to 40% CPU usage.

Edit to what processes are used in your script and let it run. cpulimit will run in background and watch for asked processes and limits its use. If any of the processes is finished cpulimit will still stay and limit the processes if they ever come alive again.

(I encountered a strange problem were I tried to run ffmpeg through a for-loop in terminal. This paradoxically spawned two ffmpeg instances which made cpulimit'ing almost useless. I couldn't find an answer to what the problem is. So even if it's "just a for-loop" you might need to write a script for this.)

0

Use the -P parameter and place the absolute path before the executable.

-1

I tried setting up alias for cpulimit -l 50 ffmpeg in .bashrc

alias ffmpegl = "cpulimit -l 50 ffmpeg"

and then used it in my script with the following code to source aliases

shopt -s expand_aliases
source /home/your_user/.bashrc

Now i can use cpulimit with ffmpeg anywhere inside the script for multiple commands using the alias. Tested on scientific linux 6.5.Works perfectly.

2
  • unfortunately, the cpulimit command then goes into background, making iterative scripting impossible – phil294 Nov 1 '17 at 19:53
  • I also encountered this; as a workaround if iterations are not very complex, using a combination of 'find' piped to 'xargs' did the job for me. – Karthik M Jan 17 '18 at 13:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.