OpenScheme : Utilisation CPU et charge de batterie
Par :
Guilhem de Wailly (gdw@erian-concept.com)
et :
Fernand Boéri (boeri@unice.fr)
Résumé
Nous poursuivons la programmation d'exemples utilisant la bibliothèque graphique d'OpenScheme avec un petit programme permettant d'afficher des informations relatives à la charge du processeur et à la charge de la batterie des ordinateurs portables.
L'environnement OpenScheme est disponible sur le CDROM de Linux Magazine. Il est aussi disponible sur www.open-scheme.com. Cet environnement existe en version libre ou commerciale.
Introduction
Ce mois-ci, nous continuons à utiliser la bibliothèque graphique d'OpenScheme pour écrire un petit programme permettant d'afficher l'utilisation des ressources du système. Pour rester simples, les ressources affichées sont l'utilisation du CPU et la charge de la batterie des portables. Le programme est configurable en modifiant les sources. Nous aurions pu utilisation le module OP de OpenScheme permettant de manipuler les fichiers d'initialisation .ini, mais le texte aurait été trop long pour cet article.
Le moniteur crée une fenêtre sur l'écran dans laquelle s'affichent deux règles indiquant la charge du processeur et la charge de la batterie, comme le montre la figure suivante :
Figure 1: Fenêtre du moniteur : la règle du haut indique la charge du CPU, la règle du bas indique la charge de la batterie.
La fenêtre du moniteur est découpée en deux parties : la première affiche la jauge de l'utilisation du processeur. La seconde jauge affiche l'état de la charge de la batterie avec une couleur différente si la batterie est en charge. La fenêtre n'est pas gérée par le gestionnaire de fenêtres ; aussi, elle est affichée sans cadre et sans titre, et elle se déplace dans les bureaux virtuels.
Le programme est organisé autour d'un temporisateur (timer) qui consulte régulièrement l'état du système et affiche les deux jauges.
Informations Linux
Les informations que l'on souhaite afficher sont situées dans le répertoire /proc des systèmes Linux. Ce programme ne fonctionne donc que sous Linux.
Le répertoire /proc contient des fichiers virtuels dont le contenu correspond à des informations du noyau Linux. Ces fichiers peuvent être consultés par simple lecture.
Les deux fichiers de /proc qui l'on souhaite consulter sont /proc/loadavg pour les informations sur le processeur, et le fichier /proc/apm pour les informations relatives à la batterie.
Pour consulter le fichier /proc/loadavg, on peut taper :
$ cat /proc/loadavg
0.13 0.00
0.00 2/45 704
L'information qui nous importe est le premier nombre qui correspond à la charge du processeur. La consultation des pages de manuel donnera la signification des autres champs.
L'autre fichier, /proc/apm, peut etre consulatable avec :
$ cat /proc/apm
1.9 1.2 0x03
0x01 0x03 0x09 89% -1 ?
Les informations qui nous intéressent sont la quatrième valeur et la septième valeur. Lorsque la quatrième valeur vaut 0x01, le portable est en charge ; lorsqu'elle vaut 0x00, le portable fonctionne sur la batterie. La septième valeur indique le taux de charge de la batterie qui vaut 100% lorsque la batterie est entièrement chargée.
Timer
Le moniteur que nous allons programmer utilise les timers pour rafraîchir l'affichage de manière périodique. Aussi, nous décrivons dans cette section la bibliothèque correspondante.
La bibliothèque des timer est inclue dans OpenScheme dans le plugin OT. Elle composée des fonctions suivantes :
ï‚· (timer:new proc .
milisec)
Cette fonction retourne un nouveau timer
attaché à la fonction proc
sans argument. Cette fonction sera invoquée toutes les
milisec millisecondes, ou
avec une valeur par défaut. L'usage de la valeur par défaut
est recommandé.
Le timer, une fois créé,
n'est pas actif.
L'objet est automatique libéré
lorsqu'il n'est plus utilisé.
ï‚· (timer? object)
Cette
fonction retourne #t si
l'objet est un timer, et
#f sinon.
ï‚· (timer:start timer)
Cette
fonction démarre le timer
donnée en argument.
ï‚· (timer:stop timer)
Cette
fonction stoppe le timer
donné en argument.
ï‚· (timer:interval
timer)
Cette fonction retourne l'intervalle de temps
en millisecondes séparant les différentes invocations
du timer.
ï‚· (timer:proc timer)
Enfin,
cette fonction retourne la procédure attachée au
timer. Il est ainsi
possible d'enchaîner les différentes procédures.
Les timers sont préhemptifs, c'est à dire qu'ils peuvent survenir à n'importe quel moment. La bibliothèque d'OpenScheme est rendue réentrante, ce qui permet de gérer au plus bas niveau par la machine virtuelle l'ordonnancement des appels.
Le programme
Le programme présenté dans ces lignes est disponible à l'adresse http://www.open-scheme.com/pub/cpuinf.osm.
Fonction principale
La fonction principale est chargée de déclarer un certain nombre de constantes, créer la fenêtre du moniteur et d'initialiser le timer. Nous avons :
; initialisation des
bibliothèques
(use 'r4rs) ;
bibliothèque standard
(use 'ok) ;
fonctions graphiques
(use 'ot) ; timer
; constantes
;
position (x,y) de la fenêtre
(define X
0)
(define Y 0)
;
largeur de la fenêtre
(define WIDTH
50)
; hauteur de chacune des jauges
(define
HEIGHT 10)
; marges entre les bords de la
fenêtre
; les jauges
(define MARGIN
2)
; couleur du fond de la fenêtre
(define
BACKGROUND/COLOR ok:white)
; couleur de la jauge
processeur
(define LOAD/COLOR ok:red)
;
couleur de la jauge batterie
(define APM/COLOR
ok:blue)
; couleur de la jauge de la batterie
;
lorsque la batterie n'est pas en
; charge
(define
APM/BAT/COLOR ok:red)
; fonction
principale
(define (main)
(let* (;
création de la fenêtre
[win
(ok:create-window
#t
BACKGROUND/COLOR
X
Y
WIDTH
(+ HEIGHT HEIGHT
MARGIN MARGIN MARGIN))]
; création du
timer
[timer (timer:new (lambda ()
(refresh win))
1000)])
; fonction de rappel pour les touches
;
relâchées au dessus de la fenêtre
(ok:release-callback! win
(lambda
(key)
(timer:stop timer)
#f))
; fonction de rappel pour
le
; rafraîchissement
(ok:refresh-callback! win
(lambda
()
(refresh win)
#t))
; la fenêtre est affichée
normalement
(ok:show win ok:show:normal)
;
le timer est démarré
(timer:start
timer)
; les événements graphiques sont
; traités
(ok:exec)))
La fonction crée la fenêtre de l'application. Le premier argument est la fenêtre parente, ici #t. Lorsque le parent est #t, la fenêtre est créée sans être gérée par le gestionnaire de fenêtres ; elle sera donc affichée sans décorations et échappe à la gestion standard. Si le parent est #f, la fenêtre est gérée par le gestionnaire de fenêtres. Les arguments suivants sont la couleur du fond de la fenêtre, la position (x,y) du coin en haut à gauche de la fenêtre, la largeur et la hauteur de la fenêtre.
Le timer est créé avec une fonction de rappel invoquée toutes les secondes. Cette fonction rafraîchit le contenu de la fenêtre avec la fonction refresh définie plus loin. Le timer n'est pas encore actif ; il le sera après l'appel à la fonction timer:start.
Lorsqu'une touche est relâchée au-dessus de la fenêtre du moniteur, la fonction de rappel correspondante à l'appel à ok:release-callback! est invoquée. La fonction de rappel stoppe le timer est retourne #f, ce qui a pour effet de stopper aussi le traitement des événements initié par l'appel à ok:exec ; la fonction main se termine donc entraînant l'arrêt du programme.
L'affichage du contenu de la fenêtre est confié à la fonction de rappel positionnée par l'appel à ok:refresh-callback!. Là, nous appelons la fonction , définie plus bas.
Rafraîchissement
Le rafraîchissement de la fenêtre se contente d'appeler deux fonctions d'affichage définies plus loin, l'une pour les informations du processeur, l'autre pour les informations de la batterie :
(define (refresh win)
(let* (; dimensions de la fenêtre
[rec (ok:rectangle win)]
; largeur de la
fenêtre
[w (vector-ref rec 2)])
; affichage des jauges
(draw-load win w 0)
(draw-apm win w (+ MARGIN HEIGHT))
; force le
traitement des événements
(ok:show win
ok:show:normal)))
Les fonctions d'affichage sont invoquées avec la fenêtre comme argument, ainsi que la largeur de la fenêtre et la position y où l'affichage doit avoir lieu. La fonction ok:show est invoquée pour forcer le traitement des événements par le gestionnaire d'affichage. En effet, la plupart des affichages dans la fenêtre vont être effectués suite à l'activation du timer ; hors sans cet appel, le gestionnaire risque de placer les événements générés dans un tampon et de ne traiter que les derniers événements, rendant du même coup l'affichage incohérent.
Informations du processeur
Cette fonction est chargée d'effectuer l'affichage des informations du processeur. Elle est définie par :
(define (draw-load win w
y)
(let (; lecture de la valeur
[load (with-input-from-file
"/proc/loadavg"
read)])
;
interdire le 0 pour la division
(if (zero?
load)
(set! load 0.001))
; dessine la
jauge
(draw-slider win w y
(inexact->exact
(/ (* (- w MARGIN
MARGIN)
load)
(ceiling load)))
LOAD/COLOR)
;
dessin des unités
(let ([l (quotient
(- w MARGIN MARGIN)
(ceiling
load))])
(do ([i 1 (+ i 1)]
[x
(+ MARGIN l)(+ x l)])
((> i (floor load)))
(ok:draw-line win
x MARGIN
0 HEIGHT)))))
La première partie de la fonction lit la valeur de cette jauge directement dans le fichier loadavg dans /proc. Cette lecture est effectuée avec la fonction with-input-from-file qui prend comme argument un nom de fichier et une procédure sans argument. Le corps de cette procédure est invoqué avec comme fichier standard d'entrée le contenu du fichier donné. Ici, la procédure est la fonction read qui lit un objet Scheme. Comme le premier champ du fichier est celui qui nous intéresse, un seul appel à read est nécessaire. Si la valeur retournée dans load est nulle, nous la plaçons à une valeur presque nulle de manière à éviter les divisions par zéro.
Ensuite la fonction invoque draw-slider définie plus bas, avec comme arguments la fenêtre, sa largeur et la position ou la jauge dit être dessinée, la largeur de la valeur à indiquer dans la jauge, et enfin sa couleur.
Ensuite, nous traçons des lignes verticales pour indiquer les unités.
Remarquons que la fonction ceilling renvoie la plus petite valeur entière plus grande que la valeur passée en argument, et que la fonction floor renvoie la plus grande valeur entière plus petite que l'argument.
Informations de la batterie
L'affichage des informations relatives à la batterie s'effectue de la même manière que dans la fonction précédente :
(define (draw-apm win w
y)
(let (; valeurs à lire
[bat #f]
[charge #f])
; lecture dans le
fichier
(with-input-from-file
"/proc/apm"
(lambda ()
(read)
(read)
(read)
;
conversion en booléen
(set! bat (eq?
(read) '0x00))
(read)
(read)
; conversion en entier
(set!
charge
(string->number
(substring (symbol->string (read))
0
2)))))
;
dessin de la jauge
(draw-slider win w y
(if (negative? charge)
0
(quotient (* (- w MARGIN MARGIN)
charge)
100))
(if bat APM/BAT/COLOR APM/COLOR))))
La seule difficulté est que la lecture des informations relatives à la batterie à partir du fichier /proc/apm ne peut être effectuée avec un seul read. De plus les valeurs qui nous intéresse dans fichier /proc/apm ne sont pas de objets Scheme ; aussi, il nous faut les convertir.
En ce qui concerne l'affichage, nous utilisons une couleur différente si la batterie est ou non connectée au secteur.
Affichage de la jauge
La dernière fonction du programme dessine une jauge :
(define (draw-slider win
w y width color)
; dessin de la jauge
(ok:foreground! win color)
(ok:background! win color)
(ok:draw-rectangle win
MARGIN (+ y MARGIN)
width
HEIGHT)
;
dessin du cadre autour de la jauge
(ok:foreground! win
ok:black)
(ok:background! win ok:transparent)
(ok:draw-rectangle win
MARGIN (+ y MARGIN)
(- w MARGIN MARGIN)
HEIGHT))
Les arguments sont la fenêtre sur laquelle la jauge doit être dessinée, la largeur de la fenêtre, la position y de la jauge, la largeur de la valeur de la jauge et sa couleur. La seule remarque concerne l'utilisation de la couleur transparent qui permet de dessiner le rectangle sans fond.
Exécution
Il ne reste plus qu'à invoquer la fonction main à la fin du fichier :
(main)
Pour exécuter le programme, nous tapons sur la ligne de commande du shell la commande suivante :
$ ./osm --exec cpuinf.osm
Il est aussi possible de placer en haut du fichier la ligne suivante :
#! ./osm --exec
De cette manière, et en rendant le fichier exécutable, il est possible d'invoquer le programme directement.
Améliorations
Le programme actuel permet d'afficher les jauges pour l'utilisation du processeur et de la batterie. Nous pourrions ajouter d'autres jauges en consultant d'autres fichiers de /proc. Dans ce cas, il est nécessaire d'écrire le nom des jauges afin de les différencier.
Le programme utilise des constantes pour initialiser certains paramètres importants. Il serait possible de créer un fichier d'initialisation et d'utiliser les fonctions du module OP pour faciliter la configuration.
Il serait aussi possible d'utiliser la fonction osm:parse-options qui permet de définir facilement des options de la ligne de commande des applications.
Les auteurs
Guilhem de Wailly, directeur de la société Erian Concept : support, formations, configurations, administration, développements Linux. Environnement OpenScheme.
http://www.erian-concept.com
Pr Fernand Boéri, Professeur à l'Université de Nice - Sophia-Antipolis, membre de l'unité SPORTS du laboratoire I3S, spécialiste en modélisation, évaluation de performances et architectures parallèles.
http://www.i3s.unice.fr
Références
Programmation orientée objet
 OMT: 1-Modélisation et
conception orientées objet
James Bumbaugh et
al.
Masson / Prentice Hall
Scheme
 Structure et Interprétation
des programmes informatiques
H. Abelson, GJ. Sussman
InterEdition
 The Scheme Programming
Languages - Ansi Scheme
R. Kent Dybvig
Prentice Hall
 Les langages Lisps -
Christian Queinnec
InterEdition
 Programmer avec Scheme
- J. Chazarin
Thomson Publishing
 Revised4 Report on the
Algorithmic Language Scheme
W. Clinger, J.
Rees
ftp://ftp.nj.nec.com/pub/kelsey
Environnements Scheme
 Scm - A.
Jaffer
http://www-swiss.ai.mit.edu/~jaffer
La
référence des interprètes Scheme. Très
petit, rapide, pour beaucoup de plates-formes, extensible.
 PCScheme - Texas
Instrument
ftp://cui.unige.ch/public/pcs/pcscheme.exe
Un
très bon environnement de programmation Scheme pour DOS, avec
éditeur intégré.
 DrScheme -
Rice University
http://www.cs.rice.edu/CS/PLT/
Environnement
Scheme libre très avancé.
 ChezScheme -
Cadence, Inc
http://www.scheme.com/
Environnement
Scheme très performant.
 Inlab Scheme - Inlab
Software GmbH
http://www.munich.net/inlab/scheme/
Environnement
commercial
 EdScheme, 3Dscheme -
Scheme, Inc
http://www.schemers.com/
Environnement
de programmation Scheme pour Windows.
 OpenScheme -
Erian Concept
http://www.open-scheme.com
Environnement
professionnel de programmation Scheme comprenant un interprète,
un compilateur et un débogueur symbolique.
Existe en
version libre et commerciale, pour Linux, FreeBSD, Solaris, Windows
et BeOS, sur systèmes Intel.