diff --git a/public/client/TracySysPower.cpp b/public/client/TracySysPower.cpp index 1d4a3cdc..d26eab19 100644 --- a/public/client/TracySysPower.cpp +++ b/public/client/TracySysPower.cpp @@ -2,21 +2,130 @@ #ifdef TRACY_HAS_SYSPOWER +#include +#include +#include +#include +#include + +#include "TracyDebug.hpp" +#include "../common/TracyAlloc.hpp" + namespace tracy { SysPower::SysPower() + : m_domains( 4 ) { + ScanDirectory( "/sys/devices/virtual/powercap/intel-rapl", -1 ); } SysPower::~SysPower() { + for( auto& v : m_domains ) + { + fclose( v.handle ); + // Do not release v.name, as it may be still needed + } } void SysPower::Tick() { } +void SysPower::ScanDirectory( const char* path, int parent ) +{ + DIR* dir = opendir( path ); + if( !dir ) return; + struct dirent* ent; + uint64_t maxRange = 0; + char* name = nullptr; + FILE* handle = nullptr; + while( ( ent = readdir( dir ) ) ) + { + if( ent->d_type == DT_REG ) + { + if( strcmp( ent->d_name, "max_energy_range_uj" ) == 0 ) + { + char tmp[PATH_MAX]; + snprintf( tmp, PATH_MAX, "%s/max_energy_range_uj", path ); + FILE* f = fopen( tmp, "r" ); + if( f ) + { + fscanf( f, "%" PRIu64, &maxRange ); + fclose( f ); + } + } + else if( strcmp( ent->d_name, "name" ) == 0 ) + { + char tmp[PATH_MAX]; + snprintf( tmp, PATH_MAX, "%s/name", path ); + FILE* f = fopen( tmp, "r" ); + if( f ) + { + char ntmp[128]; + if( fgets( ntmp, 128, f ) ) + { + // Last character is newline, skip it + const auto sz = strlen( ntmp ) - 1; + if( parent < 0 ) + { + name = (char*)tracy_malloc( sz + 1 ); + memcpy( name, ntmp, sz ); + name[sz] = '\0'; + } + else + { + const auto p = m_domains[parent]; + const auto psz = strlen( p.name ); + name = (char*)tracy_malloc( psz + sz + 2 ); + memcpy( name, p.name, psz ); + name[psz] = ':'; + memcpy( name+psz+1, ntmp, sz ); + name[psz+sz+1] = '\0'; + } + } + fclose( f ); + } + } + else if( strcmp( ent->d_name, "energy_uj" ) == 0 ) + { + char tmp[PATH_MAX]; + snprintf( tmp, PATH_MAX, "%s/energy_uj", path ); + handle = fopen( tmp, "r" ); + } + } + if( name && handle && maxRange > 0 ) break; + } + if( name && handle && maxRange > 0 ) + { + parent = (int)m_domains.size(); + Domain* domain = m_domains.push_next(); + domain->value = 0; + domain->overflow = maxRange; + domain->handle = handle; + domain->name = name; + TracyDebug( "Power domain id %i, %s found at %s\n", parent, name, path ); + } + else + { + if( name ) tracy_free( name ); + if( handle ) fclose( handle ); + } + + rewinddir( dir ); + while( ( ent = readdir( dir ) ) ) + { + if( ent->d_type == DT_DIR && strncmp( ent->d_name, "intel-rapl:", 11 ) == 0 ) + { + char tmp[PATH_MAX]; + snprintf( tmp, PATH_MAX, "%s/%s", path, ent->d_name ); + ScanDirectory( tmp, parent ); + } + } + closedir( dir ); +} + } #endif diff --git a/public/client/TracySysPower.hpp b/public/client/TracySysPower.hpp index 90c42352..01fa75c9 100644 --- a/public/client/TracySysPower.hpp +++ b/public/client/TracySysPower.hpp @@ -7,16 +7,34 @@ #ifdef TRACY_HAS_SYSPOWER +#include +#include + +#include "TracyFastVector.hpp" + namespace tracy { class SysPower { + struct Domain + { + uint64_t value; + uint64_t overflow; + FILE* handle; + const char* name; + }; + public: SysPower(); ~SysPower(); void Tick(); + +private: + void ScanDirectory( const char* path, int parent ); + + FastVector m_domains; }; }