Index: lldb/include/lldb/Target/Target.h =================================================================== --- lldb/include/lldb/Target/Target.h +++ lldb/include/lldb/Target/Target.h @@ -29,6 +29,7 @@ #include "lldb/Target/PathMappingList.h" #include "lldb/Target/SectionLoadHistory.h" #include "lldb/Target/ThreadSpec.h" +#include "lldb/Utility/Analytics.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/LLDBAssert.h" @@ -1451,23 +1452,14 @@ // Utilities for `statistics` command. private: - std::vector m_stats_storage; - bool m_collecting_stats = false; + Analytics m_analytics; public: - void SetCollectingStats(bool v) { m_collecting_stats = v; } + void SetCollectingStats(bool v) { m_analytics.SetEnabled(v); } - bool GetCollectingStats() { return m_collecting_stats; } + bool GetCollectingStats() { return m_analytics.IsEnabled(); } - void IncrementStats(lldb_private::StatisticKind key) { - if (!GetCollectingStats()) - return; - lldbassert(key < lldb_private::StatisticKind::StatisticMax && - "invalid statistics!"); - m_stats_storage[key] += 1; - } - - std::vector GetStatistics() { return m_stats_storage; } + Analytics &GetAnalytics() { return m_analytics; } private: /// Construct with optional file and arch. Index: lldb/include/lldb/Utility/Analytics.h =================================================================== --- /dev/null +++ lldb/include/lldb/Utility/Analytics.h @@ -0,0 +1,49 @@ +//===-- Analytics.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_UTILITY_ANALYTICS_H +#define LLDB_UTILITY_ANALYTICS_H + +#include "lldb/Utility/StructuredData.h" + +#include + +namespace lldb_private { + +class Stream; + +/// A kind of metric to collect. +enum class Metric : unsigned { +#define LLDB_METRIC_DEF(EnumName, Desc) EnumName, +#include "lldb/Utility/Metrics.def" + MaxID +}; + +/// Keep track of statistics. Data collection is off by default. +class Analytics { +public: + Analytics(); + + void SetEnabled(bool v) { m_collecting_analytics = v; } + + bool IsEnabled() const { return m_collecting_analytics; } + + void Record(Metric stat); + + void Print(Stream &stream) const; + + std::unique_ptr GetAsStructuredData() const; + +private: + std::vector m_counters; + bool m_collecting_analytics = false; +}; + +} // namespace lldb_private + +#endif // LLDB_UTILITY_ANALYTICS_H Index: lldb/include/lldb/Utility/Metrics.def =================================================================== --- /dev/null +++ lldb/include/lldb/Utility/Metrics.def @@ -0,0 +1,18 @@ +//===-- Statistics.def ------------------------------------------*- 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_METRIC_DEF +#error "Must define LLDB_METRIC_DEF(EnumName, Desc)." +#endif + +LLDB_METRIC_DEF(ExpressionSuccess, "Number of expr evaluation successes") +LLDB_METRIC_DEF(ExpressionFailure, "Number of expr evaluation failures") +LLDB_METRIC_DEF(FrameVarSuccess, "Number of frame var successes") +LLDB_METRIC_DEF(FrameVarFailure, "Number of frame var failures") + +#undef LLDB_METRIC_DEF Index: lldb/include/lldb/lldb-private-enumerations.h =================================================================== --- lldb/include/lldb/lldb-private-enumerations.h +++ lldb/include/lldb/lldb-private-enumerations.h @@ -212,33 +212,6 @@ AnyType = Any | Class | Struct | Union | Enum | Typedef }; -// Enumerations that can be used to specify the kind of metric we're looking at -// when collecting stats. -enum StatisticKind { - ExpressionSuccessful = 0, - ExpressionFailure = 1, - FrameVarSuccess = 2, - FrameVarFailure = 3, - StatisticMax = 4 -}; - - -inline std::string GetStatDescription(lldb_private::StatisticKind K) { - switch (K) { - case StatisticKind::ExpressionSuccessful: - return "Number of expr evaluation successes"; - case StatisticKind::ExpressionFailure: - return "Number of expr evaluation failures"; - case StatisticKind::FrameVarSuccess: - return "Number of frame var successes"; - case StatisticKind::FrameVarFailure: - return "Number of frame var failures"; - case StatisticKind::StatisticMax: - return ""; - } - llvm_unreachable("Statistic not registered!"); -} - } // namespace lldb_private namespace llvm { Index: lldb/include/lldb/module.modulemap =================================================================== --- lldb/include/lldb/module.modulemap +++ lldb/include/lldb/module.modulemap @@ -130,6 +130,8 @@ umbrella "Utility" module * { export * } + textual header "Utility/Statistics.def" + module lldb_defines { header "lldb-defines.h" export * } module lldb_enumerations { header "lldb-enumerations.h" export * } module lldb_forward { header "lldb-forward.h" export * } Index: lldb/source/API/SBTarget.cpp =================================================================== --- lldb/source/API/SBTarget.cpp +++ lldb/source/API/SBTarget.cpp @@ -218,16 +218,7 @@ if (!target_sp) return LLDB_RECORD_RESULT(data); - auto stats_up = std::make_unique(); - int i = 0; - for (auto &Entry : target_sp->GetStatistics()) { - std::string Desc = lldb_private::GetStatDescription( - static_cast(i)); - stats_up->AddIntegerItem(Desc, Entry); - i += 1; - } - - data.m_impl_up->SetObjectSP(std::move(stats_up)); + data.m_impl_up->SetObjectSP(target_sp->GetAnalytics().GetAsStructuredData()); return LLDB_RECORD_RESULT(data); } Index: lldb/source/Commands/CommandObjectExpression.cpp =================================================================== --- lldb/source/Commands/CommandObjectExpression.cpp +++ lldb/source/Commands/CommandObjectExpression.cpp @@ -642,6 +642,7 @@ } Target &target = GetSelectedOrDummyTarget(); + Analytics &analytics = target.GetAnalytics(); if (EvaluateExpression(expr, result.GetOutputStream(), result.GetErrorStream(), result)) { @@ -659,13 +660,11 @@ fixed_command.append(m_fixed_expression); history.AppendString(fixed_command); } - // Increment statistics to record this expression evaluation success. - target.IncrementStats(StatisticKind::ExpressionSuccessful); + analytics.Record(Metric::ExpressionSuccess); return true; } - // Increment statistics to record this expression evaluation failure. - target.IncrementStats(StatisticKind::ExpressionFailure); + analytics.Record(Metric::ExpressionFailure); result.SetStatus(eReturnStatusFailed); return false; } Index: lldb/source/Commands/CommandObjectFrame.cpp =================================================================== --- lldb/source/Commands/CommandObjectFrame.cpp +++ lldb/source/Commands/CommandObjectFrame.cpp @@ -709,10 +709,8 @@ // Increment statistics. bool res = result.Succeeded(); Target &target = GetSelectedOrDummyTarget(); - if (res) - target.IncrementStats(StatisticKind::FrameVarSuccess); - else - target.IncrementStats(StatisticKind::FrameVarFailure); + Analytics &analytics = target.GetAnalytics(); + analytics.Record(res ? Metric::FrameVarSuccess : Metric::FrameVarFailure); return res; } Index: lldb/source/Commands/CommandObjectStats.cpp =================================================================== --- lldb/source/Commands/CommandObjectStats.cpp +++ lldb/source/Commands/CommandObjectStats.cpp @@ -72,17 +72,7 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target &target = GetSelectedOrDummyTarget(); - - uint32_t i = 0; - for (auto &stat : target.GetStatistics()) { - result.AppendMessageWithFormat( - "%s : %u\n", - lldb_private::GetStatDescription( - static_cast(i)) - .c_str(), - stat); - i += 1; - } + target.GetAnalytics().Print(result.GetOutputStream()); result.SetStatus(eReturnStatusSuccessFinishResult); return true; } Index: lldb/source/Target/Target.cpp =================================================================== --- lldb/source/Target/Target.cpp +++ lldb/source/Target/Target.cpp @@ -95,14 +95,10 @@ m_watchpoint_list(), m_process_sp(), m_search_filter_sp(), m_image_search_paths(ImageSearchPathsChanged, this), m_source_manager_up(), m_stop_hooks(), m_stop_hook_next_id(0), - m_latest_stop_hook_id(0), - m_valid(true), m_suppress_stop_hooks(false), + m_latest_stop_hook_id(0), m_valid(true), m_suppress_stop_hooks(false), m_is_dummy_target(is_dummy_target), m_frame_recognizer_manager_up( - std::make_unique()), - m_stats_storage(static_cast(StatisticKind::StatisticMax)) - -{ + std::make_unique()) { SetEventName(eBroadcastBitBreakpointChanged, "breakpoint-changed"); SetEventName(eBroadcastBitModulesLoaded, "modules-loaded"); SetEventName(eBroadcastBitModulesUnloaded, "modules-unloaded"); Index: lldb/source/Utility/Analytics.cpp =================================================================== --- /dev/null +++ lldb/source/Utility/Analytics.cpp @@ -0,0 +1,70 @@ +//===-- Analytics.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/Utility/Analytics.h" + +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StructuredData.h" + +#include +#include +#include + +namespace lldb_private { + +static unsigned GetNumberOfMetrics() { + return static_cast(Metric::MaxID); +} + +static unsigned GetCounterIndexForMetric(Metric S) { + assert(S != Metric::MaxID && "invalid metric"); + return static_cast(S); +} + +static Metric GetMetricForCounterIndex(unsigned index) { + assert(index < GetNumberOfMetrics() && "invalid metric"); + return static_cast(index); +} + +static const char *GetMetricDescription(Metric S) { + switch (S) { +#define LLDB_METRIC_DEF(EnumName, Desc) \ + case Metric::EnumName: \ + return Desc; +#include "lldb/Utility/Metrics.def" + case Metric::MaxID: + llvm_unreachable("invalid metric"); + } +} + +Analytics::Analytics() { m_counters.resize(GetNumberOfMetrics()); } + +void Analytics::Record(Metric metric) { + if (!m_collecting_analytics) + return; + ++m_counters[GetCounterIndexForMetric(metric)]; +} + +void Analytics::Print(Stream &stream) const { + for (unsigned metric_id = 0; metric_id < GetNumberOfMetrics(); ++metric_id) { + Metric s = GetMetricForCounterIndex(metric_id); + stream.Printf("%s : %u\n", GetMetricDescription(s), m_counters[metric_id]); + } +} + +std::unique_ptr +Analytics::GetAsStructuredData() const { + auto metrics_up = std::make_unique(); + for (unsigned metric_id = 0; metric_id < GetNumberOfMetrics(); ++metric_id) { + Metric s = GetMetricForCounterIndex(metric_id); + metrics_up->AddIntegerItem(GetMetricDescription(s), m_counters[metric_id]); + } + return metrics_up; +} + +} // namespace lldb_private Index: lldb/source/Utility/CMakeLists.txt =================================================================== --- lldb/source/Utility/CMakeLists.txt +++ lldb/source/Utility/CMakeLists.txt @@ -24,6 +24,7 @@ endif() add_lldb_library(lldbUtility + Analytics.cpp ArchSpec.cpp Args.cpp Baton.cpp Index: lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py =================================================================== --- lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py +++ lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py @@ -27,7 +27,7 @@ stream = lldb.SBStream() res = stats.GetAsJSON(stream) stats_json = sorted(json.loads(stream.GetData())) - self.assertEqual(len(stats_json), 4) + self.assertEqual(len(stats_json), 4, stream.GetData()) self.assertIn("Number of expr evaluation failures", stats_json) self.assertIn("Number of expr evaluation successes", stats_json) self.assertIn("Number of frame var failures", stats_json)