brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.7 KiB · f7311a8 Raw
538 lines · cpp
1//===-- Statistics.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Target/Statistics.h"10 11#include "lldb/Core/Debugger.h"12#include "lldb/Core/Module.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Interpreter/CommandInterpreter.h"15#include "lldb/Symbol/SymbolFile.h"16#include "lldb/Target/DynamicLoader.h"17#include "lldb/Target/Process.h"18#include "lldb/Target/Target.h"19#include "lldb/Target/UnixSignals.h"20#include "lldb/Utility/StructuredData.h"21 22using namespace lldb;23using namespace lldb_private;24using namespace llvm;25 26static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,27                              const std::string &str) {28  if (str.empty())29    return;30  if (LLVM_LIKELY(llvm::json::isUTF8(str)))31    obj.try_emplace(key, str);32  else33    obj.try_emplace(key, llvm::json::fixUTF8(str));34}35 36json::Value StatsSuccessFail::ToJSON() const {37  return json::Object{{"successes", successes}, {"failures", failures}};38}39 40static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) {41  StatsDuration::Duration elapsed =42      end.time_since_epoch() - start.time_since_epoch();43  return elapsed.count();44}45 46void TargetStats::CollectStats(Target &target) {47  m_module_identifiers.clear();48  for (ModuleSP module_sp : target.GetImages().Modules())49    m_module_identifiers.emplace_back((intptr_t)module_sp.get());50}51 52json::Value ModuleStats::ToJSON() const {53  json::Object module;54  EmplaceSafeString(module, "path", path);55  EmplaceSafeString(module, "uuid", uuid);56  EmplaceSafeString(module, "triple", triple);57  module.try_emplace("identifier", identifier);58  module.try_emplace("symbolTableParseTime", symtab_parse_time);59  module.try_emplace("symbolTableIndexTime", symtab_index_time);60  module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache);61  module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache);62  module.try_emplace("debugInfoParseTime", debug_parse_time);63  module.try_emplace("debugInfoIndexTime", debug_index_time);64  module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size);65  module.try_emplace("debugInfoIndexLoadedFromCache",66                     debug_info_index_loaded_from_cache);67  module.try_emplace("debugInfoIndexSavedToCache",68                     debug_info_index_saved_to_cache);69  module.try_emplace("debugInfoEnabled", debug_info_enabled);70  module.try_emplace("debugInfoHadVariableErrors",71                     debug_info_had_variable_errors);72  module.try_emplace("debugInfoHadIncompleteTypes",73                     debug_info_had_incomplete_types);74  module.try_emplace("symbolTableStripped", symtab_stripped);75  module.try_emplace("symbolTableSymbolCount", symtab_symbol_count);76  module.try_emplace("dwoFileCount", dwo_stats.dwo_file_count);77  module.try_emplace("loadedDwoFileCount", dwo_stats.loaded_dwo_file_count);78  module.try_emplace("dwoErrorCount", dwo_stats.dwo_error_count);79 80  if (!symbol_locator_time.map.empty()) {81    json::Object obj;82    for (const auto &entry : symbol_locator_time.map)83      obj.try_emplace(entry.first().str(), entry.second);84    module.try_emplace("symbolLocatorTime", std::move(obj));85  }86 87  if (!symfile_path.empty())88    module.try_emplace("symbolFilePath", symfile_path);89 90  if (!symfile_modules.empty()) {91    json::Array symfile_ids;92    for (const auto symfile_id : symfile_modules)93      symfile_ids.emplace_back(symfile_id);94    module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids));95  }96 97  if (!type_system_stats.empty()) {98    json::Array type_systems;99    for (const auto &entry : type_system_stats) {100      json::Object obj;101      obj.try_emplace(entry.first().str(), entry.second);102      type_systems.emplace_back(std::move(obj));103    }104    module.try_emplace("typeSystemInfo", std::move(type_systems));105  }106 107  return module;108}109 110llvm::json::Value ConstStringStats::ToJSON() const {111  json::Object obj;112  obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal());113  obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed());114  obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused());115  return obj;116}117 118json::Value119TargetStats::ToJSON(Target &target,120                    const lldb_private::StatisticsOptions &options) {121  json::Object target_metrics_json;122  ProcessSP process_sp = target.GetProcessSP();123  const bool summary_only = options.GetSummaryOnly();124  const bool include_modules = options.GetIncludeModules();125  if (!summary_only) {126    CollectStats(target);127 128    json::Array json_module_uuid_array;129    for (auto module_identifier : m_module_identifiers)130      json_module_uuid_array.emplace_back(module_identifier);131 132    target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON());133    target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON());134    if (include_modules)135      target_metrics_json.try_emplace("moduleIdentifiers",136                                      std::move(json_module_uuid_array));137 138    if (m_launch_or_attach_time && m_first_private_stop_time) {139      double elapsed_time =140          elapsed(*m_launch_or_attach_time, *m_first_private_stop_time);141      target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time);142    }143    if (m_launch_or_attach_time && m_first_public_stop_time) {144      double elapsed_time =145          elapsed(*m_launch_or_attach_time, *m_first_public_stop_time);146      target_metrics_json.try_emplace("firstStopTime", elapsed_time);147    }148    target_metrics_json.try_emplace("targetCreateTime",149                                    m_create_time.get().count());150 151    if (m_load_core_time.get().count() > 0) {152      target_metrics_json.try_emplace("loadCoreTime",153                                      m_load_core_time.get().count());154    }155 156    json::Array breakpoints_array;157    double totalBreakpointResolveTime = 0.0;158    // Report both the normal breakpoint list and the internal breakpoint list.159    for (int i = 0; i < 2; ++i) {160      BreakpointList &breakpoints = target.GetBreakpointList(i == 1);161      std::unique_lock<std::recursive_mutex> lock;162      breakpoints.GetListMutex(lock);163      size_t num_breakpoints = breakpoints.GetSize();164      for (size_t i = 0; i < num_breakpoints; i++) {165        Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();166        breakpoints_array.push_back(bp->GetStatistics());167        totalBreakpointResolveTime += bp->GetResolveTime().count();168      }169    }170    target_metrics_json.try_emplace("breakpoints",171                                    std::move(breakpoints_array));172    target_metrics_json.try_emplace("totalBreakpointResolveTime",173                                    totalBreakpointResolveTime);174 175    if (process_sp) {176      UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();177      if (unix_signals_sp)178        target_metrics_json.try_emplace(179            "signals", unix_signals_sp->GetHitCountStatistics());180    }181  }182 183  // Counting "totalSharedLibraryEventHitCount" from breakpoints of kind184  // "shared-library-event".185  {186    uint32_t shared_library_event_breakpoint_hit_count = 0;187    // The "shared-library-event" is only found in the internal breakpoint list.188    BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true);189    std::unique_lock<std::recursive_mutex> lock;190    breakpoints.GetListMutex(lock);191    size_t num_breakpoints = breakpoints.GetSize();192    for (size_t i = 0; i < num_breakpoints; i++) {193      Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();194      if (strcmp(bp->GetBreakpointKind(), "shared-library-event") == 0)195        shared_library_event_breakpoint_hit_count += bp->GetHitCount();196    }197 198    target_metrics_json.try_emplace("totalSharedLibraryEventHitCount",199                                    shared_library_event_breakpoint_hit_count);200  }201 202  if (process_sp) {203    uint32_t stop_id = process_sp->GetStopID();204    target_metrics_json.try_emplace("stopCount", stop_id);205 206    llvm::StringRef dyld_plugin_name;207    if (process_sp->GetDynamicLoader())208      dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName();209    target_metrics_json.try_emplace("dyldPluginName", dyld_plugin_name);210  }211  target_metrics_json.try_emplace("sourceMapDeduceCount",212                                  m_source_map_deduce_count);213  target_metrics_json.try_emplace("sourceRealpathAttemptCount",214                                  m_source_realpath_attempt_count);215  target_metrics_json.try_emplace("sourceRealpathCompatibleCount",216                                  m_source_realpath_compatible_count);217  target_metrics_json.try_emplace("summaryProviderStatistics",218                                  target.GetSummaryStatisticsCache().ToJSON());219  return target_metrics_json;220}221 222void TargetStats::Reset(Target &target) {223  m_launch_or_attach_time.reset();224  m_first_private_stop_time.reset();225  m_first_public_stop_time.reset();226  // Report both the normal breakpoint list and the internal breakpoint list.227  for (int i = 0; i < 2; ++i) {228    BreakpointList &breakpoints = target.GetBreakpointList(i == 1);229    std::unique_lock<std::recursive_mutex> lock;230    breakpoints.GetListMutex(lock);231    size_t num_breakpoints = breakpoints.GetSize();232    for (size_t i = 0; i < num_breakpoints; i++) {233      Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get();234      bp->ResetStatistics();235    }236  }237  target.GetSummaryStatisticsCache().Reset();238}239 240void TargetStats::SetLaunchOrAttachTime() {241  m_launch_or_attach_time = StatsClock::now();242  m_first_private_stop_time = std::nullopt;243}244 245void TargetStats::SetFirstPrivateStopTime() {246  // Launching and attaching has many paths depending on if synchronous mode247  // was used or if we are stopping at the entry point or not. Only set the248  // first stop time if it hasn't already been set.249  if (!m_first_private_stop_time)250    m_first_private_stop_time = StatsClock::now();251}252 253void TargetStats::SetFirstPublicStopTime() {254  // Launching and attaching has many paths depending on if synchronous mode255  // was used or if we are stopping at the entry point or not. Only set the256  // first stop time if it hasn't already been set.257  if (!m_first_public_stop_time)258    m_first_public_stop_time = StatsClock::now();259}260 261void TargetStats::IncreaseSourceMapDeduceCount() {262  ++m_source_map_deduce_count;263}264 265void TargetStats::IncreaseSourceRealpathAttemptCount(uint32_t count) {266  m_source_realpath_attempt_count += count;267}268 269void TargetStats::IncreaseSourceRealpathCompatibleCount(uint32_t count) {270  m_source_realpath_compatible_count += count;271}272 273bool DebuggerStats::g_collecting_stats = false;274 275void DebuggerStats::ResetStatistics(Debugger &debugger, Target *target) {276  std::lock_guard<std::recursive_mutex> guard(277      Module::GetAllocationModuleCollectionMutex());278  const uint64_t num_modules = target != nullptr279                                   ? target->GetImages().GetSize()280                                   : Module::GetNumberAllocatedModules();281  for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {282    Module *module = target != nullptr283                         ? target->GetImages().GetModuleAtIndex(image_idx).get()284                         : Module::GetAllocatedModuleAtIndex(image_idx);285    if (module == nullptr)286      continue;287    module->ResetStatistics();288  }289  if (target)290    target->ResetStatistics();291  else {292    for (const auto &target : debugger.GetTargetList().Targets())293      target->ResetStatistics();294  }295}296 297llvm::json::Value DebuggerStats::ReportStatistics(298    Debugger &debugger, Target *target,299    const lldb_private::StatisticsOptions &options) {300 301  const bool summary_only = options.GetSummaryOnly();302  const bool load_all_debug_info = options.GetLoadAllDebugInfo();303  const bool include_targets = options.GetIncludeTargets();304  const bool include_modules = options.GetIncludeModules();305  const bool include_transcript = options.GetIncludeTranscript();306  const bool include_plugins = options.GetIncludePlugins();307 308  json::Array json_targets;309  json::Array json_modules;310  StatisticsMap symbol_locator_total_time;311  double symtab_parse_time = 0.0;312  double symtab_index_time = 0.0;313  double debug_parse_time = 0.0;314  double debug_index_time = 0.0;315  uint32_t symtabs_loaded = 0;316  uint32_t symtabs_loaded_from_cache = 0;317  uint32_t symtabs_saved_to_cache = 0;318  uint32_t debug_index_loaded = 0;319  uint32_t debug_index_saved = 0;320  uint64_t debug_info_size = 0;321 322  std::lock_guard<std::recursive_mutex> guard(323      Module::GetAllocationModuleCollectionMutex());324  const uint64_t num_modules = target != nullptr325                                   ? target->GetImages().GetSize()326                                   : Module::GetNumberAllocatedModules();327  uint32_t num_debug_info_enabled_modules = 0;328  uint32_t num_modules_has_debug_info = 0;329  uint32_t num_modules_with_variable_errors = 0;330  uint32_t num_modules_with_incomplete_types = 0;331  uint32_t num_stripped_modules = 0;332  uint32_t symtab_symbol_count = 0;333  DWOStats total_dwo_stats;334  for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {335    Module *module = target != nullptr336                         ? target->GetImages().GetModuleAtIndex(image_idx).get()337                         : Module::GetAllocatedModuleAtIndex(image_idx);338    ModuleStats module_stat;339    module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count();340    module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count();341    module_stat.symbol_locator_time = module->GetSymbolLocatorStatistics();342    symbol_locator_total_time.merge(module_stat.symbol_locator_time);343    Symtab *symtab = module->GetSymtab(/*can_create=*/false);344    if (symtab) {345      module_stat.symtab_symbol_count = symtab->GetNumSymbols();346      symtab_symbol_count += module_stat.symtab_symbol_count;347      ++symtabs_loaded;348      module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache();349      if (module_stat.symtab_loaded_from_cache)350        ++symtabs_loaded_from_cache;351      module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache();352      if (module_stat.symtab_saved_to_cache)353        ++symtabs_saved_to_cache;354    }355    SymbolFile *sym_file = module->GetSymbolFile(/*can_create=*/false);356    if (sym_file) {357      if (!summary_only) {358        if (sym_file->GetObjectFile() != module->GetObjectFile())359          module_stat.symfile_path =360              sym_file->GetObjectFile()->GetFileSpec().GetPath();361        ModuleList symbol_modules = sym_file->GetDebugInfoModules();362        for (const auto &symbol_module : symbol_modules.Modules())363          module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());364      }365      DWOStats current_dwo_stats = sym_file->GetDwoStats();366      module_stat.dwo_stats += current_dwo_stats;367      total_dwo_stats += current_dwo_stats;368      module_stat.debug_info_index_loaded_from_cache =369          sym_file->GetDebugInfoIndexWasLoadedFromCache();370      if (module_stat.debug_info_index_loaded_from_cache)371        ++debug_index_loaded;372      module_stat.debug_info_index_saved_to_cache =373          sym_file->GetDebugInfoIndexWasSavedToCache();374      if (module_stat.debug_info_index_saved_to_cache)375        ++debug_index_saved;376      module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count();377      module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count();378      module_stat.debug_info_size =379          sym_file->GetDebugInfoSize(load_all_debug_info);380      module_stat.symtab_stripped = module->GetObjectFile()->IsStripped();381      if (module_stat.symtab_stripped)382        ++num_stripped_modules;383      module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() &&384                                       module_stat.debug_info_size > 0;385      module_stat.debug_info_had_variable_errors =386          sym_file->GetDebugInfoHadFrameVariableErrors();387      if (module_stat.debug_info_enabled)388        ++num_debug_info_enabled_modules;389      if (module_stat.debug_info_size > 0)390        ++num_modules_has_debug_info;391      if (module_stat.debug_info_had_variable_errors)392        ++num_modules_with_variable_errors;393    }394    symtab_parse_time += module_stat.symtab_parse_time;395    symtab_index_time += module_stat.symtab_index_time;396    debug_parse_time += module_stat.debug_parse_time;397    debug_index_time += module_stat.debug_index_time;398    debug_info_size += module_stat.debug_info_size;399    module->ForEachTypeSystem([&](lldb::TypeSystemSP ts) {400      if (auto stats = ts->ReportStatistics())401        module_stat.type_system_stats.insert({ts->GetPluginName(), *stats});402      if (ts->GetHasForcefullyCompletedTypes())403        module_stat.debug_info_had_incomplete_types = true;404      return true;405    });406    if (module_stat.debug_info_had_incomplete_types)407      ++num_modules_with_incomplete_types;408 409    if (include_modules) {410      module_stat.identifier = (intptr_t)module;411      module_stat.path = module->GetFileSpec().GetPath();412      if (ConstString object_name = module->GetObjectName()) {413        module_stat.path.append(1, '(');414        module_stat.path.append(object_name.GetStringRef().str());415        module_stat.path.append(1, ')');416      }417      module_stat.uuid = module->GetUUID().GetAsString();418      module_stat.triple = module->GetArchitecture().GetTriple().str();419      json_modules.emplace_back(module_stat.ToJSON());420    }421  }422 423  json::Object global_stats{424      {"totalSymbolTableParseTime", symtab_parse_time},425      {"totalSymbolTableIndexTime", symtab_index_time},426      {"totalSymbolTablesLoaded", symtabs_loaded},427      {"totalSymbolTablesLoadedFromCache", symtabs_loaded_from_cache},428      {"totalSymbolTablesSavedToCache", symtabs_saved_to_cache},429      {"totalDebugInfoParseTime", debug_parse_time},430      {"totalDebugInfoIndexTime", debug_index_time},431      {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded},432      {"totalDebugInfoIndexSavedToCache", debug_index_saved},433      {"totalDebugInfoByteSize", debug_info_size},434      {"totalModuleCount", num_modules},435      {"totalModuleCountHasDebugInfo", num_modules_has_debug_info},436      {"totalModuleCountWithVariableErrors", num_modules_with_variable_errors},437      {"totalModuleCountWithIncompleteTypes",438       num_modules_with_incomplete_types},439      {"totalDebugInfoEnabled", num_debug_info_enabled_modules},440      {"totalSymbolTableStripped", num_stripped_modules},441      {"totalSymbolTableSymbolCount", symtab_symbol_count},442      {"totalLoadedDwoFileCount", total_dwo_stats.loaded_dwo_file_count},443      {"totalDwoFileCount", total_dwo_stats.dwo_file_count},444      {"totalDwoErrorCount", total_dwo_stats.dwo_error_count},445  };446 447  if (include_targets) {448    if (target) {449      json_targets.emplace_back(target->ReportStatistics(options));450    } else {451      for (const auto &target : debugger.GetTargetList().Targets())452        json_targets.emplace_back(target->ReportStatistics(options));453    }454    global_stats.try_emplace("targets", std::move(json_targets));455  }456 457  if (!symbol_locator_total_time.map.empty()) {458    json::Object obj;459    for (const auto &entry : symbol_locator_total_time.map)460      obj.try_emplace(entry.first().str(), entry.second);461    global_stats.try_emplace("totalSymbolLocatorTime", std::move(obj));462  }463 464  ConstStringStats const_string_stats;465  json::Object json_memory{466      {"strings", const_string_stats.ToJSON()},467  };468  global_stats.try_emplace("memory", std::move(json_memory));469  if (!summary_only) {470    json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics();471    global_stats.try_emplace("commands", std::move(cmd_stats));472  }473 474  if (include_modules) {475    global_stats.try_emplace("modules", std::move(json_modules));476  }477 478  if (include_transcript) {479    // When transcript is available, add it to the to-be-returned statistics.480    //481    // NOTE:482    // When the statistics is polled by an LLDB command:483    // - The transcript in the returned statistics *will NOT* contain the484    //   returned statistics itself (otherwise infinite recursion).485    // - The returned statistics *will* be written to the internal transcript486    //   buffer. It *will* appear in the next statistcs or transcript poll.487    //488    // For example, let's say the following commands are run in order:489    // - "version"490    // - "statistics dump"  <- call it "A"491    // - "statistics dump"  <- call it "B"492    // The output of "A" will contain the transcript of "version" and493    // "statistics dump" (A), with the latter having empty output. The output494    // of B will contain the trascnript of "version", "statistics dump" (A),495    // "statistics dump" (B), with A's output populated and B's output empty.496    const StructuredData::Array &transcript =497        debugger.GetCommandInterpreter().GetTranscript();498    if (transcript.GetSize() != 0) {499      std::string buffer;500      llvm::raw_string_ostream ss(buffer);501      json::OStream json_os(ss);502      transcript.Serialize(json_os);503      if (auto json_transcript = llvm::json::parse(buffer))504        global_stats.try_emplace("transcript",505                                 std::move(json_transcript.get()));506    }507  }508 509  if (include_plugins) {510    global_stats.try_emplace("plugins", PluginManager::GetJSON());511  }512 513  return std::move(global_stats);514}515 516llvm::json::Value SummaryStatistics::ToJSON() const {517  return json::Object{{518      {"name", GetName()},519      {"type", GetSummaryKindName()},520      {"count", GetSummaryCount()},521      {"totalTime", GetTotalTime()},522  }};523}524 525json::Value SummaryStatisticsCache::ToJSON() {526  std::lock_guard<std::mutex> guard(m_map_mutex);527  json::Array json_summary_stats;528  for (const auto &summary_stat : m_summary_stats_map)529    json_summary_stats.emplace_back(summary_stat.second->ToJSON());530 531  return json_summary_stats;532}533 534void SummaryStatisticsCache::Reset() {535  for (const auto &summary_stat : m_summary_stats_map)536    summary_stat.second->Reset();537}538