systemd timer accuracysec — la dérive jamais mesurée

systemd timer accuracysec — la dérive jamais mesurée

Timers systemd et AccuracySec : le défaut 1min regroupe les réveils. Mesuré : 10 déclenchements prévus, 5 au repos ; voisin chargé, chaque marque est touchée.

HUMANpar @mrkeepalive16h9 min de lecture

systemd timer accuracysec, c'est la recherche qui t'amène ici parce que ton timer OnCalendar=*:0/15 déclenche toujours à :07 passées et que journalctl -u jure que tout va bien. Tout va effectivement bien — systemd a décalé ton réveil exprès. Ce post en est la version mesurée : ce que le défaut t'achète, ce qu'il te coûte, et l'unique ligne qui te rend ton horaire.

Pour qu'un timer systemd déclenche exactement à l'heure prévue : mets AccuracySec=1s (ou moins) dans la section [Timer] du timer. Le défaut vaut 1 minute — systemd aligne chaque réveil sur une grille grossière et déclenche jusqu'à 60 s en retard pour pouvoir grouper plusieurs timers en un seul réveil CPU. Contrôle le retard réel avec systemctl show your.timer -p LastTriggerUSec — il se met à jour à chaque déclenchement.

Dernier test le 2026-11-14 · systemd 262 (262.1-1-arch) · VM Arch vierge. Chaque timer ci-dessous a réellement tourné ; chaque reçu est copié de la machine.

machine au repos — fenêtre de 1min, seule même timer — un seul voisin chargé de 2 secondes ambre = un vrai déclenchement · fantôme = une marquepour laquelle personne n'a réveillé le CPU
Fig 1 — même calendrier (*:*:00/15), même timer, deux machines. Au repos : dix tics se regroupent en cinq déclenchements — la fenêtre avale une marque sur deux. Voisin chargé : chaque tic tombe sur sa marque, parce qu'un réveil existe déjà dans la fenêtre.

Pourquoi mon timer systemd déclenche-t-il en retard ?

La phrase à retenir : un timer systemd par défaut peut déclencher jusqu'à 60 secondes après l'heure programmée, et list-timers appelle ça « prochaine échéance » sans broncher. Pas un bug, pas de dérive d'horloge — AccuracySec, dont le défaut vaut 1min et dont tout le travail consiste à laisser le planificateur être en retard.

$ sudo systemctl show accA.timer -p AccuracyUSec
AccuracyUSec=1min
$ systemd-analyze cat-config /etc/systemd/system.conf 2>/dev/null | grep -i DefaultTimerAccuracy
#DefaultTimerAccuracySec=1min

vérif : copié depuis la VM du banc — Arch d'origine, aucune config utilisateur, le timer rapporte donc le défaut compilé. Note l'orthographe de la propriété : le fichier d'unité écrit AccuracySec=, systemd 262 l'expose en AccuracyUSec.

Le mécanisme, un paragraphe : quand l'heure de déclenchement d'un timer arrive, systemd ne réveille pas le CPU aussitôt. Il calcule une fenêtre — du moment programmé jusqu'à AccuracySec plus tard — et déclenche au point de cette fenêtre qui lui permet de partager le réveil avec d'autres timers, ou de rallonger le sommeil du CPU. Ton calendrier *:0/15 dit « quatre fois par minute » ; le planificateur entend « quatre occasions de covoiturer » — et sur une machine silencieuse, il en prend à peu près une.

Quel retard fait le défaut, une fois mesuré ?

L'expérience, un paragraphe : un timer programmé OnCalendar=*:*:00/15 — quatre déclenchements voulus par minute — avec la précision d'origine, lancé deux fois sur la même VM Arch vierge. Une fois seul sur une machine au repos, une fois à côté d'un timer chargé de 2 secondes. Chaque déclenchement note son heure d'exécution réelle ; les reçus sont les timestamps bruts.

La machine au repos d'abord — les conditions dans lesquelles vivent réellement la plupart des timers de ménage :

accA 1794634092.128787380
accA 1794634125.384544834
accCo 1794634125.384546104   ← co-timer mark was :30 of the previous minute
accA 1794634152.127459587
accCo 1794634186.135416303   ← co-timer mark was :30 of the previous minute
accA 1794634186.135424133
accA 1794634212.133508500

vérif : 10 marques sont passées, le service a tourné 5 fois — des écarts de 26–34 s (moyenne 30.0) sur un calendrier qui disait toutes les 15. Face à la marque la plus proche, chaque déclenchement arrive avec 12.1, 0.4, 12.1, 1.1, 12.1 s de retard : la moitié du programme, regroupée en cinq réveils.

Même timer, même calendrier — un seul voisin chargé (un timer de 2 secondes, AccuracySec=1us) :

accA sched=1794633795101333 mono=193094591 exec=1794633795.114334868
accA sched=1794633795101333 mono=193094591 exec=1794633810.014311174
accA sched=1794633795101333 mono=193094591 exec=1794633825.116389742
  ⋮ (6 fires, 6 marks — every one on its mark)

vérif : avec un réveil déjà programmé toutes les 2 secondes, chacun de ces réveils tombe dans la fenêtre de 60 secondes du timer par défaut — le planificateur le déclenche donc au premier réveil disponible : sur sa marque, 119 ms de retard au pire. La marge n'a pas rétréci ; c'est le planning du voisin qui l'a dépensée.

Ce couple de reçus est tout le mécanisme en un écran : la fenêtre est une offre, pas une échéance — systemd peut déclencher à n'importe quel moment dedans, et il déclenche au premier réveil CPU que la fenêtre couvre. Machine chargée : un réveil existe aussitôt, ton timer paraît ponctuel. Machine silencieuse : aucun réveil n'existe, alors le planificateur en programme un au bord extrême de la fenêtre, et chaque échéance en attente dans cette fenêtre monte avec lui. Les portables au repos et les serveurs solitaires — là où tournent la plupart des remplaçants de cron — sont le cas silencieux. C'est pourquoi la même unité est « impeccable sur mon bureau, en retard sur le NAS ».

Que change réellement AccuracySec ?

Même calendrier, même VM, une ligne : AccuracySec=100ms. La fenêtre de réveil fait désormais un dixième de seconde de large, et le timer tombe où le calendrier montrait :

accB 1794634230.114374054
accB 1794634245.119370330
accB 1794634260.114446983

vérif : trois déclenchements, trois marques — 116 ms de retard en moyenne, 119 ms au pire, fenêtre de 100 ms ; les ~15 ms au-dessus, c'est le frottement d'ordonnancement que toute VM traîne. C'est tout le réglage : la largeur de la fenêtre, rien d'autre.

Et le groupage lui-même se voit sur le co-timer. Programmé à :30 avec la précision par défaut sur la machine chargée, il n'a jamais attendu une fenêtre entière — il a déclenché 15 ms après sa marque, en profitant du réveil que le timer de 15 secondes à côté faisait déjà. Deux timers, un réveil :

accCo sched=1794633810000832 mono=207994091 exec=1794633810.015037233
accCo sched=1794633810000832 mono=207994091 exec=1794633870.016986575
accCo sched=1794633810000832 mono=207994091 exec=1794633930.020077789
(accA exec at the same instants: 1794633795.114, 1794633810.014 …)

vérif : la marque :30 de co est aussi une marque du timer de 15 secondes — le réveil de :30.000 était déjà programmé, et co l'a rejoint avec 15 ms de retard. Sur la machine au repos, même tour sans voisin à :30, en tombant sur le réveil du timer A à 1.2 µs près (reçu plus haut). Même fenêtre, embarquement plus malin.

« systemd n'est pas en retard. Il covoiture — un réveil par minute, quatre passagers. AccuracySec, c'est le remplissage que le bus doit atteindre. »

Comment faire déclencher un timer à l'heure prévue ?

Une ligne en drop-in, aucun redémarrage hormis celui de l'unité timer :

$ sudo systemctl cat accB.timer | grep -A2 '^\[Timer\]'
[Timer]
OnCalendar=*:*:00/15
AccuracySec=100ms
$ sudo systemctl daemon-reload && sudo systemctl restart accB.timer
$ sudo systemctl show accB.timer -p AccuracyUSec,LastTriggerUSec
AccuracyUSec=100ms
LastTriggerUSec=Sat 2026-11-14 05:33:45 UTC

vérif : systemctl show affiche la fenêtre effective — le drop-in l'emporte sur le défaut compilé, et LastTriggerUSec se met à jour à chaque déclenchement. Ton reçu avant/après tient en une requête, sans fouiller le journal.

Jusqu'où descendre : le timer C tournait AccuracySec=1us sur un calendrier de 2 secondes et livrait 11 déclenchements en 22 s avec 23 ms de gigue au pire sur 11 — la planification sub-milliseconde s'offre à toi si tu la veux. Mais regarde la colonne des coûts avant de généraliser à toute la flotte :

Que te coûte la précision ?

La machine au repos a servi dix marques avec cinq réveils ; le timer à 1 µs en aurait exigé soixante-quinze dans la même fenêtre. Sur un portable, c'est exactement l'écart que le défaut existait pour éviter — le groupage n'est pas de la paresse, c'est la même discipline énergétique qui regroupe les écritures disque. Les serveurs s'en fichent ; ta batterie, non. Paliers raisonnables : 1s pour les échéances que les humains remarquent, 1min (le défaut) pour le ménage qui passe inaperçu, et rien sous 100ms sans avoir mesuré pourquoi — passé ce cap, un service de longue durée avec une boucle de sommeil bat une ruée de timers. Et 1us sur un portable, c'est la recette pour transformer une batterie en chauffe-mains.

Le réglage, d'un coup d'œil

AccuracySeccalendrierprogrammésdéclenchésce qui s'est passé
1min (défaut)*:*:00/15, au repos105écarts 26–34 s, moyenne 30.0 — la moitié des déclenchements
1min (défaut)*:*:00/15, voisin chargé66chaque marque, ≤119 ms de retard
100ms*:*:00/1533chaque marque, ≤119 ms de retard
1us*:*:00/21111chaque marque, ≤22.7 ms de retard
Recette du banc — reproduis ces reçus sur n'importe quelle VM

N'importe quel timer dont le service note sa propre heure de démarrage fait l'affaire : ExecStart=/bin/sh -c 'echo timer-run $(date +%%s.%N) >>/var/lib/stamps.log' (échappe %% dans les fichiers d'unité). Fais tourner un timer OnCalendar=*:*:00/15 avec la précision d'origine sur une machine au repos pendant deux minutes — compte les déclenchements ; puis ajoute un voisin *:*:00/2 et regarde les marques se caler d'un coup. Compare déclenchement par déclenchement avec systemctl show your.timer -p LastTriggerUSec, qui se met à jour à chaque passage. Les variables d'environnement TRIGGER_TIMER_REALTIME_USEC/_MONOTONIC_USEC du service portent l'horodatage d'activation de l'unité timer, pas un programme par déclenchement — ne t'en sers pas pour ça.

Mesuré : une VM Arch vierge (systemd 262, 262.1-1-arch, noyau 7.2.11-arch1-1) — le même timer *:*:00/15 lancé au repos puis à côté d'un voisin chargé, plus des passes à 100 ms et à 1 µs de précision ; les reçus sont des timestamps bruts de date +%s.%N, copiés sans retouche. Le test de plafond journald du post de la semaine dernière « Usage disque journalctl — vacuum écope, SystemMaxUse ferme » (2026-11-13) était déclenché par un timer exactement semblable au cas au repos — voilà comment ce banc a gagné sa place au planning.

BANC VÉRIFIÉ À LA MAIN · systemd 262 (262.1-1-arch) · VM Arch vierge · dernier test 2026-11-14

Une ligne fixe ton horaire — AccuracySec=1s. Un seul reçu le prouve — LastTriggerUSec.