227 lines
10 KiB
PowerShell
Executable File
227 lines
10 KiB
PowerShell
Executable File
# Monitor whether DPTF/INT3404 sends fan control: ETW trace + high-frequency _FST poll.
|
|
# Run as Administrator. Needs ectest (ec-test-app) for _FST polling.
|
|
# -Mode watch: poll _FST, print only when FAND *changes* (INT3404 sends _FSL => FAND changes).
|
|
|
|
param(
|
|
[ValidateSet("check", "poll", "watch", "etw", "all")]
|
|
[string]$Mode = "check",
|
|
[string]$EctestPath = "C:\Users\Jack\ec-test-app\exe\x64\Release\ectest.exe",
|
|
[int]$PollSeconds = 60,
|
|
[double]$PollIntervalMs = 200,
|
|
[string]$LogDir = $PSScriptRoot
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
# ---- 1) Check DPTF presence ----
|
|
function Get-DptfPresence {
|
|
Write-Host "=== DPTF / thermal stack check ===" -ForegroundColor Cyan
|
|
$svc = Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Name -match "dptf|esif|intel.*thermal|dynamic.*thermal" }
|
|
if ($svc) {
|
|
$svc | Format-Table Name, Status, DisplayName -AutoSize
|
|
} else {
|
|
Write-Host "No DPTF/ESIF/thermal service found by name." -ForegroundColor Yellow
|
|
}
|
|
$drv = Get-WmiObject Win32_PnPSignedDriver -ErrorAction SilentlyContinue | Where-Object { $_.DeviceName -match "DPTF|Dynamic Platform|Intel.*Thermal|ESIF" }
|
|
if ($drv) {
|
|
$drv | Select-Object DeviceName, DriverVersion | Format-Table -AutoSize
|
|
} else {
|
|
Write-Host "No DPTF/thermal driver found by name." -ForegroundColor Yellow
|
|
}
|
|
$acpiByClass = Get-PnpDevice -Class ACPI -ErrorAction SilentlyContinue | Where-Object { $_.FriendlyName -match "INT3404|INT3400|DPTF|Thermal|Dynamic Tuning|Fan Participant" }
|
|
$acpiById = Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.InstanceId -match "ACPI\\INT340[04]" }
|
|
$acpi = @($acpiByClass) + @($acpiById) | Sort-Object -Property InstanceId -Unique
|
|
if ($acpi) {
|
|
Write-Host "ACPI devices (DPTF/thermal/fan, INT3404/INT3400):" -ForegroundColor Green
|
|
$acpi | Select-Object Class, Status, FriendlyName, InstanceId | Format-Table -AutoSize
|
|
} else {
|
|
Write-Host "No DPTF-related ACPI device (INT3404/INT3400) found." -ForegroundColor Yellow
|
|
Write-Host " -> INT3404 = DPTF fan device (_FSL); INT3400 = thermal. Without these, Windows/DPTF cannot send fan control." -ForegroundColor DarkGray
|
|
}
|
|
$any = Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.FriendlyName -match "Dynamic Tuning|Fan Participant" }
|
|
if ($any -and -not $acpi) {
|
|
Write-Host "Dynamic Tuning devices (any class):" -ForegroundColor Cyan
|
|
$any | Select-Object Class, Status, FriendlyName | Format-Table -AutoSize
|
|
Write-Host " -> Check device Details for 'Device instance path'; if ACPI\INT3404\0, the fan device is present but was missed by class filter." -ForegroundColor DarkGray
|
|
}
|
|
Write-Host ""
|
|
|
|
# Power / thermal (DPTF may be gated by power plan or OEM settings)
|
|
Write-Host "=== Power / thermal (for DPTF fan control) ===" -ForegroundColor Cyan
|
|
try {
|
|
$active = powercfg /getactivescheme
|
|
if ($active) {
|
|
Write-Host "Active power scheme:" -ForegroundColor Green
|
|
$active
|
|
}
|
|
} catch {}
|
|
Write-Host "Manual check:" -ForegroundColor Yellow
|
|
Write-Host " 1. Settings -> System -> Power -> Power mode / Additional power settings" -ForegroundColor DarkGray
|
|
Write-Host " 2. Control Panel -> Power Options -> Change plan settings -> Change advanced power settings" -ForegroundColor DarkGray
|
|
Write-Host " Look for: Processor power, Intel, Thermal, or OEM (e.g. Acer) thermal/fan." -ForegroundColor DarkGray
|
|
Write-Host " 3. Device Manager -> Intel Dynamic Tuning Fan Participant -> Properties -> Driver: ensure enabled, no errors." -ForegroundColor DarkGray
|
|
Write-Host " 4. OEM app (e.g. Acer Care, Lenovo Vantage): turn OFF any 'quiet/silent fan' or 'disable DPTF'." -ForegroundColor DarkGray
|
|
Write-Host ""
|
|
}
|
|
|
|
# ---- 2) High-frequency _FST poll and log ----
|
|
function Start-FstPollLog {
|
|
if (-not (Test-Path $EctestPath)) {
|
|
Write-Host "ectest not found: $EctestPath" -ForegroundColor Red
|
|
return
|
|
}
|
|
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
|
|
$csvPath = Join-Path $LogDir "FST_poll_$ts.csv"
|
|
$end = [DateTime]::UtcNow.AddSeconds($PollSeconds)
|
|
Write-Host "Polling _FST every $PollIntervalMs ms for $PollSeconds s. Log: $csvPath" -ForegroundColor Cyan
|
|
Write-Host "Apply CPU load (e.g. stress) to see if FAND changes. Ctrl+C to stop early." -ForegroundColor Yellow
|
|
$headers = "TimeUtc,ElapsedMs,FAND"
|
|
$headers | Set-Content $csvPath -Encoding UTF8
|
|
$t0 = [DateTime]::UtcNow
|
|
$lastFand = $null
|
|
$changeCount = 0
|
|
while ([DateTime]::UtcNow -lt $end) {
|
|
$out = & $EctestPath -acpi "\_SB.ECT0._FST" 2>$null
|
|
$fand = $null
|
|
$capture = $false
|
|
foreach ($line in ($out -split "`n")) {
|
|
if ($line -match 'Argument\[1\]:') { $capture = $true; continue }
|
|
if ($capture -and $line -match 'Integer Value:\s*(0x[0-9A-Fa-f]+|\d+)') {
|
|
$fand = $Matches[1]
|
|
break
|
|
}
|
|
}
|
|
$elapsed = ([DateTime]::UtcNow - $t0).TotalMilliseconds
|
|
$val = if ($fand) { $fand } else { "N/A" }
|
|
$line = "{0:O},{1:F0},{2}" -f [DateTime]::UtcNow, $elapsed, $val
|
|
Add-Content $csvPath $line -Encoding UTF8
|
|
if ($null -ne $lastFand -and $fand -ne $lastFand) { $changeCount++ }
|
|
$lastFand = $fand
|
|
[System.Threading.Thread]::Sleep([int]$PollIntervalMs)
|
|
}
|
|
Write-Host "Done. FAND changed $changeCount times. Log: $csvPath" -ForegroundColor Green
|
|
}
|
|
|
|
# ---- 2b) Watch FAND: print only when value changes (see if INT3404 sends _FSL) ----
|
|
function Start-FstWatch {
|
|
if (-not (Test-Path $EctestPath)) {
|
|
Write-Host "ectest not found: $EctestPath" -ForegroundColor Red
|
|
return
|
|
}
|
|
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
|
|
$csvPath = Join-Path $LogDir "FST_watch_$ts.csv"
|
|
$end = [DateTime]::UtcNow.AddSeconds($PollSeconds)
|
|
Write-Host "=== INT3404 / FAND watch (FAND change = something wrote _FSL) ===" -ForegroundColor Cyan
|
|
Write-Host "Polling _FST every $PollIntervalMs ms for $PollSeconds s. Log: $csvPath" -ForegroundColor Cyan
|
|
Write-Host "Apply CPU load; if you see 'FAND changed' below, INT3404 or host wrote _FSL." -ForegroundColor Yellow
|
|
Write-Host ""
|
|
"TimeUtc,ElapsedMs,FAND,Changed" | Set-Content $csvPath -Encoding UTF8
|
|
$t0 = [DateTime]::UtcNow
|
|
$lastFand = $null
|
|
$changeCount = 0
|
|
while ([DateTime]::UtcNow -lt $end) {
|
|
$out = & $EctestPath -acpi "\_SB.ECT0._FST" 2>$null
|
|
$fand = $null
|
|
$capture = $false
|
|
foreach ($line in ($out -split "`n")) {
|
|
if ($line -match 'Argument\[1\]:') { $capture = $true; continue }
|
|
if ($capture -and $line -match 'Integer Value:\s*(0x[0-9A-Fa-f]+|\d+)') {
|
|
$fand = $Matches[1]
|
|
break
|
|
}
|
|
}
|
|
$val = if ($fand) { $fand } else { "N/A" }
|
|
$elapsed = ([DateTime]::UtcNow - $t0).TotalMilliseconds
|
|
$changed = $false
|
|
if ($null -ne $lastFand -and $fand -ne $lastFand) {
|
|
$changeCount++
|
|
$changed = $true
|
|
Write-Host (" {0} FAND changed: {1} -> {2}" -f (Get-Date -Format "HH:mm:ss"), $lastFand, $val) -ForegroundColor Green
|
|
}
|
|
$flag = if ($changed) { "1" } else { "0" }
|
|
$line = "{0:O},{1:F0},{2},{3}" -f [DateTime]::UtcNow, $elapsed, $val, $flag
|
|
Add-Content $csvPath $line -Encoding UTF8
|
|
$lastFand = $fand
|
|
[System.Threading.Thread]::Sleep([int]$PollIntervalMs)
|
|
}
|
|
Write-Host ""
|
|
if ($changeCount -eq 0) {
|
|
Write-Host "FAND never changed => INT3404 did not send _FSL (or EC overwrote)." -ForegroundColor Yellow
|
|
} else {
|
|
Write-Host "FAND changed $changeCount times => fan control was written (e.g. by INT3404)." -ForegroundColor Green
|
|
}
|
|
Write-Host "Log: $csvPath" -ForegroundColor Cyan
|
|
}
|
|
|
|
# ---- 3) ETW trace (DPTF / ESIF) ----
|
|
function Start-DptfEtwTrace {
|
|
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
if (-not $isAdmin) {
|
|
Write-Host "ETW mode requires Administrator. Right-click PowerShell -> Run as administrator, then run again." -ForegroundColor Red
|
|
return
|
|
}
|
|
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
|
|
$etlPath = Join-Path $LogDir "DPTF_trace_$ts.etl"
|
|
$sessionName = "DptfMonitorSession"
|
|
# Remove if leftover (suppress "data collector set not found" and "access denied" when not admin)
|
|
$null = cmd /c "logman stop $sessionName 2>nul"
|
|
$null = cmd /c "logman delete $sessionName 2>nul"
|
|
# Prefer ESIF low-level (often present when DPTF is installed)
|
|
$providers = @(
|
|
@{ N = "EsifLfEtwProvider"; K = "0x200000"; L = 5 },
|
|
@{ N = "EsifUmdf2EtwProvider"; K = "0xFFFFFFFF"; L = 5 }
|
|
)
|
|
$added = $false
|
|
foreach ($p in $providers) {
|
|
$err = & { logman create trace $sessionName -p $p.N $p.K $p.L -o $etlPath -ets 2>&1 }
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host "Created trace with provider: $($p.N)" -ForegroundColor Green
|
|
$added = $true
|
|
break
|
|
}
|
|
}
|
|
if (-not $added) {
|
|
Write-Host "Could not create trace. Possible causes:" -ForegroundColor Red
|
|
Write-Host " - Not running as Administrator (required for ETW)." -ForegroundColor DarkGray
|
|
Write-Host " - DPTF ETW providers (EsifLfEtwProvider etc.) not registered on this build." -ForegroundColor DarkGray
|
|
Write-Host "You can still use -Mode watch to see if FAND changes." -ForegroundColor Yellow
|
|
return
|
|
}
|
|
logman start $sessionName -ets
|
|
Write-Host "ETW trace started. Run CPU stress for 1-2 min, then press Enter to stop..." -ForegroundColor Yellow
|
|
Read-Host
|
|
logman stop $sessionName -ets
|
|
$csvOut = $etlPath -replace '\.etl$', '.csv'
|
|
tracerpt $etlPath -o $csvOut -of CSV 2>$null
|
|
if (Test-Path $csvOut) {
|
|
Write-Host "Trace summary: $csvOut" -ForegroundColor Green
|
|
}
|
|
Write-Host "Raw ETL: $etlPath" -ForegroundColor Cyan
|
|
logman delete $sessionName -ets 2>$null
|
|
}
|
|
|
|
# ---- Main ----
|
|
switch ($Mode) {
|
|
"check" {
|
|
Get-DptfPresence
|
|
}
|
|
"poll" {
|
|
Get-DptfPresence
|
|
Start-FstPollLog
|
|
}
|
|
"watch" {
|
|
Get-DptfPresence
|
|
Start-FstWatch
|
|
}
|
|
"etw" {
|
|
Get-DptfPresence
|
|
Start-DptfEtwTrace
|
|
}
|
|
"all" {
|
|
Get-DptfPresence
|
|
Start-DptfEtwTrace
|
|
Write-Host "Now polling _FST for $PollSeconds s..." -ForegroundColor Cyan
|
|
Start-FstPollLog
|
|
}
|
|
}
|