LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-21-2015, 08:46 AM   #1
äxl
Member
 
Registered: Feb 2013
Location: Germany, EU
Distribution: Debian (stable release)
Posts: 67

Rep: Reputation: 10
Bash script: Automatic BOINC temperature regulation


Hi all,

I wrote a simple bash script to change the CPU usage according to its temperature.
I wrote this for my AMD Athlon 64 X2 (R) [2006] on Debian Wheezy (should also work on Ubuntu ...?). You'll need the packages lm-sensors and sed. Note that you have to start this as root or with sudo rights (to change the BOINC owned preferences file).

The only thing I haven't got rid of is that it will output twice at start if you hit a time that corresponds with the OUTPUTPAUSE.
Suggestions and changes are welcome. I will update this post.

Use your favorite internet search enginge for your CPU's suggested temperature and set TARGTEMP.

I've set the interval of usage changes to 25 seconds and value of usage change to 4 %. This gives me quite stable output to the terminal. I'm not sure of decreasing the interval or increasing the value because this might influence the crunch results negatively.

Code:
#!/bin/bash
#Script to adapt BOINC's global CPU usage to CPU temperature
#Use your favorite internet search enginge
#for your CPU's suggested temperature
#Written for AMD Athlon 64 X2 (R) [2006]
#
#Released into the Public Domain or CC0, your choice.
#Thanks to grymoire.com, tldp.org, stackoverflow.com
#and all of the Free, Libre, Open Source Community.
#Version 0.2
#
#Usage:
#You can give the CPU usage as an argument and the script
#will set it and exit
#Run it without argument and it will adjust according to temperature

#Set target temperature of your CPU in Degree Celsius here:
TARGTEMP=50

#Value changes of CPU usage in percent
USAGELEAPS=4
#Can be adjusted in line 60 and 61 (e. g. -1 or +5).

#Set interval between usage changes (in seconds)
CHANGEPAUSE=25

#Set interval between screen outputs (in minutes)
OUTPUTPAUSE=5

#Simple check for dependencies
DEPENDENCIES="sensors sed"
for i in $DEPENDENCIES; do
if ! command -v "$i" >/dev/null
then echo "Please check if you have the package necessary for \033[1m$i\033[0m installed." && exit 1; fi; done

#Display (a kind of) progress bar graph of advised CPU usage
output () {
	echo -n "$CURRTEMP °C "
	echo -n $(date +"%H:%M")
	for i in $(seq 1 "$ADVCPU"); do echo -n "="; done
	echo -n "$ADVCPU"% && echo
}

#Change to BOINC_DIR and create temporary folder for backup
BOINCDAT=$(grep BOINC_DIR /etc/default/boinc-client | grep -v "^#" | cut -d"\"" -f2)
cd $BOINCDAT
mkdir -p tmp

#Set counter before "while loop" (v)
COUNTER=0

#Begin loop if BOINC is running
while [ -f "lockfile" ]; do
#Grab current CPU usage settings
CURRCPU=$(grep "<cpu_usage_limit>" global_prefs_override.xml | cut -d">" -f2 | cut -d"." -f1)
#Grab current temperature
CURRTEMP=$(sensors | grep "Core1 Temp" | head -1 | cut -d"+" -f2 | cut -d"." -f1)
#In-/Decrease usage by ^USAGELEAPS
if [[ "$CURRTEMP" -gt "$TARGTEMP"  &&  "$CURRCPU" -gt "$USAGELEAPS" ]]
	then ADVCPU=$(( $CURRCPU-$USAGELEAPS ))
	else ADVCPU=$(( $CURRCPU+$USAGELEAPS ))
fi

#If argument given set it as CPU usage
[ -n "${1}" ] && ADVCPU=$1

#Puts out advised CPU usage once at start (^ COUNTER=0)
if [ "$COUNTER" = 0 ]; then
	output
	COUNTER=1
fi

#Calculates pause for output on screen and to log by remainder
MINUTE=$(date +"%-M")
REMAINDER=$(( $MINUTE % $OUTPUTPAUSE ))
if [ "$REMAINDER" = 0 ] && [ "$MINUTE" != "$OLDMINUTE" ]; then
	output
#Save time to compare as to not output more than once in the same minute	
OLDMINUTE="$MINUTE"
fi

#Stream EDit line with cpu_usage_limit by substituting CURRCPU with ADVCPU
sed '/cpu_usage_limit/ s/'$CURRCPU'/'$ADVCPU'/' <global_prefs_override.xml >tmp/global_prefs_override.xml
#Check temporary backup and copy to original (errors go to output AND into boinctemp.log)
if grep "<cpu_usage_limit>"$ADVCPU"" tmp/global_prefs_override.xml 2>&1>/dev/null | tee -a boinctemp.log
	then cp tmp/global_prefs_override.xml global_prefs_override.xml
	else echo "Can't edit preferences file. Check your disk." && exit 1
fi
boinccmd --read_global_prefs_override
#if usage is given as argument, exit
[ -n "${1}" ] && exit
sleep "$CHANGEPAUSE"s
done
Apologies to other flavour users but this should be easily adaptable.
 
Old 07-04-2018, 10:04 AM   #2
äxl
Member
 
Registered: Feb 2013
Location: Germany, EU
Distribution: Debian (stable release)
Posts: 67

Original Poster
Rep: Reputation: 10
Can I change the original post?

Here's v0.5 of the script:
Code:
#!/bin/bash
#Script to adapt BOINC's global CPU usage to CPU temperature
#Use your favorite internet search enginge
#for your CPU's suggested temperature
#Written for AMD Athlon 64 X2 (R) [2006]
#
#Released into the Public Domain or CC0, your choice.
#Thanks to grymoire.com, tldp.org, stackoverflow.com
#and all of the Free, Libre, Open Source Community.
#Version 0.5
#
#Usage:
#You can give the CPU usage as an argument 
# and the script will set it and exit
#Run it without argument and it will adjust according to temperature

#Set target temperature of your CPU in Degree Celsius here:
TARGTEMP=60

#Value changes of CPU usage in percent
USAGELEAPS=4
#Can be adjusted in line 60 and 61.

#Set interval between usage changes (in seconds)
CHANGEPAUSE=60

#Set interval between screen outputs (in minutes)
OUTPUTPAUSE=1

#Simple check for dependencies
DEPENDENCIES="sensors sed"
for i in $DEPENDENCIES; do
if ! command -v "$i" >/dev/null
then echo "Please check if you have the package necessary for \033[1m$i\033[0m installed." && exit 1; fi; done

#Function for displaying (a kind of) progress bar graph of advised CPU usage
output () {
	echo -n "$CURRTEMP °C "
	echo -n $(date +"%H:%M")
	echo -n " $ADVCPU"% && echo
}

#Change to BOINC_DIR and create temporary folder for backup
BOINCDAT=$(grep BOINC_DIR /etc/default/boinc-client | grep -v "^#" | cut -d"\"" -f2)
cd $BOINCDAT
mkdir -p tmp

#Set counter before "while loop" (v)
COUNTER=0

#Begin loop if BOINC is running
while [ -f "lockfile" ]; do
#Grab current CPU usage settings
	CURRCPU=$(grep "<cpu_usage_limit>" global_prefs_override.xml | cut -d">" -f2 | cut -d"." -f1)
#Grab current temperature
	CURRTEMP=$(sensors | grep "Core1 Temp" | head -1 | cut -d"+" -f2 | cut -d"." -f1)
#Make sure that advised CPU usage will not fall under 1
#In-/Decrease usage by ^USAGELEAPS
	if [[ "$TARGTEMP" -ge "$CURRTEMP" ]]
	then if [[ "$ADVCPU" -lt 100-"$USAGELEAPS" ]]
		then ADVCPU=$(( $CURRCPU+$USAGELEAPS ))
		else ADVCPU=99
	fi
	fi
	if [[ "$TARGTEMP" -lt "$CURRTEMP" ]]
	then if [[ "$ADVCPU" -gt 1+"$USAGELEAPS" ]]
		then ADVCPU=$(( $CURRCPU-$USAGELEAPS ))
		else ADVCPU=1
	fi
	fi	

#set CPU usage to 50 at start
[ "$COUNTER" -eq 0 ] && ADVCPU=50
#If argument given set it as CPU usage
[ -n "${1}" ] && ADVCPU=$1

#Sometimes puts advised CPU usage above 100%
#meaning that it will take longer to come back down 
#to normal percentage. If the script sets it to 0 
#it will also go to 100. So here's a warning:
	CHECKCPU=$(grep "<cpu_usage_limit>" global_prefs_override.xml | cut -d">" -f2 | cut -d"." -f1)
	if [[ "$CHECKCPU" -gt 99-"$USAGELEAPS" || "$CHECKCPU" -lt 2+"$USAGELEAPS" ]]
		then echo "Check BOINC's CPU usage limit!"
	fi

#Puts out advised CPU usage once at start (^ COUNTER=0)
if [ "$COUNTER" = 0 ]; then
	output
	COUNTER=1
fi

#Calculates pause for output on screen and to log by remainder
MINUTE=$(date +"%-M")
REMAINDER=$(( $MINUTE % $OUTPUTPAUSE ))
if [ "$REMAINDER" = 0 ] && [ "$MINUTE" != "$OLDMINUTE" ]; then
	output
#Save time to compare as to not output more than once in the same minute	
OLDMINUTE="$MINUTE"
fi

#Stream EDit line with CPU usage by substituting CURRCPU with ADVCPU
sed '/cpu_usage_limit/ s/'$CURRCPU'/'$ADVCPU'/' <global_prefs_override.xml >tmp/global_prefs_override.xml
#Check temporary backup and copy to original (errors go to output AND into boinctemp.log)
if grep "<cpu_usage_limit>"$ADVCPU"" tmp/global_prefs_override.xml 2>&1>/dev/null | tee -a boinctemp.log
	then cp tmp/global_prefs_override.xml global_prefs_override.xml
	else echo "Can't edit preferences file. Check your disk." && exit 1
fi
boinccmd --read_global_prefs_override
#if usage is given as argument, exit
[ -n "${1}" ] && exit
sleep "$CHANGEPAUSE"s
done

Last edited by äxl; 07-04-2018 at 10:06 AM.
 
Old 07-12-2018, 10:16 AM   #3
sag47
Senior Member
 
Registered: Sep 2009
Location: Raleigh, NC
Distribution: Ubuntu, PopOS, Raspbian
Posts: 1,899
Blog Entries: 36

Rep: Reputation: 477Reputation: 477Reputation: 477Reputation: 477Reputation: 477
Upload it to GitHub where changes can be tracked by interested people. After a time period you can no longer edit your own posts.
 
1 members found this post helpful.
Old 02-05-2019, 05:55 AM   #4
äxl
Member
 
Registered: Feb 2013
Location: Germany, EU
Distribution: Debian (stable release)
Posts: 67

Original Poster
Rep: Reputation: 10
Thanks, sag47.
https://gitlab.com/UMLAUTaxl/boincte...r/boinctemp.sh
 
1 members found this post helpful.
Old 02-10-2019, 10:14 AM   #5
sag47
Senior Member
 
Registered: Sep 2009
Location: Raleigh, NC
Distribution: Ubuntu, PopOS, Raspbian
Posts: 1,899
Blog Entries: 36

Rep: Reputation: 477Reputation: 477Reputation: 477Reputation: 477Reputation: 477
Hi axl, a little bit of feedback if you don’t mind. For a temp directory I recommend using mktemp command. I also recommend using a “bash trap function” to automatically clean up your tmp on exit. Here’s a sample

Code:
function cleanup_on() {
    [ -z "${TMP_DIR%/}" ] || rm -rf "${TMP_DIR}"
}
trap cleanup_on EXIT

export TMP_DIR="$(mktemp -d)"

# now you can write to TMP_DIR and it will auto cleanup on exit
echo stuff > "${TMP_DIR}/file.txt"

Last edited by sag47; 02-10-2019 at 09:02 PM.
 
Old 02-10-2019, 11:04 AM   #6
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,850

Rep: Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309
do not use both [ ] and [[ ]]. I think [[ ]] is preferred (and good enough).
please use shellcheck to test your script.

I think line 115 will not do what you wish:
Code:
if grep "<cpu_usage_limit>"$ADVCPU"" tmp/global_prefs_override.xml 2>&1>/dev/null | tee -a boinctemp.log
# if will check the return code of tee (not the grep) which is [almost] always 0
# redirection should be written as: grep .... >/dev/null 2>&1
# how do you want to use tee if result was redirected to /dev/null?
# use grep -q if you do not need the result
# also see what shellcheck reports
avoid using grep|cut|sed|head and similar chains, they are usually can be solved with a single command (which is obviously more efficient)
 
1 members found this post helpful.
Old 02-10-2019, 08:52 PM   #7
sag47
Senior Member
 
Registered: Sep 2009
Location: Raleigh, NC
Distribution: Ubuntu, PopOS, Raspbian
Posts: 1,899
Blog Entries: 36

Rep: Reputation: 477Reputation: 477Reputation: 477Reputation: 477Reputation: 477
Quote:
Originally Posted by pan64 View Post
do not use both [ ] and [[ ]]. I think [[ ]] is preferred (and good enough).
please use shellcheck to test your script.
I also recommend shellcheck but to be clear shellcheck does not care about usage of [ ] or [[ ]] or a mix. It does warn you about known bad practices, though. As long as [ ] is not used with more than two expressions (which violates POSIX compatibility) it really doesn’t matter which. If you do use [[ ]] at all then I do recommend being consistent in your usage.

The trap function I gave is also compatible with “set -e”.

Last edited by sag47; 02-10-2019 at 08:54 PM.
 
Old 03-02-2019, 05:00 AM   #8
äxl
Member
 
Registered: Feb 2013
Location: Germany, EU
Distribution: Debian (stable release)
Posts: 67

Original Poster
Rep: Reputation: 10
Thanks for the feedback. Unless someone reports a compatibility problem I don't care for conventions.
But you're right, pan64. boinctemp.log isn't even created although I had many errors. (Mainly due to connection problems to the BOINC Manager I presume.)
Although it's not needed anymore since I run the script in it's own terminal: How else do I "double log" then (to terminal and a log file) if grep outputs an error?

On further inspection this part might have been why the script sometimes went awry!? Needs more testing.
 
Old 03-02-2019, 10:59 AM   #9
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,850

Rep: Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309
Quote:
Originally Posted by äxl View Post
How else do I "double log" then (to terminal and a log file) if grep outputs an error?
You must not redirect stderr to /dev/null if you want to write it into a log file (or more), 2>/dev/null will eat up your error messages.

Last edited by pan64; 03-02-2019 at 12:13 PM.
 
Old 03-16-2019, 12:07 PM   #10
äxl
Member
 
Registered: Feb 2013
Location: Germany, EU
Distribution: Debian (stable release)
Posts: 67

Original Poster
Rep: Reputation: 10
Sooo after two weeks of letting it run this seemed to be the culprit of it sometimes bugging out, suddenly jumping to 100% with no explanation. Thanks again, pan64.
https://gitlab.com/UMLAUTaxl/boincte...685a6a060469e8

But I don't understand what you're saying about redirecting. Is redirecting the problem? I thought it was "just" that the pipe was breaking my if-condition.
tee was created to send output into a terminal and a log file. So I would presume it's something like:
Code:
grep foo checkfile | tee -a logfile
Now if I want to check if foo is actually in the checkfile and send error codes into terminal and logfile tee is the way isn't it?
Code:
if grep foo checkfile | tee -a logfile
	then echo "checks out"
	else echo "failed"
fi
I understand that's not working. But how else would it work?
 
Old 03-16-2019, 12:23 PM   #11
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,850

Rep: Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309
I would rather write:
Code:
if grep ....
then ....
else
fi | tee -a logfile
 
1 members found this post helpful.
Old 03-17-2019, 10:24 AM   #12
äxl
Member
 
Registered: Feb 2013
Location: Germany, EU
Distribution: Debian (stable release)
Posts: 67

Original Poster
Rep: Reputation: 10
Thanks. Output is like this now:
Code:
79 °C 19:11 25%
   <cpu_usage_limit>25.000000</cpu_usage_limit>
76 °C 19:12 21%
   <cpu_usage_limit>21.000000</cpu_usage_limit>
boinctemp.log like this:
Code:
   <cpu_usage_limit>25.000000</cpu_usage_limit>
   <cpu_usage_limit>21.000000</cpu_usage_limit>
But I want error messages and desired output on terminal and in the log file only error messages.

This changes nothing regarding output and logging:
Code:
if grep .... 2>&1
....

Last edited by äxl; 03-17-2019 at 10:26 AM.
 
Old 03-17-2019, 12:31 PM   #13
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,850

Rep: Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309
if you mix stdout and stderr into a logfile (or anywhere else) you cannot separate them any more.
grep can only parse the specified input (either stdin or file[s]), tee can redirect only its input to two [or more] different locations.
 
1 members found this post helpful.
Old 03-18-2019, 05:55 PM   #14
äxl
Member
 
Registered: Feb 2013
Location: Germany, EU
Distribution: Debian (stable release)
Posts: 67

Original Poster
Rep: Reputation: 10
Soooo like this if I only want stderr in terminal and logfile?
Code:
if grep .... 1>/dev/null
then ....
else
fi | tee -a logfile
 
Old 03-19-2019, 01:57 AM   #15
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,850

Rep: Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309Reputation: 7309
why don't you try it?
stderr of what ?
 
1 members found this post helpful.
  


Reply

Tags
bash, boinc, linux, script, temperature



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
bash script automatic file rename if exists AutoC Programming 4 06-23-2015 03:31 PM
Temperature inside computer box and CPU temperature Lola Kews Linux - Hardware 14 11-29-2013 06:22 PM
Bash script for automatic viewport changing and other WM stuff (works with compiz) Juako Programming 8 01-05-2011 06:35 AM
Console/ bash: Post your script to retrieve and echo the weather/temperature ? frenchn00b Linux - General 1 02-16-2008 09:45 AM
send automatic input to a script called by another script in bash programming jorgecab Programming 2 04-01-2004 12:20 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:35 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration