From 78ba7b9f5485d6d208199b78776750267abbd066 Mon Sep 17 00:00:00 2001 From: manus-admin Date: Mon, 1 Jun 2026 01:39:27 +0200 Subject: [PATCH] fix: CPU via cgroup v2 usage_usec (mesure precise conteneur LXC) + RAM formule free --- src/backend/src/docker.js | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/backend/src/docker.js b/src/backend/src/docker.js index 2a761c6..f01a55d 100644 --- a/src/backend/src/docker.js +++ b/src/backend/src/docker.js @@ -186,17 +186,38 @@ function getServerMetrics() { // Lecture directe de /proc (monté depuis l'hôte via le namespace PID du conteneur) // Pas besoin de nsenter : /proc dans le conteneur reflète l'hôte - // CPU : delta /proc/stat sur 300ms + // CPU : mesure via cgroup v2 usage_usec (méthode précise pour conteneur LXC) + // Fallback sur /proc/stat normalisé par nproc si cgroup v2 non disponible let cpuUsage = 0; try { - const parseCpuLine = (line) => line.trim().split(/\s+/).slice(1).map(Number); - const s1 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu '))); - execSync("sleep 0.3"); - const s2 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu '))); - const idle1 = s1[3], total1 = s1.reduce((a,b)=>a+b,0); - const idle2 = s2[3], total2 = s2.reduce((a,b)=>a+b,0); - const dIdle = idle2 - idle1, dTotal = total2 - total1; - cpuUsage = dTotal > 0 ? Math.round((1 - dIdle / dTotal) * 100) : 0; + const ncpu = parseInt(execSync('nproc').toString().trim()) || 1; + const cgroupPath = '/sys/fs/cgroup/cpu.stat'; + const readUsageUsec = () => { + const stat = fs.readFileSync(cgroupPath, 'utf8'); + const m = stat.match(/^usage_usec\s+(\d+)/m); + return m ? parseInt(m[1]) : null; + }; + const u1 = readUsageUsec(); + if (u1 !== null) { + // Méthode cgroup v2 : mesure la consommation CPU réelle du conteneur + execSync('sleep 0.5'); + const u2 = readUsageUsec(); + // delta en microsecondes / (500ms * ncpu) = % CPU du conteneur + const deltaUs = u2 - u1; + cpuUsage = Math.min(100, Math.round(deltaUs / (500000 * ncpu) * 100)); + } else { + // Fallback : /proc/stat normalisé par nproc + const parseCpuLine = (line) => line.trim().split(/\s+/).slice(1).map(Number); + const s1 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu '))); + execSync('sleep 0.3'); + const s2 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu '))); + const idle1 = s1[3], total1 = s1.reduce((a,b)=>a+b,0); + const idle2 = s2[3], total2 = s2.reduce((a,b)=>a+b,0); + const dIdle = idle2 - idle1, dTotal = total2 - total1; + const rawCpu = dTotal > 0 ? (1 - dIdle / dTotal) * 100 : 0; + // Normaliser par nproc pour éviter l'effet nœud physique sur LXC + cpuUsage = Math.round(rawCpu / ncpu); + } } catch(e) {} // RAM : lecture de /proc/meminfo (valeurs réelles via lxcfs)