/* ** 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.cpp $ // $Author: mhoffe $ // $Revision: #6 $ // $DateTime: 2003/08/14 13:43:29 $ // // ©2003 Electronic Arts // // Profile module main code ////////////////////////////////////////////////////////////////////////////// #include "_pch.h" #include #include "mmsystem.h" #pragma comment (lib,"winmm") // yuk, I'm doing this so weird because the destructor // of cmd must never be called... static ProfileCmdInterface &cmd=*(ProfileCmdInterface *)new (ProfileAllocMemory(sizeof(ProfileCmdInterface))) ProfileCmdInterface(); // we have this here so that our command interface will always // be linked in as well... static bool __RegisterDebugCmdGroup_Profile=Debug::AddCommands("profile",&cmd); void *ProfileAllocMemory(unsigned numBytes) { HGLOBAL h=GlobalAlloc(GMEM_FIXED,numBytes); if (!h) DCRASH_RELEASE("Debug mem alloc failed"); return (void *)h; } void *ProfileReAllocMemory(void *oldPtr, unsigned newSize) { // Windows doesn't like ReAlloc with NULL handle/ptr... if (!oldPtr) return newSize?ProfileAllocMemory(newSize):0; // Shrinking to 0 size is basically freeing memory if (!newSize) { GlobalFree((HGLOBAL)oldPtr); return 0; } // now try GlobalReAlloc first HGLOBAL h=GlobalReAlloc((HGLOBAL)oldPtr,newSize,0); if (!h) { // this failed (Windows doesn't like ReAlloc'ing larger // fixed memory blocks) - go with Alloc/Free instead h=GlobalAlloc(GMEM_FIXED,newSize); if (!h) DCRASH_RELEASE("Debug mem realloc failed"); unsigned oldSize=GlobalSize((HGLOBAL)oldPtr); memcpy((void *)h,oldPtr,oldSizenext) { if (SimpleMatch(range,cur->pattern)) active=cur->isActive; } if (active) { #ifdef _PROFILE m_frameNames[k].funcIndex=ProfileFuncLevelTracer::FrameStart(); DASSERT(m_frameNames[k].funcIndex>=0); #endif m_frameNames[k].highIndex=ProfileId::FrameStart(); DASSERT(m_frameNames[k].highIndex>=0); } else { m_frameNames[k].funcIndex=-1; m_frameNames[k].highIndex=-1; } } void Profile::AppendRange(const char *range) { // set default if (!range) range="frame"; // known name? for (unsigned k=0;knext) { if (SimpleMatch(range,cur->pattern)) active=cur->isActive; } if (active) { #ifdef _PROFILE m_frameNames[k].funcIndex=ProfileFuncLevelTracer::FrameStart(); DASSERT(m_frameNames[k].funcIndex>=0); #endif m_frameNames[k].highIndex=ProfileId::FrameStart(); DASSERT(m_frameNames[k].highIndex>=0); } else { m_frameNames[k].funcIndex=-1; m_frameNames[k].highIndex=-1; } } void Profile::StopRange(const char *range) { // set default if (!range) range="frame"; // known name? for (unsigned k=0;k=0 || #endif m_frameNames[k].highIndex>=0 ) { // add to list of known frames? int atIndex; if (!m_frameNames[k].doAppend|| m_frameNames[k].lastGlobalIndex<0) { atIndex=-1; m_frameNames[k].lastGlobalIndex=m_rec; m_recNames=(char **)ProfileReAllocMemory(m_recNames,(m_rec+1)*sizeof(char *)); m_recNames[m_rec]=(char *)ProfileAllocMemory(strlen(range)+1+6); wsprintf(m_recNames[m_rec++],"%s:%i",range,++m_frameNames[k].frames); } else atIndex=m_frameNames[k].lastGlobalIndex; #ifdef _PROFILE if (m_frameNames[k].funcIndex>=0) ProfileFuncLevelTracer::FrameEnd(m_frameNames[k].funcIndex,atIndex); if (m_frameNames[k].highIndex>=0) #endif ProfileId::FrameEnd(m_frameNames[k].highIndex,atIndex); } } bool Profile::IsEnabled(void) { for (unsigned k=0;k=m_rec?NULL:m_recNames[frame]; } void Profile::ClearTotals(void) { #ifdef _PROFILE ProfileFuncLevelTracer::ClearTotals(); #endif ProfileId::ClearTotals(); } _int64 Profile::GetClockCyclesPerSecond(void) { return m_clockCycles; } void Profile::AddResultFunction(ProfileResultInterface* (*func)(int, const char * const *), const char *name, const char *arg) { ProfileCmdInterface::AddResultFunction(func,name,arg); } bool Profile::SimpleMatch(const char *str, const char *pattern) { DASSERT(str); DASSERT(pattern); while (*str&&*pattern) { if (*pattern=='*') { pattern++; while (*str) if (SimpleMatch(str++,pattern)) return true; return *str==*pattern; } else { if (*str++!=*pattern++) return false; } } return *str==*pattern; } static void ProfileShutdown(void) { #ifdef _PROFILE ProfileFuncLevelTracer::Shutdown(); #endif ProfileId::Shutdown(); DLOG("CPU speed is " << unsigned(Profile::GetClockCyclesPerSecond()) << " Hz.\n"); cmd.RunResultFunctions(); } int profileTracerInit=atexit(ProfileShutdown);