Cog/Frameworks/OpenMPT/OpenMPT/common/Profiler.cpp
Christopher Snowhill da1973bcd9 Build libOpenMPT from source once again
Bundle libOpenMPT as a dynamic framework, which should be safe once
again, now that there is only one version to bundle. Also, now it is
using the versions of libvorbisfile and libmpg123 that are bundled with
the player, instead of compiling minimp3 and stbvorbis.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2022-06-30 22:56:52 -07:00

221 lines
3.6 KiB
C++

/*
* Profiler.cpp
* ------------
* Purpose: Performance measuring
* Notes : (currently none)
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#include "stdafx.h"
#include "Profiler.h"
OPENMPT_NAMESPACE_BEGIN
#ifdef USE_PROFILER
class Statistics
{
public:
Profile &profile;
Profile::Data data;
double usage;
Statistics(Profile &p) : profile(p)
{
usage = 0.0;
Update();
}
void Update()
{
data = profile.GetAndResetData();
uint64 now = profile.GetTime();
uint64 timewindow = now - data.Start;
if(data.Calls > 0 && timewindow > 0)
{
usage = (double)data.Sum / (double)timewindow;
} else
{
usage = 0.0;
}
}
};
struct ProfileBlock
{
class Profile * profile;
const char * name;
class Statistics * stats;
};
static constexpr std::size_t MAX_PROFILES = 1024;
static ProfileBlock Profiles[ MAX_PROFILES ];
static std::size_t NextProfile = 0;
static void RegisterProfile(Profile *newprofile)
{
if(NextProfile < MAX_PROFILES)
{
Profiles[NextProfile].profile = newprofile;
Profiles[NextProfile].stats = 0;
NextProfile++;
}
}
static void UnregisterProfile(Profile *oldprofile)
{
for(std::size_t i=0; i<NextProfile; i++) {
if(Profiles[i].profile == oldprofile) {
Profiles[i].profile = 0;
delete Profiles[i].stats;
Profiles[i].stats = 0;
}
}
}
void Profiler::Update()
{
for(std::size_t i=0; i<NextProfile; i++)
{
if(!Profiles[i].stats)
{
Profiles[i].stats = new Statistics(*Profiles[i].profile);
} else
{
Profiles[i].stats->Update();
}
}
}
std::string Profiler::DumpProfiles()
{
std::string ret;
for(std::size_t i=0; i<NextProfile; i++)
{
if(Profiles[i].stats)
{
Statistics &stats = *Profiles[i].stats;
std::string cat;
switch(stats.profile.Category)
{
case Profiler::GUI: cat = "GUI"; break;
case Profiler::Audio: cat = "Audio"; break;
case Profiler::Notify: cat = "Notify"; break;
}
ret += cat + " " + std::string(stats.profile.Name) + ": " + mpt::afmt::right(6, mpt::afmt::fix(stats.usage * 100.0, 3)) + "%\r\n";
}
}
ret += "\r\n";
return ret;
}
std::vector<double> Profiler::DumpCategories()
{
std::vector<double> ret;
ret.resize(Profiler::CategoriesCount);
for(std::size_t i=0; i<NextProfile; i++)
{
if(Profiles[i].stats)
{
ret[Profiles[i].profile->Category] += Profiles[i].stats->usage;
}
}
return ret;
}
uint64 Profile::GetTime() const
{
LARGE_INTEGER ret;
ret.QuadPart = 0;
QueryPerformanceCounter(&ret);
return ret.QuadPart;
}
uint64 Profile::GetFrequency() const
{
LARGE_INTEGER ret;
ret.QuadPart = 0;
QueryPerformanceFrequency(&ret);
return ret.QuadPart;
}
Profile::Profile(Profiler::Category category, const char *name) : Category(category), Name(name)
{
data.Calls = 0;
data.Sum = 0;
data.Overhead = 0;
data.Start = GetTime();
EnterTime = 0;
RegisterProfile(this);
}
Profile::~Profile()
{
UnregisterProfile(this);
}
Profile::Data Profile::GetAndResetData()
{
Profile::Data ret;
datamutex.lock();
ret = data;
data.Calls = 0;
data.Sum = 0;
data.Overhead = 0;
data.Start = GetTime();
datamutex.unlock();
return ret;
}
void Profile::Reset()
{
datamutex.lock();
data.Calls = 0;
data.Sum = 0;
data.Overhead = 0;
data.Start = GetTime();
datamutex.unlock();
}
void Profile::Enter()
{
EnterTime = GetTime();
}
void Profile::Leave()
{
uint64 LeaveTime = GetTime();
datamutex.lock();
data.Calls += 1;
data.Sum += LeaveTime - EnterTime;
datamutex.unlock();
}
#else // !USE_PROFILER
MPT_MSVC_WORKAROUND_LNK4221(Profiler)
#endif // USE_PROFILER
OPENMPT_NAMESPACE_END