Path: blob/main/contrib/llvm-project/lldb/source/Target/Statistics.cpp
39587 views
//===-- Statistics.cpp ----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Target/Statistics.h"910#include "lldb/Core/Debugger.h"11#include "lldb/Core/Module.h"12#include "lldb/Interpreter/CommandInterpreter.h"13#include "lldb/Symbol/SymbolFile.h"14#include "lldb/Target/DynamicLoader.h"15#include "lldb/Target/Process.h"16#include "lldb/Target/Target.h"17#include "lldb/Target/UnixSignals.h"18#include "lldb/Utility/StructuredData.h"1920using namespace lldb;21using namespace lldb_private;22using namespace llvm;2324static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,25const std::string &str) {26if (str.empty())27return;28if (LLVM_LIKELY(llvm::json::isUTF8(str)))29obj.try_emplace(key, str);30else31obj.try_emplace(key, llvm::json::fixUTF8(str));32}3334json::Value StatsSuccessFail::ToJSON() const {35return json::Object{{"successes", successes}, {"failures", failures}};36}3738static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {39StatsDuration::Duration elapsed =40end.time_since_epoch() - start.time_since_epoch();41return elapsed.count();42}4344void TargetStats::CollectStats(Target &target) {45m_module_identifiers.clear();46for (ModuleSP module_sp : target.GetImages().Modules())47m_module_identifiers.emplace_back((intptr_t)module_sp.get());48}4950json::Value ModuleStats::ToJSON() const {51json::Object module;52EmplaceSafeString(module, "path", path);53EmplaceSafeString(module, "uuid", uuid);54EmplaceSafeString(module, "triple", triple);55module.try_emplace("identifier", identifier);56module.try_emplace("symbolTableParseTime", symtab_parse_time);57module.try_emplace("symbolTableIndexTime", symtab_index_time);58module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache);59module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache);60module.try_emplace("debugInfoParseTime", debug_parse_time);61module.try_emplace("debugInfoIndexTime", debug_index_time);62module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);63module.try_emplace("debugInfoIndexLoadedFromCache",64debug_info_index_loaded_from_cache);65module.try_emplace("debugInfoIndexSavedToCache",66debug_info_index_saved_to_cache);67module.try_emplace("debugInfoEnabled", debug_info_enabled);68module.try_emplace("debugInfoHadVariableErrors",69debug_info_had_variable_errors);70module.try_emplace("debugInfoHadIncompleteTypes",71debug_info_had_incomplete_types);72module.try_emplace("symbolTableStripped", symtab_stripped);73if (!symfile_path.empty())74module.try_emplace("symbolFilePath", symfile_path);7576if (!symfile_modules.empty()) {77json::Array symfile_ids;78for (const auto symfile_id: symfile_modules)79symfile_ids.emplace_back(symfile_id);80module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids));81}8283if (!type_system_stats.empty()) {84json::Array type_systems;85for (const auto &entry : type_system_stats) {86json::Object obj;87obj.try_emplace(entry.first().str(), entry.second);88type_systems.emplace_back(std::move(obj));89}90module.try_emplace("typeSystemInfo", std::move(type_systems));91}9293return module;94}9596llvm::json::Value ConstStringStats::ToJSON() const {97json::Object obj;98obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal());99obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed());100obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused());101return obj;102}103104json::Value105TargetStats::ToJSON(Target &target,106const lldb_private::StatisticsOptions &options) {107json::Object target_metrics_json;108ProcessSP process_sp = target.GetProcessSP();109const bool summary_only = options.GetSummaryOnly();110const bool include_modules = options.GetIncludeModules();111if (!summary_only) {112CollectStats(target);113114json::Array json_module_uuid_array;115for (auto module_identifier : m_module_identifiers)116json_module_uuid_array.emplace_back(module_identifier);117118target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON());119target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON());120if (include_modules)121target_metrics_json.try_emplace("moduleIdentifiers",122std::move(json_module_uuid_array));123124if (m_launch_or_attach_time && m_first_private_stop_time) {125double elapsed_time =126elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);127target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);128}129if (m_launch_or_attach_time && m_first_public_stop_time) {130double elapsed_time =131elapsed(*m_launch_or_attach_time, *m_first_public_stop_time);132target_metrics_json.try_emplace("firstStopTime", elapsed_time);133}134target_metrics_json.try_emplace("targetCreateTime",135m_create_time.get().count());136137json::Array breakpoints_array;138double totalBreakpointResolveTime = 0.0;139// Report both the normal breakpoint list and the internal breakpoint list.140for (int i = 0; i < 2; ++i) {141BreakpointList &breakpoints = target.GetBreakpointList(i == 1);142std::unique_lock<std::recursive_mutex> lock;143breakpoints.GetListMutex(lock);144size_t num_breakpoints = breakpoints.GetSize();145for (size_t i = 0; i < num_breakpoints; i++) {146Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();147breakpoints_array.push_back(bp->GetStatistics());148totalBreakpointResolveTime += bp->GetResolveTime().count();149}150}151target_metrics_json.try_emplace("breakpoints",152std::move(breakpoints_array));153target_metrics_json.try_emplace("totalBreakpointResolveTime",154totalBreakpointResolveTime);155156if (process_sp) {157UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();158if (unix_signals_sp)159target_metrics_json.try_emplace(160"signals", unix_signals_sp->GetHitCountStatistics());161}162}163164// Counting "totalSharedLibraryEventHitCount" from breakpoints of kind165// "shared-library-event".166{167uint32_t shared_library_event_breakpoint_hit_count = 0;168// The "shared-library-event" is only found in the internal breakpoint list.169BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true);170std::unique_lock<std::recursive_mutex> lock;171breakpoints.GetListMutex(lock);172size_t num_breakpoints = breakpoints.GetSize();173for (size_t i = 0; i < num_breakpoints; i++) {174Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();175if (strcmp(bp->GetBreakpointKind(), "shared-library-event") == 0)176shared_library_event_breakpoint_hit_count += bp->GetHitCount();177}178179target_metrics_json.try_emplace("totalSharedLibraryEventHitCount",180shared_library_event_breakpoint_hit_count);181}182183if (process_sp) {184uint32_t stop_id = process_sp->GetStopID();185target_metrics_json.try_emplace("stopCount", stop_id);186187llvm::StringRef dyld_plugin_name;188if (process_sp->GetDynamicLoader())189dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName();190target_metrics_json.try_emplace("dyldPluginName", dyld_plugin_name);191}192target_metrics_json.try_emplace("sourceMapDeduceCount",193m_source_map_deduce_count);194return target_metrics_json;195}196197void TargetStats::SetLaunchOrAttachTime() {198m_launch_or_attach_time = StatsClock::now();199m_first_private_stop_time = std::nullopt;200}201202void TargetStats::SetFirstPrivateStopTime() {203// Launching and attaching has many paths depending on if synchronous mode204// was used or if we are stopping at the entry point or not. Only set the205// first stop time if it hasn't already been set.206if (!m_first_private_stop_time)207m_first_private_stop_time = StatsClock::now();208}209210void TargetStats::SetFirstPublicStopTime() {211// Launching and attaching has many paths depending on if synchronous mode212// was used or if we are stopping at the entry point or not. Only set the213// first stop time if it hasn't already been set.214if (!m_first_public_stop_time)215m_first_public_stop_time = StatsClock::now();216}217218void TargetStats::IncreaseSourceMapDeduceCount() {219++m_source_map_deduce_count;220}221222bool DebuggerStats::g_collecting_stats = false;223224llvm::json::Value DebuggerStats::ReportStatistics(225Debugger &debugger, Target *target,226const lldb_private::StatisticsOptions &options) {227228const bool summary_only = options.GetSummaryOnly();229const bool load_all_debug_info = options.GetLoadAllDebugInfo();230const bool include_targets = options.GetIncludeTargets();231const bool include_modules = options.GetIncludeModules();232const bool include_transcript = options.GetIncludeTranscript();233234json::Array json_targets;235json::Array json_modules;236double symtab_parse_time = 0.0;237double symtab_index_time = 0.0;238double debug_parse_time = 0.0;239double debug_index_time = 0.0;240uint32_t symtabs_loaded = 0;241uint32_t symtabs_saved = 0;242uint32_t debug_index_loaded = 0;243uint32_t debug_index_saved = 0;244uint64_t debug_info_size = 0;245246std::vector<ModuleStats> modules;247std::lock_guard<std::recursive_mutex> guard(248Module::GetAllocationModuleCollectionMutex());249const uint64_t num_modules = Module::GetNumberAllocatedModules();250uint32_t num_debug_info_enabled_modules = 0;251uint32_t num_modules_has_debug_info = 0;252uint32_t num_modules_with_variable_errors = 0;253uint32_t num_modules_with_incomplete_types = 0;254uint32_t num_stripped_modules = 0;255for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {256Module *module = Module::GetAllocatedModuleAtIndex(image_idx);257ModuleStats module_stat;258module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();259module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();260Symtab *symtab = module->GetSymtab();261if (symtab) {262module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();263if (module_stat.symtab_loaded_from_cache)264++symtabs_loaded;265module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();266if (module_stat.symtab_saved_to_cache)267++symtabs_saved;268}269SymbolFile *sym_file = module->GetSymbolFile();270if (sym_file) {271if (!summary_only) {272if (sym_file->GetObjectFile() != module->GetObjectFile())273module_stat.symfile_path =274sym_file->GetObjectFile()->GetFileSpec().GetPath();275ModuleList symbol_modules = sym_file->GetDebugInfoModules();276for (const auto &symbol_module : symbol_modules.Modules())277module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());278}279module_stat.debug_info_index_loaded_from_cache =280sym_file->GetDebugInfoIndexWasLoadedFromCache();281if (module_stat.debug_info_index_loaded_from_cache)282++debug_index_loaded;283module_stat.debug_info_index_saved_to_cache =284sym_file->GetDebugInfoIndexWasSavedToCache();285if (module_stat.debug_info_index_saved_to_cache)286++debug_index_saved;287module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();288module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();289module_stat.debug_info_size =290sym_file->GetDebugInfoSize(load_all_debug_info);291module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();292if (module_stat.symtab_stripped)293++num_stripped_modules;294module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() &&295module_stat.debug_info_size > 0;296module_stat.debug_info_had_variable_errors =297sym_file->GetDebugInfoHadFrameVariableErrors();298if (module_stat.debug_info_enabled)299++num_debug_info_enabled_modules;300if (module_stat.debug_info_size > 0)301++num_modules_has_debug_info;302if (module_stat.debug_info_had_variable_errors)303++num_modules_with_variable_errors;304}305symtab_parse_time += module_stat.symtab_parse_time;306symtab_index_time += module_stat.symtab_index_time;307debug_parse_time += module_stat.debug_parse_time;308debug_index_time += module_stat.debug_index_time;309debug_info_size += module_stat.debug_info_size;310module->ForEachTypeSystem([&](lldb::TypeSystemSP ts) {311if (auto stats = ts->ReportStatistics())312module_stat.type_system_stats.insert({ts->GetPluginName(), *stats});313if (ts->GetHasForcefullyCompletedTypes())314module_stat.debug_info_had_incomplete_types = true;315return true;316});317if (module_stat.debug_info_had_incomplete_types)318++num_modules_with_incomplete_types;319320if (include_modules) {321module_stat.identifier = (intptr_t)module;322module_stat.path = module->GetFileSpec().GetPath();323if (ConstString object_name = module->GetObjectName()) {324module_stat.path.append(1, '(');325module_stat.path.append(object_name.GetStringRef().str());326module_stat.path.append(1, ')');327}328module_stat.uuid = module->GetUUID().GetAsString();329module_stat.triple = module->GetArchitecture().GetTriple().str();330json_modules.emplace_back(module_stat.ToJSON());331}332}333334json::Object global_stats{335{"totalSymbolTableParseTime", symtab_parse_time},336{"totalSymbolTableIndexTime", symtab_index_time},337{"totalSymbolTablesLoadedFromCache", symtabs_loaded},338{"totalSymbolTablesSavedToCache", symtabs_saved},339{"totalDebugInfoParseTime", debug_parse_time},340{"totalDebugInfoIndexTime", debug_index_time},341{"totalDebugInfoIndexLoadedFromCache", debug_index_loaded},342{"totalDebugInfoIndexSavedToCache", debug_index_saved},343{"totalDebugInfoByteSize", debug_info_size},344{"totalModuleCount", num_modules},345{"totalModuleCountHasDebugInfo", num_modules_has_debug_info},346{"totalModuleCountWithVariableErrors", num_modules_with_variable_errors},347{"totalModuleCountWithIncompleteTypes",348num_modules_with_incomplete_types},349{"totalDebugInfoEnabled", num_debug_info_enabled_modules},350{"totalSymbolTableStripped", num_stripped_modules},351};352353if (include_targets) {354if (target) {355json_targets.emplace_back(target->ReportStatistics(options));356} else {357for (const auto &target : debugger.GetTargetList().Targets())358json_targets.emplace_back(target->ReportStatistics(options));359}360global_stats.try_emplace("targets", std::move(json_targets));361}362363ConstStringStats const_string_stats;364json::Object json_memory{365{"strings", const_string_stats.ToJSON()},366};367global_stats.try_emplace("memory", std::move(json_memory));368if (!summary_only) {369json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();370global_stats.try_emplace("commands", std::move(cmd_stats));371}372373if (include_modules) {374global_stats.try_emplace("modules", std::move(json_modules));375}376377if (include_transcript) {378// When transcript is available, add it to the to-be-returned statistics.379//380// NOTE:381// When the statistics is polled by an LLDB command:382// - The transcript in the returned statistics *will NOT* contain the383// returned statistics itself (otherwise infinite recursion).384// - The returned statistics *will* be written to the internal transcript385// buffer. It *will* appear in the next statistcs or transcript poll.386//387// For example, let's say the following commands are run in order:388// - "version"389// - "statistics dump" <- call it "A"390// - "statistics dump" <- call it "B"391// The output of "A" will contain the transcript of "version" and392// "statistics dump" (A), with the latter having empty output. The output393// of B will contain the trascnript of "version", "statistics dump" (A),394// "statistics dump" (B), with A's output populated and B's output empty.395const StructuredData::Array &transcript =396debugger.GetCommandInterpreter().GetTranscript();397if (transcript.GetSize() != 0) {398std::string buffer;399llvm::raw_string_ostream ss(buffer);400json::OStream json_os(ss);401transcript.Serialize(json_os);402if (auto json_transcript = llvm::json::parse(ss.str()))403global_stats.try_emplace("transcript",404std::move(json_transcript.get()));405}406}407408return std::move(global_stats);409}410411412