Skip to content

[lldb]Implement LLDB Telemetry #98528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
dbb8b15
[llvm][lib]Propose a simple Telemetry framework.
oontvoo Aug 7, 2024
6e43f67
add header
oontvoo Aug 7, 2024
e25f5fc
fixed typo
oontvoo Aug 7, 2024
ad3906c
Merge branch 'llvm:main' into llvm_telemetry
oontvoo Aug 9, 2024
24d07d6
Merge branch 'llvm:main' into llvm_telemetry
oontvoo Aug 22, 2024
0057bcf
add tests and addressed review comments
oontvoo Aug 29, 2024
750e4ac
formatting changes
oontvoo Aug 29, 2024
1378ed4
more formatting
oontvoo Aug 29, 2024
02e750e
more formatting changes
oontvoo Aug 29, 2024
63e99fc
Added header comment to describe the package
oontvoo Aug 29, 2024
fa88512
reformat header
oontvoo Aug 29, 2024
0866f64
addressed review comments and added separate docs in llvm/docs/
oontvoo Sep 3, 2024
a8523f7
updated field names in tests
oontvoo Sep 4, 2024
47e8b06
reformated doc and added additional details
oontvoo Sep 4, 2024
690c6ab
fix formatting
oontvoo Sep 4, 2024
db668f4
details
oontvoo Sep 4, 2024
0290a14
formatted TelemetryTest.cpp
oontvoo Sep 4, 2024
14b5234
fix formatting in docs
oontvoo Sep 4, 2024
6ca87e5
convert comments to doxygen style
oontvoo Sep 4, 2024
4155add
fix doc toc
oontvoo Sep 4, 2024
11ead4a
group all the testing-params into a Context struct
oontvoo Sep 5, 2024
48228ee
fix conversion warnings
oontvoo Sep 5, 2024
ed8a3f1
Merge branch 'llvm:main' into llvm_telemetry
oontvoo Sep 5, 2024
990e1ca
finish up todos
oontvoo Sep 5, 2024
42781f7
[lldb]Implement LLDB Telemetry :
oontvoo Sep 12, 2024
04b7da8
change the data type from json to structureddata
oontvoo Sep 17, 2024
0e49b93
Rework the default impl of Telemetry in LLDB as "Plugin" to allow for…
oontvoo Sep 20, 2024
10b5f46
Merge branch 'llvm:main' into telemetry_shared
oontvoo Sep 24, 2024
f85900d
UPdate LLDB implementation to match changes in LLVM's telemetry
oontvoo Dec 11, 2024
66b77aa
fix vtable issue
oontvoo Dec 11, 2024
67a0ed0
more renaming for consistency
oontvoo Dec 11, 2024
f7f7004
remove unused
oontvoo Dec 11, 2024
949b994
addressed review comments
oontvoo Dec 17, 2024
1eeb6f9
formatting
oontvoo Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lldb/include/lldb/API/SBDebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "lldb/API/SBDefines.h"
#include "lldb/API/SBPlatform.h"
#include "lldb/API/SBStructuredData.h"

namespace lldb_private {
class CommandPluginInterfaceImplementation;
Expand Down Expand Up @@ -245,6 +246,8 @@ class LLDB_API SBDebugger {

lldb::SBTarget GetDummyTarget();

void SendTelemetry(const lldb::SBStructuredData &entry);

// Return true if target is deleted from the target list of the debugger.
bool DeleteTarget(lldb::SBTarget &target);

Expand Down
10 changes: 10 additions & 0 deletions lldb/include/lldb/Core/Debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Core/Telemetry.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/StreamFile.h"
Expand All @@ -31,6 +33,7 @@
#include "lldb/Utility/Diagnostics.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/UserID.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
Expand All @@ -46,6 +49,7 @@
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Threading.h"
#include "llvm/Telemetry/Telemetry.h"

#include <cassert>
#include <cstddef>
Expand Down Expand Up @@ -149,6 +153,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,

repro::DataRecorder *GetInputRecorder();

TelemetryManager *GetTelemetryManager() { return m_telemetry_manager.get(); }

void SendClientTelemetry(const lldb_private::StructuredDataImpl &entry);

Status SetInputString(const char *data);

void SetInputFile(lldb::FileSP file);
Expand Down Expand Up @@ -759,6 +767,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
eBroadcastBitEventThreadIsListening = (1 << 0),
};

std::unique_ptr<TelemetryManager> m_telemetry_manager;

private:
// Use Debugger::CreateInstance() to get a shared pointer to a new debugger
// object
Expand Down
9 changes: 9 additions & 0 deletions lldb/include/lldb/Core/PluginManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,15 @@ class PluginManager {
const UUID *uuid,
const ArchSpec *arch);

// TelemetryVendor
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
TelemetryVendorCreateInstance create_callback);

static bool UnregisterPlugin(TelemetryVendorCreateInstance create_callback);

static TelemetryVendorCreateInstance
GetTelemetryVendorCreateCallbackAtIndex(uint32_t idx);

// Trace
static bool RegisterPlugin(
llvm::StringRef name, llvm::StringRef description,
Expand Down
308 changes: 308 additions & 0 deletions lldb/include/lldb/Core/Telemetry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
//===-- 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 <atomic>
#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;
static const KindType DebuggerInfo = 0b11001;
static const KindType TargetInfo = 0b11010;
static const KindType ClientInfo = 0b11100;
static const KindType CommandInfo = 0b11101;
static const KindType MiscInfo = 0b11110;
};

/// 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;

// 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;
};

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;
};

KindType getKind() const override { return LldbEntryKind::DebuggerInfo; }

static bool classof(const TelemetryInfo *T) {
if (T == nullptr)
return false;
return T->getKind() == LldbEntryKind::DebuggerInfo;
}

void serialize(Serializer &serializer) const override;
};

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;
};

// Entry from client (eg., SB-API)
struct ClientTelemetryInfo : public LldbBaseTelemetryInfo {
std::string request_name;
std::string error_msg;

ClientTelemetryInfo() = default;

ClientTelemetryInfo(const ClientTelemetryInfo &other) {
request_name = other.request_name;
error_msg = other.error_msg;
}

KindType getKind() const override { return LldbEntryKind::ClientInfo; }

static bool classof(const TelemetryInfo *T) {
if (T == nullptr)
return false;
return T->getKind() == LldbEntryKind::ClientInfo;
}

void serialize(Serializer &serializer) const override;
};

struct CommandTelemetryInfo : public LldbBaseTelemetryInfo {
Target *target_ptr;
CommandReturnObject *result;

// If the command is/can be associated with a target entry,
// this field contains that target's UUID.
// <EMPTY> otherwise.
std::string target_uuid;
std::string command_uuid;

// Eg., "breakpoint set"
std::string command_name;

// !!NOTE!!: The following fields may be omitted due to PII risk.
// (Configurable via the telemery::Config struct)
std::string original_command;
std::string args;

std::optional<ExitDescription> exit_desc;
lldb::ReturnStatus ret_status;

CommandTelemetryInfo() = default;

CommandTelemetryInfo(const CommandTelemetryInfo &other) {
target_uuid = other.target_uuid;
command_uuid = other.command_uuid;
command_name = other.command_name;
original_command = other.original_command;
args = other.args;
exit_desc = other.exit_desc;
ret_status = other.ret_status;
}

KindType getKind() const override { return LldbEntryKind::CommandInfo; }

static bool classof(const TelemetryInfo *T) {
if (T == nullptr)
return false;
return T->getKind() == LldbEntryKind::CommandInfo;
}

void serialize(Serializer &serializer) const override;
};

/// The "catch-all" entry to store a set of custom/non-standard
/// data.
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;
}

KindType getKind() const override { return LldbEntryKind::MiscInfo; }

static bool classof(const TelemetryInfo *T) {
if (T == nullptr)
return false;
return T->getKind() == LldbEntryKind::MiscInfo;
}

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:
/// Creates an instance of TelemetryManager.
/// This uses the plugin registry to find an instance:
/// - If a vendor supplies a implementation, it will use it.
/// - If not, it will either return a no-op instance or a basic
/// implementation for testing.
///
/// See also lldb_private::TelemetryVendor.
static std::unique_ptr<TelemetryManager>
CreateInstance(std::unique_ptr<llvm::telemetry::Config> config,
Debugger *debugger);

/// To be invoked upon LLDB startup.
virtual void LogStartup(DebuggerTelemetryInfo *entry);

/// To be invoked upon LLDB exit.
virtual void LogExit(DebuggerTelemetryInfo *entry);

/// To be invoked upon loading the main executable module.
/// We log in a fire-n-forget fashion so that if the load
/// crashes, we don't lose the entry.
virtual void LogMainExecutableLoadStart(TargetTelemetryInfo *entry);
virtual void LogMainExecutableLoadEnd(TargetTelemetryInfo *entry);

/// To be invoked upon process exit.
virtual void LogProcessExit(TargetTelemetryInfo *entry);

/// Invoked for each command
/// We log in a fire-n-forget fashion so that if the command execution
/// crashes, we don't lose the entry.
virtual void LogCommandStart(CommandTelemetryInfo *entry);
virtual void LogCommandEnd(CommandTelemetryInfo *entry);

/// For client (eg., SB API) to send telemetry entries.
virtual void
LogClientTelemetry(const lldb_private::StructuredDataImpl &entry);

virtual std::string GetNextUUID() {
return std::to_string(uuid_seed.fetch_add(1));
}

llvm::Error dispatch(TelemetryInfo *entry) override;
void addDestination(std::unique_ptr<Destination> destination) override;

protected:
TelemetryManager(std::unique_ptr<llvm::telemetry::Config> config,
Debugger *debugger);
TelemetryManager() = default;
virtual void CollectMiscBuildInfo();

private:
std::atomic<size_t> uuid_seed = 0;
std::unique_ptr<llvm::telemetry::Config> m_config;
Debugger *m_debugger;
const std::string m_session_uuid;
std::vector<std::unique_ptr<Destination>> m_destinations;
};

} // namespace lldb_private
#endif // LLDB_CORE_TELEMETRY_H
Loading