476 lines
11 KiB
Markdown
Executable File
476 lines
11 KiB
Markdown
Executable File
|
||
# 04 – Spécification du script client de benchmark (bench.sh)
|
||
|
||
Objectif : définir précisément le comportement du script Bash exécuté sur les machines clientes pour :
|
||
- collecter les informations matérielles et système,
|
||
- exécuter les benchmarks,
|
||
- calculer les scores,
|
||
- envoyer un JSON complet au backend via HTTP.
|
||
|
||
Ce fichier sert de référence pour écrire `scripts/bench.sh` dans le dépôt.
|
||
|
||
---
|
||
|
||
## 1. Usage et interface en ligne de commande
|
||
|
||
Le script doit être exécutable en one-liner depuis une machine cliente, par exemple :
|
||
|
||
```bash
|
||
curl -s https://gitea.maison43.duckdns.org/gilles/linux-benchtools/raw/branch/main/scripts/bench.sh \
|
||
| bash -s -- \
|
||
--server https://bench.maison43/api/benchmark \
|
||
--token "XXXXXXX" \
|
||
--device "elitedesk-800g3" \
|
||
--iperf-server 10.0.0.10 \
|
||
--short
|
||
```
|
||
|
||
### 1.1. Arguments supportés
|
||
|
||
- `--server <URL>` (obligatoire)
|
||
URL de l’endpoint backend `POST /api/benchmark`.
|
||
|
||
- `--token <TOKEN>` (obligatoire)
|
||
Token d’authentification à envoyer dans `Authorization: Bearer <TOKEN>`.
|
||
|
||
- `--device <NAME>` (optionnel)
|
||
Identifiant logique de la machine (`device_identifier`).
|
||
Si non fourni, utiliser `hostname` de la machine.
|
||
|
||
- `--iperf-server <HOST>` (optionnel)
|
||
Hôte/IP du serveur iperf3 utilisé pour les tests réseau.
|
||
|
||
- `--skip-cpu`, `--skip-memory`, `--skip-disk`, `--skip-network`, `--skip-gpu` (optionnels)
|
||
Permettent de désactiver certains tests.
|
||
|
||
- `--short` (optionnel)
|
||
Version “rapide” des tests (durées/tailles réduites).
|
||
|
||
- `--help`
|
||
Affiche un message d’aide et quitte.
|
||
|
||
### 1.2. Variables internes
|
||
|
||
- `BENCH_SCRIPT_VERSION` (string, ex: `"1.0.0"`)
|
||
Doit être mise à jour à chaque changement incompatible du script.
|
||
|
||
---
|
||
|
||
## 2. Pré-requis et compatibilité
|
||
|
||
### 2.1. OS visés (MVP)
|
||
|
||
- Debian / Ubuntu / Proxmox (base Debian).
|
||
|
||
Le script doit :
|
||
- Lire `/etc/os-release` pour détecter l’OS.
|
||
- Utiliser `apt-get` pour installer les paquets manquants.
|
||
|
||
### 2.2. Outils nécessaires
|
||
|
||
Le script doit vérifier et installer si besoin :
|
||
|
||
- `curl`
|
||
- `jq` (construction JSON)
|
||
- `sysbench` (CPU + mémoire)
|
||
- `fio` (disque)
|
||
- `iperf3` (réseau, si `--iperf-server` fourni)
|
||
- `dmidecode` (RAM, carte mère, BIOS)
|
||
- `lsblk`
|
||
- `lscpu`
|
||
- `smartmontools` (optionnel pour SMART disques)
|
||
- `lm-sensors` (optionnel pour températures)
|
||
- `glmark2` (optionnel pour GPU si dispo)
|
||
|
||
---
|
||
|
||
## 3. Structure générale du script
|
||
|
||
1. Parser les arguments.
|
||
2. Vérifier `--server` et `--token` (sinon erreur + exit 1).
|
||
3. Déterminer :
|
||
- `DEVICE_IDENTIFIER` = `--device` ou `hostname`.
|
||
- `BENCH_SCRIPT_VERSION`.
|
||
4. Détecter l’OS et préparer la commande d’installation de paquets.
|
||
5. Vérifier/installer les outils nécessaires.
|
||
6. Collecter les informations hardware et OS.
|
||
7. Exécuter les benchmarks (en respectant les flags `--skip-*`).
|
||
8. Calculer les scores (CPU, mémoire, disque, réseau, GPU, global).
|
||
9. Construire le JSON.
|
||
10. Envoyer le JSON au backend.
|
||
11. Afficher un récap et le statut HTTP.
|
||
|
||
---
|
||
|
||
## 4. Collecte des informations matérielles et système
|
||
|
||
Toutes les infos doivent ensuite être assemblées dans le bloc `hardware` du JSON.
|
||
|
||
### 4.1. CPU
|
||
|
||
Commandes possibles :
|
||
|
||
- `lscpu`
|
||
- `/proc/cpuinfo`
|
||
|
||
Informations à extraire :
|
||
|
||
- `vendor` : ligne `Vendor ID` (ou `GenuineIntel`, `AuthenticAMD`, etc.).
|
||
- `model` : `Model name`.
|
||
- `microarchitecture` : optionnel (peut être déterminé via une table interne si souhaité, sinon laisser vide).
|
||
- `cores` : `Core(s) per socket` × `Socket(s)` ou `CPU(s)` minus hyperthreading.
|
||
- `threads` : `CPU(s)` (nombre logique).
|
||
- `base_freq_ghz` : depuis `lscpu` (MHz -> GHz).
|
||
- `max_freq_ghz` : `CPU max MHz` si disponible.
|
||
- `cache_l1_kb`, `cache_l2_kb`, `cache_l3_kb` : `L1d cache`, `L2 cache`, `L3 cache`.
|
||
- `flags` : liste depuis `Flags` / `Features`.
|
||
- `tdp_w` : non triviale à extraire dans un script, peut rester null.
|
||
|
||
### 4.2. RAM
|
||
|
||
Commandes :
|
||
|
||
- `free -m`
|
||
- `dmidecode --type memory` (requiert sudo)
|
||
|
||
Infos :
|
||
|
||
- `total_mb` : depuis `free -m`.
|
||
- `slots_total` : nombre d’entrées `Locator` dans `dmidecode` (type DIMM).
|
||
- `slots_used` : slots où `Size` n’est pas `No Module Installed`.
|
||
- `ecc` : champ `Total Width` vs `Data Width` ou `Error Correction Type`.
|
||
- `layout` : tableau d’objets avec :
|
||
- `slot` (Locator)
|
||
- `size_mb`
|
||
- `type` (DDR3/DDR4/DDR5/etc.)
|
||
- `speed_mhz`
|
||
- `vendor`
|
||
- `part_number`
|
||
|
||
### 4.3. GPU
|
||
|
||
Commandes :
|
||
|
||
- `lspci | grep -i vga`
|
||
- éventuellement `nvidia-smi` si NVIDIA.
|
||
|
||
Infos :
|
||
|
||
- `vendor` : Intel, NVIDIA, AMD…
|
||
- `model` : texte brut de `lspci`.
|
||
- `driver_version` : si récupérable (`nvidia-smi --query-gpu=driver_version`).
|
||
- `memory_dedicated_mb` : via `nvidia-smi`/outils spécifiques si possible, sinon null.
|
||
- `memory_shared_mb` : éventuellement via `lspci`/`/proc`, sinon null.
|
||
- `api_support` : optionnel (OpenGL/Vulkan), peut être laissé vide.
|
||
|
||
### 4.4. Stockage (disques et partitions)
|
||
|
||
Commandes :
|
||
|
||
- `lsblk -o NAME,SIZE,TYPE,MODEL,TRAN,MOUNTPOINT,FSTYPE`
|
||
- `smartctl -H /dev/sdX` (si présent)
|
||
- éventuellement `nvme list` / `nvme smart-log`.
|
||
|
||
Infos :
|
||
|
||
- `devices` : tableau d’objets :
|
||
- `name` (ex: `/dev/nvme0n1`)
|
||
- `type` (HDD/SSD/NVMe, déduit de `TYPE`/`TRAN`/nom).
|
||
- `interface` (SATA, PCIe 3.0 x4, USB, etc. si déductible).
|
||
- `capacity_gb` : depuis `SIZE`.
|
||
- `vendor` / `model` : `MODEL`.
|
||
- `smart_health` : `PASSED` / `FAILED` / null.
|
||
- `temperature_c` : si dispo via SMART.
|
||
|
||
- `partitions` : tableau d’objets :
|
||
- `name`
|
||
- `mount_point`
|
||
- `fs_type`
|
||
- `used_gb`
|
||
- `total_gb`
|
||
|
||
### 4.5. Réseau
|
||
|
||
Commandes :
|
||
|
||
- `ip addr`
|
||
- `ip -o link`
|
||
- `ethtool <iface>` (pour vitesse si dispo).
|
||
- pour Wi-Fi : `iw dev` / `iwconfig`.
|
||
|
||
Infos :
|
||
|
||
- `interfaces` : tableau d’objets :
|
||
- `name` (ex: `eth0`, `enp3s0`, `wlan0`)
|
||
- `type` (`ethernet`, `wifi`, `other`)
|
||
- `mac`
|
||
- `ip` (IPv4 principale si existante)
|
||
- `speed_mbps` : via `ethtool`.
|
||
- `driver` : éventuellement depuis `/sys/class/net/<iface>/device/driver`.
|
||
|
||
### 4.6. Carte mère / BIOS
|
||
|
||
Commandes :
|
||
|
||
- `dmidecode --type baseboard`
|
||
- `dmidecode --type bios`
|
||
|
||
Infos :
|
||
|
||
- `motherboard.vendor`
|
||
- `motherboard.model`
|
||
- `bios_version`
|
||
- `bios_date`
|
||
|
||
### 4.7. OS
|
||
|
||
Commandes :
|
||
|
||
- `/etc/os-release`
|
||
- `uname -r`
|
||
- `uname -m`
|
||
- `systemd-detect-virt` (si dispo).
|
||
|
||
Infos :
|
||
|
||
- `name` : ID ou PRETTY_NAME.
|
||
- `version` : VERSION ou VERSION_CODENAME.
|
||
- `kernel_version` : `uname -r`.
|
||
- `architecture` : `uname -m`.
|
||
- `virtualization_type` : sortie de `systemd-detect-virt` (kvm, qemu, none, etc.).
|
||
|
||
### 4.8. Capteurs (facultatif)
|
||
|
||
- `sensors` (lm-sensors)
|
||
- `smartctl -A` pour température disques.
|
||
|
||
Infos :
|
||
|
||
- `sensors.cpu_temp_c` (ou valeur moyenne).
|
||
- `sensors.disk_temps_c` : map `{ "/dev/nvme0n1": 42 }`.
|
||
|
||
---
|
||
|
||
## 5. Benchmarks à exécuter
|
||
|
||
Les résultats iront dans le bloc `results` du JSON.
|
||
|
||
### 5.1. CPU – sysbench
|
||
|
||
Commande par défaut (mode complet) :
|
||
|
||
```bash
|
||
sysbench cpu --cpu-max-prime=20000 --threads="$(nproc)" run
|
||
```
|
||
|
||
Mode `--short` :
|
||
```bash
|
||
sysbench cpu --cpu-max-prime=10000 --threads="$(nproc)" run
|
||
```
|
||
|
||
Valeurs à extraire :
|
||
|
||
- `events_per_sec` : ligne `events per second: X`.
|
||
- `duration_s` : temps total (`total time:`).
|
||
|
||
Score CPU :
|
||
|
||
- Score simple :
|
||
- définir une valeur de référence (par ex. 5000 events/s = 50 points).
|
||
- `cpu_score = min(100, events_per_sec / ref * 50)` (ajuster plus tard).
|
||
- Pour l’instant, le script peut :
|
||
- soit calculer cette note,
|
||
- soit juste envoyer les valeurs brutes et laisser le backend calculer.
|
||
|
||
### 5.2. Mémoire – sysbench
|
||
|
||
Commande (complet) :
|
||
|
||
```bash
|
||
sysbench memory --memory-total-size=2G --memory-oper=write run
|
||
```
|
||
|
||
Mode `--short` :
|
||
```bash
|
||
sysbench memory --memory-total-size=512M --memory-oper=write run
|
||
```
|
||
|
||
Valeurs :
|
||
|
||
- `throughput_mib_s` : ligne `transferred (XXXX MiB/sec)`.
|
||
|
||
Score mémoire :
|
||
|
||
- Basé sur `throughput_mib_s` et une référence.
|
||
|
||
### 5.3. Disque – fio
|
||
|
||
Profil simple (séquentiel read/write 1GiB) :
|
||
|
||
```bash
|
||
fio --name=bench_seq_rw \
|
||
--rw=readwrite \
|
||
--bs=1M \
|
||
--size=1G \
|
||
--numjobs=1 \
|
||
--iodepth=16 \
|
||
--filename=/tmp/fio_benchfile \
|
||
--direct=1 \
|
||
--group_reporting
|
||
```
|
||
|
||
Mode `--short` :
|
||
- Taille 256M.
|
||
|
||
Valeurs à extraire (via parsing ou `--output-format=json`) :
|
||
|
||
- `read_mb_s`
|
||
- `write_mb_s`
|
||
- éventuellement `iops_read`, `iops_write`, `latency_ms`.
|
||
|
||
Score disque :
|
||
|
||
- Moyenne pondérée de read/write vs valeurs de référence.
|
||
|
||
Après test, supprimer `/tmp/fio_benchfile`.
|
||
|
||
### 5.4. Réseau – iperf3
|
||
|
||
Uniquement si `--iperf-server` fourni.
|
||
|
||
Download (client -> server, test reverse) :
|
||
|
||
```bash
|
||
iperf3 -c "$IPERF_SERVER" -R -J
|
||
```
|
||
|
||
Upload :
|
||
|
||
```bash
|
||
iperf3 -c "$IPERF_SERVER" -J
|
||
```
|
||
|
||
Utiliser le JSON (`-J`) + `jq` pour extraire :
|
||
|
||
- `upload_mbps`
|
||
- `download_mbps`
|
||
- `jitter_ms`
|
||
- `packet_loss_percent` (si UDP, option future).
|
||
|
||
Ping (latence) :
|
||
|
||
```bash
|
||
ping -c 5 "$IPERF_SERVER"
|
||
```
|
||
|
||
Extraire :
|
||
|
||
- `ping_ms` = moyenne.
|
||
|
||
Score réseau :
|
||
|
||
- Combinaison débit (min(up, down)) et latence (ping).
|
||
|
||
### 5.5. GPU – glmark2 (optionnel)
|
||
|
||
Si `glmark2` disponible :
|
||
|
||
```bash
|
||
glmark2
|
||
```
|
||
|
||
Extraire :
|
||
|
||
- Score global `glmark2_score`.
|
||
|
||
Score GPU :
|
||
|
||
- Normalisation simple vs référence.
|
||
|
||
---
|
||
|
||
## 6. Construction du JSON
|
||
|
||
Le script utilise `jq` pour construire le JSON final :
|
||
|
||
Structure :
|
||
|
||
```json
|
||
{
|
||
"device_identifier": "...",
|
||
"bench_script_version": "1.0.0",
|
||
"hardware": { ... },
|
||
"results": { ... }
|
||
}
|
||
```
|
||
|
||
Principes :
|
||
|
||
- Utiliser `jq -n` et passer les valeurs via `--arg` / `--argjson`.
|
||
- Attention aux nombres vs strings (utiliser `--argjson` pour les nombres).
|
||
- Gérer proprement les valeurs nulles (par exemple si test GPU non réalisé).
|
||
|
||
Exemple (simplifié) en shell :
|
||
|
||
```bash
|
||
payload=$(jq -n --arg device_identifier "$DEVICE_IDENTIFIER" --arg bench_script_version "$BENCH_SCRIPT_VERSION" --argjson cpu "$CPU_JSON" --argjson ram "$RAM_JSON" --argjson results "$RESULTS_JSON" '{
|
||
device_identifier: $device_identifier,
|
||
bench_script_version: $bench_script_version,
|
||
hardware: {
|
||
cpu: $cpu,
|
||
ram: $ram
|
||
},
|
||
results: $results
|
||
}')
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Envoi au backend
|
||
|
||
Commandes :
|
||
|
||
```bash
|
||
HTTP_RESPONSE=$(curl -s -o /tmp/bench_response.txt -w "%{http_code}" \
|
||
-X POST "$SERVER_URL" \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-d "$payload")
|
||
```
|
||
|
||
- Si `HTTP_RESPONSE` != `200` :
|
||
- Afficher un message d’erreur (console).
|
||
- Optionnel : afficher `/tmp/bench_response.txt`.
|
||
|
||
- Si succès :
|
||
- Afficher un message confirmant l’ID du benchmark si présent dans la réponse.
|
||
|
||
---
|
||
|
||
## 8. Gestion des erreurs à prévoir
|
||
|
||
- Absence de `--server` ou `--token` -> erreur et exit.
|
||
- Outils manquants et impossible à installer -> avertir, sauter le test concerné, transmettre `score = null`.
|
||
- Erreurs iperf3 (serveur indisponible) -> ignorer la partie réseau, `network` null.
|
||
- Temps de test trop long -> proposer un mode `--short`.
|
||
|
||
---
|
||
|
||
## 9. Journalisation locale (optionnelle)
|
||
|
||
- Possibilité de logger les infos dans `/var/log/linux_benchtools_client.log` ou `/tmp/linux_benchtools_client.log`.
|
||
- Log recommandé :
|
||
- Date/heure.
|
||
- SERVER, DEVICE_IDENTIFIER.
|
||
- Résumé des scores.
|
||
- Code HTTP de la réponse.
|
||
|
||
---
|
||
|
||
## 10. Bonnes pratiques
|
||
|
||
- Ne jamais supprimer ou modifier des fichiers système.
|
||
- Nettoyer les fichiers temporaires (fio, résultats intermédiaires).
|
||
- Garder le script idempotent : on peut le relancer sans casser la machine.
|
||
- Prévoir un délai total raisonnable pour un run complet (ex. < 5–10 minutes en mode complet, < 2–3 minutes en mode `--short`).
|