1# Test the SBAPI for GetStatistics() 2 3import json 4import lldb 5from lldbsuite.test.decorators import * 6from lldbsuite.test.lldbtest import * 7from lldbsuite.test import lldbutil 8 9 10class TestStatsAPI(TestBase): 11 NO_DEBUG_INFO_TESTCASE = True 12 13 def test_stats_api(self): 14 """ 15 Test SBTarget::GetStatistics() API. 16 """ 17 self.build() 18 exe = self.getBuildArtifact("a.out") 19 # Launch a process and break 20 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 21 self, "break here", lldb.SBFileSpec("main.c") 22 ) 23 24 # Test enabling/disabling stats 25 self.assertFalse(target.GetCollectingStats()) 26 target.SetCollectingStats(True) 27 self.assertTrue(target.GetCollectingStats()) 28 target.SetCollectingStats(False) 29 self.assertFalse(target.GetCollectingStats()) 30 31 # Test the function to get the statistics in JSON'ish. 32 stats = target.GetStatistics() 33 stream = lldb.SBStream() 34 res = stats.GetAsJSON(stream) 35 debug_stats = json.loads(stream.GetData()) 36 self.assertIn( 37 "targets", 38 debug_stats, 39 'Make sure the "targets" key in in target.GetStatistics()', 40 ) 41 self.assertIn( 42 "modules", 43 debug_stats, 44 'Make sure the "modules" key in in target.GetStatistics()', 45 ) 46 stats_json = debug_stats["targets"][0] 47 self.assertIn( 48 "expressionEvaluation", 49 stats_json, 50 'Make sure the "expressionEvaluation" key in in target.GetStatistics()["targets"][0]', 51 ) 52 self.assertIn( 53 "frameVariable", 54 stats_json, 55 'Make sure the "frameVariable" key in in target.GetStatistics()["targets"][0]', 56 ) 57 expressionEvaluation = stats_json["expressionEvaluation"] 58 self.assertIn( 59 "successes", 60 expressionEvaluation, 61 'Make sure the "successes" key in in "expressionEvaluation" dictionary"', 62 ) 63 self.assertIn( 64 "failures", 65 expressionEvaluation, 66 'Make sure the "failures" key in in "expressionEvaluation" dictionary"', 67 ) 68 frameVariable = stats_json["frameVariable"] 69 self.assertIn( 70 "successes", 71 frameVariable, 72 'Make sure the "successes" key in in "frameVariable" dictionary"', 73 ) 74 self.assertIn( 75 "failures", 76 frameVariable, 77 'Make sure the "failures" key in in "frameVariable" dictionary"', 78 ) 79 80 # Test statistics summary. 81 stats_options = lldb.SBStatisticsOptions() 82 stats_options.SetSummaryOnly(True) 83 stats_summary = target.GetStatistics(stats_options) 84 stream_summary = lldb.SBStream() 85 stats_summary.GetAsJSON(stream_summary) 86 debug_stats_summary = json.loads(stream_summary.GetData()) 87 self.assertNotIn("modules", debug_stats_summary) 88 self.assertNotIn("commands", debug_stats_summary) 89 90 # Summary values should be the same as in full statistics. 91 # The exceptions to this are: 92 # - The parse time on Mac OS X is not deterministic. 93 # - Memory usage may grow over time due to the use of ConstString. 94 for key, value in debug_stats_summary.items(): 95 self.assertIn(key, debug_stats) 96 if key != "memory" and key != "targets" and not key.endswith("Time"): 97 self.assertEqual(debug_stats[key], value) 98 99 def test_command_stats_api(self): 100 """ 101 Test GetCommandInterpreter::GetStatistics() API. 102 """ 103 self.build() 104 exe = self.getBuildArtifact("a.out") 105 lldbutil.run_to_name_breakpoint(self, "main") 106 107 interp = self.dbg.GetCommandInterpreter() 108 result = lldb.SBCommandReturnObject() 109 interp.HandleCommand("bt", result) 110 111 stream = lldb.SBStream() 112 res = interp.GetStatistics().GetAsJSON(stream) 113 command_stats = json.loads(stream.GetData()) 114 115 # Verify bt command is correctly parsed into final form. 116 self.assertEqual(command_stats["thread backtrace"], 1) 117 # Verify original raw command is not duplicatedly captured. 118 self.assertNotIn("bt", command_stats) 119 # Verify bt's regex command is not duplicatedly captured. 120 self.assertNotIn("_regexp-bt", command_stats) 121 122 @add_test_categories(["dwo"]) 123 def test_command_stats_force(self): 124 """ 125 Test reporting all pssible debug info stats by force loading all debug 126 info. For example, dwo files 127 """ 128 src_dir = self.getSourceDir() 129 dwo_yaml_path = os.path.join(src_dir, "main-main.dwo.yaml") 130 exe_yaml_path = os.path.join(src_dir, "main.yaml") 131 dwo_path = self.getBuildArtifact("main-main.dwo") 132 exe_path = self.getBuildArtifact("main") 133 self.yaml2obj(dwo_yaml_path, dwo_path) 134 self.yaml2obj(exe_yaml_path, exe_path) 135 136 # Turn on symbols on-demand loading 137 self.runCmd("settings set symbols.load-on-demand true") 138 139 # We need the current working directory to be set to the build directory 140 os.chdir(self.getBuildDir()) 141 # Create a target with the object file we just created from YAML 142 target = self.dbg.CreateTarget(exe_path) 143 self.assertTrue(target, VALID_TARGET) 144 145 # Get statistics 146 stats_options = lldb.SBStatisticsOptions() 147 stats = target.GetStatistics(stats_options) 148 stream = lldb.SBStream() 149 stats.GetAsJSON(stream) 150 debug_stats = json.loads(stream.GetData()) 151 self.assertEqual(debug_stats["totalDebugInfoByteSize"], 193) 152 153 # Get statistics with force loading 154 stats_options.SetReportAllAvailableDebugInfo(True) 155 stats_force = target.GetStatistics(stats_options) 156 stream_force = lldb.SBStream() 157 stats_force.GetAsJSON(stream_force) 158 debug_stats_force = json.loads(stream_force.GetData()) 159 self.assertEqual(debug_stats_force["totalDebugInfoByteSize"], 445) 160