Logo

Linux: Monitoring matériel et validation du refroidissement

Cet article explique comment accéder aux paramètres des capteurs matériels (sondes, ventilateurs) et les contrôler sur un serveur physique sous Linux Ubuntu, et effectuer un test de charge pour vérifier que le refroidissement est correct sur un serveur nouvellement installé.

Note

On ne considère ici que le matériel grand public (PC assemblé). En cas d'utilisation de matériel de récupération (Dell iDRAC, HP iLO, Supermicro, etc.) voir également ipmitool.

Commandes standard

Installer de quoi surveiller le matériel:

# apt install lm-sensors nvme-cli linux-firmware amd64-microcode hwinfo jq

Vérifier:

# sensors-detect

=> valider toutes les réponses par défaut et ignorer le "no sensors were detected" (beaucoup de cartes mères récentes exposent les capteurs directement via le noyau et sensors-detect ne trouve rien, ce qui est normal).

Commandes utiles:

# hwinfo
# sensors
# nvme list
# nvme smart-log /dev/nvmeX

Exemple de sortie de la commande sensors:

$ sensors
amdgpu-pci-1c00
Adapter: PCI adapter
vddgfx:        1.10 V  
vddnb:       914.00 mV 
edge:         +44.0°C  
PPT:           8.00 mW 

nvme-pci-0400
Adapter: PCI adapter
Composite:    +49.9°C  (low  = -273.1°C, high = +80.8°C)
                       (crit = +84.8°C)
Sensor 1:     +62.9°C  (low  = -273.1°C, high = +65261.8°C)
Sensor 2:     +49.9°C  (low  = -273.1°C, high = +65261.8°C)

r8169_0_f00:00-mdio-0
Adapter: MDIO adapter
temp1:        +60.0°C  (high = +120.0°C)

k10temp-pci-00c3
Adapter: PCI adapter
Tctl:         +48.4°C  
Tccd1:        +31.9°C  
Tccd2:        +33.1°C  

nvme-pci-0700
Adapter: PCI adapter
Composite:    +49.9°C  (low  = -273.1°C, high = +80.8°C)
                       (crit = +84.8°C)
Sensor 1:     +61.9°C  (low  = -273.1°C, high = +65261.8°C)
Sensor 2:     +49.9°C  (low  = -273.1°C, high = +65261.8°C)
Notes

1. La température Composite est généralement celle utilisée pour le throttling et constitue donc l'indicateur le plus pertinent.

2. Si le GPU est passé en passthrough à une VM, la commande sensors ne récupèrera pas la température, il faut passer la commande dans la VM.

Faire un stress-test

Le script suivant permet de vérifier le comportement du CPU sous forte charge en surveillant la température, afin de valider le compromis silence/refroidissement réglé dans le BIOS:

#!/bin/bash
trap 'killall yes 2>/dev/null' EXIT
CORES=$(nproc)
for i in $(seq 1 $CORES); do
  yes > /dev/null &
done
sleep 20
killall yes
#end#

Ce script charge tous les cores pendant 20 secondes.

Afficher les températures en parallèle avec la commande sensors:

La température doit monter immédiatement puis se stabiliser (autour de max. ~85 à 90 degrés dans mon cas pour un AMD 9950X ; dépend de la spécification du Tjmax du CPU) puis redescendre en quelques secondes après la fin du test.

Note

C'est un test minimal pour faire monter le CPU en température sans installer de paquet supplémentaire. Il ne sollicite pratiquement que les unités entières. Pour un test plus représentatif, utiliser stress-ng (voir plus bas).

Commandes supplémentaires

Voici des exemples de commandes complémenatires pour contrôler les ventilateurs depuis l'OS (sur carte mère compatible) et de faire des stress-tests plus poussés:

# apt install lm-sensors fancontrol stress-ng
# pwmconfig
# systemctl enable --now fancontrol
# systemctl status fancontrol
# stress-ng --cpu 0 --timeout 30s
# stress-ng --cpu 4 --vm 2 --io 2 --timeout 60s
# stress-ng --matrix 0 --timeout 30s --metrics-brief # test de charge hardware
Note

fancontrol est un outil destiné à des cas particuliers ; tous les BIOS modernes savent très bien gérer les ventilateurs.

Journalisation

Pour enregistrer périodiquement les températures dans les logs, voici un exemple simple de script à intégrer:

Note:

J'ai mis en place ce logging suite à un crash "sec" d'un serveur, sans aucune info exploitable dans les logs, nada. Pour écarter un éventuel problème de surchauffe j'ai décidé de mettre ça en place, ce qui en cas de récidive permettra de confirmer ou infirmier l'hypothèse. Ce serveur fonctionne maintenant depuis longtemps sans avoir crashé.

vi /usr/local/bin/hwmon-sampler.sh
#!/usr/bin/env bash
set -euo pipefail

LOGFILE="/var/log/hwmon-samples.log"
LOCKFILE="/tmp/hwmon-sampler.lock"

exec 9>"$LOCKFILE"
if ! flock -n 9; then
  exit 0
fi

sample_once() {
  local ts cpu gpu nic load1 load5 load15 mem_used mem_total mem_free mem_avail uptime_s
  ts="$(date -Is)"

  # Load averages
  read -r load1 load5 load15 _ < /proc/loadavg

  # Memory (kB)
  read -r _ mem_total _ < <(grep -m1 '^MemTotal:' /proc/meminfo)
  read -r _ mem_free  _ < <(grep -m1 '^MemFree:'  /proc/meminfo)
  read -r _ mem_avail _ < <(grep -m1 '^MemAvailable:' /proc/meminfo)
  mem_total="${mem_total% kB}"
  mem_free="${mem_free% kB}"
  mem_avail="${mem_avail% kB}"
  mem_used=$(( mem_total - mem_avail ))

  # Uptime (seconds)
  read -r uptime_s _ < /proc/uptime

  # Sensors JSON
  local js
  if ! js="$(sensors -j 2>/dev/null)"; then
    echo "$ts level=error msg=\"sensors failed\"" >> "$LOGFILE"
    return
  fi

  # CPU temp (k10temp: prefer Tctl then Tdie)
  cpu="$(jq -r '
    to_entries
    | map(select(.key|startswith("k10temp")))
    | (.[0].value.Tctl.temp1_input // .[0].value.Tdie.temp1_input // empty)
  ' <<<"$js")"
  [[ -z "${cpu:-}" ]] && cpu=""

  # GPU temp (amdgpu edge)
  gpu="$(jq -r '
    to_entries
    | map(select(.key|startswith("amdgpu")))
    | if length>0 then (.[0].value.edge.temp1_input // empty) else empty end
  ' <<<"$js")"
  [[ -z "${gpu:-}" ]] && gpu=""

  # NIC temp (e.g. r8169)
  nic="$(jq -r '
    to_entries
    | map(select(.key|test("(^|-)r8169")))
    | if length>0 then (.[0].value.temp1.temp1_input // empty) else empty end
  ' <<<"$js")"
  [[ -z "${nic:-}" ]] && nic=""

  # NVMe Composite temps sorted by device id → nvme1..nvme4
  IFS=$'\n' read -r -d '' -a nvmes < <(jq -r '
    to_entries
    | map(select(.key|startswith("nvme-pci-")))
    | sort_by(.key)
    | map(.value.Composite.temp1_input // empty)
    | .[]
  ' <<<"$js" && printf '\0')
  nvme1="${nvmes[0]:-}"; nvme2="${nvmes[1]:-}"; nvme3="${nvmes[2]:-}"; nvme4="${nvmes[3]:-}"

  # Optional GPU power if exposed as PPT (amdgpu)
  local gpupwr
  gpupwr="$(jq -r '
    to_entries
    | map(select(.key|startswith("amdgpu")))
    | if length>0 then (
        (.[0].value.PPT.power1_average // .[0].value.PPT.power1_input // empty)
      ) else empty end
  ' <<<"$js")"
  [[ -z "${gpupwr:-}" ]] && gpupwr=""

  # One compact line (space-separated key=val)
  echo "$ts cpu_c=${cpu}C gpu_c=${gpu}C nvme1_c=${nvme1}C nvme2_c=${nvme2}C nvme3_c=${nvme3}C nvme4_c=${nvme4}C nic_c=${nic}C gpupwr_w=${gpupwr} load1=${load1} load5=${load5} load15=${load15} mem_used_kb=${mem_used} mem_total_kb=${mem_total} uptime_s=${uptime_s}" >> "$LOGFILE"
}

# 4 samples at 15s interval
for _ in 1 2 3 4; do
  sample_once
  sleep 15
done

Pour mettre en place la collecte dans les logs: exemple

# chmod +x /usr/local/bin/hwmon-sampler.sh
# crontab -e
* * * * * /usr/local/bin/hwmon-sampler.sh

GPU

Pour un GPU Nvidia:

# nvidia-smi
# nvidia-smi --query-gpu=temperature.gpu,fan.speed --format=csv

Résumé - vérification rapide

Pour aller directement à l'essentiel et récupérer rapidement toutes les informations utiles sur l'état du système:

# apt install lm-sensors stress-ng nvme-cli
# sensors
# watch -n1 sensors
# stress-ng --cpu 0 --timeout 60s
# nvidia-smi

--
TG - 06/2026

Cet article a été généré par un humain