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 module.try_emplace("debugInfoEnabled", debug_info_enabled); 66 module.try_emplace("debugInfoHadVariableErrors", 67 debug_info_had_variable_errors); 68 module.try_emplace("debugInfoHadIncompleteTypes", 69 debug_info_had_incomplete_types); 70 module.try_emplace("symbolTableStripped", symtab_stripped); 71 if (!symfile_path.empty()) 72 module.try_emplace("symbolFilePath", symfile_path); 73 74 if (!symfile_modules.empty()) { 75 json::Array symfile_ids; 76 for (const auto symfile_id: symfile_modules) 77 symfile_ids.emplace_back(symfile_id); 78 module.try_emplace("symbolFileModuleIdentifiers", std::move(symfile_ids)); 79 } 80 81 if (!type_system_stats.empty()) { 82 json::Array type_systems; 83 for (const auto &entry : type_system_stats) { 84 json::Object obj; 85 obj.try_emplace(entry.first().str(), entry.second); 86 type_systems.emplace_back(std::move(obj)); 87 } 88 module.try_emplace("typeSystemInfo", std::move(type_systems)); 89 } 90 91 return module; 92 } 93 94 llvm::json::Value ConstStringStats::ToJSON() const { 95 json::Object obj; 96 obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal()); 97 obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed()); 98 obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused()); 99 return obj; 100 } 101 102 json::Value TargetStats::ToJSON(Target &target) { 103 CollectStats(target); 104 105 json::Array json_module_uuid_array; 106 for (auto module_identifier : m_module_identifiers) 107 json_module_uuid_array.emplace_back(module_identifier); 108 109 json::Object target_metrics_json{ 110 {m_expr_eval.name, m_expr_eval.ToJSON()}, 111 {m_frame_var.name, m_frame_var.ToJSON()}, 112 {"moduleIdentifiers", std::move(json_module_uuid_array)}}; 113 114 if (m_launch_or_attach_time && m_first_private_stop_time) { 115 double elapsed_time = 116 elapsed(*m_launch_or_attach_time, *m_first_private_stop_time); 117 target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time); 118 } 119 if (m_launch_or_attach_time && m_first_public_stop_time) { 120 double elapsed_time = 121 elapsed(*m_launch_or_attach_time, *m_first_public_stop_time); 122 target_metrics_json.try_emplace("firstStopTime", elapsed_time); 123 } 124 target_metrics_json.try_emplace("targetCreateTime", 125 m_create_time.get().count()); 126 127 json::Array breakpoints_array; 128 double totalBreakpointResolveTime = 0.0; 129 // Rport both the normal breakpoint list and the internal breakpoint list. 130 for (int i = 0; i < 2; ++i) { 131 BreakpointList &breakpoints = target.GetBreakpointList(i == 1); 132 std::unique_lock<std::recursive_mutex> lock; 133 breakpoints.GetListMutex(lock); 134 size_t num_breakpoints = breakpoints.GetSize(); 135 for (size_t i = 0; i < num_breakpoints; i++) { 136 Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); 137 breakpoints_array.push_back(bp->GetStatistics()); 138 totalBreakpointResolveTime += bp->GetResolveTime().count(); 139 } 140 } 141 142 ProcessSP process_sp = target.GetProcessSP(); 143 if (process_sp) { 144 UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals(); 145 if (unix_signals_sp) 146 target_metrics_json.try_emplace("signals", 147 unix_signals_sp->GetHitCountStatistics()); 148 uint32_t stop_id = process_sp->GetStopID(); 149 target_metrics_json.try_emplace("stopCount", stop_id); 150 } 151 target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array)); 152 target_metrics_json.try_emplace("totalBreakpointResolveTime", 153 totalBreakpointResolveTime); 154 target_metrics_json.try_emplace("sourceMapDeduceCount", m_source_map_deduce_count); 155 156 return target_metrics_json; 157 } 158 159 void TargetStats::SetLaunchOrAttachTime() { 160 m_launch_or_attach_time = StatsClock::now(); 161 m_first_private_stop_time = std::nullopt; 162 } 163 164 void TargetStats::SetFirstPrivateStopTime() { 165 // Launching and attaching has many paths depending on if synchronous mode 166 // was used or if we are stopping at the entry point or not. Only set the 167 // first stop time if it hasn't already been set. 168 if (!m_first_private_stop_time) 169 m_first_private_stop_time = StatsClock::now(); 170 } 171 172 void TargetStats::SetFirstPublicStopTime() { 173 // Launching and attaching has many paths depending on if synchronous mode 174 // was used or if we are stopping at the entry point or not. Only set the 175 // first stop time if it hasn't already been set. 176 if (!m_first_public_stop_time) 177 m_first_public_stop_time = StatsClock::now(); 178 } 179 180 void TargetStats::IncreaseSourceMapDeduceCount() { 181 ++m_source_map_deduce_count; 182 } 183 184 bool DebuggerStats::g_collecting_stats = false; 185 186 llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, 187 Target *target) { 188 json::Array json_targets; 189 json::Array json_modules; 190 double symtab_parse_time = 0.0; 191 double symtab_index_time = 0.0; 192 double debug_parse_time = 0.0; 193 double debug_index_time = 0.0; 194 uint32_t symtabs_loaded = 0; 195 uint32_t symtabs_saved = 0; 196 uint32_t debug_index_loaded = 0; 197 uint32_t debug_index_saved = 0; 198 uint64_t debug_info_size = 0; 199 if (target) { 200 json_targets.emplace_back(target->ReportStatistics()); 201 } else { 202 for (const auto &target : debugger.GetTargetList().Targets()) 203 json_targets.emplace_back(target->ReportStatistics()); 204 } 205 std::vector<ModuleStats> modules; 206 std::lock_guard<std::recursive_mutex> guard( 207 Module::GetAllocationModuleCollectionMutex()); 208 const uint64_t num_modules = Module::GetNumberAllocatedModules(); 209 uint32_t num_debug_info_enabled_modules = 0; 210 uint32_t num_modules_has_debug_info = 0; 211 uint32_t num_modules_with_variable_errors = 0; 212 uint32_t num_modules_with_incomplete_types = 0; 213 uint32_t num_stripped_modules = 0; 214 for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { 215 Module *module = Module::GetAllocatedModuleAtIndex(image_idx); 216 ModuleStats module_stat; 217 module_stat.identifier = (intptr_t)module; 218 module_stat.path = module->GetFileSpec().GetPath(); 219 if (ConstString object_name = module->GetObjectName()) { 220 module_stat.path.append(1, '('); 221 module_stat.path.append(object_name.GetStringRef().str()); 222 module_stat.path.append(1, ')'); 223 } 224 module_stat.uuid = module->GetUUID().GetAsString(); 225 module_stat.triple = module->GetArchitecture().GetTriple().str(); 226 module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count(); 227 module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count(); 228 Symtab *symtab = module->GetSymtab(); 229 if (symtab) { 230 module_stat.symtab_loaded_from_cache = symtab->GetWasLoadedFromCache(); 231 if (module_stat.symtab_loaded_from_cache) 232 ++symtabs_loaded; 233 module_stat.symtab_saved_to_cache = symtab->GetWasSavedToCache(); 234 if (module_stat.symtab_saved_to_cache) 235 ++symtabs_saved; 236 } 237 SymbolFile *sym_file = module->GetSymbolFile(); 238 if (sym_file) { 239 240 if (sym_file->GetObjectFile() != module->GetObjectFile()) 241 module_stat.symfile_path = 242 sym_file->GetObjectFile()->GetFileSpec().GetPath(); 243 module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count(); 244 module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count(); 245 module_stat.debug_info_size = sym_file->GetDebugInfoSize(); 246 module_stat.debug_info_index_loaded_from_cache = 247 sym_file->GetDebugInfoIndexWasLoadedFromCache(); 248 if (module_stat.debug_info_index_loaded_from_cache) 249 ++debug_index_loaded; 250 module_stat.debug_info_index_saved_to_cache = 251 sym_file->GetDebugInfoIndexWasSavedToCache(); 252 if (module_stat.debug_info_index_saved_to_cache) 253 ++debug_index_saved; 254 ModuleList symbol_modules = sym_file->GetDebugInfoModules(); 255 for (const auto &symbol_module: symbol_modules.Modules()) 256 module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); 257 module_stat.symtab_stripped = module->GetObjectFile()->IsStripped(); 258 if (module_stat.symtab_stripped) 259 ++num_stripped_modules; 260 module_stat.debug_info_enabled = sym_file->GetLoadDebugInfoEnabled() && 261 module_stat.debug_info_size > 0; 262 module_stat.debug_info_had_variable_errors = 263 sym_file->GetDebugInfoHadFrameVariableErrors(); 264 if (module_stat.debug_info_enabled) 265 ++num_debug_info_enabled_modules; 266 if (module_stat.debug_info_size > 0) 267 ++num_modules_has_debug_info; 268 if (module_stat.debug_info_had_variable_errors) 269 ++num_modules_with_variable_errors; 270 } 271 symtab_parse_time += module_stat.symtab_parse_time; 272 symtab_index_time += module_stat.symtab_index_time; 273 debug_parse_time += module_stat.debug_parse_time; 274 debug_index_time += module_stat.debug_index_time; 275 debug_info_size += module_stat.debug_info_size; 276 module->ForEachTypeSystem([&](lldb::TypeSystemSP ts) { 277 if (auto stats = ts->ReportStatistics()) 278 module_stat.type_system_stats.insert({ts->GetPluginName(), *stats}); 279 if (ts->GetHasForcefullyCompletedTypes()) 280 module_stat.debug_info_had_incomplete_types = true; 281 return true; 282 }); 283 if (module_stat.debug_info_had_incomplete_types) 284 ++num_modules_with_incomplete_types; 285 286 json_modules.emplace_back(module_stat.ToJSON()); 287 } 288 289 ConstStringStats const_string_stats; 290 json::Object json_memory{ 291 {"strings", const_string_stats.ToJSON()}, 292 }; 293 294 json::Object global_stats{ 295 {"targets", std::move(json_targets)}, 296 {"modules", std::move(json_modules)}, 297 {"memory", std::move(json_memory)}, 298 {"totalSymbolTableParseTime", symtab_parse_time}, 299 {"totalSymbolTableIndexTime", symtab_index_time}, 300 {"totalSymbolTablesLoadedFromCache", symtabs_loaded}, 301 {"totalSymbolTablesSavedToCache", symtabs_saved}, 302 {"totalDebugInfoParseTime", debug_parse_time}, 303 {"totalDebugInfoIndexTime", debug_index_time}, 304 {"totalDebugInfoIndexLoadedFromCache", debug_index_loaded}, 305 {"totalDebugInfoIndexSavedToCache", debug_index_saved}, 306 {"totalDebugInfoByteSize", debug_info_size}, 307 {"totalModuleCount", num_modules}, 308 {"totalModuleCountHasDebugInfo", num_modules_has_debug_info}, 309 {"totalModuleCountWithVariableErrors", num_modules_with_variable_errors}, 310 {"totalModuleCountWithIncompleteTypes", num_modules_with_incomplete_types}, 311 {"totalDebugInfoEnabled", num_debug_info_enabled_modules}, 312 {"totalSymbolTableStripped", num_stripped_modules}, 313 }; 314 return std::move(global_stats); 315 } 316