mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									90501f20e6
								
							
						
					
					
						commit
						e3a8292495
					
				
					 13 changed files with 8 additions and 306 deletions
				
			
		|  | @ -47,7 +47,6 @@ set(HEADERS | |||
|             microprofile.h | ||||
|             microprofileui.h | ||||
|             platform.h | ||||
|             profiler.h | ||||
|             profiler_reporting.h | ||||
|             scm_rev.h | ||||
|             scope_exit.h | ||||
|  |  | |||
|  | @ -13,4 +13,7 @@ | |||
| #define MICROPROFILE_HELP_ALT "Right-Click" | ||||
| #define MICROPROFILE_HELP_MOD "Ctrl" | ||||
| 
 | ||||
| // This isn't included by microprofileui.h :(
 | ||||
| #include <cstdlib> // For std::abs | ||||
| 
 | ||||
| #include <microprofileui.h> | ||||
|  |  | |||
|  | @ -7,71 +7,16 @@ | |||
| #include <vector> | ||||
| 
 | ||||
| #include "common/assert.h" | ||||
| #include "common/profiler.h" | ||||
| #include "common/profiler_reporting.h" | ||||
| #include "common/synchronized_wrapper.h" | ||||
| 
 | ||||
| #if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013.
 | ||||
|     #define WIN32_LEAN_AND_MEAN | ||||
|     #include <Windows.h> // For QueryPerformanceCounter/Frequency
 | ||||
| #endif | ||||
| 
 | ||||
| namespace Common { | ||||
| namespace Profiling { | ||||
| 
 | ||||
| #if ENABLE_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) { | ||||
| 
 | ||||
|     ProfilingManager& manager = GetProfilingManager(); | ||||
|     category_id = manager.RegisterTimingCategory(this, name); | ||||
|     if (parent != nullptr) | ||||
|         manager.SetTimingCategoryParent(category_id, parent->category_id); | ||||
| } | ||||
| 
 | ||||
| ProfilingManager::ProfilingManager() | ||||
|         : last_frame_end(Clock::now()), this_frame_start(Clock::now()) { | ||||
| } | ||||
| 
 | ||||
| unsigned int ProfilingManager::RegisterTimingCategory(TimingCategory* category, const char* name) { | ||||
|     TimingCategoryInfo info; | ||||
|     info.category = category; | ||||
|     info.name = name; | ||||
|     info.parent = TimingCategoryInfo::NO_PARENT; | ||||
| 
 | ||||
|     unsigned int id = (unsigned int)timing_categories.size(); | ||||
|     timing_categories.push_back(std::move(info)); | ||||
| 
 | ||||
|     return id; | ||||
| } | ||||
| 
 | ||||
| void ProfilingManager::SetTimingCategoryParent(unsigned int category, unsigned int parent) { | ||||
|     ASSERT(category < timing_categories.size()); | ||||
|     ASSERT(parent < timing_categories.size()); | ||||
| 
 | ||||
|     timing_categories[category].parent = parent; | ||||
| } | ||||
| 
 | ||||
| void ProfilingManager::BeginFrame() { | ||||
|     this_frame_start = Clock::now(); | ||||
| } | ||||
|  | @ -82,11 +27,6 @@ void ProfilingManager::FinishFrame() { | |||
|     results.interframe_time = now - last_frame_end; | ||||
|     results.frame_time = now - this_frame_start; | ||||
| 
 | ||||
|     results.time_per_category.resize(timing_categories.size()); | ||||
|     for (size_t i = 0; i < timing_categories.size(); ++i) { | ||||
|         results.time_per_category[i] = timing_categories[i].category->GetAccumulatedTime(); | ||||
|     } | ||||
| 
 | ||||
|     last_frame_end = now; | ||||
| } | ||||
| 
 | ||||
|  | @ -100,26 +40,9 @@ void TimingResultsAggregator::Clear() { | |||
|     window_size = cursor = 0; | ||||
| } | ||||
| 
 | ||||
| void TimingResultsAggregator::SetNumberOfCategories(size_t n) { | ||||
|     size_t old_size = times_per_category.size(); | ||||
|     if (n == old_size) | ||||
|         return; | ||||
| 
 | ||||
|     times_per_category.resize(n); | ||||
| 
 | ||||
|     for (size_t i = old_size; i < n; ++i) { | ||||
|         times_per_category[i].resize(max_window_size, Duration::zero()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void TimingResultsAggregator::AddFrame(const ProfilingFrameResult& frame_result) { | ||||
|     SetNumberOfCategories(frame_result.time_per_category.size()); | ||||
| 
 | ||||
|     interframe_times[cursor] = frame_result.interframe_time; | ||||
|     frame_times[cursor] = frame_result.frame_time; | ||||
|     for (size_t i = 0; i < frame_result.time_per_category.size(); ++i) { | ||||
|         times_per_category[i][cursor] = frame_result.time_per_category[i]; | ||||
|     } | ||||
| 
 | ||||
|     ++cursor; | ||||
|     if (cursor == max_window_size) | ||||
|  | @ -162,11 +85,6 @@ AggregatedFrameResult TimingResultsAggregator::GetAggregatedResults() const { | |||
|         result.fps = 0.0f; | ||||
|     } | ||||
| 
 | ||||
|     result.time_per_category.resize(times_per_category.size()); | ||||
|     for (size_t i = 0; i < times_per_category.size(); ++i) { | ||||
|         result.time_per_category[i] = AggregateField(times_per_category[i], window_size); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  | @ -4,22 +4,17 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <cstddef> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/profiler.h" | ||||
| #include "common/synchronized_wrapper.h" | ||||
| 
 | ||||
| namespace Common { | ||||
| namespace Profiling { | ||||
| 
 | ||||
| struct TimingCategoryInfo { | ||||
|     static const unsigned int NO_PARENT = -1; | ||||
| 
 | ||||
|     TimingCategory* category; | ||||
|     const char* name; | ||||
|     unsigned int parent; | ||||
| }; | ||||
| using Clock = std::chrono::high_resolution_clock; | ||||
| using Duration = Clock::duration; | ||||
| 
 | ||||
| struct ProfilingFrameResult { | ||||
|     /// Time since the last delivered frame
 | ||||
|  | @ -27,22 +22,12 @@ struct ProfilingFrameResult { | |||
| 
 | ||||
|     /// Time spent processing a frame, excluding VSync
 | ||||
|     Duration frame_time; | ||||
| 
 | ||||
|     /// Total amount of time spent inside each category in this frame. Indexed by the category id
 | ||||
|     std::vector<Duration> time_per_category; | ||||
| }; | ||||
| 
 | ||||
| class ProfilingManager final { | ||||
| public: | ||||
|     ProfilingManager(); | ||||
| 
 | ||||
|     unsigned int RegisterTimingCategory(TimingCategory* category, const char* name); | ||||
|     void SetTimingCategoryParent(unsigned int category, unsigned int parent); | ||||
| 
 | ||||
|     const std::vector<TimingCategoryInfo>& GetTimingCategoriesInfo() const { | ||||
|         return timing_categories; | ||||
|     } | ||||
| 
 | ||||
|     /// This should be called after swapping screen buffers.
 | ||||
|     void BeginFrame(); | ||||
|     /// This should be called before swapping screen buffers.
 | ||||
|  | @ -54,7 +39,6 @@ public: | |||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::vector<TimingCategoryInfo> timing_categories; | ||||
|     Clock::time_point last_frame_end; | ||||
|     Clock::time_point this_frame_start; | ||||
| 
 | ||||
|  | @ -73,9 +57,6 @@ struct AggregatedFrameResult { | |||
|     AggregatedDuration frame_time; | ||||
| 
 | ||||
|     float fps; | ||||
| 
 | ||||
|     /// Total amount of time spent inside each category in this frame. Indexed by the category id
 | ||||
|     std::vector<AggregatedDuration> time_per_category; | ||||
| }; | ||||
| 
 | ||||
| class TimingResultsAggregator final { | ||||
|  | @ -83,7 +64,6 @@ public: | |||
|     TimingResultsAggregator(size_t window_size); | ||||
| 
 | ||||
|     void Clear(); | ||||
|     void SetNumberOfCategories(size_t n); | ||||
| 
 | ||||
|     void AddFrame(const ProfilingFrameResult& frame_result); | ||||
| 
 | ||||
|  | @ -95,7 +75,6 @@ public: | |||
| 
 | ||||
|     std::vector<Duration> interframe_times; | ||||
|     std::vector<Duration> frame_times; | ||||
|     std::vector<std::vector<Duration>> times_per_category; | ||||
| }; | ||||
| 
 | ||||
| ProfilingManager& GetProfilingManager(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue