You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
8.6 KiB
357 lines
8.6 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
#include "filesystem_engine.h" |
|
#include "filesystem.h" |
|
#include "dt_instrumentation_server.h" |
|
#include "dt_send.h" |
|
#include "tier1/utlstring.h" |
|
#include "utllinkedlist.h" |
|
#include "dt.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#define DELTA_DISTANCE_BAND 200 |
|
#define NUM_DELTA_DISTANCE_BANDS (8000/DELTA_DISTANCE_BAND) |
|
|
|
|
|
// Data we track per SendTable on the server. |
|
class CDTISendTable |
|
{ |
|
public: |
|
// Which SendTable we're interested in. |
|
CUtlString m_NetTableName; |
|
|
|
// How many cycles we've spent in certain calls. |
|
CCycleCount m_nCalcDeltaCycles; |
|
int m_nCalcDeltaCalls; |
|
|
|
CCycleCount m_nEncodeCycles; |
|
int m_nEncodeCalls; |
|
|
|
CCycleCount m_nShouldTransmitCycles; |
|
int m_nShouldTransmitCalls; |
|
|
|
CCycleCount m_nWriteDeltaPropsCycles; |
|
|
|
// Used to determine how much the class uses manual mode. |
|
int m_nChangeAutoDetects; |
|
int m_nNoChanges; |
|
|
|
// Set to false if no events were recorded for this class. |
|
bool HadAnyAction() const { return m_nCalcDeltaCalls || m_nEncodeCalls || m_nShouldTransmitCalls; } |
|
|
|
// This tracks how many times an entity was delta'd for each distance from a client. |
|
unsigned short m_DistanceDeltaCounts[NUM_DELTA_DISTANCE_BANDS]; |
|
}; |
|
|
|
|
|
static CCycleCount g_TotalServerDTICycles; |
|
|
|
static CUtlLinkedList<CDTISendTable*, unsigned short> g_DTISendTables; |
|
|
|
bool g_bServerDTIEnabled = false; |
|
static char const *g_pServerDTIFilename = 0; |
|
|
|
static bool g_bFirstHookTimer = true; |
|
static CCycleCount g_ServerDTITimer; |
|
|
|
|
|
|
|
void ServerDTI_Init( char const *pFilename ) |
|
{ |
|
g_pServerDTIFilename = pFilename; |
|
g_bServerDTIEnabled = true; |
|
g_TotalServerDTICycles.Init(); |
|
g_bFirstHookTimer = true; |
|
} |
|
|
|
|
|
void ServerDTI_Term() |
|
{ |
|
if ( !g_pServerDTIFilename ) |
|
return; |
|
ServerDTI_Flush(); |
|
g_DTISendTables.PurgeAndDeleteElements(); |
|
g_pServerDTIFilename = 0; |
|
g_bServerDTIEnabled = false; |
|
} |
|
|
|
|
|
void ServerDTI_Flush() |
|
{ |
|
if ( !g_pServerDTIFilename ) |
|
return; |
|
|
|
CCycleCount curTime; |
|
curTime.Sample(); |
|
|
|
CCycleCount runningTime; |
|
CCycleCount::Sub( curTime, g_ServerDTITimer, runningTime ); |
|
|
|
// Write out a file that can be used by Excel. |
|
FileHandle_t fp = g_pFileSystem->Open( g_pServerDTIFilename, "wt", "LOGDIR" ); |
|
|
|
if( fp != FILESYSTEM_INVALID_HANDLE ) |
|
{ |
|
// Write the header. |
|
g_pFileSystem->FPrintf( fp, |
|
"DTName" |
|
|
|
"\tCalcDelta calls" |
|
"\tCalcDelta ms" |
|
|
|
"\tEncode calls" |
|
"\tEncode ms" |
|
|
|
"\tShouldTransmit calls" |
|
"\tShouldTransmit ms" |
|
|
|
"\tWriteDeltaProps ms" |
|
|
|
"\t%% manual mode" |
|
|
|
"\tTotal" |
|
"\tPercent" |
|
"\n" |
|
); |
|
|
|
// Calculate totals. |
|
CCycleCount totalCalcDelta, totalEncode, totalShouldTransmit, totalDeltaProps; |
|
totalCalcDelta.Init(); |
|
totalEncode.Init(); |
|
totalShouldTransmit.Init(); |
|
|
|
FOR_EACH_LL( g_DTISendTables, i ) |
|
{ |
|
CDTISendTable *pTable = g_DTISendTables[i]; |
|
|
|
CCycleCount::Add( pTable->m_nCalcDeltaCycles, totalCalcDelta, totalCalcDelta ); |
|
CCycleCount::Add( pTable->m_nEncodeCycles, totalEncode, totalEncode ); |
|
CCycleCount::Add( pTable->m_nShouldTransmitCycles, totalShouldTransmit, totalShouldTransmit ); |
|
CCycleCount::Add( pTable->m_nWriteDeltaPropsCycles, totalDeltaProps, totalDeltaProps ); |
|
} |
|
|
|
|
|
FOR_EACH_LL( g_DTISendTables, j ) |
|
{ |
|
CDTISendTable *pTable = g_DTISendTables[j]; |
|
|
|
if ( !pTable->HadAnyAction() ) |
|
continue; |
|
|
|
CCycleCount total; |
|
CCycleCount::Add( pTable->m_nEncodeCycles, pTable->m_nCalcDeltaCycles, total ); |
|
CCycleCount::Add( pTable->m_nShouldTransmitCycles, total, total ); |
|
|
|
g_pFileSystem->FPrintf( fp, |
|
"%s" |
|
|
|
"\t%d" |
|
"\t%.3f" |
|
|
|
"\t%d" |
|
"\t%.3f" |
|
|
|
"\t%d" |
|
"\t%.3f" |
|
|
|
"\t%.3f" |
|
|
|
"\t%.2f" |
|
|
|
"\t%.3f" |
|
"\t%.3f" |
|
"\n", |
|
pTable->m_NetTableName.String(), |
|
|
|
pTable->m_nCalcDeltaCalls, |
|
pTable->m_nCalcDeltaCycles.GetMillisecondsF(), |
|
|
|
pTable->m_nEncodeCalls, |
|
pTable->m_nEncodeCycles.GetMillisecondsF(), |
|
|
|
pTable->m_nShouldTransmitCalls, |
|
pTable->m_nShouldTransmitCycles.GetMillisecondsF(), |
|
|
|
pTable->m_nWriteDeltaPropsCycles.GetMillisecondsF(), |
|
|
|
(float)pTable->m_nNoChanges * 100.0f / (pTable->m_nNoChanges + pTable->m_nChangeAutoDetects), |
|
|
|
total.GetMillisecondsF(), |
|
total.GetMillisecondsF() * 100 / runningTime.GetMillisecondsF() |
|
); |
|
} |
|
|
|
g_pFileSystem->FPrintf( fp, "\n\n" ); |
|
|
|
g_pFileSystem->FPrintf( fp, |
|
"Total profile ms:" |
|
"\t%.3f\n", |
|
runningTime.GetMillisecondsF() |
|
); |
|
|
|
g_pFileSystem->FPrintf( fp, |
|
"Total CalcDelta ms:" |
|
"\t%.3f" |
|
"\tPercent:" |
|
"\t%.3f\n", |
|
totalCalcDelta.GetMillisecondsF(), |
|
totalCalcDelta.GetMillisecondsF() * 100.0 / runningTime.GetMillisecondsF() |
|
); |
|
|
|
g_pFileSystem->FPrintf( fp, |
|
"Total Encode ms:" |
|
"\t%.3f" |
|
"\tPercent:" |
|
"\t%.3f\n", |
|
totalEncode.GetMillisecondsF(), |
|
totalEncode.GetMillisecondsF() * 100.0 / runningTime.GetMillisecondsF() |
|
); |
|
|
|
g_pFileSystem->FPrintf( fp, |
|
"Total ShouldTransmit ms:" |
|
"\t%.3f" |
|
"\tPercent:" |
|
"\t%.3f\n", |
|
totalShouldTransmit.GetMillisecondsF(), |
|
totalShouldTransmit.GetMillisecondsF() * 100.0 / runningTime.GetMillisecondsF() |
|
); |
|
|
|
g_pFileSystem->FPrintf( fp, |
|
"Total WriteDeltaProps ms:" |
|
"\t%.3f" |
|
"\tPercent:" |
|
"\t%.3f\n", |
|
totalDeltaProps.GetMillisecondsF(), |
|
totalDeltaProps.GetMillisecondsF() * 100.0 / runningTime.GetMillisecondsF() |
|
); |
|
|
|
g_pFileSystem->Close( fp ); |
|
|
|
Msg( "DTI: Wrote delta distances into %s.\n", g_pServerDTIFilename ); |
|
} |
|
|
|
|
|
// Write the delta distances. |
|
const char *pDeltaDistancesFilename = "dti_delta_distances.txt"; |
|
fp = g_pFileSystem->Open( pDeltaDistancesFilename, "wt", "LOGDIR" ); |
|
if( fp != FILESYSTEM_INVALID_HANDLE ) |
|
{ |
|
// Write the column labels. |
|
g_pFileSystem->FPrintf( fp, "ClassName" ); |
|
for ( int i=0; i < NUM_DELTA_DISTANCE_BANDS; i++ ) |
|
{ |
|
g_pFileSystem->FPrintf( fp, "\t<%d", (i+1) * DELTA_DISTANCE_BAND ); |
|
} |
|
g_pFileSystem->FPrintf( fp, "\n" ); |
|
|
|
// Now write the data. |
|
FOR_EACH_LL( g_DTISendTables, j ) |
|
{ |
|
CDTISendTable *pTable = g_DTISendTables[j]; |
|
|
|
if ( !pTable->HadAnyAction() ) |
|
continue; |
|
|
|
g_pFileSystem->FPrintf( fp, "%s", pTable->m_NetTableName.String() ); |
|
for ( int i=0; i < NUM_DELTA_DISTANCE_BANDS; i++ ) |
|
{ |
|
g_pFileSystem->FPrintf( fp, "\t%d", pTable->m_DistanceDeltaCounts[i] ); |
|
} |
|
g_pFileSystem->FPrintf( fp, "\n" ); |
|
} |
|
|
|
g_pFileSystem->Close( fp ); |
|
|
|
Msg( "DTI: Wrote instrumentation data into %s.\n", pDeltaDistancesFilename ); |
|
} |
|
} |
|
|
|
|
|
CDTISendTable* ServerDTI_HookTable( SendTable *pTable ) |
|
{ |
|
if ( !g_bServerDTIEnabled ) |
|
return NULL; |
|
|
|
CDTISendTable *pRet = new CDTISendTable; |
|
memset( pRet, 0, sizeof( *pRet ) ); |
|
|
|
pRet->m_NetTableName.Set( pTable->m_pNetTableName ); |
|
|
|
g_DTISendTables.AddToTail( pRet ); |
|
return pRet; |
|
} |
|
|
|
|
|
void ServerDTI_AddEntityEncodeEvent( SendTable *pSendTable, float distToPlayer ) |
|
{ |
|
CSendTablePrecalc *pPrecalc = pSendTable->m_pPrecalc; |
|
if ( !pPrecalc || !pPrecalc->m_pDTITable ) |
|
return; |
|
|
|
CDTISendTable *pTable = pPrecalc->m_pDTITable; |
|
if ( !pTable ) |
|
return; |
|
|
|
int iDist = (int)( distToPlayer / DELTA_DISTANCE_BAND ); |
|
iDist = clamp( iDist, 0, NUM_DELTA_DISTANCE_BANDS - 1 ); |
|
pTable->m_DistanceDeltaCounts[iDist]++; |
|
} |
|
|
|
void _ServerDTI_HookTimer( const SendTable *pSendTable, ServerDTITimerType timerType, CCycleCount const &count ) |
|
{ |
|
CSendTablePrecalc *pPrecalc = pSendTable->m_pPrecalc; |
|
if ( !pPrecalc || !pPrecalc->m_pDTITable ) |
|
return; |
|
|
|
CDTISendTable *pTable = pPrecalc->m_pDTITable; |
|
|
|
if ( g_bFirstHookTimer ) |
|
{ |
|
g_ServerDTITimer.Sample(); |
|
g_bFirstHookTimer = false; |
|
} |
|
|
|
// Add to the total cycles. |
|
CCycleCount::Add( count, g_TotalServerDTICycles, g_TotalServerDTICycles ); |
|
|
|
if ( timerType == SERVERDTI_CALCDELTA ) |
|
{ |
|
CCycleCount::Add( count, pTable->m_nCalcDeltaCycles, pTable->m_nCalcDeltaCycles ); |
|
++pTable->m_nCalcDeltaCalls; |
|
} |
|
else if ( timerType == SERVERDTI_ENCODE ) |
|
{ |
|
CCycleCount::Add( count, pTable->m_nEncodeCycles, pTable->m_nEncodeCycles ); |
|
++pTable->m_nEncodeCalls; |
|
} |
|
else if ( timerType == SERVERDTI_SHOULDTRANSMIT ) |
|
{ |
|
CCycleCount::Add( count, pTable->m_nShouldTransmitCycles, pTable->m_nShouldTransmitCycles ); |
|
++pTable->m_nShouldTransmitCalls; |
|
} |
|
else if ( timerType == SERVERDTI_WRITE_DELTA_PROPS ) |
|
{ |
|
CCycleCount::Add( count, pTable->m_nWriteDeltaPropsCycles, pTable->m_nWriteDeltaPropsCycles ); |
|
} |
|
} |
|
|
|
void _ServerDTI_RegisterNetworkStateChange( SendTable *pSendTable, bool bStateChanged ) |
|
{ |
|
CSendTablePrecalc *pPrecalc = pSendTable->m_pPrecalc; |
|
if ( !pPrecalc || !pPrecalc->m_pDTITable ) |
|
return; |
|
|
|
CDTISendTable *pTable = pPrecalc->m_pDTITable; |
|
|
|
if ( bStateChanged ) |
|
++pTable->m_nChangeAutoDetects; |
|
else |
|
++pTable->m_nNoChanges; |
|
} |
|
|
|
|