/* ** 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); }