/*
** Command & Conquer Generals Zero Hour(tm)
** Copyright 2025 Electronic Arts 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 .
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/profile/profile_highlevel.cpp $
// $Author: mhoffe $
// $Revision: #2 $
// $DateTime: 2003/08/14 13:43:29 $
//
// ©2003 Electronic Arts
//
// High level profiling
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include
#include
// our own fast critical section
static ProfileFastCS cs;
//////////////////////////////////////////////////////////////////////////////
// ProfileHighLevel::Id
void ProfileHighLevel::Id::Increment(double add)
{
if (m_idPtr)
m_idPtr->Increment(add);
}
void ProfileHighLevel::Id::SetMax(double max)
{
if (m_idPtr)
m_idPtr->Maximum(max);
}
const char *ProfileHighLevel::Id::GetName(void) const
{
return m_idPtr?m_idPtr->GetName():NULL;
}
const char *ProfileHighLevel::Id::GetDescr(void) const
{
return m_idPtr?m_idPtr->GetDescr():NULL;
}
const char *ProfileHighLevel::Id::GetUnit(void) const
{
return m_idPtr?m_idPtr->GetUnit():NULL;
}
const char *ProfileHighLevel::Id::GetCurrentValue(void) const
{
return m_idPtr?m_idPtr->AsString(m_idPtr->GetCurrentValue()):NULL;
}
const char *ProfileHighLevel::Id::GetValue(unsigned frame) const
{
double v;
if (!m_idPtr||!m_idPtr->GetFrameValue(frame,v))
return NULL;
return m_idPtr->AsString(v);
}
const char *ProfileHighLevel::Id::GetTotalValue(void) const
{
return m_idPtr?m_idPtr->AsString(m_idPtr->GetTotalValue()):NULL;
}
//////////////////////////////////////////////////////////////////////////////
// ProfileHighLevel::Block
ProfileHighLevel::Block::Block(const char *name)
{
DFAIL_IF(!name) return;
m_idTime=AddProfile(name,NULL,"msec",6,-4);
char help[256];
strncpy(help,name,sizeof(help));
help[sizeof(help)-1-2]=0;
strcat(help,".c");
AddProfile(help,NULL,"calls",6,0).Increment();
ProfileGetTime(m_start);
}
ProfileHighLevel::Block::~Block()
{
_int64 end;
ProfileGetTime(end);
end-=m_start;
m_idTime.Increment(double(end)/(double)Profile::GetClockCyclesPerSecond());
}
//////////////////////////////////////////////////////////////////////////////
// ProfileId
// profile ID stuff
ProfileId *ProfileId::first;
int ProfileId::curFrame;
unsigned ProfileId::frameRecordMask;
char ProfileId::stringBuf[ProfileId::STRING_BUFFER_SIZE];
unsigned ProfileId::stringBufUnused;
ProfileId::ProfileId(const char *name, const char *descr, const char *unit, int precision, int exp10)
{
m_next=first; first=this;
m_name=(char *)ProfileAllocMemory(strlen(name)+1);
strcpy(m_name,name);
if (descr)
{
m_descr=(char *)ProfileAllocMemory(strlen(descr)+1);
strcpy(m_descr,descr);
}
else
m_descr=NULL;
if (unit)
{
m_unit=(char *)ProfileAllocMemory(strlen(unit)+1);
strcpy(m_unit,unit);
}
else
m_unit=NULL;
m_precision=precision;
m_exp10=exp10;
m_curVal=m_totalVal=0.;
m_recFrameVal=NULL;
m_firstFrame=curFrame;
m_valueMode=Unknown;
}
void ProfileId::Increment(double add)
{
DFAIL_IF(m_valueMode!=Unknown&&m_valueMode!=ModeIncrement)
return;
m_valueMode=ModeIncrement;
m_curVal+=add;
m_totalVal+=add;
if (frameRecordMask)
{
unsigned mask=frameRecordMask;
for (unsigned i=0;i>=1))
break;
}
}
}
void ProfileId::Maximum(double max)
{
DFAIL_IF(m_valueMode!=Unknown&&m_valueMode!=ModeMaximum)
return;
m_valueMode=ModeMaximum;
if (max>m_curVal)
m_curVal=max;
if (max>m_totalVal)
m_totalVal=max;
if (frameRecordMask)
{
unsigned mask=frameRecordMask;
for (unsigned i=0;im_frameVal[i])
m_frameVal[i]=max;
}
if (!(mask>>=1))
break;
}
}
}
const char *ProfileId::AsString(double v) const
{
char help1[10],help[40];
wsprintf(help1,"%%%i.lf",m_precision);
double mul=1.0;
int k;
for (k=m_exp10;k<0;k++) mul*=10.0;
for (;k>0;k--) mul/=10.0;
unsigned len=_snprintf(help,sizeof(help),help1,v*mul)+1;
ProfileFastCS::Lock lock(cs);
if (stringBufUnused+len>STRING_BUFFER_SIZE)
stringBufUnused=0;
char *ret=stringBuf+stringBufUnused;
memcpy(ret,help,len);
stringBufUnused+=len;
return ret;
}
int ProfileId::FrameStart(void)
{
ProfileFastCS::Lock lock(cs);
for (unsigned i=0;im_next)
p->m_frameVal[i]=0.;
frameRecordMask|=1<=MAX_FRAME_RECORDS)
return;
DFAIL_IF(!(frameRecordMask&(1<=curFrame)
return;
ProfileFastCS::Lock lock(cs);
frameRecordMask^=1<m_next)
{
p->m_recFrameVal=(double *)ProfileReAllocMemory(p->m_recFrameVal,sizeof(double)*(curFrame-p->m_firstFrame));
p->m_recFrameVal[curFrame-p->m_firstFrame-1]=p->m_frameVal[which];
}
}
else
{
// append data
for (ProfileId *p=first;p;p=p->m_next)
{
if (p->m_firstFrame>mixIndex)
continue;
double &val=p->m_recFrameVal[mixIndex-p->m_firstFrame];
switch(p->m_valueMode)
{
case ProfileId::Unknown:
break;
case ProfileId::ModeIncrement:
val+=p->m_frameVal[which];
break;
case ProfileId::ModeMaximum:
if (p->m_frameVal[which]>val)
val=p->m_frameVal[which];
break;
default:
DFAIL();
}
}
}
}
void ProfileId::Shutdown(void)
{
if (frameRecordMask)
{
for (unsigned i=0;iGetNext());
id.m_idPtr=cur;
return cur!=NULL;
}
bool ProfileHighLevel::FindProfile(const char *name, Id &id)
{
DFAIL_IF(!name) return false;
ProfileFastCS::Lock lock(cs);
for (ProfileId *cur=ProfileId::GetFirst();cur;cur=cur->GetNext())
if (!strcmp(name,cur->GetName()))
{
id.m_idPtr=cur;
return true;
}
id.m_idPtr=NULL;
return false;
}
ProfileHighLevel::ProfileHighLevel(void)
{
}
ProfileHighLevel ProfileHighLevel::Instance;