Script BASH per controllo temperatura CPU

Stampa
( 0 Votes ) 
Valutazione attuale:  / 0
ScarsoOttimo 
Categoria: Informatica
Data pubblicazione
Scritto da MGuruDC Visite: 2429

Script BASH per controllo temperatura CPU

Uno script per il controllo della temperatura della CPU via software

A partire da questa estate il mio computer ha cominciato ad avere problemi termici a causa di alcuni problemi col dissipatore.
Visto che il computer era ancora in garanzia non potevo ripararlo da solo né rimanere giorni e giorni senza mandandolo in assistenza, quindi ho escogitato un modo per tenere sotto controllo la temperatura della CPU tramite uno script BASH per Linux.



La teoria è molto semplice:
Se uno o più processi richiede molte operazioni al processore, la coda dello scheduler si riempie, la CPU lavora di continuo e la temperatura aumenta.
Questo script va ad "interferire" con le operazioni dello scheduler per liberare la coda e "mitigare" la temperatura.
Per liberare la coda d'esecuzione basta mettere in pausa i processi, se andiamo a mettere in pausa i processi che in quel momento occupano di più la CPU otteniamo anche il desiderato abbassamento di temperatura.

Sorgono un po' di questioni:
- Non è rischioso intervenire nelle operazioni dello scheduler?
In teoria si, ma nella pratica non ha mai dato problemi. Mettere in pausa un processo che magari sta dialogando con altri elementi può causare dei crash, non mi è mai successo ma c'è la possibiiltà. C'è anche il rischio che lo script metta in pausa se stesso o i suoi processi figli, ma anche questo non è mai successo.
- Mettere in pausa i processi non mina l'usabilità del computer?
Si, se il nostro computer è già molto carico e ad esempio andiamo ad aprire un video su YouTube il nostro browser quasi sicuramente verrà messo in pausa, quindi fin quando la temperatura non tornerà nella norma il video sarà fermo e il browser non risponderà a nessun comando. Se ad esempio stiamo convertendo un video, il convertitore verrà messo continuamente in pausa e poi riavviato, quindi il tempo di conversione aumenterà parecchio. A ogni modo è meglio avere questi problemini piuttosto che lo spegnimento del computer per sovraccarico termico.
- Fermare processi attraverso altri processi... non è controproducente?
Finché le operazioni compiute sono semplici il problema non si pone, ma se si chiedono operazioni più complesse la velocità di intervento dello script si abbassa e i suoi effetti svaniscono, per questo motivo ad esempio ho mantenuto un sistema rigido e non scalabile, ho implementato i controlli sulla frequenza di lavoro della CPU ma non li ho attivati. Un buon compromesso è tenere una temperatura d'intervento abbastanza bassa e avviare lo script con la massima priorità.
- Che prestazioni ha questo sistema?
In termini di efficienza e velocità va molto bene, e questa efficienza aumenta con l'aumentare della priorità del processo. In precisione invece non va molto bene, il processore infatti sale in temperatura molto velocemente, dunque quando lo script ha appena cominciato ad intervenire la temperatura potrebbe essere già 5-10°C più alta della soglia di intervento. Nelle ultime prove che fo fatto, con una soglia di intervento a 50°C la CPU ha toccato un picco di 58°C
- Qual'è la temperatura di intervento ideale?
Dipende dal nostro sistema, dall'architettura e dal nostro uso del computer. Sul mio computer con dissipatore molto sottodimensionato e ventola poco efficiente e spesso bloccata la temperatura d'intervento ideale è 60°, ma con sistemi di raffreddamento efficienti questa soglia può essere spostata a 80° considerando che nei processori moderni lo spegnimento automatico per surriscaldamento avviene intorno ai 90°. Per CPU AMD consiglio di tenere più bassa la soglia, visto che gli AMD sono notoriamente più "focosi". La portabilità è 0% e 100%... 0% perché lo script fa uso del programma "sensors" che potrebbe non essere disponibile per tutte le architetture ma è facilmente adattabile ad un altro programma; 100% perché gli altri comandi usati sono standard per i sistemi Linux e Unix ed essendo uno script non c'è alcun problema di compatibilità binaria.

Tiriamo le somme: su un sistema non funzionante come il mio, lo script è un ottimo palliativo, è una dialisi in attesa del nuovo rene(=dissipatore ), su un sistema efficiente invece, con tempi di controllo dilatati servirebbe a scongiurare il sovraccarico termico nel raro caso in cui venga raggiunto.

Ora vediamo come funziona. Come ho già detto l'algoritmo è molto rigido perché deve essere velocissimo.
Si tratta di due cicli annidati, il più esterno esegue ogni 2 secondi un controllo sulla temperatura e in caso di necessità fa partire quello più interno che ferma un processo al secondo finché la temperatura non torna normale, una volta stabilizzata la temperatura vengono riavviati tutti i processi. Ecco il diagramma di flusso:

 

 

Vediamo il codice implementato per un processore a due core:

#/bin/bash

AlTemp=60

while true
    do
    stop=0
    intervento=0 
    stringa=`sensors`
    temp0=${stringa:53:2}
    temp1=${stringa:152:2}
    if ((temp0>$AlTemp || temp1>$AlTemp))
        then
        intervento=1
#        cpufreq-selector -c 0 -f 800000            #blocca la frequenza della prima CPU ad 800MHz
#        cpufreq-selector -c 1 -f 800000            #blocca la frequenza della seconda CPU ad 800MHz
        fi

Come prima cosa viene registrata la temperatura di intervento desiderata nella variabile "AlTemp", in questo caso 60°C, poi parte il ciclo infinito che terrà in vita lo script fino alla sua uccisione o allo spegnimento del PC. "intervento" e "stop" sono dei registri che memorizzano se è necessario intervenire e se è stato fermato qualche processo. La variabile "stringa" è solo d'appoggio per lavorare sul risultato del comando "sensors". Questo comando infatti stampa una stringa del genere:

coretemp-isa-0000
Adapter: ISA adapter
Core 0:      +34.0°C  (high = +100.0°C, crit = +100.0°C) 

coretemp-isa-0001
Adapter: ISA adapter
Core 1:      +32.0°C  (high = +100.0°C, crit = +100.0°C) 

quindi con il comando "${stringa:posizione:lunghezza}" andiamo ad estrarre da questo output le temperature dei due core e a memorizzarle nelle variabili "temp0" e "temp1"
Se una delle due temperature è maggiore dei 60°C fissati prima viene registrata la necessità di intervenire.
Come potete notare ci sono due righe disattivate contenenti un comando che blocca a 800MHz la frequenza delle CPU ma preferisco escluderle poiché il comando "cpufreq-selector" rallenta troppo lo script. Con implementazioni migliori del comando oppure l'esecuzione su sistemi con un solo processore il comando può essere usato.

    while ((intervento==1))
        do
        stringa=`ps aux --sort -%cpu | head -n2 | awk '{print $2}'`
        PID=${stringa:4}
        kill -19 $PID
        stop=1
        sleep 1s
        intervento=0
        stringa=`sensors`
        temp0=${stringa:53:2}
        temp1=${stringa:152:2}
        if ((temp0>$AlTemp || temp1>$AlTemp))
            then
            intervento=1
            fi
        done

Se è  stato richiesto un intervento parte il secondo ciclo che come prima cosa va a cercare il PID(numero identificativo) del processo che in quel momento stressa di più la CPU. Per fare ciò dovremo concatenare tre comandi: il primo, "ps aux --sort -%cpu" ci mostra la lista dei processi e ce la ordina secondo la percentuale di CPU utilizzata. Ecco un esempio di output del primo comando

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
marco     3778  7.4  1.5 238536 48056 ?        Sl   14:58  13:35 rhythmbox /home/marco/Scrivania/MusicaTmp/...
root        1423  6.9  1.3 313076 40480 tty7     Ss+  13:51  17:23 /usr/bin/X :0 -br -verbose -auth /var/run/gdm/...
marco     3482  4.7  2.9 397324 90996 ?        Sl   14:39   9:34 /usr/lib/firefox-3.5.8/firefox
marco     2434  3.8  0.1 225416  5268 ?        Ssl  13:51   9:27 /usr/bin/pulseaudio --start
marco     3529  3.5  4.1 1054544 129124 ?      Sl   14:40   7:01 /usr/lib/jvm/java-6-openjdk/jre/lib/i386/...
[...]

In questa tabella abbiamo tutti i dati riguardanti i processi, queste sono solo le prime righe, ma ne sono centinaia.
Come potete vedere in quel momento il processo più pesante era rithmbox con cui stavo ascoltando della musica, seguito da gdm, poi firefox, il server audio e il supporto java. A noi interessa solo la prima riga, per questo concateniamo il comando "head -n2" e l'output si riduce a

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
marco     3778  7.3  1.5 238536 48124 ?        Sl   14:58  13:50 rhythmbox /home/marco/Scrivania/MusicaTmp/...

In ultimo concatenando il comando "awk '{print $2}'" avremo in uscita solo la seconda colonna della tabella

PID
3778

Adesso il PID del processo è identificato in maniera univoca e memorizzato nella variabile "PID" con il comando "PID=${stringa:4}"
Il PID quindi viene dato in pasto al comando "kill -19 $PID" che con l'opzione "-19" non ucciderà il processo ma lo fermerà soltanto inviando il segnale "STOP" anziché il "KILL" che invia normalmente.
Dopo aver registrato che un processo è stato fermato lo script si mette in pausa per 1 secondo dopodiché rilegge la temperatura della CPU.
Se la temperatura è ancora alta il ciclo viene ripetuto.

    if ((stop==1))
        then
        killall -CONT -u `users |awk '{print $1}'`
#        cpufreq-selector -c 0 -g ondemand        #reimposta la prima CPU in modalità "ondemand"
#        cpufreq-selector -c 1 -g ondemand        #reimposta la seconda CPU in modalità "ondemand"
        echo tutti i processi sono stati riavviati
        fi
    sleep 2s
    done

Se qualche processo è stato fermato, una volta abbassata la temperatura va riavviato. Il comando "killall" invia un segnale a più processi, in questo caso mandiamo un "CONT" a tutti i processi dell'utente, i processi attivi semplicemente ignoreranno il segnale, mentre quelli fermati si rimetteranno in esecuzione. Per determinare il nome dell'utente useremo i due comandi concatenati "users |awk '{print $1}'", il primo stampa la lista degli utenti attivi, il secondo prende solo la prima colonna di questa lista.
Se precedentemente è stato usato il comando "cpufreq-selector" bisogna attivare le due righe successive che sbloccano la frequenza di lavoro della CPU.
Alla fine script viene messo in pausa per 2 secondi e poi ricomincia da capo.

Spero sia utile a qualcuno
Saluti
Guru

Joomla 1.7 Templates designed by College Jacke