Modifier facilement la fréquence processeur

Embarqué, Linux, Microprocesseur, Temps-réel | Publié par cpb
avr 30 2012

Linux offre une possibilité intéressante : celle de configurer assez finement la vitesse du processeur depuis la ligne de commande. Il permet d’agir indépendamment (pour autant que l’architecture matérielle le permette) sur les différents coeurs des processeurs. On m’a demandé récemment une petite illustration pratique de ces possibilités : en voici un résumé.

Configurer la vitesse CPU avec /sys

La première opération nécessaire est de connaître la liste des fréquences supportées par un CPU. Cette liste est accessible grâce au pseudo système de fichier /sys.

# ls /sys/devices/system/cpu/
cpu0  cpu1  cpu2  cpu3  cpufreq  cpuidle  kernel_max  offline  online  possible  present  probe  release  sched_mc_power_savings
# cat /sys/devices/system/cpu/online 
0-3
# cat /sys/devices/system/cpu/possible 
0-7
# cat /sys/devices/system/cpu/present 
0-3
#

Ici, le noyau peut gérer sept CPU (paramètre possible), mais il n’y en a que quatre connectés (present). Ils sont tous actifs (online). Choisissons, arbitrairement, le CPU numéro 1 et vérifions ses fréquences de fonctionnement.

# ls /sys/devices/system/cpu/cpu1/
cache  cpufreq  crash_notes  online  thermal_throttle  topology
# ls /sys/devices/system/cpu/cpu1/cpufreq/
affected_cpus               related_cpus                   scaling_max_freq
bios_limit                  scaling_available_frequencies  scaling_min_freq
cpuinfo_cur_freq            scaling_available_governors    scaling_setspeed
cpuinfo_max_freq            scaling_cur_freq               stats
cpuinfo_min_freq            scaling_driver
cpuinfo_transition_latency  scaling_governor
# cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_available_frequencies 
2400000 2133000 1867000 1600000
# cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq 
2400000
#

Le CPU accepte quatre fréquences, il est actuellement configuré avec la plus rapide : 2,4GHz. On peut la modifier ainsi.

# echo userspace > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor 
# echo 1867000 > /sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed 
# cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq 
1867000
#

Mesurer les effets de la vitesse CPU

Nous expliquerons la première ligne de l’exemple ci-dessus dans le prochain paragraphe.
Pour voir les effets de la configuration précédente, on peut utiliser un petit programme qui incrémente un compteur pendant une durée donnée (cinq secondes ici).

compte-iterations.c :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>

int main(void)
{
	struct timeval tv;
	struct timeval tv_debut;
	long long int compteur;

	// Attendre le debut d'une nouvelle seconde
	gettimeofday(& tv_debut, NULL);
	do {
		gettimeofday(& tv, NULL);
	} while (tv.tv_sec == tv_debut.tv_sec);

	// Compter pendant cinq secondes
	compteur = 0;
	tv_debut = tv;
	do {
		compteur ++;
		gettimeofday(& tv, NULL);
	} while (tv.tv_sec < (tv_debut.tv_sec + 5));

	printf("Resultats : %lld\n", compteur);
	return EXIT_SUCCESS;
}

Essayons de l’exécuter avec différentes fréquences.

# echo 1600000 > /sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed 
# taskset -pc 1 $$
pid 9778's current affinity list: 0-3
pid 9778's new affinity list: 1
# ./compte-iterations 
Resultats : 17263876
# ./compte-iterations 
Resultats : 16733090
# ./compte-iterations 
Resultats : 16810727
# echo 1867000 > /sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed 
# ./compte-iterations 
Resultats : 19926359
# ./compte-iterations 
Resultats : 19868890
# ./compte-iterations 
Resultats : 19681040
# echo 2133000 > /sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed 
# ./compte-iterations 
Resultats : 22517877
# ./compte-iterations 
Resultats : 23028619
# ./compte-iterations 
Resultats : 22310298
# echo 2400000 > /sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed 
# ./compte-iterations 
Resultats : 25317042
# ./compte-iterations 
Resultats : 25806554
# ./compte-iterations 
Resultats : 25916774
#

Nous voyons bien que le nombre d’itérations fluctue en fonction de la fréquence configurée.

Configurer le comportement du CPU

Plutôt qu’agir directement sur la fréquence, ce qui nécessite de lire la valeur et d’inscrire celle choisie, le noyau nous propose des comportements, des heuristiques, qu’il nomme governors, qui vont assurer la modification de la fréquence CPU afin de l’ajuster aux besoins de l’utilisateur.
On trouvera des explications plus détaillées sur les governors dans cet article. Il existe (suivant la configuration du noyau à la compilation) jusqu’à cinq governors, dont les noms sont visibles ainsi.

# cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_available_governors 
conservative ondemand userspace powersave performance
#

Leurs comportements :

  • powersave : économiser la batterie (d’un ordinateur portable) en utilisant la fréquence la plus faible possible.
  • performance : optimiser la vitesse de traitement en adoptant la fréquence disponible la plus élevée.
  • ondemand : faire varier la fréquence en fonction de la charge système afin d’optimiser la vitesse de traitement lorsqu’il y a une forte demande, tout en économisant la batterie lorsqu’il y a peu de tâches en cours.
  • conservative : adopter le même comportement que ondemand, en évitant les modifications trop fréquentes de la vitesse du CPU.
  • userspace : laisser l’utilisateur fixer lui-même la vitesse qui lui convient, comme nous l’avons fait dans les paragraphes précédents.

Essayons les effets des principaux governors sur notre programme.

# echo performance > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor 
# cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq 
2400000
# ./compte-iterations 
Resultats : 25932762
# ./compte-iterations 
Resultats : 25937413
# ./compte-iterations 
Resultats : 25335626
# echo powersave > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor 
# cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq
1600000
# ./compte-iterations 
Resultats : 17625101
# ./compte-iterations 
Resultats : 16788736
# ./compte-iterations 
Resultats : 17017337
# echo ondemand > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor 
# cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq
1600000
# ./compte-iterations 
Resultats : 25371803
# ./compte-iterations 
Resultats : 25294453
# ./compte-iterations 
Resultats : 25920801
#

Conclusion

Il est intéressant de pouvoir configurer facilement la vitesse du processeur indépendamment des fréquences exactes, en employant par exemple une heuristique powersave sur un portable, performance sur un serveur, ou ondemand sur un poste de travail généraliste.

Pour les systèmes embarqués, les choix ne sont pas toujours évidents, comme on peut le voir dans ces articles : Temps réel et économie d’énergie 1 et 2.

[ACTU] Simulateur de second tour des présidentielles

Intérêts divers, Linux | Publié par cpb
avr 23 2012

Vous trouverez sur cette page un petit simulateur en javascript qui permet de calculer les résultats du second tour en fonction de votre estimation personnelle des participations et reports de voix des candidats du premier tour.

Traitements parallèles dans un script shell

Linux, Shell | Publié par cpb
avr 21 2012

Il est rare de devoir utiliser des traitements en tâche de fond dans un script shell. À moins, bien entendu, qu’il s’agisse d’un script de démarrage servant justement à lancer plusieurs traitements en parallèle.

Il peut néanmoins être parfois nécessaire de gérer des lancements en arrière-plan, comme cela m’est arrivé une fois.

Situation

Un système aéroportuaire de traitement de plots radar m’envoyait des informations en continu sur un port réseau UDP/IP. Je devais les enregistrer dans des fichiers horodatés. Chaque fichier contenait une heure d’enregistrement environ. Je devais également, à l’issue de chaque enregistrement, effectuer une analyse des données qui durait environ cinq minutes.

Logiciels existants

Deux logiciels, écrits en C, étaient disponibles.

Le premier, appelons-le enregistreur prenait plusieurs arguments sur sa ligne de commande

  • L’adresse IPv4 du groupe multicast dans lequel s’inscrire. Ceci n’a pas d’intérêt pour ce qui nous concerne ici, prenons par exemple 224.10.10.10.
  • Le numéro de port UDP pour recevoir les données. La valeur ne nous concerne pas plus que la précédente. Fixons-la arbitrairement à 2012.
  • La durée en secondes de l’enregistrement à réaliser. Pour une durée d’une heure, nous passerons 3600.
  • Le nom du fichier où stocker l’enregistrement. Pour que les fichiers soient aisément manipulables par la suite, il est nécessaire que leurs noms contiennent un horodatage compréhensible.

Le second logiciel, que nous appellerons statistiques était un outil étudiant les données reçues (qu’il lisait depuis un fichier), et sortant des éléments d’information sur sa sortie standard. Ce programme prenait uniquement en argument le nom du fichier d’enregistrement à traiter.

Ces deux logiciels fonctionnaient très bien, et je devais les enchaîner dans un script shell afin qu’ils tournent 24H/24H.

Problème

Tout d’abord il fallait générer le nom du fichier en incluant un horodatage lisible. Pour cela le plus simple est souvent de s’appuyer sur la commande date dont les options permettent facilement de construire une chaîne de caractères en insérant des éléments de date et d’heure.

NOM_FICHIER=$(date +"enregistrement-LFPG-%Y-%m-%d-%H-%M.dat")

La variable NOM_FICHIER contiendra une chaîne de caractères comme enregistrement-LFPG-2012-04-21-09-00.dat.

Le second problème était plus gênant. Si l’on pouvait tolérer la perte d’une seconde de messages entre deux enregistrements, il n’était pas envisageable d’avoir un « trou » de cinq minutes (durée du programme statistiques). Je ne pouvais donc pas utiliser le shéma évident suivant.

#! /bin/sh
ADRESSE_IP=224.10.10.10
PORT_UDP=2012
while true
do
    # Generer le nom du fichier d'enregistrement
    FICHIER=$(date +"enregistrement-LFPG-%Y-%m-%d-%H-%M.dat")

    # Declencher l'enregistrement
    enregistreur ${ADRESSE_IP} ${PORT_UDP} 3600 "${FICHIER}"

    # Traiter l'heure ecoulee
    statistiques "${FICHIER}" > fichier-resultat.txt
done

Il fallait donc paralléliser le traitement statistique et l’enregistrement des données.

Première idée

On peut tout d’abord imaginer un schéma où le traitement statistique fonctionne en arrière-plan, la boucle principale étant cadencée par l’enregistreur. En voici un exemple.

#! /bin/sh
[...]
while true
do
    # Generer le nom du fichier d'enregistrement
    FICHIER=$(date +"enregistrement-LFPG-%Y-%m-%d-%H-%M.dat")

    # Declencher l'enregistrement
    enregistreur ${ADRESSE_IP} ${PORT_UDP} 3600 "${FICHIER}"

    # Traiter l'heure ecoulee
    statistiques "${FICHIER}" > fichier-resultat.txt &
done

On remarquera, à la fin de la ligne de la commande statistiques, le & qui provoque le passage à l’arrière-plan. Ceci permet au shell de reprendre immédiatement son exécution en début de boucle et donc de démarrer un nouvel enregistrement.

Cette méthode fonctionnait, mais elle présentait néanmoins un petit inconvénient. A l’issue du traitement statistique, le fichier de résultats devait être renommé en utilisant un numéro d’ordre séquentiel et copié dans un répertoire indépendant ; ceci seulement dans le cas où le fichier n’était pas vide. Il devenait compliqué de réaliser ces opérations dans une exécution en arrière-plan.

L’idée fut donc d’inverser le principe précédent, en effectuant l’enregistrement en arrière-plan et le traitement statistique dans la boucle principale.

Seconde idée

Voici un premier aperçu de la nouvelle solution.

#! /bin/sh
[...]
NUMERO_RESULTAT=1

while true
do
    # Generer le nom du fichier d'enregistrement
    FICHIER=$(date +"enregistrement-LFPG-%Y-%m-%d-%H-%M.dat")

    # Declencher l'enregistrement
    enregistreur ${ADRESSE_IP} ${PORT_UDP} 3600 "${FICHIER}" &

    # Traiter l'heure ecoulee
    statistiques "${FICHIER}" > fichier-resultat.txt

    # si le fichier n'est pas vide
    if [ -s fichier-resultat.txt ]

        # Le renommer et le déplacer
        mv fichier-resultat.txt "resultat-${NUMERO_RESULTAT}.txt"
        mv "resultat-${NUMERO_RESULTAT}.txt"  ~/resultats-statistiques/

        # Incrémenter le numéro d'ordre
        NUMERO_RESULTAT=$(( NUMERO_RESULTAT + 1 ))
    fi
done

Si cette idée semble séduisante au premier abord, elle ne fonctionne pas du tout en réalité. Lorsqu’on lance l’enregistreur en arrière-plan, le traitement statistique s’exécute en quelques minutes et relance un nouvel enregistreur alors que le précédent n’est pas terminé, et ainsi de suite.

Pour que cette méthode soit utilisable, il faudrait s’assurer avant de démarrer un enregistrement que le précédent soit fini. Pour cela, nous allons noter après le lancement en arrière-plan de l’enregistreur son numéro de processus (PID), et avant le lancement nous attendrons que le processus enregistreur précédent soit terminé.

Le shell nous fournit dans la variable $! le PID du dernier processus lancé en arrière-plan. Ajoutons donc la ligne suivante dans notre code.

[...]
    enregistreur ${ADRESSE_IP} ${PORT_UDP} 3600 "${FICHIER}" &
    PID_ENREGISTREUR=$!
    # Traiter l'heure ecoulee
    [...]

Pour attendre la fin d’un processus lancé par le shell, celui-ci nous propose la commande wait que l’on peut faire suivre du numéro de PID. Ajoutons cette attente avant le lancement.

[...]
    wait ${PID_ENREGISTREUR}
    enregistreur ${ADRESSE_IP} ${PORT_UDP} 3600 "${FICHIER}" &
    [...]

Nous devons bien sûr prendre en considération le démarrage de notre script, où aucun enregistreur ne tourne encore. Pour cela, il suffit d’initialiser la variable PID_ENREGISTREUR à un numéro impossible de processus (les PID sont toujours supérieurs à zéro) et de la tester avant d’appeler wait.

Troisième essai

Notre code devient :

#! /bin/sh
ADRESSE_IP=224.10.10.10
PORT_UDP=2012
REPERTOIRE_STATISTIQUES="~/resultats-statistiques/"
PID_ENREGISTREUR=0
while true
do
    # Generer le nom du fichier d'enregistrement
    FICHIER=$(date +"enregistrement-LFPG-%Y-%m-%d-%H-%M.dat")

    # Attendre la fin de l'enregistreur precedent
    if [ $PID_ENREGISTREUR -gt 0 ]
    then
        wait $PID_ENREGISTREUR
    fi
    # Declencher l'enregistrement
    enregistreur ${ADRESSE_IP} ${PORT_UDP} 3600 "${FICHIER}" &
    PID_ENREGISTREUR=$!

    # Traiter l'heure ecoulee
    statistiques "${FICHIER}" > fichier-resultat.txt

    # si le fichier n'est pas vide
    if [ -s fichier-resultat.txt ]
        # Le renommer et le deplacer
        mv "fichier-resultat.txt" "resultat-${NUMERO_RESULTAT}.txt"
        mv "resultat-${NUMERO_RESULTAT}.txt" "${REPERTOIRE_STATISTIQUES}"

        # Incrementer le numero d'ordre
        NUMERO_RESULTAT=$(( NUMERO_RESULTAT + 1 ))
    fi
done

Pourtant, en observant le script, on peut s’apercevoir d’un gros défaut : le traitement statistique démarre sur le même fichier que l’enregistreur en cours ! Il faut bien sûr qu’il travaille sur l’enregistrement précédent. Modifions encore notre script.

Solution

#! /bin/sh
ADRESSE_IP=224.10.10.10
PORT_UDP=2012
REPERTOIRE_STATISTIQUES="~/resultats-statistiques/"
PID_ENREGISTREUR=0
FICHIER_COURANT=""
FICHIER_PRECEDENT=""

while true
do
    # Attendre la fin de l'enregistreur precedent
    if [ ${PID_ENREGISTREUR} -gt 0 ]
    then
        wait ${PID_ENREGISTREUR}
        FICHIER_PRECEDENT="${FICHIER_COURANT}"
    fi

    # Generer le nom du nouvel enregistrement
    FICHIER_COURANT=$(date +"enregistrement-LFPG-%Y-%m-%d-%H-%M.dat")

    # Lancer l'enregistreur en arriere-plan
    enregistreur ${ADRESSE_IP} ${PORT_UDP} 3600 "${FICHIER_COURANT}" &
    PID_ENREGISTREUR=$!

    # Traiter l'enregistrement de l'heure ecoulee
    statistiques "${FICHIER_PRECEDENT}" > fichier-resultat.txt

    # si le resultat n'est pas vide
    if [ -s fichier-resultat.txt ]
        # Le renommer et le deplacer
        mv "fichier-resultat.txt" "resultat-${NUMERO_RESULTAT}.txt"
        mv "resultat-${NUMERO_RESULTAT}.txt" "${REPERTOIRE_STATISTIQUES}"

        # Incrementer le numero d'ordre
        NUMERO_RESULTAT=$(( NUMERO_RESULTAT + 1 ))
    fi
done

Cette fois le script est correct et fonctionne.

Conclusion

Nous voyons que l’encadrement par un script shell de programmes existants n’est pas toujours évident surtout lorsqu’il existe une dépendance temporelle entre eux (synchronisation). Ici, certains points du script ont été ignorés (gestion des erreurs d’exécution comme la saturation du disque par exemple), mais il nous a quand même fallu quatre versions pour obtenir enfin un programme correct. On retiendra égtalement que le soin apporté à la lisibilité et à la clarté du script est un gage de facilité de maintenance ultérieure, surtout lorsque l’algorithme global sort quelque peu de l’ordinaire (parallélisme par exemple).

[NOSTALGIE] Le ZX-81

Intérêts divers | Publié par cpb
avr 05 2012

Voilà, c’est sûr, mon vieux ZX-81 ne fonctionne plus…

ZX-81

ZX-81, imprimante et extension 16ko

J’ai voulu en avoir le cœur net, et j’ai tenté de le remettre en marche pour fêter le trentième anniversaire de son acquisition. En vain, il n’y a aucun signe de fonctionnement – bien que l’alimentation soit toujours correcte. En outre le câble plat qui reliait le clavier à la carte à microprocesseur à mal supporté l’usure du temps et s’est cassé net en plusieurs endroits ce qui me paraît difficilement réparable.

Tant pis, il ne se rallumera pas, mais cela ne m’empêchera aucunement de le conserver sur une étagère avec un certain nombre d’autres rescapés de la même époque. J’éprouve une affection particulière pour ce petit ordinateur sur lequel j’ai découvert la programmation en basic et en assembleur.

Pour ceux qui n’ont pas connu le ZX-81 (TS-1000 dans sa version américaine), il faut savoir que c’était le premier ordinateur vraiment grand public, et que les choix économiques rigoureux faits par son concepteur (Sir Clive Sinclair) en rendait l’utilisation assez… particulière. Tout d’abord le gros défaut de cet ordinateur était le manque de fiabilité des connexions sur le bus d’extension (où l’on branchait entre autre le bloc d’extension mémoire) ce qui provoquait des coupures inopinées d’alimentation en cas de mouvement de l’unité centrale, avec toutes les pertes de données que l’on peut imaginer.

Le système reposait sur un processeur huit bits, le Zilog Z-80-A, cadencé  à 3.5 MHz, et sur une mémoire RAM de 1 kilo-octet extensible à 16ko, voire 64ko pour les plus fortunés. Et aussi étonnant que cela puisse paraître, nous disposions de nombreux programmes (jeux, utilitaires, programmation, etc.) qui tenaient dans ces dimensions réduites de mémoire. La sauvegarde de la mémoire se faisait sur des cassettes audios par l’intermédiaire d’un magnétophone externe, le chargement d’un programme de quelques kilo-octets pouvant durer plusieurs longues minutes avec une fiabilité plutôt aléatoire.

Dès la mise sous tension, l’utilisateur disposait d’un prompt permettant de saisir des lignes de codes dans une version simplifiée du langage BASIC. Deux instructions, PEEK et POKE, permettaient de lire ou d’écrire des octets directement dans la mémoire et la fonction USR autorisait l’exécution d’un code à une adresse quelconque, généralement après y avoir inséré du code assembleur personnel.

Capture 3D Monster Maze

3D Monster Maze

Les capacités vidéo étaient très limitées : 32 x 24 caractères monochromes. 16 caractères spéciaux étaitent constitués d’une matrice de quatre petits carrés, qui pouvaient se combiner pour offrir des graphiques avec la résolution de 64×48 pixels ! L’ingéniosité des programmeurs permettait de disposer quand même de jeux graphiques, comme le fameux « 3D Monster Maze » dans lequel le joueur se trouvait plongé dans un labyrinthe chassé par un tyrannosaure. J’ai pu en prendre la copie d’écran ci-contre sur un émulateur en-ligne. Mes jeux favoris étaient également « Space Invaders » et « Flight Simulation » (copie d’écran ci-dessous) ainsi que tous les programmes que l’on trouvait sous forme de listing dans les revues de l’époque.

Flight Simulation

Flight Simulation

J’ai appris sur cet ordinateur la programmation en BASIC, en écrivant notamment quelques outils de calculs pour l’astronomie (à usage personnel), et la programmation assembleur pour des jeux – inspirés de Pac-man ou Centipède – qui n’ont à ma connaissance jamais été diffusés en dehors d’un cercle très restreint d’amis possesseurs de la même machine.

 Il faut souligner la pédagogie du manuel (en français) du ZX-81 qui permettait de découvrir progressivement les principes de la programmation, et la bonne qualité des livres – disponibles en français également – pour approfondir l’étude de l’assembleur par exemple.

Même s’il ne redémarre pas, ce petit ordinateur continuera à trôner sur une étagère de mon bureau, attirant les regards surpris, amusés et parfois nostalgiques des visiteurs qui l’aperçoivent.

[ACTU] Mais pourquoi la Freebox reste-t-elle à l’heure d’hiver ?

Actualité, Embarqué, Linux | Publié par cpb
mar 27 2012

Comme beaucoup d’entre vous le savent déjà, la Freebox v.6 a raté son passage à l’heure d’été. Ce matin, alors que mon PC, ma montre et mon téléphone affichent 09:44, la Freebox posée à côté de mon bureau affiche encore 08:44. Au-delà du fait divers amusant, source de plaisanteries et de sarcasmes sur Twitter, je trouve cette mésaventure intéressante, car elle trouve son origine dans des logiciels que connaissent bien les amateurs de Linux embarqué !Freebox a l'heure d'hiver

La bibliothèque µClibc regroupe les fonctionnalités communes dont les applications de haut-niveau ont besoin (par exemple des traitements de chaîne de caractères, des fonctions de calcul, des méthodes d’accès aux fichiers, etc.) en fournissant les points d’entrée pour le noyau Linux (les appels-système). La particularité de la µClibc par rapport aux bibliothèques « C » plus classiques comme la Gnu Glibc est d’être écrite en essayant de réduite au maximum la taille du code exécutable, et de pouvoir ainsi être employée dans les systèmes embarqués avec de fortes contraintes de place mémoire.

La plupart des systèmes embarqués construits avec des outils comme Buildroot (comme ceux que nous avons mis en oeuvre dans plusieurs articles) s’appuient sur la µClibc, et la Freebox v.6 ne fait apparemment pas exception, même si la bibliothèque n’est pas explicitement mentionnée dans la liste de logiciels libres décrites ici.

Dans la dernière version stable de la µClibc (0.9.33 du 1er février), un bug a été corrigé, comme cela est mentionné dans sa page de ChangeLog. Voici la portion qui nous intéresse :

commit 47f3da1cf49377c25772bb54d07db55225bbb142
Author: Guillaume Bourcier
Date:   Tue Oct 11 13:45:33 2011 +0200

    libc: fix daylight saving time handling

    The algorithm computing daylight saving time incorrectly adds a day for
    each month after January for leap years. The clock shift from/to DST can
    be delayed if the last Sunday of a transition month is exactly seven
    days before the first of the following month.

    This change adds a day for the February month only.

    Signed-off-by: Guillaume Bourcier
    Signed-off-by: Richard Braun
    Signed-off-by: Carmelo Amoroso

Pour les années bissextiles (comme 2012), l’algorithme de calcul de la date de passage à l’heure d’été ajoutait par erreur un jour au mois de février.

Ainsi le dernier dimanche du mois de mars (ce qui définit officiellement la date du changement d’heure) était considéré comme le dimanche 31 mars (alors que le 31 mars tombe en réalité un samedi). Visiblement le firmware de la Freebox ne contient pas encore cette correction, aussi pense-t-elle que le changement horaire doit avoir lieu dimanche prochain.

Si cette explication est la bonne, nos Freebox devraient basculer en heure d’été dimanche 1er avril à 02:00. Peut être Free va-t-il plaider l’hypothèse d’un poisson d’avril sophistiqué et anticipé ? À moins qu’une mise à jour du firmware intervienne d’ici là.

Une touche d’humour supplémentaire : dans le message ChangeLog ci-dessus j’ai supprimé la fin des adresses mails des personnes mentionnées pour leur éviter le spam. Il faut quand même savoir que l’adresse de G.Bourcier qui a détecté et corrigé le bug est « Free.fr » !

[AJOUT le 30/03/2012]: Free annonce avoir modifié le firmware du Freebox Server (version 1.1.5) pour corriger l’erreur. Il faut le redémarrer pour que la mise à jour ait lieu. Je ne l’ai pas fait sur ma Freebox pour vérifier dimanche si le changement horaire est bien décalé d’une semaine.

[AJOUT le 01/04/2012]: Comme on pouvait s’y attendre, le changement horaire a eu lieu cette nuit et l’afficheur de la Freebox indique bien l’heure correcte. Il est temps de faire la mise à jour du firmware, car sa nouvelle version intègre plusieurs corrections.