mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-29 13:20:54 +00:00
Add support for ARM counters
Adding support for ARM counters via a third-party lib. The main target platform is Android.
This commit is contained in:
committed by
Baldur Karlsson
parent
6a2415f334
commit
f1bd727dff
@@ -51,6 +51,7 @@ enum class CounterFamily
|
||||
Intel,
|
||||
NVIDIA,
|
||||
VulkanExtended,
|
||||
ARM,
|
||||
};
|
||||
|
||||
CounterFamily GetCounterFamily(GPUCounter counter)
|
||||
@@ -71,6 +72,10 @@ CounterFamily GetCounterFamily(GPUCounter counter)
|
||||
{
|
||||
return CounterFamily::VulkanExtended;
|
||||
}
|
||||
else if(IsARMCounter(counter))
|
||||
{
|
||||
return CounterFamily::ARM;
|
||||
}
|
||||
|
||||
return CounterFamily::Generic;
|
||||
}
|
||||
@@ -84,6 +89,7 @@ QString ToString(CounterFamily family)
|
||||
case CounterFamily::Intel: return lit("Intel");
|
||||
case CounterFamily::NVIDIA: return lit("NVIDIA");
|
||||
case CounterFamily::VulkanExtended: return lit("Vulkan Extended");
|
||||
case CounterFamily::ARM: return lit("ARM");
|
||||
case CounterFamily::Unknown: return lit("Unknown");
|
||||
}
|
||||
|
||||
|
||||
@@ -177,6 +177,10 @@ QTableWidgetItem *PerformanceCounterViewer::MakeCounterResultItem(const CounterR
|
||||
|
||||
case CounterUnit::Absolute:
|
||||
case CounterUnit::Ratio: break;
|
||||
|
||||
case CounterUnit::Hertz: returnValue += lit(" Hz"); break;
|
||||
case CounterUnit::Volt: returnValue += lit(" V"); break;
|
||||
case CounterUnit::Celsius: returnValue += lit(" °C"); break;
|
||||
}
|
||||
|
||||
return new CustomSortedTableItem(returnValue, SortValue(result, description));
|
||||
|
||||
@@ -83,6 +83,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NV", "renderdoc\driver\ihv\
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Intel", "renderdoc\driver\ihv\intel\Intel.vcxproj", "{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ARM", "renderdoc\driver\ihv\arm\ARM.vcxproj", "{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Development|x64 = Development|x64
|
||||
@@ -283,6 +285,14 @@ Global
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Release|x64.Build.0 = Release|x64
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Release|x86.ActiveCfg = Release|Win32
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5}.Release|x86.Build.0 = Release|Win32
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}.Development|x64.ActiveCfg = Development|x64
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}.Development|x64.Build.0 = Development|x64
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}.Development|x86.ActiveCfg = Development|Win32
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}.Development|x86.Build.0 = Development|Win32
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}.Release|x64.ActiveCfg = Release|x64
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}.Release|x64.Build.0 = Release|x64
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}.Release|x86.ActiveCfg = Release|Win32
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -318,5 +328,6 @@ Global
|
||||
{37955C79-D91D-423F-8C6C-8F5BCF4F28D4} = {B5A783D9-AEB9-420D-8E77-D4D930F8D88C}
|
||||
{40349AD9-5558-4DF4-84E2-11934DE90A11} = {4DA2F3E3-9A65-45DD-A69B-82C7757D4904}
|
||||
{7FCB5FC5-1DBD-4DA6-83A0-6BA4E945BDA5} = {4DA2F3E3-9A65-45DD-A69B-82C7757D4904}
|
||||
{F9CCE6CA-0CA3-4A22-9C7B-881369955E62} = {4DA2F3E3-9A65-45DD-A69B-82C7757D4904}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -502,6 +502,12 @@ if(ENABLE_GL OR ENABLE_GLES)
|
||||
list(APPEND renderdoc_objects $<TARGET_OBJECTS:rdoc_intel>)
|
||||
endif()
|
||||
|
||||
# pull in the ARM folder for perf query
|
||||
if(ENABLE_GL OR ENABLE_GLES)
|
||||
add_subdirectory(driver/ihv/arm)
|
||||
list(APPEND renderdoc_objects $<TARGET_OBJECTS:rdoc_arm>)
|
||||
endif()
|
||||
|
||||
add_library(rdoc OBJECT ${sources})
|
||||
target_compile_definitions(rdoc ${RDOC_DEFINITIONS})
|
||||
target_include_directories(rdoc ${RDOC_INCLUDES})
|
||||
|
||||
@@ -558,11 +558,22 @@ struct AndroidRemoteServer : public RemoteServer
|
||||
{
|
||||
ResetAndroidSettings();
|
||||
|
||||
// enable profiling to measure hardware counters
|
||||
Android::adbExecCommand(m_deviceID, "shell setprop security.perf_harden 0");
|
||||
|
||||
LazilyStartLogcatThread();
|
||||
|
||||
return RemoteServer::OpenCapture(proxyid, filename, opts, progress);
|
||||
}
|
||||
|
||||
virtual void CloseCapture(IReplayController *rend) override
|
||||
{
|
||||
// disable profiling
|
||||
Android::adbExecCommand(m_deviceID, "shell setprop security.perf_harden 1");
|
||||
|
||||
RemoteServer::CloseCapture(rend);
|
||||
}
|
||||
|
||||
virtual rdcstr GetHomeFolder() override { return ""; }
|
||||
virtual rdcarray<PathEntry> ListFolder(const char *path) override
|
||||
{
|
||||
|
||||
@@ -3229,7 +3229,10 @@ enum class GPUCounter : uint32_t
|
||||
FirstVulkanExtended = 4000000,
|
||||
LastNvidia = FirstVulkanExtended - 1,
|
||||
|
||||
LastVulkanExtended = 5000000,
|
||||
FirstARM = 5000000,
|
||||
LastVulkanExtended = FirstARM - 1,
|
||||
|
||||
LastARM = 6000000,
|
||||
};
|
||||
|
||||
ITERABLE_OPERATORS(GPUCounter);
|
||||
@@ -3290,6 +3293,17 @@ inline constexpr bool IsVulkanExtendedCounter(GPUCounter c)
|
||||
return c >= GPUCounter::FirstVulkanExtended && c <= GPUCounter::LastVulkanExtended;
|
||||
}
|
||||
|
||||
DOCUMENT(R"(Check whether or not this is an ARM private counter.
|
||||
|
||||
:param GPUCounter c: The counter.
|
||||
:return: ``True`` if it is an ARM private counter, ``False`` if it's not.
|
||||
:rtype: ``bool``
|
||||
)");
|
||||
inline constexpr bool IsARMCounter(GPUCounter c)
|
||||
{
|
||||
return c >= GPUCounter::FirstARM && c <= GPUCounter::LastARM;
|
||||
}
|
||||
|
||||
DOCUMENT(R"(The unit that GPU counter data is returned in.
|
||||
|
||||
.. data:: Absolute
|
||||
@@ -3324,6 +3338,9 @@ enum class CounterUnit : uint32_t
|
||||
Ratio,
|
||||
Bytes,
|
||||
Cycles,
|
||||
Hertz,
|
||||
Volt,
|
||||
Celsius
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_ENUM(CounterUnit);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include "driver/ihv/amd/amd_counters.h"
|
||||
#include "driver/ihv/arm/arm_counters.h"
|
||||
#include "driver/ihv/intel/intel_gl_counters.h"
|
||||
#include "gl_driver.h"
|
||||
#include "gl_replay.h"
|
||||
@@ -65,6 +66,11 @@ rdcarray<GPUCounter> GLReplay::EnumerateCounters()
|
||||
ret.append(m_pIntelCounters->GetPublicCounterIds());
|
||||
}
|
||||
|
||||
if(m_pARMCounters)
|
||||
{
|
||||
ret.append(m_pARMCounters->GetPublicCounterIds());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -96,6 +102,11 @@ CounterDescription GLReplay::DescribeCounter(GPUCounter counterID)
|
||||
}
|
||||
}
|
||||
|
||||
if(IsARMCounter(counterID) && m_pARMCounters)
|
||||
{
|
||||
return m_pARMCounters->GetCounterDescription(counterID);
|
||||
}
|
||||
|
||||
// FFBA5548-FBF8-405D-BA18-F0329DA370A0
|
||||
desc.uuid.words[0] = 0xFFBA5548;
|
||||
desc.uuid.words[1] = 0xFBF8405D;
|
||||
@@ -461,6 +472,84 @@ rdcarray<CounterResult> GLReplay::FetchCountersIntel(const rdcarray<GPUCounter>
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLReplay::FillTimersARM(uint32_t *eventStartID, uint32_t *sampleIndex,
|
||||
rdcarray<uint32_t> *eventIDs, const DrawcallDescription &drawnode)
|
||||
{
|
||||
if(drawnode.children.empty())
|
||||
return;
|
||||
|
||||
for(size_t i = 0; i < drawnode.children.size(); i++)
|
||||
{
|
||||
const DrawcallDescription &d = drawnode.children[i];
|
||||
|
||||
FillTimersARM(eventStartID, sampleIndex, eventIDs, drawnode.children[i]);
|
||||
|
||||
if(d.events.empty())
|
||||
continue;
|
||||
|
||||
eventIDs->push_back(d.eventId);
|
||||
|
||||
m_pDriver->ReplayLog(*eventStartID, d.eventId, eReplay_WithoutDraw);
|
||||
|
||||
m_pARMCounters->BeginSample(d.eventId);
|
||||
|
||||
m_pDriver->ReplayLog(*eventStartID, d.eventId, eReplay_OnlyDraw);
|
||||
|
||||
// wait for the GPU to process all commands
|
||||
GLsync sync = GL.glFenceSync(eGL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
GL.glClientWaitSync(sync, eGL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
|
||||
m_pARMCounters->EndSample();
|
||||
|
||||
GL.glDeleteSync(sync);
|
||||
|
||||
*eventStartID = d.eventId + 1;
|
||||
++*sampleIndex;
|
||||
}
|
||||
}
|
||||
|
||||
rdcarray<CounterResult> GLReplay::FetchCountersARM(const rdcarray<GPUCounter> &counters)
|
||||
{
|
||||
m_pARMCounters->DisableAllCounters();
|
||||
|
||||
// enable counters it needs
|
||||
for(size_t i = 0; i < counters.size(); i++)
|
||||
{
|
||||
// This function is only called internally, and violating this assertion means our
|
||||
// caller has invoked this method incorrectly
|
||||
RDCASSERT(IsARMCounter(counters[i]));
|
||||
m_pARMCounters->EnableCounter(counters[i]);
|
||||
}
|
||||
|
||||
uint32_t passCount = m_pARMCounters->GetPassCount();
|
||||
|
||||
uint32_t sampleIndex = 0;
|
||||
|
||||
rdcarray<uint32_t> eventIDs;
|
||||
|
||||
m_pDriver->ReplayMarkers(false);
|
||||
|
||||
for(uint32_t p = 0; p < passCount; p++)
|
||||
{
|
||||
m_pARMCounters->BeginPass(p);
|
||||
|
||||
uint32_t eventStartID = 0;
|
||||
|
||||
sampleIndex = 0;
|
||||
|
||||
eventIDs.clear();
|
||||
|
||||
FillTimersARM(&eventStartID, &sampleIndex, &eventIDs, m_pDriver->GetRootDraw());
|
||||
|
||||
m_pARMCounters->EndPass();
|
||||
}
|
||||
m_pDriver->ReplayMarkers(true);
|
||||
|
||||
rdcarray<CounterResult> ret = m_pARMCounters->GetCounterData(eventIDs, counters);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdcarray<CounterResult> GLReplay::FetchCounters(const rdcarray<GPUCounter> &allCounters)
|
||||
{
|
||||
rdcarray<CounterResult> ret;
|
||||
@@ -503,6 +592,16 @@ rdcarray<CounterResult> GLReplay::FetchCounters(const rdcarray<GPUCounter> &allC
|
||||
}
|
||||
}
|
||||
|
||||
if(m_pARMCounters)
|
||||
{
|
||||
rdcarray<GPUCounter> armCounters;
|
||||
std::copy_if(allCounters.begin(), allCounters.end(), std::back_inserter(armCounters),
|
||||
[](const GPUCounter &c) { return IsARMCounter(c); });
|
||||
|
||||
if(!armCounters.empty())
|
||||
ret = FetchCountersARM(armCounters);
|
||||
}
|
||||
|
||||
if(counters.empty())
|
||||
{
|
||||
return ret;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "gl_replay.h"
|
||||
#include "core/settings.h"
|
||||
#include "driver/ihv/amd/amd_counters.h"
|
||||
#include "driver/ihv/arm/arm_counters.h"
|
||||
#include "driver/ihv/intel/intel_gl_counters.h"
|
||||
#include "maths/matrix.h"
|
||||
#include "serialise/rdcfile.h"
|
||||
@@ -67,6 +68,7 @@ void GLReplay::Shutdown()
|
||||
{
|
||||
SAFE_DELETE(m_pAMDCounters);
|
||||
SAFE_DELETE(m_pIntelCounters);
|
||||
SAFE_DELETE(m_pARMCounters);
|
||||
|
||||
DeleteDebugData();
|
||||
|
||||
@@ -235,6 +237,7 @@ void GLReplay::SetReplayData(GLWindowingData data)
|
||||
{
|
||||
AMDCounters *countersAMD = NULL;
|
||||
IntelGlCounters *countersIntel = NULL;
|
||||
ARMCounters *countersARM = NULL;
|
||||
|
||||
bool isMesa = false;
|
||||
|
||||
@@ -283,6 +286,11 @@ void GLReplay::SetReplayData(GLWindowingData data)
|
||||
RDCLOG("AMD GPU detected - trying to initialise AMD counters");
|
||||
countersAMD = new AMDCounters();
|
||||
}
|
||||
else if(m_DriverInfo.vendor == GPUVendor::ARM)
|
||||
{
|
||||
RDCLOG("ARM Mali GPU detected - trying to initialise ARM counters");
|
||||
countersARM = new ARMCounters();
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCLOG("%s GPU detected - no counters available", ToStr(m_DriverInfo.vendor).c_str());
|
||||
@@ -308,6 +316,16 @@ void GLReplay::SetReplayData(GLWindowingData data)
|
||||
delete countersIntel;
|
||||
m_pIntelCounters = NULL;
|
||||
}
|
||||
|
||||
if(countersARM && countersARM->Init())
|
||||
{
|
||||
m_pARMCounters = countersARM;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete countersARM;
|
||||
m_pARMCounters = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "gl_common.h"
|
||||
|
||||
class AMDCounters;
|
||||
class ARMCounters;
|
||||
class IntelGlCounters;
|
||||
class WrappedOpenGL;
|
||||
struct GLCounterContext;
|
||||
@@ -465,4 +466,12 @@ private:
|
||||
const DrawcallDescription &drawnode);
|
||||
|
||||
rdcarray<CounterResult> FetchCountersIntel(const rdcarray<GPUCounter> &counters);
|
||||
|
||||
// ARM counter instance
|
||||
ARMCounters *m_pARMCounters = NULL;
|
||||
|
||||
void FillTimersARM(uint32_t *eventStartID, uint32_t *sampleIndex, rdcarray<uint32_t> *eventIDs,
|
||||
const DrawcallDescription &drawnode);
|
||||
|
||||
rdcarray<CounterResult> FetchCountersARM(const rdcarray<GPUCounter> &counters);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Development|Win32">
|
||||
<Configuration>Development</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Development|x64">
|
||||
<Configuration>Development</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}</ProjectGuid>
|
||||
<RootNamespace>AMD</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
|
||||
<ExecutablePath>$(ExecutablePath)</ExecutablePath>
|
||||
<IncludePath>$(SolutionDir)\breakpad;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
<ExcludePath>$(ExcludePath)</ExcludePath>
|
||||
<TargetName>driver_$(ProjectName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)renderdoc\;$(SolutionDir)renderdoc\3rdparty\</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>RENDERDOC_EXPORTS;RENDERDOC_PLATFORM_WIN32;WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4100</DisableSpecificWarnings>
|
||||
<AdditionalOptions>/w44062 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Development'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="arm_counters.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arm_counters_stub.cpp" />
|
||||
<ClCompile Include="official\lizard\gatord_xml_reader.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\gator_api.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\gator_message.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\hwcpipe_api.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\hwcpipe_communication.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\lizard.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\lizard_api.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\lizard_communication.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\lizard_counter.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\message_util.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\socket.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\thirdparty\hwcpipe\hwcpipe.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\thirdparty\hwcpipe\vendor\arm\mali\mali_profiler.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\thirdparty\hwcpipe\vendor\arm\pmu\pmu_counter.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\thirdparty\hwcpipe\vendor\arm\pmu\pmu_profiler.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="arm_counters.h" />
|
||||
<ClInclude Include="official\lizard\gatord_xml_reader.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\gator_api.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\gator_constants.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\gator_message.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\hwcpipe_api.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\hwcpipe_communication.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\include\lizard\lizard.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\include\lizard\lizard_api.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\include\lizard\lizard_counter.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\lizard_communication.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\message_util.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\socket.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\cpu_profiler.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\gpu_profiler.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\hwcpipe.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\hwcpipe_log.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\value.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\mali\hwc.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\mali\hwc_names.hpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\mali\mali_profiler.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\pmu\pmu_counter.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\pmu\pmu_profiler.h">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Counters">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="official">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="official\lizard">
|
||||
<UniqueIdentifier>{7e5aff88-5de6-4985-ad92-c69fd47fb6ce}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="official\lizard\thirdparty">
|
||||
<UniqueIdentifier>{b1fd2e34-8140-4eed-a65c-db2c592e00e9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="official\lizard\thirdparty\hwcpipe">
|
||||
<UniqueIdentifier>{45866afa-f87c-4bfd-8f1b-720bebf4e82e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="official\lizard\thirdparty\hwcpipe\mali">
|
||||
<UniqueIdentifier>{d25e3ccb-84a3-4a4a-8bf6-24795ba1bf47}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="official\lizard\thirdparty\hwcpipe\pmu">
|
||||
<UniqueIdentifier>{7f040482-c5df-453f-869b-a1d6cf2c537e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="arm_counters.cpp">
|
||||
<Filter>Counters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arm_counters_stub.cpp">
|
||||
<Filter>Counters</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\gator_api.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\gator_message.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\gatord_xml_reader.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\hwcpipe_api.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\hwcpipe_communication.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\lizard.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\lizard_api.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\lizard_communication.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\lizard_counter.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\message_util.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\socket.cpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\thirdparty\hwcpipe\hwcpipe.cpp">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\thirdparty\hwcpipe\vendor\arm\mali\mali_profiler.cpp">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe\mali</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\thirdparty\hwcpipe\vendor\arm\pmu\pmu_counter.cpp">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe\pmu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="official\lizard\thirdparty\hwcpipe\vendor\arm\pmu\pmu_profiler.cpp">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe\pmu</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="arm_counters.h">
|
||||
<Filter>Counters</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\gator_api.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\gator_constants.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\gator_message.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\gatord_xml_reader.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\hwcpipe_api.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\hwcpipe_communication.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\lizard_communication.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\message_util.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\socket.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\include\lizard\lizard.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\include\lizard\lizard_api.h">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\include\lizard\lizard_counter.hpp">
|
||||
<Filter>official\lizard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\cpu_profiler.h">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\gpu_profiler.h">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\hwcpipe.h">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\hwcpipe_log.h">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\value.h">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\mali\hwc.hpp">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe\mali</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\mali\hwc_names.hpp">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe\mali</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\mali\mali_profiler.h">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe\mali</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\pmu\pmu_counter.h">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe\pmu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="official\lizard\thirdparty\hwcpipe\vendor\arm\pmu\pmu_profiler.h">
|
||||
<Filter>official\lizard\thirdparty\hwcpipe\pmu</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,62 @@
|
||||
set(sources
|
||||
arm_counters.h
|
||||
)
|
||||
|
||||
if(ANDROID)
|
||||
list(APPEND sources
|
||||
arm_counters.cpp
|
||||
|
||||
official/lizard/include/lizard/lizard_api.h
|
||||
official/lizard/lizard_api.cpp
|
||||
|
||||
official/lizard/include/lizard/lizard.hpp
|
||||
official/lizard/lizard.cpp
|
||||
official/lizard/lizard_counter.cpp
|
||||
official/lizard/lizard_communication.hpp
|
||||
official/lizard/lizard_communication.cpp
|
||||
official/lizard/hwcpipe_communication.hpp
|
||||
official/lizard/hwcpipe_communication.cpp
|
||||
official/lizard/hwcpipe_api.hpp
|
||||
official/lizard/hwcpipe_api.cpp
|
||||
official/lizard/gatord_xml_reader.cpp
|
||||
|
||||
official/lizard/gator_api.cpp
|
||||
official/lizard/gator_constants.hpp
|
||||
official/lizard/gator_message.cpp
|
||||
official/lizard/gator_message.hpp
|
||||
official/lizard/message_util.cpp
|
||||
official/lizard/message_util.hpp
|
||||
official/lizard/socket.cpp
|
||||
|
||||
official/lizard/thirdparty/hwcpipe/hwcpipe.h
|
||||
official/lizard/thirdparty/hwcpipe/hwcpipe.cpp
|
||||
official/lizard/thirdparty/hwcpipe/cpu_profiler.h
|
||||
official/lizard/thirdparty/hwcpipe/gpu_profiler.h
|
||||
official/lizard/thirdparty/hwcpipe/value.h
|
||||
|
||||
official/lizard/thirdparty/hwcpipe/vendor/arm/mali/hwc.hpp
|
||||
official/lizard/thirdparty/hwcpipe/vendor/arm/mali/hwc_names.hpp
|
||||
official/lizard/thirdparty/hwcpipe/vendor/arm/mali/mali_profiler.h
|
||||
official/lizard/thirdparty/hwcpipe/vendor/arm/mali/mali_profiler.cpp
|
||||
|
||||
official/lizard/thirdparty/hwcpipe/vendor/arm/pmu/pmu_counter.h
|
||||
official/lizard/thirdparty/hwcpipe/vendor/arm/pmu/pmu_counter.cpp
|
||||
official/lizard/thirdparty/hwcpipe/vendor/arm/pmu/pmu_profiler.h
|
||||
official/lizard/thirdparty/hwcpipe/vendor/arm/pmu/pmu_profiler.cpp
|
||||
)
|
||||
else()
|
||||
list(APPEND sources
|
||||
arm_counters_stub.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(rdoc_arm OBJECT ${sources})
|
||||
|
||||
set(include_dirs
|
||||
${RDOC_INCLUDES}
|
||||
official/lizard/
|
||||
official/lizard/include/lizard
|
||||
official/lizard/thirdparty/hwcpipe/
|
||||
)
|
||||
target_include_directories(rdoc_arm ${include_dirs})
|
||||
target_compile_definitions(rdoc_arm ${RDOC_DEFINITIONS})
|
||||
@@ -0,0 +1,227 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "arm_counters.h"
|
||||
|
||||
#include "android/android.h"
|
||||
#include "common/common.h"
|
||||
#include "common/formatting.h"
|
||||
#include "core/plugins.h"
|
||||
#include "os/os_specific.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "official/lizard/include/lizard/lizard_api.h"
|
||||
|
||||
static CounterDescription ARMCreateCounterDescription(GPUCounter index,
|
||||
LizardCounterDescription &lzdDesc)
|
||||
{
|
||||
CounterDescription desc;
|
||||
desc.name = StringFormat::Fmt("%s %s", lzdDesc.title, lzdDesc.name);
|
||||
desc.counter = GPUCounter(index);
|
||||
desc.category = lzdDesc.category;
|
||||
|
||||
if(strlen(lzdDesc.short_name) > 0)
|
||||
desc.description = StringFormat::Fmt("%s (%s)", lzdDesc.description, lzdDesc.short_name);
|
||||
else
|
||||
desc.description = lzdDesc.description;
|
||||
|
||||
switch(lzdDesc.result_type)
|
||||
{
|
||||
case LZD_TYPE_INT: desc.resultType = CompType::UInt; break;
|
||||
case LZD_TYPE_DOUBLE: desc.resultType = CompType::Double; break;
|
||||
default: desc.resultType = CompType::UInt; break;
|
||||
}
|
||||
|
||||
switch(lzdDesc.units)
|
||||
{
|
||||
case LZD_UNITS_BYTE: desc.unit = CounterUnit::Bytes; break;
|
||||
case LZD_UNITS_CELSIUS: desc.unit = CounterUnit::Celsius; break;
|
||||
case LZD_UNITS_HZ: desc.unit = CounterUnit::Hertz; break;
|
||||
case LZD_UNITS_S: desc.unit = CounterUnit::Seconds; break;
|
||||
case LZD_UNITS_V: desc.unit = CounterUnit::Volt; break;
|
||||
default: desc.unit = CounterUnit::Absolute; break;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
ARMCounters::ARMCounters() : m_Api(NULL), m_Ctx(0), m_EventId(0), m_passIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
ARMCounters::~ARMCounters()
|
||||
{
|
||||
if(m_Ctx)
|
||||
m_Api->Destroy(m_Ctx);
|
||||
}
|
||||
|
||||
bool ARMCounters::Init()
|
||||
{
|
||||
if(LoadApi(&m_Api) != LZD_OK)
|
||||
{
|
||||
RDCLOG("Failed to load Lizard api.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_Api->version != LIZARD_VERSION_0_1)
|
||||
{
|
||||
RDCLOG("Lizard version is not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Ctx = m_Api->Init("127.0.0.1", 8080);
|
||||
if(!m_Ctx)
|
||||
{
|
||||
RDCLOG("Failed to initialize Lizard.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t count = m_Api->GetAvailableCountersCount(m_Ctx);
|
||||
|
||||
if(count == 0)
|
||||
{
|
||||
RDCLOG("Couldn't find available ARM counters.");
|
||||
m_Api->Destroy(m_Ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
for(LizardCounterId idx = 1; idx <= count; idx++)
|
||||
{
|
||||
struct LizardCounterDescription lzdDesc;
|
||||
|
||||
LZD_Result result = m_Api->GetCounterDescription(m_Ctx, idx, &lzdDesc);
|
||||
|
||||
if(result == LZD_OK)
|
||||
{
|
||||
CounterDescription desc =
|
||||
ARMCreateCounterDescription(GPUCounter((int)GPUCounter::FirstARM + idx), lzdDesc);
|
||||
m_CounterDescriptions.push_back(desc);
|
||||
m_CounterIds.push_back(desc.counter);
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCLOG("Failed to get ARM counter information.");
|
||||
m_Api->Destroy(m_Ctx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
rdcarray<GPUCounter> ARMCounters::GetPublicCounterIds()
|
||||
{
|
||||
return m_CounterIds;
|
||||
}
|
||||
|
||||
CounterDescription ARMCounters::GetCounterDescription(GPUCounter index)
|
||||
{
|
||||
return m_CounterDescriptions[(int)index - (int)GPUCounter::FirstARM - 1];
|
||||
}
|
||||
|
||||
void ARMCounters::EnableCounter(GPUCounter counter)
|
||||
{
|
||||
uint32_t id = (uint32_t)counter - (uint32_t)GPUCounter::FirstARM;
|
||||
m_EnabledCounters.push_back(id);
|
||||
}
|
||||
|
||||
void ARMCounters::DisableAllCounters()
|
||||
{
|
||||
m_EnabledCounters.clear();
|
||||
}
|
||||
|
||||
uint32_t ARMCounters::GetPassCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ARMCounters::BeginPass(uint32_t passID)
|
||||
{
|
||||
m_passIndex = passID;
|
||||
for(size_t i = 0; i < m_EnabledCounters.size(); i++)
|
||||
{
|
||||
m_Api->EnableCounter(m_Ctx, m_EnabledCounters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ARMCounters::EndPass()
|
||||
{
|
||||
for(size_t i = 0; i < m_EnabledCounters.size(); i++)
|
||||
{
|
||||
m_Api->DisableCounter(m_Ctx, m_EnabledCounters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ARMCounters::BeginSample(uint32_t eventId)
|
||||
{
|
||||
m_EventId = eventId;
|
||||
m_Api->StartCapture(m_Ctx);
|
||||
}
|
||||
|
||||
void ARMCounters::EndSample()
|
||||
{
|
||||
m_Api->StopCapture(m_Ctx);
|
||||
|
||||
for(uint32_t counterId : m_EnabledCounters)
|
||||
{
|
||||
const CounterDescription &desc = m_CounterDescriptions[counterId - 1];
|
||||
CounterValue data;
|
||||
data.u64 = 0;
|
||||
if(desc.resultType == CompType::UInt)
|
||||
{
|
||||
data.u64 = m_Api->ReadCounterInt(m_Ctx, counterId);
|
||||
}
|
||||
else if(desc.resultType == CompType::Double)
|
||||
{
|
||||
data.d = m_Api->ReadCounterDouble(m_Ctx, counterId);
|
||||
}
|
||||
m_CounterData[m_EventId][counterId] = data;
|
||||
}
|
||||
}
|
||||
|
||||
rdcarray<CounterResult> ARMCounters::GetCounterData(const rdcarray<uint32_t> &eventIDs,
|
||||
const rdcarray<GPUCounter> &counters)
|
||||
{
|
||||
rdcarray<CounterResult> result;
|
||||
for(size_t i = 0; i < eventIDs.size(); i++)
|
||||
{
|
||||
uint32_t eventId = eventIDs[i];
|
||||
for(size_t j = 0; j < counters.size(); j++)
|
||||
{
|
||||
GPUCounter counter = counters[j];
|
||||
uint32_t counterId = (uint32_t)counter - (uint32_t)GPUCounter::FirstARM;
|
||||
const CounterDescription &desc = GetCounterDescription(counter);
|
||||
const CounterValue &data = m_CounterData[eventId][counterId];
|
||||
if(desc.resultType == CompType::UInt)
|
||||
{
|
||||
result.push_back(CounterResult(eventId, counter, data.u64));
|
||||
}
|
||||
else if(desc.resultType == CompType::Double)
|
||||
{
|
||||
result.push_back(CounterResult(eventId, counter, data.d));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "api/replay/data_types.h"
|
||||
#include "api/replay/renderdoc_replay.h"
|
||||
#include "api/replay/replay_enums.h"
|
||||
#include "common/common.h"
|
||||
|
||||
struct LizardApi;
|
||||
typedef void *LizardInstance;
|
||||
|
||||
class ARMCounters
|
||||
{
|
||||
public:
|
||||
ARMCounters();
|
||||
~ARMCounters();
|
||||
|
||||
bool Init();
|
||||
rdcarray<GPUCounter> GetPublicCounterIds();
|
||||
CounterDescription GetCounterDescription(GPUCounter index);
|
||||
|
||||
void EnableCounter(GPUCounter counter);
|
||||
void DisableAllCounters();
|
||||
|
||||
uint32_t GetPassCount();
|
||||
|
||||
void BeginPass(uint32_t passID);
|
||||
void EndPass();
|
||||
|
||||
void BeginSample(uint32_t eventId);
|
||||
void EndSample();
|
||||
|
||||
rdcarray<CounterResult> GetCounterData(const rdcarray<uint32_t> &eventIDs,
|
||||
const rdcarray<GPUCounter> &counters);
|
||||
|
||||
private:
|
||||
#if ENABLED(RDOC_ANDROID)
|
||||
struct LizardApi *m_Api;
|
||||
LizardInstance m_Ctx;
|
||||
|
||||
uint32_t m_EventId;
|
||||
uint32_t m_passIndex;
|
||||
|
||||
rdcarray<uint32_t> m_EnabledCounters;
|
||||
rdcarray<CounterDescription> m_CounterDescriptions;
|
||||
rdcarray<GPUCounter> m_CounterIds;
|
||||
std::map<uint32_t, std::map<uint32_t, CounterValue>> m_CounterData;
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "arm_counters.h"
|
||||
|
||||
ARMCounters::ARMCounters()
|
||||
{
|
||||
}
|
||||
|
||||
ARMCounters::~ARMCounters()
|
||||
{
|
||||
}
|
||||
|
||||
bool ARMCounters::Init()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rdcarray<GPUCounter> ARMCounters::GetPublicCounterIds()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
CounterDescription ARMCounters::GetCounterDescription(GPUCounter index)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void ARMCounters::EnableCounter(GPUCounter counter)
|
||||
{
|
||||
}
|
||||
|
||||
void ARMCounters::DisableAllCounters()
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t ARMCounters::GetPassCount()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ARMCounters::BeginPass(uint32_t passID)
|
||||
{
|
||||
}
|
||||
|
||||
void ARMCounters::EndPass()
|
||||
{
|
||||
}
|
||||
|
||||
void ARMCounters::BeginSample(uint32_t eventId)
|
||||
{
|
||||
}
|
||||
|
||||
void ARMCounters::EndSample()
|
||||
{
|
||||
}
|
||||
|
||||
rdcarray<CounterResult> ARMCounters::GetCounterData(const rdcarray<uint32_t> &eventIDs,
|
||||
const rdcarray<GPUCounter> &counters)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,21 @@
|
||||
## Lizard
|
||||
|
||||
Lizard is a library to capture ARM hardware counters on Android devices.
|
||||
|
||||
### Using the library with gatord
|
||||
|
||||
This step is optional, the library can query a few hardware counters directly.
|
||||
|
||||
1. Build `gatord` for Android.
|
||||
|
||||
2. Copy `gatord` to a directory which is publicly readable, writeable and executable on the Android device (e.g. /data/local/tmp)
|
||||
|
||||
```sh
|
||||
$ adb push gatord /data/local/tmp/gatord
|
||||
```
|
||||
|
||||
3. Start gatord on the Android device ( -M: Mali device type e.g. G71, G76, etc.)
|
||||
|
||||
```sh
|
||||
$ adb shell ./data/local/tmp/gatord -M G71
|
||||
```
|
||||
@@ -0,0 +1,461 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "gator_api.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "gator_constants.hpp"
|
||||
#include "gator_message.hpp"
|
||||
#include "gatord_xml_reader.hpp"
|
||||
#include "message_util.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
static const std::string ATTR_TYPE = "type";
|
||||
|
||||
static const std::string TAG_REQUEST = "request";
|
||||
|
||||
static const std::string VALUE_CAPTURED = "captured";
|
||||
static const std::string VALUE_CONFIGURATION = "configuration";
|
||||
static const std::string VALUE_COUNTERS = "counters";
|
||||
static const std::string VALUE_DEFAULTS = "defaults";
|
||||
static const std::string VALUE_EVENTS = "events";
|
||||
|
||||
GatorApi::GatorApi(char *hostname, const uint32_t port,
|
||||
std::vector<LizardCounter> &availableCounters, LizardCounterDataStore &dataStore)
|
||||
: m_host(hostname),
|
||||
m_port(port),
|
||||
m_connection(NULL),
|
||||
m_availableCounters(availableCounters),
|
||||
m_data(dataStore)
|
||||
{
|
||||
}
|
||||
|
||||
GatorApi::~GatorApi()
|
||||
{
|
||||
if(m_host)
|
||||
{
|
||||
free(m_host);
|
||||
}
|
||||
|
||||
if(m_connection)
|
||||
{
|
||||
delete m_connection;
|
||||
m_connection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool GatorApi::createConnection()
|
||||
{
|
||||
m_connection = lizard::Socket::createConnection(m_host, m_port);
|
||||
if(m_connection == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GatorApi::destroyConnection()
|
||||
{
|
||||
Socket::destroyConnection(m_connection);
|
||||
m_connection = NULL;
|
||||
}
|
||||
|
||||
bool GatorApi::init(uint32_t &counterId)
|
||||
{
|
||||
std::string eventsXml = requestEvents();
|
||||
std::string countersXml = requestCounters();
|
||||
|
||||
// Store all events supported by gatord
|
||||
std::vector<GatordXML::EventCategory> gatordEvents =
|
||||
GatordXML::parseEvents(eventsXml.c_str(), eventsXml.size());
|
||||
// Store available counters provided by gatord
|
||||
std::vector<std::string> gatordAvailableCounters =
|
||||
GatordXML::parseCounters(countersXml.c_str(), countersXml.size());
|
||||
|
||||
std::vector<std::string>::const_iterator countersStart = gatordAvailableCounters.begin();
|
||||
std::vector<std::string>::const_iterator countersEnd = gatordAvailableCounters.end();
|
||||
|
||||
uint32_t counterNum = counterId;
|
||||
|
||||
for(GatordXML::EventCategory &category : gatordEvents)
|
||||
{
|
||||
for(GatordXML::Event &event : category.events)
|
||||
{
|
||||
if(std::find(countersStart, countersEnd, event.counter) != countersEnd)
|
||||
{
|
||||
// found the counter
|
||||
LizardCounter::ClassType classType = event.eventClass == CLASS_ABSOLUTE
|
||||
? LizardCounter::CLASS_ABSOLUTE
|
||||
: LizardCounter::CLASS_DELTA;
|
||||
m_availableCounters.emplace_back(++counterId, event.counter.c_str(), event.name.c_str(),
|
||||
event.title.c_str(), event.description.c_str(),
|
||||
category.name.c_str(), event.multiplier, event.units,
|
||||
classType, LizardCounter::SOURCE_GATORD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counterId > counterNum;
|
||||
}
|
||||
|
||||
bool GatorApi::setupCapturedCounters()
|
||||
{
|
||||
std::string capturedXml = requestCaptured();
|
||||
std::vector<GatordXML::CapturedCounter> capturedCounters =
|
||||
GatordXML::parseCapturedCounters(capturedXml.c_str(), capturedXml.size());
|
||||
|
||||
if(capturedCounters.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for(GatordXML::CapturedCounter captured : capturedCounters)
|
||||
{
|
||||
for(LizardCounter &counter : m_availableCounters)
|
||||
{
|
||||
if(captured.type == counter.key())
|
||||
{
|
||||
counter.setInternalKey(captured.key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GatorApi::sendConfiguration(const std::vector<LizardCounter> &enabledCounters)
|
||||
{
|
||||
std::string xml = std::string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
xml += "<configurations revision=\"3\">\n";
|
||||
for(uint32_t idx = 0; idx < enabledCounters.size(); idx++)
|
||||
{
|
||||
const lizard::LizardCounter &cnt = enabledCounters[idx];
|
||||
xml += "<configuration counter=\"" + std::string(cnt.key()) + "\" />\n";
|
||||
}
|
||||
xml += "</configurations>";
|
||||
sendXml(xml);
|
||||
uint8_t response = getResponse();
|
||||
if(response != RESPONSE_ACK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GatorApi::sendSession()
|
||||
{
|
||||
std::string xml = std::string(
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<session call_stack_unwinding=\"no\" "
|
||||
"parse_debug_info=\"no\" version=\"1\" high_resolution=\"no\" buffer_mode=\"streaming\" "
|
||||
"sample_rate=\"normal\" duration=\"0\" target_address=\"localhost\" live_rate=\"100\" "
|
||||
"stop_gator=\"no\">\n<energy_capture version=\"1\" type=\"none\">\n<channel id=\"0\" "
|
||||
"resistance=\"20\" power=\"yes\"/>\n</energy_capture></session>\n");
|
||||
sendXml(xml);
|
||||
uint8_t response = getResponse();
|
||||
if(response != RESPONSE_ACK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GatorApi::sendDisconnect()
|
||||
{
|
||||
sendCommand(COMMAND_DISCONNECT);
|
||||
getResponse();
|
||||
}
|
||||
|
||||
std::string GatorApi::requestCounters()
|
||||
{
|
||||
requestXml(VALUE_COUNTERS);
|
||||
return getXmlResponse();
|
||||
}
|
||||
|
||||
std::string GatorApi::requestEvents()
|
||||
{
|
||||
requestXml(VALUE_EVENTS);
|
||||
return getXmlResponse();
|
||||
}
|
||||
|
||||
std::string GatorApi::requestConfiguration()
|
||||
{
|
||||
requestXml(VALUE_CONFIGURATION);
|
||||
return getXmlResponse();
|
||||
}
|
||||
|
||||
std::string GatorApi::requestDefaults()
|
||||
{
|
||||
requestXml(VALUE_DEFAULTS);
|
||||
return getXmlResponse();
|
||||
}
|
||||
|
||||
std::string GatorApi::requestCaptured()
|
||||
{
|
||||
requestXml(VALUE_CAPTURED);
|
||||
return getXmlResponse();
|
||||
}
|
||||
|
||||
void GatorApi::requestXml(const std::string &attributeValue)
|
||||
{
|
||||
std::string xml = std::string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
xml += "<" + TAG_REQUEST + " " + ATTR_TYPE + "=" + attributeValue + "/>";
|
||||
|
||||
uint8_t header[5];
|
||||
header[0] = COMMAND_REQUEST_XML;
|
||||
writeLEInt(header + 1, xml.size());
|
||||
|
||||
size_t byteSent;
|
||||
m_connection->send(header, sizeof(header), &byteSent);
|
||||
m_connection->send(xml.c_str(), xml.size(), &byteSent);
|
||||
}
|
||||
|
||||
void GatorApi::sendXml(const std::string &xml)
|
||||
{
|
||||
uint8_t header[5];
|
||||
header[0] = COMMAND_DELIVER_XML;
|
||||
writeLEInt(header + 1, xml.size());
|
||||
|
||||
size_t byteSent;
|
||||
m_connection->send(header, sizeof(header), &byteSent);
|
||||
m_connection->send(xml.c_str(), xml.size(), &byteSent);
|
||||
}
|
||||
|
||||
uint8_t GatorApi::getResponse()
|
||||
{
|
||||
uint8_t responseType;
|
||||
uint32_t responseSize;
|
||||
getResponseHeader(&responseType, &responseSize);
|
||||
return responseType;
|
||||
}
|
||||
|
||||
std::string GatorApi::getXmlResponse()
|
||||
{
|
||||
uint8_t responseType;
|
||||
uint32_t responseSize;
|
||||
getResponseHeader(&responseType, &responseSize);
|
||||
|
||||
if(responseType != RESPONSE_XML)
|
||||
return "";
|
||||
|
||||
std::vector<char> responseXml(responseSize);
|
||||
|
||||
size_t bytesRecv;
|
||||
m_connection->receiveAll(responseXml.data(), responseSize, &bytesRecv);
|
||||
|
||||
std::string xml(responseXml.begin(), responseXml.end());
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
void GatorApi::sendCommand(uint8_t command)
|
||||
{
|
||||
uint8_t message[5];
|
||||
message[0] = command;
|
||||
writeLEInt(message + 1, 0);
|
||||
size_t byteSent;
|
||||
m_connection->send(message, sizeof(message), &byteSent);
|
||||
}
|
||||
|
||||
Socket::Result GatorApi::getResponseHeader(uint8_t *responseType, uint32_t *responseSize)
|
||||
{
|
||||
uint8_t responseHeader[5];
|
||||
size_t bytesRecv;
|
||||
Socket::Result result = m_connection->receive(responseHeader, sizeof(responseHeader), &bytesRecv);
|
||||
if(result == Socket::Result::SUCCESS)
|
||||
{
|
||||
*responseType = responseHeader[0];
|
||||
*responseSize = readLEInt(responseHeader + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GatorApi::sendVersion()
|
||||
{
|
||||
char *msg_version = (char *)GATOR_PROTOCOL_VERSION;
|
||||
char *msg_streamline = (char *)STREAMLINE;
|
||||
|
||||
size_t bytesSent;
|
||||
m_connection->send(msg_version, strlen(msg_version), &bytesSent);
|
||||
m_connection->send(msg_streamline, strlen(msg_streamline), &bytesSent);
|
||||
|
||||
// "GATOR 670\n"
|
||||
size_t bytesRecv = 0;
|
||||
size_t size = 10;
|
||||
char buffer[size];
|
||||
m_connection->receiveAll(buffer, sizeof(buffer), &bytesRecv);
|
||||
|
||||
std::string gator_pattern = "GATOR ";
|
||||
if(bytesRecv != size || std::strncmp(buffer, gator_pattern.c_str(), gator_pattern.length()) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sendCommand(COMMAND_PING);
|
||||
uint8_t response = getResponse();
|
||||
if(response != RESPONSE_ACK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GatorApi::resendConfiguration(const std::vector<LizardCounter> &enabledGatorCounters)
|
||||
{
|
||||
if(enabledGatorCounters.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!createConnection())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!sendVersion())
|
||||
{
|
||||
destroyConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!sendConfiguration(enabledGatorCounters))
|
||||
{
|
||||
sendDisconnect();
|
||||
destroyConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
sendDisconnect();
|
||||
destroyConnection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GatorApi::startSession()
|
||||
{
|
||||
if(!createConnection())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!sendVersion())
|
||||
{
|
||||
destroyConnection();
|
||||
return false;
|
||||
}
|
||||
if(!sendSession())
|
||||
{
|
||||
sendDisconnect();
|
||||
destroyConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!setupCapturedCounters())
|
||||
{
|
||||
sendDisconnect();
|
||||
destroyConnection();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GatorApi::startCapture()
|
||||
{
|
||||
sendCommand(COMMAND_APC_START);
|
||||
}
|
||||
|
||||
void GatorApi::stopCapture()
|
||||
{
|
||||
sendCommand(COMMAND_APC_STOP);
|
||||
}
|
||||
|
||||
GatorApi::MessageResult GatorApi::readMessage(GatorMessage &message)
|
||||
{
|
||||
uint8_t responseType;
|
||||
uint32_t responseSize;
|
||||
|
||||
Socket::Result result = getResponseHeader(&responseType, &responseSize);
|
||||
if(result == Socket::Result::SUCCESS)
|
||||
{
|
||||
message.setType(responseType);
|
||||
if(responseSize > 0)
|
||||
{
|
||||
std::vector<uint8_t> response(responseSize);
|
||||
size_t bytesRecv;
|
||||
result = m_connection->receiveAll(response.data(), responseSize, &bytesRecv);
|
||||
if(result == Socket::Result::SUCCESS)
|
||||
{
|
||||
message.setData(response);
|
||||
return GatorApi::MessageResult::SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return GatorApi::MessageResult::ERROR;
|
||||
}
|
||||
|
||||
void GatorApi::processMessage(GatorMessage &message)
|
||||
{
|
||||
if(!message.getData().empty() && message.getType() == RESPONSE_APC_DATA &&
|
||||
message.getPackedInt() == FRAME_BLOCK_COUNTER)
|
||||
{
|
||||
processBlockCounter(message);
|
||||
}
|
||||
}
|
||||
|
||||
void GatorApi::processBlockCounter(GatorMessage &message)
|
||||
{
|
||||
(void) message.getPackedInt(); // skip first item in message
|
||||
|
||||
while(message.hasRemaining())
|
||||
{
|
||||
int64_t key = message.getPackedInt();
|
||||
int64_t value = message.getPackedInt();
|
||||
|
||||
if(isValidKey(key))
|
||||
{
|
||||
Value v;
|
||||
v.as_int = value;
|
||||
for(LizardCounter counter : m_availableCounters)
|
||||
{
|
||||
if(counter.internalKey() == (uint64_t)key)
|
||||
{
|
||||
m_data.addValue(counter.id(), v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GatorApi::isValidKey(int64_t key)
|
||||
{
|
||||
return key > 2;
|
||||
}
|
||||
|
||||
} /* namespace lizard */
|
||||
@@ -0,0 +1,90 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GATOR_API_H
|
||||
#define GATOR_API_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../../gator_message.hpp"
|
||||
#include "lizard_counter.hpp"
|
||||
#include "socket.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
#define GATOR_PROTOCOL_VERSION "VERSION 671\n";
|
||||
#define STREAMLINE "STREAMLINE\n";
|
||||
|
||||
class GatorApi
|
||||
{
|
||||
public:
|
||||
enum MessageResult
|
||||
{
|
||||
SUCCESS,
|
||||
ERROR,
|
||||
};
|
||||
|
||||
GatorApi(char *host, const uint32_t port, std::vector<LizardCounter> &availableCounters,
|
||||
LizardCounterDataStore &dataStore);
|
||||
~GatorApi();
|
||||
bool createConnection();
|
||||
void destroyConnection();
|
||||
bool init(uint32_t &counterId);
|
||||
bool sendVersion();
|
||||
void startCapture();
|
||||
void stopCapture();
|
||||
void sendDisconnect();
|
||||
MessageResult readMessage(GatorMessage &message);
|
||||
void processMessage(GatorMessage &message);
|
||||
bool resendConfiguration(const std::vector<LizardCounter> &enabledGatorCounters);
|
||||
bool startSession();
|
||||
|
||||
private:
|
||||
bool setupCapturedCounters();
|
||||
bool sendConfiguration(const std::vector<LizardCounter> &enabledCounters);
|
||||
bool sendSession();
|
||||
void requestXml(const std::string &attributeValue);
|
||||
void sendXml(const std::string &xml);
|
||||
uint8_t getResponse();
|
||||
std::string getXmlResponse();
|
||||
Socket::Result getResponseHeader(uint8_t *responseType, uint32_t *responseSize);
|
||||
void sendCommand(uint8_t command);
|
||||
std::string requestCounters();
|
||||
std::string requestEvents();
|
||||
std::string requestConfiguration();
|
||||
std::string requestDefaults();
|
||||
std::string requestCaptured();
|
||||
void processBlockCounter(GatorMessage &message);
|
||||
bool isValidKey(int64_t key);
|
||||
|
||||
char *m_host;
|
||||
const uint32_t m_port;
|
||||
Socket *m_connection;
|
||||
std::vector<LizardCounter> &m_availableCounters;
|
||||
LizardCounterDataStore &m_data;
|
||||
};
|
||||
|
||||
} /* namespace lizard */
|
||||
|
||||
#endif // GATOR_API_H
|
||||
@@ -0,0 +1,88 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GATOR_CONSTANTS_H
|
||||
#define GATOR_CONSTANTS_H
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
enum
|
||||
{
|
||||
FRAME_UNKNOWN = 0,
|
||||
FRAME_SUMMARY = 1,
|
||||
FRAME_BACKTRACE = 2,
|
||||
FRAME_NAME = 3,
|
||||
FRAME_COUNTER = 4,
|
||||
FRAME_BLOCK_COUNTER = 5,
|
||||
FRAME_ANNOTATE = 6,
|
||||
FRAME_SCHED_TRACE = 7,
|
||||
FRAME_IDLE = 9,
|
||||
FRAME_EXTERNAL = 10,
|
||||
FRAME_PERF_ATTRS = 11,
|
||||
FRAME_PROC = 11,
|
||||
FRAME_PERF = 12,
|
||||
FRAME_ACTIVITY_TRACE = 13,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RESPONSE_XML = 1,
|
||||
RESPONSE_APC_DATA = 3,
|
||||
RESPONSE_ACK = 4,
|
||||
RESPONSE_NAK = 5,
|
||||
RESPONSE_ERROR = 0xFF
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
COMMAND_REQUEST_XML = 0,
|
||||
COMMAND_DELIVER_XML = 1,
|
||||
COMMAND_APC_START = 2,
|
||||
COMMAND_APC_STOP = 3,
|
||||
COMMAND_DISCONNECT = 4,
|
||||
COMMAND_PING = 5
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CLASS_UNKNOWN,
|
||||
CLASS_ABSOLUTE,
|
||||
CLASS_ACTIVITY,
|
||||
CLASS_DELTA,
|
||||
CLASS_INCIDENT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DISPLAY_UNKNOWN,
|
||||
DISPLAY_ACCUMULATE,
|
||||
DISPLAY_AVERAGE,
|
||||
DISPLAY_MAXIMUM,
|
||||
DISPLAY_MINIMUM,
|
||||
DISPLAY_HERTZ
|
||||
};
|
||||
|
||||
} /* namespace lizard */
|
||||
|
||||
#endif // GATOR_CONSTANTS_H
|
||||
@@ -0,0 +1,91 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "gator_message.hpp"
|
||||
#include "message_util.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
GatorMessage::GatorMessage() : m_type(0), m_pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
GatorMessage::GatorMessage(const std::vector<uint8_t> &in, uint8_t type)
|
||||
: m_in(in), m_type(type), m_pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
GatorMessage::~GatorMessage()
|
||||
{
|
||||
}
|
||||
|
||||
void GatorMessage::setType(uint8_t type)
|
||||
{
|
||||
m_type = type;
|
||||
}
|
||||
|
||||
uint8_t GatorMessage::getType()
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void GatorMessage::setData(const std::vector<uint8_t> &data)
|
||||
{
|
||||
m_in = data;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> &GatorMessage::getData()
|
||||
{
|
||||
return m_in;
|
||||
}
|
||||
|
||||
bool GatorMessage::hasData()
|
||||
{
|
||||
return !m_in.empty();
|
||||
}
|
||||
|
||||
bool GatorMessage::hasRemaining()
|
||||
{
|
||||
return m_pos < (m_in.size() - 1);
|
||||
}
|
||||
|
||||
int64_t GatorMessage::getPackedInt()
|
||||
{
|
||||
unsigned int sizeRead;
|
||||
int64_t value = decodeSLEB128(&m_in[m_pos], &sizeRead);
|
||||
m_pos += sizeRead;
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string GatorMessage::getGatorString()
|
||||
{
|
||||
unsigned int sizeRead;
|
||||
int64_t stringLength = decodeSLEB128(&m_in[m_pos], &sizeRead);
|
||||
m_pos += sizeRead;
|
||||
std::string result(m_in.begin() + m_pos, m_in.begin() + m_pos + stringLength);
|
||||
m_pos += stringLength;
|
||||
return result;
|
||||
}
|
||||
|
||||
} /* namespace lizard */
|
||||
@@ -0,0 +1,57 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GATOR_MESSAGE_H
|
||||
#define GATOR_MESSAGE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "stdint.h"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
class GatorMessage
|
||||
{
|
||||
public:
|
||||
GatorMessage();
|
||||
GatorMessage(const std::vector<uint8_t> &in, uint8_t type);
|
||||
~GatorMessage();
|
||||
int64_t getPackedInt();
|
||||
std::string getGatorString();
|
||||
bool hasRemaining();
|
||||
bool hasData();
|
||||
void setType(uint8_t type);
|
||||
uint8_t getType();
|
||||
void setData(const std::vector<uint8_t> &data);
|
||||
const std::vector<uint8_t> &getData();
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> m_in;
|
||||
uint8_t m_type;
|
||||
unsigned int m_pos;
|
||||
};
|
||||
|
||||
} /* namespace lizard */
|
||||
|
||||
#endif // GATOR_MESSAGE_H
|
||||
@@ -0,0 +1,266 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "gatord_xml_reader.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "gator_constants.hpp"
|
||||
|
||||
#include <pugixml/pugixml.hpp>
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
static void reportXmlError(pugi::xml_parse_result result, const void *xmlData, size_t xmlSize)
|
||||
{
|
||||
std::cout << "XML [] parsed with errors: ";
|
||||
std::cout << "Error description: " << result.description() << "\n";
|
||||
std::cout << "Error offset: " << result.offset << " (error at [..."
|
||||
<< (static_cast<const char *>(xmlData) + result.offset) << "]\n\n";
|
||||
}
|
||||
|
||||
static uint8_t strToEventClass(const std::string &eventClass)
|
||||
{
|
||||
if(eventClass == "absolute")
|
||||
{
|
||||
return CLASS_ABSOLUTE;
|
||||
}
|
||||
else if(eventClass == "activity")
|
||||
{
|
||||
return CLASS_ACTIVITY;
|
||||
}
|
||||
else if(eventClass == "delta")
|
||||
{
|
||||
return CLASS_DELTA;
|
||||
}
|
||||
else if(eventClass == "incident")
|
||||
{
|
||||
return CLASS_INCIDENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CLASS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t strToEventDisplay(const std::string &eventDisplay)
|
||||
{
|
||||
if(eventDisplay == "accumulate")
|
||||
{
|
||||
return DISPLAY_ACCUMULATE;
|
||||
}
|
||||
else if(eventDisplay == "average")
|
||||
{
|
||||
return DISPLAY_AVERAGE;
|
||||
}
|
||||
else if(eventDisplay == "maximum")
|
||||
{
|
||||
return DISPLAY_MAXIMUM;
|
||||
}
|
||||
else if(eventDisplay == "minimum")
|
||||
{
|
||||
return DISPLAY_MINIMUM;
|
||||
}
|
||||
else if(eventDisplay == "hertz")
|
||||
{
|
||||
return DISPLAY_HERTZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DISPLAY_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static LizardCounter::UnitType strToEventUnits(const std::string &eventUnits)
|
||||
{
|
||||
if(eventUnits == "B")
|
||||
{
|
||||
return LizardCounter::UNITS_BYTE;
|
||||
}
|
||||
else if(eventUnits == "Hz")
|
||||
{
|
||||
return LizardCounter::UNITS_HZ;
|
||||
}
|
||||
else if(eventUnits == "MHz")
|
||||
{
|
||||
return LizardCounter::UNITS_MHZ;
|
||||
}
|
||||
else if(eventUnits == "pages")
|
||||
{
|
||||
return LizardCounter::UNITS_PAGES;
|
||||
}
|
||||
else if(eventUnits == "s")
|
||||
{
|
||||
return LizardCounter::UNITS_S;
|
||||
}
|
||||
else if(eventUnits == "V")
|
||||
{
|
||||
return LizardCounter::UNITS_V;
|
||||
}
|
||||
else if(eventUnits == "mV")
|
||||
{
|
||||
return LizardCounter::UNITS_MV;
|
||||
}
|
||||
else if(eventUnits == "°C")
|
||||
{
|
||||
return LizardCounter::UNITS_CELSIUS;
|
||||
}
|
||||
else if(eventUnits == "RPM")
|
||||
{
|
||||
return LizardCounter::UNITS_RPM;
|
||||
}
|
||||
else
|
||||
{
|
||||
return LizardCounter::UNITS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<GatordXML::Configuration> GatordXML::parseConfiguration(const void *xmlData,
|
||||
size_t xmlSize)
|
||||
{
|
||||
std::vector<GatordXML::Configuration> configurations;
|
||||
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_buffer(xmlData, xmlSize);
|
||||
|
||||
if(result)
|
||||
{
|
||||
for(pugi::xml_node &cfg : doc.child("configurations").children("configuration"))
|
||||
{
|
||||
std::string name = cfg.attribute("counter").as_string();
|
||||
uint32_t event = cfg.attribute("event").as_uint();
|
||||
uint32_t cores = cfg.attribute("cores").as_uint();
|
||||
|
||||
assert(name.size() > 0);
|
||||
|
||||
configurations.push_back({name, event, cores});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reportXmlError(result, xmlData, xmlSize);
|
||||
}
|
||||
|
||||
return configurations;
|
||||
}
|
||||
|
||||
std::vector<std::string> GatordXML::parseCounters(const void *xmlData, size_t xmlSize)
|
||||
{
|
||||
std::vector<std::string> counters;
|
||||
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_buffer(xmlData, xmlSize);
|
||||
|
||||
if(result)
|
||||
{
|
||||
for(pugi::xml_node &cfg : doc.child("counters").children("counter"))
|
||||
{
|
||||
std::string name = cfg.attribute("name").as_string();
|
||||
assert(name.size() > 0);
|
||||
counters.push_back(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reportXmlError(result, xmlData, xmlSize);
|
||||
}
|
||||
|
||||
return counters;
|
||||
}
|
||||
|
||||
std::vector<GatordXML::EventCategory> GatordXML::parseEvents(const void *xmlData, size_t xmlSize)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_buffer(xmlData, xmlSize);
|
||||
|
||||
if(!result)
|
||||
{
|
||||
reportXmlError(result, xmlData, xmlSize);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<GatordXML::EventCategory> eventCategories;
|
||||
|
||||
for(pugi::xml_node &categoryNode : doc.child("events").children("category"))
|
||||
{
|
||||
GatordXML::EventCategory category;
|
||||
category.name = categoryNode.attribute("name").as_string();
|
||||
assert(category.name.size() > 0);
|
||||
|
||||
for(pugi::xml_node &eventNode : categoryNode.children("event"))
|
||||
{
|
||||
GatordXML::Event event;
|
||||
event.name = eventNode.attribute("name").as_string();
|
||||
event.title = eventNode.attribute("title").as_string();
|
||||
event.counter = eventNode.attribute("counter").as_string();
|
||||
event.description = eventNode.attribute("description").as_string();
|
||||
event.event = eventNode.attribute("event").as_uint();
|
||||
event.eventClass = strToEventClass(eventNode.attribute("class").as_string());
|
||||
event.display = strToEventDisplay(eventNode.attribute("display").as_string());
|
||||
event.units = strToEventUnits(eventNode.attribute("units").as_string());
|
||||
event.multiplier = eventNode.attribute("multiplier").as_double();
|
||||
if(event.multiplier == 0)
|
||||
{
|
||||
event.multiplier = 1;
|
||||
}
|
||||
assert(event.name.size() > 0);
|
||||
|
||||
category.events.push_back(event);
|
||||
}
|
||||
|
||||
eventCategories.push_back(category);
|
||||
}
|
||||
|
||||
return eventCategories;
|
||||
}
|
||||
|
||||
std::vector<GatordXML::CapturedCounter> GatordXML::parseCapturedCounters(const void *xmlData,
|
||||
size_t xmlSize)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_buffer(xmlData, xmlSize);
|
||||
|
||||
if(!result)
|
||||
{
|
||||
reportXmlError(result, xmlData, xmlSize);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<GatordXML::CapturedCounter> capturedCounters;
|
||||
|
||||
for(pugi::xml_node &counterNode : doc.child("captured").child("counters"))
|
||||
{
|
||||
GatordXML::CapturedCounter counter;
|
||||
counter.key = counterNode.attribute("key").as_int();
|
||||
counter.type = counterNode.attribute("type").as_string();
|
||||
counter.event = counterNode.attribute("event").as_int();
|
||||
capturedCounters.push_back(counter);
|
||||
}
|
||||
|
||||
return capturedCounters;
|
||||
}
|
||||
|
||||
} /* namespace lizard */
|
||||
@@ -0,0 +1,79 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIB_GATORD_XML_READER_HPP
|
||||
#define LIB_GATORD_XML_READER_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "lizard_counter.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
namespace GatordXML
|
||||
{
|
||||
struct Configuration
|
||||
{
|
||||
std::string name;
|
||||
uint32_t event;
|
||||
uint32_t cores;
|
||||
};
|
||||
|
||||
std::vector<Configuration> parseConfiguration(const void *xmlData, size_t xmlSize);
|
||||
std::vector<std::string> parseCounters(const void *xmlData, size_t xmlSize);
|
||||
|
||||
struct Event
|
||||
{
|
||||
std::string title;
|
||||
std::string name;
|
||||
std::string description;
|
||||
uint32_t event;
|
||||
std::string counter;
|
||||
uint8_t eventClass;
|
||||
uint8_t display;
|
||||
LizardCounter::UnitType units;
|
||||
double multiplier;
|
||||
};
|
||||
struct EventCategory
|
||||
{
|
||||
std::string name;
|
||||
std::vector<Event> events;
|
||||
};
|
||||
|
||||
std::vector<EventCategory> parseEvents(const void *xmlData, size_t xmlSize);
|
||||
|
||||
struct CapturedCounter
|
||||
{
|
||||
uint32_t key;
|
||||
std::string type;
|
||||
uint32_t event;
|
||||
};
|
||||
|
||||
std::vector<CapturedCounter> parseCapturedCounters(const void *xmlData, size_t xmlSize);
|
||||
}
|
||||
|
||||
} /* namespace lizard */
|
||||
|
||||
#endif /* LIB_GATORD_XML_READER_HPP */
|
||||
@@ -0,0 +1,172 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "hwcpipe_api.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
HwcPipeApi::HwcPipeApi(std::vector<LizardCounter> &availableCounters,
|
||||
LizardCounterDataStore &dataStore)
|
||||
: m_availableCounters(availableCounters), m_data(dataStore), m_HwcPipe(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
HwcPipeApi::~HwcPipeApi()
|
||||
{
|
||||
if(m_HwcPipe)
|
||||
{
|
||||
delete m_HwcPipe;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TID, typename TINFO, typename THASH>
|
||||
LizardCounter createCounter(uint64_t counterId, TID hwcpipeId,
|
||||
const std::unordered_map<std::string, TID> &names,
|
||||
const std::unordered_map<TID, TINFO, THASH> &info,
|
||||
const std::string &category, const LizardCounter::SourceType sourceType)
|
||||
{
|
||||
std::string title;
|
||||
for(auto &i : names)
|
||||
{
|
||||
if(i.second == hwcpipeId)
|
||||
{
|
||||
title = i.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::string desc = (info.at(hwcpipeId)).desc;
|
||||
std::string unit = (info.at(hwcpipeId)).unit;
|
||||
std::string key = "";
|
||||
std::string name = "";
|
||||
LizardCounter cnt = LizardCounter(
|
||||
++counterId, key.c_str(), name.c_str(), title.c_str(), desc.c_str(), category.c_str(), 1,
|
||||
unit.compare("B") == 0 ? LizardCounter::UNITS_BYTE : LizardCounter::UNITS_UNKNOWN,
|
||||
LizardCounter::CLASS_ABSOLUTE, sourceType);
|
||||
cnt.setInternalKey((uint64_t)hwcpipeId);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
bool HwcPipeApi::init(uint32_t &counterId)
|
||||
{
|
||||
m_HwcPipe = new hwcpipe::HWCPipe();
|
||||
|
||||
uint64_t counterNum = counterId;
|
||||
|
||||
if(m_HwcPipe->cpu_profiler())
|
||||
{
|
||||
for(hwcpipe::CpuCounter hwcpipeId : m_HwcPipe->cpu_profiler()->supported_counters())
|
||||
{
|
||||
m_availableCounters.push_back(createCounter(++counterId, hwcpipeId, hwcpipe::cpu_counter_names,
|
||||
hwcpipe::cpu_counter_info, "HWCPipe CPU Counter",
|
||||
LizardCounter::SOURCE_HWCPIPE_CPU));
|
||||
}
|
||||
}
|
||||
|
||||
if(m_HwcPipe->gpu_profiler())
|
||||
{
|
||||
for(hwcpipe::GpuCounter hwcpipeId : m_HwcPipe->gpu_profiler()->supported_counters())
|
||||
{
|
||||
m_availableCounters.push_back(createCounter(++counterId, hwcpipeId, hwcpipe::gpu_counter_names,
|
||||
hwcpipe::gpu_counter_info, "HWCPipe GPU Counter",
|
||||
LizardCounter::SOURCE_HWCPIPE_GPU));
|
||||
}
|
||||
}
|
||||
|
||||
return counterId > counterNum;
|
||||
}
|
||||
|
||||
void HwcPipeApi::enableCounters(const std::vector<LizardCounter> &counters)
|
||||
{
|
||||
hwcpipe::CpuCounterSet cpuCounterSet;
|
||||
hwcpipe::GpuCounterSet gpuCounterSet;
|
||||
|
||||
for(LizardCounter counter : counters)
|
||||
{
|
||||
switch(counter.sourceType())
|
||||
{
|
||||
case LizardCounter::SourceType::SOURCE_HWCPIPE_CPU:
|
||||
cpuCounterSet.insert((hwcpipe::CpuCounter)counter.internalKey());
|
||||
break;
|
||||
case LizardCounter::SourceType::SOURCE_HWCPIPE_GPU:
|
||||
gpuCounterSet.insert((hwcpipe::GpuCounter)counter.internalKey());
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
m_HwcPipe->set_enabled_cpu_counters(cpuCounterSet);
|
||||
m_HwcPipe->set_enabled_gpu_counters(gpuCounterSet);
|
||||
}
|
||||
|
||||
void HwcPipeApi::startCapture()
|
||||
{
|
||||
m_HwcPipe->run();
|
||||
m_HwcPipe->sample();
|
||||
}
|
||||
|
||||
void HwcPipeApi::stopCapture()
|
||||
{
|
||||
m_HwcPipe->stop();
|
||||
}
|
||||
|
||||
void HwcPipeApi::readMessage()
|
||||
{
|
||||
hwcpipe::Measurements measurements = m_HwcPipe->sample();
|
||||
if(measurements.cpu)
|
||||
{
|
||||
for(const std::pair<hwcpipe::CpuCounter, hwcpipe::Value> &data : *measurements.cpu)
|
||||
{
|
||||
for(LizardCounter &counter : m_availableCounters)
|
||||
{
|
||||
if(counter.sourceType() == LizardCounter::SourceType::SOURCE_HWCPIPE_CPU &&
|
||||
counter.internalKey() == (uint64_t)data.first)
|
||||
{
|
||||
Value value;
|
||||
value.as_double = data.second.get<long long>();
|
||||
m_data.addValue(counter.id(), value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(measurements.gpu)
|
||||
{
|
||||
for(const std::pair<hwcpipe::GpuCounter, hwcpipe::Value> &data : *measurements.gpu)
|
||||
{
|
||||
for(LizardCounter &counter : m_availableCounters)
|
||||
{
|
||||
if(counter.sourceType() == LizardCounter::SourceType::SOURCE_HWCPIPE_GPU &&
|
||||
counter.internalKey() == (uint64_t)data.first)
|
||||
{
|
||||
Value value;
|
||||
value.as_double = data.second.get<double>();
|
||||
m_data.addValue(counter.id(), value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIB_HWCPIPE_API_H
|
||||
#define LIB_HWCPIPE_API_H
|
||||
|
||||
#include "thirdparty/hwcpipe/hwcpipe.h"
|
||||
#include "lizard_counter.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
class HwcPipeApi
|
||||
{
|
||||
public:
|
||||
HwcPipeApi(std::vector<LizardCounter> &availableCounters, LizardCounterDataStore &dataStore);
|
||||
~HwcPipeApi();
|
||||
bool init(uint32_t &counterNum);
|
||||
void enableCounters(const std::vector<LizardCounter> &counters);
|
||||
void startCapture();
|
||||
void stopCapture();
|
||||
void readMessage();
|
||||
|
||||
private:
|
||||
std::vector<LizardCounter> &m_availableCounters;
|
||||
LizardCounterDataStore &m_data;
|
||||
hwcpipe::HWCPipe *m_HwcPipe;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* LIB_HWCPIPE_API_H */
|
||||
@@ -0,0 +1,63 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <hwcpipe_communication.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
HwcPipeThread::HwcPipeThread(HwcPipeApi &hwcPipeApi)
|
||||
: m_HwcPipeApi(hwcPipeApi), m_thread()
|
||||
{
|
||||
}
|
||||
|
||||
HwcPipeThread::~HwcPipeThread()
|
||||
{
|
||||
}
|
||||
|
||||
void HwcPipeThread::start(void)
|
||||
{
|
||||
m_shouldWork = true;
|
||||
m_HwcPipeApi.startCapture();
|
||||
m_thread = std::thread(&HwcPipeThread::worker, this);
|
||||
}
|
||||
|
||||
void HwcPipeThread::stop(void)
|
||||
{
|
||||
m_shouldWork = false;
|
||||
m_thread.join();
|
||||
m_HwcPipeApi.stopCapture();
|
||||
}
|
||||
|
||||
void HwcPipeThread::worker(void)
|
||||
{
|
||||
while(m_shouldWork != false)
|
||||
{
|
||||
m_HwcPipeApi.readMessage();
|
||||
}
|
||||
m_HwcPipeApi.readMessage();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIB_HWCPIPE_COMMUNICATION_HPP
|
||||
#define LIB_HWCPIPE_COMMUNICATION_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#include "hwcpipe_api.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
class HwcPipeThread
|
||||
{
|
||||
public:
|
||||
HwcPipeThread(HwcPipeApi &hwcPipeApi);
|
||||
~HwcPipeThread(void);
|
||||
|
||||
void start(void);
|
||||
void stop(void);
|
||||
|
||||
private:
|
||||
void worker(void);
|
||||
|
||||
std::atomic<bool> m_shouldWork;
|
||||
HwcPipeApi& m_HwcPipeApi;
|
||||
std::thread m_thread;
|
||||
};
|
||||
|
||||
} /* namespace lizard */
|
||||
|
||||
#endif /* LIB_HWCPIPE_COMMUNICATION_HPP */
|
||||
@@ -0,0 +1,176 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIB_LIZARD_HPP
|
||||
#define LIB_LIZARD_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <lizard_counter.hpp>
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
class GatorApi;
|
||||
class CommunicationThread;
|
||||
class HwcPipeApi;
|
||||
class HwcPipeThread;
|
||||
|
||||
class Lizard
|
||||
{
|
||||
public:
|
||||
Lizard(void);
|
||||
|
||||
~Lizard(void);
|
||||
|
||||
/**
|
||||
* Set the gatord hostname and port number to connect to.
|
||||
*
|
||||
* :param hostname: should be an ipv4 compatible address or hostname.
|
||||
* :param port: port number.
|
||||
*/
|
||||
bool configure(const char *hostname, uint32_t port);
|
||||
|
||||
/**
|
||||
* Query the list of available counters into an array.
|
||||
*
|
||||
* Usage:
|
||||
* {
|
||||
* Lizard lzd; // lzd should be configured after initialization!
|
||||
*
|
||||
* int count = lzd.availableCountersCount();
|
||||
* std::vector<LizardCounter> counters;
|
||||
* counters.reserve(count);
|
||||
*
|
||||
* int copied = lzd.availableCounters(&counters[0], count));
|
||||
* }
|
||||
*
|
||||
* :param outCounter: output array of available counters.
|
||||
* :param arraySize: size (element count) of the `outCounter` array.
|
||||
* :returns: the number of `LizardCounter` elements copied into the `outCounter` array.
|
||||
*/
|
||||
uint32_t availableCounters(LizardCounter *outCounters, uint32_t arraySize);
|
||||
|
||||
/**
|
||||
* Query the list of available counters (non-copy).
|
||||
*
|
||||
* Usage:
|
||||
* {
|
||||
* Lizard lzd; // lzd should be configured after initialization!
|
||||
*
|
||||
* int count = lzd.availableCountersCount();
|
||||
* LizardCounter *counterslzd.availableCounters();
|
||||
* }
|
||||
*
|
||||
* :returns: a pointer to a `LizardCounter` array containing maximum `availableCountersCount()`
|
||||
* elements.
|
||||
*/
|
||||
const LizardCounter *availableCounters(void) const { return &m_availableCounters[0]; }
|
||||
|
||||
/**
|
||||
* Query the number of available counters;
|
||||
*
|
||||
* Usage:
|
||||
* See `availableCounters`.
|
||||
*
|
||||
* :returns: number of `LizardCounter` elements available.
|
||||
*/
|
||||
uint32_t availableCountersCount(void) const;
|
||||
|
||||
/**
|
||||
* Enable a set of counters based on Id values.
|
||||
*
|
||||
* Usage:
|
||||
* {
|
||||
* Lizard lzd; // lzd should be configured after initialization!
|
||||
*
|
||||
* std::vector<LizardCounter> counters;
|
||||
* // fill counters with required counters.
|
||||
* // ...
|
||||
* // Enable the first three counters.
|
||||
* std::vector<LizardCounterId> ids;
|
||||
* ids.reserve(3);
|
||||
* lizard::countersToIds(&counters[0], &ids[0], 3);
|
||||
*
|
||||
* lzd.enableCounters(&ids[0], 3);
|
||||
* }
|
||||
*
|
||||
* :param counterIds: array of `LizardCounterId` values to enable.
|
||||
* :param arraySize: size (element count) of the `counterIds` array.
|
||||
*/
|
||||
void enableCounters(const LizardCounterId *counterIds, uint32_t arraySize);
|
||||
|
||||
void disableCounters(const LizardCounterId *counterIds, uint32_t arraySize);
|
||||
|
||||
/**
|
||||
* Start the capture of the enabled counters.
|
||||
*
|
||||
* This operation does not block. Underlying communication is done in a different thread.
|
||||
*
|
||||
* :returns: true if the capture was started correctly, otherwise false.
|
||||
*/
|
||||
bool startCapture(void);
|
||||
|
||||
/**
|
||||
* Stops the capture.
|
||||
*
|
||||
* Captured data can be accessed via another method.
|
||||
*/
|
||||
void endCapture(void);
|
||||
|
||||
LizardCounterData *readCounter(const LizardCounterId counterId) const;
|
||||
|
||||
size_t readCounterInt(const LizardCounterId counterId, int64_t *values) const;
|
||||
size_t readCounterDouble(const LizardCounterId counterId, double *values) const;
|
||||
|
||||
const LizardCounter *getCounterInfo(const LizardCounterId counterId) const;
|
||||
|
||||
private:
|
||||
bool configureGatord(const char *hostname, uint32_t port);
|
||||
bool configureHwcPipe(void);
|
||||
bool startGatord(void);
|
||||
void stopGatord(void);
|
||||
bool startHwcPipe(void);
|
||||
void stopHwcPipe(void);
|
||||
|
||||
uint32_t m_idCounter;
|
||||
|
||||
std::vector<LizardCounter> m_availableCounters;
|
||||
std::vector<bool> m_enabledCounters;
|
||||
|
||||
GatorApi *m_gatorApi;
|
||||
CommunicationThread *m_comm;
|
||||
|
||||
HwcPipeApi *m_HwcPipeApi;
|
||||
HwcPipeThread *m_HwcPipe_comm;
|
||||
|
||||
bool m_configuredGatord;
|
||||
bool m_configuredHwcPipe;
|
||||
|
||||
LizardCounterDataStore m_dataStore;
|
||||
};
|
||||
|
||||
} /* namepsace lizard */
|
||||
|
||||
#endif /* LIB_LIZARD_HPP */
|
||||
@@ -0,0 +1,234 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIB_LIZARD_API_H
|
||||
#define LIB_LIZARD_API_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // End of __cplusplus
|
||||
|
||||
struct LizardApi;
|
||||
typedef void *LizardInstance;
|
||||
typedef uint32_t LizardCounterId;
|
||||
|
||||
enum LizardVersion
|
||||
{
|
||||
LIZARD_VERSION_0_1 = 1,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
LZD_OK = 0,
|
||||
LZD_FAILURE,
|
||||
} LZD_Result;
|
||||
|
||||
/**
|
||||
* LizardInstance* LZD_Init(const char* host, int port);
|
||||
*
|
||||
* Initializes a Lizard Instance with the given host:port arguments.
|
||||
* The Lizard Instance must be destroyed with the LZD_Destroy method.
|
||||
*
|
||||
* :param host: IP address of the target gatord.
|
||||
* :param port: Port number of the target gatord.
|
||||
*/
|
||||
typedef LizardInstance (*LZD_Init_PFN)(const char *host, int port);
|
||||
|
||||
/**
|
||||
* void LZD_Destroy(LizardInstance** ctx);
|
||||
*
|
||||
* Destroy the Lizard Instance and sets the `ctx` pointer's value to NULL.
|
||||
*/
|
||||
typedef void (*LZD_Destroy_PFN)(LizardInstance ctx);
|
||||
|
||||
/**
|
||||
* Get the number of the available counters.
|
||||
*
|
||||
* The LizardIds are in the range of [1, MAX_UINT].
|
||||
*
|
||||
* :param ctx: LizardInstance created via LZD_Init.
|
||||
* :returns: Number of available counters.
|
||||
*/
|
||||
typedef uint32_t (*LZD_GetAvailableCountersCount_PFN)(LizardInstance ctx);
|
||||
|
||||
|
||||
struct LizardCounterDescription
|
||||
{
|
||||
LizardCounterId id;
|
||||
const char *short_name;
|
||||
const char *name;
|
||||
const char *title;
|
||||
const char *description;
|
||||
const char *category;
|
||||
double multiplier;
|
||||
uint32_t units;
|
||||
uint32_t class_type;
|
||||
uint32_t result_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get information about the counter
|
||||
*
|
||||
* :param ctx: LizardInstance created via LZD_Init.
|
||||
* :param id: id of the counter, must be 1 or above.
|
||||
* :param lzdDesc: LizardCounterDescription to be populated.
|
||||
* :returns: LZD_OK if succeeded
|
||||
*/
|
||||
typedef LZD_Result (*LZD_GetCounterDescription_PFN)(LizardInstance ctx, LizardCounterId id,
|
||||
LizardCounterDescription *lzdDesc);
|
||||
|
||||
/**
|
||||
* Enable the counter for capture.
|
||||
*
|
||||
* :param ctx: Lizard Instance created via LZD_Init.
|
||||
* :param id: Id of the counter to enable.
|
||||
*/
|
||||
typedef void (*LZD_EnableCounter_PFN)(LizardInstance ctx, LizardCounterId id);
|
||||
|
||||
/**
|
||||
* Disable the counter for capture.
|
||||
*
|
||||
* :param ctx: Lizard Instance created via LZD_Init
|
||||
* :param id: Id of the counter to disable.
|
||||
*/
|
||||
typedef void (*LZD_DisableCounter_PFN)(LizardInstance ctx, LizardCounterId id);
|
||||
|
||||
/**
|
||||
* Disable all counters for capture.
|
||||
*
|
||||
* By default all counters are disabled.
|
||||
*
|
||||
* :param ctx: Lizard Instance created via LZD_Init
|
||||
*/
|
||||
typedef void (*LZD_DisableAllCounters_PFN)(LizardInstance ctx);
|
||||
|
||||
/**
|
||||
* Start capture.
|
||||
*
|
||||
* The actual capture is performed in a different thread.
|
||||
*
|
||||
* :param ctx: Lizard Instance created via LZD_Init
|
||||
* :returns: LZD_OK if succeeded
|
||||
*/
|
||||
typedef LZD_Result (*LZD_StartCapture_PFN)(LizardInstance ctx);
|
||||
|
||||
/**
|
||||
* Stop capture.
|
||||
*
|
||||
* :param ctx: Lizard Instance created via LZD_Init
|
||||
* :returns: LZD_OK if succeeded
|
||||
*/
|
||||
typedef LZD_Result (*LZD_StopCapture_PFN)(LizardInstance ctx);
|
||||
|
||||
typedef enum {
|
||||
LZD_ABSOLUTE = 1,
|
||||
LZD_DELTA = 2,
|
||||
} LZD_CounterClassType;
|
||||
|
||||
/**
|
||||
* Get the measured counter value as an integer.
|
||||
*
|
||||
* :param ctx: Lizard Instance created via LZD_Init
|
||||
* :param id: The id of the counter which value is measured.
|
||||
* :returns: The measured value.
|
||||
*/
|
||||
typedef int64_t (*LZD_ReadCounterInt_PFN)(LizardInstance ctx, LizardCounterId id);
|
||||
|
||||
/**
|
||||
* Get the measured counter value as a double.
|
||||
*
|
||||
* :param ctx: Lizard Instance created via LZD_Init
|
||||
* :param id: The id of the counter which value is measured.
|
||||
* :returns: The measured value.
|
||||
*/
|
||||
typedef double (*LZD_ReadCounterDouble_PFN)(LizardInstance ctx, LizardCounterId id);
|
||||
|
||||
typedef enum {
|
||||
LZD_UNITS_UNKNOWN,
|
||||
LZD_UNITS_BYTE,
|
||||
LZD_UNITS_CELSIUS,
|
||||
LZD_UNITS_HZ,
|
||||
LZD_UNITS_PAGES,
|
||||
LZD_UNITS_RPM,
|
||||
LZD_UNITS_S,
|
||||
LZD_UNITS_V,
|
||||
|
||||
LZD_TYPE_INT,
|
||||
LZD_TYPE_DOUBLE,
|
||||
} LZD_CounterAttribute;
|
||||
|
||||
struct LizardApi
|
||||
{
|
||||
int struct_size;
|
||||
int version;
|
||||
LZD_Init_PFN Init;
|
||||
LZD_Destroy_PFN Destroy;
|
||||
LZD_GetAvailableCountersCount_PFN GetAvailableCountersCount;
|
||||
LZD_GetCounterDescription_PFN GetCounterDescription;
|
||||
LZD_EnableCounter_PFN EnableCounter;
|
||||
LZD_DisableCounter_PFN DisableCounter;
|
||||
LZD_DisableAllCounters_PFN DisableAllCounters;
|
||||
|
||||
LZD_StartCapture_PFN StartCapture;
|
||||
LZD_StopCapture_PFN StopCapture;
|
||||
|
||||
LZD_ReadCounterInt_PFN ReadCounterInt;
|
||||
LZD_ReadCounterDouble_PFN ReadCounterDouble;
|
||||
};
|
||||
|
||||
/**
|
||||
* Entry point of the API.
|
||||
*
|
||||
* To load the api search for the "LoadApi" function symbol and
|
||||
* invoke the method with a `LizardApi` pointer to get access to all
|
||||
* API functions.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* void* lib = dlopen("liblizard.so", RTLD_LAZY);
|
||||
* LZD_LoadApi_PFN loadApi = (LZD_LoadApi_PFN)dlsym(lib, "LoadApi");
|
||||
*
|
||||
* struct LizardApi* api;
|
||||
*
|
||||
* if (loadApi(&api) != LZD_OK) {
|
||||
* // report failure and return
|
||||
* }
|
||||
* if (api->version != LIZARD_VERSION_0_1) {
|
||||
* // report version mismatch and return
|
||||
* }
|
||||
*
|
||||
* LizardInstance* ctx = api->Init("127.0.0.1", 8080);
|
||||
*
|
||||
* :param api: LizardApi struct pointer to initialize the API pointers.
|
||||
* :returns: LZD_OK if the counter initialization was ok.
|
||||
*/
|
||||
typedef LZD_Result (*LZD_LoadApi_PFN)(struct LizardApi **api);
|
||||
LZD_Result LoadApi(struct LizardApi **api);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // End of __cplusplus
|
||||
|
||||
#endif /* LIB_LIZARD_API_H */
|
||||
@@ -0,0 +1,136 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIB_LIZARD_COUNTER_HPP
|
||||
#define LIB_LIZARD_COUNTER_HPP
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
typedef uint32_t LizardCounterId;
|
||||
|
||||
typedef union
|
||||
{
|
||||
int64_t as_int;
|
||||
double as_double;
|
||||
} Value;
|
||||
|
||||
class LizardCounterData
|
||||
{
|
||||
public:
|
||||
LizardCounterData(LizardCounterId id, const int64_t *values, size_t length);
|
||||
LizardCounterData(LizardCounterId id, const double *values, size_t length);
|
||||
~LizardCounterData(void);
|
||||
const int64_t *getIntValues() const { return reinterpret_cast<int64_t *>(m_values); }
|
||||
const double *getDoubleValues() const { return reinterpret_cast<double *>(m_values); }
|
||||
const Value *getValues() const { return m_values; }
|
||||
LizardCounterId getId() const { return m_id; }
|
||||
size_t getLength() const { return m_length; }
|
||||
bool isInt() const { return m_is_int; }
|
||||
private:
|
||||
LizardCounterId m_id;
|
||||
Value *m_values;
|
||||
size_t m_length;
|
||||
bool m_is_int;
|
||||
};
|
||||
|
||||
class LizardCounter
|
||||
{
|
||||
public:
|
||||
enum ClassType
|
||||
{
|
||||
CLASS_ABSOLUTE,
|
||||
CLASS_DELTA,
|
||||
};
|
||||
|
||||
enum SourceType
|
||||
{
|
||||
SOURCE_GATORD,
|
||||
SOURCE_HWCPIPE_CPU,
|
||||
SOURCE_HWCPIPE_GPU,
|
||||
};
|
||||
|
||||
enum UnitType
|
||||
{
|
||||
UNITS_UNKNOWN,
|
||||
UNITS_BYTE,
|
||||
UNITS_CELSIUS,
|
||||
UNITS_HZ,
|
||||
UNITS_MHZ,
|
||||
UNITS_PAGES,
|
||||
UNITS_RPM,
|
||||
UNITS_S,
|
||||
UNITS_V,
|
||||
UNITS_MV
|
||||
};
|
||||
|
||||
LizardCounter() : m_id(0), m_multiplier(1) {}
|
||||
LizardCounter(LizardCounterId id, const char *key, const char *name, const char *title,
|
||||
const char *description, const char *category, const double multiplier,
|
||||
UnitType units, ClassType classType, SourceType sourceType);
|
||||
~LizardCounter(void) {}
|
||||
LizardCounterId id(void) const { return m_id; }
|
||||
const char *key(void) const { return m_key.c_str(); }
|
||||
const char *name(void) const { return m_name.c_str(); }
|
||||
const char *title(void) const { return m_title.c_str(); }
|
||||
const char *description(void) const { return m_description.c_str(); }
|
||||
const char *category(void) const { return m_category.c_str(); }
|
||||
double multiplier(void) const { return m_multiplier; }
|
||||
UnitType units(void) const { return m_units; }
|
||||
ClassType classType(void) const { return m_classType; }
|
||||
SourceType sourceType(void) const { return m_sourceType; }
|
||||
uint64_t internalKey(void) const { return m_internalKey; }
|
||||
void setInternalKey(uint64_t key);
|
||||
|
||||
private:
|
||||
const LizardCounterId m_id;
|
||||
std::string m_key;
|
||||
std::string m_name;
|
||||
std::string m_title;
|
||||
std::string m_description;
|
||||
std::string m_category;
|
||||
double m_multiplier;
|
||||
UnitType m_units;
|
||||
ClassType m_classType;
|
||||
SourceType m_sourceType;
|
||||
uint64_t m_internalKey;
|
||||
};
|
||||
|
||||
class LizardCounterDataStore
|
||||
{
|
||||
public:
|
||||
void addValue(int64_t key, Value value);
|
||||
const std::vector<Value> &getValues(int64_t key) const;
|
||||
void clear();
|
||||
|
||||
private:
|
||||
std::map<int64_t, std::vector<Value>> m_values;
|
||||
};
|
||||
|
||||
}; /* namespace lizard */
|
||||
|
||||
#endif /* LIB_LIZARD_COUNTER_HPP */
|
||||
@@ -0,0 +1,341 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "lizard.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
||||
#include "gator_api.hpp"
|
||||
#include "hwcpipe_communication.hpp"
|
||||
#include "lizard_communication.hpp"
|
||||
#include "lizard_counter.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
enum
|
||||
{
|
||||
MAX_HOSTNAME_SIZE = 64,
|
||||
};
|
||||
|
||||
Lizard::Lizard(void)
|
||||
: m_idCounter(0),
|
||||
m_availableCounters(),
|
||||
m_enabledCounters(),
|
||||
m_gatorApi(NULL),
|
||||
m_comm(NULL),
|
||||
m_HwcPipeApi(NULL),
|
||||
m_HwcPipe_comm(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Lizard::~Lizard()
|
||||
{
|
||||
if(m_gatorApi)
|
||||
{
|
||||
delete m_gatorApi;
|
||||
}
|
||||
if(m_HwcPipeApi)
|
||||
{
|
||||
delete m_HwcPipeApi;
|
||||
}
|
||||
}
|
||||
|
||||
bool Lizard::configure(const char *hostname, uint32_t port)
|
||||
{
|
||||
m_availableCounters.clear();
|
||||
|
||||
m_configuredGatord = configureGatord(hostname, port);
|
||||
m_configuredHwcPipe = configureHwcPipe();
|
||||
if(m_configuredGatord || m_configuredHwcPipe)
|
||||
{
|
||||
m_availableCounters.shrink_to_fit();
|
||||
m_enabledCounters.clear();
|
||||
m_enabledCounters.resize(m_availableCounters.size() + 1); // +1 as 0 ID is invalid
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Lizard::configureGatord(const char *hostname, uint32_t port)
|
||||
{
|
||||
m_gatorApi = new lizard::GatorApi(strndup(hostname, MAX_HOSTNAME_SIZE), port, m_availableCounters,
|
||||
m_dataStore);
|
||||
|
||||
if(!m_gatorApi->createConnection())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_gatorApi->sendVersion())
|
||||
{
|
||||
m_gatorApi->destroyConnection();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = m_gatorApi->init(m_idCounter);
|
||||
|
||||
m_gatorApi->sendDisconnect();
|
||||
m_gatorApi->destroyConnection();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
uint32_t Lizard::availableCountersCount(void) const
|
||||
{
|
||||
return m_availableCounters.size();
|
||||
}
|
||||
|
||||
void Lizard::enableCounters(const LizardCounterId *counterIds, uint32_t arraySize)
|
||||
{
|
||||
for(uint32_t idx = 0; idx < arraySize; idx++)
|
||||
{
|
||||
m_enabledCounters[counterIds[idx]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Lizard::disableCounters(const LizardCounterId *counterIds, uint32_t arraySize)
|
||||
{
|
||||
for(uint32_t idx = 0; idx < arraySize; idx++)
|
||||
{
|
||||
m_enabledCounters[counterIds[idx]] = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Lizard::startCapture(void)
|
||||
{
|
||||
m_dataStore.clear();
|
||||
|
||||
bool started = false;
|
||||
|
||||
if(m_configuredGatord)
|
||||
{
|
||||
started = startGatord() || started;
|
||||
}
|
||||
|
||||
if(m_configuredHwcPipe)
|
||||
{
|
||||
started = startHwcPipe() || started;
|
||||
}
|
||||
|
||||
return started;
|
||||
}
|
||||
|
||||
bool Lizard::startGatord()
|
||||
{
|
||||
if(m_comm != NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<LizardCounter> enabledGatorCounters;
|
||||
|
||||
for(size_t i = 0; i < m_availableCounters.size(); i++)
|
||||
{
|
||||
if(m_enabledCounters[m_availableCounters[i].id()] &&
|
||||
m_availableCounters[i].sourceType() == LizardCounter::SOURCE_GATORD)
|
||||
{
|
||||
enabledGatorCounters.push_back(m_availableCounters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!m_gatorApi->resendConfiguration(enabledGatorCounters))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_gatorApi->startSession())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_comm = new CommunicationThread(*m_gatorApi);
|
||||
m_comm->start();
|
||||
|
||||
// Give gatord a bit of time to start up
|
||||
usleep(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Lizard::startHwcPipe()
|
||||
{
|
||||
if(m_HwcPipe_comm != NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<LizardCounter> enabledHwcPipeCounters;
|
||||
|
||||
for(size_t i = 0; i < m_availableCounters.size(); i++)
|
||||
{
|
||||
if(m_enabledCounters[m_availableCounters[i].id()] &&
|
||||
(m_availableCounters[i].sourceType() == LizardCounter::SOURCE_HWCPIPE_CPU ||
|
||||
m_availableCounters[i].sourceType() == LizardCounter::SOURCE_HWCPIPE_GPU))
|
||||
{
|
||||
enabledHwcPipeCounters.push_back(m_availableCounters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(enabledHwcPipeCounters.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_HwcPipeApi->enableCounters(enabledHwcPipeCounters);
|
||||
|
||||
m_HwcPipe_comm = new HwcPipeThread(*m_HwcPipeApi);
|
||||
m_HwcPipe_comm->start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Lizard::endCapture(void)
|
||||
{
|
||||
stopGatord();
|
||||
stopHwcPipe();
|
||||
}
|
||||
|
||||
void Lizard::stopGatord(void)
|
||||
{
|
||||
if(m_comm != NULL)
|
||||
{
|
||||
usleep(1);
|
||||
m_comm->stop();
|
||||
|
||||
delete m_comm;
|
||||
m_comm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Lizard::stopHwcPipe(void)
|
||||
{
|
||||
if(m_HwcPipe_comm != NULL)
|
||||
{
|
||||
m_HwcPipe_comm->stop();
|
||||
|
||||
delete m_HwcPipe_comm;
|
||||
m_HwcPipe_comm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LizardCounterData *Lizard::readCounter(const LizardCounterId counterId) const
|
||||
{
|
||||
if(counterId < 1 || counterId > m_availableCounters.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const std::vector<Value> &values = m_dataStore.getValues(counterId);
|
||||
|
||||
switch(getCounterInfo(counterId)->sourceType())
|
||||
{
|
||||
case LizardCounter::SOURCE_GATORD:
|
||||
{
|
||||
std::vector<int64_t> vec(values.size());
|
||||
for(size_t i = 0; i < values.size(); i++)
|
||||
{
|
||||
vec[i] = values[i].as_int;
|
||||
}
|
||||
return new LizardCounterData(counterId, (int64_t *)&vec[0], vec.size());
|
||||
}
|
||||
case LizardCounter::SOURCE_HWCPIPE_CPU:
|
||||
case LizardCounter::SOURCE_HWCPIPE_GPU:
|
||||
{
|
||||
std::vector<double> vec(values.size());
|
||||
for(size_t i = 0; i < values.size(); i++)
|
||||
{
|
||||
vec[i] = values[i].as_double;
|
||||
}
|
||||
return new LizardCounterData(counterId, vec.data(), vec.size());
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t Lizard::readCounterInt(const LizardCounterId counterId, int64_t *values) const
|
||||
{
|
||||
if(counterId < 1 || counterId > m_availableCounters.size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::vector<Value> &vals = m_dataStore.getValues(counterId);
|
||||
std::vector<int64_t> vec(vals.size());
|
||||
|
||||
for(size_t i = 0; i < vals.size(); i++)
|
||||
{
|
||||
vec[i] = vals[i].as_int;
|
||||
}
|
||||
if(values)
|
||||
{
|
||||
memcpy(values, vec.data(), vec.size() * sizeof(int64_t));
|
||||
}
|
||||
|
||||
return vec.size();
|
||||
}
|
||||
|
||||
size_t Lizard::readCounterDouble(const LizardCounterId counterId, double *values) const
|
||||
{
|
||||
if(counterId < 1 || counterId > m_availableCounters.size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::vector<Value> &vals = m_dataStore.getValues(counterId);
|
||||
std::vector<double> vec(vals.size());
|
||||
|
||||
for(size_t i = 0; i < vals.size(); i++)
|
||||
{
|
||||
vec[i] = vals[i].as_double;
|
||||
}
|
||||
if(values)
|
||||
{
|
||||
memcpy(values, vec.data(), vec.size() * sizeof(double));
|
||||
}
|
||||
|
||||
return vec.size();
|
||||
}
|
||||
|
||||
const LizardCounter *Lizard::getCounterInfo(const LizardCounterId counterId) const
|
||||
{
|
||||
if(counterId < 1 || counterId > m_availableCounters.size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return &m_availableCounters[counterId - 1];
|
||||
}
|
||||
|
||||
bool Lizard::configureHwcPipe()
|
||||
{
|
||||
m_HwcPipeApi = new HwcPipeApi(m_availableCounters, m_dataStore);
|
||||
return m_HwcPipeApi->init(m_idCounter);
|
||||
}
|
||||
|
||||
} /* namespace lizard */
|
||||
@@ -0,0 +1,280 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <lizard_api.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
|
||||
#include <gator_constants.hpp>
|
||||
#include <lizard.hpp>
|
||||
|
||||
static LizardInstance LZD_Init(const char *host, int port)
|
||||
{
|
||||
lizard::Lizard *lzd = new lizard::Lizard();
|
||||
|
||||
bool configured = lzd->configure(host, port);
|
||||
|
||||
if(!configured)
|
||||
{
|
||||
delete lzd;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return static_cast<LizardInstance>(lzd);
|
||||
}
|
||||
|
||||
static void LZD_Destroy(LizardInstance ctx)
|
||||
{
|
||||
delete static_cast<lizard::Lizard *>(ctx);
|
||||
}
|
||||
|
||||
static uint32_t LZD_GetAvailableCountersCount(LizardInstance ctx)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
|
||||
if(lzd == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return lzd->availableCountersCount();
|
||||
}
|
||||
|
||||
static LZD_Result LZD_GetCounterDescription(LizardInstance ctx, LizardCounterId id,
|
||||
LizardCounterDescription *desc)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
|
||||
if(lzd == NULL || desc == NULL)
|
||||
{
|
||||
return LZD_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t count = lzd->availableCountersCount();
|
||||
|
||||
if(id == 0 || id > count)
|
||||
{
|
||||
return LZD_FAILURE;
|
||||
}
|
||||
|
||||
const lizard::LizardCounter *lzdCounter = lzd->availableCounters() + (id - 1);
|
||||
|
||||
desc->id = lzdCounter->id();
|
||||
desc->short_name = lzdCounter->key();
|
||||
desc->title = lzdCounter->title();
|
||||
desc->name = lzdCounter->name();
|
||||
desc->category = lzdCounter->category();
|
||||
desc->description = lzdCounter->description();
|
||||
desc->multiplier = lzdCounter->multiplier();
|
||||
|
||||
switch(lzdCounter->classType())
|
||||
{
|
||||
case lizard::LizardCounter::CLASS_ABSOLUTE: desc->class_type = LZD_ABSOLUTE; break;
|
||||
case lizard::LizardCounter::CLASS_DELTA: desc->class_type = LZD_DELTA; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch(lzdCounter->units())
|
||||
{
|
||||
case lizard::LizardCounter::UNITS_BYTE: desc->units = LZD_UNITS_BYTE; break;
|
||||
case lizard::LizardCounter::UNITS_CELSIUS: desc->units = LZD_UNITS_CELSIUS; break;
|
||||
case lizard::LizardCounter::UNITS_MHZ:
|
||||
case lizard::LizardCounter::UNITS_HZ: desc->units = LZD_UNITS_HZ; break;
|
||||
case lizard::LizardCounter::UNITS_PAGES: desc->units = LZD_UNITS_PAGES; break;
|
||||
case lizard::LizardCounter::UNITS_RPM: desc->units = LZD_UNITS_RPM; break;
|
||||
case lizard::LizardCounter::UNITS_S: desc->units = LZD_UNITS_S; break;
|
||||
case lizard::LizardCounter::UNITS_V: desc->units = LZD_UNITS_V; break;
|
||||
default: desc->units = LZD_UNITS_UNKNOWN; break;
|
||||
}
|
||||
|
||||
if(lzdCounter->multiplier() == 1 && lzdCounter->sourceType() == lizard::LizardCounter::SOURCE_GATORD)
|
||||
{
|
||||
desc->result_type = LZD_TYPE_INT;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc->result_type = LZD_TYPE_DOUBLE;
|
||||
}
|
||||
|
||||
return LZD_OK;
|
||||
}
|
||||
|
||||
static void LZD_EnableCounter(LizardInstance ctx, LizardCounterId id)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
if(lzd != NULL)
|
||||
{
|
||||
lzd->enableCounters(&id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void LZD_DisableCounter(LizardInstance ctx, LizardCounterId id)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
if(lzd != NULL)
|
||||
{
|
||||
lzd->disableCounters(&id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void LZD_DisableAllCounters(LizardInstance ctx)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
if(lzd != NULL)
|
||||
{
|
||||
uint32_t count = lzd->availableCountersCount();
|
||||
const lizard::LizardCounter *counters = lzd->availableCounters();
|
||||
|
||||
for(uint32_t idx = 0; idx < count; idx++)
|
||||
{
|
||||
lizard::LizardCounterId id = counters[idx].id();
|
||||
lzd->disableCounters(&id, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LZD_Result LZD_StartCapture(LizardInstance ctx)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
if(lzd == NULL)
|
||||
{
|
||||
return LZD_FAILURE;
|
||||
}
|
||||
bool result = lzd->startCapture();
|
||||
return result ? LZD_OK : LZD_FAILURE;
|
||||
}
|
||||
|
||||
static LZD_Result LZD_StopCapture(LizardInstance ctx)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
if(lzd == NULL)
|
||||
{
|
||||
return LZD_FAILURE;
|
||||
}
|
||||
lzd->endCapture();
|
||||
return LZD_OK;
|
||||
}
|
||||
|
||||
static int64_t LZD_ReadCounterInt(LizardInstance ctx, LizardCounterId id)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
|
||||
if(lzd == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t size = lzd->readCounterInt(id, nullptr);
|
||||
|
||||
std::vector<int64_t> values(size);
|
||||
|
||||
size = lzd->readCounterInt(id, values.data());
|
||||
|
||||
int64_t result = 0;
|
||||
|
||||
for(size_t idx = 0; idx < size; idx++)
|
||||
{
|
||||
result += values[idx];
|
||||
}
|
||||
|
||||
if(lzd->getCounterInfo(id)->classType() == lizard::LizardCounter::CLASS_ABSOLUTE && size != 0)
|
||||
{
|
||||
result /= size;
|
||||
}
|
||||
|
||||
if(lzd->getCounterInfo(id)->units() == lizard::LizardCounter::UNITS_MHZ)
|
||||
{
|
||||
result *= 1000000;
|
||||
}
|
||||
|
||||
return result * lzd->getCounterInfo(id)->multiplier();
|
||||
}
|
||||
|
||||
static double LZD_ReadCounterDouble(LizardInstance ctx, LizardCounterId id)
|
||||
{
|
||||
lizard::Lizard *lzd = static_cast<lizard::Lizard *>(ctx);
|
||||
|
||||
if(lzd == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t size = lzd->readCounterDouble(id, nullptr);
|
||||
|
||||
std::vector<double> values(size);
|
||||
|
||||
size = lzd->readCounterDouble(id, values.data());
|
||||
|
||||
double result = 0;
|
||||
|
||||
for(size_t idx = 0; idx < size; idx++)
|
||||
{
|
||||
result += values[idx];
|
||||
}
|
||||
|
||||
if(lzd->getCounterInfo(id)->classType() == lizard::LizardCounter::CLASS_ABSOLUTE && size != 0)
|
||||
{
|
||||
result /= size;
|
||||
}
|
||||
|
||||
return result * lzd->getCounterInfo(id)->multiplier();
|
||||
}
|
||||
|
||||
static struct LizardApi s_ApiInstance;
|
||||
|
||||
static void InitApi(void)
|
||||
{
|
||||
s_ApiInstance.struct_size = sizeof(struct LizardApi);
|
||||
s_ApiInstance.version = LIZARD_VERSION_0_1;
|
||||
s_ApiInstance.Init = &LZD_Init;
|
||||
s_ApiInstance.Destroy = &LZD_Destroy;
|
||||
s_ApiInstance.GetAvailableCountersCount = &LZD_GetAvailableCountersCount;
|
||||
s_ApiInstance.GetCounterDescription = &LZD_GetCounterDescription;
|
||||
s_ApiInstance.EnableCounter = &LZD_EnableCounter;
|
||||
s_ApiInstance.DisableCounter = &LZD_DisableCounter;
|
||||
s_ApiInstance.DisableAllCounters = &LZD_DisableAllCounters;
|
||||
s_ApiInstance.StartCapture = &LZD_StartCapture;
|
||||
s_ApiInstance.StopCapture = &LZD_StopCapture;
|
||||
s_ApiInstance.ReadCounterInt = &LZD_ReadCounterInt;
|
||||
s_ApiInstance.ReadCounterDouble = &LZD_ReadCounterDouble;
|
||||
}
|
||||
|
||||
extern "C" LZD_Result LoadApi(struct LizardApi **api)
|
||||
{
|
||||
static bool initialized = false;
|
||||
if(!initialized)
|
||||
{
|
||||
InitApi();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if(api == NULL)
|
||||
{
|
||||
return LZD_FAILURE;
|
||||
}
|
||||
|
||||
*api = &s_ApiInstance;
|
||||
return LZD_OK;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "lizard_communication.hpp"
|
||||
|
||||
#include "gator_api.hpp"
|
||||
#include "gator_message.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
CommunicationThread::CommunicationThread(GatorApi &gatorApi) : m_gatorApi(gatorApi), m_thread()
|
||||
{
|
||||
}
|
||||
|
||||
CommunicationThread::~CommunicationThread()
|
||||
{
|
||||
}
|
||||
|
||||
void CommunicationThread::start(void)
|
||||
{
|
||||
m_shouldWork = true;
|
||||
m_gatorApi.startCapture();
|
||||
m_thread = std::thread(&CommunicationThread::worker, this);
|
||||
}
|
||||
|
||||
void CommunicationThread::stop(void)
|
||||
{
|
||||
m_shouldWork = false;
|
||||
m_gatorApi.stopCapture();
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
void CommunicationThread::worker(void)
|
||||
{
|
||||
bool hasData = false;
|
||||
|
||||
while(m_shouldWork != false || hasData)
|
||||
{
|
||||
GatorMessage message;
|
||||
GatorApi::MessageResult result = m_gatorApi.readMessage(message);
|
||||
hasData = result == GatorApi::MessageResult::SUCCESS;
|
||||
if(hasData)
|
||||
{
|
||||
m_gatorApi.processMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef LIB_LIZARD_COMMUNICATION_HPP
|
||||
#define LIB_LIZARD_COMMUNICATION_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "gator_api.hpp"
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
class CommunicationThread
|
||||
{
|
||||
public:
|
||||
CommunicationThread(GatorApi &gatorApi);
|
||||
~CommunicationThread(void);
|
||||
|
||||
void start(void);
|
||||
void stop(void);
|
||||
|
||||
private:
|
||||
void worker(void);
|
||||
|
||||
std::atomic<bool> m_shouldWork;
|
||||
GatorApi &m_gatorApi;
|
||||
std::thread m_thread;
|
||||
};
|
||||
|
||||
} /* namespace lizard */
|
||||
|
||||
#endif /* LIB_LIZARD_COMMUNICATION_HPP */
|
||||
@@ -0,0 +1,92 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "lizard_counter.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
static std::vector<Value> s_empty;
|
||||
|
||||
LizardCounterData::LizardCounterData(LizardCounterId id, const int64_t *values, size_t length)
|
||||
: m_id(id), m_length(length), m_is_int(true)
|
||||
{
|
||||
m_values = new Value[length];
|
||||
memcpy(m_values, (const void *)values, sizeof(int64_t) * length);
|
||||
}
|
||||
|
||||
LizardCounterData::LizardCounterData(LizardCounterId id, const double *values, size_t length)
|
||||
: m_id(id), m_length(length), m_is_int(false)
|
||||
{
|
||||
m_values = new Value[length];
|
||||
memcpy(m_values, (const void *)values, sizeof(double) * length);
|
||||
}
|
||||
|
||||
LizardCounterData::~LizardCounterData()
|
||||
{
|
||||
delete[] m_values;
|
||||
}
|
||||
|
||||
LizardCounter::LizardCounter(LizardCounterId id, const char *key, const char *name, const char *title,
|
||||
const char *description, const char *category, const double multiplier,
|
||||
UnitType units, ClassType classType, SourceType sourceType)
|
||||
: m_id(id),
|
||||
m_key(key),
|
||||
m_name(name),
|
||||
m_title(title),
|
||||
m_description(description),
|
||||
m_category(category),
|
||||
m_multiplier(multiplier),
|
||||
m_units(units),
|
||||
m_classType(classType),
|
||||
m_sourceType(sourceType)
|
||||
{
|
||||
}
|
||||
|
||||
void LizardCounter::setInternalKey(uint64_t key)
|
||||
{
|
||||
m_internalKey = key;
|
||||
}
|
||||
|
||||
void LizardCounterDataStore::addValue(int64_t key, Value value)
|
||||
{
|
||||
m_values[key].push_back(value);
|
||||
}
|
||||
|
||||
const std::vector<Value> &LizardCounterDataStore::getValues(int64_t key) const
|
||||
{
|
||||
const std::map<int64_t, std::vector<Value> >::const_iterator it = m_values.find(key);
|
||||
if(it != m_values.end())
|
||||
return it->second;
|
||||
else
|
||||
return s_empty;
|
||||
}
|
||||
|
||||
void LizardCounterDataStore::clear()
|
||||
{
|
||||
m_values.clear();
|
||||
}
|
||||
|
||||
} /* namespace lizard */
|
||||
@@ -0,0 +1,77 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
void writeLEInt(uint8_t *buf, uint32_t v)
|
||||
{
|
||||
buf[0] = (v >> 0) & 0xFF;
|
||||
buf[1] = (v >> 8) & 0xFF;
|
||||
buf[2] = (v >> 16) & 0xFF;
|
||||
buf[3] = (v >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
uint32_t readLEInt(uint8_t *buffer)
|
||||
{
|
||||
return (buffer[0] << 0) | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to decode a SLEB128 value.
|
||||
* Source: https://llvm.org/doxygen/LEB128_8h_source.html
|
||||
*/
|
||||
int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr, const uint8_t *end = nullptr,
|
||||
const char **error = nullptr)
|
||||
{
|
||||
const uint8_t *orig_p = p;
|
||||
int64_t Value = 0;
|
||||
unsigned Shift = 0;
|
||||
uint8_t Byte;
|
||||
if(error)
|
||||
*error = nullptr;
|
||||
do
|
||||
{
|
||||
if(end && p == end)
|
||||
{
|
||||
if(error)
|
||||
*error = "malformed sleb128, extends past end";
|
||||
if(n)
|
||||
*n = (unsigned)(p - orig_p);
|
||||
return 0;
|
||||
}
|
||||
Byte = *p++;
|
||||
Value |= (uint64_t(Byte & 0x7f) << Shift);
|
||||
Shift += 7;
|
||||
} while(Byte >= 128);
|
||||
// Sign extend negative numbers if needed.
|
||||
if(Shift < 64 && (Byte & 0x40))
|
||||
Value |= (-1ULL) << Shift;
|
||||
if(n)
|
||||
*n = (unsigned)(p - orig_p);
|
||||
return Value;
|
||||
}
|
||||
|
||||
} /* namespace lizard */
|
||||
@@ -0,0 +1,40 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef GATOR_MESSAGE_UTIL_H
|
||||
#define GATOR_MESSAGE_UTIL_H
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
void writeLEInt(uint8_t *buf, uint32_t v);
|
||||
|
||||
uint32_t readLEInt(uint8_t *buffer);
|
||||
|
||||
/// Utility function to decode a SLEB128 value.
|
||||
int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr, const uint8_t *end = nullptr,
|
||||
const char **error = nullptr);
|
||||
|
||||
} /* namespace lizard */
|
||||
|
||||
#endif // GATOR_MESSAGE_UTIL_H
|
||||
@@ -0,0 +1,156 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "socket.hpp"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <cerrno>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
Socket *Socket::createConnection(const char *host, uint32_t port)
|
||||
{
|
||||
struct sockaddr_in serv_addr;
|
||||
int sock;
|
||||
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(port);
|
||||
|
||||
if(inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
int connectResult = connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
|
||||
if(connectResult < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return new lizard::Socket(sock);
|
||||
}
|
||||
|
||||
void Socket::destroyConnection(Socket *connection)
|
||||
{
|
||||
delete connection;
|
||||
}
|
||||
|
||||
static Socket::Result toSocketResult(ssize_t value, int lastErrno)
|
||||
{
|
||||
if(value > 0)
|
||||
return Socket::SUCCESS;
|
||||
if(value == 0)
|
||||
return Socket::CONNECTION_CLOSED;
|
||||
|
||||
switch(lastErrno)
|
||||
{
|
||||
case EAGAIN: return Socket::WOULD_BLOCK;
|
||||
case ECONNABORTED:
|
||||
case ECONNRESET: return Socket::CONNECTION_TERMINATED;
|
||||
default: return Socket::ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
Socket::Socket(int fd) : m_fd(fd)
|
||||
{
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
Socket::Result Socket::send(const void *buffer, size_t bufferSize, size_t *bytesSent)
|
||||
{
|
||||
ssize_t bytesWritten = ::send(m_fd, (const char *)buffer, bufferSize, 0);
|
||||
Socket::Result result = toSocketResult(bytesWritten, errno);
|
||||
|
||||
if(bytesSent != NULL)
|
||||
*bytesSent = bytesWritten > 0 ? (size_t)bytesWritten : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Socket::Result Socket::receive(void *buffer, size_t bufferSize, size_t *bytesRecv)
|
||||
{
|
||||
ssize_t bytesRead = ::recv(m_fd, (char *)buffer, bufferSize, 0);
|
||||
Result result = toSocketResult(bytesRead, errno);
|
||||
|
||||
if(bytesRecv != NULL)
|
||||
*bytesRecv = bytesRead > 0 ? (size_t)bytesRead : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Socket::Result Socket::receiveAll(void *buffer, size_t bufferSize, size_t *bytesRecv)
|
||||
{
|
||||
size_t bytesRead = 0;
|
||||
Result result;
|
||||
while(bytesRead < bufferSize)
|
||||
{
|
||||
bytesRead += ::recv(m_fd, (char *)buffer + bytesRead, bufferSize - bytesRead, 0);
|
||||
result = toSocketResult(bytesRead, errno);
|
||||
if(result != SUCCESS)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if(bytesRecv != NULL)
|
||||
*bytesRecv = bytesRead > 0 ? (size_t)bytesRead : 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
Socket::Result Socket::shutdown()
|
||||
{
|
||||
int shutdownResult = ::shutdown(m_fd, SHUT_RDWR);
|
||||
return shutdownResult == 0 ? SUCCESS : ERROR;
|
||||
}
|
||||
|
||||
Socket::Result Socket::close()
|
||||
{
|
||||
int closeResult = ::close(m_fd);
|
||||
return closeResult == 0 ? SUCCESS : ERROR;
|
||||
}
|
||||
|
||||
string Socket::resultstr(Socket::Result result)
|
||||
{
|
||||
switch(result)
|
||||
{
|
||||
case SUCCESS: return "SUCCESS";
|
||||
case WOULD_BLOCK: return "WOULD_BLOCK";
|
||||
case CONNECTION_TERMINATED: return "CONNECTION_TERMINATED";
|
||||
case CONNECTION_CLOSED: return "CONNECTION_CLOSED";
|
||||
case ERROR: return "ERROR";
|
||||
default: return "UNSPECIFIED RESULT";
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace lizard */
|
||||
@@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Samsung Electronics (UK) Limited
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SOCKET_HPP
|
||||
#define SOCKET_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace lizard
|
||||
{
|
||||
class Socket
|
||||
{
|
||||
int m_fd;
|
||||
|
||||
public:
|
||||
enum Result
|
||||
{
|
||||
SUCCESS,
|
||||
WOULD_BLOCK,
|
||||
CONNECTION_TERMINATED,
|
||||
CONNECTION_CLOSED,
|
||||
ERROR,
|
||||
}; // enum Result
|
||||
|
||||
Socket(int fd);
|
||||
~Socket();
|
||||
|
||||
Result send(const void *buffer, size_t bufferSize, size_t *bytesSent);
|
||||
Result receive(void *buffer, size_t bufferSize, size_t *bytesRead);
|
||||
Result receiveAll(void *buffer, size_t bufferSize, size_t *bytesRead);
|
||||
Result close();
|
||||
Result shutdown();
|
||||
|
||||
static Socket *createConnection(const char *host, uint32_t port);
|
||||
static void destroyConnection(Socket *connection);
|
||||
|
||||
static std::string resultstr(Result result);
|
||||
}; // class Socket
|
||||
|
||||
} /* namespace lizard */
|
||||
|
||||
#endif // SOCKET_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Arm Software
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,156 @@
|
||||
<!--
|
||||
- Copyright (c) 2019, Arm Limited and Contributors
|
||||
-
|
||||
- SPDX-License-Identifier: MIT
|
||||
-
|
||||
- Permission is hereby granted, free of charge,
|
||||
- to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
- to deal in the Software without restriction, including without limitation the rights to
|
||||
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
- and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
-
|
||||
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
-
|
||||
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
-
|
||||
-->
|
||||
|
||||
# HWCPipe
|
||||
|
||||
## Introduction
|
||||
|
||||
HWCPipe is a simple and extensible interface for reading CPU and GPU hardware counters.
|
||||
|
||||
## License
|
||||
|
||||
The software is provided under an MIT license.
|
||||
|
||||
This project has a third-party dependency, which may have independent licensing:
|
||||
|
||||
- [nlohmann/json](https://github.com/nlohmann/json): A JSON library for modern C++
|
||||
|
||||
## Contributions
|
||||
|
||||
All contributions are accepted under the same [LICENSE](LICENSE).
|
||||
|
||||
## Building
|
||||
|
||||
To use HWCPipe, build it as a shared library in your project.
|
||||
|
||||
If your project uses CMake, you can add the following to your `CMakeLists.txt`:
|
||||
|
||||
```
|
||||
add_subdirectory(hwcpipe)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Using HWCPipe
|
||||
|
||||
Basic usage for HWCPipe is simple:
|
||||
|
||||
```
|
||||
// HWCPipe performs automated platform detection for CPU/GPU counters
|
||||
hwcpipe::HWCPipe h;
|
||||
|
||||
// Start HWCPipe once at the beginning of the profiling session
|
||||
h.run();
|
||||
|
||||
while (main_loop) {
|
||||
// Call sample() to sample counters with the frequency you need
|
||||
auto measurements = h.sample();
|
||||
|
||||
[...]
|
||||
}
|
||||
|
||||
// At the end of the profiling session, stop HWCPipe
|
||||
h.stop();
|
||||
```
|
||||
|
||||
The `sample` function returns a `Measurements` struct, which can be accessed like this:
|
||||
|
||||
```
|
||||
// Check if CPU measurements are available
|
||||
if (measurements.cpu)
|
||||
{
|
||||
// Look for a counter in the map
|
||||
const auto &counter = measurements.cpu->find(CpuCounter::Cycles);
|
||||
if (counter != measurements.cpu->end())
|
||||
{
|
||||
// Get the data stored in the counter, casted to the type you need
|
||||
auto value = counter->second.get<float>();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Enabling counters
|
||||
|
||||
The available counters are specified in the `CpuCounter` and `GpuCounter` enums (`cpu_profiler.h` and `gpu_profiler.h` respectively).
|
||||
|
||||
Platforms will support a subset of these counters, which can be queried via:
|
||||
|
||||
```
|
||||
auto cpu_counters = h.cpu_profiler()->supported_counters();
|
||||
auto gpu_counters = h.gpu_profiler()->supported_counters()
|
||||
```
|
||||
|
||||
You can specify the counters to be enabled in the following ways:
|
||||
|
||||
```
|
||||
// Enable a default set of counters
|
||||
auto h = hwcpipe::HWCPipe();
|
||||
|
||||
// Pass sets of CPU and GPU counters to be enabled
|
||||
auto h = hwcpipe::HWCPipe({CpuCounter::Cycles, CpuCounter::Instructions}, {GpuCounter::GpuCycles});
|
||||
|
||||
// Pass a JSON string
|
||||
auto h = hwcpipe::HWCPipe(json);
|
||||
```
|
||||
|
||||
The JSON string should be formatted like this:
|
||||
|
||||
```
|
||||
{
|
||||
"cpu": ["Cycles", "Instructions"],
|
||||
"gpu": ["GpuCycles"]
|
||||
}
|
||||
```
|
||||
|
||||
Available counter names can be found in `cpu_counter_names` (`cpu_profiler.h`) and `gpu_counter_names` (`gpu_profiler.h`).
|
||||
|
||||
For more information regarding Mali counters, see [Mali Performance Counters](https://community.arm.com/graphics/b/blog/posts/mali-bifrost-family-performance-counters).
|
||||
|
||||
### Enabling profiling on Android
|
||||
|
||||
In order for performance data to be displayed, profiling needs to be enabled on the device.
|
||||
Some devices may disable it by default.
|
||||
|
||||
Profiling can be enabled via `adb`:
|
||||
|
||||
```
|
||||
adb shell setprop security.perf_harden 0
|
||||
```
|
||||
|
||||
## Adding support for a new platform
|
||||
|
||||
If the counters provided in `CpuCounter` and `GpuCounter` are enough for the new platform,
|
||||
the process is simple:
|
||||
|
||||
* Add an implementation of either `CpuProfiler` of `GpuProfiler` (you can use `PmuProfiler` and `MaliProfiler` as references).
|
||||
* Add your platform to the automated platform detection in `hwcpipe.cpp`. For consistency in platform detection, the constructor for your platform should throw if the platform is not available.
|
||||
* Add your platform to the build system.
|
||||
|
||||
### Adding new counters
|
||||
|
||||
If you need to add new counters to the existing ones, you should update the following variables:
|
||||
|
||||
* Add the counter to the `CpuCounter`/`GpuCounter` enum.
|
||||
* Add the counter name to the `cpu_counter_names`/`gpu_counter_names` map (necessary for JSON initialization).
|
||||
* Add a description and the unit for your counter to the `cpu_counter_info`/`gpu_counter_info` map.
|
||||
|
||||
The `CpuCounter` and `GpuCounter` enums are meant to be expanded. Platforms must not break if new counters are added.
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "value.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
// The available CPU counters. Profiler implementations will support a subset of them.
|
||||
enum class CpuCounter
|
||||
{
|
||||
Cycles,
|
||||
Instructions,
|
||||
CacheReferences,
|
||||
CacheMisses,
|
||||
BranchInstructions,
|
||||
BranchMisses,
|
||||
|
||||
MaxValue
|
||||
};
|
||||
|
||||
// Mapping from CPU counter names to enum values. Used for JSON initialization.
|
||||
const std::unordered_map<std::string, CpuCounter> cpu_counter_names{
|
||||
{"Cycles", CpuCounter::Cycles},
|
||||
{"Instructions", CpuCounter::Instructions},
|
||||
{"CacheReferences", CpuCounter::CacheReferences},
|
||||
{"CacheMisses", CpuCounter::CacheMisses},
|
||||
{"BranchInstructions", CpuCounter::BranchInstructions},
|
||||
{"BranchMisses", CpuCounter::BranchMisses},
|
||||
};
|
||||
|
||||
// A hash function for CpuCounter values
|
||||
struct CpuCounterHash
|
||||
{
|
||||
template <typename T>
|
||||
std::size_t operator()(T t) const
|
||||
{
|
||||
return static_cast<std::size_t>(t);
|
||||
}
|
||||
};
|
||||
|
||||
struct CpuCounterInfo
|
||||
{
|
||||
std::string desc;
|
||||
std::string unit;
|
||||
};
|
||||
|
||||
// Mapping from each counter to its corresponding information (description and unit)
|
||||
const std::unordered_map<CpuCounter, CpuCounterInfo, CpuCounterHash> cpu_counter_info{
|
||||
{CpuCounter::Cycles, {"Number of CPU cycles", "cycles"}},
|
||||
{CpuCounter::Instructions, {"Number of CPU instructions", "instructions"}},
|
||||
{CpuCounter::CacheReferences, {"Number of cache references", "references"}},
|
||||
{CpuCounter::CacheMisses, {"Number of cache misses", "misses"}},
|
||||
{CpuCounter::BranchInstructions, {"Number of branch instructions", "instructions"}},
|
||||
{CpuCounter::BranchMisses, {"Number of branch misses", "misses"}},
|
||||
};
|
||||
|
||||
typedef std::unordered_set<CpuCounter, CpuCounterHash> CpuCounterSet;
|
||||
typedef std::unordered_map<CpuCounter, Value, CpuCounterHash>
|
||||
CpuMeasurements;
|
||||
|
||||
/** An interface for classes that collect CPU performance data. */
|
||||
class CpuProfiler
|
||||
{
|
||||
public:
|
||||
virtual ~CpuProfiler() = default;
|
||||
|
||||
// Returns the enabled counters
|
||||
virtual const CpuCounterSet &enabled_counters() const = 0;
|
||||
|
||||
// Returns the counters that the platform supports
|
||||
virtual const CpuCounterSet &supported_counters() const = 0;
|
||||
|
||||
// Sets the enabled counters after initialization
|
||||
virtual void set_enabled_counters(CpuCounterSet counters) = 0;
|
||||
|
||||
// Starts a profiling session
|
||||
virtual void run() = 0;
|
||||
|
||||
// Sample the counters. Returns a map of measurements for the counters
|
||||
// that are both available and enabled.
|
||||
// A profiling session must be running when sampling the counters.
|
||||
virtual const CpuMeasurements &sample() = 0;
|
||||
|
||||
// Stops the active profiling session
|
||||
virtual void stop() = 0;
|
||||
};
|
||||
|
||||
} // namespace hwcpipe
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "value.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
// The available GPU counters. Profiler implementations will support a subset of them.
|
||||
enum class GpuCounter
|
||||
{
|
||||
GpuCycles,
|
||||
VertexComputeCycles,
|
||||
FragmentCycles,
|
||||
TilerCycles,
|
||||
|
||||
VertexComputeJobs,
|
||||
FragmentJobs,
|
||||
Pixels,
|
||||
|
||||
Tiles,
|
||||
TransactionEliminations,
|
||||
EarlyZTests,
|
||||
EarlyZKilled,
|
||||
LateZTests,
|
||||
LateZKilled,
|
||||
|
||||
Instructions,
|
||||
DivergedInstructions,
|
||||
|
||||
ShaderCycles,
|
||||
ShaderArithmeticCycles,
|
||||
ShaderLoadStoreCycles,
|
||||
ShaderTextureCycles,
|
||||
|
||||
CacheReadLookups,
|
||||
CacheWriteLookups,
|
||||
ExternalMemoryReadAccesses,
|
||||
ExternalMemoryWriteAccesses,
|
||||
ExternalMemoryReadStalls,
|
||||
ExternalMemoryWriteStalls,
|
||||
ExternalMemoryReadBytes,
|
||||
ExternalMemoryWriteBytes,
|
||||
|
||||
MaxValue
|
||||
};
|
||||
|
||||
// Mapping from GPU counter names to enum values. Used for JSON initialization.
|
||||
const std::unordered_map<std::string, GpuCounter> gpu_counter_names{
|
||||
{"GpuCycles", GpuCounter::GpuCycles},
|
||||
{"VertexComputeCycles", GpuCounter::VertexComputeCycles},
|
||||
{"FragmentCycles", GpuCounter::FragmentCycles},
|
||||
{"TilerCycles", GpuCounter::TilerCycles},
|
||||
|
||||
{"VertexComputeJobs", GpuCounter::VertexComputeJobs},
|
||||
{"Tiles", GpuCounter::Tiles},
|
||||
{"TransactionEliminations", GpuCounter::TransactionEliminations},
|
||||
{"FragmentJobs", GpuCounter::FragmentJobs},
|
||||
{"Pixels", GpuCounter::Pixels},
|
||||
|
||||
{"EarlyZTests", GpuCounter::EarlyZTests},
|
||||
{"EarlyZKilled", GpuCounter::EarlyZKilled},
|
||||
{"LateZTests", GpuCounter::LateZTests},
|
||||
{"LateZKilled", GpuCounter::LateZKilled},
|
||||
|
||||
{"Instructions", GpuCounter::Instructions},
|
||||
{"DivergedInstructions", GpuCounter::DivergedInstructions},
|
||||
|
||||
{"ShaderCycles", GpuCounter::ShaderCycles},
|
||||
{"ShaderArithmeticCycles", GpuCounter::ShaderArithmeticCycles},
|
||||
{"ShaderLoadStoreCycles", GpuCounter::ShaderLoadStoreCycles},
|
||||
{"ShaderTextureCycles", GpuCounter::ShaderTextureCycles},
|
||||
|
||||
{"CacheReadLookups", GpuCounter::CacheReadLookups},
|
||||
{"CacheWriteLookups", GpuCounter::CacheWriteLookups},
|
||||
{"ExternalMemoryReadAccesses", GpuCounter::ExternalMemoryReadAccesses},
|
||||
{"ExternalMemoryWriteAccesses", GpuCounter::ExternalMemoryWriteAccesses},
|
||||
{"ExternalMemoryReadStalls", GpuCounter::ExternalMemoryReadStalls},
|
||||
{"ExternalMemoryWriteStalls", GpuCounter::ExternalMemoryWriteStalls},
|
||||
{"ExternalMemoryReadBytes", GpuCounter::ExternalMemoryReadBytes},
|
||||
{"ExternalMemoryWriteBytes", GpuCounter::ExternalMemoryWriteBytes},
|
||||
};
|
||||
|
||||
// A hash function for GpuCounter values
|
||||
struct GpuCounterHash
|
||||
{
|
||||
template <typename T>
|
||||
std::size_t operator()(T t) const
|
||||
{
|
||||
return static_cast<std::size_t>(t);
|
||||
}
|
||||
};
|
||||
|
||||
struct GpuCounterInfo
|
||||
{
|
||||
std::string desc;
|
||||
std::string unit;
|
||||
};
|
||||
|
||||
// Mapping from each counter to its corresponding information (description and unit)
|
||||
const std::unordered_map<GpuCounter, GpuCounterInfo, GpuCounterHash> gpu_counter_info{
|
||||
{GpuCounter::GpuCycles, {"Number of GPU cycles", "cycles"}},
|
||||
{GpuCounter::VertexComputeCycles, {"Number of vertex/compute cycles", "cycles"}},
|
||||
{GpuCounter::FragmentCycles, {"Number of fragment cycles", "cycles"}},
|
||||
{GpuCounter::TilerCycles, {"Number of tiler cycles", "cycles"}},
|
||||
|
||||
{GpuCounter::VertexComputeJobs, {"Number of vertex/compute jobs", "jobs"}},
|
||||
{GpuCounter::Tiles, {"Number of physical tiles written", "tiles"}},
|
||||
{GpuCounter::TransactionEliminations, {"Number of transaction eliminations", "tiles"}},
|
||||
{GpuCounter::FragmentJobs, {"Number of fragment jobs", "jobs"}},
|
||||
{GpuCounter::Pixels, {"Number of pixels shaded", "cycles"}},
|
||||
|
||||
{GpuCounter::EarlyZTests, {"Early-Z tests performed", "tests"}},
|
||||
{GpuCounter::EarlyZKilled, {"Early-Z tests resulting in a kill", "tests"}},
|
||||
{GpuCounter::LateZTests, {"Late-Z tests performed", "tests"}},
|
||||
{GpuCounter::LateZKilled, {"Late-Z tests resulting in a kill", "tests"}},
|
||||
|
||||
{GpuCounter::Instructions, {"Number of shader instructions", "instructions"}},
|
||||
{GpuCounter::DivergedInstructions, {"Number of diverged shader instructions", "instructions"}},
|
||||
|
||||
{GpuCounter::ShaderCycles, {"Shader total cycles", "cycles"}},
|
||||
{GpuCounter::ShaderArithmeticCycles, {"Shader arithmetic cycles", "cycles"}},
|
||||
{GpuCounter::ShaderLoadStoreCycles, {"Shader load/store cycles", "cycles"}},
|
||||
{GpuCounter::ShaderTextureCycles, {"Shader texture cycles", "cycles"}},
|
||||
|
||||
{GpuCounter::CacheReadLookups, {"Cache read lookups", "lookups"}},
|
||||
{GpuCounter::CacheWriteLookups, {"Cache write lookups", "lookups"}},
|
||||
{GpuCounter::ExternalMemoryReadAccesses, {"Reads from external memory", "accesses"}},
|
||||
{GpuCounter::ExternalMemoryWriteAccesses, {"Writes to external memory", "accesses"}},
|
||||
{GpuCounter::ExternalMemoryReadStalls, {"Stalls when reading from external memory", "stalls"}},
|
||||
{GpuCounter::ExternalMemoryWriteStalls, {"Stalls when writing to external memory", "stalls"}},
|
||||
{GpuCounter::ExternalMemoryReadBytes, {"Bytes read to external memory", "B"}},
|
||||
{GpuCounter::ExternalMemoryWriteBytes, {"Bytes written to external memory", "B"}},
|
||||
};
|
||||
|
||||
typedef std::unordered_set<GpuCounter, GpuCounterHash> GpuCounterSet;
|
||||
typedef std::unordered_map<GpuCounter, Value, GpuCounterHash> GpuMeasurements;
|
||||
|
||||
/** An interface for classes that collect GPU performance data. */
|
||||
class GpuProfiler
|
||||
{
|
||||
public:
|
||||
virtual ~GpuProfiler() = default;
|
||||
|
||||
// Returns the enabled counters
|
||||
virtual const GpuCounterSet &enabled_counters() const = 0;
|
||||
|
||||
// Returns the counters that the platform supports
|
||||
virtual const GpuCounterSet &supported_counters() const = 0;
|
||||
|
||||
// Sets the enabled counters after initialization
|
||||
virtual void set_enabled_counters(GpuCounterSet counters) = 0;
|
||||
|
||||
// Starts a profiling session
|
||||
virtual void run() = 0;
|
||||
|
||||
// Sample the counters. Returns a map of measurements for the counters
|
||||
// that are both available and enabled.
|
||||
// A profiling session must be running when sampling the counters.
|
||||
virtual const GpuMeasurements &sample() = 0;
|
||||
|
||||
// Stops the active profiling session
|
||||
virtual void stop() = 0;
|
||||
};
|
||||
|
||||
} // namespace hwcpipe
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hwcpipe.h"
|
||||
#include "hwcpipe_log.h"
|
||||
|
||||
#ifdef __linux__
|
||||
# include "vendor/arm/pmu/pmu_profiler.h"
|
||||
# include "vendor/arm/mali/mali_profiler.h"
|
||||
#endif
|
||||
|
||||
#ifndef HWCPIPE_NO_JSON
|
||||
#include <json.hpp>
|
||||
using json = nlohmann::json;
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
#ifndef HWCPIPE_NO_JSON
|
||||
HWCPipe::HWCPipe(const char *json_string)
|
||||
{
|
||||
auto json = json::parse(json_string);
|
||||
|
||||
CpuCounterSet enabled_cpu_counters{};
|
||||
auto cpu = json.find("cpu");
|
||||
if (cpu != json.end())
|
||||
{
|
||||
for (auto &counter_name : cpu->items())
|
||||
{
|
||||
auto counter = cpu_counter_names.find(counter_name.value().get<std::string>());
|
||||
if (counter != cpu_counter_names.end())
|
||||
{
|
||||
enabled_cpu_counters.insert(counter->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWCPIPE_LOG("CPU counter \"%s\" not found.", counter_name.value().get<std::string>().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GpuCounterSet enabled_gpu_counters{};
|
||||
auto gpu = json.find("gpu");
|
||||
if (gpu != json.end())
|
||||
{
|
||||
for (auto &counter_name : gpu->items())
|
||||
{
|
||||
auto counter = gpu_counter_names.find(counter_name.value().get<std::string>());
|
||||
if (counter != gpu_counter_names.end())
|
||||
{
|
||||
enabled_gpu_counters.insert(counter->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWCPIPE_LOG("GPU counter \"%s\" not found.", counter_name.value().get<std::string>().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_profilers(std::move(enabled_cpu_counters), std::move(enabled_gpu_counters));
|
||||
}
|
||||
#endif
|
||||
|
||||
HWCPipe::HWCPipe(CpuCounterSet enabled_cpu_counters, GpuCounterSet enabled_gpu_counters)
|
||||
{
|
||||
create_profilers(std::move(enabled_cpu_counters), std::move(enabled_gpu_counters));
|
||||
}
|
||||
|
||||
HWCPipe::HWCPipe()
|
||||
{
|
||||
CpuCounterSet enabled_cpu_counters{CpuCounter::Cycles,
|
||||
CpuCounter::Instructions,
|
||||
CpuCounter::CacheReferences,
|
||||
CpuCounter::CacheMisses,
|
||||
CpuCounter::BranchInstructions,
|
||||
CpuCounter::BranchMisses};
|
||||
|
||||
GpuCounterSet enabled_gpu_counters{GpuCounter::GpuCycles,
|
||||
GpuCounter::VertexComputeCycles,
|
||||
GpuCounter::FragmentCycles,
|
||||
GpuCounter::TilerCycles,
|
||||
GpuCounter::CacheReadLookups,
|
||||
GpuCounter::CacheWriteLookups,
|
||||
GpuCounter::ExternalMemoryReadAccesses,
|
||||
GpuCounter::ExternalMemoryWriteAccesses,
|
||||
GpuCounter::ExternalMemoryReadStalls,
|
||||
GpuCounter::ExternalMemoryWriteStalls,
|
||||
GpuCounter::ExternalMemoryReadBytes,
|
||||
GpuCounter::ExternalMemoryWriteBytes};
|
||||
|
||||
create_profilers(std::move(enabled_cpu_counters), std::move(enabled_gpu_counters));
|
||||
}
|
||||
|
||||
void HWCPipe::set_enabled_cpu_counters(CpuCounterSet counters)
|
||||
{
|
||||
if (cpu_profiler_)
|
||||
{
|
||||
cpu_profiler_->set_enabled_counters(std::move(counters));
|
||||
}
|
||||
}
|
||||
|
||||
void HWCPipe::set_enabled_gpu_counters(GpuCounterSet counters)
|
||||
{
|
||||
if (gpu_profiler_)
|
||||
{
|
||||
gpu_profiler_->set_enabled_counters(std::move(counters));
|
||||
}
|
||||
}
|
||||
|
||||
void HWCPipe::run()
|
||||
{
|
||||
if (cpu_profiler_)
|
||||
{
|
||||
cpu_profiler_->run();
|
||||
}
|
||||
if (gpu_profiler_)
|
||||
{
|
||||
gpu_profiler_->run();
|
||||
}
|
||||
}
|
||||
|
||||
Measurements HWCPipe::sample()
|
||||
{
|
||||
Measurements m;
|
||||
if (cpu_profiler_)
|
||||
{
|
||||
m.cpu = &cpu_profiler_->sample();
|
||||
}
|
||||
if (gpu_profiler_)
|
||||
{
|
||||
m.gpu = &gpu_profiler_->sample();
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void HWCPipe::stop()
|
||||
{
|
||||
if (cpu_profiler_)
|
||||
{
|
||||
cpu_profiler_->stop();
|
||||
}
|
||||
if (gpu_profiler_)
|
||||
{
|
||||
gpu_profiler_->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void HWCPipe::create_profilers(CpuCounterSet enabled_cpu_counters, GpuCounterSet enabled_gpu_counters)
|
||||
{
|
||||
// Automated platform detection
|
||||
#ifdef __linux__
|
||||
try
|
||||
{
|
||||
cpu_profiler_ = std::unique_ptr<PmuProfiler>(new PmuProfiler(enabled_cpu_counters));
|
||||
}
|
||||
catch (const std::runtime_error &e)
|
||||
{
|
||||
HWCPIPE_LOG("PMU profiler initialization failed: %s", e.what());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
gpu_profiler_ = std::unique_ptr<MaliProfiler>(new MaliProfiler(enabled_gpu_counters));
|
||||
}
|
||||
catch (const std::runtime_error &e)
|
||||
{
|
||||
HWCPIPE_LOG("Mali profiler initialization failed: %s", e.what());
|
||||
}
|
||||
#else
|
||||
HWCPIPE_LOG("No counters available for this platform.");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace hwcpipe
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Force disable JSON in HWCPIPE */
|
||||
#define HWCPIPE_NO_JSON
|
||||
|
||||
#include "cpu_profiler.h"
|
||||
#include "gpu_profiler.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
struct Measurements
|
||||
{
|
||||
const CpuMeasurements *cpu{nullptr};
|
||||
const GpuMeasurements *gpu{nullptr};
|
||||
};
|
||||
|
||||
/** A class that collects CPU/GPU performance data. */
|
||||
class HWCPipe
|
||||
{
|
||||
public:
|
||||
#ifndef HWCPIPE_NO_JSON
|
||||
// Initializes HWCPipe via a JSON configuration string
|
||||
explicit HWCPipe(const char *json_string);
|
||||
#endif
|
||||
|
||||
// Initializes HWCPipe with the specified counters
|
||||
HWCPipe(CpuCounterSet enabled_cpu_counters, GpuCounterSet enabled_gpu_counters);
|
||||
|
||||
// Initializes HWCPipe with a default set of counters
|
||||
HWCPipe();
|
||||
|
||||
// Sets the enabled counters for the CPU profiler
|
||||
void set_enabled_cpu_counters(CpuCounterSet counters);
|
||||
|
||||
// Sets the enabled counters for the GPU profiler
|
||||
void set_enabled_gpu_counters(GpuCounterSet counters);
|
||||
|
||||
// Starts a profiling session
|
||||
void run();
|
||||
|
||||
// Sample the counters. The function returns pointers to the CPU and GPU
|
||||
// measurements maps, if the corresponding profiler is enabled.
|
||||
// The entries in the maps are the counters that are both available and enabled.
|
||||
// A profiling session must be running when sampling the counters.
|
||||
Measurements sample();
|
||||
|
||||
// Stops the active profiling session
|
||||
void stop();
|
||||
|
||||
const CpuProfiler *cpu_profiler()
|
||||
{
|
||||
return cpu_profiler_.get();
|
||||
}
|
||||
const GpuProfiler *gpu_profiler()
|
||||
{
|
||||
return gpu_profiler_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<CpuProfiler> cpu_profiler_{};
|
||||
std::unique_ptr<GpuProfiler> gpu_profiler_{};
|
||||
|
||||
void create_profilers(CpuCounterSet enabled_cpu_counters, GpuCounterSet enabled_gpu_counters);
|
||||
};
|
||||
|
||||
} // namespace hwcpipe
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define HWCPIPE_TAG "HWCPipe"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
# include <android/log.h>
|
||||
|
||||
# define HWCPIPE_LOG(...) //__android_log_print(ANDROID_LOG_VERBOSE, HWCPIPE_TAG, __VA_ARGS__)
|
||||
#else
|
||||
# define HWCPIPE_LOG(...) \
|
||||
{ \
|
||||
fprintf(stdout, "%s [INFO] : ", HWCPIPE_TAG); \
|
||||
fprintf(stdout, __VA_ARGS__); \
|
||||
fprintf(stdout, "\n"); \
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
class Value
|
||||
{
|
||||
public:
|
||||
Value() :
|
||||
is_int_(true),
|
||||
int_(0),
|
||||
double_(0.0f)
|
||||
{}
|
||||
Value(long long value) :
|
||||
is_int_(true),
|
||||
int_(value)
|
||||
{}
|
||||
Value(double value) :
|
||||
is_int_(false),
|
||||
double_(value)
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
T get() const
|
||||
{
|
||||
return is_int_ ? static_cast<T>(int_) : static_cast<T>(double_);
|
||||
}
|
||||
|
||||
void set(long long value)
|
||||
{
|
||||
int_ = value;
|
||||
is_int_ = true;
|
||||
}
|
||||
|
||||
void set(double value)
|
||||
{
|
||||
double_ = value;
|
||||
is_int_ = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_int_;
|
||||
long long int_{0};
|
||||
double double_{0.0};
|
||||
};
|
||||
} // namespace hwcpipe
|
||||
+413
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "hwc_names.hpp"
|
||||
|
||||
#ifndef DOXYGEN_SKIP_THIS
|
||||
|
||||
# if defined(ANDROID) || defined(__ANDROID__)
|
||||
/* We use _IOR_BAD/_IOW_BAD rather than _IOR/_IOW otherwise fails to compile with NDK-BUILD because of _IOC_TYPECHECK is defined, not because the paramter is invalid */
|
||||
# define MALI_IOR(a, b, c) _IOR_BAD(a, b, c)
|
||||
# define MALI_IOW(a, b, c) _IOW_BAD(a, b, c)
|
||||
# else
|
||||
# define MALI_IOR(a, b, c) _IOR(a, b, c)
|
||||
# define MALI_IOW(a, b, c) _IOW(a, b, c)
|
||||
# endif
|
||||
|
||||
namespace mali_userspace
|
||||
{
|
||||
union uk_header
|
||||
{
|
||||
uint32_t id;
|
||||
uint32_t ret;
|
||||
uint64_t sizer;
|
||||
};
|
||||
|
||||
# define BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS 3
|
||||
# define BASE_MAX_COHERENT_GROUPS 16
|
||||
|
||||
struct mali_base_gpu_core_props
|
||||
{
|
||||
uint32_t product_id;
|
||||
uint16_t version_status;
|
||||
uint16_t minor_revision;
|
||||
uint16_t major_revision;
|
||||
uint16_t padding;
|
||||
uint32_t gpu_speed_mhz;
|
||||
uint32_t gpu_freq_khz_max;
|
||||
uint32_t gpu_freq_khz_min;
|
||||
uint32_t log2_program_counter_size;
|
||||
uint32_t texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS];
|
||||
uint64_t gpu_available_memory_size;
|
||||
};
|
||||
|
||||
struct mali_base_gpu_l2_cache_props
|
||||
{
|
||||
uint8_t log2_line_size;
|
||||
uint8_t log2_cache_size;
|
||||
uint8_t num_l2_slices;
|
||||
uint8_t padding[5];
|
||||
};
|
||||
|
||||
struct mali_base_gpu_tiler_props
|
||||
{
|
||||
uint32_t bin_size_bytes;
|
||||
uint32_t max_active_levels;
|
||||
};
|
||||
|
||||
struct mali_base_gpu_thread_props
|
||||
{
|
||||
uint32_t max_threads;
|
||||
uint32_t max_workgroup_size;
|
||||
uint32_t max_barrier_size;
|
||||
uint16_t max_registers;
|
||||
uint8_t max_task_queue;
|
||||
uint8_t max_thread_group_split;
|
||||
uint8_t impl_tech;
|
||||
uint8_t padding[7];
|
||||
};
|
||||
|
||||
struct mali_base_gpu_coherent_group
|
||||
{
|
||||
uint64_t core_mask;
|
||||
uint16_t num_cores;
|
||||
uint16_t padding[3];
|
||||
};
|
||||
|
||||
struct mali_base_gpu_coherent_group_info
|
||||
{
|
||||
uint32_t num_groups;
|
||||
uint32_t num_core_groups;
|
||||
uint32_t coherency;
|
||||
uint32_t padding;
|
||||
mali_base_gpu_coherent_group group[BASE_MAX_COHERENT_GROUPS];
|
||||
};
|
||||
|
||||
# define GPU_MAX_JOB_SLOTS 16
|
||||
struct gpu_raw_gpu_props
|
||||
{
|
||||
uint64_t shader_present;
|
||||
uint64_t tiler_present;
|
||||
uint64_t l2_present;
|
||||
uint64_t unused_1;
|
||||
|
||||
uint32_t l2_features;
|
||||
uint32_t suspend_size;
|
||||
uint32_t mem_features;
|
||||
uint32_t mmu_features;
|
||||
|
||||
uint32_t as_present;
|
||||
|
||||
uint32_t js_present;
|
||||
uint32_t js_features[GPU_MAX_JOB_SLOTS];
|
||||
uint32_t tiler_features;
|
||||
uint32_t texture_features[3];
|
||||
|
||||
uint32_t gpu_id;
|
||||
|
||||
uint32_t thread_max_threads;
|
||||
uint32_t thread_max_workgroup_size;
|
||||
uint32_t thread_max_barrier_size;
|
||||
uint32_t thread_features;
|
||||
|
||||
uint32_t coherency_mode;
|
||||
};
|
||||
|
||||
struct mali_base_gpu_props
|
||||
{
|
||||
mali_base_gpu_core_props core_props;
|
||||
mali_base_gpu_l2_cache_props l2_props;
|
||||
uint64_t unused;
|
||||
mali_base_gpu_tiler_props tiler_props;
|
||||
mali_base_gpu_thread_props thread_props;
|
||||
gpu_raw_gpu_props raw_props;
|
||||
mali_base_gpu_coherent_group_info coherency_info;
|
||||
};
|
||||
|
||||
struct kbase_uk_gpuprops
|
||||
{
|
||||
uk_header header;
|
||||
mali_base_gpu_props props;
|
||||
};
|
||||
|
||||
# define KBASE_GPUPROP_VALUE_SIZE_U8 (0x0)
|
||||
# define KBASE_GPUPROP_VALUE_SIZE_U16 (0x1)
|
||||
# define KBASE_GPUPROP_VALUE_SIZE_U32 (0x2)
|
||||
# define KBASE_GPUPROP_VALUE_SIZE_U64 (0x3)
|
||||
|
||||
# define KBASE_GPUPROP_PRODUCT_ID 1
|
||||
# define KBASE_GPUPROP_MINOR_REVISION 3
|
||||
# define KBASE_GPUPROP_MAJOR_REVISION 4
|
||||
|
||||
# define KBASE_GPUPROP_COHERENCY_NUM_GROUPS 61
|
||||
# define KBASE_GPUPROP_COHERENCY_NUM_CORE_GROUPS 62
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_0 64
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_1 65
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_2 66
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_3 67
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_4 68
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_5 69
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_6 70
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_7 71
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_8 72
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_9 73
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_10 74
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_11 75
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_12 76
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_13 77
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_14 78
|
||||
# define KBASE_GPUPROP_COHERENCY_GROUP_15 79
|
||||
|
||||
# define KBASE_GPUPROP_L2_NUM_L2_SLICES 15
|
||||
|
||||
struct gpu_props
|
||||
{
|
||||
uint32_t product_id;
|
||||
uint16_t minor_revision;
|
||||
uint16_t major_revision;
|
||||
uint32_t num_groups;
|
||||
uint32_t num_core_groups;
|
||||
uint64_t core_mask[16];
|
||||
|
||||
uint32_t l2_slices;
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
uint32_t type;
|
||||
size_t offset;
|
||||
int size;
|
||||
} gpu_property_mapping[] = {
|
||||
# define PROP(name, member) \
|
||||
{ \
|
||||
KBASE_GPUPROP_##name, offsetof(struct gpu_props, member), \
|
||||
sizeof(((struct gpu_props *) 0)->member) \
|
||||
}
|
||||
PROP(PRODUCT_ID, product_id),
|
||||
PROP(MINOR_REVISION, minor_revision),
|
||||
PROP(MAJOR_REVISION, major_revision),
|
||||
PROP(COHERENCY_NUM_GROUPS, num_groups),
|
||||
PROP(COHERENCY_NUM_CORE_GROUPS, num_core_groups),
|
||||
PROP(COHERENCY_GROUP_0, core_mask[0]),
|
||||
PROP(COHERENCY_GROUP_1, core_mask[1]),
|
||||
PROP(COHERENCY_GROUP_2, core_mask[2]),
|
||||
PROP(COHERENCY_GROUP_3, core_mask[3]),
|
||||
PROP(COHERENCY_GROUP_4, core_mask[4]),
|
||||
PROP(COHERENCY_GROUP_5, core_mask[5]),
|
||||
PROP(COHERENCY_GROUP_6, core_mask[6]),
|
||||
PROP(COHERENCY_GROUP_7, core_mask[7]),
|
||||
PROP(COHERENCY_GROUP_8, core_mask[8]),
|
||||
PROP(COHERENCY_GROUP_9, core_mask[9]),
|
||||
PROP(COHERENCY_GROUP_10, core_mask[10]),
|
||||
PROP(COHERENCY_GROUP_11, core_mask[11]),
|
||||
PROP(COHERENCY_GROUP_12, core_mask[12]),
|
||||
PROP(COHERENCY_GROUP_13, core_mask[13]),
|
||||
PROP(COHERENCY_GROUP_14, core_mask[14]),
|
||||
PROP(COHERENCY_GROUP_15, core_mask[15]),
|
||||
|
||||
PROP(L2_NUM_L2_SLICES, l2_slices),
|
||||
# undef PROP
|
||||
{0, 0, 0}};
|
||||
|
||||
struct kbase_hwcnt_reader_metadata
|
||||
{
|
||||
uint64_t timestamp = 0;
|
||||
uint32_t event_id = 0;
|
||||
uint32_t buffer_idx = 0;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
/** Message header */
|
||||
union kbase_uk_hwcnt_header
|
||||
{
|
||||
/* 32-bit number identifying the UK function to be called. */
|
||||
uint32_t id;
|
||||
/* The int return code returned by the called UK function. */
|
||||
uint32_t ret;
|
||||
/* Used to ensure 64-bit alignment of this union. Do not remove. */
|
||||
uint64_t sizer;
|
||||
};
|
||||
|
||||
/** IOCTL parameters to check version */
|
||||
struct kbase_uk_hwcnt_reader_version_check_args
|
||||
{
|
||||
union kbase_uk_hwcnt_header header;
|
||||
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
uint8_t padding[4];
|
||||
};
|
||||
|
||||
union kbase_pointer
|
||||
{
|
||||
void * value;
|
||||
uint32_t compat_value;
|
||||
uint64_t sizer;
|
||||
};
|
||||
|
||||
struct kbase_ioctl_get_gpuprops
|
||||
{
|
||||
kbase_pointer buffer;
|
||||
uint32_t size;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct kbase_ioctl_version_check
|
||||
{
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
};
|
||||
|
||||
struct kbase_ioctl_set_flags
|
||||
{
|
||||
uint32_t create_flags;
|
||||
};
|
||||
|
||||
struct kbase_ioctl_hwcnt_reader_setup
|
||||
{
|
||||
uint32_t buffer_count;
|
||||
uint32_t jm_bm;
|
||||
uint32_t shader_bm;
|
||||
uint32_t tiler_bm;
|
||||
uint32_t mmu_l2_bm;
|
||||
};
|
||||
|
||||
# define KBASE_IOCTL_TYPE 0x80
|
||||
# define KBASE_IOCTL_GET_GPUPROPS MALI_IOW(KBASE_IOCTL_TYPE, 3, struct mali_userspace::kbase_ioctl_get_gpuprops)
|
||||
# define KBASE_IOCTL_VERSION_CHECK _IOWR(KBASE_IOCTL_TYPE, 0, struct mali_userspace::kbase_ioctl_version_check)
|
||||
# define KBASE_IOCTL_SET_FLAGS _IOW(KBASE_IOCTL_TYPE, 1, struct mali_userspace::kbase_ioctl_set_flags)
|
||||
# define KBASE_IOCTL_HWCNT_READER_SETUP _IOW(KBASE_IOCTL_TYPE, 8, struct mali_userspace::kbase_ioctl_hwcnt_reader_setup)
|
||||
|
||||
/** IOCTL parameters to set flags */
|
||||
struct kbase_uk_hwcnt_reader_set_flags
|
||||
{
|
||||
union kbase_uk_hwcnt_header header;
|
||||
|
||||
uint32_t create_flags;
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
/** IOCTL parameters to configure reader */
|
||||
struct kbase_uk_hwcnt_reader_setup
|
||||
{
|
||||
union kbase_uk_hwcnt_header header;
|
||||
|
||||
/* IN */
|
||||
uint32_t buffer_count;
|
||||
uint32_t jm_bm;
|
||||
uint32_t shader_bm;
|
||||
uint32_t tiler_bm;
|
||||
uint32_t mmu_l2_bm;
|
||||
|
||||
/* OUT */
|
||||
int32_t fd;
|
||||
};
|
||||
|
||||
static const uint32_t HWCNT_READER_API = 1;
|
||||
|
||||
struct uku_version_check_args
|
||||
{
|
||||
uk_header header;
|
||||
uint16_t major;
|
||||
uint16_t minor;
|
||||
uint8_t padding[4];
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
UKP_FUNC_ID_CHECK_VERSION = 0,
|
||||
/* Related to mali0 ioctl interface */
|
||||
LINUX_UK_BASE_MAGIC = 0x80,
|
||||
BASE_CONTEXT_CREATE_KERNEL_FLAGS = 0x2,
|
||||
KBASE_FUNC_HWCNT_UK_FUNC_ID = 512,
|
||||
KBASE_FUNC_GPU_PROPS_REG_DUMP = KBASE_FUNC_HWCNT_UK_FUNC_ID + 14,
|
||||
KBASE_FUNC_HWCNT_READER_SETUP = KBASE_FUNC_HWCNT_UK_FUNC_ID + 36,
|
||||
KBASE_FUNC_HWCNT_DUMP = KBASE_FUNC_HWCNT_UK_FUNC_ID + 11,
|
||||
KBASE_FUNC_HWCNT_CLEAR = KBASE_FUNC_HWCNT_UK_FUNC_ID + 12,
|
||||
KBASE_FUNC_SET_FLAGS = KBASE_FUNC_HWCNT_UK_FUNC_ID + 18,
|
||||
|
||||
/* The ids of ioctl commands for the reader interface */
|
||||
KBASE_HWCNT_READER = 0xBE,
|
||||
KBASE_HWCNT_READER_GET_HWVER = MALI_IOR(KBASE_HWCNT_READER, 0x00, uint32_t),
|
||||
KBASE_HWCNT_READER_GET_BUFFER_SIZE = MALI_IOR(KBASE_HWCNT_READER, 0x01, uint32_t),
|
||||
KBASE_HWCNT_READER_DUMP = MALI_IOW(KBASE_HWCNT_READER, 0x10, uint32_t),
|
||||
KBASE_HWCNT_READER_CLEAR = MALI_IOW(KBASE_HWCNT_READER, 0x11, uint32_t),
|
||||
KBASE_HWCNT_READER_GET_BUFFER = MALI_IOR(KBASE_HWCNT_READER, 0x20, struct kbase_hwcnt_reader_metadata),
|
||||
KBASE_HWCNT_READER_PUT_BUFFER = MALI_IOW(KBASE_HWCNT_READER, 0x21, struct kbase_hwcnt_reader_metadata),
|
||||
KBASE_HWCNT_READER_SET_INTERVAL = MALI_IOW(KBASE_HWCNT_READER, 0x30, uint32_t),
|
||||
KBASE_HWCNT_READER_ENABLE_EVENT = MALI_IOW(KBASE_HWCNT_READER, 0x40, uint32_t),
|
||||
KBASE_HWCNT_READER_DISABLE_EVENT = MALI_IOW(KBASE_HWCNT_READER, 0x41, uint32_t),
|
||||
KBASE_HWCNT_READER_GET_API_VERSION = MALI_IOW(KBASE_HWCNT_READER, 0xFF, uint32_t)
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PIPE_DESCRIPTOR_IN, /**< The index of a pipe's input descriptor. */
|
||||
PIPE_DESCRIPTOR_OUT, /**< The index of a pipe's output descriptor. */
|
||||
|
||||
PIPE_DESCRIPTOR_COUNT /**< The number of descriptors forming a pipe. */
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
POLL_DESCRIPTOR_SIGNAL, /**< The index of the signal descriptor in poll fds array. */
|
||||
POLL_DESCRIPTOR_HWCNT_READER, /**< The index of the hwcnt reader descriptor in poll fds array. */
|
||||
|
||||
POLL_DESCRIPTOR_COUNT /**< The number of descriptors poll is waiting for. */
|
||||
};
|
||||
|
||||
/** Write a single byte into the pipe to interrupt the reader thread */
|
||||
typedef char poll_data_t;
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
static inline int mali_ioctl(int fd, T &arg)
|
||||
{
|
||||
auto * hdr = &arg.header;
|
||||
const int cmd = _IOC(_IOC_READ | _IOC_WRITE, LINUX_UK_BASE_MAGIC, hdr->id, sizeof(T));
|
||||
|
||||
if (ioctl(fd, cmd, &arg))
|
||||
return -1;
|
||||
if (hdr->ret)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace mali_userspace
|
||||
|
||||
#endif /* DOXYGEN_SKIP_THIS */
|
||||
+3346
File diff suppressed because it is too large
Load Diff
Vendored
+614
@@ -0,0 +1,614 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include "mali_profiler.h"
|
||||
|
||||
#include "hwcpipe_log.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using mali_userspace::MALI_NAME_BLOCK_JM;
|
||||
using mali_userspace::MALI_NAME_BLOCK_MMU;
|
||||
using mali_userspace::MALI_NAME_BLOCK_SHADER;
|
||||
using mali_userspace::MALI_NAME_BLOCK_TILER;
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct MaliHWInfo
|
||||
{
|
||||
unsigned mp_count;
|
||||
unsigned gpu_id;
|
||||
unsigned r_value;
|
||||
unsigned p_value;
|
||||
unsigned core_mask;
|
||||
unsigned l2_slices;
|
||||
};
|
||||
|
||||
MaliHWInfo get_mali_hw_info(const char *path)
|
||||
{
|
||||
int fd = open(path, O_RDWR); // NOLINT
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
throw std::runtime_error("Failed to get HW info.");
|
||||
}
|
||||
|
||||
{
|
||||
mali_userspace::kbase_uk_hwcnt_reader_version_check_args version_check_args;
|
||||
version_check_args.header.id = mali_userspace::UKP_FUNC_ID_CHECK_VERSION; // NOLINT
|
||||
version_check_args.major = 10;
|
||||
version_check_args.minor = 2;
|
||||
|
||||
if (mali_userspace::mali_ioctl(fd, version_check_args) != 0)
|
||||
{
|
||||
mali_userspace::kbase_ioctl_version_check _version_check_args = {0, 0};
|
||||
if (ioctl(fd, KBASE_IOCTL_VERSION_CHECK, &_version_check_args) < 0)
|
||||
{
|
||||
close(fd);
|
||||
throw std::runtime_error("Failed to check version.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
mali_userspace::kbase_uk_hwcnt_reader_set_flags flags; // NOLINT
|
||||
memset(&flags, 0, sizeof(flags));
|
||||
flags.header.id = mali_userspace::KBASE_FUNC_SET_FLAGS; // NOLINT
|
||||
flags.create_flags = mali_userspace::BASE_CONTEXT_CREATE_KERNEL_FLAGS;
|
||||
|
||||
if (mali_userspace::mali_ioctl(fd, flags) != 0)
|
||||
{
|
||||
mali_userspace::kbase_ioctl_set_flags _flags = {1u << 1};
|
||||
if (ioctl(fd, KBASE_IOCTL_SET_FLAGS, &_flags) < 0)
|
||||
{
|
||||
close(fd);
|
||||
throw std::runtime_error("Failed settings flags ioctl.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MaliHWInfo hw_info; // NOLINT
|
||||
memset(&hw_info, 0, sizeof(hw_info));
|
||||
mali_userspace::kbase_uk_gpuprops props = {};
|
||||
props.header.id = mali_userspace::KBASE_FUNC_GPU_PROPS_REG_DUMP;
|
||||
if (mali_ioctl(fd, props) == 0)
|
||||
{
|
||||
hw_info.gpu_id = props.props.core_props.product_id;
|
||||
hw_info.r_value = props.props.core_props.major_revision;
|
||||
hw_info.p_value = props.props.core_props.minor_revision;
|
||||
for (uint32_t i = 0; i < props.props.coherency_info.num_core_groups; i++)
|
||||
hw_info.core_mask |= props.props.coherency_info.group[i].core_mask;
|
||||
hw_info.mp_count = __builtin_popcountll(hw_info.core_mask);
|
||||
hw_info.l2_slices = props.props.l2_props.num_l2_slices;
|
||||
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
mali_userspace::kbase_ioctl_get_gpuprops get_props = {};
|
||||
int ret;
|
||||
if ((ret = ioctl(fd, KBASE_IOCTL_GET_GPUPROPS, &get_props)) < 0)
|
||||
{
|
||||
throw std::runtime_error("Failed getting GPU properties.");
|
||||
close(fd);
|
||||
}
|
||||
|
||||
get_props.size = ret;
|
||||
std::vector<uint8_t> buffer(ret);
|
||||
get_props.buffer.value = buffer.data();
|
||||
ret = ioctl(fd, KBASE_IOCTL_GET_GPUPROPS, &get_props);
|
||||
if (ret < 0)
|
||||
{
|
||||
throw std::runtime_error("Failed getting GPU properties.");
|
||||
close(fd);
|
||||
}
|
||||
|
||||
#define READ_U8(p) ((p)[0])
|
||||
#define READ_U16(p) (READ_U8((p)) | (uint16_t(READ_U8((p) + 1)) << 8))
|
||||
#define READ_U32(p) (READ_U16((p)) | (uint32_t(READ_U16((p) + 2)) << 16))
|
||||
#define READ_U64(p) (READ_U32((p)) | (uint64_t(READ_U32((p) + 4)) << 32))
|
||||
|
||||
mali_userspace::gpu_props props = {};
|
||||
|
||||
const auto *ptr = buffer.data();
|
||||
int size = ret;
|
||||
while (size > 0)
|
||||
{
|
||||
uint32_t type = READ_U32(ptr);
|
||||
uint32_t value_type = type & 3;
|
||||
uint64_t value;
|
||||
|
||||
ptr += 4;
|
||||
size -= 4;
|
||||
|
||||
switch (value_type)
|
||||
{
|
||||
case KBASE_GPUPROP_VALUE_SIZE_U8:
|
||||
value = READ_U8(ptr);
|
||||
ptr++;
|
||||
size--;
|
||||
break;
|
||||
case KBASE_GPUPROP_VALUE_SIZE_U16:
|
||||
value = READ_U16(ptr);
|
||||
ptr += 2;
|
||||
size -= 2;
|
||||
break;
|
||||
case KBASE_GPUPROP_VALUE_SIZE_U32:
|
||||
value = READ_U32(ptr);
|
||||
ptr += 4;
|
||||
size -= 4;
|
||||
break;
|
||||
case KBASE_GPUPROP_VALUE_SIZE_U64:
|
||||
value = READ_U64(ptr);
|
||||
ptr += 8;
|
||||
size -= 8;
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; mali_userspace::gpu_property_mapping[i].type; i++)
|
||||
{
|
||||
if (mali_userspace::gpu_property_mapping[i].type == (type >> 2))
|
||||
{
|
||||
auto offset = mali_userspace::gpu_property_mapping[i].offset;
|
||||
void *p = reinterpret_cast<uint8_t *>(&props) + offset;
|
||||
switch (mali_userspace::gpu_property_mapping[i].size)
|
||||
{
|
||||
case 1:
|
||||
*reinterpret_cast<uint8_t *>(p) = value;
|
||||
break;
|
||||
case 2:
|
||||
*reinterpret_cast<uint16_t *>(p) = value;
|
||||
break;
|
||||
case 4:
|
||||
*reinterpret_cast<uint32_t *>(p) = value;
|
||||
break;
|
||||
case 8:
|
||||
*reinterpret_cast<uint64_t *>(p) = value;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid property size.");
|
||||
close(fd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hw_info.gpu_id = props.product_id;
|
||||
hw_info.r_value = props.major_revision;
|
||||
hw_info.p_value = props.minor_revision;
|
||||
for (uint32_t i = 0; i < props.num_core_groups; i++)
|
||||
hw_info.core_mask |= props.core_mask[i];
|
||||
hw_info.mp_count = __builtin_popcountll(hw_info.core_mask);
|
||||
hw_info.l2_slices = props.l2_slices;
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return hw_info;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
typedef std::function<uint64_t(void)> MaliValueGetter;
|
||||
|
||||
MaliProfiler::MaliProfiler(const GpuCounterSet &enabled_counters) :
|
||||
enabled_counters_(enabled_counters)
|
||||
{
|
||||
// Throws if setup fails
|
||||
init();
|
||||
|
||||
const std::unordered_map<GpuCounter, MaliValueGetter, GpuCounterHash> bifrost_mappings = {
|
||||
{GpuCounter::GpuCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "GPU_ACTIVE"); }},
|
||||
{GpuCounter::VertexComputeCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS1_ACTIVE"); }},
|
||||
{GpuCounter::FragmentCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS0_ACTIVE"); }},
|
||||
{GpuCounter::TilerCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_TILER, "TILER_ACTIVE"); }},
|
||||
|
||||
{GpuCounter::VertexComputeJobs, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS1_JOBS"); }},
|
||||
{GpuCounter::FragmentJobs, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS0_JOBS"); }},
|
||||
{GpuCounter::Pixels, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS0_TASKS") * 1024; }},
|
||||
|
||||
{GpuCounter::Tiles, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_PTILES"); }},
|
||||
{GpuCounter::TransactionEliminations, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_TRANS_ELIM"); }},
|
||||
{GpuCounter::EarlyZTests, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_QUADS_EZS_TEST"); }},
|
||||
{GpuCounter::EarlyZKilled, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_QUADS_EZS_KILL"); }},
|
||||
{GpuCounter::LateZTests, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_LZS_TEST"); }},
|
||||
{GpuCounter::LateZKilled, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_LZS_KILL"); }},
|
||||
|
||||
{GpuCounter::Instructions, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "EXEC_INSTR_COUNT"); }},
|
||||
{GpuCounter::DivergedInstructions, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "EXEC_INSTR_DIVERGED"); }},
|
||||
|
||||
{GpuCounter::ShaderCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "EXEC_CORE_ACTIVE"); }},
|
||||
{GpuCounter::ShaderArithmeticCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "EXEC_INSTR_COUNT"); }},
|
||||
{GpuCounter::ShaderLoadStoreCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "LS_MEM_READ_FULL") + get_counter_value(MALI_NAME_BLOCK_SHADER, "LS_MEM_WRITE_FULL") + get_counter_value(MALI_NAME_BLOCK_SHADER, "LS_MEM_READ_SHORT") + get_counter_value(MALI_NAME_BLOCK_SHADER, "LS_MEM_WRITE_SHORT") + get_counter_value(MALI_NAME_BLOCK_SHADER, "LS_MEM_ATOMIC"); }},
|
||||
{GpuCounter::ShaderTextureCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "TEX_FILT_NUM_OPERATIONS"); }},
|
||||
|
||||
{GpuCounter::CacheReadLookups, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_READ_LOOKUP"); }},
|
||||
{GpuCounter::CacheWriteLookups, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_WRITE_LOOKUP"); }},
|
||||
{GpuCounter::ExternalMemoryReadAccesses, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_READ"); }},
|
||||
{GpuCounter::ExternalMemoryWriteAccesses, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_WRITE"); }},
|
||||
{GpuCounter::ExternalMemoryReadStalls, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_AR_STALL"); }},
|
||||
{GpuCounter::ExternalMemoryWriteStalls, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_W_STALL"); }},
|
||||
{GpuCounter::ExternalMemoryReadBytes, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_READ_BEATS") * 16; }},
|
||||
{GpuCounter::ExternalMemoryWriteBytes, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_WRITE_BEATS") * 16; }},
|
||||
};
|
||||
|
||||
const std::unordered_map<GpuCounter, MaliValueGetter, GpuCounterHash> midgard_mappings = {
|
||||
{GpuCounter::GpuCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "GPU_ACTIVE"); }},
|
||||
{GpuCounter::VertexComputeCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS1_ACTIVE"); }},
|
||||
{GpuCounter::FragmentCycles, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS0_ACTIVE"); }},
|
||||
|
||||
{GpuCounter::VertexComputeJobs, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS1_JOBS"); }},
|
||||
{GpuCounter::FragmentJobs, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS0_JOBS"); }},
|
||||
{GpuCounter::Pixels, [this] { return get_counter_value(MALI_NAME_BLOCK_JM, "JS0_TASKS") * 1024; }},
|
||||
|
||||
{GpuCounter::Tiles, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_PTILES"); }},
|
||||
{GpuCounter::TransactionEliminations, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_TRANS_ELIM"); }},
|
||||
{GpuCounter::EarlyZTests, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_QUADS_EZS_TEST"); }},
|
||||
{GpuCounter::EarlyZKilled, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_QUADS_EZS_KILLED"); }},
|
||||
{GpuCounter::LateZTests, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_THREADS_LZS_TEST"); }},
|
||||
{GpuCounter::LateZKilled, [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "FRAG_THREADS_LZS_KILLED"); }},
|
||||
|
||||
{GpuCounter::CacheReadLookups, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_READ_LOOKUP"); }},
|
||||
{GpuCounter::CacheWriteLookups, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_WRITE_LOOKUP"); }},
|
||||
{GpuCounter::ExternalMemoryReadAccesses, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_READ"); }},
|
||||
{GpuCounter::ExternalMemoryWriteAccesses, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_WRITE"); }},
|
||||
{GpuCounter::ExternalMemoryReadStalls, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_AR_STALL"); }},
|
||||
{GpuCounter::ExternalMemoryWriteStalls, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_W_STALL"); }},
|
||||
{GpuCounter::ExternalMemoryReadBytes, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_READ_BEATS") * 16; }},
|
||||
{GpuCounter::ExternalMemoryWriteBytes, [this] { return get_counter_value(MALI_NAME_BLOCK_MMU, "L2_EXT_WRITE_BEATS") * 16; }},
|
||||
};
|
||||
|
||||
auto product = std::find_if(std::begin(mali_userspace::products), std::end(mali_userspace::products), [&](const mali_userspace::CounterMapping &cm) {
|
||||
return (cm.product_mask & gpu_id_) == cm.product_id;
|
||||
});
|
||||
|
||||
if (product != std::end(mali_userspace::products))
|
||||
{
|
||||
switch (product->product_id)
|
||||
{
|
||||
case mali_userspace::PRODUCT_ID_T60X:
|
||||
case mali_userspace::PRODUCT_ID_T62X:
|
||||
case mali_userspace::PRODUCT_ID_T72X:
|
||||
mappings_ = midgard_mappings;
|
||||
mappings_[GpuCounter::Pixels] = [this]() { return get_counter_value(MALI_NAME_BLOCK_JM, "JS0_TASKS") * 256; };
|
||||
break;
|
||||
case mali_userspace::PRODUCT_ID_T76X:
|
||||
case mali_userspace::PRODUCT_ID_T82X:
|
||||
case mali_userspace::PRODUCT_ID_T83X:
|
||||
case mali_userspace::PRODUCT_ID_T86X:
|
||||
case mali_userspace::PRODUCT_ID_TFRX:
|
||||
mappings_ = midgard_mappings;
|
||||
break;
|
||||
case mali_userspace::PRODUCT_ID_TMIX:
|
||||
case mali_userspace::PRODUCT_ID_THEX:
|
||||
mappings_ = bifrost_mappings;
|
||||
mappings_[GpuCounter::ShaderTextureCycles] = [this] { return get_counter_value(MALI_NAME_BLOCK_SHADER, "TEX_COORD_ISSUE"); };
|
||||
break;
|
||||
case mali_userspace::PRODUCT_ID_TSIX:
|
||||
case mali_userspace::PRODUCT_ID_TNOX:
|
||||
default:
|
||||
mappings_ = bifrost_mappings;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HWCPIPE_LOG("Mali counters initialization failed: Failed to identify GPU");
|
||||
}
|
||||
}
|
||||
|
||||
void MaliProfiler::init()
|
||||
{
|
||||
MaliHWInfo hw_info = get_mali_hw_info(device_);
|
||||
|
||||
num_cores_ = hw_info.mp_count;
|
||||
num_l2_slices_ = hw_info.l2_slices;
|
||||
gpu_id_ = hw_info.gpu_id;
|
||||
|
||||
fd_ = open(device_, O_RDWR | O_CLOEXEC | O_NONBLOCK); // NOLINT
|
||||
|
||||
if (fd_ < 0)
|
||||
{
|
||||
throw std::runtime_error("Failed to open /dev/mali0.");
|
||||
}
|
||||
|
||||
{
|
||||
mali_userspace::kbase_uk_hwcnt_reader_version_check_args check; // NOLINT
|
||||
memset(&check, 0, sizeof(check));
|
||||
|
||||
if (mali_userspace::mali_ioctl(fd_, check) != 0)
|
||||
{
|
||||
mali_userspace::kbase_ioctl_version_check _check = {0, 0};
|
||||
if (ioctl(fd_, KBASE_IOCTL_VERSION_CHECK, &_check) < 0)
|
||||
{
|
||||
throw std::runtime_error("Failed to get ABI version.");
|
||||
}
|
||||
}
|
||||
else if (check.major < 10)
|
||||
{
|
||||
throw std::runtime_error("Unsupported ABI version 10.");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
mali_userspace::kbase_uk_hwcnt_reader_set_flags flags; // NOLINT
|
||||
memset(&flags, 0, sizeof(flags));
|
||||
flags.header.id = mali_userspace::KBASE_FUNC_SET_FLAGS; // NOLINT
|
||||
flags.create_flags = mali_userspace::BASE_CONTEXT_CREATE_KERNEL_FLAGS;
|
||||
|
||||
if (mali_userspace::mali_ioctl(fd_, flags) != 0)
|
||||
{
|
||||
mali_userspace::kbase_ioctl_set_flags _flags = {1u << 1};
|
||||
if (ioctl(fd_, KBASE_IOCTL_SET_FLAGS, &_flags) < 0)
|
||||
{
|
||||
throw std::runtime_error("Failed settings flags ioctl.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
mali_userspace::kbase_uk_hwcnt_reader_setup setup; // NOLINT
|
||||
memset(&setup, 0, sizeof(setup));
|
||||
setup.header.id = mali_userspace::KBASE_FUNC_HWCNT_READER_SETUP; // NOLINT
|
||||
setup.buffer_count = buffer_count_;
|
||||
setup.jm_bm = -1;
|
||||
setup.shader_bm = -1;
|
||||
setup.tiler_bm = -1;
|
||||
setup.mmu_l2_bm = -1;
|
||||
setup.fd = -1;
|
||||
|
||||
if (mali_userspace::mali_ioctl(fd_, setup) != 0)
|
||||
{
|
||||
mali_userspace::kbase_ioctl_hwcnt_reader_setup _setup = {};
|
||||
_setup.buffer_count = buffer_count_;
|
||||
_setup.jm_bm = -1;
|
||||
_setup.shader_bm = -1;
|
||||
_setup.tiler_bm = -1;
|
||||
_setup.mmu_l2_bm = -1;
|
||||
|
||||
int ret;
|
||||
if ((ret = ioctl(fd_, KBASE_IOCTL_HWCNT_READER_SETUP, &_setup)) < 0)
|
||||
{
|
||||
throw std::runtime_error("Failed setting hwcnt reader ioctl.");
|
||||
}
|
||||
hwc_fd_ = ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
hwc_fd_ = setup.fd;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t api_version = ~mali_userspace::HWCNT_READER_API;
|
||||
|
||||
if (ioctl(hwc_fd_, mali_userspace::KBASE_HWCNT_READER_GET_API_VERSION, &api_version) != 0) // NOLINT
|
||||
{
|
||||
throw std::runtime_error("Could not determine hwcnt reader API.");
|
||||
}
|
||||
else if (api_version != mali_userspace::HWCNT_READER_API)
|
||||
{
|
||||
throw std::runtime_error("Invalid API version.");
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(hwc_fd_, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_BUFFER_SIZE), &buffer_size_) != 0) // NOLINT
|
||||
{
|
||||
throw std::runtime_error("Failed to get buffer size.");
|
||||
}
|
||||
|
||||
if (ioctl(hwc_fd_, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_HWVER), &hw_ver_) != 0) // NOLINT
|
||||
{
|
||||
throw std::runtime_error("Could not determine HW version.");
|
||||
}
|
||||
|
||||
if (hw_ver_ < 5)
|
||||
{
|
||||
throw std::runtime_error("Unsupported HW version.");
|
||||
}
|
||||
|
||||
sample_data_ = static_cast<uint8_t *>(mmap(nullptr, buffer_count_ * buffer_size_, PROT_READ, MAP_PRIVATE, hwc_fd_, 0));
|
||||
|
||||
if (sample_data_ == MAP_FAILED) // NOLINT
|
||||
{
|
||||
throw std::runtime_error("Failed to map sample data.");
|
||||
}
|
||||
|
||||
auto product = std::find_if(std::begin(mali_userspace::products), std::end(mali_userspace::products), [&](const mali_userspace::CounterMapping &cm) {
|
||||
return (cm.product_mask & hw_info.gpu_id) == cm.product_id;
|
||||
});
|
||||
|
||||
if (product != std::end(mali_userspace::products))
|
||||
{
|
||||
names_lut_ = product->names_lut;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Could not identify GPU.");
|
||||
}
|
||||
|
||||
raw_counter_buffer_.resize(buffer_size_ / sizeof(uint32_t));
|
||||
|
||||
// Build core remap table.
|
||||
core_index_remap_.clear();
|
||||
core_index_remap_.reserve(hw_info.mp_count);
|
||||
|
||||
unsigned int mask = hw_info.core_mask;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
unsigned int bit = __builtin_ctz(mask);
|
||||
core_index_remap_.push_back(bit);
|
||||
mask &= ~(1u << bit);
|
||||
}
|
||||
}
|
||||
|
||||
void MaliProfiler::run()
|
||||
{
|
||||
sample_counters();
|
||||
wait_next_event();
|
||||
}
|
||||
|
||||
void MaliProfiler::stop()
|
||||
{
|
||||
// We don't need to do anything on stop()
|
||||
}
|
||||
|
||||
const GpuMeasurements &MaliProfiler::sample()
|
||||
{
|
||||
sample_counters();
|
||||
wait_next_event();
|
||||
|
||||
for (const auto &counter : enabled_counters_)
|
||||
{
|
||||
auto mapping = mappings_.find(counter);
|
||||
if (mapping == mappings_.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
measurements_[mapping->first] = mapping->second();
|
||||
}
|
||||
|
||||
return measurements_;
|
||||
}
|
||||
|
||||
void MaliProfiler::sample_counters()
|
||||
{
|
||||
if (ioctl(hwc_fd_, mali_userspace::KBASE_HWCNT_READER_DUMP, 0) != 0)
|
||||
{
|
||||
throw std::runtime_error("Could not sample hardware counters.");
|
||||
}
|
||||
}
|
||||
|
||||
void MaliProfiler::wait_next_event()
|
||||
{
|
||||
pollfd poll_fd; // NOLINT
|
||||
poll_fd.fd = hwc_fd_;
|
||||
poll_fd.events = POLLIN;
|
||||
|
||||
const int count = poll(&poll_fd, 1, -1);
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
throw std::runtime_error("poll() failed.");
|
||||
}
|
||||
|
||||
if ((poll_fd.revents & POLLIN) != 0)
|
||||
{
|
||||
mali_userspace::kbase_hwcnt_reader_metadata meta; // NOLINT
|
||||
|
||||
if (ioctl(hwc_fd_, static_cast<int>(mali_userspace::KBASE_HWCNT_READER_GET_BUFFER), &meta) != 0) // NOLINT
|
||||
{
|
||||
throw std::runtime_error("Failed READER_GET_BUFFER.");
|
||||
}
|
||||
|
||||
memcpy(raw_counter_buffer_.data(), sample_data_ + buffer_size_ * meta.buffer_idx, buffer_size_);
|
||||
timestamp_ = meta.timestamp;
|
||||
|
||||
if (ioctl(hwc_fd_, mali_userspace::KBASE_HWCNT_READER_PUT_BUFFER, &meta) != 0) // NOLINT
|
||||
{
|
||||
throw std::runtime_error("Failed READER_PUT_BUFFER.");
|
||||
}
|
||||
}
|
||||
else if ((poll_fd.revents & POLLHUP) != 0)
|
||||
{
|
||||
throw std::runtime_error("HWC hung up.");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t MaliProfiler::get_counter_value(mali_userspace::MaliCounterBlockName block, const char *name) const
|
||||
{
|
||||
uint64_t sum = 0;
|
||||
switch (block)
|
||||
{
|
||||
case mali_userspace::MALI_NAME_BLOCK_MMU:
|
||||
// If an MMU counter is selected, sum the values over MMU slices
|
||||
for (int i = 0; i < num_l2_slices_; i++)
|
||||
{
|
||||
sum += get_counters(block, i)[find_counter_index_by_name(block, name)];
|
||||
}
|
||||
return sum;
|
||||
|
||||
case mali_userspace::MALI_NAME_BLOCK_SHADER:
|
||||
// If a shader core counter is selected, sum the values over shader cores
|
||||
for (int i = 0; i < num_cores_; i++)
|
||||
{
|
||||
sum += get_counters(block, i)[find_counter_index_by_name(block, name)];
|
||||
}
|
||||
return sum;
|
||||
|
||||
case mali_userspace::MALI_NAME_BLOCK_JM:
|
||||
case mali_userspace::MALI_NAME_BLOCK_TILER:
|
||||
default:
|
||||
return static_cast<uint64_t>(get_counters(block)[find_counter_index_by_name(block, name)]);
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t *MaliProfiler::get_counters(mali_userspace::MaliCounterBlockName block, int index) const
|
||||
{
|
||||
switch (block)
|
||||
{
|
||||
case mali_userspace::MALI_NAME_BLOCK_JM:
|
||||
return raw_counter_buffer_.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * 0;
|
||||
case mali_userspace::MALI_NAME_BLOCK_MMU:
|
||||
if (index < 0 || index >= num_l2_slices_)
|
||||
{
|
||||
throw std::runtime_error("Invalid slice number.");
|
||||
}
|
||||
|
||||
// If an MMU counter is selected, index refers to the MMU slice
|
||||
return raw_counter_buffer_.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * (2 + index);
|
||||
case mali_userspace::MALI_NAME_BLOCK_TILER:
|
||||
return raw_counter_buffer_.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * 1;
|
||||
default:
|
||||
if (index < 0 || index >= num_cores_)
|
||||
{
|
||||
throw std::runtime_error("Invalid core number.");
|
||||
}
|
||||
|
||||
// If a shader core counter is selected, index refers to the core index
|
||||
return raw_counter_buffer_.data() + mali_userspace::MALI_NAME_BLOCK_SIZE * (2 + num_l2_slices_ + core_index_remap_[index]);
|
||||
}
|
||||
}
|
||||
|
||||
int MaliProfiler::find_counter_index_by_name(mali_userspace::MaliCounterBlockName block, const char *name) const
|
||||
{
|
||||
const char *const *names = &names_lut_[mali_userspace::MALI_NAME_BLOCK_SIZE * block];
|
||||
|
||||
for (int i = 0; i < mali_userspace::MALI_NAME_BLOCK_SIZE; ++i)
|
||||
{
|
||||
if (strstr(names[i], name) != nullptr)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace hwcpipe
|
||||
Vendored
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_profiler.h"
|
||||
|
||||
#include "hwc.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
/** A Gpu profiler that uses Mali counter data. */
|
||||
class MaliProfiler : public GpuProfiler
|
||||
{
|
||||
public:
|
||||
explicit MaliProfiler(const GpuCounterSet &enabled_counters);
|
||||
virtual ~MaliProfiler() = default;
|
||||
|
||||
virtual const GpuCounterSet &enabled_counters() const override
|
||||
{
|
||||
return enabled_counters_;
|
||||
}
|
||||
|
||||
virtual const GpuCounterSet &supported_counters() const override
|
||||
{
|
||||
return supported_counters_;
|
||||
};
|
||||
|
||||
virtual void set_enabled_counters(GpuCounterSet counters) override
|
||||
{
|
||||
enabled_counters_ = std::move(counters);
|
||||
};
|
||||
|
||||
virtual void run() override;
|
||||
virtual const GpuMeasurements &sample() override;
|
||||
virtual void stop() override;
|
||||
|
||||
private:
|
||||
GpuCounterSet enabled_counters_{};
|
||||
|
||||
const GpuCounterSet supported_counters_{
|
||||
GpuCounter::GpuCycles,
|
||||
GpuCounter::VertexComputeCycles,
|
||||
GpuCounter::FragmentCycles,
|
||||
GpuCounter::TilerCycles,
|
||||
GpuCounter::VertexComputeJobs,
|
||||
GpuCounter::Tiles,
|
||||
GpuCounter::TransactionEliminations,
|
||||
GpuCounter::FragmentJobs,
|
||||
GpuCounter::Pixels,
|
||||
GpuCounter::EarlyZTests,
|
||||
GpuCounter::EarlyZKilled,
|
||||
GpuCounter::LateZTests,
|
||||
GpuCounter::LateZKilled,
|
||||
GpuCounter::Instructions,
|
||||
GpuCounter::DivergedInstructions,
|
||||
GpuCounter::ShaderCycles,
|
||||
GpuCounter::ShaderArithmeticCycles,
|
||||
GpuCounter::ShaderLoadStoreCycles,
|
||||
GpuCounter::ShaderTextureCycles,
|
||||
GpuCounter::CacheReadLookups,
|
||||
GpuCounter::CacheWriteLookups,
|
||||
GpuCounter::ExternalMemoryReadAccesses,
|
||||
GpuCounter::ExternalMemoryWriteAccesses,
|
||||
GpuCounter::ExternalMemoryReadStalls,
|
||||
GpuCounter::ExternalMemoryWriteStalls,
|
||||
GpuCounter::ExternalMemoryReadBytes,
|
||||
GpuCounter::ExternalMemoryWriteBytes,
|
||||
};
|
||||
|
||||
typedef std::function<double(void)> MaliValueGetter;
|
||||
std::unordered_map<GpuCounter, MaliValueGetter, GpuCounterHash> mappings_{};
|
||||
|
||||
const char *const device_{"/dev/mali0"};
|
||||
int num_cores_{0};
|
||||
int num_l2_slices_{0};
|
||||
int gpu_id_{0};
|
||||
uint32_t hw_ver_{0};
|
||||
int buffer_count_{16};
|
||||
size_t buffer_size_{0};
|
||||
uint8_t * sample_data_{nullptr};
|
||||
uint64_t timestamp_{0};
|
||||
const char *const *names_lut_{
|
||||
nullptr};
|
||||
std::vector<uint32_t> raw_counter_buffer_{};
|
||||
std::vector<unsigned int> core_index_remap_{};
|
||||
int fd_{-1};
|
||||
int hwc_fd_{-1};
|
||||
|
||||
GpuMeasurements measurements_{};
|
||||
|
||||
void init();
|
||||
void sample_counters();
|
||||
void wait_next_event();
|
||||
const uint32_t *get_counters(mali_userspace::MaliCounterBlockName block, int index = 0) const;
|
||||
uint64_t get_counter_value(mali_userspace::MaliCounterBlockName block, const char *name) const;
|
||||
int find_counter_index_by_name(mali_userspace::MaliCounterBlockName block, const char *name) const;
|
||||
};
|
||||
|
||||
} // namespace hwcpipe
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "pmu_counter.h"
|
||||
|
||||
#include <asm/unistd.h>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/* Add std_to_string implementation as it is possible that Android does not provide it */
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
template <typename T>
|
||||
std::string std_to_string(T value)
|
||||
{
|
||||
std::ostringstream os ;
|
||||
os << value ;
|
||||
return os.str() ;
|
||||
}
|
||||
|
||||
|
||||
PmuCounter::PmuCounter() :
|
||||
_perf_config()
|
||||
{
|
||||
_perf_config.type = PERF_TYPE_HARDWARE;
|
||||
_perf_config.size = sizeof(perf_event_attr);
|
||||
|
||||
// Start disabled
|
||||
_perf_config.disabled = 1;
|
||||
// The inherit bit specifies that this counter should count events of child
|
||||
// tasks as well as the task specified
|
||||
_perf_config.inherit = 1;
|
||||
// Enables saving of event counts on context switch for inherited tasks
|
||||
_perf_config.inherit_stat = 1;
|
||||
}
|
||||
|
||||
PmuCounter::PmuCounter(uint64_t config) :
|
||||
PmuCounter()
|
||||
{
|
||||
open(config);
|
||||
}
|
||||
|
||||
PmuCounter::~PmuCounter()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void PmuCounter::open(uint64_t config)
|
||||
{
|
||||
_perf_config.config = config;
|
||||
open(_perf_config);
|
||||
}
|
||||
|
||||
void PmuCounter::open(const perf_event_attr &perf_config)
|
||||
{
|
||||
// Measure this process/thread (+ children) on any CPU
|
||||
_fd = syscall(__NR_perf_event_open, &perf_config, 0, -1, -1, 0);
|
||||
|
||||
if (_fd < 0)
|
||||
{
|
||||
throw std::runtime_error("perf_event_open failed. Counter ID: " + config_to_str(_perf_config));
|
||||
}
|
||||
|
||||
const int result = ioctl(_fd, PERF_EVENT_IOC_ENABLE, 0);
|
||||
if (result == -1)
|
||||
{
|
||||
throw std::runtime_error("Failed to enable PMU counter: " + std::string(strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
void PmuCounter::close()
|
||||
{
|
||||
if (_fd != -1)
|
||||
{
|
||||
::close(_fd);
|
||||
_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool PmuCounter::reset()
|
||||
{
|
||||
const int result = ioctl(_fd, PERF_EVENT_IOC_RESET, 0);
|
||||
|
||||
if (result == -1)
|
||||
{
|
||||
throw std::runtime_error("Failed to reset PMU counter: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
return result != -1;
|
||||
}
|
||||
|
||||
std::string PmuCounter::config_to_str(const perf_event_attr &perf_config)
|
||||
{
|
||||
switch (perf_config.type)
|
||||
{
|
||||
case PERF_TYPE_HARDWARE:
|
||||
switch (perf_config.config)
|
||||
{
|
||||
case PERF_COUNT_HW_CPU_CYCLES:
|
||||
return "PERF_COUNT_HW_CPU_CYCLES";
|
||||
case PERF_COUNT_HW_INSTRUCTIONS:
|
||||
return "PERF_COUNT_HW_INSTRUCTIONS";
|
||||
case PERF_COUNT_HW_CACHE_REFERENCES:
|
||||
return "PERF_COUNT_HW_CACHE_REFERENCES";
|
||||
case PERF_COUNT_HW_CACHE_MISSES:
|
||||
return "PERF_COUNT_HW_CACHE_MISSES";
|
||||
case PERF_COUNT_HW_BRANCH_INSTRUCTIONS:
|
||||
return "PERF_COUNT_HW_BRANCH_INSTRUCTIONS";
|
||||
case PERF_COUNT_HW_BRANCH_MISSES:
|
||||
return "PERF_COUNT_HW_BRANCH_MISSES";
|
||||
case PERF_COUNT_HW_BUS_CYCLES:
|
||||
return "PERF_COUNT_HW_BUS_CYCLES";
|
||||
case PERF_COUNT_HW_STALLED_CYCLES_FRONTEND:
|
||||
return "PERF_COUNT_HW_STALLED_CYCLES_FRONTEND";
|
||||
case PERF_COUNT_HW_STALLED_CYCLES_BACKEND:
|
||||
return "PERF_COUNT_HW_STALLED_CYCLES_BACKEND";
|
||||
case PERF_COUNT_HW_REF_CPU_CYCLES:
|
||||
return "PERF_COUNT_HW_REF_CPU_CYCLES";
|
||||
default:
|
||||
return "UNKNOWN HARDWARE COUNTER";
|
||||
}
|
||||
|
||||
case PERF_TYPE_SOFTWARE:
|
||||
switch (perf_config.config)
|
||||
{
|
||||
case PERF_COUNT_SW_CPU_CLOCK:
|
||||
return "PERF_COUNT_SW_CPU_CLOCK";
|
||||
case PERF_COUNT_SW_TASK_CLOCK:
|
||||
return "PERF_COUNT_SW_TASK_CLOCK";
|
||||
case PERF_COUNT_SW_PAGE_FAULTS:
|
||||
return "PERF_COUNT_SW_PAGE_FAULTS";
|
||||
case PERF_COUNT_SW_CONTEXT_SWITCHES:
|
||||
return "PERF_COUNT_SW_CONTEXT_SWITCHES";
|
||||
case PERF_COUNT_SW_CPU_MIGRATIONS:
|
||||
return "PERF_COUNT_SW_CPU_MIGRATIONS";
|
||||
case PERF_COUNT_SW_PAGE_FAULTS_MIN:
|
||||
return "PERF_COUNT_SW_PAGE_FAULTS_MIN";
|
||||
case PERF_COUNT_SW_PAGE_FAULTS_MAJ:
|
||||
return "PERF_COUNT_SW_PAGE_FAULTS_MAJ";
|
||||
case PERF_COUNT_SW_ALIGNMENT_FAULTS:
|
||||
return "PERF_COUNT_SW_ALIGNMENT_FAULTS";
|
||||
case PERF_COUNT_SW_EMULATION_FAULTS:
|
||||
return "PERF_COUNT_SW_EMULATION_FAULTS";
|
||||
case PERF_COUNT_SW_DUMMY:
|
||||
return "PERF_COUNT_SW_DUMMY";
|
||||
default:
|
||||
return "UNKNOWN SOFTWARE COUNTER";
|
||||
}
|
||||
default:
|
||||
return std_to_string(perf_config.config);
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "hwcpipe_log.h"
|
||||
|
||||
/** Class provides access to CPU hardware counters. */
|
||||
class PmuCounter
|
||||
{
|
||||
public:
|
||||
/** Default constructor. */
|
||||
PmuCounter();
|
||||
|
||||
/** Create PMU counter with specified config.
|
||||
*
|
||||
* This constructor automatically calls @ref open with the default
|
||||
* configuration.
|
||||
*
|
||||
* @param[in] config Counter identifier.
|
||||
*/
|
||||
PmuCounter(uint64_t config);
|
||||
|
||||
/** Default destructor. */
|
||||
~PmuCounter();
|
||||
|
||||
/** Get the counter value.
|
||||
*
|
||||
* @return Counter value casted to the specified type. */
|
||||
template <typename T>
|
||||
T get_value() const;
|
||||
|
||||
/** Open the specified counter based on the default configuration.
|
||||
*
|
||||
* @param[in] config The default configuration.
|
||||
*/
|
||||
void open(uint64_t config);
|
||||
|
||||
/** Open the specified configuration.
|
||||
*
|
||||
* @param[in] perf_config The specified configuration.
|
||||
*/
|
||||
void open(const perf_event_attr &perf_config);
|
||||
|
||||
/** Close the currently open counter. */
|
||||
void close();
|
||||
|
||||
/** Reset counter.
|
||||
*
|
||||
* @return false if reset fails. */
|
||||
bool reset();
|
||||
|
||||
/** Print counter config ID. */
|
||||
std::string config_to_str(const perf_event_attr &perf_config);
|
||||
|
||||
private:
|
||||
perf_event_attr _perf_config;
|
||||
long _fd{-1};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T PmuCounter::get_value() const
|
||||
{
|
||||
long long value{};
|
||||
const ssize_t result = read(_fd, &value, sizeof(long long));
|
||||
|
||||
if (result == -1)
|
||||
{
|
||||
throw std::runtime_error("Can't get PMU counter value: " + std::string(std::strerror(errno)));
|
||||
}
|
||||
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
Vendored
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "pmu_profiler.h"
|
||||
|
||||
#include "hwcpipe_log.h"
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
const std::unordered_map<CpuCounter, uint64_t, CpuCounterHash> pmu_mappings{
|
||||
{CpuCounter::Cycles, PERF_COUNT_HW_CPU_CYCLES},
|
||||
{CpuCounter::Instructions, PERF_COUNT_HW_INSTRUCTIONS},
|
||||
{CpuCounter::CacheReferences, PERF_COUNT_HW_CACHE_REFERENCES},
|
||||
{CpuCounter::CacheMisses, PERF_COUNT_HW_CACHE_MISSES},
|
||||
{CpuCounter::BranchInstructions, PERF_COUNT_HW_BRANCH_INSTRUCTIONS},
|
||||
{CpuCounter::BranchMisses, PERF_COUNT_HW_BRANCH_MISSES},
|
||||
};
|
||||
|
||||
PmuProfiler::PmuProfiler(const CpuCounterSet &enabled_counters) :
|
||||
enabled_counters_(enabled_counters)
|
||||
{
|
||||
// Set up PMU counters
|
||||
for (const auto &counter : enabled_counters)
|
||||
{
|
||||
const auto &pmu_config = pmu_mappings.find(counter);
|
||||
if (pmu_config != pmu_mappings.end())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create a PMU counter with the specified configuration
|
||||
auto pmu_counter_res = pmu_counters_.emplace(counter, pmu_config->second);
|
||||
|
||||
// Try reading a value from the counter to check that it opened correctly
|
||||
auto &pmu_counter = pmu_counter_res.first->second;
|
||||
pmu_counter.get_value<long long>();
|
||||
|
||||
// PMU counter is created and can retrieve values
|
||||
available_counters_.insert(counter);
|
||||
}
|
||||
catch (const std::runtime_error &e)
|
||||
{
|
||||
// PMU counter initialization failed
|
||||
HWCPIPE_LOG("%s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (available_counters_.size() == 0)
|
||||
{
|
||||
throw std::runtime_error("PMU counters not available.");
|
||||
}
|
||||
}
|
||||
|
||||
void PmuProfiler::run()
|
||||
{
|
||||
for (auto &pmu_counter : pmu_counters_)
|
||||
{
|
||||
pmu_counter.second.reset();
|
||||
prev_measurements_[pmu_counter.first] = Value{};
|
||||
}
|
||||
}
|
||||
|
||||
const CpuMeasurements &PmuProfiler::sample()
|
||||
{
|
||||
for (const auto &counter : enabled_counters_)
|
||||
{
|
||||
const auto &pmu_counter = pmu_counters_.find(counter);
|
||||
if (pmu_counter == pmu_counters_.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto value = pmu_counter->second.get_value<long long>();
|
||||
|
||||
// Resetting the PMU counter every frame seems to alter the data,
|
||||
// so we make a differential reading.
|
||||
measurements_[pmu_counter->first] = value - prev_measurements_[pmu_counter->first].get<long long>();
|
||||
prev_measurements_[pmu_counter->first] = value;
|
||||
}
|
||||
catch (const std::runtime_error &e)
|
||||
{
|
||||
HWCPIPE_LOG("Failed to get value from PMU: %s.", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return measurements_;
|
||||
}
|
||||
|
||||
void PmuProfiler::stop()
|
||||
{
|
||||
// We don't need to do anything on stop()
|
||||
}
|
||||
|
||||
} // namespace hwcpipe
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2019 ARM Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu_profiler.h"
|
||||
|
||||
#include "pmu_counter.h"
|
||||
|
||||
namespace hwcpipe
|
||||
{
|
||||
/** A CPU profiler that uses PMU counter data. */
|
||||
class PmuProfiler : public CpuProfiler
|
||||
{
|
||||
public:
|
||||
explicit PmuProfiler(const CpuCounterSet &enabled_counters);
|
||||
virtual ~PmuProfiler() = default;
|
||||
|
||||
virtual const CpuCounterSet &enabled_counters() const override
|
||||
{
|
||||
return enabled_counters_;
|
||||
}
|
||||
|
||||
virtual const CpuCounterSet &supported_counters() const override
|
||||
{
|
||||
return supported_counters_;
|
||||
};
|
||||
|
||||
virtual void set_enabled_counters(CpuCounterSet counters) override
|
||||
{
|
||||
enabled_counters_ = std::move(counters);
|
||||
};
|
||||
|
||||
virtual void run() override;
|
||||
virtual const CpuMeasurements &sample() override;
|
||||
virtual void stop() override;
|
||||
|
||||
private:
|
||||
CpuCounterSet enabled_counters_{};
|
||||
CpuCounterSet available_counters_{};
|
||||
|
||||
const CpuCounterSet supported_counters_{
|
||||
CpuCounter::Cycles,
|
||||
CpuCounter::Instructions,
|
||||
CpuCounter::CacheReferences,
|
||||
CpuCounter::CacheMisses,
|
||||
CpuCounter::BranchInstructions,
|
||||
CpuCounter::BranchMisses};
|
||||
|
||||
CpuMeasurements measurements_{};
|
||||
CpuMeasurements prev_measurements_{};
|
||||
|
||||
std::unordered_map<CpuCounter, PmuCounter, CpuCounterHash> pmu_counters_{};
|
||||
};
|
||||
|
||||
} // namespace hwcpipe
|
||||
@@ -677,6 +677,9 @@
|
||||
<ProjectReference Include="driver\ihv\amd\AMD.vcxproj">
|
||||
<Project>{5de5a561-548a-4dd7-90f0-06a2b39eae9a}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="driver\ihv\arm\ARM.vcxproj">
|
||||
<Project>{F9CCE6CA-0CA3-4A22-9C7B-881369955E62}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="driver\ihv\intel\Intel.vcxproj">
|
||||
<Project>{7fcb5fc5-1dbd-4da6-83a0-6ba4e945bda5}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
Reference in New Issue
Block a user