AMD GPUPerfAPI 3.0 Preview Integration.

Direct3D11, Direct3D12, OpenGL, and Vulkan supported.
Fixes Direct3D11 counter command isolation.
This commit is contained in:
herb marselas
2018-02-28 12:10:36 +00:00
committed by baldurk
parent e5350505c0
commit f720cd1e7d
26 changed files with 1242 additions and 216 deletions
+442 -70
View File
@@ -23,29 +23,84 @@
******************************************************************************/
#include "amd_counters.h"
#include <Windows.h>
#include "common/common.h"
#include "common/timing.h"
#include "core/plugins.h"
#include "official/GPUPerfAPI/Include/GPUPerfAPI.h"
#include "official/GPUPerfAPI/Include/GPUPerfAPIFunctionTypes.h"
#include "strings/string_utils.h"
inline bool AMD_FAILED(GPA_Status status)
{
return status != GPA_STATUS_OK;
}
inline bool AMD_SUCCEEDED(GPA_Status status)
{
return status == GPA_STATUS_OK;
}
static void GPA_LoggingCallback(GPA_Logging_Type messageType, const char *pMessage)
{
if(messageType == GPA_LOGGING_ERROR)
{
RDCWARN(pMessage);
}
else
{
RDCLOG(pMessage);
}
}
AMDCounters::AMDCounters() : m_pGPUPerfAPI(NULL)
{
}
bool AMDCounters::Init(void *pContext)
std::string AMDCounters::FormatErrMessage(const char *operation, uint32_t status)
{
const char *dllName = "GPUPerfAPIDX11-x64.dll";
std::string err =
StringFormat::Fmt("%s. %s", operation, m_pGPUPerfAPI->GPA_GetStatusAsStr((GPA_Status)status));
return err;
}
bool AMDCounters::Init(ApiType apiType, void *pContext)
{
#if DISABLED(RDOC_WIN32) && DISABLED(RDOC_LINUX)
return false;
#else
std::string dllName("GPUPerfAPI");
switch(apiType)
{
case ApiType::Dx11: dllName += "DX11"; break;
case ApiType::Dx12: dllName += "DX12"; break;
case ApiType::Ogl: dllName += "GL"; break;
case ApiType::Vk: dllName += "VK"; break;
default:
RDCWARN(
"AMD GPU performance counters could not be initialized successfully. "
"Unsupported API type specified");
return false;
}
#if ENABLED(RDOC_WIN32)
#if ENABLED(RDOC_X64)
dllName += "-x64";
#endif
dllName += ".dll";
#else
dllName = "lib" + dllName;
dllName += ".so";
#endif
// first try in the plugin location it will be in distributed builds
HMODULE module = LoadLibraryA(LocatePluginFile("amd/counters", dllName).c_str());
std::string dllPath = LocatePluginFile("amd/counters", dllName.c_str());
// if that failed then try checking for it just in the default search path
void *module = Process::LoadModule(dllPath.c_str());
if(module == NULL)
{
module = LoadLibraryA(dllName);
module = Process::LoadModule(dllName.c_str());
}
if(module == NULL)
@@ -53,39 +108,52 @@ bool AMDCounters::Init(void *pContext)
RDCWARN(
"AMD GPU performance counters could not be initialized successfully. "
"Are you missing the DLLs?");
return false;
}
m_pGPUPerfAPI = new GPAApi();
GPA_GetFuncTablePtrType getFuncTable =
(GPA_GetFuncTablePtrType)GetProcAddress(module, "GPA_GetFuncTable");
(GPA_GetFuncTablePtrType)Process::GetFunctionAddress(module, "GPA_GetFuncTable");
m_pGPUPerfAPI = new GPAApi();
if(getFuncTable)
{
getFuncTable((void **)&m_pGPUPerfAPI);
}
else
{
RDCWARN(
"GPA version is out of date, doesn't expose GPA_GetFuncTable. Make sure you have 3.0 or "
"above.");
delete m_pGPUPerfAPI;
GPA_LoggingCallback(GPA_LOGGING_ERROR,
"Failed to get GPA function table. Invalid dynamic library?");
return false;
}
GPA_Logging_Type loggingType = GPA_LOGGING_ERROR;
#if ENABLED(RDOC_DEVEL)
loggingType = GPA_LOGGING_ERROR_AND_MESSAGE;
#endif
GPA_Status status = m_pGPUPerfAPI->GPA_RegisterLoggingCallback(loggingType, GPA_LoggingCallback);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Failed to initialize logging", status).c_str());
return false;
}
status = m_pGPUPerfAPI->GPA_Initialize();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Initialization failed", status).c_str());
delete m_pGPUPerfAPI;
m_pGPUPerfAPI = NULL;
return false;
}
if(m_pGPUPerfAPI->GPA_Initialize() != GPA_STATUS_OK)
{
delete m_pGPUPerfAPI;
m_pGPUPerfAPI = NULL;
return false;
}
if(m_pGPUPerfAPI->GPA_OpenContext(pContext, GPA_OPENCONTEXT_HIDE_PUBLIC_COUNTERS_BIT |
GPA_OPENCONTEXT_CLOCK_MODE_PEAK_BIT) !=
GPA_STATUS_OK)
status = m_pGPUPerfAPI->GPA_OpenContext(
pContext, GPA_OPENCONTEXT_HIDE_SOFTWARE_COUNTERS_BIT | GPA_OPENCONTEXT_CLOCK_MODE_PEAK_BIT);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Open context for counters failed", status).c_str());
m_pGPUPerfAPI->GPA_Destroy();
delete m_pGPUPerfAPI;
m_pGPUPerfAPI = NULL;
@@ -95,66 +163,127 @@ bool AMDCounters::Init(void *pContext)
m_Counters = EnumerateCounters();
return true;
#endif
}
AMDCounters::~AMDCounters()
{
if(m_pGPUPerfAPI)
{
GPA_Status status = GPA_STATUS_OK;
GPA_Status status = m_pGPUPerfAPI->GPA_CloseContext();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Close context failed", status).c_str());
}
status = m_pGPUPerfAPI->GPA_CloseContext();
status = m_pGPUPerfAPI->GPA_Destroy();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Destroy failed", status).c_str());
}
delete m_pGPUPerfAPI;
}
}
vector<AMDCounters::InternalCounterDescription> AMDCounters::EnumerateCounters()
std::map<uint32_t, CounterDescription> AMDCounters::EnumerateCounters()
{
std::map<uint32_t, CounterDescription> counters;
gpa_uint32 num;
m_pGPUPerfAPI->GPA_GetNumCounters(&num);
vector<InternalCounterDescription> counters;
GPA_Status status = m_pGPUPerfAPI->GPA_GetNumCounters(&num);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get number of counters", status).c_str());
return counters;
}
for(uint32_t i = 0; i < num; ++i)
{
InternalCounterDescription internalDesc;
internalDesc.desc = InternalGetCounterDescription(i);
GPA_Usage_Type usageType;
internalDesc.internalIndex = i;
internalDesc.desc.counter = MakeAMDCounter(i);
counters.push_back(internalDesc);
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(i, &usageType);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get counter usage type.", status).c_str());
return counters;
}
// Ignore percentage counters due to aggregate roll-up support
if(usageType == GPA_USAGE_TYPE_PERCENTAGE)
{
continue;
}
CounterDescription desc = InternalGetCounterDescription(i);
desc.counter = MakeAMDCounter(i);
counters[i] = desc;
m_PublicToInternalCounter[desc.counter] = i;
}
return counters;
}
uint32_t AMDCounters::GetNumCounters()
std::vector<GPUCounter> AMDCounters::GetPublicCounterIds() const
{
return (uint32_t)m_Counters.size();
std::vector<GPUCounter> ret;
for(const std::pair<GPUCounter, uint32_t> &entry : m_PublicToInternalCounter)
ret.push_back(entry.first);
return ret;
}
CounterDescription AMDCounters::GetCounterDescription(GPUCounter counter)
{
return m_Counters[GPUCounterToCounterIndex(counter)].desc;
return m_Counters[m_PublicToInternalCounter[counter]];
}
CounterDescription AMDCounters::InternalGetCounterDescription(uint32_t internalIndex)
{
CounterDescription desc = {};
const char *tmp = NULL;
m_pGPUPerfAPI->GPA_GetCounterName(internalIndex, &tmp);
GPA_Status status = m_pGPUPerfAPI->GPA_GetCounterName(internalIndex, &tmp);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Get counter name.", status).c_str());
return desc;
}
desc.name = tmp;
m_pGPUPerfAPI->GPA_GetCounterDescription(internalIndex, &tmp);
status = m_pGPUPerfAPI->GPA_GetCounterDescription(internalIndex, &tmp);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get counter description.", status).c_str());
return desc;
}
desc.description = tmp;
m_pGPUPerfAPI->GPA_GetCounterCategory(internalIndex, &tmp);
status = m_pGPUPerfAPI->GPA_GetCounterCategory(internalIndex, &tmp);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Get counter category.", status).c_str());
return desc;
}
desc.category = tmp;
GPA_Usage_Type usageType;
m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get counter usage type.", status).c_str());
return desc;
}
switch(usageType)
{
@@ -184,7 +313,13 @@ CounterDescription AMDCounters::InternalGetCounterDescription(uint32_t internalI
GPA_Type type;
m_pGPUPerfAPI->GPA_GetCounterDataType(internalIndex, &type);
status = m_pGPUPerfAPI->GPA_GetCounterDataType(internalIndex, &type);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get counter data type.", status).c_str());
return desc;
}
// results should either be float32/64 or uint32/64 as the GetSample functions only support those
switch(type)
@@ -227,41 +362,164 @@ CounterDescription AMDCounters::InternalGetCounterDescription(uint32_t internalI
void AMDCounters::EnableCounter(GPUCounter counter)
{
const uint32_t internalIndex = m_Counters[GPUCounterToCounterIndex(counter)].internalIndex;
const uint32_t internalIndex = m_PublicToInternalCounter[counter];
m_pGPUPerfAPI->GPA_EnableCounter(internalIndex);
GPA_Status status = m_pGPUPerfAPI->GPA_EnableCounter(internalIndex);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Enable counter.", status).c_str());
}
}
void AMDCounters::EnableAllCounters()
{
m_pGPUPerfAPI->GPA_EnableAllCounters();
GPA_Status status = m_pGPUPerfAPI->GPA_EnableAllCounters();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Enable all counters.", status).c_str());
}
}
void AMDCounters::DisableAllCounters()
{
m_pGPUPerfAPI->GPA_DisableAllCounters();
GPA_Status status = m_pGPUPerfAPI->GPA_DisableAllCounters();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Disable all counters.", status).c_str());
}
}
uint32_t AMDCounters::GetPassCount()
{
gpa_uint32 numRequiredPasses;
m_pGPUPerfAPI->GPA_GetPassCount(&numRequiredPasses);
gpa_uint32 numRequiredPasses = 0;
GPA_Status status = m_pGPUPerfAPI->GPA_GetPassCount(&numRequiredPasses);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Get pass count.", status).c_str());
}
return (uint32_t)numRequiredPasses;
}
uint32_t AMDCounters::BeginSession()
{
gpa_uint32 sessionID;
gpa_uint32 sessionID = 0;
m_pGPUPerfAPI->GPA_BeginSession(&sessionID);
GPA_Status status = m_pGPUPerfAPI->GPA_BeginSession(&sessionID);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Begin session.", status).c_str());
}
return (uint32_t)sessionID;
}
void AMDCounters::EndSesssion()
{
m_pGPUPerfAPI->GPA_EndSession();
GPA_Status status = m_pGPUPerfAPI->GPA_EndSession();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("End session.", status).c_str());
}
}
std::vector<CounterResult> AMDCounters::GetCounterData(uint32_t sessionID, uint32_t maxSampleIndex,
const std::vector<uint32_t> &eventIDs,
const std::vector<GPUCounter> &counters)
{
std::vector<CounterResult> ret;
bool isReady = false;
const uint32_t timeoutPeriod = 10000; // ms
PerformanceTimer timeout;
do
{
isReady = IsSessionReady(sessionID);
if(!isReady)
{
Threading::Sleep(0);
PerformanceTimer endTime;
if(timeout.GetMilliseconds() > timeoutPeriod)
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, "GetCounterData failed due to elapsed timeout.");
return ret;
}
}
} while(!isReady);
for(uint32_t s = 0; s < maxSampleIndex; s++)
{
for(size_t c = 0; c < counters.size(); c++)
{
const CounterDescription desc = GetCounterDescription(counters[c]);
switch(desc.resultType)
{
case CompType::UInt:
{
if(desc.resultByteWidth == sizeof(uint32_t))
{
uint32_t value = GetSampleUint32(sessionID, s, counters[c]);
if(desc.unit == CounterUnit::Percentage)
{
value = RDCCLAMP(value, 0U, 100U);
}
ret.push_back(CounterResult(eventIDs[s], counters[c], value));
}
else if(desc.resultByteWidth == sizeof(uint64_t))
{
uint64_t value = GetSampleUint64(sessionID, s, counters[c]);
if(desc.unit == CounterUnit::Percentage)
{
value = RDCCLAMP(value, (uint64_t)0, (uint64_t)100);
}
ret.push_back(CounterResult(eventIDs[s], counters[c], value));
}
else
{
RDCERR("Unexpected byte width %u", desc.resultByteWidth);
}
}
break;
case CompType::Float:
{
float value = GetSampleFloat32(sessionID, s, counters[c]);
if(desc.unit == CounterUnit::Percentage)
{
value = RDCCLAMP(value, 0.0f, 100.0f);
}
ret.push_back(CounterResult(eventIDs[s], counters[c], value));
}
break;
case CompType::Double:
{
double value = GetSampleFloat64(sessionID, s, counters[c]);
if(desc.unit == CounterUnit::Percentage)
{
value = RDCCLAMP(value, 0.0, 100.0);
}
ret.push_back(CounterResult(eventIDs[s], counters[c], value));
}
break;
default: RDCASSERT(0); break;
};
}
}
return ret;
}
bool AMDCounters::IsSessionReady(uint32_t sessionIndex)
@@ -269,98 +527,212 @@ bool AMDCounters::IsSessionReady(uint32_t sessionIndex)
gpa_uint8 readyResult = 0;
GPA_Status status = m_pGPUPerfAPI->GPA_IsSessionReady(&readyResult, sessionIndex);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Is session ready", status).c_str());
}
return readyResult && status == GPA_STATUS_OK;
}
void AMDCounters::BeginPass()
{
m_pGPUPerfAPI->GPA_BeginPass();
GPA_Status status = m_pGPUPerfAPI->GPA_BeginPass();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Begin pass.", status).c_str());
}
}
void AMDCounters::EndPass()
{
m_pGPUPerfAPI->GPA_EndPass();
GPA_Status status = m_pGPUPerfAPI->GPA_EndPass();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("End pass.", status).c_str());
}
}
void AMDCounters::BeginSample(uint32_t index)
{
m_pGPUPerfAPI->GPA_BeginSample(index);
GPA_Status status = m_pGPUPerfAPI->GPA_BeginSample(index);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Begin sample.", status).c_str());
}
}
void AMDCounters::EndSample()
{
m_pGPUPerfAPI->GPA_EndSample();
GPA_Status status = m_pGPUPerfAPI->GPA_EndSample();
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("End sample.", status).c_str());
}
}
void AMDCounters::BeginSampleList(void *pSampleList)
{
GPA_Status status = m_pGPUPerfAPI->GPA_BeginSampleList(pSampleList);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("BeginSampleList.", status).c_str());
}
}
void AMDCounters::EndSampleList(void *pSampleList)
{
GPA_Status status = m_pGPUPerfAPI->GPA_EndSampleList(pSampleList);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("EndSampleList.", status).c_str());
}
}
void AMDCounters::BeginSampleInSampleList(uint32_t sampleID, void *pSampleList)
{
GPA_Status status = m_pGPUPerfAPI->GPA_BeginSampleInSampleList(sampleID, pSampleList);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("BeginSampleInSampleList.", status).c_str());
}
}
void AMDCounters::EndSampleInSampleList(void *pSampleList)
{
GPA_Status status = m_pGPUPerfAPI->GPA_EndSampleInSampleList(pSampleList);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("EndSampleInSampleList.", status).c_str());
}
}
uint32_t AMDCounters::GetSampleUint32(uint32_t session, uint32_t sample, GPUCounter counter)
{
const uint32_t internalIndex = m_Counters[GPUCounterToCounterIndex(counter)].internalIndex;
uint32_t value;
const uint32_t internalIndex = m_PublicToInternalCounter[counter];
uint32_t value = 0;
m_pGPUPerfAPI->GPA_GetSampleUInt32(session, sample, internalIndex, &value);
GPA_Status status = m_pGPUPerfAPI->GPA_GetSampleUInt32(session, sample, internalIndex, &value);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Get sample uint32.", status).c_str());
return value;
}
// normalise units as expected
GPA_Usage_Type usageType;
m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get counter usage type.", status).c_str());
return value;
}
if(usageType == GPA_USAGE_TYPE_KILOBYTES)
{
value *= 1000;
}
return value;
}
uint64_t AMDCounters::GetSampleUint64(uint32_t session, uint32_t sample, GPUCounter counter)
{
const uint32_t internalIndex = m_Counters[GPUCounterToCounterIndex(counter)].internalIndex;
gpa_uint64 value;
const uint32_t internalIndex = m_PublicToInternalCounter[counter];
gpa_uint64 value = 0;
m_pGPUPerfAPI->GPA_GetSampleUInt64(session, sample, internalIndex, &value);
GPA_Status status = m_pGPUPerfAPI->GPA_GetSampleUInt64(session, sample, internalIndex, &value);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Get sample uint64.", status).c_str());
return value;
}
// normalise units as expected
GPA_Usage_Type usageType;
m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get counter usage type.", status).c_str());
return value;
}
if(usageType == GPA_USAGE_TYPE_KILOBYTES)
{
value *= 1000;
}
return value;
}
float AMDCounters::GetSampleFloat32(uint32_t session, uint32_t sample, GPUCounter counter)
{
const uint32_t internalIndex = m_Counters[GPUCounterToCounterIndex(counter)].internalIndex;
float value;
const uint32_t internalIndex = m_PublicToInternalCounter[counter];
float value = 0;
m_pGPUPerfAPI->GPA_GetSampleFloat32(session, sample, internalIndex, &value);
GPA_Status status = m_pGPUPerfAPI->GPA_GetSampleFloat32(session, sample, internalIndex, &value);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Get sample float32.", status).c_str());
return value;
}
// normalise units as expected
GPA_Usage_Type usageType;
m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get counter usage type.", status).c_str());
return value;
}
if(usageType == GPA_USAGE_TYPE_KILOBYTES)
{
value *= 1000.0f;
}
else if(usageType == GPA_USAGE_TYPE_MILLISECONDS)
{
value /= 1000.0f;
}
return value;
}
double AMDCounters::GetSampleFloat64(uint32_t session, uint32_t sample, GPUCounter counter)
{
const uint32_t internalIndex = m_Counters[GPUCounterToCounterIndex(counter)].internalIndex;
const uint32_t internalIndex = m_PublicToInternalCounter[counter];
double value;
m_pGPUPerfAPI->GPA_GetSampleFloat64(session, sample, internalIndex, &value);
GPA_Status status = m_pGPUPerfAPI->GPA_GetSampleFloat64(session, sample, internalIndex, &value);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR, FormatErrMessage("Get sample float64.", status).c_str());
return value;
}
// normalise units as expected
GPA_Usage_Type usageType;
m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
status = m_pGPUPerfAPI->GPA_GetCounterUsageType(internalIndex, &usageType);
if(AMD_FAILED(status))
{
GPA_LoggingCallback(GPA_LOGGING_ERROR,
FormatErrMessage("Get counter usage type.", status).c_str());
return value;
}
if(usageType == GPA_USAGE_TYPE_KILOBYTES)
{
value *= 1000.0;
}
else if(usageType == GPA_USAGE_TYPE_MILLISECONDS)
{
value /= 1000.0;
}
return value;
}