2014-11-19 11:57:12 -07:00
|
|
|
// Copyright 2014 Dolphin Emulator Project
|
2021-07-04 19:22:19 -06:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2014-11-19 11:57:12 -07:00
|
|
|
|
2021-12-09 19:22:16 -07:00
|
|
|
#include "Common/Profiler.h"
|
|
|
|
|
2017-01-23 00:08:45 -07:00
|
|
|
#include <algorithm>
|
2014-11-19 11:57:12 -07:00
|
|
|
#include <cmath>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <ios>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
#include "Common/Timer.h"
|
|
|
|
|
2015-08-20 03:41:49 -06:00
|
|
|
namespace Common
|
|
|
|
{
|
2014-12-03 20:54:54 -07:00
|
|
|
static const u32 PROFILER_FIELD_LENGTH = 8;
|
|
|
|
static const u32 PROFILER_FIELD_LENGTH_FP = PROFILER_FIELD_LENGTH + 3;
|
|
|
|
static const int PROFILER_LAZY_DELAY = 60; // in frames
|
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
std::list<Profiler*> Profiler::s_all_profilers;
|
2015-08-20 03:41:49 -06:00
|
|
|
std::mutex Profiler::s_mutex;
|
2014-11-19 11:57:12 -07:00
|
|
|
u32 Profiler::s_max_length = 0;
|
|
|
|
u64 Profiler::s_frame_time;
|
|
|
|
u64 Profiler::s_usecs_frame;
|
|
|
|
|
2019-03-02 11:42:25 -07:00
|
|
|
std::string Profiler::s_lazy_result;
|
2014-11-19 11:57:12 -07:00
|
|
|
int Profiler::s_lazy_delay = 0;
|
|
|
|
|
|
|
|
Profiler::Profiler(const std::string& name)
|
2017-06-07 05:16:02 -06:00
|
|
|
: m_name(name), m_usecs(0), m_usecs_min(UINT64_MAX), m_usecs_max(0), m_usecs_quad(0),
|
|
|
|
m_calls(0), m_depth(0)
|
2014-11-19 11:57:12 -07:00
|
|
|
{
|
|
|
|
m_time = Common::Timer::GetTimeUs();
|
|
|
|
s_max_length = std::max<u32>(s_max_length, u32(m_name.length()));
|
|
|
|
|
2015-08-20 03:41:49 -06:00
|
|
|
std::lock_guard<std::mutex> lk(s_mutex);
|
2014-11-19 11:57:12 -07:00
|
|
|
s_all_profilers.push_back(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
Profiler::~Profiler()
|
|
|
|
{
|
2015-08-20 03:41:49 -06:00
|
|
|
std::lock_guard<std::mutex> lk(s_mutex);
|
2014-11-19 11:57:12 -07:00
|
|
|
s_all_profilers.remove(this);
|
|
|
|
}
|
|
|
|
|
2015-08-20 03:41:49 -06:00
|
|
|
bool Profiler::operator<(const Profiler& b) const
|
|
|
|
{
|
|
|
|
return m_usecs < b.m_usecs;
|
|
|
|
}
|
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
std::string Profiler::ToString()
|
|
|
|
{
|
|
|
|
if (s_lazy_delay > 0)
|
|
|
|
{
|
|
|
|
s_lazy_delay--;
|
|
|
|
return s_lazy_result;
|
|
|
|
}
|
|
|
|
s_lazy_delay = PROFILER_LAZY_DELAY - 1;
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
// don't write anything if no profilation is enabled
|
2015-08-20 03:41:49 -06:00
|
|
|
std::lock_guard<std::mutex> lk(s_mutex);
|
2014-11-19 11:57:12 -07:00
|
|
|
if (s_all_profilers.empty())
|
|
|
|
return "";
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
u64 end = Common::Timer::GetTimeUs();
|
|
|
|
s_usecs_frame = end - s_frame_time;
|
|
|
|
s_frame_time = end;
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
std::ostringstream buffer;
|
|
|
|
buffer << std::setw(s_max_length) << std::left << ""
|
|
|
|
<< " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "calls"
|
|
|
|
<< " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "sum"
|
|
|
|
<< " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "rel"
|
|
|
|
<< " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "min"
|
|
|
|
<< " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "avg"
|
|
|
|
<< " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << "stdev"
|
|
|
|
<< " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << "max"
|
2016-06-24 02:43:46 -06:00
|
|
|
<< " ";
|
2014-11-19 11:57:12 -07:00
|
|
|
buffer << "/ usec" << std::endl;
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2015-08-20 03:41:49 -06:00
|
|
|
s_all_profilers.sort([](Profiler* a, Profiler* b) { return *b < *a; });
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
for (auto profiler : s_all_profilers)
|
|
|
|
{
|
|
|
|
buffer << profiler->Read() << std::endl;
|
|
|
|
}
|
|
|
|
s_lazy_result = buffer.str();
|
|
|
|
return s_lazy_result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::Start()
|
|
|
|
{
|
|
|
|
if (!m_depth++)
|
|
|
|
{
|
|
|
|
m_time = Common::Timer::GetTimeUs();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Profiler::Stop()
|
|
|
|
{
|
|
|
|
if (!--m_depth)
|
|
|
|
{
|
|
|
|
u64 end = Common::Timer::GetTimeUs();
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
u64 diff = end - m_time;
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
m_usecs += diff;
|
|
|
|
m_usecs_min = std::min(m_usecs_min, diff);
|
|
|
|
m_usecs_max = std::max(m_usecs_max, diff);
|
|
|
|
m_usecs_quad += diff * diff;
|
|
|
|
m_calls++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Profiler::Read()
|
|
|
|
{
|
|
|
|
double avg = 0;
|
|
|
|
double stdev = 0;
|
|
|
|
double time_rel = 0;
|
|
|
|
if (m_calls)
|
|
|
|
{
|
|
|
|
avg = double(m_usecs) / m_calls;
|
|
|
|
stdev = std::sqrt(double(m_usecs_quad) / m_calls - avg * avg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_usecs_min = 0;
|
|
|
|
}
|
|
|
|
if (s_usecs_frame)
|
|
|
|
{
|
|
|
|
time_rel = double(m_usecs) * 100 / s_usecs_frame;
|
|
|
|
}
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
std::ostringstream buffer;
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
buffer << std::setw(s_max_length) << std::left << m_name << " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_calls << " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs << " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << time_rel << " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs_min << " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << std::fixed << std::setprecision(2)
|
|
|
|
<< avg << " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH_FP) << std::right << std::fixed << std::setprecision(2)
|
|
|
|
<< stdev << " ";
|
|
|
|
buffer << std::setw(PROFILER_FIELD_LENGTH) << std::right << m_usecs_max;
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
m_usecs = 0;
|
2017-06-07 05:16:02 -06:00
|
|
|
m_usecs_min = UINT64_MAX;
|
2014-11-19 11:57:12 -07:00
|
|
|
m_usecs_max = 0;
|
|
|
|
m_usecs_quad = 0;
|
|
|
|
m_calls = 0;
|
2016-06-24 02:43:46 -06:00
|
|
|
|
2014-11-19 11:57:12 -07:00
|
|
|
return buffer.str();
|
|
|
|
}
|
2019-05-05 17:48:12 -06:00
|
|
|
} // namespace Common
|