summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2015-02-15 15:49:27 -0200
committerGravatar Yuri Kunde Schlesner2015-03-01 21:47:14 -0300
commitdc8a3f8bc842df1b3eeeb5a283556ac644ab3183 (patch)
tree82bc4d610bd0b77ba6f2ac4e514e68d1c251b251 /src
parentAdd profiling infrastructure and widget (diff)
downloadyuzu-dc8a3f8bc842df1b3eeeb5a283556ac644ab3183.tar.gz
yuzu-dc8a3f8bc842df1b3eeeb5a283556ac644ab3183.tar.xz
yuzu-dc8a3f8bc842df1b3eeeb5a283556ac644ab3183.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/common/profiler.cpp23
-rw-r--r--src/common/profiler.h20
2 files changed, 42 insertions, 1 deletions
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp
index c37546af0..65c3df167 100644
--- a/src/common/profiler.cpp
+++ b/src/common/profiler.cpp
@@ -6,6 +6,12 @@
6#include "common/profiler_reporting.h" 6#include "common/profiler_reporting.h"
7#include "common/assert.h" 7#include "common/assert.h"
8 8
9#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013.
10#define NOMINMAX
11#define WIN32_LEAN_AND_MEAN
12#include <Windows.h> // For QueryPerformanceCounter/Frequency
13#endif
14
9namespace Common { 15namespace Common {
10namespace Profiling { 16namespace Profiling {
11 17
@@ -13,6 +19,23 @@ namespace Profiling {
13thread_local Timer* Timer::current_timer = nullptr; 19thread_local Timer* Timer::current_timer = nullptr;
14#endif 20#endif
15 21
22#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013
23QPCClock::time_point QPCClock::now() {
24 static LARGE_INTEGER freq;
25 // Use this dummy local static to ensure this gets initialized once.
26 static BOOL dummy = QueryPerformanceFrequency(&freq);
27
28 LARGE_INTEGER ticks;
29 QueryPerformanceCounter(&ticks);
30
31 // This is prone to overflow when multiplying, which is why I'm using micro instead of nano. The
32 // correct way to approach this would be to just return ticks as a time_point and then subtract
33 // and do this conversion when creating a duration from two time_points, however, as far as I
34 // could tell the C++ requirements for these types are incompatible with this approach.
35 return time_point(duration(ticks.QuadPart * std::micro::den / freq.QuadPart));
36}
37#endif
38
16TimingCategory::TimingCategory(const char* name, TimingCategory* parent) 39TimingCategory::TimingCategory(const char* name, TimingCategory* parent)
17 : accumulated_duration(0) { 40 : accumulated_duration(0) {
18 41
diff --git a/src/common/profiler.h b/src/common/profiler.h
index 53c4f6eaf..3e967b4bc 100644
--- a/src/common/profiler.h
+++ b/src/common/profiler.h
@@ -18,8 +18,26 @@ namespace Profiling {
18#define ENABLE_PROFILING 1 18#define ENABLE_PROFILING 1
19#endif 19#endif
20 20
21using Duration = std::chrono::nanoseconds; 21#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013
22// MSVC up to 2013 doesn't use QueryPerformanceCounter for high_resolution_clock, so it has bad
23// precision. We manually implement a clock based on QPC to get good results.
24
25struct QPCClock {
26 using duration = std::chrono::microseconds;
27 using time_point = std::chrono::time_point<QPCClock>;
28 using rep = duration::rep;
29 using period = duration::period;
30 static const bool is_steady = false;
31
32 static time_point now();
33};
34
35using Clock = QPCClock;
36#else
22using Clock = std::chrono::high_resolution_clock; 37using Clock = std::chrono::high_resolution_clock;
38#endif
39
40using Duration = Clock::duration;
23 41
24/** 42/**
25 * Represents a timing category that measured time can be accounted towards. Should be declared as a 43 * Represents a timing category that measured time can be accounted towards. Should be declared as a