Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
profile_result.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_result.cpp $
21// $Author: mhoffe $
22// $Revision: #2 $
23// $DateTime: 2003/08/12 15:05:00 $
24//
25// ©2003 Electronic Arts
26//
27// Result function interface and result functions
29#include "_pch.h"
30#include <new>
31#include <stdio.h>
32#include <stdlib.h>
33
35// ProfileResultFileCSV
36
37ProfileResultInterface *ProfileResultFileCSV::Create(int, const char * const *)
38{
39 return new (ProfileAllocMemory(sizeof(ProfileResultFileCSV))) ProfileResultFileCSV();
40}
41
42void ProfileResultFileCSV::WriteThread(ProfileFuncLevel::Thread &thread)
43{
44 char help[40];
45
46 sprintf(help,"prof%08x-all.csv",thread.GetId());
47 FILE *f=fopen(help,"wt");
48
49 // CSV file header
50 fprintf(f,"Function\tFile\tCall count\tPTT (all)\tGTT (all)\tPT/C (all)\tGT/C (all)\tCaller (all)");
51 for (unsigned k=0;k<Profile::GetFrameCount();k++)
52 {
53 const char *s=Profile::GetFrameName(k);
54 fprintf(f,"\tCall (%s)\tPTT (%s)\tGTT (%s)\tPT/C (%s)\tGT/C (%s)\tCaller (%s)",s,s,s,s,s,s);
55 }
56 fprintf(f,"\n");
57
58 // now show all profile IDs (functions)
59 ProfileFuncLevel::Id id;
60 for (k=0;thread.EnumProfile(k,id);k++)
61 {
62 fprintf(f,"%s[%08x]\t%s, %i",id.GetFunction(),id.GetAddress(),
63 id.GetSource(),id.GetLine());
64
66 {
67 if (!id.GetCalls(i))
68 {
69 // early skip...
70 fprintf(f,"\t\t\t\t\t\t");
71 continue;
72 }
73
74 // call count
75 fprintf(f,"\t%I64i",id.GetCalls(i));
76
77 // pure total time
78 fprintf(f,"\t%I64i",id.GetFunctionTime(i));
79
80 // global total time
81 fprintf(f,"\t%I64i",id.GetTime(i));
82
83 // pure time per call
84 fprintf(f,"\t%I64i",id.GetFunctionTime(i)/id.GetCalls(i));
85
86 // global time per call
87 fprintf(f,"\t%I64i",id.GetTime(i)/id.GetCalls(i));
88
89 // list of callers
90 ProfileFuncLevel::IdList idlist=id.GetCaller(i);
91 fprintf(f,"\t");
92 ProfileFuncLevel::Id callid;
93 unsigned count;
94 for (unsigned j=0;idlist.Enum(j,callid,&count);j++)
95 fprintf(f," %s[%08x](%i)",callid.GetFunction(),callid.GetAddress(),count);
96 }
97 fprintf(f,"\n");
98 }
99
100 fclose(f);
101}
102
104{
106 for (unsigned k=0;ProfileFuncLevel::EnumThreads(k,t);k++)
107 WriteThread(t);
108
109 FILE *f=fopen("profile-high.csv","wt");
110
111 // CSV file header
112 fprintf(f,"Profile\tUnit\ttotal");
113 for (k=0;k<Profile::GetFrameCount();k++)
114 fprintf(f,"\t%s",Profile::GetFrameName(k));
115 fprintf(f,"\n");
116
117 // now show all high level profile IDs
119 for (k=0;ProfileHighLevel::EnumProfile(k,id);k++)
120 {
121 fprintf(f,"%s\t%s\t%s",id.GetName(),id.GetUnit(),id.GetTotalValue());
122 for (unsigned i=0;i<Profile::GetFrameCount();i++)
123 {
124 const char *p=id.GetValue(i);
125 fprintf(f,"\t%s",p?p:"");
126 }
127 fprintf(f,"\n");
128 }
129
130 fclose(f);
131}
132
134{
135 this->~ProfileResultFileCSV();
136 ProfileFreeMemory(this);
137}
138
140// ProfileResultFileDOT
141
142ProfileResultInterface *ProfileResultFileDOT::Create(int argn, const char * const *argv)
143{
144 return new (ProfileAllocMemory(sizeof(ProfileResultFileDOT)))
145 ProfileResultFileDOT(argn>0?argv[0]:NULL,
146 argn>1?argv[1]:NULL,
147 argn>2?atoi(argv[2]):NULL);
148}
149
150ProfileResultFileDOT::ProfileResultFileDOT(const char *fileName, const char *frameName, int foldThreshold)
151{
152 if (!fileName)
153 fileName="profile.dot";
154 m_fileName=(char *)ProfileAllocMemory(strlen(fileName)+1);
155 strcpy(m_fileName,fileName);
156 if (frameName)
157 {
158 m_frameName=(char *)ProfileAllocMemory(strlen(frameName)+1);
159 strcpy(m_frameName,frameName);
160 }
161 else
162 m_frameName=NULL;
163 m_foldThreshold=foldThreshold;
164}
165
167{
168 // search "main" thread
171 return;
172
173 unsigned curMax=0;
174 for (unsigned k=1;ProfileFuncLevel::EnumThreads(k,t);k++)
175 {
176 for (;curMax++;)
177 {
179 if (!tMax.EnumProfile(curMax,help))
180 {
181 tMax=t;
182 break;
183 }
184 if (!t.EnumProfile(curMax,help))
185 break;
186 curMax++;
187 }
188 }
189
190 // search frame
191 unsigned frame=ProfileFuncLevel::Id::Total;
192 if (m_frameName)
193 {
194 for (unsigned k=0;k<Profile::GetFrameCount();k++)
195 if (!strcmp(Profile::GetFrameName(k),m_frameName))
196 {
197 frame=k;
198 break;
199 }
200 }
201
202 // determine number of active functions
203 unsigned active=0;
205 for (k=0;tMax.EnumProfile(k,id);k++)
206 if (id.GetCalls(frame))
207 active++;
208
209 FILE *f=fopen(m_fileName,"wt");
210 if (!f)
211 return;
212
213 // DOT header
214 fprintf(f,"digraph G { rankdir=\"LR\";\n");
215 fprintf(f,"node [shape=box, fontname=Arial]\n");
216 fprintf(f,"edge [arrowhead=%s, labelfontname=Arial, labelfontsize=10, labelangle=0, labelfontcolor=blue]\n",
217 active>m_foldThreshold?"closed":"none");
218
219 // fold or not?
220 if (active>m_foldThreshold)
221 {
222 // folding version
223
224 // build source code clusters first
225 FoldHelper *fold=NULL;
226 for (k=0;tMax.EnumProfile(k,id);k++)
227 {
228 const char *source=id.GetSource();
229 for (FoldHelper *cur=fold;cur;cur=cur->next)
230 if (!strcmp(source,cur->source))
231 {
232 if (cur->numId<MAX_FUNCTIONS_PER_FILE)
233 cur->id[cur->numId++]=id;
234 break;
235 }
236 if (!cur)
237 {
238 cur=(FoldHelper *)ProfileAllocMemory(sizeof(FoldHelper));
239 cur->next=fold;
240 fold=cur;
241 cur->source=source;
242 cur->numId=1;
243 cur->id[0]=id;
244 }
245 }
246
247 // now write data
248 for (FoldHelper *cur=fold;cur;cur=cur->next)
249 {
250 for (FoldHelper *cur2=fold;cur2;cur2=cur2->next)
251 cur2->mark=false;
252
253 for (k=0;k<cur->numId;k++)
254 {
255 ProfileFuncLevel::IdList idlist=id.GetCaller(frame);
257 for (unsigned i=0;idlist.Enum(i,caller);i++)
258 {
259 const char *s=caller.GetSource();
260 for (FoldHelper *cur2=fold;cur2;cur2=cur2->next)
261 if (!strcmp(cur2->source,s))
262 break;
263 if (!cur2||cur2->mark)
264 continue;
265 cur2->mark=true;
266
267 fprintf(f,"\"%s\" -> \"%s\"\n",s,cur->source);
268 }
269 }
270 }
271
272 // cleanup
273 while (fold)
274 {
275 FoldHelper *next=fold->next;
276 ProfileFreeMemory(fold);
277 fold=next;
278 }
279 }
280 else
281 {
282 // non-folding version
283 for (k=0;tMax.EnumProfile(k,id);k++)
284 if (id.GetCalls(frame))
285 fprintf(f,"f%08x [label=\"%s\"]\n",id.GetAddress(),id.GetFunction());
286 for (k=0;tMax.EnumProfile(k,id);k++)
287 {
288 ProfileFuncLevel::IdList idlist=id.GetCaller(frame);
290 unsigned count;
291 for (unsigned i=0;idlist.Enum(i,caller,&count);i++)
292 fprintf(f,"f%08x -> f%08x [headlabel=\"%i\"];\n",caller.GetAddress(),id.GetAddress(),count);
293 }
294 }
295
296 fprintf(f,"}\n");
297 fclose(f);
298}
299
301{
302 this->~ProfileResultFileDOT();
303 ProfileFreeMemory(this);
304}
#define NULL
Definition BaseType.h:92
A function level profile ID.
unsigned GetAddress(void) const
Returns function address.
@ Total
return the total value/count
const char * GetSource(void) const
Returns the source file this Id is in.
const char * GetFunction(void) const
Returns the function name for this Id.
A list of function level profile IDs.
bool Enum(unsigned index, Id &id, unsigned *countPtr=0) const
Enumerates the list of IDs.
bool EnumProfile(unsigned index, Id &id) const
Enumerates the list of known function level profile values.
static bool EnumThreads(unsigned index, Thread &thread)
Enumerates the list of known and profiled threads.
A high level profile ID.
static bool EnumProfile(unsigned index, Id &id)
Enumerates the list of known high level profile values.
static unsigned GetFrameCount(void)
Determines the number of known (recorded) range frames.
Definition profile.cpp:317
static const char * GetFrameName(unsigned frame)
Determines the range name of a recorded range frame.
Definition profile.cpp:322
virtual const char * GetName(void) const
static ProfileResultInterface * Create(int argn, const char *const *)
virtual void WriteResults(void)
Write out results.
virtual void Delete(void)
Destroys the current result function.
static ProfileResultInterface * Create(int argn, const char *const *)
Creates a class instance.
virtual void WriteResults(void)
Write out results.
virtual void Delete(void)
Destroys the current result function.
void ProfileFreeMemory(void *ptr)
Definition profile.cpp:82
void * ProfileAllocMemory(unsigned numBytes)
Definition profile.cpp:44