Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
profile_highlevel.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
20// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/profile/profile_highlevel.cpp $
21// $Author: mhoffe $
22// $Revision: #2 $
23// $DateTime: 2003/08/14 13:43:29 $
24//
25// ©2003 Electronic Arts
26//
27// High level profiling
29#include "_pch.h"
30#include <new>
31#include <stdio.h>
32
33// our own fast critical section
34static ProfileFastCS cs;
35
37// ProfileHighLevel::Id
38
40{
41 if (m_idPtr)
42 m_idPtr->Increment(add);
43}
44
46{
47 if (m_idPtr)
48 m_idPtr->Maximum(max);
49}
50
51const char *ProfileHighLevel::Id::GetName(void) const
52{
53 return m_idPtr?m_idPtr->GetName():NULL;
54}
55
56const char *ProfileHighLevel::Id::GetDescr(void) const
57{
58 return m_idPtr?m_idPtr->GetDescr():NULL;
59}
60
61const char *ProfileHighLevel::Id::GetUnit(void) const
62{
63 return m_idPtr?m_idPtr->GetUnit():NULL;
64}
65
67{
68 return m_idPtr?m_idPtr->AsString(m_idPtr->GetCurrentValue()):NULL;
69}
70
71const char *ProfileHighLevel::Id::GetValue(unsigned frame) const
72{
73 double v;
74 if (!m_idPtr||!m_idPtr->GetFrameValue(frame,v))
75 return NULL;
76 return m_idPtr->AsString(v);
77}
78
80{
81 return m_idPtr?m_idPtr->AsString(m_idPtr->GetTotalValue()):NULL;
82}
83
85// ProfileHighLevel::Block
86
87ProfileHighLevel::Block::Block(const char *name)
88{
89 DFAIL_IF(!name) return;
90
91 m_idTime=AddProfile(name,NULL,"msec",6,-4);
92
93 char help[256];
94 strncpy(help,name,sizeof(help));
95 help[sizeof(help)-1-2]=0;
96 strcat(help,".c");
97 AddProfile(help,NULL,"calls",6,0).Increment();
98
99 ProfileGetTime(m_start);
100}
101
103{
104 _int64 end;
105 ProfileGetTime(end);
106 end-=m_start;
107
108 m_idTime.Increment(double(end)/(double)Profile::GetClockCyclesPerSecond());
109}
110
112// ProfileId
113
114// profile ID stuff
115ProfileId *ProfileId::first;
116int ProfileId::curFrame;
117unsigned ProfileId::frameRecordMask;
118char ProfileId::stringBuf[ProfileId::STRING_BUFFER_SIZE];
119unsigned ProfileId::stringBufUnused;
120
121ProfileId::ProfileId(const char *name, const char *descr, const char *unit, int precision, int exp10)
122{
123 m_next=first; first=this;
124 m_name=(char *)ProfileAllocMemory(strlen(name)+1);
125 strcpy(m_name,name);
126 if (descr)
127 {
128 m_descr=(char *)ProfileAllocMemory(strlen(descr)+1);
129 strcpy(m_descr,descr);
130 }
131 else
132 m_descr=NULL;
133 if (unit)
134 {
135 m_unit=(char *)ProfileAllocMemory(strlen(unit)+1);
136 strcpy(m_unit,unit);
137 }
138 else
139 m_unit=NULL;
140 m_precision=precision;
141 m_exp10=exp10;
142 m_curVal=m_totalVal=0.;
143 m_recFrameVal=NULL;
144 m_firstFrame=curFrame;
145 m_valueMode=Unknown;
146}
147
149{
150 DFAIL_IF(m_valueMode!=Unknown&&m_valueMode!=ModeIncrement)
151 return;
152
153 m_valueMode=ModeIncrement;
154 m_curVal+=add;
155 m_totalVal+=add;
156 if (frameRecordMask)
157 {
158 unsigned mask=frameRecordMask;
159 for (unsigned i=0;i<MAX_FRAME_RECORDS;i++)
160 {
161 if (mask&1)
162 m_frameVal[i]+=add;
163 if (!(mask>>=1))
164 break;
165 }
166 }
167}
168
170{
171 DFAIL_IF(m_valueMode!=Unknown&&m_valueMode!=ModeMaximum)
172 return;
173
174 m_valueMode=ModeMaximum;
175 if (max>m_curVal)
176 m_curVal=max;
177 if (max>m_totalVal)
178 m_totalVal=max;
179 if (frameRecordMask)
180 {
181 unsigned mask=frameRecordMask;
182 for (unsigned i=0;i<MAX_FRAME_RECORDS;i++)
183 {
184 if (mask&1)
185 {
186 if (max>m_frameVal[i])
187 m_frameVal[i]=max;
188 }
189 if (!(mask>>=1))
190 break;
191 }
192 }
193}
194
195const char *ProfileId::AsString(double v) const
196{
197 char help1[10],help[40];
198 wsprintf(help1,"%%%i.lf",m_precision);
199
200 double mul=1.0;
201 int k;
202 for (k=m_exp10;k<0;k++) mul*=10.0;
203 for (;k>0;k--) mul/=10.0;
204
205 unsigned len=_snprintf(help,sizeof(help),help1,v*mul)+1;
206
207 ProfileFastCS::Lock lock(cs);
208 if (stringBufUnused+len>STRING_BUFFER_SIZE)
209 stringBufUnused=0;
210 char *ret=stringBuf+stringBufUnused;
211 memcpy(ret,help,len);
212 stringBufUnused+=len;
213 return ret;
214}
215
217{
218 ProfileFastCS::Lock lock(cs);
219
220 for (unsigned i=0;i<MAX_FRAME_RECORDS;i++)
221 if (!(frameRecordMask&(1<<i)))
222 break;
223 if (i==MAX_FRAME_RECORDS)
224 return -1;
225
226 for (ProfileId *p=first;p;p=p->m_next)
227 p->m_frameVal[i]=0.;
228
229 frameRecordMask|=1<<i;
230 return i;
231}
232
233void ProfileId::FrameEnd(int which, int mixIndex)
234{
235 DFAIL_IF(which<0||which>=MAX_FRAME_RECORDS)
236 return;
237 DFAIL_IF(!(frameRecordMask&(1<<which)))
238 return;
239 DFAIL_IF(mixIndex>=curFrame)
240 return;
241
242 ProfileFastCS::Lock lock(cs);
243
244 frameRecordMask^=1<<which;
245 if (mixIndex<0)
246 {
247 // new frame
248 curFrame++;
249 for (ProfileId *p=first;p;p=p->m_next)
250 {
251 p->m_recFrameVal=(double *)ProfileReAllocMemory(p->m_recFrameVal,sizeof(double)*(curFrame-p->m_firstFrame));
252 p->m_recFrameVal[curFrame-p->m_firstFrame-1]=p->m_frameVal[which];
253 }
254 }
255 else
256 {
257 // append data
258 for (ProfileId *p=first;p;p=p->m_next)
259 {
260 if (p->m_firstFrame>mixIndex)
261 continue;
262
263 double &val=p->m_recFrameVal[mixIndex-p->m_firstFrame];
264 switch(p->m_valueMode)
265 {
266 case ProfileId::Unknown:
267 break;
268 case ProfileId::ModeIncrement:
269 val+=p->m_frameVal[which];
270 break;
271 case ProfileId::ModeMaximum:
272 if (p->m_frameVal[which]>val)
273 val=p->m_frameVal[which];
274 break;
275 default:
276 DFAIL();
277 }
278 }
279 }
280}
281
283{
284 if (frameRecordMask)
285 {
286 for (unsigned i=0;i<MAX_FRAME_RECORDS;i++)
287 if (frameRecordMask&(1<<i))
288 FrameEnd(i,-1);
289 }
290}
291
293// ProfileHighLevel
294
295ProfileHighLevel::Id ProfileHighLevel::AddProfile(const char *name, const char *descr, const char *unit, int precision, int exp10)
296{
297 // check if there is already an ID with the given name...
298 Id id;
299 if (FindProfile(name,id))
300 return id;
301
302 // checks...
303 DFAIL_IF(!name) return id;
304
305 // no, allocate one
306 ProfileFastCS::Lock lock(cs);
307 id.m_idPtr=new (ProfileAllocMemory(sizeof(ProfileId))) ProfileId(name,descr,unit,precision,exp10);
308 return id;
309}
310
311bool ProfileHighLevel::EnumProfile(unsigned index, Id &id)
312{
313 ProfileFastCS::Lock lock(cs);
314 for (ProfileId *cur=ProfileId::GetFirst();cur&&index--;cur=cur->GetNext());
315 id.m_idPtr=cur;
316 return cur!=NULL;
317}
318
319bool ProfileHighLevel::FindProfile(const char *name, Id &id)
320{
321 DFAIL_IF(!name) return false;
322
323 ProfileFastCS::Lock lock(cs);
324 for (ProfileId *cur=ProfileId::GetFirst();cur;cur=cur->GetNext())
325 if (!strcmp(name,cur->GetName()))
326 {
327 id.m_idPtr=cur;
328 return true;
329 }
330
331 id.m_idPtr=NULL;
332 return false;
333}
334
335ProfileHighLevel::ProfileHighLevel(void)
336{
337}
338
339ProfileHighLevel ProfileHighLevel::Instance;
#define NULL
Definition BaseType.h:92
#define max(x, y)
Definition BaseType.h:105
__forceinline void ProfileGetTime(__int64 &t)
Definition PerfTimer.cpp:38
void add(float *sum, float *addend)
~Block()
Updates timer based function block.
A high level profile ID.
const char * GetName(void) const
Returns the internal Id name.
const char * GetCurrentValue(void) const
Returns the current value.
void SetMax(double max)
Set a new maximum value.
const char * GetUnit(void) const
Returns the value's unit text.
const char * GetValue(unsigned frame) const
Returns the value for the given recorded frame/range.
void Increment(double add=1.0)
Increment the internal profile value.
const char * GetDescr(void) const
Returns the descriptive name.
const char * GetTotalValue(void) const
Returns the total value for all frames.
static bool FindProfile(const char *name, Id &id)
Searches for the given high level profile.
static bool EnumProfile(unsigned index, Id &id)
Enumerates the list of known high level profile values.
static Id AddProfile(const char *name, const char *descr, const char *unit, int precision, int exp10=0)
Registers a new high level profile value.
static _int64 GetClockCyclesPerSecond(void)
Determines number of CPU clock cycles per second.
Definition profile.cpp:335
an internal high level profile ID
static int FrameStart(void)
void Increment(double add)
void Maximum(double max)
static ProfileId * GetFirst(void)
static void Shutdown(void)
const char * AsString(double v) const
static void FrameEnd(int which, int mixIndex)
#define DFAIL_IF(cond)
#define DFAIL()
void * ProfileReAllocMemory(void *oldPtr, unsigned newSize)
Definition profile.cpp:52
void * ProfileAllocMemory(unsigned numBytes)
Definition profile.cpp:44