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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Target/Statistics.h" 10 11 #include "lldb/Core/Debugger.h" 12 #include "lldb/Core/Module.h" 13 #include "lldb/Symbol/SymbolFile.h" 14 #include "lldb/Target/Process.h" 15 #include "lldb/Target/Target.h" 16 #include "lldb/Target/UnixSignals.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 using namespace llvm; 21 22 static void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, 23 const std::string &str) { 24 if (str.empty()) 25 return; 26 if (LLVM_LIKELY(llvm::json::isUTF8(str))) 27 obj.try_emplace(key, str); 28 else 29 obj.try_emplace(key, llvm::json::fixUTF8(str)); 30 } 31 32 json::Value StatsSuccessFail::ToJSON() const { 33 return json::Object{{"successes", successes}, {"failures", failures}}; 34 } 35 36 static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end) { 37 StatsDuration elapsed = end.time_since_epoch() - start.time_since_epoch(); 38 return elapsed.count(); 39 } 40 41 void TargetStats::CollectStats(Target &target) { 42 m_module_identifiers.clear(); 43 for (ModuleSP module_sp : target.GetImages().Modules()) 44 m_module_identifiers.emplace_back((intptr_t)module_sp.get()); 45 } 46 47 json::Value ModuleStats::ToJSON() const { 48 json::Object module; 49 EmplaceSafeString(module, "path", path); 50 EmplaceSafeString(module, "uuid", uuid); 51 EmplaceSafeString(module, "triple", triple); 52 module.try_emplace("identifier", identifier); 53 module.try_emplace("symbolTableParseTime", symtab_parse_time); 54 module.try_emplace("symbolTableIndexTime", symtab_index_time); 55 module.try_emplace("debugInfoParseTime", debug_parse_time); 56 module.try_emplace("debugInfoIndexTime", debug_index_time); 57 module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size); 58 return module; 59 } 60 61 json::Value TargetStats::ToJSON(Target &target) { 62 CollectStats(target); 63 64 json::Array json_module_uuid_array; 65 for (auto module_identifier : m_module_identifiers) 66 json_module_uuid_array.emplace_back(module_identifier); 67 68 json::Object target_metrics_json{ 69 {m_expr_eval.name, m_expr_eval.ToJSON()}, 70 {m_frame_var.name, m_frame_var.ToJSON()}, 71 {"moduleIdentifiers", std::move(json_module_uuid_array)}}; 72 73 if (m_launch_or_attach_time && m_first_private_stop_time) { 74 double elapsed_time = 75 elapsed(*m_launch_or_attach_time, *m_first_private_stop_time); 76 target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time); 77 } 78 if (m_launch_or_attach_time && m_first_public_stop_time) { 79 double elapsed_time = 80 elapsed(*m_launch_or_attach_time, *m_first_public_stop_time); 81 target_metrics_json.try_emplace("firstStopTime", elapsed_time); 82 } 83 target_metrics_json.try_emplace("targetCreateTime", m_create_time.count()); 84 85 json::Array breakpoints_array; 86 double totalBreakpointResolveTime = 0.0; 87 // Rport both the normal breakpoint list and the internal breakpoint list. 88 for (int i = 0; i < 2; ++i) { 89 BreakpointList &breakpoints = target.GetBreakpointList(i == 1); 90 std::unique_lock<std::recursive_mutex> lock; 91 breakpoints.GetListMutex(lock); 92 size_t num_breakpoints = breakpoints.GetSize(); 93 for (size_t i = 0; i < num_breakpoints; i++) { 94 Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); 95 breakpoints_array.push_back(bp->GetStatistics()); 96 totalBreakpointResolveTime += bp->GetResolveTime().count(); 97 } 98 } 99 100 ProcessSP process_sp = target.GetProcessSP(); 101 if (process_sp) { 102 UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals(); 103 if (unix_signals_sp) 104 target_metrics_json.try_emplace("signals", 105 unix_signals_sp->GetHitCountStatistics()); 106 } 107 target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array)); 108 target_metrics_json.try_emplace("totalBreakpointResolveTime", 109 totalBreakpointResolveTime); 110 111 return target_metrics_json; 112 } 113 114 void TargetStats::SetLaunchOrAttachTime() { 115 m_launch_or_attach_time = StatsClock::now(); 116 m_first_private_stop_time = llvm::None; 117 } 118 119 void TargetStats::SetFirstPrivateStopTime() { 120 // Launching and attaching has many paths depending on if synchronous mode 121 // was used or if we are stopping at the entry point or not. Only set the 122 // first stop time if it hasn't already been set. 123 if (!m_first_private_stop_time) 124 m_first_private_stop_time = StatsClock::now(); 125 } 126 127 void TargetStats::SetFirstPublicStopTime() { 128 // Launching and attaching has many paths depending on if synchronous mode 129 // was used or if we are stopping at the entry point or not. Only set the 130 // first stop time if it hasn't already been set. 131 if (!m_first_public_stop_time) 132 m_first_public_stop_time = StatsClock::now(); 133 } 134 135 bool DebuggerStats::g_collecting_stats = false; 136 137 llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, 138 Target *target) { 139 json::Array json_targets; 140 json::Array json_modules; 141 double symtab_parse_time = 0.0; 142 double symtab_index_time = 0.0; 143 double debug_parse_time = 0.0; 144 double debug_index_time = 0.0; 145 uint64_t debug_info_size = 0; 146 if (target) { 147 json_targets.emplace_back(target->ReportStatistics()); 148 } else { 149 for (const auto &target : debugger.GetTargetList().Targets()) 150 json_targets.emplace_back(target->ReportStatistics()); 151 } 152 std::vector<ModuleStats> modules; 153 std::lock_guard<std::recursive_mutex> guard( 154 Module::GetAllocationModuleCollectionMutex()); 155 const size_t num_modules = Module::GetNumberAllocatedModules(); 156 for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { 157 Module *module = Module::GetAllocatedModuleAtIndex(image_idx); 158 ModuleStats module_stat; 159 module_stat.identifier = (intptr_t)module; 160 module_stat.path = module->GetFileSpec().GetPath(); 161 if (ConstString object_name = module->GetObjectName()) { 162 module_stat.path.append(1, '('); 163 module_stat.path.append(object_name.GetStringRef().str()); 164 module_stat.path.append(1, ')'); 165 } 166 module_stat.uuid = module->GetUUID().GetAsString(); 167 module_stat.triple = module->GetArchitecture().GetTriple().str(); 168 module_stat.symtab_parse_time = module->GetSymtabParseTime().count(); 169 module_stat.symtab_index_time = module->GetSymtabIndexTime().count(); 170 SymbolFile *sym_file = module->GetSymbolFile(); 171 if (sym_file) { 172 module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count(); 173 module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count(); 174 module_stat.debug_info_size = sym_file->GetDebugInfoSize(); 175 } 176 symtab_parse_time += module_stat.symtab_parse_time; 177 symtab_index_time += module_stat.symtab_index_time; 178 debug_parse_time += module_stat.debug_parse_time; 179 debug_index_time += module_stat.debug_index_time; 180 debug_info_size += module_stat.debug_info_size; 181 json_modules.emplace_back(module_stat.ToJSON()); 182 } 183 184 json::Object global_stats{ 185 {"targets", std::move(json_targets)}, 186 {"modules", std::move(json_modules)}, 187 {"totalSymbolTableParseTime", symtab_parse_time}, 188 {"totalSymbolTableIndexTime", symtab_index_time}, 189 {"totalDebugInfoParseTime", debug_parse_time}, 190 {"totalDebugInfoIndexTime", debug_index_time}, 191 {"totalDebugInfoByteSize", debug_info_size}, 192 }; 193 return std::move(global_stats); 194 } 195