summaryrefslogtreecommitdiff
path: root/src/common/profiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/profiler.cpp')
-rw-r--r--src/common/profiler.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp
new file mode 100644
index 000000000..c37546af0
--- /dev/null
+++ b/src/common/profiler.cpp
@@ -0,0 +1,159 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/profiler.h"
6#include "common/profiler_reporting.h"
7#include "common/assert.h"
8
9namespace Common {
10namespace Profiling {
11
12#if ENABLE_PROFILING
13thread_local Timer* Timer::current_timer = nullptr;
14#endif
15
16TimingCategory::TimingCategory(const char* name, TimingCategory* parent)
17 : accumulated_duration(0) {
18
19 ProfilingManager& manager = GetProfilingManager();
20 category_id = manager.RegisterTimingCategory(this, name);
21 if (parent != nullptr)
22 manager.SetTimingCategoryParent(category_id, parent->category_id);
23}
24
25ProfilingManager::ProfilingManager()
26 : last_frame_end(Clock::now()), this_frame_start(Clock::now()) {
27}
28
29unsigned int ProfilingManager::RegisterTimingCategory(TimingCategory* category, const char* name) {
30 TimingCategoryInfo info;
31 info.category = category;
32 info.name = name;
33 info.parent = TimingCategoryInfo::NO_PARENT;
34
35 unsigned int id = (unsigned int)timing_categories.size();
36 timing_categories.push_back(std::move(info));
37
38 return id;
39}
40
41void ProfilingManager::SetTimingCategoryParent(unsigned int category, unsigned int parent) {
42 ASSERT(category < timing_categories.size());
43 ASSERT(parent < timing_categories.size());
44
45 timing_categories[category].parent = parent;
46}
47
48void ProfilingManager::BeginFrame() {
49 this_frame_start = Clock::now();
50}
51
52void ProfilingManager::FinishFrame() {
53 Clock::time_point now = Clock::now();
54
55 results.interframe_time = now - last_frame_end;
56 results.frame_time = now - this_frame_start;
57
58 results.time_per_category.resize(timing_categories.size());
59 for (size_t i = 0; i < timing_categories.size(); ++i) {
60 results.time_per_category[i] = timing_categories[i].category->GetAccumulatedTime();
61 }
62
63 last_frame_end = now;
64}
65
66TimingResultsAggregator::TimingResultsAggregator(size_t window_size)
67 : max_window_size(window_size), window_size(0) {
68 interframe_times.resize(window_size, Duration::zero());
69 frame_times.resize(window_size, Duration::zero());
70}
71
72void TimingResultsAggregator::Clear() {
73 window_size = cursor = 0;
74}
75
76void TimingResultsAggregator::SetNumberOfCategories(size_t n) {
77 size_t old_size = times_per_category.size();
78 if (n == old_size)
79 return;
80
81 times_per_category.resize(n);
82
83 for (size_t i = old_size; i < n; ++i) {
84 times_per_category[i].resize(max_window_size, Duration::zero());
85 }
86}
87
88void TimingResultsAggregator::AddFrame(const ProfilingFrameResult& frame_result) {
89 SetNumberOfCategories(frame_result.time_per_category.size());
90
91 interframe_times[cursor] = frame_result.interframe_time;
92 frame_times[cursor] = frame_result.frame_time;
93 for (size_t i = 0; i < frame_result.time_per_category.size(); ++i) {
94 times_per_category[i][cursor] = frame_result.time_per_category[i];
95 }
96
97 ++cursor;
98 if (cursor == max_window_size)
99 cursor = 0;
100 if (window_size < max_window_size)
101 ++window_size;
102}
103
104static AggregatedDuration AggregateField(const std::vector<Duration>& v, size_t len) {
105 AggregatedDuration result;
106 result.avg = Duration::zero();
107
108 result.min = result.max = (len == 0 ? Duration::zero() : v[0]);
109
110 for (size_t i = 1; i < len; ++i) {
111 Duration value = v[i];
112 result.avg += value;
113 result.min = std::min(result.min, value);
114 result.max = std::max(result.max, value);
115 }
116 if (len != 0)
117 result.avg /= len;
118
119 return result;
120}
121
122static float tof(Common::Profiling::Duration dur) {
123 using FloatMs = std::chrono::duration<float, std::chrono::milliseconds::period>;
124 return std::chrono::duration_cast<FloatMs>(dur).count();
125}
126
127AggregatedFrameResult TimingResultsAggregator::GetAggregatedResults() const {
128 AggregatedFrameResult result;
129
130 result.interframe_time = AggregateField(interframe_times, window_size);
131 result.frame_time = AggregateField(frame_times, window_size);
132
133 if (result.interframe_time.avg != Duration::zero()) {
134 result.fps = 1000.0f / tof(result.interframe_time.avg);
135 } else {
136 result.fps = 0.0f;
137 }
138
139 result.time_per_category.resize(times_per_category.size());
140 for (size_t i = 0; i < times_per_category.size(); ++i) {
141 result.time_per_category[i] = AggregateField(times_per_category[i], window_size);
142 }
143
144 return result;
145}
146
147ProfilingManager& GetProfilingManager() {
148 // Takes advantage of "magic" static initialization for race-free initialization.
149 static ProfilingManager manager;
150 return manager;
151}
152
153SynchronizedRef<TimingResultsAggregator> GetTimingResultsAggregator() {
154 static SynchronizedWrapper<TimingResultsAggregator> aggregator(30);
155 return SynchronizedRef<TimingResultsAggregator>(aggregator);
156}
157
158} // namespace Profiling
159} // namespace Common