diff --git a/libkineto/libkineto_defs.bzl b/libkineto/libkineto_defs.bzl index e0f5bf972..a9924b727 100644 --- a/libkineto/libkineto_defs.bzl +++ b/libkineto/libkineto_defs.bzl @@ -38,6 +38,7 @@ def get_libkineto_xpupti_srcs(with_api = True): "src/plugin/xpupti/XpuptiActivityApi.cpp", "src/plugin/xpupti/XpuptiActivityProfiler.cpp", "src/plugin/xpupti/XpuptiActivityHandlers.cpp", + "src/plugin/xpupti/XpuptiScopeProfilerConfig.cpp", ] + (get_libkineto_cpu_only_srcs(with_api)) def get_libkineto_aiupti_srcs(with_api = True): diff --git a/libkineto/src/init.cpp b/libkineto/src/init.cpp index 79b1f0625..2c14b99bd 100644 --- a/libkineto/src/init.cpp +++ b/libkineto/src/init.cpp @@ -26,6 +26,7 @@ #ifdef HAS_XPUPTI #include "plugin/xpupti/XpuptiActivityApi.h" #include "plugin/xpupti/XpuptiActivityProfiler.h" +#include "plugin/xpupti/XpuptiScopeProfilerConfig.h" #endif #ifdef HAS_AIUPTI #include "plugin/aiupti/AiuptiActivityApi.h" @@ -193,6 +194,8 @@ void libkineto_init(bool cpuOnly, bool logOnError) { throw std::runtime_error(errPrefixMsg); #endif } + + XpuptiScopeProfilerConfig::registerFactory(); return std::make_unique(); }); #endif // HAS_XPUPTI diff --git a/libkineto/src/plugin/xpupti/XpuptiScopeProfilerConfig.cpp b/libkineto/src/plugin/xpupti/XpuptiScopeProfilerConfig.cpp new file mode 100644 index 000000000..117d7e1ac --- /dev/null +++ b/libkineto/src/plugin/xpupti/XpuptiScopeProfilerConfig.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "XpuptiScopeProfilerConfig.h" + +#include + +#include +#include +#include + +namespace KINETO_NAMESPACE { + +// number of scopes affect the size of counter data binary used by +// the XPUPTI Profiler. these defaults can be tuned +constexpr int KMaxAutoScopes = 1500; // supports 1500 kernels +constexpr int KMaxUserScopes = 10; // enable upto 10 sub regions marked by user + +bool XpuptiScopeProfilerConfig::handleOption( + const std::string& name, + std::string& val) { + VLOG(0) << " handling : " << name << " = " << val; + // Xpupti Scope based Profiler configuration + using namespace std::literals::string_view_literals; + if (name == "XPUPTI_PROFILER_METRICS"sv) { + activitiesXpuptiMetrics_ = splitAndTrim(val, ','); + } else if (name == "XPUPTI_PROFILER_ENABLE_PER_KERNEL"sv) { + xpuptiProfilerPerKernel_ = toBool(val); + } else if (name == "XPUPTI_PROFILER_MAX_SCOPES"sv) { + xpuptiProfilerMaxScopes_ = toInt64(val); + } else { + return false; + } + return true; +} + +void XpuptiScopeProfilerConfig::setDefaults() { + if (activitiesXpuptiMetrics_.size() > 0 && xpuptiProfilerMaxScopes_ == 0) { + xpuptiProfilerMaxScopes_ = + xpuptiProfilerPerKernel_ ? KMaxAutoScopes : KMaxUserScopes; + } +} + +void XpuptiScopeProfilerConfig::printActivityProfilerConfig( + std::ostream& s) const { + if (activitiesXpuptiMetrics_.size() > 0) { + fmt::print( + s, + "Xpupti Profiler metrics : {}\n" + "Xpupti Profiler measure per kernel : {}\n" + "Xpupti Profiler max scopes : {}\n", + fmt::join(activitiesXpuptiMetrics_, ", "), + xpuptiProfilerPerKernel_, + xpuptiProfilerMaxScopes_); + } +} + +void XpuptiScopeProfilerConfig::registerFactory() { + Config::addConfigFactory(kXpuptiProfilerConfigName, [](Config& cfg) { + return new XpuptiScopeProfilerConfig(cfg); + }); +} + +} // namespace KINETO_NAMESPACE diff --git a/libkineto/src/plugin/xpupti/XpuptiScopeProfilerConfig.h b/libkineto/src/plugin/xpupti/XpuptiScopeProfilerConfig.h new file mode 100644 index 000000000..1344bcf38 --- /dev/null +++ b/libkineto/src/plugin/xpupti/XpuptiScopeProfilerConfig.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include "Config.h" + +#include +#include + +namespace KINETO_NAMESPACE { + +constexpr char kXpuptiProfilerConfigName[] = "xpupti_scope_profiler"; + +class XpuptiScopeProfilerConfig : public AbstractConfig { + public: + bool handleOption(const std::string& name, std::string& val) override; + + void validate( + const std::chrono::time_point& + fallbackProfileStartTime) override {} + + static XpuptiScopeProfilerConfig& get(const Config& cfg) { + return dynamic_cast( + cfg.feature(kXpuptiProfilerConfigName)); + } + + Config& parent() const { + return *parent_; + } + + std::vector activitiesXpuptiMetrics() const { + return activitiesXpuptiMetrics_; + } + + bool xpuptiProfilerPerKernel() const { + return xpuptiProfilerPerKernel_; + } + + int64_t xpuptiProfilerMaxScopes() const { + return xpuptiProfilerMaxScopes_; + } + + void setSignalDefaults() override { + setDefaults(); + } + + void setClientDefaults() override { + setDefaults(); + } + + void printActivityProfilerConfig(std::ostream& s) const override; + void setActivityDependentConfig() override {} + static void registerFactory(); + + protected: + AbstractConfig* cloneDerived(AbstractConfig& parent) const override { + XpuptiScopeProfilerConfig* clone = new XpuptiScopeProfilerConfig(*this); + clone->parent_ = dynamic_cast(&parent); + return clone; + } + + private: + XpuptiScopeProfilerConfig() = delete; + explicit XpuptiScopeProfilerConfig(Config& parent) : parent_(&parent) {} + explicit XpuptiScopeProfilerConfig(const XpuptiScopeProfilerConfig& other) = + default; + + // some defaults will depend on other configuration + void setDefaults(); + + // Associated Config object + Config* parent_; + + // Counter metrics exposed via XPUPTI Profiler API + std::vector activitiesXpuptiMetrics_; + + // Collect profiler metrics per kernel - autoscope made + bool xpuptiProfilerPerKernel_{false}; + + // max number of scopes to configure the profiler for. + // this has to be set before hand to reserve space for the output + int64_t xpuptiProfilerMaxScopes_ = 0; +}; + +} // namespace KINETO_NAMESPACE diff --git a/libkineto/test/CMakeLists.txt b/libkineto/test/CMakeLists.txt index fe15a4a70..81184b0ec 100644 --- a/libkineto/test/CMakeLists.txt +++ b/libkineto/test/CMakeLists.txt @@ -19,6 +19,7 @@ endif() if(DEFINED LIBKINETO_NOXPUPTI AND NOT LIBKINETO_NOXPUPTI) set(XPU_XPUPTI_LIBRARY ${PTI_LIBRARY} ${SYCL_LIBRARY}) + add_subdirectory(xpupti) else() set(XPU_XPUPTI_LIBRARY "") endif() diff --git a/libkineto/test/xpupti/CMakeLists.txt b/libkineto/test/xpupti/CMakeLists.txt new file mode 100644 index 000000000..0c833b8c0 --- /dev/null +++ b/libkineto/test/xpupti/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set(CMAKE_CXX_STANDARD 17) + +set(LINK_LIBRARIES + gtest_main + kineto_base + kineto_api + $ + ${SYCL_LIBRARY} + ${PTI_LIBRARY} +) + +add_executable(XpuptiScopeProfilerConfigTest XpuptiScopeProfilerConfigTest.cpp) +target_link_libraries(XpuptiScopeProfilerConfigTest PRIVATE ${LINK_LIBRARIES}) +gtest_discover_tests(XpuptiScopeProfilerConfigTest) diff --git a/libkineto/test/xpupti/XpuptiScopeProfilerConfigTest.cpp b/libkineto/test/xpupti/XpuptiScopeProfilerConfigTest.cpp new file mode 100644 index 000000000..b16d5fbfc --- /dev/null +++ b/libkineto/test/xpupti/XpuptiScopeProfilerConfigTest.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "src/plugin/xpupti/XpuptiScopeProfilerConfig.h" +#include "include/Config.h" + +#include +#include + +#include + +namespace KN = KINETO_NAMESPACE; + +class XpuptiScopeProfilerConfigTest : public ::testing::Test { + protected: + void SetUp() override { + KN::XpuptiScopeProfilerConfig::registerFactory(); + } +}; + +TEST_F(XpuptiScopeProfilerConfigTest, ConfigureProfiler) { + KN::Config cfg; + std::vector metrics = { + "metric1", + "metric2", + "metric3", + }; + auto metricsConfigStr = + fmt::format("XPUPTI_PROFILER_METRICS = {}", fmt::join(metrics, ",")); + + EXPECT_TRUE(cfg.parse(metricsConfigStr)); + EXPECT_TRUE(cfg.parse("XPUPTI_PROFILER_ENABLE_PER_KERNEL = true")); + EXPECT_TRUE(cfg.parse("XPUPTI_PROFILER_MAX_SCOPES = 314159")); + + const KN::XpuptiScopeProfilerConfig& xpupti_cfg = + KN::XpuptiScopeProfilerConfig::get(cfg); + + EXPECT_EQ(xpupti_cfg.activitiesXpuptiMetrics(), metrics); + EXPECT_EQ(xpupti_cfg.xpuptiProfilerPerKernel(), true); + EXPECT_EQ(xpupti_cfg.xpuptiProfilerMaxScopes(), 314159); +} + +TEST_F(XpuptiScopeProfilerConfigTest, ScopesDefaults) { + KN::Config cfg, cfg_auto; + + // do not set max scopes in config, check defaults are sane + EXPECT_TRUE(cfg.parse("XPUPTI_PROFILER_METRICS = metric1")); + EXPECT_TRUE(cfg.parse("XPUPTI_PROFILER_ENABLE_PER_KERNEL = false")); + + cfg.setSignalDefaults(); + + EXPECT_TRUE(cfg_auto.parse("XPUPTI_PROFILER_METRICS = metric2")); + EXPECT_TRUE(cfg_auto.parse("XPUPTI_PROFILER_ENABLE_PER_KERNEL = true")); + + cfg_auto.setClientDefaults(); + + int user_scopes, auto_scopes; + + user_scopes = + KN::XpuptiScopeProfilerConfig::get(cfg).xpuptiProfilerMaxScopes(); + auto_scopes = + KN::XpuptiScopeProfilerConfig::get(cfg_auto).xpuptiProfilerMaxScopes(); + + EXPECT_EQ(user_scopes, 10); + EXPECT_EQ(auto_scopes, 1500); +}