https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/127834
>From 0d6a36d84df50ccb9eef9ef3dd6f59d4299edeac Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Wed, 19 Feb 2025 12:47:57 -0500 Subject: [PATCH 1/2] [LLDB][Telemetry]Define TargetInfo for collecting data about a target --- lldb/include/lldb/Core/Telemetry.h | 86 +++++++++++++++++++++++++- lldb/source/Core/Telemetry.cpp | 99 ++++++++++++++++++++++++++---- 2 files changed, 170 insertions(+), 15 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index b72556ecaf3c9..4be81951254de 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -13,6 +13,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" @@ -29,6 +30,9 @@ namespace telemetry { struct LLDBEntryKind : public ::llvm::telemetry::EntryKind { static const llvm::telemetry::KindType BaseInfo = 0b11000; + static const KindType TargetInfo = 0b11010; + // There are other entries in between (added in separate PRs) + static const llvm::telemetry::KindType MiscInfo = 0b11110; }; /// Defines a convenient type for timestamp of various events. @@ -56,14 +60,88 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { void serialize(llvm::telemetry::Serializer &serializer) const override; }; +/// Describes an exit status. +struct ExitDescription { + int exit_code; + std::string description; +}; + +struct TargetTelemetryInfo : public LldbBaseTelemetryInfo { + lldb::ModuleSP exec_mod; + Target *target_ptr; + + // The same as the executable-module's UUID. + std::string target_uuid; + std::string file_format; + + std::string binary_path; + size_t binary_size; + + std::optional<ExitDescription> exit_desc; + TargetTelemetryInfo() = default; + + TargetTelemetryInfo(const TargetTelemetryInfo &other) { + exec_mod = other.exec_mod; + target_uuid = other.target_uuid; + file_format = other.file_format; + binary_path = other.binary_path; + binary_size = other.binary_size; + exit_desc = other.exit_desc; + } + + KindType getKind() const override { return LldbEntryKind::TargetInfo; } + + static bool classof(const TelemetryInfo *T) { + if (T == nullptr) + return false; + return T->getKind() == LldbEntryKind::TargetInfo; + } + + void serialize(Serializer &serializer) const override; +}; + +/// The "catch-all" entry to store a set of non-standard data, such as +/// error-messages, etc. +struct MiscTelemetryInfo : public LLDBBaseTelemetryInfo { + /// If the event is/can be associated with a target entry, + /// this field contains that target's UUID. + /// <EMPTY> otherwise. + std::string target_uuid; + + /// Set of key-value pairs for any optional (or impl-specific) data + std::map<std::string, std::string> meta_data; + + MiscTelemetryInfo() = default; + + MiscTelemetryInfo(const MiscTelemetryInfo &other) { + target_uuid = other.target_uuid; + meta_data = other.meta_data; + } + + llvm::telemetry::KindType getKind() const override { + return LLDBEntryKind::MiscInfo; + } + + static bool classof(const llvm::telemetry::TelemetryInfo *T) { + return T->getKind() == LLDBEntryKind::MiscInfo; + } + + void serialize(llvm::telemetry::Serializer &serializer) const override; +}; + /// The base Telemetry manager instance in LLDB. /// This class declares additional instrumentation points /// applicable to LLDB. -class TelemetryManager : public llvm::telemetry::Manager { +class TelemetryMager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; - virtual llvm::StringRef GetInstanceName() const = 0; + const llvm::telemetry::Config *getConfig(); + + virtual void AtMainExecutableLoadStart(TargetInfo * entry); + virtual void AtMainExecutableLoadEnd(TargetInfo *entry); + + virtual llvm::StringRef GetInstanceName() const = 0; static TelemetryManager *getInstance(); protected: @@ -73,6 +151,10 @@ class TelemetryManager : public llvm::telemetry::Manager { private: std::unique_ptr<llvm::telemetry::Config> m_config; + // Each debugger is assigned a unique ID (session_id). + // All TelemetryInfo entries emitted for the same debugger instance + // will get the same session_id. + llvm::DenseMap<Debugger *, std::string> session_ids; static std::unique_ptr<TelemetryManager> g_instance; }; diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 5222f76704f91..da7aee01680fc 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -10,14 +10,20 @@ #ifdef LLVM_BUILD_TELEMETRY -#include "lldb/Core/Telemetry.h" #include "lldb/Core/Debugger.h" +#include "lldb/Core/Telemetry.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Statistics.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/UUID.h" +#include "lldb/Version/Version.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Telemetry/Telemetry.h" #include <chrono> @@ -35,15 +41,7 @@ static uint64_t ToNanosec(const SteadyTimePoint Point) { return std::chrono::nanoseconds(Point.time_since_epoch()).count(); } -void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const { - serializer.write("entry_kind", getKind()); - serializer.write("session_id", SessionId); - serializer.write("start_time", ToNanosec(start_time)); - if (end_time.has_value()) - serializer.write("end_time", ToNanosec(end_time.value())); -} - -[[maybe_unused]] static std::string MakeUUID(Debugger *debugger) { +static std::string MakeUUID(Debugger *debugger) { uint8_t random_bytes[16]; if (auto ec = llvm::getRandomBytes(random_bytes, 16)) { LLDB_LOG(GetLog(LLDBLog::Object), @@ -56,16 +54,91 @@ void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const { return UUID(random_bytes).GetAsString(); } +void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const { + serializer.write("entry_kind", getKind()); + serializer.write("session_id", SessionId); + serializer.write("start_time", ToNanosec(start_time)); + if (end_time.has_value()) + serializer.write("end_time", ToNanosec(end_time.value())); +} + +void TargetInfo::serialize(Serializer &serializer) const { + LLDBBaseTelemetryInfo::serialize(serializer); + + serializer.write("username", username); + serializer.write("lldb_git_sha", lldb_git_sha); + serializer.write("lldb_path", lldb_path); + serializer.write("cwd", cwd); + if (exit_desc.has_value()) { + serializer.write("exit_code", exit_desc->exit_code); + serializer.write("exit_desc", exit_desc->description); + } +} + +void MiscTelemetryInfo::serialize(Serializer &serializer) const { + LLDBBaseTelemetryInfo::serialize(serializer); + serializer.write("target_uuid", target_uuid); + serializer.beginObject("meta_data"); + for (const auto &kv : meta_data) + serializer.write(kv.first, kv.second); + serializer.endObject(); +} + TelemetryManager::TelemetryManager(std::unique_ptr<Config> config) : m_config(std::move(config)) {} llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { - // Do nothing for now. - // In up-coming patch, this would be where the manager - // attach the session_uuid to the entry. + LLDBBaseTelemetryInfo *lldb_entry = + llvm::dyn_cast<LLDBBaseTelemetryInfo>(entry); + std::string session_id = ""; + if (Debugger *debugger = lldb_entry->debugger) { + auto session_id_pos = session_ids.find(debugger); + if (session_id_pos != session_ids.end()) + session_id = session_id_pos->second; + else + session_id_pos->second = session_id = MakeUUID(debugger); + } + lldb_entry->SessionId = session_id; + return llvm::Error::success(); } +const Config *getConfig() { return m_config.get(); } + +void TelemetryManager::AtMainExecutableLoadStart(TargetInfo *entry) { + UserIDResolver &resolver = lldb_private::HostInfo::GetUserIDResolver(); + std::optional<llvm::StringRef> opt_username = + resolver.GetUserName(lldb_private::HostInfo::GetUserID()); + if (opt_username) + entry->username = *opt_username; + + entry->lldb_git_sha = + lldb_private::GetVersion(); // TODO: find the real git sha? + + entry->lldb_path = HostInfo::GetProgramFileSpec().GetPath(); + + llvm::SmallString<64> cwd; + if (!llvm::sys::fs::current_path(cwd)) { + entry->cwd = cwd.c_str(); + } else { + MiscTelemetryInfo misc_info; + misc_info.meta_data["internal_errors"] = "Cannot determine CWD"; + if (auto er = dispatch(&misc_info)) { + LLDB_LOG(GetLog(LLDBLog::Object), + "Failed to dispatch misc-info at startup"); + } + } + + if (auto er = dispatch(entry)) { + LLDB_LOG(GetLog(LLDBLog::Object), "Failed to dispatch entry at startup"); + } +} + +void TelemetryManager::AtMainExecutableLoadEnd(TargetInfo *entry) { + // .... + dispatch(entry); +} + std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr; TelemetryManager *TelemetryManager::getInstance() { return g_instance.get(); } >From f152b3b35de9d7907d4812254f3e0bde4564e45a Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Mon, 24 Feb 2025 16:03:07 -0500 Subject: [PATCH 2/2] introduce helper --- lldb/include/lldb/Core/Telemetry.h | 115 +++++++++++++------------- lldb/source/Core/Telemetry.cpp | 75 +++++++---------- lldb/source/Target/Target.cpp | 16 ++++ lldb/unittests/Core/TelemetryTest.cpp | 6 +- 4 files changed, 110 insertions(+), 102 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 4be81951254de..29873d91538a0 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -24,17 +24,22 @@ #include <optional> #include <string> #include <unordered_map> +#include <type_traits> +#include <utility> +#include <functional> +#include <stack> namespace lldb_private { namespace telemetry { struct LLDBEntryKind : public ::llvm::telemetry::EntryKind { static const llvm::telemetry::KindType BaseInfo = 0b11000; - static const KindType TargetInfo = 0b11010; + static const llvm::telemetry::KindType TargetInfo = 0b11010; // There are other entries in between (added in separate PRs) static const llvm::telemetry::KindType MiscInfo = 0b11110; }; + /// Defines a convenient type for timestamp of various events. using SteadyTimePoint = std::chrono::time_point<std::chrono::steady_clock, std::chrono::nanoseconds>; @@ -66,64 +71,26 @@ struct ExitDescription { std::string description; }; -struct TargetTelemetryInfo : public LldbBaseTelemetryInfo { + +struct TargetInfo : public LLDBBaseTelemetryInfo { lldb::ModuleSP exec_mod; Target *target_ptr; // The same as the executable-module's UUID. std::string target_uuid; - std::string file_format; - - std::string binary_path; - size_t binary_size; + std::string executable_path; + size_t executable_size; + std::string arch_name; std::optional<ExitDescription> exit_desc; - TargetTelemetryInfo() = default; - - TargetTelemetryInfo(const TargetTelemetryInfo &other) { - exec_mod = other.exec_mod; - target_uuid = other.target_uuid; - file_format = other.file_format; - binary_path = other.binary_path; - binary_size = other.binary_size; - exit_desc = other.exit_desc; - } + TargetInfo() = default; - KindType getKind() const override { return LldbEntryKind::TargetInfo; } + llvm::telemetry::KindType getKind() const override { return LLDBEntryKind::TargetInfo; } static bool classof(const TelemetryInfo *T) { if (T == nullptr) return false; - return T->getKind() == LldbEntryKind::TargetInfo; - } - - void serialize(Serializer &serializer) const override; -}; - -/// The "catch-all" entry to store a set of non-standard data, such as -/// error-messages, etc. -struct MiscTelemetryInfo : public LLDBBaseTelemetryInfo { - /// If the event is/can be associated with a target entry, - /// this field contains that target's UUID. - /// <EMPTY> otherwise. - std::string target_uuid; - - /// Set of key-value pairs for any optional (or impl-specific) data - std::map<std::string, std::string> meta_data; - - MiscTelemetryInfo() = default; - - MiscTelemetryInfo(const MiscTelemetryInfo &other) { - target_uuid = other.target_uuid; - meta_data = other.meta_data; - } - - llvm::telemetry::KindType getKind() const override { - return LLDBEntryKind::MiscInfo; - } - - static bool classof(const llvm::telemetry::TelemetryInfo *T) { - return T->getKind() == LLDBEntryKind::MiscInfo; + return T->getKind() == LLDBEntryKind::TargetInfo; } void serialize(llvm::telemetry::Serializer &serializer) const override; @@ -132,32 +99,68 @@ struct MiscTelemetryInfo : public LLDBBaseTelemetryInfo { /// The base Telemetry manager instance in LLDB. /// This class declares additional instrumentation points /// applicable to LLDB. -class TelemetryMager : public llvm::telemetry::Manager { +class TelemetryManager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; - const llvm::telemetry::Config *getConfig(); + const llvm::telemetry::Config *GetConfig(); + /// The following methods are for reporting the load of an executable. + /// One is invoked at the beginning of the process and the other at + /// the end. + /// This is done in two passes to avoid losing date in case of any error/crash + /// during the action. + /// + /// Invoked at the begining of the load of the main-executable. virtual void AtMainExecutableLoadStart(TargetInfo * entry); + /// Invoked at the end of the load. virtual void AtMainExecutableLoadEnd(TargetInfo *entry); - virtual llvm::StringRef GetInstanceName() const = 0; - static TelemetryManager *getInstance(); + virtual llvm::StringRef GetInstanceName() const = 0; + + static TelemetryManager *GetInstance(); protected: TelemetryManager(std::unique_ptr<llvm::telemetry::Config> config); - static void setInstance(std::unique_ptr<TelemetryManager> manger); + static void SetInstance(std::unique_ptr<TelemetryManager> manger); private: std::unique_ptr<llvm::telemetry::Config> m_config; - // Each debugger is assigned a unique ID (session_id). - // All TelemetryInfo entries emitted for the same debugger instance - // will get the same session_id. - llvm::DenseMap<Debugger *, std::string> session_ids; + static std::unique_ptr<TelemetryManager> g_instance; }; +class Helper { + public: + Helper () : m_start(std::chrono::steady_clock::now()) {} + ~Helper() { + while(! m_exit_funcs.empty()) { + (m_exit_funcs.top())(); + m_exit_funcs.pop(); + } + } + + bool TelemetryEnabled() { + TelemetryManager* instance = TelemetryManager::GetInstance(); + return instance != nullptr && instance->GetConfig()->EnableTelemetry; + } + + + SteadyTimePoint GetStartTime() {return m_start;} + SteadyTimePoint GetCurrentTime() { return std::chrono::steady_clock::now(); } + + template <typename Fp> + void RunAtScopeExit(Fp&& F){ + m_exit_funcs.push(std::forward<Fp>(F)); + } + + private: + const SteadyTimePoint m_start; + std::stack<std::function<void()>> m_exit_funcs; + +}; + } // namespace telemetry } // namespace lldb_private #endif // LLDB_CORE_TELEMETRY_H diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index da7aee01680fc..4e7f9b71c9131 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -65,10 +65,10 @@ void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const { void TargetInfo::serialize(Serializer &serializer) const { LLDBBaseTelemetryInfo::serialize(serializer); - serializer.write("username", username); - serializer.write("lldb_git_sha", lldb_git_sha); - serializer.write("lldb_path", lldb_path); - serializer.write("cwd", cwd); + serializer.write("target_uuid", target_uuid); + serializer.write("executable_path", executable_path); + serializer.write("executable_size", executable_size); + serializer.write("arch_name", arch_name); if (exit_desc.has_value()) { serializer.write("exit_code", exit_desc->exit_code); serializer.write("exit_desc", exit_desc->description); @@ -88,61 +88,50 @@ TelemetryManager::TelemetryManager(std::unique_ptr<Config> config) : m_config(std::move(config)) {} llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { - LLDBBaseTelemetryInfo *lldb_entry = - llvm::dyn_cast<LLDBBaseTelemetryInfo>(entry); - std::string session_id = ""; - if (Debugger *debugger = lldb_entry->debugger) { - auto session_id_pos = session_ids.find(debugger); - if (session_id_pos != session_ids.end()) - session_id = session_id_pos->second; - else - session_id_pos->second = session_id = MakeUUID(debugger); - } - lldb_entry->SessionId = session_id; - + // Do nothing for now. + // In up-coming patch, this would be where the manager + // attach the session_uuid to the entry. return llvm::Error::success(); } -const Config *getConfig() { return m_config.get(); } +const Config * TelemetryManager::GetConfig() { return m_config.get(); } + void TelemetryManager::AtMainExecutableLoadStart(TargetInfo *entry) { - UserIDResolver &resolver = lldb_private::HostInfo::GetUserIDResolver(); - std::optional<llvm::StringRef> opt_username = - resolver.GetUserName(lldb_private::HostInfo::GetUserID()); - if (opt_username) - entry->username = *opt_username; - - entry->lldb_git_sha = - lldb_private::GetVersion(); // TODO: find the real git sha? - - entry->lldb_path = HostInfo::GetProgramFileSpec().GetPath(); - - llvm::SmallString<64> cwd; - if (!llvm::sys::fs::current_path(cwd)) { - entry->cwd = cwd.c_str(); - } else { - MiscTelemetryInfo misc_info; - misc_info.meta_data["internal_errors"] = "Cannot determine CWD"; - if (auto er = dispatch(&misc_info)) { - LLDB_LOG(GetLog(LLDBLog::Object), - "Failed to dispatch misc-info at startup"); + if (entry->exec_mod != nullptr) { + entry->target_uuid = entry->exec_mod->GetUUID().GetAsString(); + entry->executalbe_path = entry->exec_mod->GetFileSpec().GetPathAsConstString().GetCString(); + if (auto err = llvm::sys::fs::file_size( + entry->exec_mod->GetFileSpec().GetPath(), entry->binary_size)) { + // If there was error obtaining it, just reset the size to 0. + // Maybe log the error too? + entry->binary_size = 0; } + entry->arch_name = entry->exec_mod->GetArchitecture().GetArchitectureName(); } - if (auto er = dispatch(entry)) { - LLDB_LOG(GetLog(LLDBLog::Object), "Failed to dispatch entry at startup"); + if (llvm::Error er = dispatch(entry)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), + "Failed to dispatch entry at main executable load start: {0}"); } } void TelemetryManager::AtMainExecutableLoadEnd(TargetInfo *entry) { - // .... - dispatch(entry); + if (entry->exec_mod != nullptr) { + entry->target_uuid = entry->exec_mod->GetUUID().GetAsString(); + // We don't need the rest of the data since they are already in the start entry. + + if (llvm::Error er = dispatch(entry)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), + "Failed to dispatch entry at main executable load start: {0}"); + } + } } std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr; -TelemetryManager *TelemetryManager::getInstance() { return g_instance.get(); } +TelemetryManager *TelemetryManager::GetInstance() { return g_instance.get(); } -void TelemetryManager::setInstance(std::unique_ptr<TelemetryManager> manager) { +void TelemetryManager::SetInstance(std::unique_ptr<TelemetryManager> manager) { g_instance = std::move(manager); } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index db289fe9c4b64..7ea76694f94d8 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -20,6 +20,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Telemetry.h" #include "lldb/Core/SearchFilter.h" #include "lldb/Core/Section.h" #include "lldb/Core/SourceManager.h" @@ -1558,10 +1559,25 @@ void Target::DidExec() { void Target::SetExecutableModule(ModuleSP &executable_sp, LoadDependentFiles load_dependent_files) { + telemetry::Helper helper; Log *log = GetLog(LLDBLog::Target); ClearModules(false); if (executable_sp) { + if (helper.TelemetryEnabled()) { + telemetry::TargetInfo start_entry; + start_entry.start_time = helper.GetStartTime(); + start_entry.exec_mod = executable_sp; + telemetry::TelemetryManager::GetInstance()->AtMainExecutableLoadStart(&start_entry); + + helper.RunAtScopeExit([&]() { + telemetry::TargetInfo end_entry; + end_entry.start_time = helper.GetStartTime(); + end_entry.end_time = helper.GetCurrentTime(); + end_entry.exec_mod = executable_sp; + telemetry::TelemetryManager::GetInstance()->AtMainExecutableLoadEnd(&end_entry); + }); + } ElapsedTime elapsed(m_stats.GetCreateTime()); LLDB_SCOPED_TIMERF("Target::SetExecutableModule (executable = '%s')", executable_sp->GetFileSpec().GetPath().c_str()); diff --git a/lldb/unittests/Core/TelemetryTest.cpp b/lldb/unittests/Core/TelemetryTest.cpp index 0f2eaccb21a2c..3ee6451429619 100644 --- a/lldb/unittests/Core/TelemetryTest.cpp +++ b/lldb/unittests/Core/TelemetryTest.cpp @@ -63,10 +63,10 @@ class FakePlugin : public telemetry::TelemetryManager { } static void Initialize() { - telemetry::TelemetryManager::setInstance(std::make_unique<FakePlugin>()); + telemetry::TelemetryManager::SetInstance(std::make_unique<FakePlugin>()); } - static void Terminate() { telemetry::TelemetryManager::setInstance(nullptr); } + static void Terminate() { telemetry::TelemetryManager::SetInstance(nullptr); } }; } // namespace lldb_private @@ -76,7 +76,7 @@ TEST(TelemetryTest, PluginTest) { // For tests, we just call it directly. lldb_private::FakePlugin::Initialize(); - auto *ins = lldb_private::telemetry::TelemetryManager::getInstance(); + auto *ins = lldb_private::telemetry::TelemetryManager::GetInstance(); ASSERT_NE(ins, nullptr); std::vector<const ::llvm::telemetry::TelemetryInfo *> expected_entries; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits