├── LICENSE ├── CMakeLists.txt ├── README.md ├── src └── main.cpp └── .gitignore /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 milkru 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6 FATAL_ERROR) 2 | cmake_policy(VERSION 3.6) 3 | project(gpu_clock_stabilizer VERSION 1.0.0 LANGUAGES C CXX) 4 | 5 | set(CMAKE_SUPPRESS_REGENERATION true) 6 | set(DCMAKE_GENERATOR_PLATFORM "x64") 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 9 | SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin) 10 | SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin) 11 | SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin) 12 | SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin) 13 | SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin) 14 | SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin) 15 | 16 | file(GLOB_RECURSE SRC_FILES RELATIVE 17 | ${CMAKE_CURRENT_SOURCE_DIR} 18 | ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp 19 | ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h 20 | ) 21 | 22 | foreach(source IN LISTS SRC_FILES) 23 | get_filename_component(source_path "${source}" PATH) 24 | string(REPLACE "/" "\\" source_path_msvc "${source_path}") 25 | string(REPLACE "src" "" source_path_final "${source_path_msvc}") 26 | source_group("${source_path_final}" FILES "${source}") 27 | endforeach() 28 | 29 | add_executable(${PROJECT_NAME} ${SRC_FILES}) 30 | 31 | set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11) 32 | set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) 33 | 34 | if (MSVC) 35 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) 36 | endif() 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | A simple *DirectX 12* based *GPU clock stabilizer* used for consistent *GPU* profiling on *Windows*. It can be used for profiling applications made with other modern graphics APIs as well. It utilizes *DirectX 12's* `SetStablePowerState` device method in order to achieve this. This allows more deterministic timestamp query results used for calculating elapsed *GPU* time for any given range of render calls at the expense of lower performance. You can read more about it [here](https://developer.nvidia.com/dx12-dos-and-donts#powerstate). Also, make sure that your GPU actually supports [ID3D12Device::SetStablePowerState](https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-setstablepowerstate). 3 | 4 | ## Installation 5 | The *DirectX 12 SDK* comes included with the *Windows 10 SDK* which is part of the *Visual Studio* installation. Just make sure you install the *Game Development with C++* in the *Visual Studio Installer*. 6 | 7 | Run cmd `cmake . -B bin -A x64` in the project's root. 8 | 9 | ## How it works 10 | If not specified in the command line, the first available *GPU* will be chosen. You can also specifiy the *GPU* explicitly by passing the name of the preferred *GPU*, for example "*NVIDIA GeForce RTX 3070*". Names of your *GPUs* can be found in *Device Manager*, *Display Adapters* tab. This way the application can work on *multi GPU system*. In order for *GPU clock* to remain stable, the application should remain running at all times. After exiting the application, or after one hour, clock stabilization will stop working. For testing the *GPU clock* I recommend using the [TechPowerUp GPU-Z](https://www.techpowerup.com/download/techpowerup-gpu-z/). Observe the *Sensors/GPU Core Clock's* behavior with and without the application running. 11 | 12 | ## Results 13 | First image shows the usual GPU clock values on *NVidia GeForce RTX 3070* and the second one shows the clock with the *gpu_clock_stabilizer* running. This was captured using the [TechPowerUp GPU-Z](https://www.techpowerup.com/download/techpowerup-gpu-z/).

14 | ![Unstable](https://github.com/milkru/data_resources/blob/main/gpu_clock_stabilizer/UnstableClock.PNG "Unstable") ![Stable](https://github.com/milkru/data_resources/blob/main/gpu_clock_stabilizer/StableClock.PNG "Stable") 15 | 16 | ## Troubleshooting 17 | If `SetStablePowerState` is failing, please refer to the [SetStablePowerState Microsoft Documentation](https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-setstablepowerstate) for troubleshooting. This mostly happens if *Developer Mode* is not enabled on *Windows*. 18 | 19 | ## License 20 | Distributed under the MIT License. See `LICENSE` for more information. 21 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #pragma comment(lib, "d3d12.lib") 2 | #pragma comment(lib, "dxgi.lib") 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) 12 | { 13 | wchar_t* requestedAdapterName = argc > 1 ? argv[1] : nullptr; 14 | 15 | // Create Factory. 16 | Microsoft::WRL::ComPtr factory; 17 | if (FAILED(CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)))) 18 | { 19 | fprintf_s(stderr, "IDXGIFactory4 creation FAILED.\n"); 20 | 21 | std::this_thread::sleep_for(std::chrono::minutes(1)); 22 | return EXIT_FAILURE; 23 | } 24 | 25 | // Pick Adapter. 26 | bool adapterFound = false; 27 | Microsoft::WRL::ComPtr adapter; 28 | DXGI_ADAPTER_DESC1 adapterDescriptor; 29 | for (UINT adapterIndex = 0; factory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) 30 | { 31 | adapter->GetDesc1(&adapterDescriptor); 32 | 33 | // Skip software adapters. 34 | if ((adapterDescriptor.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0) 35 | { 36 | continue; 37 | } 38 | 39 | // Skip an adapter if it's not requested. 40 | if (requestedAdapterName != nullptr && wcscmp(requestedAdapterName, adapterDescriptor.Description) != 0) 41 | { 42 | continue; 43 | } 44 | 45 | // Adequate adapter found. 46 | if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) 47 | { 48 | adapterFound = true; 49 | break; 50 | } 51 | } 52 | 53 | if (adapterFound) 54 | { 55 | fwprintf_s(stdout, L"Adapter \"%ls\" successfully FOUND.\n", adapterDescriptor.Description); 56 | } 57 | else if (requestedAdapterName != nullptr) 58 | { 59 | fwprintf_s(stderr, L"Required adapter \"%ls\" NOT FOUND.\n", requestedAdapterName); 60 | 61 | std::this_thread::sleep_for(std::chrono::minutes(1)); 62 | return EXIT_FAILURE; 63 | } 64 | else 65 | { 66 | fwprintf_s(stderr, L"NOT a single adapter was FOUND.\n"); 67 | 68 | std::this_thread::sleep_for(std::chrono::minutes(1)); 69 | return EXIT_FAILURE; 70 | } 71 | 72 | // Create Device. 73 | Microsoft::WRL::ComPtr device; 74 | if (FAILED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device)))) 75 | { 76 | fwprintf_s(stderr, L"ID3D12Device creation FAILED for \"%ls\".\n", adapterDescriptor.Description); 77 | 78 | std::this_thread::sleep_for(std::chrono::minutes(1)); 79 | return EXIT_FAILURE; 80 | } 81 | 82 | // Stabilize power state. 83 | if (FAILED(device->SetStablePowerState(TRUE))) 84 | { 85 | fwprintf_s(stderr, L"SetStablePowerState(TRUE) FAILED for \"%ls\" adapter.\n", adapterDescriptor.Description); 86 | 87 | std::this_thread::sleep_for(std::chrono::minutes(1)); 88 | return EXIT_FAILURE; 89 | } 90 | 91 | fwprintf_s(stdout, L"SetStablePowerState(TRUE) SUCCEEDED for \"%ls\" adapter.\n", adapterDescriptor.Description); 92 | fprintf_s(stdout, "Clock will remain stable while the application is running.\n"); 93 | 94 | // Turning off the application reverts the clock. 95 | std::this_thread::sleep_for(std::chrono::hours(1)); 96 | return EXIT_SUCCESS; 97 | } 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CMake 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | *.tcl 12 | *_autogen 13 | *.dir 14 | build/ 15 | visualstudio/ 16 | xcode/ 17 | androidstudio/ 18 | make/ 19 | webassembly/ 20 | 21 | ## Visual Studio 22 | # User-specific files 23 | *.vs 24 | *.vscode 25 | *.sln 26 | *.vcxproj 27 | *.filters 28 | *.suo 29 | *.user 30 | *.userosscache 31 | *.sln.docstates 32 | 33 | 34 | # User-specific files (MonoDevelop/Xamarin Studio) 35 | *.userprefs 36 | 37 | # Build results 38 | [Dd]ebug/ 39 | [Dd]ebugPublic/ 40 | [Rr]elease/ 41 | [Rr]eleases/ 42 | x64/ 43 | x86/ 44 | bld/ 45 | [Bb]in/ 46 | [Oo]bj/ 47 | [Ll]og/ 48 | 49 | # Windows 50 | 51 | *.DS_Store 52 | 53 | # Visual Studio 2015 cache/options directory 54 | .vs/ 55 | # Uncomment if you have tasks that create the project's static files in wwwroot 56 | #wwwroot/ 57 | 58 | # MSTest test Results 59 | [Tt]est[Rr]esult*/ 60 | [Bb]uild[Ll]og.* 61 | 62 | # NUNIT 63 | *.VisualState.xml 64 | TestResult.xml 65 | 66 | # Build Results of an ATL Project 67 | [Dd]ebugPS/ 68 | [Rr]eleasePS/ 69 | dlldata.c 70 | 71 | # Benchmark Results 72 | BenchmarkDotNet.Artifacts/ 73 | 74 | # .NET Core 75 | project.lock.json 76 | project.fragment.lock.json 77 | artifacts/ 78 | **/Properties/launchSettings.json 79 | 80 | *_i.c 81 | *_p.c 82 | *_i.h 83 | *.ilk 84 | *.meta 85 | *.obj 86 | *.pch 87 | *.pdb 88 | *.pgc 89 | *.pgd 90 | *.rsp 91 | *.sbr 92 | *.tlb 93 | *.tli 94 | *.tlh 95 | *.tmp 96 | *.tmp_proj 97 | *.log 98 | *.vspscc 99 | *.vssscc 100 | .builds 101 | *.pidb 102 | *.svclog 103 | *.scc 104 | 105 | # Chutzpah Test files 106 | _Chutzpah* 107 | 108 | # Visual C++ cache files 109 | ipch/ 110 | *.aps 111 | *.ncb 112 | *.opendb 113 | *.opensdf 114 | *.sdf 115 | *.cachefile 116 | *.VC.db 117 | *.VC.VC.opendb 118 | 119 | # Visual Studio profiler 120 | *.psess 121 | *.vsp 122 | *.vspx 123 | *.sap 124 | 125 | # TFS 2012 Local Workspace 126 | $tf/ 127 | 128 | # Guidance Automation Toolkit 129 | *.gpState 130 | 131 | # ReSharper is a .NET coding add-in 132 | _ReSharper*/ 133 | *.[Rr]e[Ss]harper 134 | *.DotSettings.user 135 | 136 | # JustCode is a .NET coding add-in 137 | .JustCode 138 | 139 | # TeamCity is a build add-in 140 | _TeamCity* 141 | 142 | # DotCover is a Code Coverage Tool 143 | *.dotCover 144 | 145 | # Visual Studio code coverage results 146 | *.coverage 147 | *.coveragexml 148 | 149 | # NCrunch 150 | _NCrunch_* 151 | .*crunch*.local.xml 152 | nCrunchTemp_* 153 | 154 | # MightyMoose 155 | *.mm.* 156 | AutoTest.Net/ 157 | 158 | # Web workbench (sass) 159 | .sass-cache/ 160 | 161 | # Installshield output folder 162 | [Ee]xpress/ 163 | 164 | # DocProject is a documentation generator add-in 165 | DocProject/buildhelp/ 166 | DocProject/Help/*.HxT 167 | DocProject/Help/*.HxC 168 | DocProject/Help/*.hhc 169 | DocProject/Help/*.hhk 170 | DocProject/Help/*.hhp 171 | DocProject/Help/Html2 172 | DocProject/Help/html 173 | 174 | # Click-Once directory 175 | publish/ 176 | 177 | # Publish Web Output 178 | *.[Pp]ublish.xml 179 | *.azurePubxml 180 | # Note: Comment the next line if you want to checkin your web deploy settings, 181 | # but database connection strings (with potential passwords) will be unencrypted 182 | *.pubxml 183 | *.publishproj 184 | 185 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 186 | # checkin your Azure Web App publish settings, but sensitive information contained 187 | # in these scripts will be unencrypted 188 | PublishScripts/ 189 | 190 | # NuGet Packages 191 | *.nupkg 192 | # The packages folder can be ignored because of Package Restore 193 | **/packages/* 194 | # except build/, which is used as an MSBuild target. 195 | !**/packages/build/ 196 | # Uncomment if necessary however generally it will be regenerated when needed 197 | #!**/packages/repositories.config 198 | # NuGet v3's project.json files produces more ignorable files 199 | *.nuget.props 200 | *.nuget.targets 201 | 202 | # Microsoft Azure Build Output 203 | csx/ 204 | *.build.csdef 205 | 206 | # Microsoft Azure Emulator 207 | ecf/ 208 | rcf/ 209 | 210 | # Windows Store app package directories and files 211 | AppPackages/ 212 | BundleArtifacts/ 213 | Package.StoreAssociation.xml 214 | _pkginfo.txt 215 | *.appx 216 | 217 | # Visual Studio cache files 218 | # files ending in .cache can be ignored 219 | *.[Cc]ache 220 | # but keep track of directories ending in .cache 221 | !*.[Cc]ache/ 222 | 223 | # Others 224 | ClientBin/ 225 | ~$* 226 | *~ 227 | *.dbmdl 228 | *.dbproj.schemaview 229 | *.jfm 230 | *.pfx 231 | *.publishsettings 232 | orleans.codegen.cs 233 | 234 | # Since there are multiple workflows, uncomment next line to ignore bower_components 235 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 236 | #bower_components/ 237 | 238 | # RIA/Silverlight projects 239 | Generated_Code/ 240 | 241 | # Backup & report files from converting an old project file 242 | # to a newer Visual Studio version. Backup files are not needed, 243 | # because we have git 244 | _UpgradeReport_Files/ 245 | Backup*/ 246 | UpgradeLog*.XML 247 | UpgradeLog*.htm 248 | 249 | # SQL Server files 250 | *.mdf 251 | *.ldf 252 | *.ndf 253 | 254 | # Business Intelligence projects 255 | *.rdl.data 256 | *.bim.layout 257 | *.bim_*.settings 258 | 259 | # Microsoft Fakes 260 | FakesAssemblies/ 261 | 262 | # GhostDoc plugin setting file 263 | *.GhostDoc.xml 264 | 265 | # Node.js Tools for Visual Studio 266 | .ntvs_analysis.dat 267 | node_modules/ 268 | 269 | # Typescript v1 declaration files 270 | typings/ 271 | 272 | # Visual Studio 6 build log 273 | *.plg 274 | 275 | # Visual Studio 6 workspace options file 276 | *.opt 277 | 278 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 279 | *.vbw 280 | 281 | # Visual Studio LightSwitch build output 282 | **/*.HTMLClient/GeneratedArtifacts 283 | **/*.DesktopClient/GeneratedArtifacts 284 | **/*.DesktopClient/ModelManifest.xml 285 | **/*.Server/GeneratedArtifacts 286 | **/*.Server/ModelManifest.xml 287 | _Pvt_Extensions 288 | 289 | # Paket dependency manager 290 | .paket/paket.exe 291 | paket-files/ 292 | 293 | # FAKE - F# Make 294 | .fake/ 295 | 296 | # JetBrains Rider 297 | .idea/ 298 | *.sln.iml 299 | 300 | # CodeRush 301 | .cr/ 302 | 303 | # Python Tools for Visual Studio (PTVS) 304 | __pycache__/ 305 | *.pyc 306 | 307 | # Cake - Uncomment if you are using it 308 | # tools/** 309 | # !tools/packages.config 310 | 311 | # Tabs Studio 312 | *.tss 313 | 314 | # Telerik's JustMock configuration file 315 | *.jmconfig 316 | 317 | # BizTalk build output 318 | *.btp.cs 319 | *.btm.cs 320 | *.odx.cs 321 | *.xsd.cs 322 | 323 | # Xcode 324 | # 325 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 326 | 327 | ## Build generated 328 | build/ 329 | DerivedData/ 330 | 331 | ## Various settings 332 | *.pbxuser 333 | !default.pbxuser 334 | *.mode1v3 335 | !default.mode1v3 336 | *.mode2v3 337 | !default.mode2v3 338 | *.perspectivev3 339 | !default.perspectivev3 340 | xcuserdata/ 341 | 342 | ## Other 343 | *.moved-aside 344 | *.xccheckout 345 | *.xcscmblueprint 346 | *.db 347 | 348 | ## Xcode 349 | *.xcworkspace 350 | *.xcodeproj --------------------------------------------------------------------------------