PVRScopeStats API usage#
This is a minimal example showing how to read IMG GPU counters via the PVRScopeStats API.
Ideally for this example to show something interesting an application that utilises the GPU should be running in parallel to the example code.
The example will perform the following steps:
Initialise PVRScope. If an error is encountered then the example will print the error string and exit with code 1.
Set the active counter group to 0.
Then in a loop for ~6 seconds:
Read the GPU counters.
Conditionally (if there are new definitions to be acquired) get the counter definitions.
Loop over the counter readings array, printing the counter name and reading for this sample.
Prints to
logcat
on Android platforms, and otherwise tostdout
.
Deinitialise PVRScope and exit with code 0.
#include <chrono>
#include <thread>
#include "PVRScopeStats.h"
#if defined(__ANDROID__)
#include <android/log.h>
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "PVRScope", __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "PVRScope", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , "PVRScope", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , "PVRScope", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "PVRScope", __VA_ARGS__)
#else
#include <cstdio>
#define LOG(...) printf(__VA_ARGS__)
#define LOGV(...) LOG(__VA_ARGS__)
#define LOGD(...) LOG(__VA_ARGS__)
#define LOGI(...) LOG(__VA_ARGS__)
#define LOGW(...) LOG(__VA_ARGS__)
#define LOGE(...) LOG(__VA_ARGS__)
#endif
using namespace std::chrono_literals;
static const char* InitErrorToStr(EPVRScopeInitCode eError)
{
switch (eError)
{
case EPVRScopeInitCode::ePVRScopeInitCodeOk: return "Ok";
case EPVRScopeInitCode::ePVRScopeInitCodeOutOfMem: return "Out of memory";
case EPVRScopeInitCode::ePVRScopeInitCodeDriverSupportNotFound: return "Driver support not found";
case EPVRScopeInitCode::ePVRScopeInitCodeDriverSupportInsufficient: return "Driver support insufficient";
case EPVRScopeInitCode::ePVRScopeInitCodeDriverSupportInitFailed: return "Driver initialisation failed";
case EPVRScopeInitCode::ePVRScopeInitCodeDriverSupportQueryInfoFailed: return "Driver information query failed";
default: return "Unknown";
}
}
int main()
{
SPVRScopeImplData *PVRScopeStatsData = nullptr;
const EPVRScopeInitCode eInitRet = PVRScopeInitialise(&PVRScopeStatsData);
if (ePVRScopeInitCodeOk == eInitRet)
{
LOGI("Initialised services connection.\n");
}
else
{
LOGE("PVRScope failed to initialise with error: %s.\n", InitErrorToStr(eInitRet));
return 1;
}
constexpr unsigned int nGroup = 0U;
constexpr unsigned int NUMBER_OF_LOOPS = 60U;
PVRScopeSetGroup(PVRScopeStatsData, nGroup);
unsigned int numCounters = 0U;
unsigned int nIteration = 0U;
SPVRScopeCounterDef *counterDefinitions = nullptr;
SPVRScopeCounterReading counterReading{};
while (nIteration++ < NUMBER_OF_LOOPS)
{
LOGI("Iteration %d\n", nIteration);
if (PVRScopeReadCounters(PVRScopeStatsData, &counterReading))
{
unsigned int iReadingIdx = 0U;
for (unsigned int iCounter = 0U; iCounter < numCounters && iReadingIdx < counterReading.nValueCnt; iCounter++)
{
if (counterDefinitions[iCounter].nGroup == nGroup)
{
const char* const counterName = counterDefinitions[iCounter].pszName;
const float counterValue = counterReading.pfValueBuf[iReadingIdx++];
if (counterDefinitions[iCounter].nBoolPercentage)
LOGI(" %s: %f%%\n", counterName, counterValue);
else
LOGI(" %s: %f\n", counterName, counterValue);
}
}
// If we have too many results, there may be new counters available
if (iReadingIdx < counterReading.nValueCnt)
{
if (PVRScopeGetCounters(PVRScopeStatsData, &numCounters, &counterDefinitions, nullptr))
LOGI("%d counters enabled\n", numCounters);
}
}
else
{
LOGI("No data\n");
}
std::this_thread::sleep_for(100ms);
}
LOGI("Shutting down\n");
PVRScopeDeInitialise(&PVRScopeStatsData, &counterDefinitions, &counterReading);
return 0;
}