Parcourir la source

discover max TDP via upp, remove timeout, lower fallback to 120W

- add getMaxTdp() querying SmallPowerLimit1 from PowerPlay table
- track maxTdp per GPU in gpuStates
- remove cmdTimeoutMs config and all timeout options from execSync
- change fallback max TDP from 250W to 120W
- update README with TDP discovery docs
Глухов Кирилл Викторович il y a 1 mois
Parent
commit
3a949fed14
2 fichiers modifiés avec 27 ajouts et 12 suppressions
  1. 6 7
      README.md
  2. 21 5
      amd-gpu-temp-control.js

+ 6 - 7
README.md

@@ -17,11 +17,12 @@ AMD Radeon discrete GPUs with PowerPlay table support:
 
 ## How it works
 
-1. Reads temperature from all `temp*_input` sensors under `/sys/class/drm/card{N}/device/hwmon/`
-2. Compares against configured min/max temperature thresholds
-3. When temperature exceeds the range, linearly scales TDP down via `upp` PowerPlay table modifications
-4. When temperature drops below the range, restores TDP to maximum
-5. Changes are applied in configured step increments to avoid abrupt power shifts
+1. Discovers actual max TDP via `upp get SmallPowerLimit1` at startup (fallback: 120W)
+2. Reads temperature from all `temp*_input` sensors under `/sys/class/drm/card{N}/device/hwmon/`
+3. Compares against configured min/max temperature thresholds
+4. When temperature exceeds the range, linearly scales TDP down via `upp` PowerPlay table modifications
+5. When temperature drops below the range, restores TDP to maximum
+6. Changes are applied in configured step increments to avoid abrupt power shifts
 
 ## Requirements
 
@@ -57,7 +58,6 @@ Default config path: `/etc/amd-gpu-temp-control.json`
   "maxTdpPercent": 100,
   "tdpStepPercent": 10,
   "checkIntervalMs": 2000,
-  "cmdTimeoutMs": 5000,
   "uppPath": "upp"
 }
 ```
@@ -70,7 +70,6 @@ Default config path: `/etc/amd-gpu-temp-control.json`
 | `maxTdpPercent`    | 100     | Maximum TDP percentage (full power)                      |
 | `tdpStepPercent`   | 10      | Maximum TDP change per cycle (%)                         |
 | `checkIntervalMs`  | 2000    | Temperature read interval (ms)                           |
-| `cmdTimeoutMs`     | 5000    | Timeout for `upp` command (ms)                           |
 | `uppPath`          | `upp`   | Path to the `upp` binary                                 |
 
 ## Usage

+ 21 - 5
amd-gpu-temp-control.js

@@ -11,7 +11,6 @@ const DEFAULT_MIN_TDP_PERCENT = 10;
 const DEFAULT_MAX_TDP_PERCENT = 100;
 const DEFAULT_TDP_STEP_PERCENT = 10;
 const DEFAULT_CHECK_INTERVAL_MS = 2000;
-const DEFAULT_CMD_TIMEOUT_MS = 5000;
 const DEFAULT_UPP_PATH = 'upp';
 
 function loadConfig(configPath) {
@@ -30,7 +29,6 @@ function mergeConfig(config) {
     maxTdpPercent: config.maxTdpPercent ?? DEFAULT_MAX_TDP_PERCENT,
     tdpStepPercent: config.tdpStepPercent ?? DEFAULT_TDP_STEP_PERCENT,
     checkIntervalMs: config.checkIntervalMs ?? DEFAULT_CHECK_INTERVAL_MS,
-    cmdTimeoutMs: config.cmdTimeoutMs ?? DEFAULT_CMD_TIMEOUT_MS,
     uppPath: config.uppPath ?? DEFAULT_UPP_PATH,
   };
 }
@@ -143,7 +141,20 @@ function setTdpForCard(cardNumber, power, config) {
     `BoostPowerLimit=${power} ` +
     `smcPPTable/SocketPowerLimitAc0=${power} ` +
     `smcPPTable/SocketPowerLimitDc=${power}`;
-  execSync(cmd, { encoding: 'utf-8', stdio: 'pipe', timeout: config.cmdTimeoutMs });
+  execSync(cmd, { encoding: 'utf-8', stdio: 'pipe' });
+}
+
+function getMaxTdp(cardNumber, config) {
+  try {
+    const cardPath = getCardPath(cardNumber);
+    const out = execSync(
+      `${config.uppPath} -p ${cardPath} get SmallPowerLimit1`,
+      { encoding: 'utf-8', stdio: 'pipe' }
+    ).trim();
+    const match = out.match(/(\d+(?:\.\d+)?)/);
+    if (match) return parseFloat(match[1]);
+  } catch { /* ignore */ }
+  return 120;
 }
 
 function parseArgs(argv) {
@@ -208,9 +219,14 @@ async function main() {
   const gpuStates = cardIndices.map(cardNumber => ({
     cardNumber,
     deviceName: getDeviceName(cardNumber),
+    maxTdp: getMaxTdp(cardNumber, config),
     currentTdpPercent: null,
   }));
 
+  for (const state of gpuStates) {
+    log(`GPU ${state.cardNumber} [${state.deviceName}]: max TDP ${state.maxTdp}W`);
+  }
+
   if (gpuStates.length === 0) {
     log('No GPUs found');
     process.exit(1);
@@ -259,12 +275,12 @@ async function main() {
 
           if (shouldApply) {
             const clampedPercent = Math.max(config.minTdpPercent, Math.min(config.maxTdpPercent, gpuState.currentTdpPercent));
-            const power = wattsFromPercent(clampedPercent, 250);
+            const power = wattsFromPercent(clampedPercent, gpuState.maxTdp);
             setTdpForCard(gpuState.cardNumber, power, config);
             log(`GPU ${gpuState.cardNumber} [${gpuState.deviceName}]: ${temp.toFixed(1)}°C | TDP: ${clampedPercent}% (${power}W)`);
           }
         } else if (gpuState.currentTdpPercent !== null && iteration % 10 === 0) {
-          const currentWatts = wattsFromPercent(gpuState.currentTdpPercent, 250);
+          const currentWatts = wattsFromPercent(gpuState.currentTdpPercent, gpuState.maxTdp);
           log(`GPU ${gpuState.cardNumber} [${gpuState.deviceName}]: ${temp.toFixed(1)}°C | TDP: ${gpuState.currentTdpPercent}% (${currentWatts}W) (stable)`);
         }
       } catch (err) {