Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0d6a36d
[LLDB][Telemetry]Define TargetInfo for collecting data about a target
oontvoo Feb 19, 2025
19c6181
Merge branch 'llvm:main' into target
oontvoo Feb 24, 2025
f152b3b
introduce helper
oontvoo Feb 24, 2025
4f8555a
undo change
oontvoo Mar 3, 2025
a5bd22e
Merge branch 'main' into target
oontvoo Mar 3, 2025
bb22874
update interface
oontvoo Mar 3, 2025
f49c3e2
formatting
oontvoo Mar 3, 2025
3bd8897
remove unused
oontvoo Mar 3, 2025
d3cb8d8
formatting
oontvoo Mar 3, 2025
267345a
qual
oontvoo Mar 4, 2025
32d949b
use UUID for target_uuid
oontvoo Mar 5, 2025
5c6c83c
Merge branch 'llvm:main' into target
oontvoo Mar 5, 2025
39c39cc
Merge branch 'main' into target
oontvoo Mar 6, 2025
1fdf120
revert dup
oontvoo Mar 8, 2025
1ed73e7
Merge branch 'target' of github.com:oontvoo/llvm-project into target
oontvoo Mar 8, 2025
92e06fa
Merge branch 'main' into target
oontvoo Mar 8, 2025
aab5002
unused include
oontvoo Mar 8, 2025
31c63e0
Update Telemetry.h
oontvoo Mar 8, 2025
20c8f59
Update Telemetry.cpp
oontvoo Mar 8, 2025
9954083
reconcile with main
oontvoo Mar 8, 2025
55aa4ee
Merge branch 'target' of github.com:oontvoo/llvm-project into target
oontvoo Mar 8, 2025
c8ca5b8
format
oontvoo Mar 8, 2025
4783b57
Update lldb/include/lldb/Core/Telemetry.h
oontvoo Mar 11, 2025
ae73ebe
reformatting
oontvoo Mar 12, 2025
0a2505a
Addressed review comments:
oontvoo Mar 12, 2025
4d3d26e
...
oontvoo Mar 12, 2025
b1b7a50
addressed review comment
oontvoo Mar 13, 2025
f7be9c9
remove unused import
oontvoo Mar 13, 2025
41f0696
Merge branch 'llvm:main' into target
oontvoo Mar 18, 2025
5e99cc7
addressed review comments
oontvoo Mar 18, 2025
a709ac3
Update Telemetry.h
oontvoo Mar 18, 2025
220554a
Update Telemetry.cpp
oontvoo Mar 18, 2025
1ecbe48
Update CommandInterpreter.cpp
oontvoo Mar 18, 2025
1231bc2
Update Target.cpp
oontvoo Mar 18, 2025
5757b41
Merge branch 'llvm:main' into target
oontvoo Mar 18, 2025
a936e2e
Merge branch 'target' of github.com:oontvoo/llvm-project into target
oontvoo Mar 18, 2025
142097a
more fixing
oontvoo Mar 18, 2025
d297813
formating
oontvoo Mar 18, 2025
885675e
Merge branch 'main' into target
oontvoo Mar 18, 2025
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
101 changes: 79 additions & 22 deletions lldb/include/lldb/Core/Telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
Expand All @@ -25,6 +26,11 @@
#include <optional>
#include <string>

#include <functional>
#include <type_traits>
#include <unordered_map>
#include <utility>

namespace lldb_private {
namespace telemetry {

Expand All @@ -33,11 +39,14 @@ namespace telemetry {
// 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to say I'm liking this bitfield system less and less every time I see it.

// 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 DebuggerInfo = 0b11000100;
static const llvm::telemetry::KindType TargetInfo = 0b11001000;
};

/// Defines a convenient type for timestamp of various events.
Expand Down Expand Up @@ -66,6 +75,40 @@ struct LLDBBaseTelemetryInfo : public llvm::telemetry::TelemetryInfo {
void serialize(llvm::telemetry::Serializer &serializer) const override;
};

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

struct TargetInfo : public LLDBBaseTelemetryInfo {
lldb::ModuleSP exec_mod;

// The same as the executable-module's UUID.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The same as the executable-module's UUID.
/// The same as the executable-module's UUID.

std::string target_uuid;
std::string arch_name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string target_uuid;
std::string arch_name;
UUID target_uuid;
ArchSpec arch_name;


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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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


// Describes the exit of the executable module.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Describes the exit of the executable module.
/// Describes the exit of the executable module.

std::optional<ExitDescription> exit_desc;
TargetInfo() = default;

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

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

struct DebuggerInfo : public LLDBBaseTelemetryInfo {
std::string lldb_version;

Expand Down Expand Up @@ -99,15 +142,14 @@ class TelemetryManager : public llvm::telemetry::Manager {

static TelemetryManager *GetInstance();

static TelemetryManager *GetInstanceIfEnabled();

protected:
TelemetryManager(std::unique_ptr<llvm::telemetry::Config> config);

static void SetInstance(std::unique_ptr<TelemetryManager> manger);

private:
std::unique_ptr<llvm::telemetry::Config> m_config;

// Each instance of a TelemetryManager is assigned a unique ID.
const std::string m_id;

Expand All @@ -118,39 +160,54 @@ 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(llvm::unique_function<void(Info *info)> callback,
ScopedDispatcher(Debugger *debugger = nullptr) {
// Start the timer.
m_start_time = std::chrono::steady_clock::now();
debugger = debugger;
}
ScopedDispatcher(llvm::unique_function<void(Info *info)> final_callback,
Debugger *debugger = nullptr)
: m_callback(std::move(callback)) {
: m_final_callback(std::move(final_callback)) {
// Start the timer.
m_start_time = std::chrono::steady_clock::now();
m_info.debugger = debugger;
this->debugger = debugger;
}

void SetDebugger(Debugger *debugger) { m_info.debugger = debugger; }
void SetDebugger(Debugger *debugger) { this->debugger = debugger; }

~ScopedDispatcher() {
// If Telemetry is disabled (either at buildtime or runtime),
// then don't do anything.
TelemetryManager *manager = TelemetryManager::GetInstanceIfEnabled();
if (!manager)
return;
void DispatchOnExit(llvm::unique_function<void(Info *info)> final_callback) {
// We probably should not be overriding previously set cb.
assert(!m_final_callback);
m_final_callback = std::move(final_callback);
}

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);
void DispatchNow(llvm::unique_function<void(Info *info)> populate_fields_cb) {
TelemetryManager *manager = TelemetryManager::GetInstance();
if (!manager->GetConfig()->EnableTelemetry)
return;
Info info;
// Populate the common fields we know aboutl
info.start_time = m_start_time;
info.end_time = std::chrono::steady_clock::now();
info.debugger = debugger;
// The callback will set the rest.
populate_fields_cb(&info);
// And then we dispatch.
if (llvm::Error er = manager->dispatch(&m_info)) {
if (llvm::Error er = manager->dispatch(&info)) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Object), std::move(er),
"Failed to dispatch entry of type: {0}", m_info.getKind());
"Failed to dispatch entry of type: {0}", info.getKind());
}
}

~ScopedDispatcher() {
if (m_final_callback)
DispatchNow(std::move(m_final_callback));
}

private:
SteadyTimePoint m_start_time;
llvm::unique_function<void(Info *info)> m_callback;
Info m_info;
llvm::unique_function<void(Info *info)> m_final_callback;
Debugger *debugger;
};

} // namespace telemetry
Expand Down
60 changes: 46 additions & 14 deletions lldb/source/Core/Telemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#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>
Expand Down Expand Up @@ -67,6 +68,18 @@ void DebuggerInfo::serialize(Serializer &serializer) const {
serializer.write("is_exit_entry", is_exit_entry);
}

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

serializer.write("target_uuid", target_uuid);
serializer.write("arch_name", arch_name);
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<Config> config)
: m_config(std::move(config)), m_id(MakeUUID()) {}

Expand All @@ -81,26 +94,45 @@ llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) {

const Config *TelemetryManager::GetConfig() { return m_config.get(); }

std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr;
TelemetryManager *TelemetryManager::GetInstance() {
if (!Config::BuildTimeEnableTelemetry)
return nullptr;
return g_instance.get();
}
class NoOpTelemetryManager : public TelemetryManager {
public:
llvm::Error preDispatch(llvm::telemetry::TelemetryInfo *entry) override {
// Does nothing.
return llvm::Error::success();
}

explicit NoOpTelemetryManager()
: TelemetryManager(std::make_unique<::llvm::telemetry::Config>(
/*EnableTelemetry*/ false)) {}

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;
virtual llvm::StringRef GetInstanceName() const override {
return "NoOpTelemetryManager";
}

return nullptr;
llvm::Error dispatch(llvm::telemetry::TelemetryInfo *entry) override {
// Does nothing.
return llvm::Error::success();
}

static NoOpTelemetryManager *GetInstance() {
static std::unique_ptr<NoOpTelemetryManager> g_ins =
std::make_unique<NoOpTelemetryManager>();
return g_ins.get();
}
};

std::unique_ptr<TelemetryManager> TelemetryManager::g_instance = nullptr;
TelemetryManager *TelemetryManager::GetInstance() {
// If Telemetry is disabled or if there is no default instance, then use the
// NoOp manager. We use a dummy instance to avoid having to do nullchecks in
// various places.
if (!Config::BuildTimeEnableTelemetry || !g_instance)
return NoOpTelemetryManager::GetInstance();
return g_instance.get();
}

void TelemetryManager::SetInstance(std::unique_ptr<TelemetryManager> manager) {
if (Config::BuildTimeEnableTelemetry)
g_instance = std::move(manager);
g_instance = std::move(manager);
}

} // namespace telemetry
Expand Down
16 changes: 16 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 @@ -1064,6 +1065,21 @@ 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);
Debugger *debugger = &(GetTarget().GetDebugger());
telemetry::ScopedDispatcher<telemetry::TargetInfo> helper(debugger);
// Save the Module UUID since the Module might be gone by end of scope.
std::string target_uuid =
GetTarget().GetExecutableModule()->GetUUID().GetAsString();

helper.DispatchNow([&](telemetry::TargetInfo *info) {
info->target_uuid = target_uuid;
info->is_start_entry = true;
});

helper.DispatchOnExit([&](telemetry::TargetInfo *info) {
info->target_uuid = target_uuid;
info->exit_desc = {status, exit_string.str()};
});

Log *log(GetLog(LLDBLog::State | LLDBLog::Process));
LLDB_LOG(log, "(plugin = {0} status = {1} ({1:x8}), description=\"{2}\")",
Expand Down
14 changes: 14 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,23 @@ void Target::DidExec() {

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

if (executable_sp) {
helper.DispatchNow([&](telemetry::TargetInfo *info) {
info->exec_mod = executable_sp;
info->target_uuid = executable_sp->GetUUID().GetAsString();
info->arch_name = executable_sp->GetArchitecture().GetArchitectureName();
info->is_start_entry = true;
});

helper.DispatchOnExit([&](telemetry::TargetInfo *info) {
info->exec_mod = executable_sp;
info->target_uuid = executable_sp->GetUUID().GetAsString();
});

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