Warn when host power scheme is not high performance before launching Windows Sandbox#298
Conversation
|
|
전원 프로필 "이름(고성능 GUID)" 매칭은 복제/OEM 계획을 오탐하고 AC의 균형 조정처럼 실제로는 100%로 동작하는 경우도 잘못 경고했다. 실제 성능에 직접적인 CPU 최대 성능 상한 (최대 프로세서 상태)을 읽어 판정하도록 바꾸고, 안내도 전용 창으로 친절하게 재구성한다. 판정 (Helpers) - IsHighPerformancePowerScheme(이름 매칭) 제거. 현재 전원 소스(AC/DC)에 적용되는 최대 프로세서 상태(GUID_PROCESSOR_THROTTLE_MAXIMUM)를 PowerReadAC/DCValueIndex로 읽어, 100% 미만이면 스로틀로 판정(IsSandboxCpuLikelyThrottled). 판별 실패 시 null → 경고 억제. - 순수 분류기 IsProcessorStateThrottled(int)로 값→판정 로직을 단위 테스트(ProcessorThrottleTests). 안내 UI - 시스템 메시지 박스 → 전용 PowerSchemeGuideWindow(MVVM). 상황을 설명하고 클래식 제어판 (powercfg.cpl)과 모던 설정(전원 및 절전) 중 하나를 골라 열 수 있다. - 열기 버튼은 해당 설정만 열고 모달은 유지, '나중에'로만 닫는다. 버튼 내부 텍스트는 전용 템플릿으로 왼쪽 정렬(테마 색은 DynamicResource 유지). - IAppUserInterface 팩토리 + DI 등록. SandboxLauncher는 UI 스레드로 마샬링해 모달 표시. - InfoStrings.Info_Sandbox_ProcessorThrottled 제거, UIStringResources에 PowerSchemeGuide_* 추가(한/영). 빌드 경고 0, 테스트 통과, 스로틀 시뮬레이션·스모크 실행으로 검증. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds host-side power/CPU-throttling detection and a dedicated WPF guide window to inform users when Windows Sandbox may run slowly due to a limited “Maximum processor state”, with localized UI strings and unit tests for the pure classification logic.
Changes:
- Added
Helperslogic to read the active power scheme and the effective “Maximum processor state (%)”, plus a pure classifier for throttling. - Added a new
PowerSchemeGuideWindow(XAML + ViewModel) and DI wiring, and invoked it fromSandboxLauncherbefore launching Sandbox. - Added new localized strings (en/ko) and a new MSTest class validating the throttle classifier.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/TableCloth.Test/ProcessorThrottleTests.cs | Adds unit tests for the pure “processor state throttled” classifier. |
| src/TableCloth.Core/Resources/UIStringResources.resx | Adds English strings for the power/performance guide window. |
| src/TableCloth.Core/Resources/UIStringResources.ko.resx | Adds Korean strings for the power/performance guide window. |
| src/TableCloth.Core/Resources/UIStringResources.Designer.cs | Adds Designer accessors for the new resource keys. |
| src/TableCloth.Core/Helpers.cs | Introduces P/Invoke-based reading of max processor state and throttling determination. |
| src/TableCloth.App/ViewModels/PowerSchemeGuideWindowViewModel.cs | Adds commands to open classic/modern power settings and dismiss the guide. |
| src/TableCloth.App/Dialogs/PowerSchemeGuideWindow.xaml.cs | Wires CloseRequested to close the window. |
| src/TableCloth.App/Dialogs/PowerSchemeGuideWindow.xaml | Implements the guide window UI and binds to new resource strings/commands. |
| src/TableCloth.App/DependencyInjection/UseTableClothExtensions.cs | Registers the new window + view model in DI. |
| src/TableCloth.App/Components/Implementations/SandboxLauncher.cs | Shows the guide window based on throttling detection before launch. |
| src/TableCloth.App/Components/Implementations/AppUserInterface.cs | Adds a factory method to create the new window with ownership. |
| src/TableCloth.App/Components/IAppUserInterface.cs | Exposes the new window factory on the UI abstraction. |
Files not reviewed (1)
- src/TableCloth.Core/Resources/UIStringResources.Designer.cs: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // CPU 최대 성능이 제한(스로틀)되어 있으면, 시스템 메시지 박스 대신 전용 안내 창을 띄워 | ||
| // 클래식(powercfg.cpl)/모던(전원 및 절전) 전원 설정 중 하나를 골라 열 수 있게 안내한다. | ||
| // 백그라운드에서 호출될 수 있으므로 UI 스레드로 마샬링해 모달로 표시한다(런치는 계속 진행). | ||
| if (Helpers.IsSandboxCpuLikelyThrottled() == true) | ||
| applicationService.DispatchInvoke(() => appUserInterface.CreatePowerSchemeGuideWindow().ShowDialog(), []); |
| // CPU 최대 성능이 제한(스로틀)되어 있으면, 시스템 메시지 박스 대신 전용 안내 창을 띄워 | ||
| // 클래식(powercfg.cpl)/모던(전원 및 절전) 전원 설정 중 하나를 골라 열 수 있게 안내한다. | ||
| // 백그라운드에서 호출될 수 있으므로 UI 스레드로 마샬링해 모달로 표시한다(런치는 계속 진행). | ||
| if (Helpers.IsSandboxCpuLikelyThrottled() == true) | ||
| applicationService.DispatchInvoke(() => appUserInterface.CreatePowerSchemeGuideWindow().ShowDialog(), []); |
| private static bool IsRunningOnBattery() | ||
| { | ||
| if (!GetSystemPowerStatus(out var status)) | ||
| return false; | ||
|
|
||
| // 0 = 배터리. 1(AC)/255(알 수 없음)은 AC로 간주해 AC 설정을 읽는다(보수적). | ||
| return status.ACLineStatus == 0; | ||
| } |
| public static int? GetActiveMaxProcessorStatePercent() | ||
| { | ||
| var activeSchemeGuid = GetActivePowerSchemeGuid(); | ||
| if (!activeSchemeGuid.HasValue) | ||
| return null; | ||
|
|
||
| var schemeGuid = activeSchemeGuid.Value; | ||
|
|
||
| var result = IsRunningOnBattery() | ||
| ? PowerReadDCValueIndex(IntPtr.Zero, in schemeGuid, in ProcessorSettingsSubgroupGuid, | ||
| in ProcessorThrottleMaximumSettingGuid, out var value) | ||
| : PowerReadACValueIndex(IntPtr.Zero, in schemeGuid, in ProcessorSettingsSubgroupGuid, | ||
| in ProcessorThrottleMaximumSettingGuid, out value); | ||
|
|
||
| if (result != ERROR_SUCCESS) | ||
| return null; | ||
|
|
||
| return (int)value; | ||
| } |
Windows Sandbox startup can be noticeably slower when the host's active power plan isn't a high-performance one. This surfaces a non-blocking recommendation at launch time so users can opt into a faster experience.
Changes
Helpers.cs— power scheme detectionGetActivePowerSchemeGuid(): reads the active scheme GUID viaPowerGetActiveScheme(powrprof.dll), freeing the returned pointer withLocalFree; returnsnullon failure.IsHighPerformancePowerScheme(Guid): pure classifier treating High performance (8c5e7fda-…) and Ultimate Performance (e9a42b02-…) as high-performance.IsHighPerformancePowerSchemeActive(): returnsbool?—nullwhen detection isn't possible, so the warning only fires when we're confident the scheme is not high performance.SandboxLauncher.RunSandboxAsync— shows an info message before launch when the scheme is confirmed non-high-performance; does not block the launch.Resources — added
Info_PowerScheme_NotHighPerformance(en + ko + Designer).Tests —
PowerSchemeTestscovers the classification logic across High performance / Ultimate / Balanced / Power saver / empty GUID. Logic lives in the netstandard2.0TableCloth.Coreproject to keep it unit-testable independent of the WPF host.Notes
nullfrom detection is treated as "unknown" and intentionally suppresses the warning to avoid false positives on environments wherePowerGetActiveSchemeis unavailable.