Browse Source
Common: Remove section measurement from profiler (#1731)
Common: Remove section measurement from profiler (#1731)
This has been entirely superseded by MicroProfile. The rest of the code can go when a simpler frametime/FPS meter is added to the GUI.nce_cpp
13 changed files with 8 additions and 306 deletions
-
26src/citra_qt/debugger/profiler.cpp
-
1src/common/CMakeLists.txt
-
3src/common/microprofileui.h
-
82src/common/profiler.cpp
-
152src/common/profiler.h
-
27src/common/profiler_reporting.h
-
7src/core/arm/dyncom/arm_dyncom_interpreter.cpp
-
1src/core/hle/service/gsp_gpu.cpp
-
4src/core/hle/svc.cpp
-
4src/video_core/command_processor.cpp
-
3src/video_core/rasterizer.cpp
-
1src/video_core/renderer_opengl/gl_rasterizer.cpp
-
3src/video_core/shader/shader.cpp
@ -1,152 +0,0 @@ |
|||||
// Copyright 2015 Citra Emulator Project |
|
||||
// Licensed under GPLv2 or any later version |
|
||||
// Refer to the license.txt file included. |
|
||||
|
|
||||
#pragma once |
|
||||
|
|
||||
#include <atomic> |
|
||||
#include <chrono> |
|
||||
|
|
||||
#include "common/assert.h" |
|
||||
#include "common/thread.h" |
|
||||
|
|
||||
namespace Common { |
|
||||
namespace Profiling { |
|
||||
|
|
||||
// If this is defined to 0, it turns all Timers into no-ops. |
|
||||
#ifndef ENABLE_PROFILING |
|
||||
#define ENABLE_PROFILING 1 |
|
||||
#endif |
|
||||
|
|
||||
#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 |
|
||||
* global variable and passed to Timers. |
|
||||
*/ |
|
||||
class TimingCategory final { |
|
||||
public: |
|
||||
TimingCategory(const char* name, TimingCategory* parent = nullptr); |
|
||||
|
|
||||
unsigned int GetCategoryId() const { |
|
||||
return category_id; |
|
||||
} |
|
||||
|
|
||||
/// Adds some time to this category. Can safely be called from multiple threads at the same time. |
|
||||
void AddTime(Duration amount) { |
|
||||
std::atomic_fetch_add_explicit( |
|
||||
&accumulated_duration, amount.count(), |
|
||||
std::memory_order_relaxed); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Atomically retrieves the accumulated measured time for this category and resets the counter |
|
||||
* to zero. Can be safely called concurrently with AddTime. |
|
||||
*/ |
|
||||
Duration GetAccumulatedTime() { |
|
||||
return Duration(std::atomic_exchange_explicit( |
|
||||
&accumulated_duration, (Duration::rep)0, |
|
||||
std::memory_order_relaxed)); |
|
||||
} |
|
||||
|
|
||||
private: |
|
||||
unsigned int category_id; |
|
||||
std::atomic<Duration::rep> accumulated_duration; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Measures time elapsed between a call to Start and a call to Stop and attributes it to the given |
|
||||
* TimingCategory. Start/Stop can be called multiple times on the same timer, but each call must be |
|
||||
* appropriately paired. |
|
||||
* |
|
||||
* When a Timer is started, it automatically pauses a previously running timer on the same thread, |
|
||||
* which is resumed when it is stopped. As such, no special action needs to be taken to avoid |
|
||||
* double-accounting of time on two categories. |
|
||||
*/ |
|
||||
class Timer { |
|
||||
public: |
|
||||
Timer(TimingCategory& category) : category(category) { |
|
||||
} |
|
||||
|
|
||||
void Start() { |
|
||||
#if ENABLE_PROFILING |
|
||||
ASSERT(!running); |
|
||||
previous_timer = current_timer; |
|
||||
current_timer = this; |
|
||||
if (previous_timer != nullptr) |
|
||||
previous_timer->StopTiming(); |
|
||||
|
|
||||
StartTiming(); |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
void Stop() { |
|
||||
#if ENABLE_PROFILING |
|
||||
ASSERT(running); |
|
||||
StopTiming(); |
|
||||
|
|
||||
if (previous_timer != nullptr) |
|
||||
previous_timer->StartTiming(); |
|
||||
current_timer = previous_timer; |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
private: |
|
||||
#if ENABLE_PROFILING |
|
||||
void StartTiming() { |
|
||||
start = Clock::now(); |
|
||||
running = true; |
|
||||
} |
|
||||
|
|
||||
void StopTiming() { |
|
||||
auto duration = Clock::now() - start; |
|
||||
running = false; |
|
||||
category.AddTime(std::chrono::duration_cast<Duration>(duration)); |
|
||||
} |
|
||||
|
|
||||
Clock::time_point start; |
|
||||
bool running = false; |
|
||||
|
|
||||
Timer* previous_timer; |
|
||||
static thread_local Timer* current_timer; |
|
||||
#endif |
|
||||
|
|
||||
TimingCategory& category; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* A Timer that automatically starts timing when created and stops at the end of the scope. Should |
|
||||
* be used in the majority of cases. |
|
||||
*/ |
|
||||
class ScopeTimer : public Timer { |
|
||||
public: |
|
||||
ScopeTimer(TimingCategory& category) : Timer(category) { |
|
||||
Start(); |
|
||||
} |
|
||||
|
|
||||
~ScopeTimer() { |
|
||||
Stop(); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
} // namespace Profiling |
|
||||
} // namespace Common |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue