Index: lldb/include/lldb/Target/Target.h =================================================================== --- lldb/include/lldb/Target/Target.h +++ lldb/include/lldb/Target/Target.h @@ -1450,16 +1450,9 @@ static void ImageSearchPathsChanged(const PathMappingList &path_list, void *baton); - // Utilities for `statistics` command. -private: - Analytics m_analytics; - public: - void SetCollectingStats(bool v) { m_analytics.SetEnabled(v); } - - bool GetCollectingStats() { return m_analytics.IsEnabled(); } - - Analytics &GetAnalytics() { return m_analytics; } + void SetCollectingStats(bool v) { GetAnalytics()->SetEnabled(v); } + bool GetCollectingStats() { return GetAnalytics()->IsEnabled(); } private: /// Construct with optional file and arch. Index: lldb/include/lldb/Utility/Analytics.h =================================================================== --- lldb/include/lldb/Utility/Analytics.h +++ lldb/include/lldb/Utility/Analytics.h @@ -11,6 +11,7 @@ #include "lldb/Utility/StructuredData.h" +#include #include namespace lldb_private { @@ -39,11 +40,36 @@ std::unique_ptr GetAsStructuredData() const; + static void Initialize(); + static void Terminate(); + private: std::vector m_counters; bool m_collecting_analytics = false; }; +/// RAII helper which acquires an exlusive lock on the global Analytics +/// singleton on construction, and releases the lock on destruction. +class ExclusivelyLockedAnalytics { +public: + ExclusivelyLockedAnalytics(); + ~ExclusivelyLockedAnalytics(); + + ExclusivelyLockedAnalytics(ExclusivelyLockedAnalytics &&) = default; + + ExclusivelyLockedAnalytics & + operator=(ExclusivelyLockedAnalytics &&) = default; + + Analytics *operator->() const; + +private: + std::unique_lock m_guard; +}; + +/// Get a reference to the global Analytics singleton. This has UB when called +/// without first calling \ref Analytics::Initialize. +ExclusivelyLockedAnalytics GetAnalytics(); + } // namespace lldb_private #endif // LLDB_UTILITY_ANALYTICS_H Index: lldb/source/API/SBTarget.cpp =================================================================== --- lldb/source/API/SBTarget.cpp +++ lldb/source/API/SBTarget.cpp @@ -57,6 +57,7 @@ #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" +#include "lldb/Utility/Analytics.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/FileSpec.h" @@ -218,7 +219,7 @@ if (!target_sp) return LLDB_RECORD_RESULT(data); - data.m_impl_up->SetObjectSP(target_sp->GetAnalytics().GetAsStructuredData()); + data.m_impl_up->SetObjectSP(GetAnalytics()->GetAsStructuredData()); return LLDB_RECORD_RESULT(data); } Index: lldb/source/API/SystemInitializerFull.cpp =================================================================== --- lldb/source/API/SystemInitializerFull.cpp +++ lldb/source/API/SystemInitializerFull.cpp @@ -76,6 +76,9 @@ #define LLDB_PLUGIN(p) LLDB_PLUGIN_INITIALIZE(p); #include "Plugins/Plugins.def" + // Initialize analytics. + Analytics::Initialize(); + // Initialize plug-ins in core LLDB ProcessTrace::Initialize(); @@ -92,6 +95,9 @@ void SystemInitializerFull::Terminate() { Debugger::SettingsTerminate(); + // Terminate analytics. + Analytics::Terminate(); + // Terminate plug-ins in core LLDB ProcessTrace::Terminate(); Index: lldb/source/Commands/CommandObjectExpression.cpp =================================================================== --- lldb/source/Commands/CommandObjectExpression.cpp +++ lldb/source/Commands/CommandObjectExpression.cpp @@ -642,7 +642,6 @@ } Target &target = GetSelectedOrDummyTarget(); - Analytics &analytics = target.GetAnalytics(); if (EvaluateExpression(expr, result.GetOutputStream(), result.GetErrorStream(), result)) { @@ -660,11 +659,11 @@ fixed_command.append(m_fixed_expression); history.AppendString(fixed_command); } - analytics.Record(Metric::ExpressionSuccess); + GetAnalytics()->Record(Metric::ExpressionSuccess); return true; } - analytics.Record(Metric::ExpressionFailure); + GetAnalytics()->Record(Metric::ExpressionFailure); result.SetStatus(eReturnStatusFailed); return false; } Index: lldb/source/Commands/CommandObjectFrame.cpp =================================================================== --- lldb/source/Commands/CommandObjectFrame.cpp +++ lldb/source/Commands/CommandObjectFrame.cpp @@ -708,9 +708,8 @@ // Increment statistics. bool res = result.Succeeded(); - Target &target = GetSelectedOrDummyTarget(); - Analytics &analytics = target.GetAnalytics(); - analytics.Record(res ? Metric::FrameVarSuccess : Metric::FrameVarFailure); + GetAnalytics()->Record(res ? Metric::FrameVarSuccess + : Metric::FrameVarFailure); return res; } Index: lldb/source/Commands/CommandObjectStats.cpp =================================================================== --- lldb/source/Commands/CommandObjectStats.cpp +++ lldb/source/Commands/CommandObjectStats.cpp @@ -24,14 +24,14 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { - Target &target = GetSelectedOrDummyTarget(); + ExclusivelyLockedAnalytics analytics = GetAnalytics(); - if (target.GetCollectingStats()) { + if (analytics->IsEnabled()) { result.AppendError("statistics already enabled"); return false; } - target.SetCollectingStats(true); + analytics->SetEnabled(true); result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -48,14 +48,14 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { - Target &target = GetSelectedOrDummyTarget(); + ExclusivelyLockedAnalytics analytics = GetAnalytics(); - if (!target.GetCollectingStats()) { + if (!analytics->IsEnabled()) { result.AppendError("need to enable statistics before disabling them"); return false; } - target.SetCollectingStats(false); + analytics->SetEnabled(false); result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -71,8 +71,7 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { - Target &target = GetSelectedOrDummyTarget(); - target.GetAnalytics().Print(result.GetOutputStream()); + GetAnalytics()->Print(result.GetOutputStream()); result.SetStatus(eReturnStatusSuccessFinishResult); return true; } Index: lldb/source/Utility/Analytics.cpp =================================================================== --- lldb/source/Utility/Analytics.cpp +++ lldb/source/Utility/Analytics.cpp @@ -17,6 +17,9 @@ namespace lldb_private { +static std::unique_ptr g_analytics; +static std::mutex g_analytics_lock; + static unsigned GetNumberOfMetrics() { return static_cast(Metric::MaxID); } @@ -67,4 +70,22 @@ return metrics_up; } +void Analytics::Initialize() { g_analytics = std::make_unique(); } + +void Analytics::Terminate() { g_analytics.reset(); } + +ExclusivelyLockedAnalytics::ExclusivelyLockedAnalytics() { + m_guard = std::unique_lock(g_analytics_lock); +} + +ExclusivelyLockedAnalytics::~ExclusivelyLockedAnalytics() {} + +Analytics *ExclusivelyLockedAnalytics::operator->() const { + return g_analytics.get(); +} + +ExclusivelyLockedAnalytics GetAnalytics() { + return ExclusivelyLockedAnalytics(); +} + } // namespace lldb_private