diff --git a/src/amd_detail/configuration.cpp b/src/amd_detail/configuration.cpp index 79f2b82f..3c410547 100644 --- a/src/amd_detail/configuration.cpp +++ b/src/amd_detail/configuration.cpp @@ -11,7 +11,7 @@ using namespace hipFile; -Configuration::Configuration() : m_fastpath(true), m_fallback(true) +Configuration::Configuration() : m_fastpath(true), m_fallback(true), m_statsLevel(0) { auto maybe_env_force_compat{Environment::force_compat_mode()}; if (maybe_env_force_compat && maybe_env_force_compat.value()) { @@ -24,6 +24,11 @@ Configuration::Configuration() : m_fastpath(true), m_fallback(true) if (maybe_env_allow_compat && !maybe_env_allow_compat.value()) { m_fallback = false; } + + auto maybe_stats_level{Environment::stats_level()}; + if (maybe_stats_level) { + m_statsLevel = maybe_stats_level.value(); + } } bool @@ -37,3 +42,9 @@ Configuration::fallback() const noexcept { return m_fallback; } + +int +Configuration::statsLevel() const noexcept +{ + return m_statsLevel; +} diff --git a/src/amd_detail/configuration.h b/src/amd_detail/configuration.h index edd17776..93c6ded2 100644 --- a/src/amd_detail/configuration.h +++ b/src/amd_detail/configuration.h @@ -20,17 +20,23 @@ class IConfiguration { /// @brief Checks if the fallback backend is enabled /// @return true if the fallback backend is enabled, false otherwise virtual bool fallback() const noexcept = 0; + + /// @brief Shows the level of detail for stats collection + /// @return 0 if stats collection disabled, higher levels of detail as value increases + virtual int statsLevel() const noexcept = 0; }; class Configuration : public IConfiguration { bool m_fastpath; bool m_fallback; + int m_statsLevel; public: Configuration(); bool fastpath() const noexcept override; bool fallback() const noexcept override; + int statsLevel() const noexcept override; }; } diff --git a/src/amd_detail/environment.cpp b/src/amd_detail/environment.cpp index 7305d83a..98db246d 100644 --- a/src/amd_detail/environment.cpp +++ b/src/amd_detail/environment.cpp @@ -28,6 +28,27 @@ Environment::get(const char *key) return std::nullopt; } +template <> +std::optional +Environment::get(const char *key) +{ + const char *value{Context::get()->getenv(key)}; + if (value == nullptr) + return std::nullopt; + errno = 0; + char *end; + int x{static_cast(std::strtol(value, &end, 10))}; + if (errno != 0) + return std::nullopt; + if (end == nullptr) + return std::nullopt; + if (end == value) + return std::nullopt; + if (*end != '\0') + return std::nullopt; + return x; +} + optional Environment::allow_compat_mode() { @@ -39,3 +60,9 @@ Environment::force_compat_mode() { return Environment::get(Environment::FORCE_COMPAT_MODE); } + +optional +Environment::stats_level() +{ + return Environment::get(Environment::STATS_LEVEL); +} diff --git a/src/amd_detail/environment.h b/src/amd_detail/environment.h index 2f841d10..a01102fa 100644 --- a/src/amd_detail/environment.h +++ b/src/amd_detail/environment.h @@ -39,6 +39,14 @@ class Environment { static constexpr const char *const FORCE_COMPAT_MODE{"HIPFILE_FORCE_COMPAT_MODE"}; static std::optional force_compat_mode(); + + /// @brief Control how much information is collected to be reported to ais-stats + /// + /// 0 indicates no stats should be recorded. + /// >= 1 indicates basic stats will be collected. + static constexpr const char *const STATS_LEVEL{"HIPFILE_STATS_LEVEL"}; + + static std::optional stats_level(); }; } diff --git a/test/amd_detail/configuration.cpp b/test/amd_detail/configuration.cpp index f75d6dd3..37524b44 100644 --- a/test/amd_detail/configuration.cpp +++ b/test/amd_detail/configuration.cpp @@ -27,6 +27,7 @@ struct ConfigurationExpectationBuilder { StrictMock &m_mhip; std::optional m_env_force_compat_mode; std::optional m_env_allow_compat_mode; + std::optional m_env_stats_level; void *m_hip_amd_file_read{reinterpret_cast(0xDEADBEEF)}; void *m_hip_amd_file_write{reinterpret_cast(0x0BADF00D)}; @@ -47,6 +48,12 @@ struct ConfigurationExpectationBuilder { return *this; } + ConfigurationExpectationBuilder &env_stats_level(const char *value) + { + m_env_stats_level = value; + return *this; + } + ConfigurationExpectationBuilder &hip_amd_file_read(void *value) { m_hip_amd_file_read = value; @@ -81,6 +88,14 @@ struct ConfigurationExpectation { EXPECT_CALL(builder.m_msys, getenv(StrEq(hipFile::Environment::ALLOW_COMPAT_MODE))); } + if (builder.m_env_stats_level) { + EXPECT_CALL(builder.m_msys, getenv(StrEq(hipFile::Environment::STATS_LEVEL))) + .WillOnce(Return(const_cast(builder.m_env_stats_level.value()))); + } + else { + EXPECT_CALL(builder.m_msys, getenv(StrEq(hipFile::Environment::STATS_LEVEL))); + } + EXPECT_CALL(builder.m_mhip, hipRuntimeGetVersion).Times(2); EXPECT_CALL(builder.m_mhip, hipGetProcAddress(StrEq("hipAmdFileRead"), _, _, _)) .WillOnce(Return(builder.m_hip_amd_file_read)); @@ -148,4 +163,16 @@ TEST_F(HipFileConfiguration, FallbackDisabledIfAllowCompatModeEnvironmentVariabl ASSERT_FALSE(Configuration().fallback()); } +TEST_F(HipFileConfiguration, StatsLevelEnvironmentVariableIsNotSetOrInvalid) +{ + ConfigurationExpectationBuilder{msys, mhip}.build(); + ASSERT_EQ(0, Configuration().statsLevel()); +} + +TEST_F(HipFileConfiguration, StatsLevelEnvironmentVariableIsSet) +{ + ConfigurationExpectationBuilder{msys, mhip}.env_stats_level("1").build(); + ASSERT_EQ(1, Configuration().statsLevel()); +} + HIPFILE_WARN_NO_GLOBAL_CTOR_ON diff --git a/test/amd_detail/environment.cpp b/test/amd_detail/environment.cpp index a7ecfe75..3b0f2f97 100644 --- a/test/amd_detail/environment.cpp +++ b/test/amd_detail/environment.cpp @@ -63,4 +63,32 @@ TEST(HipFileEnvironment, GetBoolReturnsOptionalFalseIfFalse) ASSERT_EQ(hipFile::Environment::get(""), make_optional<>(false)); } +TEST(HipFileEnvironment, GetIntReturnsNulloptIfNotSet) +{ + StrictMock msys; + + EXPECT_CALL(msys, getenv).WillOnce(Return(nullptr)); + ASSERT_EQ(hipFile::Environment::get(""), nullopt); +} + +TEST(HipFileEnvironment, GetIntReturnsNulloptIfValueIsInvalid) +{ + StrictMock msys; + + EXPECT_CALL(msys, getenv).WillOnce(Return(const_cast("blah"))); + ASSERT_EQ(hipFile::Environment::get(""), nullopt); + EXPECT_CALL(msys, getenv).WillOnce(Return(const_cast(""))); + ASSERT_EQ(hipFile::Environment::get(""), nullopt); + EXPECT_CALL(msys, getenv).WillOnce(Return(const_cast("1abc"))); + ASSERT_EQ(hipFile::Environment::get(""), nullopt); +} + +TEST(HipFileEnvironment, GetIntReturnsIntIfValueIsInt) +{ + StrictMock msys; + + EXPECT_CALL(msys, getenv).WillOnce(Return(const_cast("0"))); + ASSERT_EQ(hipFile::Environment::get(""), make_optional<>(0)); +} + HIPFILE_WARN_NO_GLOBAL_CTOR_ON