mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Profiler: Implement QPCClock to get better precision on Win32
MSVC 2013 (at least) doesn't use QueryPerformanceCounter to implement std::chrono::high_resolution_clock, so it has bad precision. Manually implementing our own clock type using it works around this for now.
This commit is contained in:
		
							parent
							
								
									cd1fbfcf1b
								
							
						
					
					
						commit
						dc8a3f8bc8
					
				
					 2 changed files with 42 additions and 1 deletions
				
			
		|  | @ -6,6 +6,12 @@ | |||
| #include "common/profiler_reporting.h" | ||||
| #include "common/assert.h" | ||||
| 
 | ||||
| #if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013.
 | ||||
| #define NOMINMAX | ||||
| #define WIN32_LEAN_AND_MEAN | ||||
| #include <Windows.h> // For QueryPerformanceCounter/Frequency
 | ||||
| #endif | ||||
| 
 | ||||
| namespace Common { | ||||
| namespace Profiling { | ||||
| 
 | ||||
|  | @ -13,6 +19,23 @@ namespace Profiling { | |||
| thread_local Timer* Timer::current_timer = nullptr; | ||||
| #endif | ||||
| 
 | ||||
| #if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013
 | ||||
| QPCClock::time_point QPCClock::now() { | ||||
|     static LARGE_INTEGER freq; | ||||
|     // Use this dummy local static to ensure this gets initialized once.
 | ||||
|     static BOOL dummy = QueryPerformanceFrequency(&freq); | ||||
| 
 | ||||
|     LARGE_INTEGER ticks; | ||||
|     QueryPerformanceCounter(&ticks); | ||||
| 
 | ||||
|     // This is prone to overflow when multiplying, which is why I'm using micro instead of nano. The
 | ||||
|     // correct way to approach this would be to just return ticks as a time_point and then subtract
 | ||||
|     // and do this conversion when creating a duration from two time_points, however, as far as I
 | ||||
|     // could tell the C++ requirements for these types are incompatible with this approach.
 | ||||
|     return time_point(duration(ticks.QuadPart * std::micro::den / freq.QuadPart)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| TimingCategory::TimingCategory(const char* name, TimingCategory* parent) | ||||
|         : accumulated_duration(0) { | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,8 +18,26 @@ namespace Profiling { | |||
| #define ENABLE_PROFILING 1 | ||||
| #endif | ||||
| 
 | ||||
| using Duration = std::chrono::nanoseconds; | ||||
| #if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013
 | ||||
| // MSVC up to 2013 doesn't use QueryPerformanceCounter for high_resolution_clock, so it has bad
 | ||||
| // precision. We manually implement a clock based on QPC to get good results.
 | ||||
| 
 | ||||
| struct QPCClock { | ||||
|     using duration = std::chrono::microseconds; | ||||
|     using time_point = std::chrono::time_point<QPCClock>; | ||||
|     using rep = duration::rep; | ||||
|     using period = duration::period; | ||||
|     static const bool is_steady = false; | ||||
| 
 | ||||
|     static time_point now(); | ||||
| }; | ||||
| 
 | ||||
| using Clock = QPCClock; | ||||
| #else | ||||
| using Clock = std::chrono::high_resolution_clock; | ||||
| #endif | ||||
| 
 | ||||
| using Duration = Clock::duration; | ||||
| 
 | ||||
| /**
 | ||||
|  * Represents a timing category that measured time can be accounted towards. Should be declared as a | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue