/*
** Command & Conquer Generals(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 .
*/
/*****************************************************************************
** **
** Westwood Studios Pacific. **
** **
** Confidential Information **
** Copyright (C) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: Dune Emperor **
** **
** Module: (_) **
** **
** Version: $ID$ **
** **
** File name: audprof.cpp **
** **
** Created by: mm/dd/yy **
** **
** Description: **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#define WIN32_LEAN_AND_MEAN
#include
#include
#include
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
#ifndef IG_FINAL_RELEASE
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheInit ( ProfileData *prof, int pages, int pageSize )
{
memset ( prof, 0, sizeof ( ProfileData ));
if ( !QueryPerformanceFrequency( (LARGE_INTEGER*) &prof->freq ))
{
prof->freq = 0;
}
prof->update = prof->freq;
prof->cacheSize = pages*pageSize;
prof->numPages = pages;
prof->pageSize = pageSize;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheDeinit ( ProfileData * )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheNewFrame ( ProfileData *prof )
{
int total;
prof->frames++;
if ( prof->totalTime > prof->longestFrame )
{
prof->nextLongestFrame = prof->longestFrame;
prof->nextLongestFramePages = prof->longestFramePages;
prof->nextLongestFrameBytes = prof->longestFrameBytes;
prof->longestFrame = prof->totalTime ;
prof->longestFrameBytes = prof->totalDataBytes;
prof->longestFramePages = prof->pageCount;
}
else if ( prof->totalTime > prof->nextLongestFrame )
{
prof->nextLongestFrame = prof->totalTime ;
prof->nextLongestFrameBytes = prof->totalDataBytes;
prof->nextLongestFramePages = prof->pageCount;
}
prof->pageCount = 0;
if ( (total = prof->hits + prof->misses ))
{
prof->HitPercent = (prof->hits *100) / total;
}
prof->BytesPerFrame = prof->totalFrameBytes / prof->frames;
if ( prof->frames > 3*30 )
{
prof->totalFrameBytes = 0;
prof->frames = 0;
}
if ( ! (prof->frames % 30) )
{
prof->hits = 0;
prof->misses = 0;
}
if ( prof->totalTime > prof->update )
{
int ms;
ms = (int) ( (prof->totalTime *1000 )/prof->freq);
prof->TotalBytesPerSecond = (int) (((unsigned __int64) prof->totalDataBytes *1000)/ ms);
prof->totalDataBytes = 0;
prof->totalTime = 0;
ms = (int) ((prof->totalDecompTime *1000 )/prof->freq) ;
if ( ms )
{
prof->DecompBytesPerSecond = (int) (((unsigned __int64) prof->totalDecompBytes *1000)/ ms);
}
else
{
prof->DecompBytesPerSecond = 0;
}
prof->totalDecompBytes = 0;
prof->totalDecompTime = 0;
ms = (int) ((prof->totalLoadTime *1000 )/prof->freq );
if ( ms )
{
prof->LoadBytesPerSecond = (int) (((unsigned __int64)prof->totalLoadBytes *1000)/ ms);
}
else
{
prof->LoadBytesPerSecond = 0;
}
prof->totalLoadBytes = 0;
prof->totalLoadTime = 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheLoadStart ( ProfileData *prof, int bytes )
{
QueryPerformanceCounter( (LARGE_INTEGER*)&prof->start );
prof->dbytes = bytes;
prof->start_decomp = 0;
prof->pageCount++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheAddLoadBytes ( ProfileData *prof, int bytes )
{
prof->dbytes += bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheDecompress ( ProfileData *prof, int bytes )
{
QueryPerformanceCounter( (LARGE_INTEGER*)&prof->start_decomp );
prof->lbytes = bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheLoadEnd ( ProfileData *prof )
{
QueryPerformanceCounter( (LARGE_INTEGER*)&prof->end );
prof->totalTime += prof->end - prof->start;
prof->totalDataBytes += prof->dbytes;
prof->totalFrameBytes += prof->dbytes;
if ( prof->start_decomp )
{
prof->totalLoadTime += prof->start_decomp - prof->start;
prof->totalDecompTime += prof->end - prof->start_decomp;
prof->totalLoadBytes += prof->lbytes;
prof->totalDecompBytes += prof->dbytes;
}
else
{
prof->totalLoadTime += prof->end - prof->start;
prof->totalLoadBytes += prof->dbytes;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheMiss ( ProfileData *prof )
{
prof->misses++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheHit ( ProfileData *prof )
{
prof->hits++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheAddPage ( ProfileData *prof )
{
prof->pagesUsed++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheRemovePage ( ProfileData *prof )
{
prof->pagesUsed--;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheFill ( ProfileData *prof, int bytes )
{
prof->cacheUsed += bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheRemove ( ProfileData *prof, int bytes )
{
prof->cacheUsed -= bytes;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheText ( ProfileData *prof, void ( *print) ( char *text ) )
{
char buf[1024];
int used;
int filled;
print ("Audio Cache Stats\n");
sprintf( buf, "Hits: %d%%\n", prof->HitPercent );
print ( buf );
if ( prof->numPages )
{
used = (prof->pagesUsed *100)/prof->numPages;
}
else
{
used = 0;
}
if ( prof->pagesUsed * prof->pageSize )
{
filled = (prof->cacheUsed *100)/ (prof->pagesUsed * prof->pageSize );
}
else
{
filled = 0;
}
sprintf( buf, "Used: %d%% (%d%%)\n", used, filled );
print ( buf );
sprintf( buf, "KbPS: %d.%02d (%d.%02d,%d.%02d)\n",
prof->TotalBytesPerSecond/1024, ((prof->TotalBytesPerSecond%1024)*100)/1024,
prof->LoadBytesPerSecond/1024, ((prof->LoadBytesPerSecond%1024)*100)/1024,
prof->DecompBytesPerSecond/1024, ((prof->DecompBytesPerSecond%1024)*100)/1024);
print ( buf );
sprintf( buf, "KPF: %d.%02d\n",
prof->BytesPerFrame/1024, ((prof->BytesPerFrame%1024)*100)/1024 );
print ( buf );
sprintf( buf, " LF: %d.%02ds; %d pages; %d Kb\n",
(int) (prof->longestFrame/prof->freq), (int)(((prof->longestFrame % prof->freq)*100)/prof->freq),
prof->longestFramePages, prof->longestFrameBytes/1024 );
print ( buf );
sprintf( buf, "NLF: %d.%02ds; %d pages; %d Kb\n",
(int) (prof->nextLongestFrame/prof->freq), (int) (((prof->nextLongestFrame % prof->freq)*100)/prof->freq),
prof->nextLongestFramePages, prof->nextLongestFrameBytes/1024 );
print ( buf );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfCacheUpdateInterval ( ProfileData *prof, int mseconds )
{
prof->update = (prof->freq * mseconds )/ 1000;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static ProfStamp calc_ticks ( ProfStamp start, ProfStamp end )
{
if ( start < end )
{
return end - start;
}
return ((ProfStamp)0xffffffffffffffff) - start + end ;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
static void calc_stats ( ProfileCPU &prof )
{
if ( prof.lastCPU )
{
prof.cpuUsage = (int) ((prof.lastTicks*((ProfStamp)1000))/prof.lastCPU);
}
else
{
prof.cpuUsage = 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUInit ( ProfileCPU &prof )
{
memset ( &prof, 0, sizeof ( ProfileCPU ));
if ( !QueryPerformanceFrequency( (LARGE_INTEGER*) &prof.freq ))
{
prof.freq = 0;
}
prof.updateInterval = SECONDS(1);
if ( prof.freq )
{
prof.overflowInterval = SECONDS ( (((ProfStamp) 0xffffffffffffffff) / prof.freq) );
if ( prof.overflowInterval < prof.updateInterval )
{
prof.updateInterval = prof.overflowInterval;
}
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUDeinit ( ProfileCPU &prof )
{
prof;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUStart ( ProfileCPU &prof )
{
if ( prof.state == PROF_STATE_IDLE )
{
QueryPerformanceCounter( (LARGE_INTEGER*)&prof.start );
if ( prof.lastStart )
{
prof.totalCPUTicks += calc_ticks ( prof.lastStart, prof.start );
}
prof.lastStart = prof.start;
prof.state = PROF_STATE_PROFILING;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUPause ( ProfileCPU &prof )
{
if ( prof.state == PROF_STATE_PROFILING )
{
ProfStamp end;
QueryPerformanceCounter( (LARGE_INTEGER*) &end );
prof.totalTicks += calc_ticks ( prof.start, end );
prof.state = PROF_STATE_PAUSED;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUResume ( ProfileCPU &prof )
{
if ( prof.state == PROF_STATE_PAUSED )
{
QueryPerformanceCounter( (LARGE_INTEGER*) &prof.start );
prof.state = PROF_STATE_PROFILING;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUEnd ( ProfileCPU &prof )
{
ProfStamp end;
QueryPerformanceCounter( (LARGE_INTEGER*) &end );
if ( prof.state != PROF_STATE_IDLE )
{
if ( prof.start && prof.totalCPUTicks )
{
prof.totalTicks += calc_ticks ( prof.start, end );
}
prof.state = PROF_STATE_IDLE;
}
TimeStamp now = AudioGetTime();
TimeStamp lastUpdate = now - prof.lastUpdate;
if ( lastUpdate > prof.updateInterval )
{
prof.lastUpdate = now;
if ( lastUpdate < prof.overflowInterval )
{
// we can use the data
prof.lastTicks = prof.totalTicks;
prof.lastCPU = prof.totalCPUTicks;
calc_stats ( prof );
}
prof.totalTicks = 0;
prof.totalCPUTicks = 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int ProfileCPUUsage ( ProfileCPU &prof )
{
return prof.cpuUsage;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int ProfileCPUTicks ( ProfileCPU &prof )
{
prof;
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUSetName ( ProfileCPU &prof, const char *name )
{
strncpy ( prof.name, name, MAX_PROF_NAME );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void ProfileCPUPrint ( ProfileCPU &prof, void ( *print) ( char *text ) )
{
char buffer[200];
if ( prof.freq )
{
sprintf ( buffer, "%s : CPU %3d.%1d / %I64d", prof.name, prof.cpuUsage/10, prof.cpuUsage%10, prof.lastTicks );
}
else
{
sprintf ( buffer, "%s : CPU (no timer)" );
}
print ( buffer );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
#endif