llvm-project/lldb/source/Target/Statistics.cpp
GeorgeHuyubo 070a4ae2f9
Add symbol locator time for each module in statistics (#134563)
In statistics, add locate time for each module in statistics, we time
the PluginManager::LocateExecutableSymbolFile and
PluginManager::LocateExecutableObjectFile call, save the duration for
the succeeded symbol locator plugin in the Module class as a map.
New key being added:
Module level: "_symbolLocatorTime_"
Summary level: "_totalSymbolLocatorTime_"
which would be a map of symbol_locator_plugin_name to time.

Sample statistic dump output after this change:

```
Command: statistics dump
===============Output===============
{
  "commands": {
    "command container add": 1,
    "command script add": 51,
    "command script import": 59,
    "statistics dump": 1,
    "target create": 1,
    "type summary add": 36,
    "type synthetic add": 21
  },
  "memory": {
    "strings": {
      "bytesTotal": 2801664,
      "bytesUnused": 1704256,
      "bytesUsed": 1097408
    }
  },
  "modules": [
    {
      "debugInfoByteSize": 244927,
      "debugInfoEnabled": true,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0.61934599999999995,
      "debugInfoParseTime": 0.00033100000000000002,
      "identifier": 94868115726768,
      "path": "/home/hyubo/.cache/llvm-debuginfod/client/llvmcache-720c9a0f5ba8b460a1524a25597226f0fa551f71-c4crasher",
      "symbolLocatorTime": {
        "debuginfod": 1.4547020000000002
      },
      "symbolTableIndexTime": 0.0035370000000000002,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.0055040000000000002,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--linux",
      "uuid": "720C9A0F-5BA8-B460-A152-4A25597226F0-FA551F71"
    },
    {
      "debugInfoByteSize": 0,
      "debugInfoEnabled": false,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0,
      "debugInfoParseTime": 0,
      "identifier": 94868111142256,
      "path": "[vdso](0x00007ffd41c59000)",
      "symbolLocatorTime": {
        "debuginfod": 0.80597700000000005
      },
      "symbolTableIndexTime": 2.8e-05,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.00037300000000000001,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--linux",
      "uuid": "4D1F38BD-BD34-DFB3-C9A5-B49A2A912219-AC713763"
    },
    {
      "debugInfoByteSize": 0,
      "debugInfoEnabled": false,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0,
      "debugInfoParseTime": 0,
      "identifier": 94868116162096,
      "path": "/usr/local/fbcode/platform010/lib/libc.so.6",
      "symbolLocatorTime": {
        "debuginfod": 0.286356
      },
      "symbolTableIndexTime": 0.0091780000000000004,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.081841999999999998,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--linux",
      "uuid": "ACE9DF01-8872-3A35-6D14-3C92527EF739-4BE32C75"
    },
    {
      "debugInfoByteSize": 0,
      "debugInfoEnabled": false,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0,
      "debugInfoParseTime": 0,
      "identifier": 94868111990032,
      "path": "/usr/local/fbcode/platform010/lib/libm.so.6",
      "symbolLocatorTime": {
        "debuginfod": 0.63356699999999999
      },
      "symbolTableIndexTime": 0.0023960000000000001,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.021706,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--linux",
      "uuid": "85932B54-0DE7-4FC1-23B0-FB09AD1A5A61-8E1098B7"
    },
    {
      "debugInfoByteSize": 0,
      "debugInfoEnabled": false,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0,
      "debugInfoParseTime": 0,
      "identifier": 94868116399488,
      "path": "/usr/local/fbcode/platform010/lib/libmvec.so.1",
      "symbolLocatorTime": {
        "debuginfod": 0.66705099999999995
      },
      "symbolTableIndexTime": 0.00053700000000000004,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.0034429999999999999,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--linux",
      "uuid": "4537CA22-8E6E-495B-7A03-FC2CEDCAD71C-8A7B2067"
    },
    {
      "debugInfoByteSize": 0,
      "debugInfoEnabled": false,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0,
      "debugInfoParseTime": 0,
      "identifier": 94868111778368,
      "path": "/usr/local/fbcode/platform010/lib/libatomic.so.1",
      "symbolLocatorTime": {
        "debuginfod": 0.83268299999999995
      },
      "symbolTableIndexTime": 0.000243,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.0026640000000000001,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--",
      "uuid": "F90F9111-BBD1-C2A9-972A-34EB75ABE62E-3BDED9CF"
    },
    {
      "debugInfoByteSize": 0,
      "debugInfoEnabled": false,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0,
      "debugInfoParseTime": 0,
      "identifier": 94868116403264,
      "path": "/usr/local/fbcode/platform010/lib/libgcc_s.so.1",
      "symbolLocatorTime": {
        "debuginfod": 0.58871499999999999
      },
      "symbolTableIndexTime": 0.000292,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.0033,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--",
      "uuid": "1C715A92-40BE-BE95-E148-1B401749BAB8-15D09F9D"
    },
    {
      "debugInfoByteSize": 0,
      "debugInfoEnabled": false,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0,
      "debugInfoParseTime": 0,
      "identifier": 94868113225328,
      "path": "/usr/local/fbcode/platform010/lib/libstdc++.so.6",
      "symbolLocatorTime": {
        "debuginfod": 0.76993400000000001
      },
      "symbolTableIndexTime": 0.042455,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.081374000000000002,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--",
      "uuid": "C9DAEE53-F607-981B-6BED-F2042833BFC7-71A1E66C"
    },
    {
      "debugInfoByteSize": 0,
      "debugInfoEnabled": false,
      "debugInfoHadIncompleteTypes": false,
      "debugInfoHadVariableErrors": false,
      "debugInfoIndexLoadedFromCache": false,
      "debugInfoIndexSavedToCache": false,
      "debugInfoIndexTime": 0,
      "debugInfoParseTime": 0,
      "identifier": 94868113600960,
      "path": "/usr/local/fbcode/platform010/lib/ld.so",
      "symbolLocatorTime": {
        "debuginfod": 0.48382199999999997
      },
      "symbolTableIndexTime": 0.00054799999999999998,
      "symbolTableLoadedFromCache": false,
      "symbolTableParseTime": 0.0057219999999999997,
      "symbolTableSavedToCache": false,
      "symbolTableStripped": false,
      "triple": "x86_64--linux",
      "uuid": "CCA86CF4-E4FF-42C8-7056-2F7D8B83AEE0-530B4095"
    }
  ],
  "targets": [
    {
      "breakpoints": [],
      "dyldPluginName": "dump-modulelist-dyld",
      "expressionEvaluation": {
        "failures": 0,
        "successes": 0
      },
      "frameVariable": {
        "failures": 0,
        "successes": 0
      },
      "mismatchCoredumpModuleCount": 0,
      "moduleIdentifiers": [
        94868115726768,
        94868111142256,
        94868116162096,
        94868111990032,
        94868116399488,
        94868111778368,
        94868116403264,
        94868113225328,
        94868113600960
      ],
      "signals": [
        {
          "SIGABRT": 1
        }
      ],
      "sourceMapDeduceCount": 0,
      "sourceRealpathAttemptCount": 0,
      "sourceRealpathCompatibleCount": 0,
      "stopCount": 1,
      "summaryProviderStatistics": [],
      "targetCreateTime": 4.1999999999999998e-05,
      "totalBreakpointResolveTime": 0,
      "totalSharedLibraryEventHitCount": 0
    }
  ],
  "totalDebugInfoByteSize": 244927,
  "totalDebugInfoEnabled": 1,
  "totalDebugInfoIndexLoadedFromCache": 0,
  "totalDebugInfoIndexSavedToCache": 0,
  "totalDebugInfoIndexTime": 0.61934599999999995,
  "totalDebugInfoParseTime": 0.00033100000000000002,
  "totalModuleCount": 9,
  "totalModuleCountHasDebugInfo": 1,
  "totalModuleCountWithIncompleteTypes": 0,
  "totalModuleCountWithVariableErrors": 0,
  "totalSymbolLocatorTime": {
    "debuginfod": 6.5228070000000002
  },
  "totalSymbolTableIndexTime": 0.059214000000000003,
  "totalSymbolTableParseTime": 0.205928,
  "totalSymbolTableStripped": 0,
  "totalSymbolTablesLoadedFromCache": 0,
  "totalSymbolTablesSavedToCache": 0,
  "transcript": [
    {
      "command": "symsrv",
      "commandArguments": "",
      "commandName": "symsrv",
      "durationInSeconds": 0.00069099999999999999,
      "error": "",
      "output": "",
      "timestampInEpochSeconds": 1744934015
    },
    {
      "command": "settings set symbols.enable-external-lookup true",
      "commandArguments": "symbols.enable-external-lookup true",
      "commandName": "settings set",
      "durationInSeconds": 4.1999999999999998e-05,
      "error": "",
      "output": "",
      "timestampInEpochSeconds": 1744934015
    },
    {
      "command": "settings insert-before plugin.symbol-locator.debuginfod.server-urls 0 https://our.intern.facebook.com/intern/debuginfod",
      "commandArguments": "plugin.symbol-locator.debuginfod.server-urls 0 https://our.intern.facebook.com/intern/debuginfod",
      "commandName": "settings insert-before",
      "durationInSeconds": 5.5999999999999999e-05,
      "error": "",
      "output": "",
      "timestampInEpochSeconds": 1744934015
    },
    {
      "command": "target create --core \"/var/tmp/cores/c4crasher.crasher.1576894\"",
      "commandArguments": "--core \"/var/tmp/cores/c4crasher.crasher.1576894\"",
      "commandName": "target create",
      "durationInSeconds": 6.7297630000000002,
      "error": "",
      "output": "Core file '/var/tmp/cores/c4crasher.crasher.1576894' (x86_64) was loaded.\n",
      "timestampInEpochSeconds": 1744934017
    },
    {
      "command": "fbpaste statistics dump",
      "commandArguments": "statistics dump",
      "commandName": "fbpaste",
      "timestampInEpochSeconds": 1744934055
    },
    {
      "command": "statistics dump",
      "commandArguments": "",
      "commandName": "statistics dump",
      "timestampInEpochSeconds": 1744934055
    }
  ]
}

```

Co-authored-by: George Hu <georgehuyubo@gmail.com>
2025-04-25 10:43:17 -07:00

519 lines
21 KiB
C++

//===-- Statistics.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/Target/Statistics.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
using namespace llvm;
static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
const std::string &str) {
if (str.empty())
return;
if (LLVM_LIKELY(llvm::json::isUTF8(str)))
obj.try_emplace(key, str);
else
obj.try_emplace(key, llvm::json::fixUTF8(str));
}
json::Value StatsSuccessFail::ToJSON() const {
return json::Object{{"successes", successes}, {"failures", failures}};
}
static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {
StatsDuration::Duration elapsed =
end.time_since_epoch() - start.time_since_epoch();
return elapsed.count();
}
void TargetStats::CollectStats(Target &target) {
m_module_identifiers.clear();
for (ModuleSP module_sp : target.GetImages().Modules())
m_module_identifiers.emplace_back((intptr_t)module_sp.get());
}
json::Value ModuleStats::ToJSON() const {
json::Object module;
EmplaceSafeString(module, "path", path);
EmplaceSafeString(module, "uuid", uuid);
EmplaceSafeString(module, "triple", triple);
module.try_emplace("identifier", identifier);
module.try_emplace("symbolTableParseTime", symtab_parse_time);
module.try_emplace("symbolTableIndexTime", symtab_index_time);
module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache);
module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache);
module.try_emplace("debugInfoParseTime", debug_parse_time);
module.try_emplace("debugInfoIndexTime", debug_index_time);
module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);
module.try_emplace("debugInfoIndexLoadedFromCache",
debug_info_index_loaded_from_cache);
module.try_emplace("debugInfoIndexSavedToCache",
debug_info_index_saved_to_cache);
module.try_emplace("debugInfoEnabled", debug_info_enabled);
module.try_emplace("debugInfoHadVariableErrors",
debug_info_had_variable_errors);
module.try_emplace("debugInfoHadIncompleteTypes",
debug_info_had_incomplete_types);
module.try_emplace("symbolTableStripped", symtab_stripped);
module.try_emplace("symbolTableSymbolCount", symtab_symbol_count);
module.try_emplace("symbolsLoaded", num_symbols_loaded);
if (!symbol_locator_time.map.empty()) {
json::Object obj;
for (const auto &entry : symbol_locator_time.map)
obj.try_emplace(entry.first().str(), entry.second);
module.try_emplace("symbolLocatorTime", std::move(obj));
}
if (!symfile_path.empty())
module.try_emplace("symbolFilePath", symfile_path);
if (!symfile_modules.empty()) {
json::Array symfile_ids;
for (const auto symfile_id: symfile_modules)
symfile_ids.emplace_back(symfile_id);
module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids));
}
if (!type_system_stats.empty()) {
json::Array type_systems;
for (const auto &entry : type_system_stats) {
json::Object obj;
obj.try_emplace(entry.first().str(), entry.second);
type_systems.emplace_back(std::move(obj));
}
module.try_emplace("typeSystemInfo", std::move(type_systems));
}
return module;
}
llvm::json::Value ConstStringStats::ToJSON() const {
json::Object obj;
obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal());
obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed());
obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused());
return obj;
}
json::Value
TargetStats::ToJSON(Target &target,
const lldb_private::StatisticsOptions &options) {
json::Object target_metrics_json;
ProcessSP process_sp = target.GetProcessSP();
const bool summary_only = options.GetSummaryOnly();
const bool include_modules = options.GetIncludeModules();
if (!summary_only) {
CollectStats(target);
json::Array json_module_uuid_array;
for (auto module_identifier : m_module_identifiers)
json_module_uuid_array.emplace_back(module_identifier);
target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON());
target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON());
if (include_modules)
target_metrics_json.try_emplace("moduleIdentifiers",
std::move(json_module_uuid_array));
if (m_launch_or_attach_time && m_first_private_stop_time) {
double elapsed_time =
elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);
target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);
}
if (m_launch_or_attach_time && m_first_public_stop_time) {
double elapsed_time =
elapsed(*m_launch_or_attach_time, *m_first_public_stop_time);
target_metrics_json.try_emplace("firstStopTime", elapsed_time);
}
target_metrics_json.try_emplace("targetCreateTime",
m_create_time.get().count());
json::Array breakpoints_array;
double totalBreakpointResolveTime = 0.0;
// Report both the normal breakpoint list and the internal breakpoint list.
for (int i = 0; i < 2; ++i) {
BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
std::unique_lock<std::recursive_mutex> lock;
breakpoints.GetListMutex(lock);
size_t num_breakpoints = breakpoints.GetSize();
for (size_t i = 0; i < num_breakpoints; i++) {
Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
breakpoints_array.push_back(bp->GetStatistics());
totalBreakpointResolveTime += bp->GetResolveTime().count();
}
}
target_metrics_json.try_emplace("breakpoints",
std::move(breakpoints_array));
target_metrics_json.try_emplace("totalBreakpointResolveTime",
totalBreakpointResolveTime);
if (process_sp) {
UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
if (unix_signals_sp)
target_metrics_json.try_emplace(
"signals", unix_signals_sp->GetHitCountStatistics());
}
}
// Counting "totalSharedLibraryEventHitCount" from breakpoints of kind
// "shared-library-event".
{
uint32_t shared_library_event_breakpoint_hit_count = 0;
// The "shared-library-event" is only found in the internal breakpoint list.
BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true);
std::unique_lock<std::recursive_mutex> lock;
breakpoints.GetListMutex(lock);
size_t num_breakpoints = breakpoints.GetSize();
for (size_t i = 0; i < num_breakpoints; i++) {
Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
if (strcmp(bp->GetBreakpointKind(), "shared-library-event") == 0)
shared_library_event_breakpoint_hit_count += bp->GetHitCount();
}
target_metrics_json.try_emplace("totalSharedLibraryEventHitCount",
shared_library_event_breakpoint_hit_count);
}
if (process_sp) {
uint32_t stop_id = process_sp->GetStopID();
target_metrics_json.try_emplace("stopCount", stop_id);
llvm::StringRef dyld_plugin_name;
if (process_sp->GetDynamicLoader())
dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName();
target_metrics_json.try_emplace("dyldPluginName", dyld_plugin_name);
}
target_metrics_json.try_emplace("sourceMapDeduceCount",
m_source_map_deduce_count);
target_metrics_json.try_emplace("sourceRealpathAttemptCount",
m_source_realpath_attempt_count);
target_metrics_json.try_emplace("sourceRealpathCompatibleCount",
m_source_realpath_compatible_count);
target_metrics_json.try_emplace("summaryProviderStatistics",
target.GetSummaryStatisticsCache().ToJSON());
return target_metrics_json;
}
void TargetStats::Reset(Target &target) {
m_launch_or_attach_time.reset();
m_first_private_stop_time.reset();
m_first_public_stop_time.reset();
// Report both the normal breakpoint list and the internal breakpoint list.
for (int i = 0; i < 2; ++i) {
BreakpointList &breakpoints = target.GetBreakpointList(i == 1);
std::unique_lock<std::recursive_mutex> lock;
breakpoints.GetListMutex(lock);
size_t num_breakpoints = breakpoints.GetSize();
for (size_t i = 0; i < num_breakpoints; i++) {
Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();
bp->ResetStatistics();
}
}
target.GetSummaryStatisticsCache().Reset();
}
void TargetStats::SetLaunchOrAttachTime() {
m_launch_or_attach_time = StatsClock::now();
m_first_private_stop_time = std::nullopt;
}
void TargetStats::SetFirstPrivateStopTime() {
// Launching and attaching has many paths depending on if synchronous mode
// was used or if we are stopping at the entry point or not. Only set the
// first stop time if it hasn't already been set.
if (!m_first_private_stop_time)
m_first_private_stop_time = StatsClock::now();
}
void TargetStats::SetFirstPublicStopTime() {
// Launching and attaching has many paths depending on if synchronous mode
// was used or if we are stopping at the entry point or not. Only set the
// first stop time if it hasn't already been set.
if (!m_first_public_stop_time)
m_first_public_stop_time = StatsClock::now();
}
void TargetStats::IncreaseSourceMapDeduceCount() {
++m_source_map_deduce_count;
}
void TargetStats::IncreaseSourceRealpathAttemptCount(uint32_t count) {
m_source_realpath_attempt_count += count;
}
void TargetStats::IncreaseSourceRealpathCompatibleCount(uint32_t count) {
m_source_realpath_compatible_count += count;
}
bool DebuggerStats::g_collecting_stats = false;
void DebuggerStats::ResetStatistics(Debugger &debugger, Target *target) {
std::lock_guard<std::recursive_mutex> guard(
Module::GetAllocationModuleCollectionMutex());
const uint64_t num_modules = target != nullptr
? target->GetImages().GetSize()
: Module::GetNumberAllocatedModules();
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
: Module::GetAllocatedModuleAtIndex(image_idx);
if (module == nullptr)
continue;
module->ResetStatistics();
}
if (target)
target->ResetStatistics();
else {
for (const auto &target : debugger.GetTargetList().Targets())
target->ResetStatistics();
}
}
llvm::json::Value DebuggerStats::ReportStatistics(
Debugger &debugger, Target *target,
const lldb_private::StatisticsOptions &options) {
const bool summary_only = options.GetSummaryOnly();
const bool load_all_debug_info = options.GetLoadAllDebugInfo();
const bool include_targets = options.GetIncludeTargets();
const bool include_modules = options.GetIncludeModules();
const bool include_transcript = options.GetIncludeTranscript();
json::Array json_targets;
json::Array json_modules;
StatisticsMap symbol_locator_total_time;
double symtab_parse_time = 0.0;
double symtab_index_time = 0.0;
double debug_parse_time = 0.0;
double debug_index_time = 0.0;
uint32_t symtabs_loaded = 0;
uint32_t symtabs_loaded_from_cache = 0;
uint32_t symtabs_saved_to_cache = 0;
uint32_t debug_index_loaded = 0;
uint32_t debug_index_saved = 0;
uint64_t debug_info_size = 0;
std::vector<ModuleStats> modules;
std::lock_guard<std::recursive_mutex> guard(
Module::GetAllocationModuleCollectionMutex());
const uint64_t num_modules = target != nullptr
? target->GetImages().GetSize()
: Module::GetNumberAllocatedModules();
uint32_t num_debug_info_enabled_modules = 0;
uint32_t num_modules_has_debug_info = 0;
uint32_t num_modules_with_variable_errors = 0;
uint32_t num_modules_with_incomplete_types = 0;
uint32_t num_stripped_modules = 0;
uint32_t symtab_symbol_count = 0;
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
: Module::GetAllocatedModuleAtIndex(image_idx);
ModuleStats module_stat;
module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();
module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();
module_stat.symbol_locator_time = module->GetSymbolLocatorStatistics();
symbol_locator_total_time.merge(module_stat.symbol_locator_time);
Symtab *symtab = module->GetSymtab(/*can_create=*/false);
if (symtab) {
module_stat.symtab_symbol_count = symtab->GetNumSymbols();
symtab_symbol_count += module_stat.symtab_symbol_count;
++symtabs_loaded;
module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();
if (module_stat.symtab_loaded_from_cache)
++symtabs_loaded_from_cache;
module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();
if (module_stat.symtab_saved_to_cache)
++symtabs_saved_to_cache;
}
SymbolFile *sym_file = module->GetSymbolFile(/*can_create=*/false);
if (sym_file) {
if (!summary_only) {
if (sym_file->GetObjectFile() != module->GetObjectFile())
module_stat.symfile_path =
sym_file->GetObjectFile()->GetFileSpec().GetPath();
ModuleList symbol_modules = sym_file->GetDebugInfoModules();
for (const auto &symbol_module : symbol_modules.Modules())
module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
}
module_stat.debug_info_index_loaded_from_cache =
sym_file->GetDebugInfoIndexWasLoadedFromCache();
if (module_stat.debug_info_index_loaded_from_cache)
++debug_index_loaded;
module_stat.debug_info_index_saved_to_cache =
sym_file->GetDebugInfoIndexWasSavedToCache();
if (module_stat.debug_info_index_saved_to_cache)
++debug_index_saved;
module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();
module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();
module_stat.debug_info_size =
sym_file->GetDebugInfoSize(load_all_debug_info);
module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();
if (module_stat.symtab_stripped)
++num_stripped_modules;
module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() &&
module_stat.debug_info_size > 0;
module_stat.debug_info_had_variable_errors =
sym_file->GetDebugInfoHadFrameVariableErrors();
if (module_stat.debug_info_enabled)
++num_debug_info_enabled_modules;
if (module_stat.debug_info_size > 0)
++num_modules_has_debug_info;
if (module_stat.debug_info_had_variable_errors)
++num_modules_with_variable_errors;
}
symtab_parse_time += module_stat.symtab_parse_time;
symtab_index_time += module_stat.symtab_index_time;
debug_parse_time += module_stat.debug_parse_time;
debug_index_time += module_stat.debug_index_time;
debug_info_size += module_stat.debug_info_size;
module->ForEachTypeSystem([&](lldb::TypeSystemSP ts) {
if (auto stats = ts->ReportStatistics())
module_stat.type_system_stats.insert({ts->GetPluginName(), *stats});
if (ts->GetHasForcefullyCompletedTypes())
module_stat.debug_info_had_incomplete_types = true;
return true;
});
if (module_stat.debug_info_had_incomplete_types)
++num_modules_with_incomplete_types;
if (include_modules) {
module_stat.identifier = (intptr_t)module;
module_stat.path = module->GetFileSpec().GetPath();
if (ConstString object_name = module->GetObjectName()) {
module_stat.path.append(1, '(');
module_stat.path.append(object_name.GetStringRef().str());
module_stat.path.append(1, ')');
}
module_stat.uuid = module->GetUUID().GetAsString();
module_stat.triple = module->GetArchitecture().GetTriple().str();
json_modules.emplace_back(module_stat.ToJSON());
}
}
json::Object global_stats{
{"totalSymbolTableParseTime", symtab_parse_time},
{"totalSymbolTableIndexTime", symtab_index_time},
{"totalSymbolTablesLoaded", symtabs_loaded},
{"totalSymbolTablesLoadedFromCache", symtabs_loaded_from_cache},
{"totalSymbolTablesSavedToCache", symtabs_saved_to_cache},
{"totalDebugInfoParseTime", debug_parse_time},
{"totalDebugInfoIndexTime", debug_index_time},
{"totalDebugInfoIndexLoadedFromCache", debug_index_loaded},
{"totalDebugInfoIndexSavedToCache", debug_index_saved},
{"totalDebugInfoByteSize", debug_info_size},
{"totalModuleCount", num_modules},
{"totalModuleCountHasDebugInfo", num_modules_has_debug_info},
{"totalModuleCountWithVariableErrors", num_modules_with_variable_errors},
{"totalModuleCountWithIncompleteTypes",
num_modules_with_incomplete_types},
{"totalDebugInfoEnabled", num_debug_info_enabled_modules},
{"totalSymbolTableStripped", num_stripped_modules},
{"totalSymbolTableSymbolCount", symtab_symbol_count},
};
if (include_targets) {
if (target) {
json_targets.emplace_back(target->ReportStatistics(options));
} else {
for (const auto &target : debugger.GetTargetList().Targets())
json_targets.emplace_back(target->ReportStatistics(options));
}
global_stats.try_emplace("targets", std::move(json_targets));
}
if (!symbol_locator_total_time.map.empty()) {
json::Object obj;
for (const auto &entry : symbol_locator_total_time.map)
obj.try_emplace(entry.first().str(), entry.second);
global_stats.try_emplace("totalSymbolLocatorTime", std::move(obj));
}
ConstStringStats const_string_stats;
json::Object json_memory{
{"strings", const_string_stats.ToJSON()},
};
global_stats.try_emplace("memory", std::move(json_memory));
if (!summary_only) {
json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();
global_stats.try_emplace("commands", std::move(cmd_stats));
}
if (include_modules) {
global_stats.try_emplace("modules", std::move(json_modules));
}
if (include_transcript) {
// When transcript is available, add it to the to-be-returned statistics.
//
// NOTE:
// When the statistics is polled by an LLDB command:
// - The transcript in the returned statistics *will NOT* contain the
// returned statistics itself (otherwise infinite recursion).
// - The returned statistics *will* be written to the internal transcript
// buffer. It *will* appear in the next statistcs or transcript poll.
//
// For example, let's say the following commands are run in order:
// - "version"
// - "statistics dump" <- call it "A"
// - "statistics dump" <- call it "B"
// The output of "A" will contain the transcript of "version" and
// "statistics dump" (A), with the latter having empty output. The output
// of B will contain the trascnript of "version", "statistics dump" (A),
// "statistics dump" (B), with A's output populated and B's output empty.
const StructuredData::Array &transcript =
debugger.GetCommandInterpreter().GetTranscript();
if (transcript.GetSize() != 0) {
std::string buffer;
llvm::raw_string_ostream ss(buffer);
json::OStream json_os(ss);
transcript.Serialize(json_os);
if (auto json_transcript = llvm::json::parse(buffer))
global_stats.try_emplace("transcript",
std::move(json_transcript.get()));
}
}
return std::move(global_stats);
}
llvm::json::Value SummaryStatistics::ToJSON() const {
return json::Object{{
{"name", GetName()},
{"type", GetSummaryKindName()},
{"count", GetSummaryCount()},
{"totalTime", GetTotalTime()},
}};
}
json::Value SummaryStatisticsCache::ToJSON() {
std::lock_guard<std::mutex> guard(m_map_mutex);
json::Array json_summary_stats;
for (const auto &summary_stat : m_summary_stats_map)
json_summary_stats.emplace_back(summary_stat.second->ToJSON());
return json_summary_stats;
}
void SummaryStatisticsCache::Reset() {
for (const auto &summary_stat : m_summary_stats_map)
summary_stat.second->Reset();
}