/*
** 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_result.cpp $
// $Author: mhoffe $
// $Revision: #2 $
// $DateTime: 2003/08/12 15:05:00 $
//
// ©2003 Electronic Arts
//
// Result function interface and result functions
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include
#include
#include
//////////////////////////////////////////////////////////////////////////////
// ProfileResultFileCSV
ProfileResultInterface *ProfileResultFileCSV::Create(int, const char * const *)
{
return new (ProfileAllocMemory(sizeof(ProfileResultFileCSV))) ProfileResultFileCSV();
}
void ProfileResultFileCSV::WriteThread(ProfileFuncLevel::Thread &thread)
{
char help[40];
sprintf(help,"prof%08x-all.csv",thread.GetId());
FILE *f=fopen(help,"wt");
// CSV file header
fprintf(f,"Function\tFile\tCall count\tPTT (all)\tGTT (all)\tPT/C (all)\tGT/C (all)\tCaller (all)");
for (unsigned k=0;k~ProfileResultFileCSV();
ProfileFreeMemory(this);
}
//////////////////////////////////////////////////////////////////////////////
// ProfileResultFileDOT
ProfileResultInterface *ProfileResultFileDOT::Create(int argn, const char * const *argv)
{
return new (ProfileAllocMemory(sizeof(ProfileResultFileDOT)))
ProfileResultFileDOT(argn>0?argv[0]:NULL,
argn>1?argv[1]:NULL,
argn>2?atoi(argv[2]):NULL);
}
ProfileResultFileDOT::ProfileResultFileDOT(const char *fileName, const char *frameName, int foldThreshold)
{
if (!fileName)
fileName="profile.dot";
m_fileName=(char *)ProfileAllocMemory(strlen(fileName)+1);
strcpy(m_fileName,fileName);
if (frameName)
{
m_frameName=(char *)ProfileAllocMemory(strlen(frameName)+1);
strcpy(m_frameName,frameName);
}
else
m_frameName=NULL;
m_foldThreshold=foldThreshold;
}
void ProfileResultFileDOT::WriteResults(void)
{
// search "main" thread
ProfileFuncLevel::Thread t,tMax;
if (!ProfileFuncLevel::EnumThreads(0,tMax))
return;
unsigned curMax=0;
for (unsigned k=1;ProfileFuncLevel::EnumThreads(k,t);k++)
{
for (;curMax++;)
{
ProfileFuncLevel::Id help;
if (!tMax.EnumProfile(curMax,help))
{
tMax=t;
break;
}
if (!t.EnumProfile(curMax,help))
break;
curMax++;
}
}
// search frame
unsigned frame=ProfileFuncLevel::Id::Total;
if (m_frameName)
{
for (unsigned k=0;km_foldThreshold?"closed":"none");
// fold or not?
if (active>m_foldThreshold)
{
// folding version
// build source code clusters first
FoldHelper *fold=NULL;
for (k=0;tMax.EnumProfile(k,id);k++)
{
const char *source=id.GetSource();
for (FoldHelper *cur=fold;cur;cur=cur->next)
if (!strcmp(source,cur->source))
{
if (cur->numIdid[cur->numId++]=id;
break;
}
if (!cur)
{
cur=(FoldHelper *)ProfileAllocMemory(sizeof(FoldHelper));
cur->next=fold;
fold=cur;
cur->source=source;
cur->numId=1;
cur->id[0]=id;
}
}
// now write data
for (FoldHelper *cur=fold;cur;cur=cur->next)
{
for (FoldHelper *cur2=fold;cur2;cur2=cur2->next)
cur2->mark=false;
for (k=0;knumId;k++)
{
ProfileFuncLevel::IdList idlist=id.GetCaller(frame);
ProfileFuncLevel::Id caller;
for (unsigned i=0;idlist.Enum(i,caller);i++)
{
const char *s=caller.GetSource();
for (FoldHelper *cur2=fold;cur2;cur2=cur2->next)
if (!strcmp(cur2->source,s))
break;
if (!cur2||cur2->mark)
continue;
cur2->mark=true;
fprintf(f,"\"%s\" -> \"%s\"\n",s,cur->source);
}
}
}
// cleanup
while (fold)
{
FoldHelper *next=fold->next;
ProfileFreeMemory(fold);
fold=next;
}
}
else
{
// non-folding version
for (k=0;tMax.EnumProfile(k,id);k++)
if (id.GetCalls(frame))
fprintf(f,"f%08x [label=\"%s\"]\n",id.GetAddress(),id.GetFunction());
for (k=0;tMax.EnumProfile(k,id);k++)
{
ProfileFuncLevel::IdList idlist=id.GetCaller(frame);
ProfileFuncLevel::Id caller;
unsigned count;
for (unsigned i=0;idlist.Enum(i,caller,&count);i++)
fprintf(f,"f%08x -> f%08x [headlabel=\"%i\"];\n",caller.GetAddress(),id.GetAddress(),count);
}
}
fprintf(f,"}\n");
fclose(f);
}
void ProfileResultFileDOT::Delete(void)
{
this->~ProfileResultFileDOT();
ProfileFreeMemory(this);
}