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::Duration elapsed = 38 end.time_since_epoch() - start.time_since_epoch(); 39 return elapsed.count(); 40 } 41 42 void TargetStats::CollectStats(Target &target) { 43 m_module_identifiers.clear(); 44 for (ModuleSP module_sp : target.GetImages().Modules()) 45 m_module_identifiers.emplace_back((intptr_t)module_sp.get()); 46 } 47 48 json::Value ModuleStats::ToJSON() const { 49 json::Object module; 50 EmplaceSafeString(module, "path", path); 51 EmplaceSafeString(module, "uuid", uuid); 52 EmplaceSafeString(module, "triple", triple); 53 module.try_emplace("identifier", identifier); 54 module.try_emplace("symbolTableParseTime", symtab_parse_time); 55 module.try_emplace("symbolTableIndexTime", symtab_index_time); 56 module.try_emplace("symbolTableLoadedFromCache", symtab_loaded_from_cache); 57 module.try_emplace("symbolTableSavedToCache", symtab_saved_to_cache); 58 module.try_emplace("debugInfoParseTime", debug_parse_time); 59 module.try_emplace("debugInfoIndexTime", debug_index_time); 60 module.try_emplace("debugInfoByteSize", (int64_t)debug_info_size); 61 module.try_emplace("debugInfoIndexLoadedFromCache", 62 debug_info_index_loaded_from_cache); 63 module.try_emplace("debugInfoIndexSavedToCache", 64 debug_info_index_saved_to_cache); 65 return module; 66 } 67 68 llvm::json::Value ConstStringStats::ToJSON() const { 69 json::Object obj; 70 obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal()); 71 obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed()); 72 obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused()); 73 return obj; 74 } 75 76 json::Value TargetStats::ToJSON(Target &target) { 77 CollectStats(target); 78 79 json::Array json_module_uuid_array; 80 for (auto module_identifier : m_module_identifiers) 81 json_module_uuid_array.emplace_back(module_identifier); 82 83 json::Object target_metrics_json{ 84 {m_expr_eval.name, m_expr_eval.ToJSON()}, 85 {m_frame_var.name, m_frame_var.ToJSON()}, 86 {"moduleIdentifiers", std::move(json_module_uuid_array)}}; 87 88 if (m_launch_or_attach_time && m_first_private_stop_time) { 89 double elapsed_time = 90 elapsed(*m_launch_or_attach_time, *m_first_private_stop_time); 91 target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time); 92 } 93 if (m_launch_or_attach_time && m_first_public_stop_time) { 94 double elapsed_time = 95 elapsed(*m_launch_or_attach_time, *m_first_public_stop_time); 96 target_metrics_json.try_emplace("firstStopTime", elapsed_time); 97 } 98 target_metrics_json.try_emplace("targetCreateTime", 99 m_create_time.get().count()); 100 101 json::Array breakpoints_array; 102 double totalBreakpointResolveTime = 0.0; 103 // Rport both the normal breakpoint list and the internal breakpoint list. 104 for (int i = 0; i < 2; ++i) { 105 BreakpointList &breakpoints = target.GetBreakpointList(i == 1); 106 std::unique_lock<std::recursive_mutex> lock; 107 breakpoints.GetListMutex(lock); 108 size_t num_breakpoints = breakpoints.GetSize(); 109 for (size_t i = 0; i < num_breakpoints; i++) { 110 Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); 111 breakpoints_array.push_back(bp->GetStatistics()); 112 totalBreakpointResolveTime += bp->GetResolveTime().count(); 113 } 114 } 115 116 ProcessSP process_sp = target.GetProcessSP(); 117 if (process_sp) { 118 UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals(); 119 if (unix_signals_sp) 120 target_metrics_json.try_emplace("signals", 121 unix_signals_sp->GetHitCountStatistics()); 122 uint32_t stop_id = process_sp->GetStopID(); 123 target_metrics_json.try_emplace("stopCount", stop_id); 124 } 125 target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array)); 126 target_metrics_json.try_emplace("totalBreakpointResolveTime", 127 totalBreakpointResolveTime); 128 129 return target_metrics_json; 130 } 131 132 void TargetStats::SetLaunchOrAttachTime() { 133 m_launch_or_attach_time = StatsClock::now(); 134 m_first_private_stop_time = llvm::None; 135 } 136 137 void TargetStats::SetFirstPrivateStopTime() { 138 // Launching and attaching has many paths depending on if synchronous mode 139 // was used or if we are stopping at the entry point or not. Only set the 140 // first stop time if it hasn't already been set. 141 if (!m_first_private_stop_time) 142 m_first_private_stop_time = StatsClock::now(); 143 } 144 145 void TargetStats::SetFirstPublicStopTime() { 146 // Launching and attaching has many paths depending on if synchronous mode 147 // was used or if we are stopping at the entry point or not. Only set the 148 // first stop time if it hasn't already been set. 149 if (!m_first_public_stop_time) 150 m_first_public_stop_time = StatsClock::now(); 151 } 152 153 bool DebuggerStats::g_collecting_stats = false; 154 155 llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, 156 Target *target) { 157 json::Array json_targets; 158 json::Array json_modules; 159 double symtab_parse_time = 0.0; 160 double symtab_index_time = 0.0; 161 double debug_parse_time = 0.0; 162 double debug_index_time = 0.0; 163 uint32_t symtabs_loaded = 0; 164 uint32_t symtabs_saved = 0; 165 uint32_t debug_index_loaded = 0; 166 uint32_t debug_index_saved = 0; 167 uint64_t debug_info_size = 0; 168 if (target) { 169 json_targets.emplace_back(target->ReportStatistics()); 170 } else { 171 for (const auto &target : debugger.GetTargetList().Targets()) 172 json_targets.emplace_back(target->ReportStatistics()); 173 } 174 std::vector<ModuleStats> modules; 175 std::lock_guard<std::recursive_mutex> guard( 176 Module::GetAllocationModuleCollectionMutex()); 177 const size_t num_modules = Module::GetNumberAllocatedModules(); 178 for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { 179 Module *module = Module::GetAllocatedModuleAtIndex(image_idx); 180 ModuleStats module_stat; 181 module_stat.identifier = (intptr_t)module; 182 module_stat.path = module->GetFileSpec().GetPath(); 183 if (ConstString object_name = module->GetObjectName()) { 184 module_stat.path.append(1, '('); 185 module_stat.path.append(object_name.GetStringRef().str()); 186 module_stat.path.append(1, ')'); 187 } 188 module_stat.uuid = module->GetUUID().GetAsString(); 189 module_stat.triple = module->GetArchitecture().GetTriple().str(); 190 module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count(); 191 module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count(); 192 Symtab *symtab = module->GetSymtab(); 193 if (symtab) { 194 module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache(); 195 if (module_stat.symtab_loaded_from_cache) 196 ++symtabs_loaded; 197 module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache(); 198 if (module_stat.symtab_saved_to_cache) 199 ++symtabs_saved; 200 } 201 SymbolFile *sym_file = module->GetSymbolFile(); 202 if (sym_file) { 203 module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count(); 204 module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count(); 205 module_stat.debug_info_size = sym_file->GetDebugInfoSize(); 206 module_stat.debug_info_index_loaded_from_cache = 207 sym_file->GetDebugInfoIndexWasLoadedFromCache(); 208 if (module_stat.debug_info_index_loaded_from_cache) 209 ++debug_index_loaded; 210 module_stat.debug_info_index_saved_to_cache = 211 sym_file->GetDebugInfoIndexWasSavedToCache(); 212 if (module_stat.debug_info_index_saved_to_cache) 213 ++debug_index_saved; 214 } 215 symtab_parse_time += module_stat.symtab_parse_time; 216 symtab_index_time += module_stat.symtab_index_time; 217 debug_parse_time += module_stat.debug_parse_time; 218 debug_index_time += module_stat.debug_index_time; 219 debug_info_size += module_stat.debug_info_size; 220 json_modules.emplace_back(module_stat.ToJSON()); 221 } 222 223 ConstStringStats const_string_stats; 224 json::Object json_memory{ 225 {"strings", const_string_stats.ToJSON()}, 226 }; 227 228 json::Object global_stats{ 229 {"targets", std::move(json_targets)}, 230 {"modules", std::move(json_modules)}, 231 {"memory", std::move(json_memory)}, 232 {"totalSymbolTableParseTime", symtab_parse_time}, 233 {"totalSymbolTableIndexTime", symtab_index_time}, 234 {"totalSymbolTablesLoadedFromCache", symtabs_loaded}, 235 {"totalSymbolTablesSavedToCache", symtabs_saved}, 236 {"totalDebugInfoParseTime", debug_parse_time}, 237 {"totalDebugInfoIndexTime", debug_index_time}, 238 {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded}, 239 {"totalDebugInfoIndexSavedToCache", debug_index_saved}, 240 {"totalDebugInfoByteSize", debug_info_size}, 241 }; 242 return std::move(global_stats); 243 } 244