1d7b33853SGreg Claytonimport json 23db7cc1bSGreg Claytonimport os 370f41a8cSroyitaqiimport re 4*24feaab8Sjeffreytan81 5*24feaab8Sjeffreytan81import lldb 66bbdecc5SRaphael Isemannfrom lldbsuite.test.decorators import * 76bbdecc5SRaphael Isemannfrom lldbsuite.test.lldbtest import * 86bbdecc5SRaphael Isemannfrom lldbsuite.test import lldbutil 999451b44SJordan Rupprecht 106bbdecc5SRaphael Isemann 112238dcc3SJonas Devlieghereclass TestCase(TestBase): 12d7b33853SGreg Clayton NO_DEBUG_INFO_TESTCASE = True 13d7b33853SGreg Clayton 14d7b33853SGreg Clayton def test_enable_disable(self): 15d7b33853SGreg Clayton """ 16d7b33853SGreg Clayton Test "statistics disable" and "statistics enable". These don't do 17d7b33853SGreg Clayton anything anymore for cheap to gather statistics. In the future if 18d7b33853SGreg Clayton statistics are expensive to gather, we can enable the feature inside 19d7b33853SGreg Clayton of LLDB and test that enabling and disabling stops expesive information 20d7b33853SGreg Clayton from being gathered. 21d7b33853SGreg Clayton """ 223db7cc1bSGreg Clayton self.build() 23d7b33853SGreg Clayton target = self.createTestTarget() 246bbdecc5SRaphael Isemann 252238dcc3SJonas Devlieghere self.expect( 262238dcc3SJonas Devlieghere "statistics disable", 272238dcc3SJonas Devlieghere substrs=["need to enable statistics before disabling"], 282238dcc3SJonas Devlieghere error=True, 292238dcc3SJonas Devlieghere ) 306bbdecc5SRaphael Isemann self.expect("statistics enable") 312238dcc3SJonas Devlieghere self.expect("statistics enable", substrs=["already enabled"], error=True) 326bbdecc5SRaphael Isemann self.expect("statistics disable") 332238dcc3SJonas Devlieghere self.expect( 342238dcc3SJonas Devlieghere "statistics disable", 352238dcc3SJonas Devlieghere substrs=["need to enable statistics before disabling"], 362238dcc3SJonas Devlieghere error=True, 372238dcc3SJonas Devlieghere ) 386bbdecc5SRaphael Isemann 39d7b33853SGreg Clayton def verify_key_in_dict(self, key, d, description): 401eeeab82SJordan Rupprecht self.assertIn( 411eeeab82SJordan Rupprecht key, d, 'make sure key "%s" is in dictionary %s' % (key, description) 422238dcc3SJonas Devlieghere ) 43d7b33853SGreg Clayton 44d7b33853SGreg Clayton def verify_key_not_in_dict(self, key, d, description): 451eeeab82SJordan Rupprecht self.assertNotIn( 461eeeab82SJordan Rupprecht key, d, 'make sure key "%s" is in dictionary %s' % (key, description) 472238dcc3SJonas Devlieghere ) 48d7b33853SGreg Clayton 49d7b33853SGreg Clayton def verify_keys(self, dict, description, keys_exist, keys_missing=None): 50d7b33853SGreg Clayton """ 51d7b33853SGreg Clayton Verify that all keys in "keys_exist" list are top level items in 52d7b33853SGreg Clayton "dict", and that all keys in "keys_missing" do not exist as top 53d7b33853SGreg Clayton level items in "dict". 54d7b33853SGreg Clayton """ 55d7b33853SGreg Clayton if keys_exist: 56d7b33853SGreg Clayton for key in keys_exist: 57d7b33853SGreg Clayton self.verify_key_in_dict(key, dict, description) 58d7b33853SGreg Clayton if keys_missing: 59d7b33853SGreg Clayton for key in keys_missing: 60d7b33853SGreg Clayton self.verify_key_not_in_dict(key, dict, description) 61d7b33853SGreg Clayton 62d7b33853SGreg Clayton def verify_success_fail_count(self, stats, key, num_successes, num_fails): 63d7b33853SGreg Clayton self.verify_key_in_dict(key, stats, 'stats["%s"]' % (key)) 64d7b33853SGreg Clayton success_fail_dict = stats[key] 652238dcc3SJonas Devlieghere self.assertEqual( 662238dcc3SJonas Devlieghere success_fail_dict["successes"], num_successes, "make sure success count" 672238dcc3SJonas Devlieghere ) 682238dcc3SJonas Devlieghere self.assertEqual( 692238dcc3SJonas Devlieghere success_fail_dict["failures"], num_fails, "make sure success count" 702238dcc3SJonas Devlieghere ) 71d7b33853SGreg Clayton 72c571988eSGreg Clayton def get_target_stats(self, debug_stats): 73c571988eSGreg Clayton if "targets" in debug_stats: 74c571988eSGreg Clayton return debug_stats["targets"][0] 75c571988eSGreg Clayton return None 76c571988eSGreg Clayton 7776706090Sjeffreytan81 def get_command_stats(self, debug_stats): 7876706090Sjeffreytan81 if "commands" in debug_stats: 7976706090Sjeffreytan81 return debug_stats["commands"] 8076706090Sjeffreytan81 return None 8176706090Sjeffreytan81 82d7b33853SGreg Clayton def test_expressions_frame_var_counts(self): 833db7cc1bSGreg Clayton self.build() 842238dcc3SJonas Devlieghere lldbutil.run_to_source_breakpoint( 8522144e20SJacob Lalonde self, "// break here", lldb.SBFileSpec("main.cpp") 862238dcc3SJonas Devlieghere ) 87d7b33853SGreg Clayton 882238dcc3SJonas Devlieghere self.expect("expr patatino", substrs=["27"]) 89c571988eSGreg Clayton stats = self.get_target_stats(self.get_stats()) 902238dcc3SJonas Devlieghere self.verify_success_fail_count(stats, "expressionEvaluation", 1, 0) 912238dcc3SJonas Devlieghere self.expect( 922238dcc3SJonas Devlieghere "expr doesnt_exist", 932238dcc3SJonas Devlieghere error=True, 942238dcc3SJonas Devlieghere substrs=["undeclared identifier 'doesnt_exist'"], 952238dcc3SJonas Devlieghere ) 966a4905aeSRaphael Isemann # Doesn't successfully execute. 976a4905aeSRaphael Isemann self.expect("expr int *i = nullptr; *i", error=True) 98910838f0SGreg Clayton # Interpret an integer as an array with 3 elements is a failure for 99910838f0SGreg Clayton # the "expr" command, but the expression evaluation will succeed and 100910838f0SGreg Clayton # be counted as a success even though the "expr" options will for the 101910838f0SGreg Clayton # command to fail. It is more important to track expression evaluation 102910838f0SGreg Clayton # from all sources instead of just through the command, so this was 103910838f0SGreg Clayton # changed. If we want to track command success and fails, we can do 104910838f0SGreg Clayton # so using another metric. 1052238dcc3SJonas Devlieghere self.expect( 1062238dcc3SJonas Devlieghere "expr -Z 3 -- 1", 1072238dcc3SJonas Devlieghere error=True, 1082238dcc3SJonas Devlieghere substrs=["expression cannot be used with --element-count"], 1092238dcc3SJonas Devlieghere ) 1106a4905aeSRaphael Isemann # We should have gotten 3 new failures and the previous success. 111c571988eSGreg Clayton stats = self.get_target_stats(self.get_stats()) 1122238dcc3SJonas Devlieghere self.verify_success_fail_count(stats, "expressionEvaluation", 2, 2) 1136bbdecc5SRaphael Isemann 1146bbdecc5SRaphael Isemann self.expect("statistics enable") 1156bbdecc5SRaphael Isemann # 'frame var' with enabled statistics will change stats. 1162238dcc3SJonas Devlieghere self.expect("frame var", substrs=["27"]) 117c571988eSGreg Clayton stats = self.get_target_stats(self.get_stats()) 1182238dcc3SJonas Devlieghere self.verify_success_fail_count(stats, "frameVariable", 1, 0) 119d7b33853SGreg Clayton 120dbd36e1eSGreg Clayton # Test that "stopCount" is available when the process has run 1211eeeab82SJordan Rupprecht self.assertIn("stopCount", stats, 'ensure "stopCount" is in target JSON') 1222238dcc3SJonas Devlieghere self.assertGreater( 1232238dcc3SJonas Devlieghere stats["stopCount"], 0, 'make sure "stopCount" is greater than zero' 1242238dcc3SJonas Devlieghere ) 125dbd36e1eSGreg Clayton 126d7b33853SGreg Clayton def test_default_no_run(self): 127d7b33853SGreg Clayton """Test "statistics dump" without running the target. 128d7b33853SGreg Clayton 129d7b33853SGreg Clayton When we don't run the target, we expect to not see any 'firstStopTime' 130d7b33853SGreg Clayton or 'launchOrAttachTime' top level keys that measure the launch or 131d7b33853SGreg Clayton attach of the target. 132d7b33853SGreg Clayton 133d7b33853SGreg Clayton Output expected to be something like: 134d7b33853SGreg Clayton 135d7b33853SGreg Clayton (lldb) statistics dump 136d7b33853SGreg Clayton { 137cd8122b2SJonas Devlieghere "memory" : {...}, 138c571988eSGreg Clayton "modules" : [...], 139c571988eSGreg Clayton "targets" : [ 140c571988eSGreg Clayton { 141d7b33853SGreg Clayton "targetCreateTime": 0.26566899599999999, 142d7b33853SGreg Clayton "expressionEvaluation": { 143d7b33853SGreg Clayton "failures": 0, 144d7b33853SGreg Clayton "successes": 0 145d7b33853SGreg Clayton }, 146d7b33853SGreg Clayton "frameVariable": { 147d7b33853SGreg Clayton "failures": 0, 148d7b33853SGreg Clayton "successes": 0 149d7b33853SGreg Clayton }, 150c571988eSGreg Clayton "moduleIdentifiers": [...], 151c571988eSGreg Clayton } 152c571988eSGreg Clayton ], 1532887d9fdSGreg Clayton "totalDebugInfoByteSize": 182522234, 1542887d9fdSGreg Clayton "totalDebugInfoIndexTime": 2.33343, 1552887d9fdSGreg Clayton "totalDebugInfoParseTime": 8.2121400240000071, 156c571988eSGreg Clayton "totalSymbolTableParseTime": 0.123, 157c571988eSGreg Clayton "totalSymbolTableIndexTime": 0.234, 158d7b33853SGreg Clayton } 159d7b33853SGreg Clayton """ 1603db7cc1bSGreg Clayton self.build() 161d7b33853SGreg Clayton target = self.createTestTarget() 162c571988eSGreg Clayton debug_stats = self.get_stats() 163c571988eSGreg Clayton debug_stat_keys = [ 1642238dcc3SJonas Devlieghere "memory", 1652238dcc3SJonas Devlieghere "modules", 1662238dcc3SJonas Devlieghere "targets", 1672238dcc3SJonas Devlieghere "totalSymbolTableParseTime", 1682238dcc3SJonas Devlieghere "totalSymbolTableIndexTime", 1692238dcc3SJonas Devlieghere "totalSymbolTablesLoadedFromCache", 1702238dcc3SJonas Devlieghere "totalSymbolTablesSavedToCache", 1712238dcc3SJonas Devlieghere "totalDebugInfoByteSize", 1722238dcc3SJonas Devlieghere "totalDebugInfoIndexTime", 1732238dcc3SJonas Devlieghere "totalDebugInfoIndexLoadedFromCache", 1742238dcc3SJonas Devlieghere "totalDebugInfoIndexSavedToCache", 1752238dcc3SJonas Devlieghere "totalDebugInfoParseTime", 176c571988eSGreg Clayton ] 177c571988eSGreg Clayton self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) 1782238dcc3SJonas Devlieghere stats = debug_stats["targets"][0] 179d7b33853SGreg Clayton keys_exist = [ 1802238dcc3SJonas Devlieghere "expressionEvaluation", 1812238dcc3SJonas Devlieghere "frameVariable", 1822238dcc3SJonas Devlieghere "moduleIdentifiers", 1832238dcc3SJonas Devlieghere "targetCreateTime", 184d7b33853SGreg Clayton ] 1852238dcc3SJonas Devlieghere keys_missing = ["firstStopTime", "launchOrAttachTime"] 186d7b33853SGreg Clayton self.verify_keys(stats, '"stats"', keys_exist, keys_missing) 1872238dcc3SJonas Devlieghere self.assertGreater(stats["targetCreateTime"], 0.0) 188d7b33853SGreg Clayton 189d7b33853SGreg Clayton def test_default_with_run(self): 190d7b33853SGreg Clayton """Test "statistics dump" when running the target to a breakpoint. 191d7b33853SGreg Clayton 192d7b33853SGreg Clayton When we run the target, we expect to see 'launchOrAttachTime' and 193d7b33853SGreg Clayton 'firstStopTime' top level keys. 194d7b33853SGreg Clayton 195d7b33853SGreg Clayton Output expected to be something like: 196d7b33853SGreg Clayton 197d7b33853SGreg Clayton (lldb) statistics dump 198d7b33853SGreg Clayton { 199cd8122b2SJonas Devlieghere "memory" : {...}, 200c571988eSGreg Clayton "modules" : [...], 201c571988eSGreg Clayton "targets" : [ 202c571988eSGreg Clayton { 203d7b33853SGreg Clayton "firstStopTime": 0.34164492800000001, 204d7b33853SGreg Clayton "launchOrAttachTime": 0.31969605400000001, 205c571988eSGreg Clayton "moduleIdentifiers": [...], 206d7b33853SGreg Clayton "targetCreateTime": 0.0040863039999999998 207d7b33853SGreg Clayton "expressionEvaluation": { 208d7b33853SGreg Clayton "failures": 0, 209d7b33853SGreg Clayton "successes": 0 210d7b33853SGreg Clayton }, 211d7b33853SGreg Clayton "frameVariable": { 212d7b33853SGreg Clayton "failures": 0, 213d7b33853SGreg Clayton "successes": 0 214d7b33853SGreg Clayton }, 215d7b33853SGreg Clayton } 216c571988eSGreg Clayton ], 2172887d9fdSGreg Clayton "totalDebugInfoByteSize": 182522234, 2182887d9fdSGreg Clayton "totalDebugInfoIndexTime": 2.33343, 2192887d9fdSGreg Clayton "totalDebugInfoParseTime": 8.2121400240000071, 220c571988eSGreg Clayton "totalSymbolTableParseTime": 0.123, 221c571988eSGreg Clayton "totalSymbolTableIndexTime": 0.234, 222c571988eSGreg Clayton } 223d7b33853SGreg Clayton 224d7b33853SGreg Clayton """ 2253db7cc1bSGreg Clayton self.build() 226d7b33853SGreg Clayton target = self.createTestTarget() 2272238dcc3SJonas Devlieghere lldbutil.run_to_source_breakpoint( 22822144e20SJacob Lalonde self, "// break here", lldb.SBFileSpec("main.cpp") 2292238dcc3SJonas Devlieghere ) 230c571988eSGreg Clayton debug_stats = self.get_stats() 231c571988eSGreg Clayton debug_stat_keys = [ 2322238dcc3SJonas Devlieghere "memory", 2332238dcc3SJonas Devlieghere "modules", 2342238dcc3SJonas Devlieghere "targets", 2352238dcc3SJonas Devlieghere "totalSymbolTableParseTime", 2362238dcc3SJonas Devlieghere "totalSymbolTableIndexTime", 2372238dcc3SJonas Devlieghere "totalSymbolTablesLoadedFromCache", 2382238dcc3SJonas Devlieghere "totalSymbolTablesSavedToCache", 2392238dcc3SJonas Devlieghere "totalDebugInfoByteSize", 2402238dcc3SJonas Devlieghere "totalDebugInfoIndexTime", 2412238dcc3SJonas Devlieghere "totalDebugInfoIndexLoadedFromCache", 2422238dcc3SJonas Devlieghere "totalDebugInfoIndexSavedToCache", 2432238dcc3SJonas Devlieghere "totalDebugInfoParseTime", 244c571988eSGreg Clayton ] 245c571988eSGreg Clayton self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) 2462238dcc3SJonas Devlieghere stats = debug_stats["targets"][0] 247d7b33853SGreg Clayton keys_exist = [ 2482238dcc3SJonas Devlieghere "expressionEvaluation", 2492238dcc3SJonas Devlieghere "firstStopTime", 2502238dcc3SJonas Devlieghere "frameVariable", 2512238dcc3SJonas Devlieghere "launchOrAttachTime", 2522238dcc3SJonas Devlieghere "moduleIdentifiers", 2532238dcc3SJonas Devlieghere "targetCreateTime", 25422144e20SJacob Lalonde "summaryProviderStatistics", 255d7b33853SGreg Clayton ] 256d7b33853SGreg Clayton self.verify_keys(stats, '"stats"', keys_exist, None) 2572238dcc3SJonas Devlieghere self.assertGreater(stats["firstStopTime"], 0.0) 2582238dcc3SJonas Devlieghere self.assertGreater(stats["launchOrAttachTime"], 0.0) 2592238dcc3SJonas Devlieghere self.assertGreater(stats["targetCreateTime"], 0.0) 260c571988eSGreg Clayton 261cd8122b2SJonas Devlieghere def test_memory(self): 262cd8122b2SJonas Devlieghere """ 263cd8122b2SJonas Devlieghere Test "statistics dump" and the memory information. 264cd8122b2SJonas Devlieghere """ 2653db7cc1bSGreg Clayton self.build() 266cd8122b2SJonas Devlieghere exe = self.getBuildArtifact("a.out") 267cd8122b2SJonas Devlieghere target = self.createTestTarget(file_path=exe) 268cd8122b2SJonas Devlieghere debug_stats = self.get_stats() 269cd8122b2SJonas Devlieghere debug_stat_keys = [ 2702238dcc3SJonas Devlieghere "memory", 2712238dcc3SJonas Devlieghere "modules", 2722238dcc3SJonas Devlieghere "targets", 2732238dcc3SJonas Devlieghere "totalSymbolTableParseTime", 2742238dcc3SJonas Devlieghere "totalSymbolTableIndexTime", 2752238dcc3SJonas Devlieghere "totalSymbolTablesLoadedFromCache", 2762238dcc3SJonas Devlieghere "totalSymbolTablesSavedToCache", 2772238dcc3SJonas Devlieghere "totalDebugInfoParseTime", 2782238dcc3SJonas Devlieghere "totalDebugInfoIndexTime", 2792238dcc3SJonas Devlieghere "totalDebugInfoIndexLoadedFromCache", 2802238dcc3SJonas Devlieghere "totalDebugInfoIndexSavedToCache", 2812238dcc3SJonas Devlieghere "totalDebugInfoByteSize", 282cd8122b2SJonas Devlieghere ] 283cd8122b2SJonas Devlieghere self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) 284cd8122b2SJonas Devlieghere 2852238dcc3SJonas Devlieghere memory = debug_stats["memory"] 286cd8122b2SJonas Devlieghere memory_keys = [ 2872238dcc3SJonas Devlieghere "strings", 288cd8122b2SJonas Devlieghere ] 289cd8122b2SJonas Devlieghere self.verify_keys(memory, '"memory"', memory_keys, None) 290cd8122b2SJonas Devlieghere 2912238dcc3SJonas Devlieghere strings = memory["strings"] 292cd8122b2SJonas Devlieghere strings_keys = [ 2932238dcc3SJonas Devlieghere "bytesTotal", 2942238dcc3SJonas Devlieghere "bytesUsed", 2952238dcc3SJonas Devlieghere "bytesUnused", 296cd8122b2SJonas Devlieghere ] 297cd8122b2SJonas Devlieghere self.verify_keys(strings, '"strings"', strings_keys, None) 298cd8122b2SJonas Devlieghere 299c571988eSGreg Clayton def find_module_in_metrics(self, path, stats): 3002238dcc3SJonas Devlieghere modules = stats["modules"] 301c571988eSGreg Clayton for module in modules: 3022238dcc3SJonas Devlieghere if module["path"] == path: 303c571988eSGreg Clayton return module 304c571988eSGreg Clayton return None 305c571988eSGreg Clayton 3063db7cc1bSGreg Clayton def find_module_by_id_in_metrics(self, id, stats): 3072238dcc3SJonas Devlieghere modules = stats["modules"] 3083db7cc1bSGreg Clayton for module in modules: 3092238dcc3SJonas Devlieghere if module["identifier"] == id: 3103db7cc1bSGreg Clayton return module 3113db7cc1bSGreg Clayton return None 3123db7cc1bSGreg Clayton 313c571988eSGreg Clayton def test_modules(self): 314c571988eSGreg Clayton """ 315c571988eSGreg Clayton Test "statistics dump" and the module information. 316c571988eSGreg Clayton """ 3173db7cc1bSGreg Clayton self.build() 318c571988eSGreg Clayton exe = self.getBuildArtifact("a.out") 319c571988eSGreg Clayton target = self.createTestTarget(file_path=exe) 320c571988eSGreg Clayton debug_stats = self.get_stats() 321c571988eSGreg Clayton debug_stat_keys = [ 3222238dcc3SJonas Devlieghere "memory", 3232238dcc3SJonas Devlieghere "modules", 3242238dcc3SJonas Devlieghere "targets", 3252238dcc3SJonas Devlieghere "totalSymbolTableParseTime", 3262238dcc3SJonas Devlieghere "totalSymbolTableIndexTime", 3272238dcc3SJonas Devlieghere "totalSymbolTablesLoadedFromCache", 3282238dcc3SJonas Devlieghere "totalSymbolTablesSavedToCache", 3292238dcc3SJonas Devlieghere "totalDebugInfoParseTime", 3302238dcc3SJonas Devlieghere "totalDebugInfoIndexTime", 3312238dcc3SJonas Devlieghere "totalDebugInfoIndexLoadedFromCache", 3322238dcc3SJonas Devlieghere "totalDebugInfoIndexSavedToCache", 3332238dcc3SJonas Devlieghere "totalDebugInfoByteSize", 334c571988eSGreg Clayton ] 335c571988eSGreg Clayton self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) 3362238dcc3SJonas Devlieghere stats = debug_stats["targets"][0] 337c571988eSGreg Clayton keys_exist = [ 3382238dcc3SJonas Devlieghere "moduleIdentifiers", 339c571988eSGreg Clayton ] 340c571988eSGreg Clayton self.verify_keys(stats, '"stats"', keys_exist, None) 341c571988eSGreg Clayton exe_module = self.find_module_in_metrics(exe, debug_stats) 342c571988eSGreg Clayton module_keys = [ 3432238dcc3SJonas Devlieghere "debugInfoByteSize", 3442238dcc3SJonas Devlieghere "debugInfoIndexLoadedFromCache", 3452238dcc3SJonas Devlieghere "debugInfoIndexTime", 3462238dcc3SJonas Devlieghere "debugInfoIndexSavedToCache", 3472238dcc3SJonas Devlieghere "debugInfoParseTime", 3482238dcc3SJonas Devlieghere "identifier", 3492238dcc3SJonas Devlieghere "path", 3502238dcc3SJonas Devlieghere "symbolTableIndexTime", 3512238dcc3SJonas Devlieghere "symbolTableLoadedFromCache", 3522238dcc3SJonas Devlieghere "symbolTableParseTime", 3532238dcc3SJonas Devlieghere "symbolTableSavedToCache", 3542238dcc3SJonas Devlieghere "triple", 3552238dcc3SJonas Devlieghere "uuid", 356c571988eSGreg Clayton ] 357c571988eSGreg Clayton self.assertNotEqual(exe_module, None) 358c571988eSGreg Clayton self.verify_keys(exe_module, 'module dict for "%s"' % (exe), module_keys) 359fb254968SGreg Clayton 36076706090Sjeffreytan81 def test_commands(self): 36176706090Sjeffreytan81 """ 36276706090Sjeffreytan81 Test "statistics dump" and the command information. 36376706090Sjeffreytan81 """ 36476706090Sjeffreytan81 self.build() 36576706090Sjeffreytan81 exe = self.getBuildArtifact("a.out") 36676706090Sjeffreytan81 target = self.createTestTarget(file_path=exe) 36776706090Sjeffreytan81 36876706090Sjeffreytan81 interp = self.dbg.GetCommandInterpreter() 36976706090Sjeffreytan81 result = lldb.SBCommandReturnObject() 37076706090Sjeffreytan81 interp.HandleCommand("target list", result) 37176706090Sjeffreytan81 interp.HandleCommand("target list", result) 37276706090Sjeffreytan81 37376706090Sjeffreytan81 debug_stats = self.get_stats() 37476706090Sjeffreytan81 37576706090Sjeffreytan81 command_stats = self.get_command_stats(debug_stats) 37676706090Sjeffreytan81 self.assertNotEqual(command_stats, None) 37776706090Sjeffreytan81 self.assertEqual(command_stats["target list"], 2) 37876706090Sjeffreytan81 379fb254968SGreg Clayton def test_breakpoints(self): 380fb254968SGreg Clayton """Test "statistics dump" 381fb254968SGreg Clayton 382fb254968SGreg Clayton Output expected to be something like: 383fb254968SGreg Clayton 384fb254968SGreg Clayton { 385cd8122b2SJonas Devlieghere "memory" : {...}, 386fb254968SGreg Clayton "modules" : [...], 387fb254968SGreg Clayton "targets" : [ 388fb254968SGreg Clayton { 389fb254968SGreg Clayton "firstStopTime": 0.34164492800000001, 390fb254968SGreg Clayton "launchOrAttachTime": 0.31969605400000001, 391fb254968SGreg Clayton "moduleIdentifiers": [...], 392fb254968SGreg Clayton "targetCreateTime": 0.0040863039999999998 393fb254968SGreg Clayton "expressionEvaluation": { 394fb254968SGreg Clayton "failures": 0, 395fb254968SGreg Clayton "successes": 0 396fb254968SGreg Clayton }, 397fb254968SGreg Clayton "frameVariable": { 398fb254968SGreg Clayton "failures": 0, 399fb254968SGreg Clayton "successes": 0 400fb254968SGreg Clayton }, 401fb254968SGreg Clayton "breakpoints": [ 402fb254968SGreg Clayton { 403fb254968SGreg Clayton "details": {...}, 404fb254968SGreg Clayton "id": 1, 405fb254968SGreg Clayton "resolveTime": 2.65438675 406fb254968SGreg Clayton }, 407fb254968SGreg Clayton { 408fb254968SGreg Clayton "details": {...}, 409fb254968SGreg Clayton "id": 2, 410fb254968SGreg Clayton "resolveTime": 4.3632581669999997 411fb254968SGreg Clayton } 412fb254968SGreg Clayton ] 413fb254968SGreg Clayton } 414fb254968SGreg Clayton ], 415fb254968SGreg Clayton "totalDebugInfoByteSize": 182522234, 416fb254968SGreg Clayton "totalDebugInfoIndexTime": 2.33343, 417fb254968SGreg Clayton "totalDebugInfoParseTime": 8.2121400240000071, 418fb254968SGreg Clayton "totalSymbolTableParseTime": 0.123, 419fb254968SGreg Clayton "totalSymbolTableIndexTime": 0.234, 420fb254968SGreg Clayton "totalBreakpointResolveTime": 7.0176449170000001 421fb254968SGreg Clayton } 422fb254968SGreg Clayton 423fb254968SGreg Clayton """ 4243db7cc1bSGreg Clayton self.build() 425fb254968SGreg Clayton target = self.createTestTarget() 426fb254968SGreg Clayton self.runCmd("b main.cpp:7") 427fb254968SGreg Clayton self.runCmd("b a_function") 428fb254968SGreg Clayton debug_stats = self.get_stats() 429fb254968SGreg Clayton debug_stat_keys = [ 4302238dcc3SJonas Devlieghere "memory", 4312238dcc3SJonas Devlieghere "modules", 4322238dcc3SJonas Devlieghere "targets", 4332238dcc3SJonas Devlieghere "totalSymbolTableParseTime", 4342238dcc3SJonas Devlieghere "totalSymbolTableIndexTime", 4352238dcc3SJonas Devlieghere "totalSymbolTablesLoadedFromCache", 4362238dcc3SJonas Devlieghere "totalSymbolTablesSavedToCache", 4372238dcc3SJonas Devlieghere "totalDebugInfoParseTime", 4382238dcc3SJonas Devlieghere "totalDebugInfoIndexTime", 4392238dcc3SJonas Devlieghere "totalDebugInfoIndexLoadedFromCache", 4402238dcc3SJonas Devlieghere "totalDebugInfoIndexSavedToCache", 4412238dcc3SJonas Devlieghere "totalDebugInfoByteSize", 442fb254968SGreg Clayton ] 443fb254968SGreg Clayton self.verify_keys(debug_stats, '"debug_stats"', debug_stat_keys, None) 4442238dcc3SJonas Devlieghere target_stats = debug_stats["targets"][0] 445fb254968SGreg Clayton keys_exist = [ 4462238dcc3SJonas Devlieghere "breakpoints", 4472238dcc3SJonas Devlieghere "expressionEvaluation", 4482238dcc3SJonas Devlieghere "frameVariable", 4492238dcc3SJonas Devlieghere "targetCreateTime", 4502238dcc3SJonas Devlieghere "moduleIdentifiers", 4512238dcc3SJonas Devlieghere "totalBreakpointResolveTime", 45222144e20SJacob Lalonde "summaryProviderStatistics", 453fb254968SGreg Clayton ] 454fb254968SGreg Clayton self.verify_keys(target_stats, '"stats"', keys_exist, None) 4552238dcc3SJonas Devlieghere self.assertGreater(target_stats["totalBreakpointResolveTime"], 0.0) 4562238dcc3SJonas Devlieghere breakpoints = target_stats["breakpoints"] 457fb254968SGreg Clayton bp_keys_exist = [ 4582238dcc3SJonas Devlieghere "details", 4592238dcc3SJonas Devlieghere "id", 4602238dcc3SJonas Devlieghere "internal", 4612238dcc3SJonas Devlieghere "numLocations", 4622238dcc3SJonas Devlieghere "numResolvedLocations", 4632238dcc3SJonas Devlieghere "resolveTime", 464fb254968SGreg Clayton ] 465fb254968SGreg Clayton for breakpoint in breakpoints: 4662238dcc3SJonas Devlieghere self.verify_keys( 4672238dcc3SJonas Devlieghere breakpoint, 'target_stats["breakpoints"]', bp_keys_exist, None 4682238dcc3SJonas Devlieghere ) 4693db7cc1bSGreg Clayton 4703db7cc1bSGreg Clayton @skipUnlessDarwin 4713db7cc1bSGreg Clayton @no_debug_info_test 4723db7cc1bSGreg Clayton def test_dsym_binary_has_symfile_in_stats(self): 4733db7cc1bSGreg Clayton """ 4743db7cc1bSGreg Clayton Test that if our executable has a stand alone dSYM file containing 4753db7cc1bSGreg Clayton debug information, that the dSYM file path is listed as a key/value 4763db7cc1bSGreg Clayton pair in the "a.out" binaries module stats. Also verify the the main 4773db7cc1bSGreg Clayton executable's module statistics has a debug info size that is greater 4783db7cc1bSGreg Clayton than zero as the dSYM contains debug info. 4793db7cc1bSGreg Clayton """ 4803db7cc1bSGreg Clayton self.build(debug_info="dsym") 4812238dcc3SJonas Devlieghere exe_name = "a.out" 4823db7cc1bSGreg Clayton exe = self.getBuildArtifact(exe_name) 4833db7cc1bSGreg Clayton dsym = self.getBuildArtifact(exe_name + ".dSYM") 4843db7cc1bSGreg Clayton # Make sure the executable file exists after building. 4851eeeab82SJordan Rupprecht self.assertTrue(os.path.exists(exe)) 4863db7cc1bSGreg Clayton # Make sure the dSYM file exists after building. 4871eeeab82SJordan Rupprecht self.assertTrue(os.path.isdir(dsym)) 4883db7cc1bSGreg Clayton 4893db7cc1bSGreg Clayton # Create the target 4903db7cc1bSGreg Clayton target = self.createTestTarget(file_path=exe) 4913db7cc1bSGreg Clayton 4923db7cc1bSGreg Clayton debug_stats = self.get_stats() 4933db7cc1bSGreg Clayton 4943db7cc1bSGreg Clayton exe_stats = self.find_module_in_metrics(exe, debug_stats) 4953db7cc1bSGreg Clayton # If we have a dSYM file, there should be a key/value pair in the module 4963db7cc1bSGreg Clayton # statistics and the path should match the dSYM file path in the build 4973db7cc1bSGreg Clayton # artifacts. 4982238dcc3SJonas Devlieghere self.assertIn("symbolFilePath", exe_stats) 4992238dcc3SJonas Devlieghere stats_dsym = exe_stats["symbolFilePath"] 5003db7cc1bSGreg Clayton 5013db7cc1bSGreg Clayton # Make sure main executable's module info has debug info size that is 5023db7cc1bSGreg Clayton # greater than zero as the dSYM file and main executable work together 5033db7cc1bSGreg Clayton # in the lldb.SBModule class to provide the data. 5042238dcc3SJonas Devlieghere self.assertGreater(exe_stats["debugInfoByteSize"], 0) 5053db7cc1bSGreg Clayton 5063db7cc1bSGreg Clayton # The "dsym" variable contains the bundle directory for the dSYM, while 5073db7cc1bSGreg Clayton # the "stats_dsym" will have the 5083db7cc1bSGreg Clayton self.assertIn(dsym, stats_dsym) 5093db7cc1bSGreg Clayton # Since we have a dSYM file, we should not be loading DWARF from the .o 5103db7cc1bSGreg Clayton # files and the .o file module identifiers should NOT be in the module 5113db7cc1bSGreg Clayton # statistics. 5122238dcc3SJonas Devlieghere self.assertNotIn("symbolFileModuleIdentifiers", exe_stats) 5133db7cc1bSGreg Clayton 5143db7cc1bSGreg Clayton @skipUnlessDarwin 5153db7cc1bSGreg Clayton @no_debug_info_test 5163db7cc1bSGreg Clayton def test_no_dsym_binary_has_symfile_identifiers_in_stats(self): 5173db7cc1bSGreg Clayton """ 5183db7cc1bSGreg Clayton Test that if our executable loads debug info from the .o files, 5193db7cc1bSGreg Clayton that the module statistics contains a 'symbolFileModuleIdentifiers' 5203db7cc1bSGreg Clayton key which is a list of module identifiers, and verify that the 5213db7cc1bSGreg Clayton module identifier can be used to find the .o file's module stats. 5223db7cc1bSGreg Clayton Also verify the the main executable's module statistics has a debug 5233db7cc1bSGreg Clayton info size that is zero, as the main executable itself has no debug 5243db7cc1bSGreg Clayton info, but verify that the .o files have debug info size that is 5253db7cc1bSGreg Clayton greater than zero. This test ensures that we don't double count 5263db7cc1bSGreg Clayton debug info. 5273db7cc1bSGreg Clayton """ 5283db7cc1bSGreg Clayton self.build(debug_info="dwarf") 5292238dcc3SJonas Devlieghere exe_name = "a.out" 5303db7cc1bSGreg Clayton exe = self.getBuildArtifact(exe_name) 5313db7cc1bSGreg Clayton dsym = self.getBuildArtifact(exe_name + ".dSYM") 5323db7cc1bSGreg Clayton # Make sure the executable file exists after building. 5331eeeab82SJordan Rupprecht self.assertTrue(os.path.exists(exe)) 5343db7cc1bSGreg Clayton # Make sure the dSYM file doesn't exist after building. 5351eeeab82SJordan Rupprecht self.assertFalse(os.path.isdir(dsym)) 5363db7cc1bSGreg Clayton 5373db7cc1bSGreg Clayton # Create the target 5383db7cc1bSGreg Clayton target = self.createTestTarget(file_path=exe) 5393db7cc1bSGreg Clayton 5403db7cc1bSGreg Clayton # Force the 'main.o' .o file's DWARF to be loaded so it will show up 5413db7cc1bSGreg Clayton # in the stats. 5423db7cc1bSGreg Clayton self.runCmd("b main.cpp:7") 5433db7cc1bSGreg Clayton 544*24feaab8Sjeffreytan81 debug_stats = self.get_stats("--all-targets") 5453db7cc1bSGreg Clayton 5463db7cc1bSGreg Clayton exe_stats = self.find_module_in_metrics(exe, debug_stats) 5473db7cc1bSGreg Clayton # If we don't have a dSYM file, there should not be a key/value pair in 5483db7cc1bSGreg Clayton # the module statistics. 5492238dcc3SJonas Devlieghere self.assertNotIn("symbolFilePath", exe_stats) 5503db7cc1bSGreg Clayton 5513db7cc1bSGreg Clayton # Make sure main executable's module info has debug info size that is 5523db7cc1bSGreg Clayton # zero as there is no debug info in the main executable, only in the 5533db7cc1bSGreg Clayton # .o files. The .o files will also only be loaded if something causes 5543db7cc1bSGreg Clayton # them to be loaded, so we set a breakpoint to force the .o file debug 5553db7cc1bSGreg Clayton # info to be loaded. 5562238dcc3SJonas Devlieghere self.assertEqual(exe_stats["debugInfoByteSize"], 0) 5573db7cc1bSGreg Clayton 5583db7cc1bSGreg Clayton # When we don't have a dSYM file, the SymbolFileDWARFDebugMap class 5593db7cc1bSGreg Clayton # should create modules for each .o file that contains DWARF that the 5603db7cc1bSGreg Clayton # symbol file creates, so we need to verify that we have a valid module 5613db7cc1bSGreg Clayton # identifier for main.o that is we should not be loading DWARF from the .o 5623db7cc1bSGreg Clayton # files and the .o file module identifiers should NOT be in the module 5633db7cc1bSGreg Clayton # statistics. 5642238dcc3SJonas Devlieghere self.assertIn("symbolFileModuleIdentifiers", exe_stats) 5653db7cc1bSGreg Clayton 5662238dcc3SJonas Devlieghere symfileIDs = exe_stats["symbolFileModuleIdentifiers"] 5673db7cc1bSGreg Clayton for symfileID in symfileIDs: 5683db7cc1bSGreg Clayton o_module = self.find_module_by_id_in_metrics(symfileID, debug_stats) 5693db7cc1bSGreg Clayton self.assertNotEqual(o_module, None) 5703db7cc1bSGreg Clayton # Make sure each .o file has some debug info bytes. 5712238dcc3SJonas Devlieghere self.assertGreater(o_module["debugInfoByteSize"], 0) 5728f893513SGreg Clayton 5738f893513SGreg Clayton @skipUnlessDarwin 5748f893513SGreg Clayton @no_debug_info_test 5758f893513SGreg Clayton def test_had_frame_variable_errors(self): 5768f893513SGreg Clayton """ 5778f893513SGreg Clayton Test that if we have frame variable errors that we see this in the 5788f893513SGreg Clayton statistics for the module that had issues. 5798f893513SGreg Clayton """ 5808f893513SGreg Clayton self.build(debug_info="dwarf") 5812238dcc3SJonas Devlieghere exe_name = "a.out" 5828f893513SGreg Clayton exe = self.getBuildArtifact(exe_name) 5838f893513SGreg Clayton dsym = self.getBuildArtifact(exe_name + ".dSYM") 5842238dcc3SJonas Devlieghere main_obj = self.getBuildArtifact("main.o") 5858f893513SGreg Clayton # Make sure the executable file exists after building. 5861eeeab82SJordan Rupprecht self.assertTrue(os.path.exists(exe)) 5878f893513SGreg Clayton # Make sure the dSYM file doesn't exist after building. 5881eeeab82SJordan Rupprecht self.assertFalse(os.path.isdir(dsym)) 5898f893513SGreg Clayton # Make sure the main.o object file exists after building. 5901eeeab82SJordan Rupprecht self.assertTrue(os.path.exists(main_obj)) 5918f893513SGreg Clayton 5928f893513SGreg Clayton # Delete the main.o file that contains the debug info so we force an 5938f893513SGreg Clayton # error when we run to main and try to get variables 5948f893513SGreg Clayton os.unlink(main_obj) 5958f893513SGreg Clayton 5962238dcc3SJonas Devlieghere (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main") 5978f893513SGreg Clayton 5988f893513SGreg Clayton # Get stats and verify we had errors. 599aac1c3b1SGreg Clayton stats = self.get_stats() 600aac1c3b1SGreg Clayton exe_stats = self.find_module_in_metrics(exe, stats) 6019c246882SJordan Rupprecht self.assertIsNotNone(exe_stats) 6028f893513SGreg Clayton 6038f893513SGreg Clayton # Make sure we have "debugInfoHadVariableErrors" variable that is set to 6048f893513SGreg Clayton # false before failing to get local variables due to missing .o file. 6051eeeab82SJordan Rupprecht self.assertFalse(exe_stats["debugInfoHadVariableErrors"]) 6068f893513SGreg Clayton 607aac1c3b1SGreg Clayton # Verify that the top level statistic that aggregates the number of 608aac1c3b1SGreg Clayton # modules with debugInfoHadVariableErrors is zero 6092238dcc3SJonas Devlieghere self.assertEqual(stats["totalModuleCountWithVariableErrors"], 0) 610aac1c3b1SGreg Clayton 6118f893513SGreg Clayton # Try and fail to get variables 6128f893513SGreg Clayton vars = thread.GetFrameAtIndex(0).GetVariables(True, True, False, True) 6138f893513SGreg Clayton 6148f893513SGreg Clayton # Make sure we got an error back that indicates that variables were not 6158f893513SGreg Clayton # available 6168f893513SGreg Clayton self.assertTrue(vars.GetError().Fail()) 6178f893513SGreg Clayton 6188f893513SGreg Clayton # Get stats and verify we had errors. 619aac1c3b1SGreg Clayton stats = self.get_stats() 620aac1c3b1SGreg Clayton exe_stats = self.find_module_in_metrics(exe, stats) 6219c246882SJordan Rupprecht self.assertIsNotNone(exe_stats) 6228f893513SGreg Clayton 6238f893513SGreg Clayton # Make sure we have "hadFrameVariableErrors" variable that is set to 6248f893513SGreg Clayton # true after failing to get local variables due to missing .o file. 6251eeeab82SJordan Rupprecht self.assertTrue(exe_stats["debugInfoHadVariableErrors"]) 626aac1c3b1SGreg Clayton 627aac1c3b1SGreg Clayton # Verify that the top level statistic that aggregates the number of 628aac1c3b1SGreg Clayton # modules with debugInfoHadVariableErrors is greater than zero 6292238dcc3SJonas Devlieghere self.assertGreater(stats["totalModuleCountWithVariableErrors"], 0) 630c2d061daSroyitaqi 631c2d061daSroyitaqi def test_transcript_happy_path(self): 632c2d061daSroyitaqi """ 633c2d061daSroyitaqi Test "statistics dump" and the transcript information. 634c2d061daSroyitaqi """ 635c2d061daSroyitaqi self.build() 636c2d061daSroyitaqi exe = self.getBuildArtifact("a.out") 637c2d061daSroyitaqi target = self.createTestTarget(file_path=exe) 638c2d061daSroyitaqi self.runCmd("settings set interpreter.save-transcript true") 639c2d061daSroyitaqi self.runCmd("version") 640c2d061daSroyitaqi 641c2d061daSroyitaqi # Verify the output of a first "statistics dump" 64270f41a8cSroyitaqi debug_stats = self.get_stats("--transcript true") 643c2d061daSroyitaqi self.assertIn("transcript", debug_stats) 644c2d061daSroyitaqi transcript = debug_stats["transcript"] 645c2d061daSroyitaqi self.assertEqual(len(transcript), 2) 646c2d061daSroyitaqi self.assertEqual(transcript[0]["commandName"], "version") 647c2d061daSroyitaqi self.assertEqual(transcript[1]["commandName"], "statistics dump") 648c2d061daSroyitaqi # The first "statistics dump" in the transcript should have no output 649c2d061daSroyitaqi self.assertNotIn("output", transcript[1]) 650c2d061daSroyitaqi 651c2d061daSroyitaqi # Verify the output of a second "statistics dump" 65270f41a8cSroyitaqi debug_stats = self.get_stats("--transcript true") 653c2d061daSroyitaqi self.assertIn("transcript", debug_stats) 654c2d061daSroyitaqi transcript = debug_stats["transcript"] 655c2d061daSroyitaqi self.assertEqual(len(transcript), 3) 656c2d061daSroyitaqi self.assertEqual(transcript[0]["commandName"], "version") 657c2d061daSroyitaqi self.assertEqual(transcript[1]["commandName"], "statistics dump") 658c2d061daSroyitaqi # The first "statistics dump" in the transcript should have output now 659c2d061daSroyitaqi self.assertIn("output", transcript[1]) 660c2d061daSroyitaqi self.assertEqual(transcript[2]["commandName"], "statistics dump") 661c2d061daSroyitaqi # The second "statistics dump" in the transcript should have no output 662c2d061daSroyitaqi self.assertNotIn("output", transcript[2]) 663c2d061daSroyitaqi 66470f41a8cSroyitaqi def verify_stats(self, stats, expectation, options): 66570f41a8cSroyitaqi for field_name in expectation: 66670f41a8cSroyitaqi idx = field_name.find(".") 66770f41a8cSroyitaqi if idx == -1: 66870f41a8cSroyitaqi # `field_name` is a top-level field 66970f41a8cSroyitaqi exists = field_name in stats 67070f41a8cSroyitaqi should_exist = expectation[field_name] 67170f41a8cSroyitaqi should_exist_string = "" if should_exist else "not " 67270f41a8cSroyitaqi self.assertEqual( 67370f41a8cSroyitaqi exists, 67470f41a8cSroyitaqi should_exist, 67570f41a8cSroyitaqi f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'", 67670f41a8cSroyitaqi ) 67770f41a8cSroyitaqi else: 67870f41a8cSroyitaqi # `field_name` is a string of "<top-level field>.<second-level field>" 67970f41a8cSroyitaqi top_level_field_name = field_name[0:idx] 68070f41a8cSroyitaqi second_level_field_name = field_name[idx + 1 :] 68170f41a8cSroyitaqi for top_level_field in ( 68270f41a8cSroyitaqi stats[top_level_field_name] if top_level_field_name in stats else {} 68370f41a8cSroyitaqi ): 68470f41a8cSroyitaqi exists = second_level_field_name in top_level_field 68570f41a8cSroyitaqi should_exist = expectation[field_name] 68670f41a8cSroyitaqi should_exist_string = "" if should_exist else "not " 68770f41a8cSroyitaqi self.assertEqual( 68870f41a8cSroyitaqi exists, 68970f41a8cSroyitaqi should_exist, 69070f41a8cSroyitaqi f"'{field_name}' should {should_exist_string}exist for 'statistics dump{options}'", 69170f41a8cSroyitaqi ) 69270f41a8cSroyitaqi 69370f41a8cSroyitaqi def get_test_cases_for_sections_existence(self): 69470f41a8cSroyitaqi should_always_exist_or_not = { 69570f41a8cSroyitaqi "totalDebugInfoEnabled": True, 69670f41a8cSroyitaqi "memory": True, 69770f41a8cSroyitaqi } 69870f41a8cSroyitaqi test_cases = [ 69970f41a8cSroyitaqi { # Everything mode 70070f41a8cSroyitaqi "command_options": "", 70170f41a8cSroyitaqi "api_options": {}, 70270f41a8cSroyitaqi "expect": { 70370f41a8cSroyitaqi "commands": True, 70470f41a8cSroyitaqi "targets": True, 70570f41a8cSroyitaqi "targets.moduleIdentifiers": True, 70670f41a8cSroyitaqi "targets.breakpoints": True, 70770f41a8cSroyitaqi "targets.expressionEvaluation": True, 708f65a52abSroyitaqi "targets.frameVariable": True, 709f65a52abSroyitaqi "targets.totalSharedLibraryEventHitCount": True, 71070f41a8cSroyitaqi "modules": True, 71170f41a8cSroyitaqi "transcript": True, 71270f41a8cSroyitaqi }, 71370f41a8cSroyitaqi }, 71470f41a8cSroyitaqi { # Summary mode 71570f41a8cSroyitaqi "command_options": " --summary", 71670f41a8cSroyitaqi "api_options": { 71770f41a8cSroyitaqi "SetSummaryOnly": True, 71870f41a8cSroyitaqi }, 71970f41a8cSroyitaqi "expect": { 72070f41a8cSroyitaqi "commands": False, 721f65a52abSroyitaqi "targets": True, 72270f41a8cSroyitaqi "targets.moduleIdentifiers": False, 72370f41a8cSroyitaqi "targets.breakpoints": False, 72470f41a8cSroyitaqi "targets.expressionEvaluation": False, 725f65a52abSroyitaqi "targets.frameVariable": False, 726f65a52abSroyitaqi "targets.totalSharedLibraryEventHitCount": True, 72770f41a8cSroyitaqi "modules": False, 72870f41a8cSroyitaqi "transcript": False, 72970f41a8cSroyitaqi }, 73070f41a8cSroyitaqi }, 73170f41a8cSroyitaqi { # Summary mode with targets 73270f41a8cSroyitaqi "command_options": " --summary --targets=true", 73370f41a8cSroyitaqi "api_options": { 73470f41a8cSroyitaqi "SetSummaryOnly": True, 73570f41a8cSroyitaqi "SetIncludeTargets": True, 73670f41a8cSroyitaqi }, 73770f41a8cSroyitaqi "expect": { 73870f41a8cSroyitaqi "commands": False, 73970f41a8cSroyitaqi "targets": True, 74070f41a8cSroyitaqi "targets.moduleIdentifiers": False, 74170f41a8cSroyitaqi "targets.breakpoints": False, 74270f41a8cSroyitaqi "targets.expressionEvaluation": False, 743f65a52abSroyitaqi "targets.frameVariable": False, 74470f41a8cSroyitaqi "targets.totalSharedLibraryEventHitCount": True, 74570f41a8cSroyitaqi "modules": False, 74670f41a8cSroyitaqi "transcript": False, 74770f41a8cSroyitaqi }, 74870f41a8cSroyitaqi }, 749f65a52abSroyitaqi { # Summary mode without targets 750f65a52abSroyitaqi "command_options": " --summary --targets=false", 751f65a52abSroyitaqi "api_options": { 752f65a52abSroyitaqi "SetSummaryOnly": True, 753f65a52abSroyitaqi "SetIncludeTargets": False, 754f65a52abSroyitaqi }, 755f65a52abSroyitaqi "expect": { 756f65a52abSroyitaqi "commands": False, 757f65a52abSroyitaqi "targets": False, 758f65a52abSroyitaqi "modules": False, 759f65a52abSroyitaqi "transcript": False, 760f65a52abSroyitaqi }, 761f65a52abSroyitaqi }, 76270f41a8cSroyitaqi { # Summary mode with modules 76370f41a8cSroyitaqi "command_options": " --summary --modules=true", 76470f41a8cSroyitaqi "api_options": { 76570f41a8cSroyitaqi "SetSummaryOnly": True, 76670f41a8cSroyitaqi "SetIncludeModules": True, 76770f41a8cSroyitaqi }, 76870f41a8cSroyitaqi "expect": { 76970f41a8cSroyitaqi "commands": False, 770f65a52abSroyitaqi "targets": True, 77170f41a8cSroyitaqi "targets.moduleIdentifiers": False, 77270f41a8cSroyitaqi "targets.breakpoints": False, 77370f41a8cSroyitaqi "targets.expressionEvaluation": False, 774f65a52abSroyitaqi "targets.frameVariable": False, 775f65a52abSroyitaqi "targets.totalSharedLibraryEventHitCount": True, 77670f41a8cSroyitaqi "modules": True, 77770f41a8cSroyitaqi "transcript": False, 77870f41a8cSroyitaqi }, 77970f41a8cSroyitaqi }, 780f65a52abSroyitaqi { # Default mode without modules and transcript 78170f41a8cSroyitaqi "command_options": " --modules=false --transcript=false", 78270f41a8cSroyitaqi "api_options": { 78370f41a8cSroyitaqi "SetIncludeModules": False, 78470f41a8cSroyitaqi "SetIncludeTranscript": False, 78570f41a8cSroyitaqi }, 78670f41a8cSroyitaqi "expect": { 78770f41a8cSroyitaqi "commands": True, 78870f41a8cSroyitaqi "targets": True, 78970f41a8cSroyitaqi "targets.moduleIdentifiers": False, 79070f41a8cSroyitaqi "targets.breakpoints": True, 79170f41a8cSroyitaqi "targets.expressionEvaluation": True, 792f65a52abSroyitaqi "targets.frameVariable": True, 793f65a52abSroyitaqi "targets.totalSharedLibraryEventHitCount": True, 79470f41a8cSroyitaqi "modules": False, 79570f41a8cSroyitaqi "transcript": False, 79670f41a8cSroyitaqi }, 79770f41a8cSroyitaqi }, 798f65a52abSroyitaqi { # Default mode without modules 79970f41a8cSroyitaqi "command_options": " --modules=false", 80070f41a8cSroyitaqi "api_options": { 80170f41a8cSroyitaqi "SetIncludeModules": False, 80270f41a8cSroyitaqi }, 80370f41a8cSroyitaqi "expect": { 80470f41a8cSroyitaqi "commands": True, 80570f41a8cSroyitaqi "targets": True, 80670f41a8cSroyitaqi "targets.moduleIdentifiers": False, 80770f41a8cSroyitaqi "targets.breakpoints": True, 80870f41a8cSroyitaqi "targets.expressionEvaluation": True, 809f65a52abSroyitaqi "targets.frameVariable": True, 810f65a52abSroyitaqi "targets.totalSharedLibraryEventHitCount": True, 81170f41a8cSroyitaqi "modules": False, 81270f41a8cSroyitaqi "transcript": True, 81370f41a8cSroyitaqi }, 81470f41a8cSroyitaqi }, 81570f41a8cSroyitaqi ] 81670f41a8cSroyitaqi return (should_always_exist_or_not, test_cases) 81770f41a8cSroyitaqi 81870f41a8cSroyitaqi def test_sections_existence_through_command(self): 819c2d061daSroyitaqi """ 82070f41a8cSroyitaqi Test "statistics dump" and the existence of sections when different 82170f41a8cSroyitaqi options are given through the command line (CLI or HandleCommand). 822c2d061daSroyitaqi """ 823c2d061daSroyitaqi self.build() 824c2d061daSroyitaqi exe = self.getBuildArtifact("a.out") 825c2d061daSroyitaqi target = self.createTestTarget(file_path=exe) 82670f41a8cSroyitaqi 82770f41a8cSroyitaqi # Create some transcript so that it can be tested. 828c2d061daSroyitaqi self.runCmd("settings set interpreter.save-transcript true") 829c2d061daSroyitaqi self.runCmd("version") 83070f41a8cSroyitaqi self.runCmd("b main") 83170f41a8cSroyitaqi # Then disable transcript so that it won't change during verification 83270f41a8cSroyitaqi self.runCmd("settings set interpreter.save-transcript false") 833c2d061daSroyitaqi 83470f41a8cSroyitaqi # Expectation 83570f41a8cSroyitaqi ( 83670f41a8cSroyitaqi should_always_exist_or_not, 83770f41a8cSroyitaqi test_cases, 83870f41a8cSroyitaqi ) = self.get_test_cases_for_sections_existence() 83970f41a8cSroyitaqi 84070f41a8cSroyitaqi # Verification 84170f41a8cSroyitaqi for test_case in test_cases: 84270f41a8cSroyitaqi options = test_case["command_options"] 84370f41a8cSroyitaqi # Get statistics dump result 84470f41a8cSroyitaqi stats = self.get_stats(options) 84570f41a8cSroyitaqi # Verify that each field should exist (or not) 84670f41a8cSroyitaqi expectation = {**should_always_exist_or_not, **test_case["expect"]} 84770f41a8cSroyitaqi self.verify_stats(stats, expectation, options) 84870f41a8cSroyitaqi 84970f41a8cSroyitaqi def test_sections_existence_through_api(self): 85070f41a8cSroyitaqi """ 85170f41a8cSroyitaqi Test "statistics dump" and the existence of sections when different 85270f41a8cSroyitaqi options are given through the public API. 85370f41a8cSroyitaqi """ 85470f41a8cSroyitaqi self.build() 85570f41a8cSroyitaqi exe = self.getBuildArtifact("a.out") 85670f41a8cSroyitaqi target = self.createTestTarget(file_path=exe) 85770f41a8cSroyitaqi 85870f41a8cSroyitaqi # Create some transcript so that it can be tested. 85970f41a8cSroyitaqi self.runCmd("settings set interpreter.save-transcript true") 86070f41a8cSroyitaqi self.runCmd("version") 86170f41a8cSroyitaqi self.runCmd("b main") 86270f41a8cSroyitaqi # But disable transcript so that it won't change during verification 86370f41a8cSroyitaqi self.runCmd("settings set interpreter.save-transcript false") 86470f41a8cSroyitaqi 86570f41a8cSroyitaqi # Expectation 86670f41a8cSroyitaqi ( 86770f41a8cSroyitaqi should_always_exist_or_not, 86870f41a8cSroyitaqi test_cases, 86970f41a8cSroyitaqi ) = self.get_test_cases_for_sections_existence() 87070f41a8cSroyitaqi 87170f41a8cSroyitaqi # Verification 87270f41a8cSroyitaqi for test_case in test_cases: 87370f41a8cSroyitaqi # Create options 87470f41a8cSroyitaqi options = test_case["api_options"] 87570f41a8cSroyitaqi sb_options = lldb.SBStatisticsOptions() 87670f41a8cSroyitaqi for method_name, param_value in options.items(): 87770f41a8cSroyitaqi getattr(sb_options, method_name)(param_value) 87870f41a8cSroyitaqi # Get statistics dump result 87970f41a8cSroyitaqi stream = lldb.SBStream() 88070f41a8cSroyitaqi target.GetStatistics(sb_options).GetAsJSON(stream) 88170f41a8cSroyitaqi stats = json.loads(stream.GetData()) 88270f41a8cSroyitaqi # Verify that each field should exist (or not) 88370f41a8cSroyitaqi expectation = {**should_always_exist_or_not, **test_case["expect"]} 88470f41a8cSroyitaqi self.verify_stats(stats, expectation, options) 88570f41a8cSroyitaqi 88670f41a8cSroyitaqi def test_order_of_options_do_not_matter(self): 88770f41a8cSroyitaqi """ 88870f41a8cSroyitaqi Test "statistics dump" and the order of options. 88970f41a8cSroyitaqi """ 89070f41a8cSroyitaqi self.build() 89170f41a8cSroyitaqi exe = self.getBuildArtifact("a.out") 89270f41a8cSroyitaqi target = self.createTestTarget(file_path=exe) 89370f41a8cSroyitaqi 89470f41a8cSroyitaqi # Create some transcript so that it can be tested. 89570f41a8cSroyitaqi self.runCmd("settings set interpreter.save-transcript true") 89670f41a8cSroyitaqi self.runCmd("version") 89770f41a8cSroyitaqi self.runCmd("b main") 89870f41a8cSroyitaqi # Then disable transcript so that it won't change during verification 89970f41a8cSroyitaqi self.runCmd("settings set interpreter.save-transcript false") 90070f41a8cSroyitaqi 90170f41a8cSroyitaqi # The order of the following options shouldn't matter 90270f41a8cSroyitaqi test_cases = [ 90370f41a8cSroyitaqi (" --summary", " --targets=true"), 90470f41a8cSroyitaqi (" --summary", " --targets=false"), 90570f41a8cSroyitaqi (" --summary", " --modules=true"), 90670f41a8cSroyitaqi (" --summary", " --modules=false"), 90770f41a8cSroyitaqi (" --summary", " --transcript=true"), 90870f41a8cSroyitaqi (" --summary", " --transcript=false"), 90970f41a8cSroyitaqi ] 91070f41a8cSroyitaqi 91170f41a8cSroyitaqi # Verification 91270f41a8cSroyitaqi for options in test_cases: 91370f41a8cSroyitaqi debug_stats_0 = self.get_stats(options[0] + options[1]) 91470f41a8cSroyitaqi debug_stats_1 = self.get_stats(options[1] + options[0]) 91570f41a8cSroyitaqi # Redact all numbers 91670f41a8cSroyitaqi debug_stats_0 = re.sub(r"\d+", "0", json.dumps(debug_stats_0)) 91770f41a8cSroyitaqi debug_stats_1 = re.sub(r"\d+", "0", json.dumps(debug_stats_1)) 91870f41a8cSroyitaqi # Verify that the two output are the same 91970f41a8cSroyitaqi self.assertEqual( 92070f41a8cSroyitaqi debug_stats_0, 92170f41a8cSroyitaqi debug_stats_1, 92270f41a8cSroyitaqi f"The order of options '{options[0]}' and '{options[1]}' should not matter", 92370f41a8cSroyitaqi ) 92422144e20SJacob Lalonde 92510c04d98SJacob Lalonde @skipIfWindows 92622144e20SJacob Lalonde def test_summary_statistics_providers(self): 92722144e20SJacob Lalonde """ 92822144e20SJacob Lalonde Test summary timing statistics is included in statistics dump when 92922144e20SJacob Lalonde a type with a summary provider exists, and is evaluated. 93022144e20SJacob Lalonde """ 93122144e20SJacob Lalonde 93222144e20SJacob Lalonde self.build() 93322144e20SJacob Lalonde target = self.createTestTarget() 93422144e20SJacob Lalonde lldbutil.run_to_source_breakpoint( 93522144e20SJacob Lalonde self, "// stop here", lldb.SBFileSpec("main.cpp") 93622144e20SJacob Lalonde ) 93722144e20SJacob Lalonde self.expect("frame var", substrs=["hello world"]) 93822144e20SJacob Lalonde stats = self.get_target_stats(self.get_stats()) 93922144e20SJacob Lalonde self.assertIn("summaryProviderStatistics", stats) 94022144e20SJacob Lalonde summary_providers = stats["summaryProviderStatistics"] 94122144e20SJacob Lalonde # We don't want to take a dependency on the type name, so we just look 94222144e20SJacob Lalonde # for string and that it was called once. 94322144e20SJacob Lalonde summary_provider_str = str(summary_providers) 94422144e20SJacob Lalonde self.assertIn("string", summary_provider_str) 94522144e20SJacob Lalonde self.assertIn("'count': 1", summary_provider_str) 94622144e20SJacob Lalonde self.assertIn("'totalTime':", summary_provider_str) 94722144e20SJacob Lalonde # We may hit the std::string C++ provider, or a summary provider string 94822144e20SJacob Lalonde self.assertIn("'type':", summary_provider_str) 94922144e20SJacob Lalonde self.assertTrue( 95022144e20SJacob Lalonde "c++" in summary_provider_str or "string" in summary_provider_str 95122144e20SJacob Lalonde ) 95222144e20SJacob Lalonde 95322144e20SJacob Lalonde self.runCmd("continue") 95422144e20SJacob Lalonde self.runCmd("command script import BoxFormatter.py") 95522144e20SJacob Lalonde self.expect("frame var", substrs=["box = [27]"]) 95622144e20SJacob Lalonde stats = self.get_target_stats(self.get_stats()) 95722144e20SJacob Lalonde self.assertIn("summaryProviderStatistics", stats) 95822144e20SJacob Lalonde summary_providers = stats["summaryProviderStatistics"] 95922144e20SJacob Lalonde summary_provider_str = str(summary_providers) 96022144e20SJacob Lalonde self.assertIn("BoxFormatter.summary", summary_provider_str) 96122144e20SJacob Lalonde self.assertIn("'count': 1", summary_provider_str) 96222144e20SJacob Lalonde self.assertIn("'totalTime':", summary_provider_str) 96322144e20SJacob Lalonde self.assertIn("'type': 'python'", summary_provider_str) 96422144e20SJacob Lalonde 96510c04d98SJacob Lalonde @skipIfWindows 96622144e20SJacob Lalonde def test_summary_statistics_providers_vec(self): 96722144e20SJacob Lalonde """ 96822144e20SJacob Lalonde Test summary timing statistics is included in statistics dump when 96922144e20SJacob Lalonde a type with a summary provider exists, and is evaluated. This variation 97022144e20SJacob Lalonde tests that vector recurses into it's child type. 97122144e20SJacob Lalonde """ 97222144e20SJacob Lalonde self.build() 97322144e20SJacob Lalonde target = self.createTestTarget() 97422144e20SJacob Lalonde lldbutil.run_to_source_breakpoint( 97522144e20SJacob Lalonde self, "// stop vector", lldb.SBFileSpec("main.cpp") 97622144e20SJacob Lalonde ) 97722144e20SJacob Lalonde self.expect( 97822144e20SJacob Lalonde "frame var", substrs=["int_vec", "double_vec", "[0] = 1", "[7] = 8"] 97922144e20SJacob Lalonde ) 98022144e20SJacob Lalonde stats = self.get_target_stats(self.get_stats()) 98122144e20SJacob Lalonde self.assertIn("summaryProviderStatistics", stats) 98222144e20SJacob Lalonde summary_providers = stats["summaryProviderStatistics"] 98322144e20SJacob Lalonde summary_provider_str = str(summary_providers) 98422144e20SJacob Lalonde self.assertIn("'count': 2", summary_provider_str) 98522144e20SJacob Lalonde self.assertIn("'totalTime':", summary_provider_str) 98622144e20SJacob Lalonde self.assertIn("'type':", summary_provider_str) 98722144e20SJacob Lalonde # We may hit the std::vector C++ provider, or a summary provider string 98822144e20SJacob Lalonde if "c++" in summary_provider_str: 98922144e20SJacob Lalonde self.assertIn("std::vector", summary_provider_str) 990*24feaab8Sjeffreytan81 991*24feaab8Sjeffreytan81 @skipIfWindows 992*24feaab8Sjeffreytan81 def test_multiple_targets(self): 993*24feaab8Sjeffreytan81 """ 994*24feaab8Sjeffreytan81 Test statistics dump only reports the stats from current target and 995*24feaab8Sjeffreytan81 "statistics dump --all-targets" includes all target stats. 996*24feaab8Sjeffreytan81 """ 997*24feaab8Sjeffreytan81 da = {"CXX_SOURCES": "main.cpp", "EXE": self.getBuildArtifact("a.out")} 998*24feaab8Sjeffreytan81 self.build(dictionary=da) 999*24feaab8Sjeffreytan81 self.addTearDownCleanup(dictionary=da) 1000*24feaab8Sjeffreytan81 1001*24feaab8Sjeffreytan81 db = {"CXX_SOURCES": "second.cpp", "EXE": self.getBuildArtifact("second.out")} 1002*24feaab8Sjeffreytan81 self.build(dictionary=db) 1003*24feaab8Sjeffreytan81 self.addTearDownCleanup(dictionary=db) 1004*24feaab8Sjeffreytan81 1005*24feaab8Sjeffreytan81 main_exe = self.getBuildArtifact("a.out") 1006*24feaab8Sjeffreytan81 second_exe = self.getBuildArtifact("second.out") 1007*24feaab8Sjeffreytan81 1008*24feaab8Sjeffreytan81 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 1009*24feaab8Sjeffreytan81 self, "// break here", lldb.SBFileSpec("main.cpp"), None, "a.out" 1010*24feaab8Sjeffreytan81 ) 1011*24feaab8Sjeffreytan81 debugger_stats1 = self.get_stats() 1012*24feaab8Sjeffreytan81 self.assertIsNotNone(self.find_module_in_metrics(main_exe, debugger_stats1)) 1013*24feaab8Sjeffreytan81 self.assertIsNone(self.find_module_in_metrics(second_exe, debugger_stats1)) 1014*24feaab8Sjeffreytan81 1015*24feaab8Sjeffreytan81 (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 1016*24feaab8Sjeffreytan81 self, "// break here", lldb.SBFileSpec("second.cpp"), None, "second.out" 1017*24feaab8Sjeffreytan81 ) 1018*24feaab8Sjeffreytan81 debugger_stats2 = self.get_stats() 1019*24feaab8Sjeffreytan81 self.assertIsNone(self.find_module_in_metrics(main_exe, debugger_stats2)) 1020*24feaab8Sjeffreytan81 self.assertIsNotNone(self.find_module_in_metrics(second_exe, debugger_stats2)) 1021*24feaab8Sjeffreytan81 1022*24feaab8Sjeffreytan81 all_targets_stats = self.get_stats("--all-targets") 1023*24feaab8Sjeffreytan81 self.assertIsNotNone(self.find_module_in_metrics(main_exe, all_targets_stats)) 1024*24feaab8Sjeffreytan81 self.assertIsNotNone(self.find_module_in_metrics(second_exe, all_targets_stats)) 1025