Skip to content

Reapply LLDB-Telemetry TargetInfo branch (pr/127834) #132043

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

Merged
merged 8 commits into from
Mar 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
74 changes: 68 additions & 6 deletions lldb/include/lldb/Core/Telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
#include <atomic>
#include <chrono>
#include <ctime>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <utility>

namespace lldb_private {
namespace telemetry {
Expand All @@ -46,12 +49,18 @@ struct LLDBConfig : public ::llvm::telemetry::Config {
// Specifically:
// - Length: 8 bits
// - First two bits (MSB) must be 11 - the common prefix
// - Last two bits (LSB) are reserved for grand-children of LLDBTelemetryInfo
// If any of the subclass has descendents, those descendents
// must have their LLDBEntryKind in the similar form (ie., share common prefix)
// must have their LLDBEntryKind in the similar form (ie., share common prefix
// and differ by the last two bits)
struct LLDBEntryKind : public ::llvm::telemetry::EntryKind {
static const llvm::telemetry::KindType BaseInfo = 0b11000000;
static const llvm::telemetry::KindType CommandInfo = 0b11010000;
static const llvm::telemetry::KindType DebuggerInfo = 0b11000100;
// clang-format off
static const llvm::telemetry::KindType BaseInfo = 0b11000000;
static const llvm::telemetry::KindType CommandInfo = 0b11010000;
static const llvm::telemetry::KindType DebuggerInfo = 0b11001000;
static const llvm::telemetry::KindType ExecModuleInfo = 0b11000100;
static const llvm::telemetry::KindType ProcessExitInfo = 0b11001100;
// clang-format on
};

/// Defines a convenient type for timestamp of various events.
Expand Down Expand Up @@ -89,7 +98,7 @@ struct CommandInfo : public LLDBBaseTelemetryInfo {
/// session. Necessary because we'd send off an entry right before a command's
/// execution and another right after. This is to avoid losing telemetry if
/// the command does not execute successfully.
uint64_t command_id;
uint64_t command_id = 0;
/// The command name(eg., "breakpoint set")
std::string command_name;
/// These two fields are not collected by default due to PII risks.
Expand All @@ -116,7 +125,7 @@ struct CommandInfo : public LLDBBaseTelemetryInfo {

void serialize(llvm::telemetry::Serializer &serializer) const override;

static uint64_t GetNextId();
static uint64_t GetNextID();

private:
// We assign each command (in the same session) a unique id so that their
Expand Down Expand Up @@ -146,6 +155,59 @@ struct DebuggerInfo : public LLDBBaseTelemetryInfo {
void serialize(llvm::telemetry::Serializer &serializer) const override;
};

struct ExecutableModuleInfo : public LLDBBaseTelemetryInfo {
lldb::ModuleSP exec_mod;
/// The same as the executable-module's UUID.
UUID uuid;
/// PID of the process owned by this target.
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
/// The triple of this executable module.
std::string triple;

/// If true, this entry was emitted at the beginning of an event (eg., before
/// the executable is set). Otherwise, it was emitted at the end of an
/// event (eg., after the module and any dependency were loaded.)
bool is_start_entry = false;

ExecutableModuleInfo() = default;

llvm::telemetry::KindType getKind() const override {
return LLDBEntryKind::ExecModuleInfo;
}

static bool classof(const TelemetryInfo *T) {
// Subclasses of this is also acceptable
return (T->getKind() & LLDBEntryKind::ExecModuleInfo) ==
LLDBEntryKind::ExecModuleInfo;
}
void serialize(llvm::telemetry::Serializer &serializer) const override;
};

/// Describes an exit status.
struct ExitDescription {
int exit_code;
std::string description;
};

struct ProcessExitInfo : public LLDBBaseTelemetryInfo {
// The executable-module's UUID.
UUID module_uuid;
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
bool is_start_entry = false;
std::optional<ExitDescription> exit_desc;

llvm::telemetry::KindType getKind() const override {
return LLDBEntryKind::ProcessExitInfo;
}

static bool classof(const TelemetryInfo *T) {
// Subclasses of this is also acceptable
return (T->getKind() & LLDBEntryKind::ProcessExitInfo) ==
LLDBEntryKind::ProcessExitInfo;
}
void serialize(llvm::telemetry::Serializer &serializer) const override;
};

/// The base Telemetry manager instance in LLDB.
/// This class declares additional instrumentation points
/// applicable to LLDB.
Expand Down
25 changes: 23 additions & 2 deletions lldb/source/Core/Telemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,36 @@ void CommandInfo::serialize(Serializer &serializer) const {
serializer.write("error_data", error_data.value());
}

std::atomic<uint64_t> CommandInfo::g_command_id_seed = 1;
uint64_t CommandInfo::GetNextID() { return g_command_id_seed.fetch_add(1); }

void DebuggerInfo::serialize(Serializer &serializer) const {
LLDBBaseTelemetryInfo::serialize(serializer);

serializer.write("lldb_version", lldb_version);
serializer.write("is_exit_entry", is_exit_entry);
}

std::atomic<uint64_t> CommandInfo::g_command_id_seed = 0;
uint64_t CommandInfo::GetNextId() { return g_command_id_seed.fetch_add(1); }
void ExecutableModuleInfo::serialize(Serializer &serializer) const {
LLDBBaseTelemetryInfo::serialize(serializer);

serializer.write("uuid", uuid.GetAsString());
serializer.write("pid", pid);
serializer.write("triple", triple);
serializer.write("is_start_entry", is_start_entry);
}

void ProcessExitInfo::serialize(Serializer &serializer) const {
LLDBBaseTelemetryInfo::serialize(serializer);

serializer.write("module_uuid", module_uuid.GetAsString());
serializer.write("pid", pid);
serializer.write("is_start_entry", is_start_entry);
if (exit_desc.has_value()) {
serializer.write("exit_code", exit_desc->exit_code);
serializer.write("exit_desc", exit_desc->description);
}
}

TelemetryManager::TelemetryManager(std::unique_ptr<LLDBConfig> config)
: m_config(std::move(config)), m_id(MakeUUID()) {}
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Interpreter/CommandInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1891,7 +1891,7 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
telemetry::TelemetryManager::GetInstance()
->GetConfig()
->detailed_command_telemetry;
const int command_id = telemetry::CommandInfo::GetNextId();
const int command_id = telemetry::CommandInfo::GetNextID();

std::string command_string(command_line);
std::string original_command_string(command_string);
Expand Down
22 changes: 22 additions & 0 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Progress.h"
#include "lldb/Core/Telemetry.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/DynamicCheckerFunctions.h"
#include "lldb/Expression/UserExpression.h"
Expand Down Expand Up @@ -1066,6 +1067,27 @@ const char *Process::GetExitDescription() {
bool Process::SetExitStatus(int status, llvm::StringRef exit_string) {
// Use a mutex to protect setting the exit status.
std::lock_guard<std::mutex> guard(m_exit_status_mutex);
telemetry::ScopedDispatcher<telemetry::ProcessExitInfo> helper;

UUID module_uuid;
// Need this check because the pointer may not be valid at this point.
if (TargetSP target_sp = m_target_wp.lock()) {
helper.SetDebugger(&target_sp->GetDebugger());
if (ModuleSP mod = target_sp->GetExecutableModule())
module_uuid = mod->GetUUID();
}

helper.DispatchNow([&](telemetry::ProcessExitInfo *info) {
info->module_uuid = module_uuid;
info->pid = m_pid;
info->is_start_entry = true;
info->exit_desc = {status, exit_string.str()};
});

helper.DispatchOnExit([&](telemetry::ProcessExitInfo *info) {
info->module_uuid = module_uuid;
info->pid = m_pid;
});

Log *log(GetLog(LLDBLog::State | LLDBLog::Process));
LLDB_LOG(log, "(plugin = {0} status = {1} ({1:x8}), description=\"{2}\")",
Expand Down
21 changes: 21 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "lldb/Core/Section.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Core/Telemetry.h"
#include "lldb/DataFormatters/FormatterSection.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/ExpressionVariable.h"
Expand Down Expand Up @@ -1559,10 +1560,30 @@ void Target::DidExec() {

void Target::SetExecutableModule(ModuleSP &executable_sp,
LoadDependentFiles load_dependent_files) {
telemetry::ScopedDispatcher<telemetry::ExecutableModuleInfo> helper(
&m_debugger);
Log *log = GetLog(LLDBLog::Target);
ClearModules(false);

if (executable_sp) {
lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
if (ProcessSP proc = GetProcessSP())
pid = proc->GetID();

helper.DispatchNow([&](telemetry::ExecutableModuleInfo *info) {
info->exec_mod = executable_sp;
info->uuid = executable_sp->GetUUID();
info->pid = pid;
info->triple = executable_sp->GetArchitecture().GetTriple().getTriple();
info->is_start_entry = true;
});

helper.DispatchOnExit([&](telemetry::ExecutableModuleInfo *info) {
info->exec_mod = executable_sp;
info->uuid = executable_sp->GetUUID();
info->pid = pid;
});

ElapsedTime elapsed(m_stats.GetCreateTime());
LLDB_SCOPED_TIMERF("Target::SetExecutableModule (executable = '%s')",
executable_sp->GetFileSpec().GetPath().c_str());
Expand Down
Loading