mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-21 04:39:45 +00:00
Hoist MOULOpenSourceClientPlugin/Plasma20/* to top level
to match H'uru layout and make patching/cherry-picking easier.
This commit is contained in:
535
Sources/Plasma/NucleusLib/inc/plProfileManager.cpp
Normal file
535
Sources/Plasma/NucleusLib/inc/plProfileManager.cpp
Normal file
@ -0,0 +1,535 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include "plProfileManager.h"
|
||||
#include "plProfile.h"
|
||||
#include "hsTimer.h"
|
||||
|
||||
#include "hsUtils.h"
|
||||
|
||||
static UInt32 gCyclesPerMS = 0;
|
||||
|
||||
#ifdef HS_BUILD_FOR_WIN32
|
||||
#define USE_FAST_TIMER
|
||||
#endif
|
||||
|
||||
#ifdef USE_FAST_TIMER
|
||||
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4035) // disable no return value warning
|
||||
|
||||
__forceinline UInt32 GetPentiumCounter()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
xor eax,eax // VC won't realize that eax is modified w/out this
|
||||
// instruction to modify the val.
|
||||
// Problem shows up in release mode builds
|
||||
_emit 0x0F // Pentium high-freq counter to edx;eax
|
||||
_emit 0x31 // only care about low 32 bits in eax
|
||||
|
||||
xor edx,edx // so VC gets that edx is modified
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning (pop)
|
||||
|
||||
#include "hsWindows.h"
|
||||
|
||||
static UInt32 GetProcSpeed()
|
||||
{
|
||||
const char* keypath[] =
|
||||
{
|
||||
"HARDWARE",
|
||||
"DESCRIPTION",
|
||||
"System",
|
||||
"CentralProcessor",
|
||||
"0"
|
||||
};
|
||||
|
||||
HKEY hKey = HKEY_LOCAL_MACHINE;
|
||||
|
||||
int numKeys = sizeof(keypath) / sizeof(char*);
|
||||
for (int i = 0; i < numKeys; i++)
|
||||
{
|
||||
HKEY thisKey = NULL;
|
||||
hsBool success = (RegOpenKeyEx(hKey, keypath[i], 0, KEY_READ, &thisKey) == ERROR_SUCCESS);
|
||||
|
||||
RegCloseKey(hKey);
|
||||
hKey = thisKey;
|
||||
|
||||
if (!success)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD value=0, size=sizeof(DWORD);
|
||||
hsBool success = (RegQueryValueEx(hKey, "~MHz", 0, NULL, (BYTE*)&value, &size) == ERROR_SUCCESS);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
return value*1000000;
|
||||
}
|
||||
|
||||
UInt32 GetProcSpeedAlt()
|
||||
{
|
||||
const UInt32 kSamplePeriodMS = 250;
|
||||
|
||||
// Raise priority to avoid interference from other threads.
|
||||
int priority = GetThreadPriority(GetCurrentThread());
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||
|
||||
UInt32 startTicks, endTicks;
|
||||
UInt64 pcStart, pcEnd;
|
||||
|
||||
// Count number of processor cycles inside the specified interval
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&pcStart);
|
||||
startTicks = plProfileManager::GetTime();
|
||||
Sleep(kSamplePeriodMS);
|
||||
endTicks = plProfileManager::GetTime();
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&pcEnd);
|
||||
|
||||
// Restore thread priority.
|
||||
SetThreadPriority(GetCurrentThread(), priority);
|
||||
|
||||
// Calculate Rdtsc/PerformanceCounter ratio;
|
||||
UInt32 numTicks = endTicks - startTicks;
|
||||
UInt64 pcDiff = pcEnd - pcStart;
|
||||
|
||||
double ratio = double(numTicks) / double(pcDiff);
|
||||
UInt64 pcFreq;
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&pcFreq);
|
||||
|
||||
// Calculate CPU frequency.
|
||||
UInt64 cpuFreq = UInt64(pcFreq * ratio);
|
||||
|
||||
return (UInt32)cpuFreq;
|
||||
}
|
||||
|
||||
#define GetProfileTicks() GetPentiumCounter()
|
||||
|
||||
#else
|
||||
|
||||
#define GetProfileTicks() hsTimer::GetPrecTickCount()
|
||||
|
||||
#endif // USE_FAST_TIMER
|
||||
|
||||
#define TicksToMSec(t) (float(t) / float(gCyclesPerMS))
|
||||
#define MSecToTicks(t) (float(t) * float(gCyclesPerMS))
|
||||
|
||||
plProfileManager::plProfileManager() : fLastAvgTime(0), fProcessorSpeed(0)
|
||||
{
|
||||
#ifdef USE_FAST_TIMER
|
||||
fProcessorSpeed = GetProcSpeed();
|
||||
// Registry stuff only works on NT OS's, have to calc it otherwise
|
||||
if (fProcessorSpeed == 0)
|
||||
fProcessorSpeed = GetProcSpeedAlt();
|
||||
|
||||
gCyclesPerMS = fProcessorSpeed / 1000;
|
||||
#else
|
||||
gCyclesPerMS = hsTimer::GetPrecTicksPerSec() / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
plProfileManager::~plProfileManager()
|
||||
{
|
||||
}
|
||||
|
||||
plProfileManager& plProfileManager::Instance()
|
||||
{
|
||||
static plProfileManager theInstance;
|
||||
return theInstance;
|
||||
}
|
||||
|
||||
void plProfileManager::AddTimer(plProfileVar* var)
|
||||
{
|
||||
fVars.push_back(var);
|
||||
}
|
||||
|
||||
static UInt32 kAvgMilliseconds = 1000;
|
||||
|
||||
void plProfileManager::SetAvgTime(UInt32 avgMS)
|
||||
{
|
||||
kAvgMilliseconds = avgMS;
|
||||
}
|
||||
|
||||
static plProfileVar gVarEFPS("EFPS", "General", plProfileVar::kDisplayTime | plProfileVar::kDisplayFPS);
|
||||
|
||||
void plProfileManager::BeginFrame()
|
||||
{
|
||||
for (int i = 0; i < fVars.size(); i++)
|
||||
{
|
||||
fVars[i]->BeginFrame();
|
||||
if (fVars[i]->GetLaps())
|
||||
fVars[i]->GetLaps()->BeginFrame();
|
||||
}
|
||||
|
||||
gVarEFPS.BeginTiming();
|
||||
}
|
||||
|
||||
void plProfileManager::EndFrame()
|
||||
{
|
||||
gVarEFPS.EndTiming();
|
||||
|
||||
hsBool updateAvgs = false;
|
||||
|
||||
// If enough time has passed, update the averages
|
||||
double curTime = hsTimer::GetMilliSeconds();
|
||||
if (curTime - fLastAvgTime > kAvgMilliseconds)
|
||||
{
|
||||
fLastAvgTime = curTime;
|
||||
updateAvgs = true;
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
//
|
||||
// Update all the variables
|
||||
//
|
||||
for (i = 0; i < fVars.size(); i++)
|
||||
{
|
||||
plProfileVar* var = fVars[i];
|
||||
|
||||
if (updateAvgs)
|
||||
{
|
||||
// Timers that reset at every BeginTiming() call don't want to average over frames
|
||||
if (!hsCheckBits(var->GetDisplayFlags(), plProfileBase::kDisplayResetEveryBegin))
|
||||
{
|
||||
var->UpdateAvg();
|
||||
if (var->GetLaps())
|
||||
var->GetLaps()->UpdateAvgs();
|
||||
}
|
||||
}
|
||||
|
||||
var->EndFrame();
|
||||
|
||||
if (var->GetLaps())
|
||||
var->GetLaps()->EndFrame();
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 plProfileManager::GetTime()
|
||||
{
|
||||
return GetProfileTicks();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plProfileBase::plProfileBase() :
|
||||
fName(nil),
|
||||
fDisplayFlags(0),
|
||||
fValue(0),
|
||||
fTimerSamples(0),
|
||||
fAvgCount(0),
|
||||
fAvgTotal(0),
|
||||
fLastAvg(0),
|
||||
fMax(0),
|
||||
fActive(false),
|
||||
fRunning(true)
|
||||
{
|
||||
}
|
||||
|
||||
plProfileBase::~plProfileBase()
|
||||
{
|
||||
}
|
||||
|
||||
void plProfileBase::BeginFrame()
|
||||
{
|
||||
if (!hsCheckBits(fDisplayFlags, kDisplayNoReset))
|
||||
fValue = 0;
|
||||
fTimerSamples = 0;
|
||||
}
|
||||
|
||||
void plProfileBase::EndFrame()
|
||||
{
|
||||
fAvgCount++;
|
||||
fAvgTotal += fValue;
|
||||
fMax = hsMaximum(fMax, fValue);
|
||||
}
|
||||
|
||||
void plProfileBase::UpdateAvg()
|
||||
{
|
||||
if (fAvgCount > 0)
|
||||
{
|
||||
fLastAvg = (UInt32)(fAvgTotal / fAvgCount);
|
||||
fAvgCount = 0;
|
||||
fAvgTotal = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 plProfileBase::GetValue()
|
||||
{
|
||||
if (hsCheckBits(fDisplayFlags, kDisplayTime))
|
||||
return (UInt32)TicksToMSec(fValue);
|
||||
else
|
||||
return fValue;
|
||||
}
|
||||
|
||||
// Stolen from plMemTracker.cpp
|
||||
static const char *insertCommas(unsigned int value)
|
||||
{
|
||||
static char str[30];
|
||||
memset(str, 0, sizeof(str));
|
||||
|
||||
sprintf(str, "%u", value);
|
||||
if (strlen(str) > 3)
|
||||
{
|
||||
memmove(&str[strlen(str)-3], &str[strlen(str)-4], 4);
|
||||
str[strlen(str) - 4] = ',';
|
||||
}
|
||||
if (strlen(str) > 7)
|
||||
{
|
||||
memmove(&str[strlen(str)-7], &str[strlen(str)-8], 8);
|
||||
str[strlen(str) - 8] = ',';
|
||||
}
|
||||
if (strlen(str) > 11)
|
||||
{
|
||||
memmove(&str[strlen(str)-11], &str[strlen(str)-12], 12);
|
||||
str[strlen(str) - 12] = ',';
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void plProfileBase::IPrintValue(UInt32 value, char* buf, hsBool printType)
|
||||
{
|
||||
if (hsCheckBits(fDisplayFlags, kDisplayCount))
|
||||
{
|
||||
if (printType)
|
||||
{
|
||||
const char* valueStr = insertCommas(value);
|
||||
strcpy(buf, valueStr);
|
||||
}
|
||||
else
|
||||
sprintf(buf, "%u", value);
|
||||
}
|
||||
else if (hsCheckBits(fDisplayFlags, kDisplayFPS))
|
||||
{
|
||||
sprintf(buf, "%.1f", 1000.0f / TicksToMSec(value));
|
||||
}
|
||||
else if (hsCheckBits(fDisplayFlags, kDisplayTime))
|
||||
{
|
||||
sprintf(buf, "%.1f", TicksToMSec(value));
|
||||
if (printType)
|
||||
strcat(buf, " ms");
|
||||
}
|
||||
else if (hsCheckBits(fDisplayFlags, kDisplayMem))
|
||||
{
|
||||
if (printType)
|
||||
{
|
||||
if (value > (1024*1000))
|
||||
sprintf(buf, "%.1f MB", float(value) / (1024.f * 1024.f));
|
||||
else if (value > 1024)
|
||||
sprintf(buf, "%d KB", value / 1024);
|
||||
else
|
||||
sprintf(buf, "%d b", value);
|
||||
}
|
||||
else
|
||||
sprintf(buf, "%u", value);
|
||||
}
|
||||
}
|
||||
|
||||
void plProfileBase::PrintValue(char* buf, hsBool printType)
|
||||
{
|
||||
IPrintValue(fValue, buf, printType);
|
||||
}
|
||||
|
||||
void plProfileBase::PrintAvg(char* buf, hsBool printType)
|
||||
{
|
||||
IPrintValue(fLastAvg, buf, printType);
|
||||
}
|
||||
|
||||
void plProfileBase::PrintMax(char* buf, hsBool printType)
|
||||
{
|
||||
IPrintValue(fMax, buf, printType);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
plProfileLaps::LapInfo* plProfileLaps::IFindLap(const char* lapName)
|
||||
{
|
||||
static int lastSearch = 0;
|
||||
|
||||
int i;
|
||||
for (i = lastSearch; i < fLapTimes.size(); i++)
|
||||
{
|
||||
if(fLapTimes[i].GetName() == lapName)
|
||||
{
|
||||
lastSearch = i;
|
||||
return &fLapTimes[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(lastSearch > fLapTimes.size()) lastSearch = fLapTimes.size();
|
||||
for (i = 0; i < lastSearch; i++)
|
||||
{
|
||||
if(fLapTimes[i].GetName() == lapName)
|
||||
{
|
||||
lastSearch = i;
|
||||
return &fLapTimes[i];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
void plProfileLaps::BeginLap(UInt32 curValue, const char* name)
|
||||
{
|
||||
LapInfo* lap = IFindLap(name);
|
||||
if (!lap)
|
||||
{
|
||||
// Technically we shouldn't hold on to this pointer. However, I think
|
||||
// it will be ok in all cases, so I'll wait until this blows up
|
||||
LapInfo info(name);
|
||||
fLapTimes.push_back(info);
|
||||
lap = &(*(fLapTimes.end()-1));
|
||||
}
|
||||
|
||||
lap->fUsedThisFrame = true;
|
||||
lap->BeginTiming(curValue);
|
||||
}
|
||||
|
||||
void plProfileLaps::EndLap(UInt32 curValue, const char* name)
|
||||
{
|
||||
LapInfo* lap = IFindLap(name);
|
||||
|
||||
// There's a lap timer around the input code. You display it with "Stats.ShowLaps Update Input"
|
||||
// Since the command activates the timer INSIDE the lap, the first call to this function fails to
|
||||
// find it. (the timer wasn't active when BeginLap was called)
|
||||
if (lap)
|
||||
lap->EndTiming(curValue);
|
||||
}
|
||||
|
||||
void plProfileLaps::BeginFrame()
|
||||
{
|
||||
for (int i = 0; i < fLapTimes.size(); i++)
|
||||
{
|
||||
fLapTimes[i].BeginFrame();
|
||||
fLapTimes[i].fUsedThisFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
void plProfileLaps::EndFrame()
|
||||
{
|
||||
for (int i = 0; i < fLapTimes.size(); i++)
|
||||
{
|
||||
fLapTimes[i].EndFrame();
|
||||
if (!fLapTimes[i].fUsedThisFrame)
|
||||
{
|
||||
char buf[200];
|
||||
sprintf(buf, "Dropping unused lap %s", fLapTimes[i].GetName());
|
||||
hsStatusMessage(buf);
|
||||
fLapTimes.erase(fLapTimes.begin()+i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plProfileLaps::UpdateAvgs()
|
||||
{
|
||||
for (int i = 0; i < fLapTimes.size(); i++)
|
||||
fLapTimes[i].UpdateAvg();
|
||||
}
|
||||
|
||||
int plProfileLaps::GetNumLaps()
|
||||
{
|
||||
// std::sort(fLapTimes.begin(), fLapTimes.end());
|
||||
return fLapTimes.size();
|
||||
}
|
||||
|
||||
plProfileBase* plProfileLaps::GetLap(int i)
|
||||
{
|
||||
return &fLapTimes[i];
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
plProfileVar::plProfileVar(const char *name, const char* group, UInt8 flags) :
|
||||
fGroup(group),
|
||||
fLaps(nil)
|
||||
{
|
||||
fName = name;
|
||||
fDisplayFlags = flags;
|
||||
plProfileManager::Instance().AddTimer(this);
|
||||
fLapsActive = 0;
|
||||
}
|
||||
|
||||
plProfileVar::~plProfileVar()
|
||||
{
|
||||
delete fLaps;
|
||||
}
|
||||
|
||||
void plProfileVar::IBeginLap(const char* lapName)
|
||||
{
|
||||
if (!fLaps)
|
||||
fLaps = TRACKED_NEW plProfileLaps;
|
||||
fDisplayFlags |= kDisplayLaps;
|
||||
if(fLapsActive)
|
||||
fLaps->BeginLap(fValue, lapName);
|
||||
BeginTiming();
|
||||
}
|
||||
|
||||
void plProfileVar::IEndLap(const char* lapName)
|
||||
{
|
||||
EndTiming();
|
||||
if(fLapsActive)
|
||||
fLaps->EndLap(fValue, lapName);
|
||||
}
|
||||
|
||||
void plProfileVar::IBeginTiming()
|
||||
{
|
||||
if( hsCheckBits( fDisplayFlags, kDisplayResetEveryBegin ) )
|
||||
fValue = 0;
|
||||
|
||||
fValue -= GetProfileTicks();
|
||||
}
|
||||
|
||||
void plProfileVar::IEndTiming()
|
||||
{
|
||||
fValue += GetProfileTicks();
|
||||
|
||||
fTimerSamples++;
|
||||
|
||||
// If we reset every BeginTiming(), then we want to average all the timing calls
|
||||
// independent of framerate
|
||||
if (hsCheckBits(fDisplayFlags, plProfileBase::kDisplayResetEveryBegin))
|
||||
UpdateAvg();
|
||||
}
|
Reference in New Issue
Block a user