[Lldb-commits] [lldb] [lldb][telemetry] Implement LLDB Telemetry (part 1) (PR #119716)

Vy Nguyen via lldb-commits lldb-commits at lists.llvm.org
Thu Dec 26 17:52:19 PST 2024


https://github.com/oontvoo updated https://github.com/llvm/llvm-project/pull/119716

>From b7216d7c3edd5974d84612586fbabdef19037387 Mon Sep 17 00:00:00 2001
From: Vy Nguyen <vyng at google.com>
Date: Thu, 26 Dec 2024 20:50:40 -0500
Subject: [PATCH] Implement LLDB Telemetry (Part 1)

This contains only the concrete implementation of the framework to be used but no usages yet.

This is a subset of PR/98528.

I plan to send a few follow-up patches:
part2 : includes changes in the plugin-manager to set up the plugin stuff (ie., how to create a default vs vendor impl)
part3 (all of the following can be done in parallel):
* part 3_a: define DebuggerTelemetryInfo and related methods to collect data about debugger startup/exit
* part 3_b: define TargetTelemetryInfo and related methods to collect data about debug target(s)
* part 3_c: define CommandTelemetryInfo and related methods to collect data about debug-commands
* part 3_d: define ClientTelemtryInfo and related methods to collect data about lldb-dap/any other client
---
 lldb/include/lldb/Core/Telemetry.h    | 101 ++++++++++++++++++++++++++
 lldb/include/lldb/lldb-enumerations.h |   4 +-
 lldb/source/Core/CMakeLists.txt       |   2 +
 lldb/source/Core/Telemetry.cpp        |  92 +++++++++++++++++++++++
 lldb/test/CMakeLists.txt              |   3 +
 5 files changed, 200 insertions(+), 2 deletions(-)
 create mode 100644 lldb/include/lldb/Core/Telemetry.h
 create mode 100644 lldb/source/Core/Telemetry.cpp

diff --git a/lldb/include/lldb/Core/Telemetry.h b/lldb/include/lldb/Core/Telemetry.h
new file mode 100644
index 000000000000000..882511efd804d23
--- /dev/null
+++ b/lldb/include/lldb/Core/Telemetry.h
@@ -0,0 +1,101 @@
+//===-- Telemetry.h ----------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_CORE_TELEMETRY_H
+#define LLDB_CORE_TELEMETRY_H
+
+#include <chrono>
+#include <ctime>
+#include <memory>
+#include <optional>
+#include <string>
+#include <unordered_map>
+
+#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Telemetry/Telemetry.h"
+
+namespace lldb_private {
+
+using llvm::telemetry::Destination;
+using llvm::telemetry::KindType;
+using llvm::telemetry::Serializer;
+using llvm::telemetry::TelemetryInfo;
+
+struct LldbEntryKind : public ::llvm::telemetry::EntryKind {
+  static const KindType BaseInfo = 0b11000;
+};
+
+/// Defines a convenient type for timestamp of various events.
+/// This is used by the EventStats below.
+using SteadyTimePoint = std::chrono::time_point<std::chrono::steady_clock,
+                                                std::chrono::nanoseconds>;
+
+/// Various time (and possibly memory) statistics of an event.
+struct EventStats {
+  // REQUIRED: Start time of an event
+  SteadyTimePoint start;
+  // OPTIONAL: End time of an event - may be empty if not meaningful.
+  std::optional<SteadyTimePoint> end;
+  // TBD: could add some memory stats here too?
+
+  EventStats() = default;
+  EventStats(SteadyTimePoint start) : start(start) {}
+  EventStats(SteadyTimePoint start, SteadyTimePoint end)
+      : start(start), end(end) {}
+};
+
+/// Describes the exit signal of an event.
+struct ExitDescription {
+  int exit_code;
+  std::string description;
+};
+
+struct LldbBaseTelemetryInfo : public TelemetryInfo {
+  EventStats stats;
+
+  std::optional<ExitDescription> exit_desc;
+
+  Debugger *debugger;
+
+  // For dyn_cast, isa, etc operations.
+  KindType getKind() const override { return LldbEntryKind::BaseInfo; }
+
+  static bool classof(const TelemetryInfo *t) {
+    // Subclasses of this is also acceptable.
+    return (t->getKind() & LldbEntryKind::BaseInfo) == LldbEntryKind::BaseInfo;
+  }
+
+  void serialize(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 {
+public:
+  TelemetryManager(std::unique_ptr<llvm::telemetry::Config> config);
+
+  llvm::Error dispatch(TelemetryInfo *entry) override;
+
+  void addDestination(std::unique_ptr<Destination> destination) override;
+
+private:
+  std::unique_ptr<llvm::telemetry::Config> m_config;
+  const std::string m_session_uuid;
+  std::vector<std::unique_ptr<Destination>> m_destinations;
+};
+
+} // namespace lldb_private
+#endif // LLDB_CORE_TELEMETRY_H
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 0094fcd596fdf70..f63e446b6042f62 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -257,8 +257,8 @@ enum StopReason {
 };
 
 /// Command Return Status Types.
-enum ReturnStatus {
-  eReturnStatusInvalid,
+enum ReturnStatus : int {
+  eReturnStatusInvalid = 0,
   eReturnStatusSuccessFinishNoResult,
   eReturnStatusSuccessFinishResult,
   eReturnStatusSuccessContinuingNoResult,
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index 6d14f7a87764e05..dcab3b19ad8ff90 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -51,6 +51,7 @@ add_lldb_library(lldbCore
   Section.cpp
   SourceLocationSpec.cpp
   SourceManager.cpp
+  Telemetry.cpp
   StreamAsynchronousIO.cpp
   ThreadedCommunication.cpp
   UserSettingsController.cpp
@@ -80,6 +81,7 @@ add_lldb_library(lldbCore
     Support
     Demangle
     TargetParser
+    Telemetry
   )
 
 add_dependencies(lldbCore
diff --git a/lldb/source/Core/Telemetry.cpp b/lldb/source/Core/Telemetry.cpp
new file mode 100644
index 000000000000000..3d6264a4c8e57a3
--- /dev/null
+++ b/lldb/source/Core/Telemetry.cpp
@@ -0,0 +1,92 @@
+//===-- Telemetry.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "lldb/Core/Telemetry.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Target/Statistics.h"
+#include "lldb/Utility/ConstString.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/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/RandomNumberGenerator.h"
+#include "llvm/Telemetry/Telemetry.h"
+#include <chrono>
+#include <cstdlib>
+#include <ctime>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace lldb_private {
+
+using ::llvm::Error;
+using ::llvm::telemetry::Destination;
+using ::llvm::telemetry::TelemetryInfo;
+
+static uint64_t ToNanosec(const SteadyTimePoint Point) {
+  return nanoseconds(Point.value().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(stats.start));
+  if (stats.end.has_value())
+    serializer.write("end_time", ToNanosec(stats.end.value()));
+  if (exit_desc.has_value()) {
+    serializer.write("exit_code", exit_desc->exit_code);
+    serializer.write("exit_msg", exit_desc->description);
+  }
+}
+
+static std::string MakeUUID(lldb_private::Debugger *debugger) {
+  std::string ret;
+  uint8_t random_bytes[16];
+  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.
+    ret = std::to_string(
+              std::chrono::steady_clock::now().time_since_epoch().count()) +
+          "_" + std::to_string(debugger->GetID());
+  } else {
+    ret = lldb_private::UUID(random_bytes).GetAsString();
+  }
+
+  return ret;
+}
+
+TelemetryManager::TelemetryManager(
+    std::unique_ptr<llvm::telemetry::Config> config,
+    lldb_private::Debugger *debugger)
+    : m_config(std::move(config)), m_debugger(debugger),
+      m_session_uuid(MakeUUID(debugger)) {}
+
+llvm::Error TelemetryManager::dispatch(TelemetryInfo *entry) {
+  entry->SessionId = m_session_uuid;
+
+  llvm::Error defferedErrs = llvm::Error::success();
+  for (auto &destination : m_destinations)
+    deferredErrs = llvm::joinErrors(std::move(deferredErrs),
+                                    destination->receiveEntry(entry));
+
+  return std::move(deferredErrs);
+}
+
+void TelemetryManager::addDestination(
+    std::unique_ptr<Destination> destination) {
+  m_destinations.push_back(std::move(destination));
+}
+
+} // namespace lldb_private
diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt
index 6449ac5a9247f69..b71550d17888649 100644
--- a/lldb/test/CMakeLists.txt
+++ b/lldb/test/CMakeLists.txt
@@ -108,6 +108,9 @@ endfunction(add_lldb_test_dependency)
 add_lldb_test_dependency(lldb)
 add_lldb_test_dependency(lldb-test)
 
+# Enable Telemetry for testing.
+target_compile_definitions(lldb PRIVATE -DTEST_TELEMETRY)
+
 # On Darwin, darwin-debug is an hard dependency for the testsuites.
 if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
   add_lldb_test_dependency(darwin-debug)



More information about the lldb-commits mailing list