Index: lldb/include/lldb/Target/Statistics.h =================================================================== --- lldb/include/lldb/Target/Statistics.h +++ lldb/include/lldb/Target/Statistics.h @@ -9,6 +9,7 @@ #ifndef LLDB_TARGET_STATISTICS_H #define LLDB_TARGET_STATISTICS_H +#include "lldb/Utility/ConstString.h" #include "lldb/Utility/Stream.h" #include "lldb/lldb-forward.h" #include "llvm/Support/JSON.h" @@ -110,6 +111,11 @@ bool debug_info_index_saved_to_cache = false; }; +struct StringStats { + llvm::json::Value ToJSON() const; + ConstString::MemoryStats stats = ConstString::GetMemoryStats(); +}; + /// A class that represents statistics for a since lldb_private::Target. class TargetStats { public: Index: lldb/include/lldb/Utility/ConstString.h =================================================================== --- lldb/include/lldb/Utility/ConstString.h +++ lldb/include/lldb/Utility/ConstString.h @@ -408,6 +408,16 @@ /// in memory. static size_t StaticMemorySize(); + struct MemoryStats { + size_t GetTotalMemory() const { return total_memory; } + size_t GetBytesAllocated() const { return bytes_allocated; } + size_t GetBytesWasted() const { return total_memory - bytes_allocated; } + size_t total_memory; + size_t bytes_allocated; + }; + + static MemoryStats GetMemoryStats(); + protected: template friend struct ::llvm::DenseMapInfo; /// Only used by DenseMapInfo. Index: lldb/source/Target/Statistics.cpp =================================================================== --- lldb/source/Target/Statistics.cpp +++ lldb/source/Target/Statistics.cpp @@ -65,6 +65,14 @@ return module; } +llvm::json::Value StringStats::ToJSON() const { + json::Object obj; + obj.try_emplace("bytesTotal", stats.GetTotalMemory()); + obj.try_emplace("bytesAllocated", stats.GetBytesAllocated()); + obj.try_emplace("bytesWasted", stats.GetBytesWasted()); + return obj; +} + json::Value TargetStats::ToJSON(Target &target) { CollectStats(target); @@ -212,9 +220,12 @@ json_modules.emplace_back(module_stat.ToJSON()); } + StringStats string_stats; + json::Object global_stats{ {"targets", std::move(json_targets)}, {"modules", std::move(json_modules)}, + {"strings", string_stats.ToJSON()}, {"totalSymbolTableParseTime", symtab_parse_time}, {"totalSymbolTableIndexTime", symtab_index_time}, {"totalSymbolTablesLoadedFromCache", symtabs_loaded}, Index: lldb/source/Utility/ConstString.cpp =================================================================== --- lldb/source/Utility/ConstString.cpp +++ lldb/source/Utility/ConstString.cpp @@ -171,6 +171,17 @@ return mem_size; } + ConstString::MemoryStats GetMemoryStats() const { + ConstString::MemoryStats stats; + for (const auto &pool : m_string_pools) { + llvm::sys::SmartScopedReader rlock(pool.m_mutex); + const Allocator &alloc = pool.m_string_map.getAllocator(); + stats.total_memory += alloc.getTotalMemory(); + stats.bytes_allocated += alloc.getBytesAllocated(); + } + return stats; + } + protected: uint8_t hash(const llvm::StringRef &s) const { uint32_t h = llvm::djbHash(s); @@ -332,6 +343,10 @@ return StringPool().MemorySize(); } +ConstString::MemoryStats ConstString::GetMemoryStats() { + return StringPool().GetMemoryStats(); +} + void llvm::format_provider::format(const ConstString &CS, llvm::raw_ostream &OS, llvm::StringRef Options) { Index: lldb/test/API/commands/statistics/basic/TestStats.py =================================================================== --- lldb/test/API/commands/statistics/basic/TestStats.py +++ lldb/test/API/commands/statistics/basic/TestStats.py @@ -135,6 +135,7 @@ (lldb) statistics dump { + "strings" : {...}, "modules" : [...], "targets" : [ { @@ -160,6 +161,7 @@ target = self.createTestTarget() debug_stats = self.get_stats() debug_stat_keys = [ + 'strings', 'modules', 'targets', 'totalSymbolTableParseTime', @@ -197,6 +199,7 @@ (lldb) statistics dump { + "strings" : {...}, "modules" : [...], "targets" : [ { @@ -227,6 +230,7 @@ lldb.SBFileSpec("main.c")) debug_stats = self.get_stats() debug_stat_keys = [ + 'strings', 'modules', 'targets', 'totalSymbolTableParseTime', @@ -254,6 +258,36 @@ self.assertGreater(stats['launchOrAttachTime'], 0.0) self.assertGreater(stats['targetCreateTime'], 0.0) + def test_strings(self): + """ + Test "statistics dump" and the string memory information. + """ + exe = self.getBuildArtifact("a.out") + target = self.createTestTarget(file_path=exe) + debug_stats = self.get_stats() + debug_stat_keys = [ + 'strings', + 'modules', + 'targets', + 'totalSymbolTableParseTime', + 'totalSymbolTableIndexTime', + 'totalSymbolTablesLoadedFromCache', + 'totalSymbolTablesSavedToCache', + 'totalDebugInfoParseTime', + 'totalDebugInfoIndexTime', + 'totalDebugInfoIndexLoadedFromCache', + 'totalDebugInfoIndexSavedToCache', + 'totalDebugInfoByteSize' + ] + self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) + stats = debug_stats['strings'] + keys_exist = [ + 'bytesTotal', + 'bytesAllocated', + 'bytesWasted', + ] + self.verify_keys(stats, '"stats"', keys_exist, None) + def find_module_in_metrics(self, path, stats): modules = stats['modules'] for module in modules: @@ -269,6 +303,7 @@ target = self.createTestTarget(file_path=exe) debug_stats = self.get_stats() debug_stat_keys = [ + 'strings', 'modules', 'targets', 'totalSymbolTableParseTime', @@ -312,6 +347,7 @@ Output expected to be something like: { + "strings" : {...}, "modules" : [...], "targets" : [ { @@ -355,6 +391,7 @@ self.runCmd("b a_function") debug_stats = self.get_stats() debug_stat_keys = [ + 'strings', 'modules', 'targets', 'totalSymbolTableParseTime',