Files
GTASource/game/system/PMCPerfControl.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

278 lines
8.5 KiB
C++

//
// filename: PMCPerfControl.h
// description:
//
#ifndef INC_PMCPERFCONTROL_H_
#define INC_PMCPERFCONTROL_H_
// --- Include Files ------------------------------------------------------------
// C headers
// Rage headers
// Game headers
#if __XENON && !__FINAL && __BANK
#include <pmcpb.h>
#include <pmcpbsetup.h>
#include "Debug/Debug.h"
#include "bank/bkmgr.h"
#include "grcore/debugdraw.h"
#pragma comment(lib, "libpmcpb.lib")
#define PMCPB_PERF_REPORTS 1
#else
#define PMCPB_PERF_REPORTS 0
#endif
// --- Defines ------------------------------------------------------------------
// --- Constants ----------------------------------------------------------------
// --- Structure/Class Definitions ----------------------------------------------
#if PMCPB_PERF_REPORTS
// This structure defines a CPU performance counter that can be displayed
// on the GTA HUD. It also records the values so that they can be displayed
// every frame, instead of just on the frames when fresh values are retrieved.
struct PerfCounter
{
// Which libpmcpb setup contains the desired counter?
ePMCSetup whichSetup;
// Which counter (0 to 15) is the one you are interested in? This is best
// found by dumping a set of counters to the debug output, finding a
// counter you are interested in, and noting its index in the first column.
// Note that the values of a few of the counters -- mostly instructions
// executed per frame -- are changed in the June 2007 XDK, to correct them
// from being half the number of instructions.
int counterIndex;
// What name should be displayed for this counter?
const char* label;
// These members store the most recent value and other information about the
// counters. They need to be zero initialized initially.
unsigned int value;
unsigned int maximum;
unsigned int frameCount; // For calculating average
unsigned __int64 total; // For calculating average
};
// List of performance counters to display on the HUD. For best results these
// should be grouped by which setup they use so that the code can cycle through
// the different setups efficiently.
static PerfCounter counters[] =
{
{
PMC_SETUP_OVERVIEW_PB0T0, 6, "T0 LHS"
},
{
PMC_SETUP_OVERVIEW_PB0T0, 1, "T0 flushes"
},
{
PMC_SETUP_OVERVIEW_PB0T0, 0, "T0 i-cache miss cycles"
},
{
PMC_SETUP_OVERVIEW_PB0T0, 14, "Core 0 L2 misses"
},
{
PMC_SETUP_OVERVIEW_PB0T0, 15, "Core 1 L2 misses"
},
{
PMC_SETUP_OVERVIEW_PB0T0, 8, "Core 2 L2 misses"
},
{
PMC_SETUP_OVERVIEW_PB1T1, 2, "T3 LHS"
},
{
PMC_SETUP_OVERVIEW_PB1T1, 9, "T3 flushes"
},
{
PMC_SETUP_OVERVIEW_PB1T1, 8, "T3 i-cache miss cycles"
},
};
// This class controls the displaying of performance counters on the HUD
// and in the debugger output, both individual counters and complete
// counter sets. You have to call StartFrame/EndFrame to make it run.
class PMCPerfControl
{
public:
PMCPerfControl()
{
memset(dumpThreadOverviews, 0, sizeof(dumpThreadOverviews));
memset(dumpThreadFlushCauses, 0, sizeof(dumpThreadFlushCauses));
dumpHUDCounters = false;
enableHUDCounters = false;
bkBank *bank = BANKMGR.FindBank("PerfStuff");
if(bank==NULL)
{
bank = &BANKMGR.CreateBank("PerfStuff");
bank->AddToggle("Dump Thread 0 Overview", &dumpThreadOverviews[0]);
bank->AddToggle("Dump Thread 0 Flushes", &dumpThreadFlushCauses[0]);
bank->AddToggle("Dump Thread 2 Overview", &dumpThreadOverviews[2]);
bank->AddToggle("Dump Thread 2 Flushes", &dumpThreadFlushCauses[2]);
bank->AddToggle("Dump Thread 3 Overview", &dumpThreadOverviews[3]);
bank->AddToggle("Dump Thread 3 Flushes", &dumpThreadFlushCauses[3]);
bank->AddToggle("Dump HUD counters", &dumpHUDCounters);
// If you use the libpmcpb performance counters (i.e.; if you
// enable the HUD counters) then the sampling
// profiler and the instrumented profiler (both in XbPerfView) will
// not work because they rely on these performance counters.
bank->AddToggle("Enable HUD counters (breaks CPU profilers)", &enableHUDCounters);
}
nextPerfCounter = 0;
}
void StartFrame()
{
getHUDCounters = false;
dumpCounterSet = false;
for (int i = 0; i < _countof(dumpThreadOverviews) && !dumpCounterSet; ++i)
{
if (dumpThreadOverviews[i])
{
// Dump the flush reasons counter set for the appropriate thread.
StartTimers((ePMCSetup)(PMC_SETUP_OVERVIEW_PB0T0 + i));
// Only dump the counters once each time they are requested.
dumpThreadOverviews[i] = false;
dumpCounterSet = true;
}
}
for (int i = 0; i < _countof(dumpThreadFlushCauses) && !dumpCounterSet; ++i)
{
if (dumpThreadFlushCauses[i])
{
// Dump the flush reasons counter set for the appropriate thread.
StartTimers((ePMCSetup)(PMC_SETUP_FLUSHREASONS_PB0T0 + i));
// Only dump the counters once each time they are requested.
dumpThreadFlushCauses[i] = false;
dumpCounterSet = true;
}
}
// If we aren't dumping a complete counter set, and if the user has the HUD
// counters enabled, then start up the next counter set.
if (!dumpCounterSet && enableHUDCounters)
{
// Select a set of sixteen counters
StartTimers( counters[nextPerfCounter].whichSetup );
getHUDCounters = true;
}
}
void EndFrame()
{
if (dumpCounterSet)
StopTimersAndDumpResults();
if (getHUDCounters)
{
// Stop the counters.
PMCStop();
// Get the current values of the counters
PMCState pmcstate;
PMCGetCounters( &pmcstate );
// Grab all the counter values that use the current counter set.
ePMCSetup currentSetup = counters[nextPerfCounter].whichSetup;
for (int i = 0; i < _countof(counters); ++i)
{
if (counters[i].whichSetup == currentSetup)
{
counters[i].value = (unsigned)pmcstate.pmc[counters[i].counterIndex];
// If the frame was of a reasonable length (less than 1/10th of a second)
// then add the statistics into the average/maximum/etc. Longer frames
// probably indicate that we were broken in the debugger, doing a loading
// screen, or otherwise anomalous behavior.
if (pmcstate.ticks < 5000000)
{
counters[i].frameCount++;
counters[i].total += counters[i].value;
if (counters[i].value > counters[i].maximum)
counters[i].maximum = counters[i].value;
}
}
}
// Move to the next counter, skipping over any adjacent counters that use the
// same counter set.
while (nextPerfCounter < _countof(counters) && counters[nextPerfCounter].whichSetup == currentSetup)
++nextPerfCounter;
if (nextPerfCounter >= _countof(counters))
nextPerfCounter = 0;
}
if (enableHUDCounters)
{
// Display all of our counters. Some of the values may be a few frames old. Oh well.
for (int i = 0; i < _countof(counters); ++i)
{
if (counters[i].frameCount)
{
// Display the counter to the HUD, and optionally print it to
// the debugger output.
char buffer[1000];
sprintf(buffer, "%s = %dK, max = %dK, avg = %dK", counters[i].label, counters[i].value / 1000, counters[i].maximum / 1000, (int)(counters[i].total / (counters[i].frameCount * 1000)));
grcDebugDraw::AddDebugOutput(buffer);
if (dumpHUDCounters)
Printf("%s\n", buffer);
}
}
// When dumpHUDCounters is requested only dump them once.
if (dumpHUDCounters)
{
Printf("\n");
dumpHUDCounters = false;
}
}
}
private:
void StartTimers(ePMCSetup
#if _XDK_VER < 7978
whichSetup
#endif
)
{
#if _XDK_VER < 7978
// Select a set of sixteen counters
PMCInstallSetup( &PMCDefaultSetups[whichSetup] );
#endif
// Reset the Performance Monitor Counters in preparation for a new sampling run.
PMCResetCounters();
// To make this code work on cores other than 0 we have to tell
// the PMC library what core we are running on.
//PMCSetTriggerProcessor(GetCurrentProcessorNumber() / 2);
// Start up the Performance Monitor Counters.
PMCStart(); // Start up counters
}
void StopTimersAndDumpResults()
{
PMCStop();
PMCState pmcstate;
PMCGetCounters( &pmcstate );
PMCDumpCountersVerbose( &pmcstate, PMC_VERBOSE_NOL2ECC );
Printf("\n");
}
int nextPerfCounter;
bool getHUDCounters;
bool dumpCounterSet;
static const int numHardwareThreads = 6;
bool dumpThreadOverviews[numHardwareThreads];
bool dumpThreadFlushCauses[numHardwareThreads];
bool dumpHUDCounters;
bool enableHUDCounters;
};
#else
class PMCPerfControl
{
public:
PMCPerfControl() {}
void StartFrame() {}
void EndFrame() {}
};
#endif
// --- Globals ------------------------------------------------------------------
#endif // !INC_PMCPERFCONTROL_H_