https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/127696
>From 24e9f78744f98ecf3ac01f1f719f1eac9b3479f0 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Tue, 18 Feb 2025 15:58:08 -0500 Subject: [PATCH 01/25] [LLDB][Telemetry]Define DebuggerTelemetryInfo and related methods - This type of entry is used to collect data about the debugger startup/exit - Tests will be added (They may need to be shell test with a "test-only" TelemetryManager plugin defined. I'm trying to figure out how to get that linked only when tests are running and not to the LLDB binary all the time. --- lldb/include/lldb/Core/Telemetry.h | 78 +++++++++++++++++++ lldb/source/Core/Debugger.cpp | 40 ++++++++++ lldb/source/Core/Telemetry.cpp | 115 +++++++++++++++++++++++++---- 3 files changed, 220 insertions(+), 13 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index b72556ecaf3c9..d6eec5dc687be 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 llvm::telemetry::KindType DebuggerInfo = 0b11001; + // 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,6 +60,71 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { void serialize(llvm::telemetry::Serializer &serializer) const override; }; +/// Describes the exit status of a debugger. +struct ExitDescription { + int exit_code; + std::string description; +}; + +struct DebuggerTelemetryInfo : public LLDBBaseTelemetryInfo { + std::string username; + std::string lldb_git_sha; + std::string lldb_path; + std::string cwd; + std::optional<ExitDescription> exit_desc; + + DebuggerTelemetryInfo() = default; + + // Provide a copy ctor because we may need to make a copy before + // sanitizing the data. + // (The sanitization might differ between different Destination classes). + DebuggerTelemetryInfo(const DebuggerTelemetryInfo &other) { + username = other.username; + lldb_git_sha = other.lldb_git_sha; + lldb_path = other.lldb_path; + cwd = other.cwd; + }; + + llvm::telemetry::KindType getKind() const override { + return LLDBEntryKind::DebuggerInfo; + } + + static bool classof(const llvm::telemetry::TelemetryInfo *T) { + return T->getKind() == LLDBEntryKind::DebuggerInfo; + } + + void serialize(llvm::telemetry::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. @@ -63,6 +132,11 @@ class TelemetryManager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; + const llvm::telemetry::Config *getConfig(); + + void atDebuggerStartup(DebuggerTelemetryInfo *entry); + void atDebuggerExit(DebuggerTelemetryInfo *entry); + virtual llvm::StringRef GetInstanceName() const = 0; static TelemetryManager *getInstance(); @@ -73,6 +147,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/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 18569e155b517..b458abc798a9e 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -62,6 +62,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Process.h" @@ -69,6 +70,11 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" +#ifdef LLVM_BUILD_TELEMETRY +#include "lldb/Core/Telemetry.h" +#include <chrono> +#endif + #include <cstdio> #include <cstdlib> #include <cstring> @@ -761,12 +767,29 @@ void Debugger::InstanceInitialize() { DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, void *baton) { +#ifdef LLVM_BUILD_TELEMETRY + lldb_private::telemetry::SteadyTimePoint start_time = + std::chrono::steady_clock::now(); +#endif DebuggerSP debugger_sp(new Debugger(log_callback, baton)); if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); g_debugger_list_ptr->push_back(debugger_sp); } debugger_sp->InstanceInitialize(); + +#ifdef LLVM_BUILD_TELEMETRY + if (auto *telemetry_manager = telemetry::TelemetryManager::getInstance()) { + if (telemetry_manager->getConfig()->EnableTelemetry) { + lldb_private::telemetry::DebuggerTelemetryInfo entry; + entry.start_time = start_time; + entry.end_time = std::chrono::steady_clock::now(); + entry.debugger = debugger_sp.get(); + telemetry_manager->atDebuggerStartup(&entry); + } + } +#endif + return debugger_sp; } @@ -985,6 +1008,10 @@ void Debugger::Clear() { // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp); // static void Debugger::Terminate(); llvm::call_once(m_clear_once, [this]() { +#ifdef LLVM_BUILD_TELEMETRY + lldb_private::telemetry::SteadyTimePoint quit_start_time = + std::chrono::steady_clock::now(); +#endif ClearIOHandlers(); StopIOHandlerThread(); StopEventHandlerThread(); @@ -1007,6 +1034,19 @@ void Debugger::Clear() { if (Diagnostics::Enabled()) Diagnostics::Instance().RemoveCallback(m_diagnostics_callback_id); + +#ifdef LLVM_BUILD_TELEMETRY + if (auto telemetry_manager = telemetry::TelemetryManager::getInstance()) { + if (telemetry_manager->getConfig()->EnableTelemetry) { + // TBD: We *may* have to send off the log BEFORE the ClearIOHanders()? + lldb_private::telemetry::DebuggerTelemetryInfo entry; + entry.start_time = quit_start_time; + entry.end_time = std::chrono::steady_clock::now(); + entry.debugger = this; + telemetry_manager->atDebuggerExit(&entry); + } + } +#endif }); } diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 5222f76704f91..ab7d8ae0b44df 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,107 @@ 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 DebuggerTelemetryInfo::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::atDebuggerStartup(DebuggerTelemetryInfo *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::atDebuggerExit(DebuggerTelemetryInfo *entry) { + // There must be a reference to the debugger at this point. + assert(entry->debugger != nullptr); + + if (auto *selected_target = + entry->debugger->GetSelectedExecutionContext().GetTargetPtr()) { + if (!selected_target->IsDummyTarget()) { + const lldb::ProcessSP proc = selected_target->GetProcessSP(); + if (proc == nullptr) { + // no process has been launched yet. + entry->exit_desc = {-1, "no process launched."}; + } else { + entry->exit_desc = {proc->GetExitStatus(), ""}; + if (const char *description = proc->GetExitDescription()) + entry->exit_desc->description = std::string(description); + } + } + } + dispatch(entry); +} + std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr; TelemetryManager *TelemetryManager::getInstance() { return g_instance.get(); } >From 496c370bffd3a518eda4f8d34aabad13356831b3 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Tue, 18 Feb 2025 20:51:23 -0500 Subject: [PATCH 02/25] Update lldb/include/lldb/Core/Telemetry.h Co-authored-by: Jonas Devlieghere <jo...@devlieghere.com> --- lldb/include/lldb/Core/Telemetry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index d6eec5dc687be..9d34bf205c607 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -105,7 +105,7 @@ struct MiscTelemetryInfo : public LLDBBaseTelemetryInfo { std::string target_uuid; /// Set of key-value pairs for any optional (or impl-specific) data - std::map<std::string, std::string> meta_data; + llvm::StringMap<std::string> meta_data; MiscTelemetryInfo() = default; >From 11efc09e1ab9ffcca8e965906530af995f5c8c83 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Wed, 19 Feb 2025 14:23:00 -0500 Subject: [PATCH 03/25] Update lldb/source/Core/Telemetry.cpp Co-authored-by: Pavel Labath <pa...@labath.sk> --- lldb/source/Core/Telemetry.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index ab7d8ae0b44df..2e86d793c5ab3 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -123,9 +123,9 @@ void TelemetryManager::atDebuggerStartup(DebuggerTelemetryInfo *entry) { } 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 (llvm::Error er = dispatch(&misc_info)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), + "Failed to dispatch misc-info at startup: {0}"); } } >From 5aec2845cee08ada1a5ca7da7ff901ea9a1017d8 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 20 Feb 2025 15:51:06 -0500 Subject: [PATCH 04/25] adddressed review comments: - remove collection of username,cwd,lldb_path (that can be collected in vendor-specific impl) - use DebuggerID as key rather than the debugger pointer - renaming --- lldb/include/lldb/Core/Telemetry.h | 32 ++++++-------- lldb/source/Core/Telemetry.cpp | 67 ++++++++++++++---------------- 2 files changed, 44 insertions(+), 55 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 9d34bf205c607..1fb2c5b6b7eeb 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -66,24 +66,15 @@ struct ExitDescription { std::string description; }; -struct DebuggerTelemetryInfo : public LLDBBaseTelemetryInfo { - std::string username; - std::string lldb_git_sha; - std::string lldb_path; - std::string cwd; +struct DebuggerInfo : public LLDBBaseTelemetryInfo { + std::string lldb_version; std::optional<ExitDescription> exit_desc; - DebuggerTelemetryInfo() = default; + std::string lldb_path; + std::string cwd; + std::string username; - // Provide a copy ctor because we may need to make a copy before - // sanitizing the data. - // (The sanitization might differ between different Destination classes). - DebuggerTelemetryInfo(const DebuggerTelemetryInfo &other) { - username = other.username; - lldb_git_sha = other.lldb_git_sha; - lldb_path = other.lldb_path; - cwd = other.cwd; - }; + DebuggerInfo() = default; llvm::telemetry::KindType getKind() const override { return LLDBEntryKind::DebuggerInfo; @@ -134,8 +125,8 @@ class TelemetryManager : public llvm::telemetry::Manager { const llvm::telemetry::Config *getConfig(); - void atDebuggerStartup(DebuggerTelemetryInfo *entry); - void atDebuggerExit(DebuggerTelemetryInfo *entry); + virtual void AtDebuggerStartup(DebuggerInfo *entry); + virtual void AtDebuggerExit(DebuggerInfo *entry); virtual llvm::StringRef GetInstanceName() const = 0; static TelemetryManager *getInstance(); @@ -147,10 +138,13 @@ class TelemetryManager : public llvm::telemetry::Manager { private: std::unique_ptr<llvm::telemetry::Config> m_config; - // Each debugger is assigned a unique ID (session_id). + // Each instance of a TelemetryManager is assigned a unique ID. + const std::string m_id; + + // Map of debugger's ID to a unique session_id string. // All TelemetryInfo entries emitted for the same debugger instance // will get the same session_id. - llvm::DenseMap<Debugger *, std::string> session_ids; + llvm::DenseMap<lldb::user_id_t, 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 2e86d793c5ab3..9ae5f9c4e8243 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -41,17 +41,32 @@ static uint64_t ToNanosec(const SteadyTimePoint Point) { return std::chrono::nanoseconds(Point.time_since_epoch()).count(); } -static std::string MakeUUID(Debugger *debugger) { +// Generate a unique string. This should be unique across different runs. +// We build such string by combining three parts: +// <16 random bytes>_<timestamp>_<hash of username> +// This reduces the chances of getting the same UUID, even when the same +// user runs the two copies of binary at the same time. +static std::string MakeUUID() { uint8_t random_bytes[16]; + std::string randomString = "_"; if (auto ec = llvm::getRandomBytes(random_bytes, 16)) { LLDB_LOG(GetLog(LLDBLog::Object), "Failed to generate random bytes for UUID: {0}", ec.message()); - // Fallback to using timestamp + debugger ID. - return llvm::formatv( - "{0}_{1}", std::chrono::steady_clock::now().time_since_epoch().count(), - debugger->GetID()); + } else { + randomString = UUID(random_bytes).GetAsString(); } - return UUID(random_bytes).GetAsString(); + + std::string username = "_"; + UserIDResolver &resolver = lldb_private::HostInfo::GetUserIDResolver(); + std::optional<llvm::StringRef> opt_username = + resolver.GetUserName(lldb_private::HostInfo::GetUserID()); + if (opt_username) + username = *opt_username; + + return llvm::formatv( + "{0}_{1}_{2}", randomString, + std::chrono::steady_clock::now().time_since_epoch().count(), + llvm::MD5Hash(username)); } void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const { @@ -62,7 +77,7 @@ void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const { serializer.write("end_time", ToNanosec(end_time.value())); } -void DebuggerTelemetryInfo::serialize(Serializer &serializer) const { +void DebuggerInfo::serialize(Serializer &serializer) const { LLDBBaseTelemetryInfo::serialize(serializer); serializer.write("username", username); @@ -85,18 +100,21 @@ void MiscTelemetryInfo::serialize(Serializer &serializer) const { } TelemetryManager::TelemetryManager(std::unique_ptr<Config> config) - : m_config(std::move(config)) {} + : m_config(std::move(config)), m_id(MakeUUID) {} llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { + // Look up the session_id to assign to this entry or make one + // if none had been computed for this debugger. LLDBBaseTelemetryInfo *lldb_entry = llvm::dyn_cast<LLDBBaseTelemetryInfo>(entry); - std::string session_id = ""; + std::string session_id = m_id; if (Debugger *debugger = lldb_entry->debugger) { - auto session_id_pos = session_ids.find(debugger); + auto session_id_pos = session_ids.find(debugger->getID()); if (session_id_pos != session_ids.end()) session_id = session_id_pos->second; else - session_id_pos->second = session_id = MakeUUID(debugger); + session_id_pos->second = session_id = + llvm::formatv("{0}_{1}", m_id, debugger->getID()); } lldb_entry->SessionId = session_id; @@ -105,36 +123,13 @@ llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { const Config *getConfig() { return m_config.get(); } -void TelemetryManager::atDebuggerStartup(DebuggerTelemetryInfo *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 (llvm::Error er = dispatch(&misc_info)) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), - "Failed to dispatch misc-info at startup: {0}"); - } - } - +void TelemetryManager::AtDebuggerStartup(DebuggerInfo *entry) { if (auto er = dispatch(entry)) { LLDB_LOG(GetLog(LLDBLog::Object), "Failed to dispatch entry at startup"); } } -void TelemetryManager::atDebuggerExit(DebuggerTelemetryInfo *entry) { +void TelemetryManager::AtDebuggerExit(DebuggerInfo *entry) { // There must be a reference to the debugger at this point. assert(entry->debugger != nullptr); >From 4b6a4bdf158dd631baec5768fb44719b8e8bf100 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Mon, 24 Feb 2025 13:39:35 -0500 Subject: [PATCH 05/25] remove unused fields --- lldb/include/lldb/Core/Telemetry.h | 38 +----------- lldb/source/Core/Telemetry.cpp | 99 ++++++++++++------------------ 2 files changed, 41 insertions(+), 96 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 1fb2c5b6b7eeb..79351b8f8e37c 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -45,6 +45,7 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { std::optional<SteadyTimePoint> end_time; // TBD: could add some memory stats here too? + uint64_t debugger_id = 0; Debugger *debugger; // For dyn_cast, isa, etc operations. @@ -70,10 +71,6 @@ struct DebuggerInfo : public LLDBBaseTelemetryInfo { std::string lldb_version; std::optional<ExitDescription> exit_desc; - std::string lldb_path; - std::string cwd; - std::string username; - DebuggerInfo() = default; llvm::telemetry::KindType getKind() const override { @@ -87,35 +84,6 @@ struct DebuggerInfo : public LLDBBaseTelemetryInfo { void serialize(llvm::telemetry::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 - llvm::StringMap<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. @@ -141,10 +109,6 @@ class TelemetryManager : public llvm::telemetry::Manager { // Each instance of a TelemetryManager is assigned a unique ID. const std::string m_id; - // Map of debugger's ID to a unique session_id string. - // All TelemetryInfo entries emitted for the same debugger instance - // will get the same session_id. - llvm::DenseMap<lldb::user_id_t, 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 9ae5f9c4e8243..74dd8bf6f7e09 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -43,7 +43,7 @@ static uint64_t ToNanosec(const SteadyTimePoint Point) { // Generate a unique string. This should be unique across different runs. // We build such string by combining three parts: -// <16 random bytes>_<timestamp>_<hash of username> +// <16 random bytes>_<timestamp> // This reduces the chances of getting the same UUID, even when the same // user runs the two copies of binary at the same time. static std::string MakeUUID() { @@ -56,17 +56,9 @@ static std::string MakeUUID() { randomString = UUID(random_bytes).GetAsString(); } - std::string username = "_"; - UserIDResolver &resolver = lldb_private::HostInfo::GetUserIDResolver(); - std::optional<llvm::StringRef> opt_username = - resolver.GetUserName(lldb_private::HostInfo::GetUserID()); - if (opt_username) - username = *opt_username; - return llvm::formatv( - "{0}_{1}_{2}", randomString, - std::chrono::steady_clock::now().time_since_epoch().count(), - llvm::MD5Hash(username)); + "{0}_{1}", randomString, + std::chrono::steady_clock::now().time_since_epoch().count()); } void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const { @@ -90,33 +82,16 @@ void DebuggerInfo::serialize(Serializer &serializer) const { } } -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)), m_id(MakeUUID) {} llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { - // Look up the session_id to assign to this entry or make one - // if none had been computed for this debugger. + // Assign the manager_id, and debugger_id, if available, to this entry. LLDBBaseTelemetryInfo *lldb_entry = llvm::dyn_cast<LLDBBaseTelemetryInfo>(entry); - std::string session_id = m_id; - if (Debugger *debugger = lldb_entry->debugger) { - auto session_id_pos = session_ids.find(debugger->getID()); - if (session_id_pos != session_ids.end()) - session_id = session_id_pos->second; - else - session_id_pos->second = session_id = - llvm::formatv("{0}_{1}", m_id, debugger->getID()); - } - lldb_entry->SessionId = session_id; + lldb_entry->SessionId = m_id; + if (Debugger *debugger = lldb_entry->debugger) + lldb_entry->debugger_id = debugger->GetID(); return llvm::Error::success(); } @@ -124,40 +99,46 @@ llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { const Config *getConfig() { return m_config.get(); } void TelemetryManager::AtDebuggerStartup(DebuggerInfo *entry) { - 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 debugger startup: {0}"); } -} -void TelemetryManager::AtDebuggerExit(DebuggerInfo *entry) { - // There must be a reference to the debugger at this point. - assert(entry->debugger != nullptr); - - if (auto *selected_target = - entry->debugger->GetSelectedExecutionContext().GetTargetPtr()) { - if (!selected_target->IsDummyTarget()) { - const lldb::ProcessSP proc = selected_target->GetProcessSP(); - if (proc == nullptr) { - // no process has been launched yet. - entry->exit_desc = {-1, "no process launched."}; - } else { - entry->exit_desc = {proc->GetExitStatus(), ""}; - if (const char *description = proc->GetExitDescription()) - entry->exit_desc->description = std::string(description); + void TelemetryManager::AtDebuggerExit(DebuggerInfo * entry) { + // There must be a reference to the debugger at this point. + assert(entry->debugger != nullptr); + + if (auto *selected_target = + entry->debugger->GetSelectedExecutionContext().GetTargetPtr()) { + if (!selected_target->IsDummyTarget()) { + const lldb::ProcessSP proc = selected_target->GetProcessSP(); + if (proc == nullptr) { + // no process has been launched yet. + entry->exit_desc = {-1, "no process launched."}; + } else { + entry->exit_desc = {proc->GetExitStatus(), ""}; + if (const char *description = proc->GetExitDescription()) + entry->exit_desc->description = std::string(description); + } } } - } - dispatch(entry); -} -std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr; -TelemetryManager *TelemetryManager::getInstance() { return g_instance.get(); } + if (llvm::Error er = dispatch(entry)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), + "Failed to dispatch entry at debugger exit: {0}"); + } -void TelemetryManager::setInstance(std::unique_ptr<TelemetryManager> manager) { - g_instance = std::move(manager); -} + std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr; + TelemetryManager *TelemetryManager::getInstance() { + return g_instance.get(); + } + + void TelemetryManager::setInstance( + std::unique_ptr<TelemetryManager> manager) { + g_instance = std::move(manager); + } -} // namespace telemetry + } // namespace telemetry } // namespace lldb_private #endif // LLVM_BUILD_TELEMETRY >From 4dd0782e144c0b3943becf9ca2b62fc8bcfca039 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Wed, 26 Feb 2025 14:32:38 -0500 Subject: [PATCH 06/25] addressed review comments --- lldb/include/lldb/Core/Telemetry.h | 41 +++++++++++++++++- lldb/source/Core/Debugger.cpp | 67 +++++++++++++----------------- lldb/source/Core/Telemetry.cpp | 58 +++++++------------------- 3 files changed, 85 insertions(+), 81 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 62b3a3096d472..5c11004854c95 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -23,7 +23,7 @@ #include <memory> #include <optional> #include <string> -#include <unordered_map> +#include <stack> namespace lldb_private { namespace telemetry { @@ -91,11 +91,12 @@ class TelemetryManager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; - const llvm::telemetry::Config *getConfig(); virtual void AtDebuggerStartup(DebuggerInfo *entry); virtual void AtDebuggerExit(DebuggerInfo *entry); + const llvm::telemetry::Config *GetConfig(); + virtual llvm::StringRef GetInstanceName() const = 0; static TelemetryManager *GetInstance(); @@ -112,6 +113,42 @@ class TelemetryManager : public llvm::telemetry::Manager { static std::unique_ptr<TelemetryManager> g_instance; }; +/// Helper RAII class for collecting telemetry. +class ScopeTelemetryCollector { + public: + ScopeTelemetryCollector () { + if (TelemetryEnabled()) + m_start = std::chrono::steady_clock::now(); + } + + ~ScopeTelemetryCollector() { + 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){ + assert(llvm::telemetry::Config::BuildTimeEnableTelemetry && "Telemetry should have been enabled"); + m_exit_funcs.push(std::forward<Fp>(F)); + } + + private: + 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/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 1fd3b4a6f90c2..750ca3a91ba3d 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -52,6 +52,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" +#include "lldb/Core/Telemetry.h" #include "lldb/lldb-enumerations.h" #if defined(_WIN32) @@ -70,11 +71,8 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" -#ifdef LLVM_BUILD_TELEMETRY -#include "lldb/Core/Telemetry.h" -#include <chrono> -#endif +#include <chrono> #include <cstdio> #include <cstdlib> #include <cstring> @@ -767,29 +765,27 @@ void Debugger::InstanceInitialize() { DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, void *baton) { -#ifdef LLVM_BUILD_TELEMETRY - lldb_private::telemetry::SteadyTimePoint start_time = - std::chrono::steady_clock::now(); -#endif + lldb_private::telemetry::ScopeTelemetryCollector helper; DebuggerSP debugger_sp(new Debugger(log_callback, baton)); + + if (helper.TelemetryEnabled()) { + helper.RunAtScopeExit([&](){ + lldb_private::telemetry::TelemetryManager * manager = lldb_private::telemetry::TelemetryManager::GetInstance(); + lldb_private::telemetry::DebuggerInfo entry; + entry.debugger = debugger_sp.get(); + entry.start_time = helper.GetStartTime(); + entry.end_time = helper.GetCurrentTime(); + manager->AtDebuggerStartup(&entry); + }); + + } + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); g_debugger_list_ptr->push_back(debugger_sp); } debugger_sp->InstanceInitialize(); -#ifdef LLVM_BUILD_TELEMETRY - if (auto *telemetry_manager = telemetry::TelemetryManager::getInstance()) { - if (telemetry_manager->getConfig()->EnableTelemetry) { - lldb_private::telemetry::DebuggerTelemetryInfo entry; - entry.start_time = start_time; - entry.end_time = std::chrono::steady_clock::now(); - entry.debugger = debugger_sp.get(); - telemetry_manager->atDebuggerStartup(&entry); - } - } -#endif - return debugger_sp; } @@ -1010,10 +1006,20 @@ void Debugger::Clear() { // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp); // static void Debugger::Terminate(); llvm::call_once(m_clear_once, [this]() { -#ifdef LLVM_BUILD_TELEMETRY - lldb_private::telemetry::SteadyTimePoint quit_start_time = - std::chrono::steady_clock::now(); -#endif + lldb_private::telemetry::ScopeTelemetryCollector helper; + if (helper.TelemetryEnabled()) { + // TBD: We *may* have to send off the log BEFORE the ClearIOHanders()? + helper.RunAtScopeExit([&helper, this](){ + lldb_private::telemetry::TelemetryManager* manager + = lldb_private::telemetry::TelemetryManager::GetInstance(); + lldb_private::telemetry::DebuggerInfo entry; + entry.debugger = this; + entry.exit_desc = {0, ""}; // If we are here, there was no error. + entry.start_time = helper.GetStartTime(); + entry.end_time = helper.GetCurrentTime(); + manager->AtDebuggerExit(&entry); + }); + } ClearIOHandlers(); StopIOHandlerThread(); StopEventHandlerThread(); @@ -1036,19 +1042,6 @@ void Debugger::Clear() { if (Diagnostics::Enabled()) Diagnostics::Instance().RemoveCallback(m_diagnostics_callback_id); - -#ifdef LLVM_BUILD_TELEMETRY - if (auto telemetry_manager = telemetry::TelemetryManager::getInstance()) { - if (telemetry_manager->getConfig()->EnableTelemetry) { - // TBD: We *may* have to send off the log BEFORE the ClearIOHanders()? - lldb_private::telemetry::DebuggerTelemetryInfo entry; - entry.start_time = quit_start_time; - entry.end_time = std::chrono::steady_clock::now(); - entry.debugger = this; - telemetry_manager->atDebuggerExit(&entry); - } - } -#endif }); } diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 9870d10ad42eb..3ab1fcc8dfdf6 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -68,10 +68,7 @@ void LLDBBaseTelemetryInfo::serialize(Serializer &serializer) const { void DebuggerInfo::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("lldb_version", lldb_version); if (exit_desc.has_value()) { serializer.write("exit_code", exit_desc->exit_code); serializer.write("exit_desc", exit_desc->description); @@ -79,7 +76,7 @@ void DebuggerInfo::serialize(Serializer &serializer) const { } TelemetryManager::TelemetryManager(std::unique_ptr<Config> config) - : m_config(std::move(config)), m_id(MakeUUID) {} + : m_config(std::move(config)), m_id(MakeUUID()) {} llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { // Assign the manager_id, and debugger_id, if available, to this entry. @@ -97,44 +94,20 @@ void TelemetryManager::AtDebuggerStartup(DebuggerInfo *entry) { LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), "Failed to dispatch entry at debugger startup: {0}"); } +} + +void TelemetryManager::AtDebuggerExit(DebuggerInfo * entry) { + // There must be a reference to the debugger at this point. + assert(entry->debugger != nullptr); + + if (llvm::Error er = dispatch(entry)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), + "Failed to dispatch entry at debugger exit: {0}"); + } +} + +const Config *TelemetryManager::GetConfig() { return m_config.get(); } - void TelemetryManager::AtDebuggerExit(DebuggerInfo * entry) { - // There must be a reference to the debugger at this point. - assert(entry->debugger != nullptr); - - if (auto *selected_target = - entry->debugger->GetSelectedExecutionContext().GetTargetPtr()) { - if (!selected_target->IsDummyTarget()) { - const lldb::ProcessSP proc = selected_target->GetProcessSP(); - if (proc == nullptr) { - // no process has been launched yet. - entry->exit_desc = {-1, "no process launched."}; - } else { - entry->exit_desc = {proc->GetExitStatus(), ""}; - if (const char *description = proc->GetExitDescription()) - entry->exit_desc->description = std::string(description); - } - } - } - - if (llvm::Error er = dispatch(entry)) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), - "Failed to dispatch entry at debugger exit: {0}"); - } - - std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr; - TelemetryManager *TelemetryManager::getInstance() { - return g_instance.get(); - } - - void TelemetryManager::setInstance( - std::unique_ptr<TelemetryManager> manager) { - g_instance = std::move(manager); - } - - -const Config *getConfig() { return m_config.get(); } - std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr; TelemetryManager *TelemetryManager::GetInstance() { if (!Config::BuildTimeEnableTelemetry) @@ -146,5 +119,6 @@ void TelemetryManager::SetInstance(std::unique_ptr<TelemetryManager> manager) { g_instance = std::move(manager); } + } // namespace telemetry } // namespace lldb_private >From 7ad8360c170f5cbe599af2e7153742306d74a663 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Wed, 26 Feb 2025 14:32:47 -0500 Subject: [PATCH 07/25] format --- lldb/include/lldb/Core/Telemetry.h | 31 ++++++++++++++---------------- lldb/source/Core/Debugger.cpp | 15 +++++++-------- lldb/source/Core/Telemetry.cpp | 3 +-- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 5c11004854c95..3e9d76b37aba0 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -22,8 +22,8 @@ #include <ctime> #include <memory> #include <optional> -#include <string> #include <stack> +#include <string> namespace lldb_private { namespace telemetry { @@ -91,7 +91,6 @@ class TelemetryManager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; - virtual void AtDebuggerStartup(DebuggerInfo *entry); virtual void AtDebuggerExit(DebuggerInfo *entry); @@ -115,38 +114,36 @@ class TelemetryManager : public llvm::telemetry::Manager { /// Helper RAII class for collecting telemetry. class ScopeTelemetryCollector { - public: - ScopeTelemetryCollector () { +public: + ScopeTelemetryCollector() { if (TelemetryEnabled()) m_start = std::chrono::steady_clock::now(); } ~ScopeTelemetryCollector() { - while(! m_exit_funcs.empty()) { + 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; + TelemetryManager *instance = TelemetryManager::GetInstance(); + return instance != nullptr && instance->GetConfig()->EnableTelemetry; } + SteadyTimePoint GetStartTime() { return m_start; } + SteadyTimePoint GetCurrentTime() { return std::chrono::steady_clock::now(); } - SteadyTimePoint GetStartTime() {return m_start;} - SteadyTimePoint GetCurrentTime() { return std::chrono::steady_clock::now(); } - - template <typename Fp> - void RunAtScopeExit(Fp&& F){ - assert(llvm::telemetry::Config::BuildTimeEnableTelemetry && "Telemetry should have been enabled"); - m_exit_funcs.push(std::forward<Fp>(F)); - } + template <typename Fp> void RunAtScopeExit(Fp &&F) { + assert(llvm::telemetry::Config::BuildTimeEnableTelemetry && + "Telemetry should have been enabled"); + m_exit_funcs.push(std::forward<Fp>(F)); + } - private: +private: SteadyTimePoint m_start; std::stack<std::function<void()>> m_exit_funcs; - }; } // namespace telemetry diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 750ca3a91ba3d..6cafffe50cc22 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Progress.h" #include "lldb/Core/StreamAsynchronousIO.h" +#include "lldb/Core/Telemetry.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Expression/REPL.h" #include "lldb/Host/File.h" @@ -52,7 +53,6 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" -#include "lldb/Core/Telemetry.h" #include "lldb/lldb-enumerations.h" #if defined(_WIN32) @@ -71,7 +71,6 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" - #include <chrono> #include <cstdio> #include <cstdlib> @@ -769,15 +768,15 @@ DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, DebuggerSP debugger_sp(new Debugger(log_callback, baton)); if (helper.TelemetryEnabled()) { - helper.RunAtScopeExit([&](){ - lldb_private::telemetry::TelemetryManager * manager = lldb_private::telemetry::TelemetryManager::GetInstance(); + helper.RunAtScopeExit([&]() { + lldb_private::telemetry::TelemetryManager *manager = + lldb_private::telemetry::TelemetryManager::GetInstance(); lldb_private::telemetry::DebuggerInfo entry; entry.debugger = debugger_sp.get(); entry.start_time = helper.GetStartTime(); entry.end_time = helper.GetCurrentTime(); manager->AtDebuggerStartup(&entry); }); - } if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { @@ -1009,9 +1008,9 @@ void Debugger::Clear() { lldb_private::telemetry::ScopeTelemetryCollector helper; if (helper.TelemetryEnabled()) { // TBD: We *may* have to send off the log BEFORE the ClearIOHanders()? - helper.RunAtScopeExit([&helper, this](){ - lldb_private::telemetry::TelemetryManager* manager - = lldb_private::telemetry::TelemetryManager::GetInstance(); + helper.RunAtScopeExit([&helper, this]() { + lldb_private::telemetry::TelemetryManager *manager = + lldb_private::telemetry::TelemetryManager::GetInstance(); lldb_private::telemetry::DebuggerInfo entry; entry.debugger = this; entry.exit_desc = {0, ""}; // If we are here, there was no error. diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 3ab1fcc8dfdf6..e83775c0c5855 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -96,7 +96,7 @@ void TelemetryManager::AtDebuggerStartup(DebuggerInfo *entry) { } } -void TelemetryManager::AtDebuggerExit(DebuggerInfo * entry) { +void TelemetryManager::AtDebuggerExit(DebuggerInfo *entry) { // There must be a reference to the debugger at this point. assert(entry->debugger != nullptr); @@ -119,6 +119,5 @@ void TelemetryManager::SetInstance(std::unique_ptr<TelemetryManager> manager) { g_instance = std::move(manager); } - } // namespace telemetry } // namespace lldb_private >From d7b1275f76e2141eb52b5b505c42797642990741 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Wed, 26 Feb 2025 15:28:31 -0500 Subject: [PATCH 08/25] try reporting the crash from a crash handler --- lldb/source/API/SBDebugger.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index e646b09e05852..947df38bc716b 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -43,6 +43,7 @@ #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Host/Config.h" #include "lldb/Host/StreamFile.h" +#include "lldb/Core/Telemetry.h" #include "lldb/Host/XML.h" #include "lldb/Initialization/SystemLifetimeManager.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -226,6 +227,37 @@ lldb::SBError SBDebugger::InitializeWithErrorHandling() { return error; } +#if LLVM_ENABLE_TELEMETRY +#if ENABLE_BACKTRACES +static void TelemetryHandler(void *) { + // TODO: get the bt into the msg? + // Also need to pre-alloc the memory for this entry? + lldb_private::telemetry::DebuggerInfo entry; + entry.exit_desc = {-1, ""}; + if (auto* instance = lldb_private::telemetry::TelemeryManager::getInstance()) { + if (instance->GetConfig()->EnableTelemetry()) { + instance->AtDebuggerExit(&entry); + } + } +} + +static bool RegisterTelemetryHander() { + sys::AddSignalHandler(TelemetryHandler, nullptr); + return false; +} +#endif +#endif + +static void InstallCrashTelemetryReporter() { +#if LLVM_ENABLE_TELEMETRY + +#if ENABLE_BACKTRACES + static bool HandlerRegistered = RegisterTelemeryHandler(); + (void)HandlerRegistered; +#endif +#endif +} + void SBDebugger::PrintStackTraceOnError() { LLDB_INSTRUMENT(); @@ -233,6 +265,7 @@ void SBDebugger::PrintStackTraceOnError() { static std::string executable = llvm::sys::fs::getMainExecutable(nullptr, nullptr); llvm::sys::PrintStackTraceOnErrorSignal(executable); + InstallCrashTelemetryReporter(); } static void DumpDiagnostics(void *cookie) { >From 302552a0e8283476962056116f5aa3cd84b2af6a Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 09:56:16 -0500 Subject: [PATCH 09/25] revert crash handler changes --- lldb/source/API/SBDebugger.cpp | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index 947df38bc716b..e646b09e05852 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -43,7 +43,6 @@ #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Host/Config.h" #include "lldb/Host/StreamFile.h" -#include "lldb/Core/Telemetry.h" #include "lldb/Host/XML.h" #include "lldb/Initialization/SystemLifetimeManager.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -227,37 +226,6 @@ lldb::SBError SBDebugger::InitializeWithErrorHandling() { return error; } -#if LLVM_ENABLE_TELEMETRY -#if ENABLE_BACKTRACES -static void TelemetryHandler(void *) { - // TODO: get the bt into the msg? - // Also need to pre-alloc the memory for this entry? - lldb_private::telemetry::DebuggerInfo entry; - entry.exit_desc = {-1, ""}; - if (auto* instance = lldb_private::telemetry::TelemeryManager::getInstance()) { - if (instance->GetConfig()->EnableTelemetry()) { - instance->AtDebuggerExit(&entry); - } - } -} - -static bool RegisterTelemetryHander() { - sys::AddSignalHandler(TelemetryHandler, nullptr); - return false; -} -#endif -#endif - -static void InstallCrashTelemetryReporter() { -#if LLVM_ENABLE_TELEMETRY - -#if ENABLE_BACKTRACES - static bool HandlerRegistered = RegisterTelemeryHandler(); - (void)HandlerRegistered; -#endif -#endif -} - void SBDebugger::PrintStackTraceOnError() { LLDB_INSTRUMENT(); @@ -265,7 +233,6 @@ void SBDebugger::PrintStackTraceOnError() { static std::string executable = llvm::sys::fs::getMainExecutable(nullptr, nullptr); llvm::sys::PrintStackTraceOnErrorSignal(executable); - InstallCrashTelemetryReporter(); } static void DumpDiagnostics(void *cookie) { >From c00cd54664dbbe489074f0588dcc5468786196cf Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 10:11:35 -0500 Subject: [PATCH 10/25] Update lldb/source/Core/Telemetry.cpp Co-authored-by: Pavel Labath <pa...@labath.sk> --- lldb/source/Core/Telemetry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index e83775c0c5855..2921657395baa 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -81,7 +81,7 @@ TelemetryManager::TelemetryManager(std::unique_ptr<Config> config) llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { // Assign the manager_id, and debugger_id, if available, to this entry. LLDBBaseTelemetryInfo *lldb_entry = - llvm::dyn_cast<LLDBBaseTelemetryInfo>(entry); + llvm::cast<LLDBBaseTelemetryInfo>(entry); lldb_entry->SessionId = m_id; if (Debugger *debugger = lldb_entry->debugger) lldb_entry->debugger_id = debugger->GetID(); >From 597185f9a8a10c03100533dd29fbefd62dcb3ad9 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 10:17:29 -0500 Subject: [PATCH 11/25] remove unused headers --- lldb/source/Core/Telemetry.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 2921657395baa..61b0300d496f9 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -8,10 +8,6 @@ #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" @@ -19,7 +15,6 @@ #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> >From 41f664922a2da5788bce6e6db93c6738104765ef Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 10:21:01 -0500 Subject: [PATCH 12/25] remove miscinfo kindtype --- lldb/include/lldb/Core/Telemetry.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 3e9d76b37aba0..fb207931aa3d6 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -31,8 +31,6 @@ namespace telemetry { struct LLDBEntryKind : public ::llvm::telemetry::EntryKind { static const llvm::telemetry::KindType BaseInfo = 0b11000; static const llvm::telemetry::KindType DebuggerInfo = 0b11001; - // 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. >From 169449bbf47b5863175d0fcd0727ecc3e4652c95 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 10:39:05 -0500 Subject: [PATCH 13/25] Init debugger_id to LLDB_INVALID_UID --- lldb/include/lldb/Core/Telemetry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index fb207931aa3d6..5d663e0564428 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -43,7 +43,7 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { std::optional<SteadyTimePoint> end_time; // TBD: could add some memory stats here too? - uint64_t debugger_id = 0; + uint64_t debugger_id = LLDB_INVALID_UID; Debugger *debugger; // For dyn_cast, isa, etc operations. >From 74208119687fdcfcdba9011ccf1f4b990a40f321 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 14:54:53 -0500 Subject: [PATCH 14/25] addressed review comment --- lldb/include/lldb/Core/Telemetry.h | 55 ++++++++++++++++-------------- lldb/source/Core/Debugger.cpp | 44 +++++++++--------------- 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index fb207931aa3d6..725252fcb6db3 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -11,6 +11,7 @@ #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-forward.h" #include "llvm/ADT/DenseMap.h" @@ -111,37 +112,41 @@ class TelemetryManager : public llvm::telemetry::Manager { }; /// Helper RAII class for collecting telemetry. -class ScopeTelemetryCollector { -public: - ScopeTelemetryCollector() { - if (TelemetryEnabled()) - m_start = std::chrono::steady_clock::now(); +template <typename I> struct ScopedDispatcher { + // The debugger pointer is optional because we may not have a debugger yet. + // In that case, caller must set the debugger later. + ScopedDispatcher(std::function<void(I *info)> callback, + Debugger *debugger = nullptr) + : m_callback(callback) { + // Start the timer. + m_start_time = std::chrono::steady_clock::now(); + m_info.debugger = debugger; } - ~ScopeTelemetryCollector() { - while (!m_exit_funcs.empty()) { - (m_exit_funcs.top())(); - m_exit_funcs.pop(); + void SetDebugger(Debugger *debugger) { m_info.debugger = debugger; } + + ~ScopedDispatcher() { + TelemetryManager *manager = TelemetryManager::GetInstance(); + // If Telemetry is disabled (either at buildtime or runtime), + // then don't do anything. + if (!manager || !manager->GetConfig()->EnableTelemetry) + return; + m_info.start_time = m_start_time; + // Populate common fields that we can only set now. + m_info.end_time = std::chrono::steady_clock::now(); + // The callback will set the remaining fields. + m_callback(&m_info); + // And then we dispatch. + if (llvm::Error er = manager->dispatch(&m_info)) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), + "Failed to dispatch entry of type: {0}", m_info.getKind()); } } - 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) { - assert(llvm::telemetry::Config::BuildTimeEnableTelemetry && - "Telemetry should have been enabled"); - m_exit_funcs.push(std::forward<Fp>(F)); - } - private: - SteadyTimePoint m_start; - std::stack<std::function<void()>> m_exit_funcs; + SteadyTimePoint m_start_time; + std::function<void(I *info)> m_callback; + I m_info; }; } // namespace telemetry diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 6cafffe50cc22..b31567ff2421d 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -53,6 +53,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" +#include "lldb/Version/Version.h" #include "lldb/lldb-enumerations.h" #if defined(_WIN32) @@ -764,20 +765,13 @@ void Debugger::InstanceInitialize() { DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, void *baton) { - lldb_private::telemetry::ScopeTelemetryCollector helper; + lldb_private::telemetry::ScopedDispatcher< + lldb_private::telemetry::DebuggerInfo> + helper([](lldb_private::telemetry::DebuggerInfo *entry) { + entry->lldb_version = lldb_private::GetVersion(); + }); DebuggerSP debugger_sp(new Debugger(log_callback, baton)); - - if (helper.TelemetryEnabled()) { - helper.RunAtScopeExit([&]() { - lldb_private::telemetry::TelemetryManager *manager = - lldb_private::telemetry::TelemetryManager::GetInstance(); - lldb_private::telemetry::DebuggerInfo entry; - entry.debugger = debugger_sp.get(); - entry.start_time = helper.GetStartTime(); - entry.end_time = helper.GetCurrentTime(); - manager->AtDebuggerStartup(&entry); - }); - } + helper.SetDebugger(debugger_sp.get()); if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); @@ -1005,20 +999,16 @@ void Debugger::Clear() { // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp); // static void Debugger::Terminate(); llvm::call_once(m_clear_once, [this]() { - lldb_private::telemetry::ScopeTelemetryCollector helper; - if (helper.TelemetryEnabled()) { - // TBD: We *may* have to send off the log BEFORE the ClearIOHanders()? - helper.RunAtScopeExit([&helper, this]() { - lldb_private::telemetry::TelemetryManager *manager = - lldb_private::telemetry::TelemetryManager::GetInstance(); - lldb_private::telemetry::DebuggerInfo entry; - entry.debugger = this; - entry.exit_desc = {0, ""}; // If we are here, there was no error. - entry.start_time = helper.GetStartTime(); - entry.end_time = helper.GetCurrentTime(); - manager->AtDebuggerExit(&entry); - }); - } + lldb_private::telemetry::ScopedDispatcher< + lldb_private::telemetry::DebuggerInfo> + helper( + [](lldb_private::telemetry::DebuggerInfo *info) { + // If we are here, then there was no error. + // Any abnormal exit will be reported by the crash-handler. + info->exit_desc = {0, ""}; + }, + this); + ClearIOHandlers(); StopIOHandlerThread(); StopEventHandlerThread(); >From 68f95ab119c998e86625a0d459ad074481a3016e Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 14:57:55 -0500 Subject: [PATCH 15/25] removed unused --- lldb/include/lldb/Core/Telemetry.h | 3 --- lldb/source/Core/Telemetry.cpp | 17 ----------------- 2 files changed, 20 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 1b1eee1c3248e..a04ae42a45a48 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -90,9 +90,6 @@ class TelemetryManager : public llvm::telemetry::Manager { public: llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override; - virtual void AtDebuggerStartup(DebuggerInfo *entry); - virtual void AtDebuggerExit(DebuggerInfo *entry); - const llvm::telemetry::Config *GetConfig(); virtual llvm::StringRef GetInstanceName() const = 0; diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 61b0300d496f9..0ef92995cbe40 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -84,23 +84,6 @@ llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { return llvm::Error::success(); } -void TelemetryManager::AtDebuggerStartup(DebuggerInfo *entry) { - if (llvm::Error er = dispatch(entry)) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), - "Failed to dispatch entry at debugger startup: {0}"); - } -} - -void TelemetryManager::AtDebuggerExit(DebuggerInfo *entry) { - // There must be a reference to the debugger at this point. - assert(entry->debugger != nullptr); - - if (llvm::Error er = dispatch(entry)) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er), - "Failed to dispatch entry at debugger exit: {0}"); - } -} - const Config *TelemetryManager::GetConfig() { return m_config.get(); } std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr; >From d586956edb741bb9f5da108bf21361d41297f068 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 14:59:57 -0500 Subject: [PATCH 16/25] add smoke check --- lldb/source/Core/Debugger.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index b31567ff2421d..2ebfb3d069fcb 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1002,7 +1002,8 @@ void Debugger::Clear() { lldb_private::telemetry::ScopedDispatcher< lldb_private::telemetry::DebuggerInfo> helper( - [](lldb_private::telemetry::DebuggerInfo *info) { + [this](lldb_private::telemetry::DebuggerInfo *info) { + assert(this == info->debugger); // If we are here, then there was no error. // Any abnormal exit will be reported by the crash-handler. info->exit_desc = {0, ""}; >From 8b7afd6dc16984195b89e76bf32a225b0c07cf7e Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 15:12:39 -0500 Subject: [PATCH 17/25] remove unused headers --- lldb/include/lldb/Core/Telemetry.h | 2 -- lldb/source/Core/Telemetry.cpp | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index a04ae42a45a48..1a3f54e70d0bd 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -14,7 +14,6 @@ #include "lldb/Utility/LLDBLog.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" @@ -23,7 +22,6 @@ #include <ctime> #include <memory> #include <optional> -#include <stack> #include <string> namespace lldb_private { diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 0ef92995cbe40..1451b264a3254 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -94,7 +94,8 @@ TelemetryManager *TelemetryManager::GetInstance() { } void TelemetryManager::SetInstance(std::unique_ptr<TelemetryManager> manager) { - g_instance = std::move(manager); + if (Config::BuildTimeEnableTelemetry) + g_instance = std::move(manager); } } // namespace telemetry >From 21b8bdf1219047a15b6f0c358d4b700c637b36ca Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 15:43:57 -0500 Subject: [PATCH 18/25] added test --- lldb/unittests/Core/TelemetryTest.cpp | 53 ++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/lldb/unittests/Core/TelemetryTest.cpp b/lldb/unittests/Core/TelemetryTest.cpp index 22fade58660b5..53fd986c15dff 100644 --- a/lldb/unittests/Core/TelemetryTest.cpp +++ b/lldb/unittests/Core/TelemetryTest.cpp @@ -18,25 +18,35 @@ namespace lldb_private { -struct FakeTelemetryInfo : public llvm::telemetry::TelemetryInfo { +struct FakeTelemetryInfo : public telemetry::LLDBBaseTelemetryInfo { std::string msg; + int num; + + ::llvm::telemetry::KindType getKind() const override { return 0b11111; } }; class TestDestination : public llvm::telemetry::Destination { public: - TestDestination(std::vector<const llvm::telemetry::TelemetryInfo *> *entries) + TestDestination(std::vector<llvm::telemetry::TelemetryInfo *> *entries) : received_entries(entries) {} llvm::Error receiveEntry(const llvm::telemetry::TelemetryInfo *entry) override { - received_entries->push_back(entry); + // Save a copy of the entry for later verification (because the original + // entry might have gone out of scope by the time verification is done. + if (auto *fake_entry = llvm::dyn_cast<FakeTelemetryInfo>(entry)) { + FakeTelemetryInfo *copied = new FakeTelemetryInfo(); + copied->msg = fake_entry->msg; + copied->num = fake_entry->num; + received_entries->push_back(copied); + } return llvm::Error::success(); } llvm::StringLiteral name() const override { return "TestDestination"; } private: - std::vector<const llvm::telemetry::TelemetryInfo *> *received_entries; + std::vector<llvm::telemetry::TelemetryInfo *> *received_entries; }; class FakePlugin : public telemetry::TelemetryManager { @@ -66,6 +76,8 @@ class FakePlugin : public telemetry::TelemetryManager { } // namespace lldb_private +using namespace lldb_private::telemetry; + #if LLVM_ENABLE_TELEMETRY #define TELEMETRY_TEST(suite, test) TEST(suite, test) #else @@ -80,7 +92,7 @@ TELEMETRY_TEST(TelemetryTest, PluginTest) { auto *ins = lldb_private::telemetry::TelemetryManager::GetInstance(); ASSERT_NE(ins, nullptr); - std::vector<const ::llvm::telemetry::TelemetryInfo *> expected_entries; + std::vector<::llvm::telemetry::TelemetryInfo *> expected_entries; ins->addDestination( std::make_unique<lldb_private::TestDestination>(&expected_entries)); @@ -95,3 +107,34 @@ TELEMETRY_TEST(TelemetryTest, PluginTest) { ASSERT_EQ("FakeTelemetryPlugin", ins->GetInstanceName()); } + +TELEMETRY_TEST(TelemetryTest, ScopedDispatcherTest) { + lldb_private::FakePlugin::Initialize(); + auto *ins = TelemetryManager::GetInstance(); + ASSERT_NE(ins, nullptr); + std::vector<::llvm::telemetry::TelemetryInfo *> expected_entries; + ins->addDestination( + std::make_unique<lldb_private::TestDestination>(&expected_entries)); + + { + ScopedDispatcher<lldb_private::FakeTelemetryInfo> helper( + [](lldb_private::FakeTelemetryInfo *info) { info->num = 0; }); + } + + { + ScopedDispatcher<lldb_private::FakeTelemetryInfo> helper( + [](lldb_private::FakeTelemetryInfo *info) { info->num = 1; }); + } + + { + ScopedDispatcher<lldb_private::FakeTelemetryInfo> helper( + [](lldb_private::FakeTelemetryInfo *info) { info->num = 2; }); + } + + EXPECT_EQ(3U, expected_entries.size()); + for (int i = 0; i < 3; ++i) { + EXPECT_EQ( + i, llvm::dyn_cast<lldb_private::FakeTelemetryInfo>(expected_entries[i]) + ->num); + } +} >From 7776ea15759931509ab7fc346087f918096c594d Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 15:48:55 -0500 Subject: [PATCH 19/25] formatting --- lldb/source/Core/Debugger.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 2ebfb3d069fcb..5809d9be47656 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -778,7 +778,6 @@ DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, g_debugger_list_ptr->push_back(debugger_sp); } debugger_sp->InstanceInitialize(); - return debugger_sp; } @@ -1009,7 +1008,6 @@ void Debugger::Clear() { info->exit_desc = {0, ""}; }, this); - ClearIOHandlers(); StopIOHandlerThread(); StopEventHandlerThread(); >From c70bd5d85e81163dcff1960e7c0459c1b61e9771 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 15:56:59 -0500 Subject: [PATCH 20/25] Update lldb/include/lldb/Core/Telemetry.h Co-authored-by: Jonas Devlieghere <jo...@devlieghere.com> --- lldb/include/lldb/Core/Telemetry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 1a3f54e70d0bd..7613128343164 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -42,7 +42,7 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { std::optional<SteadyTimePoint> end_time; // TBD: could add some memory stats here too? - uint64_t debugger_id = LLDB_INVALID_UID; + lldb::user_id_t debugger_id = LLDB_INVALID_UID; Debugger *debugger; // For dyn_cast, isa, etc operations. >From bcd793ec613648af4b53079a4221af09920ef39e Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 16:03:44 -0500 Subject: [PATCH 21/25] change template to Info --- lldb/include/lldb/Core/Telemetry.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index 7613128343164..c9fe032c84073 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -107,10 +107,10 @@ class TelemetryManager : public llvm::telemetry::Manager { }; /// Helper RAII class for collecting telemetry. -template <typename I> struct ScopedDispatcher { +template <typename Info> struct ScopedDispatcher { // The debugger pointer is optional because we may not have a debugger yet. // In that case, caller must set the debugger later. - ScopedDispatcher(std::function<void(I *info)> callback, + ScopedDispatcher(std::function<void(Info *info)> callback, Debugger *debugger = nullptr) : m_callback(callback) { // Start the timer. @@ -140,8 +140,8 @@ template <typename I> struct ScopedDispatcher { private: SteadyTimePoint m_start_time; - std::function<void(I *info)> m_callback; - I m_info; + std::function<void(Info *info)> m_callback; + Info m_info; }; } // namespace telemetry >From 4ba043198a6819a52941e29d37f30ef6353e2d80 Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Thu, 27 Feb 2025 22:23:18 -0500 Subject: [PATCH 22/25] formatting --- lldb/source/Core/Telemetry.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 1451b264a3254..93c4f76c96184 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -75,12 +75,10 @@ TelemetryManager::TelemetryManager(std::unique_ptr<Config> config) llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { // Assign the manager_id, and debugger_id, if available, to this entry. - LLDBBaseTelemetryInfo *lldb_entry = - llvm::cast<LLDBBaseTelemetryInfo>(entry); + LLDBBaseTelemetryInfo *lldb_entry = llvm::cast<LLDBBaseTelemetryInfo>(entry); lldb_entry->SessionId = m_id; if (Debugger *debugger = lldb_entry->debugger) lldb_entry->debugger_id = debugger->GetID(); - return llvm::Error::success(); } >From 6027a697f1dddc7638374ddc8f5ba3286302ad0d Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Fri, 28 Feb 2025 09:03:50 -0500 Subject: [PATCH 23/25] Update lldb/source/Core/Debugger.cpp Co-authored-by: Pavel Labath <pa...@labath.sk> --- lldb/source/Core/Debugger.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 5809d9be47656..075718335be5a 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -998,8 +998,7 @@ void Debugger::Clear() { // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp); // static void Debugger::Terminate(); llvm::call_once(m_clear_once, [this]() { - lldb_private::telemetry::ScopedDispatcher< - lldb_private::telemetry::DebuggerInfo> + telemetry::ScopedDispatcher<telemetry::DebuggerInfo> helper( [this](lldb_private::telemetry::DebuggerInfo *info) { assert(this == info->debugger); >From c011531f1b470869e114baa44292cc83f64ed6da Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Fri, 28 Feb 2025 10:18:36 -0500 Subject: [PATCH 24/25] address review comments --- lldb/include/lldb/Core/Telemetry.h | 39 ++++++++++++++++----------- lldb/source/Core/Debugger.cpp | 4 +-- lldb/source/Core/Telemetry.cpp | 15 ++++++++--- lldb/unittests/Core/TelemetryTest.cpp | 35 ++++++++++++------------ 4 files changed, 54 insertions(+), 39 deletions(-) diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h index c9fe032c84073..7d8716f1659b5 100644 --- a/lldb/include/lldb/Core/Telemetry.h +++ b/lldb/include/lldb/Core/Telemetry.h @@ -14,6 +14,7 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" @@ -27,9 +28,16 @@ namespace lldb_private { namespace telemetry { +// We expect each (direct) subclass of LLDBTelemetryInfo to +// have an LLDBEntryKind in the form 0b11xxxxxxxx +// Specifically: +// - Length: 8 bits +// - First two bits (MSB) must be 11 - the common prefix +// If any of the subclass has descendents, those descendents +// must have their LLDBEntryKind in the similar form (ie., share common prefix) struct LLDBEntryKind : public ::llvm::telemetry::EntryKind { - static const llvm::telemetry::KindType BaseInfo = 0b11000; - static const llvm::telemetry::KindType DebuggerInfo = 0b11001; + static const llvm::telemetry::KindType BaseInfo = 0b11000000; + static const llvm::telemetry::KindType DebuggerInfo = 0b11000100; }; /// Defines a convenient type for timestamp of various events. @@ -58,15 +66,10 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo { void serialize(llvm::telemetry::Serializer &serializer) const override; }; -/// Describes the exit status of a debugger. -struct ExitDescription { - int exit_code; - std::string description; -}; - struct DebuggerInfo : public LLDBBaseTelemetryInfo { std::string lldb_version; - std::optional<ExitDescription> exit_desc; + + bool is_exit_entry = false; DebuggerInfo() = default; @@ -75,7 +78,9 @@ struct DebuggerInfo : public LLDBBaseTelemetryInfo { } static bool classof(const llvm::telemetry::TelemetryInfo *T) { - return T->getKind() == LLDBEntryKind::DebuggerInfo; + // Subclasses of this is also acceptable + return (T->getKind() & LLDBEntryKind::DebuggerInfo) == + LLDBEntryKind::DebuggerInfo; } void serialize(llvm::telemetry::Serializer &serializer) const override; @@ -91,8 +96,11 @@ class TelemetryManager : public llvm::telemetry::Manager { const llvm::telemetry::Config *GetConfig(); virtual llvm::StringRef GetInstanceName() const = 0; + static TelemetryManager *GetInstance(); + static TelemetryManager *GetInstanceIfEnabled(); + protected: TelemetryManager(std::unique_ptr<llvm::telemetry::Config> config); @@ -110,9 +118,9 @@ class TelemetryManager : public llvm::telemetry::Manager { template <typename Info> struct ScopedDispatcher { // The debugger pointer is optional because we may not have a debugger yet. // In that case, caller must set the debugger later. - ScopedDispatcher(std::function<void(Info *info)> callback, + ScopedDispatcher(llvm::unique_function<void(Info *info)> callback, Debugger *debugger = nullptr) - : m_callback(callback) { + : m_callback(std::move(callback)) { // Start the timer. m_start_time = std::chrono::steady_clock::now(); m_info.debugger = debugger; @@ -121,11 +129,12 @@ template <typename Info> struct ScopedDispatcher { void SetDebugger(Debugger *debugger) { m_info.debugger = debugger; } ~ScopedDispatcher() { - TelemetryManager *manager = TelemetryManager::GetInstance(); // If Telemetry is disabled (either at buildtime or runtime), // then don't do anything. - if (!manager || !manager->GetConfig()->EnableTelemetry) + TelemetryManager *manager = TelemetryManager::GetInstanceIfEnabled(); + if (!manager) return; + m_info.start_time = m_start_time; // Populate common fields that we can only set now. m_info.end_time = std::chrono::steady_clock::now(); @@ -140,7 +149,7 @@ template <typename Info> struct ScopedDispatcher { private: SteadyTimePoint m_start_time; - std::function<void(Info *info)> m_callback; + llvm::unique_function<void(Info *info)> m_callback; Info m_info; }; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 5809d9be47656..7c3f6d6006b99 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1003,9 +1003,7 @@ void Debugger::Clear() { helper( [this](lldb_private::telemetry::DebuggerInfo *info) { assert(this == info->debugger); - // If we are here, then there was no error. - // Any abnormal exit will be reported by the crash-handler. - info->exit_desc = {0, ""}; + info->is_exit_entry = true; }, this); ClearIOHandlers(); diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp index 1451b264a3254..7c951059f9a6c 100644 --- a/lldb/source/Core/Telemetry.cpp +++ b/lldb/source/Core/Telemetry.cpp @@ -64,10 +64,7 @@ void DebuggerInfo::serialize(Serializer &serializer) const { LLDBBaseTelemetryInfo::serialize(serializer); serializer.write("lldb_version", lldb_version); - if (exit_desc.has_value()) { - serializer.write("exit_code", exit_desc->exit_code); - serializer.write("exit_desc", exit_desc->description); - } + serializer.write("is_exit_entry", is_exit_entry); } TelemetryManager::TelemetryManager(std::unique_ptr<Config> config) @@ -93,6 +90,16 @@ TelemetryManager *TelemetryManager::GetInstance() { return g_instance.get(); } +TelemetryManager *TelemetryManager::GetInstanceIfEnabled() { + // Telemetry may be enabled at build time but disabled at runtime. + if (TelemetryManager *ins = TelemetryManager::GetInstance()) { + if (ins->GetConfig()->EnableTelemetry) + return ins; + } + + return nullptr; +} + void TelemetryManager::SetInstance(std::unique_ptr<TelemetryManager> manager) { if (Config::BuildTimeEnableTelemetry) g_instance = std::move(manager); diff --git a/lldb/unittests/Core/TelemetryTest.cpp b/lldb/unittests/Core/TelemetryTest.cpp index 53fd986c15dff..0e9f329110872 100644 --- a/lldb/unittests/Core/TelemetryTest.cpp +++ b/lldb/unittests/Core/TelemetryTest.cpp @@ -22,31 +22,30 @@ struct FakeTelemetryInfo : public telemetry::LLDBBaseTelemetryInfo { std::string msg; int num; - ::llvm::telemetry::KindType getKind() const override { return 0b11111; } + ::llvm::telemetry::KindType getKind() const override { return 0b11111111; } }; class TestDestination : public llvm::telemetry::Destination { public: - TestDestination(std::vector<llvm::telemetry::TelemetryInfo *> *entries) + TestDestination( + std::vector<std::unique_ptr<llvm::telemetry::TelemetryInfo>> *entries) : received_entries(entries) {} llvm::Error receiveEntry(const llvm::telemetry::TelemetryInfo *entry) override { // Save a copy of the entry for later verification (because the original // entry might have gone out of scope by the time verification is done. - if (auto *fake_entry = llvm::dyn_cast<FakeTelemetryInfo>(entry)) { - FakeTelemetryInfo *copied = new FakeTelemetryInfo(); - copied->msg = fake_entry->msg; - copied->num = fake_entry->num; - received_entries->push_back(copied); - } + if (auto *fake_entry = llvm::dyn_cast<FakeTelemetryInfo>(entry)) + received_entries->push_back( + std::make_unique<FakeTelemetryInfo>(*fake_entry)); return llvm::Error::success(); } llvm::StringLiteral name() const override { return "TestDestination"; } private: - std::vector<llvm::telemetry::TelemetryInfo *> *received_entries; + std::vector<std::unique_ptr<llvm::telemetry::TelemetryInfo>> + *received_entries; }; class FakePlugin : public telemetry::TelemetryManager { @@ -92,17 +91,18 @@ TELEMETRY_TEST(TelemetryTest, PluginTest) { auto *ins = lldb_private::telemetry::TelemetryManager::GetInstance(); ASSERT_NE(ins, nullptr); - std::vector<::llvm::telemetry::TelemetryInfo *> expected_entries; + std::vector<std::unique_ptr<::llvm::telemetry::TelemetryInfo>> + received_entries; ins->addDestination( - std::make_unique<lldb_private::TestDestination>(&expected_entries)); + std::make_unique<lldb_private::TestDestination>(&received_entries)); lldb_private::FakeTelemetryInfo entry; entry.msg = ""; ASSERT_THAT_ERROR(ins->dispatch(&entry), ::llvm::Succeeded()); - ASSERT_EQ(1U, expected_entries.size()); + ASSERT_EQ(1U, received_entries.size()); EXPECT_EQ("In FakePlugin", - llvm::dyn_cast<lldb_private::FakeTelemetryInfo>(expected_entries[0]) + llvm::dyn_cast<lldb_private::FakeTelemetryInfo>(received_entries[0]) ->msg); ASSERT_EQ("FakeTelemetryPlugin", ins->GetInstanceName()); @@ -112,9 +112,10 @@ TELEMETRY_TEST(TelemetryTest, ScopedDispatcherTest) { lldb_private::FakePlugin::Initialize(); auto *ins = TelemetryManager::GetInstance(); ASSERT_NE(ins, nullptr); - std::vector<::llvm::telemetry::TelemetryInfo *> expected_entries; + std::vector<std::unique_ptr<::llvm::telemetry::TelemetryInfo>> + received_entries; ins->addDestination( - std::make_unique<lldb_private::TestDestination>(&expected_entries)); + std::make_unique<lldb_private::TestDestination>(&received_entries)); { ScopedDispatcher<lldb_private::FakeTelemetryInfo> helper( @@ -131,10 +132,10 @@ TELEMETRY_TEST(TelemetryTest, ScopedDispatcherTest) { [](lldb_private::FakeTelemetryInfo *info) { info->num = 2; }); } - EXPECT_EQ(3U, expected_entries.size()); + EXPECT_EQ(3U, received_entries.size()); for (int i = 0; i < 3; ++i) { EXPECT_EQ( - i, llvm::dyn_cast<lldb_private::FakeTelemetryInfo>(expected_entries[i]) + i, llvm::dyn_cast<lldb_private::FakeTelemetryInfo>(received_entries[i]) ->num); } } >From 17ced2e27f43c412cac6eb366db49254a09432bb Mon Sep 17 00:00:00 2001 From: Vy Nguyen <v...@google.com> Date: Fri, 28 Feb 2025 21:43:11 -0500 Subject: [PATCH 25/25] formatting --- lldb/source/Core/Debugger.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 4edb5e13afa5d..68d1bd30cc5b0 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -998,13 +998,12 @@ void Debugger::Clear() { // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp); // static void Debugger::Terminate(); llvm::call_once(m_clear_once, [this]() { - telemetry::ScopedDispatcher<telemetry::DebuggerInfo> - helper( - [this](lldb_private::telemetry::DebuggerInfo *info) { - assert(this == info->debugger); - info->is_exit_entry = true; - }, - this); + telemetry::ScopedDispatcher<telemetry::DebuggerInfo> helper( + [this](lldb_private::telemetry::DebuggerInfo *info) { + assert(this == info->debugger); + info->is_exit_entry = true; + }, + this); ClearIOHandlers(); StopIOHandlerThread(); StopEventHandlerThread(); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits