1d52ba488SWalter Erquinigofrom collections import defaultdict 2d52ba488SWalter Erquinigoimport lldb 3d52ba488SWalter Erquinigoimport json 4d52ba488SWalter Erquinigofrom intelpt_testcase import * 5d52ba488SWalter Erquinigofrom lldbsuite.test.lldbtest import * 6d52ba488SWalter Erquinigofrom lldbsuite.test import lldbutil 7d52ba488SWalter Erquinigofrom lldbsuite.test.decorators import * 8d52ba488SWalter Erquinigoimport os 9d52ba488SWalter Erquinigo 10d52ba488SWalter Erquinigo 112238dcc3SJonas Devlieghereclass TestTraceExport(TraceIntelPTTestCaseBase): 12d52ba488SWalter Erquinigo def testErrorMessages(self): 13d52ba488SWalter Erquinigo ctf_test_file = self.getBuildArtifact("ctf-test.json") 14d52ba488SWalter Erquinigo # We first check the output when there are no targets 152238dcc3SJonas Devlieghere self.expect( 162238dcc3SJonas Devlieghere f"thread trace export ctf --file {ctf_test_file}", 172238dcc3SJonas Devlieghere substrs=[ 182238dcc3SJonas Devlieghere "error: invalid target, create a target using the 'target create' command" 192238dcc3SJonas Devlieghere ], 202238dcc3SJonas Devlieghere error=True, 212238dcc3SJonas Devlieghere ) 22d52ba488SWalter Erquinigo 23d52ba488SWalter Erquinigo # We now check the output when there's a non-running target 242238dcc3SJonas Devlieghere self.expect( 252238dcc3SJonas Devlieghere "target create " 262238dcc3SJonas Devlieghere + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 272238dcc3SJonas Devlieghere ) 28d52ba488SWalter Erquinigo 292238dcc3SJonas Devlieghere self.expect( 302238dcc3SJonas Devlieghere f"thread trace export ctf --file {ctf_test_file}", 31b7d525adSWalter Erquinigo substrs=["error: Command requires a current process."], 322238dcc3SJonas Devlieghere error=True, 332238dcc3SJonas Devlieghere ) 34d52ba488SWalter Erquinigo 35d52ba488SWalter Erquinigo # Now we check the output when there's a running target without a trace 36d52ba488SWalter Erquinigo self.expect("b main") 37d52ba488SWalter Erquinigo self.expect("run") 38d52ba488SWalter Erquinigo 392238dcc3SJonas Devlieghere self.expect( 402238dcc3SJonas Devlieghere f"thread trace export ctf --file {ctf_test_file}", 41d52ba488SWalter Erquinigo substrs=["error: Process is not being traced"], 422238dcc3SJonas Devlieghere error=True, 432238dcc3SJonas Devlieghere ) 44ef28c783SWalter Erquinigo 45a7d6c3efSWalter Erquinigo def _testHtrBasicSuperBlockPassFullCheck(self): 462238dcc3SJonas Devlieghere """ 47ef28c783SWalter Erquinigo Test the BasicSuperBlock pass of HTR. 48ef28c783SWalter Erquinigo 49ef28c783SWalter Erquinigo This test uses a very small trace so that the expected output is digestible and 50ef28c783SWalter Erquinigo it's possible to manually verify the behavior of the algorithm. 51ef28c783SWalter Erquinigo 52ef28c783SWalter Erquinigo This test exhaustively checks that each entry 53ef28c783SWalter Erquinigo in the output JSON is equal to the expected value. 54ef28c783SWalter Erquinigo 552238dcc3SJonas Devlieghere """ 56ef28c783SWalter Erquinigo 572238dcc3SJonas Devlieghere self.expect( 582238dcc3SJonas Devlieghere "trace load -v " 592238dcc3SJonas Devlieghere + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"), 602238dcc3SJonas Devlieghere substrs=["intel-pt"], 612238dcc3SJonas Devlieghere ) 62d52ba488SWalter Erquinigo 63d52ba488SWalter Erquinigo ctf_test_file = self.getBuildArtifact("ctf-test.json") 64d52ba488SWalter Erquinigo 65d52ba488SWalter Erquinigo self.expect(f"thread trace export ctf --file {ctf_test_file}") 66d52ba488SWalter Erquinigo self.assertTrue(os.path.exists(ctf_test_file)) 67d52ba488SWalter Erquinigo 68ef28c783SWalter Erquinigo with open(ctf_test_file) as f: 69ef28c783SWalter Erquinigo data = json.load(f) 70d52ba488SWalter Erquinigo 712238dcc3SJonas Devlieghere """ 72ef28c783SWalter Erquinigo The expected JSON contained by "ctf-test.json" 73ef28c783SWalter Erquinigo 74ef28c783SWalter Erquinigo dur: number of instructions in the block 75ef28c783SWalter Erquinigo 76ef28c783SWalter Erquinigo name: load address of the first instruction of the block and the 77ef28c783SWalter Erquinigo name of the most frequently called function from the block (if applicable) 78ef28c783SWalter Erquinigo 79ef28c783SWalter Erquinigo ph: 'X' for Complete events (see link to documentation below) 80ef28c783SWalter Erquinigo 81ef28c783SWalter Erquinigo pid: the ID of the HTR layer the blocks belong to 82ef28c783SWalter Erquinigo 83ef28c783SWalter Erquinigo ts: offset from the beginning of the trace for the first instruction in the block 84ef28c783SWalter Erquinigo 85ef28c783SWalter Erquinigo See https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.j75x71ritcoy 86ef28c783SWalter Erquinigo for documentation on the Trace Event Format 872238dcc3SJonas Devlieghere """ 88ef28c783SWalter Erquinigo # Comments on the right indicate if a block is a "head" and/or "tail" 89ef28c783SWalter Erquinigo # See BasicSuperBlockMerge in TraceHTR.h for a description of the algorithm 90ef28c783SWalter Erquinigo expected = [ 91ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400511", "ph": "X", "pid": 0, "ts": 0}, 92ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400518", "ph": "X", "pid": 0, "ts": 1}, 93ef28c783SWalter Erquinigo {"dur": 1, "name": "0x40051f", "ph": "X", "pid": 0, "ts": 2}, 94ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 3}, # head 95ef28c783SWalter Erquinigo {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 4}, # tail 96ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400521", "ph": "X", "pid": 0, "ts": 5}, 97ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400525", "ph": "X", "pid": 0, "ts": 6}, 98ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 7}, # head 99ef28c783SWalter Erquinigo {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 8}, # tail 100ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400521", "ph": "X", "pid": 0, "ts": 9}, 101ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400525", "ph": "X", "pid": 0, "ts": 10}, 102ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 11}, # head 103ef28c783SWalter Erquinigo {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 12}, # tail 104ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400521", "ph": "X", "pid": 0, "ts": 13}, 105ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400525", "ph": "X", "pid": 0, "ts": 14}, 106ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 15}, # head 107ef28c783SWalter Erquinigo {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 16}, # tail 108ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400521", "ph": "X", "pid": 0, "ts": 17}, 109ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400525", "ph": "X", "pid": 0, "ts": 18}, 110ef28c783SWalter Erquinigo {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 19}, # head 111ef28c783SWalter Erquinigo {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 20}, # tail 1122238dcc3SJonas Devlieghere { 1132238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 3}}, 1142238dcc3SJonas Devlieghere "dur": 3, 1152238dcc3SJonas Devlieghere "name": "0x400511", 1162238dcc3SJonas Devlieghere "ph": "X", 1172238dcc3SJonas Devlieghere "pid": 1, 1182238dcc3SJonas Devlieghere "ts": 0, 1192238dcc3SJonas Devlieghere }, 1202238dcc3SJonas Devlieghere { 1212238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1222238dcc3SJonas Devlieghere "dur": 2, 1232238dcc3SJonas Devlieghere "name": "0x400529", 1242238dcc3SJonas Devlieghere "ph": "X", 1252238dcc3SJonas Devlieghere "pid": 1, 1262238dcc3SJonas Devlieghere "ts": 3, 1272238dcc3SJonas Devlieghere }, # head, tail 1282238dcc3SJonas Devlieghere { 1292238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1302238dcc3SJonas Devlieghere "dur": 2, 1312238dcc3SJonas Devlieghere "name": "0x400521", 1322238dcc3SJonas Devlieghere "ph": "X", 1332238dcc3SJonas Devlieghere "pid": 1, 1342238dcc3SJonas Devlieghere "ts": 5, 1352238dcc3SJonas Devlieghere }, 1362238dcc3SJonas Devlieghere { 1372238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1382238dcc3SJonas Devlieghere "dur": 2, 1392238dcc3SJonas Devlieghere "name": "0x400529", 1402238dcc3SJonas Devlieghere "ph": "X", 1412238dcc3SJonas Devlieghere "pid": 1, 1422238dcc3SJonas Devlieghere "ts": 7, 1432238dcc3SJonas Devlieghere }, # head, tail 1442238dcc3SJonas Devlieghere { 1452238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1462238dcc3SJonas Devlieghere "dur": 2, 1472238dcc3SJonas Devlieghere "name": "0x400521", 1482238dcc3SJonas Devlieghere "ph": "X", 1492238dcc3SJonas Devlieghere "pid": 1, 1502238dcc3SJonas Devlieghere "ts": 9, 1512238dcc3SJonas Devlieghere }, 1522238dcc3SJonas Devlieghere { 1532238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1542238dcc3SJonas Devlieghere "dur": 2, 1552238dcc3SJonas Devlieghere "name": "0x400529", 1562238dcc3SJonas Devlieghere "ph": "X", 1572238dcc3SJonas Devlieghere "pid": 1, 1582238dcc3SJonas Devlieghere "ts": 11, 1592238dcc3SJonas Devlieghere }, # head, tail 1602238dcc3SJonas Devlieghere { 1612238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1622238dcc3SJonas Devlieghere "dur": 2, 1632238dcc3SJonas Devlieghere "name": "0x400521", 1642238dcc3SJonas Devlieghere "ph": "X", 1652238dcc3SJonas Devlieghere "pid": 1, 1662238dcc3SJonas Devlieghere "ts": 13, 1672238dcc3SJonas Devlieghere }, 1682238dcc3SJonas Devlieghere { 1692238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1702238dcc3SJonas Devlieghere "dur": 2, 1712238dcc3SJonas Devlieghere "name": "0x400529", 1722238dcc3SJonas Devlieghere "ph": "X", 1732238dcc3SJonas Devlieghere "pid": 1, 1742238dcc3SJonas Devlieghere "ts": 15, 1752238dcc3SJonas Devlieghere }, # head, tail 1762238dcc3SJonas Devlieghere { 1772238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1782238dcc3SJonas Devlieghere "dur": 2, 1792238dcc3SJonas Devlieghere "name": "0x400521", 1802238dcc3SJonas Devlieghere "ph": "X", 1812238dcc3SJonas Devlieghere "pid": 1, 1822238dcc3SJonas Devlieghere "ts": 17, 1832238dcc3SJonas Devlieghere }, 1842238dcc3SJonas Devlieghere { 1852238dcc3SJonas Devlieghere "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}}, 1862238dcc3SJonas Devlieghere "dur": 2, 1872238dcc3SJonas Devlieghere "name": "0x400529", 1882238dcc3SJonas Devlieghere "ph": "X", 1892238dcc3SJonas Devlieghere "pid": 1, 1902238dcc3SJonas Devlieghere "ts": 19, 1912238dcc3SJonas Devlieghere }, # head, tail 192ef28c783SWalter Erquinigo ] 193ef28c783SWalter Erquinigo 194ef28c783SWalter Erquinigo # Check that the length of the expected JSON array is equal to the actual 1951fb5c7a2SDave Lee self.assertEqual(len(data), len(expected)) 196ef28c783SWalter Erquinigo for i in range(len(data)): 197ef28c783SWalter Erquinigo # Check each individual JSON object in "ctf-test.json" against the expected value above 1981fb5c7a2SDave Lee self.assertEqual(data[i], expected[i]) 199ef28c783SWalter Erquinigo 200a7d6c3efSWalter Erquinigo def _testHtrBasicSuperBlockPassSequenceCheck(self): 2012238dcc3SJonas Devlieghere """ 202ef28c783SWalter Erquinigo Test the BasicSuperBlock pass of HTR. 203ef28c783SWalter Erquinigo 204ef28c783SWalter Erquinigo This test exports a modest sized trace and only checks that a particular sequence of blocks are 205ef28c783SWalter Erquinigo expected, see `testHtrBasicSuperBlockPassFullCheck` for a more "exhaustive" test. 206d52ba488SWalter Erquinigo 207d52ba488SWalter Erquinigo TODO: Once the "trace save" command is implemented, gather Intel PT 208d52ba488SWalter Erquinigo trace of this program and load it like the other tests instead of 209d52ba488SWalter Erquinigo manually executing the commands to trace the program. 2102238dcc3SJonas Devlieghere """ 2112238dcc3SJonas Devlieghere self.expect( 2122238dcc3SJonas Devlieghere f"target create {os.path.join(self.getSourceDir(), 'intelpt-trace', 'export_ctf_test_program.out')}" 2132238dcc3SJonas Devlieghere ) 214d52ba488SWalter Erquinigo self.expect("b main") 215d52ba488SWalter Erquinigo self.expect("r") 216d52ba488SWalter Erquinigo self.expect("b exit") 217d52ba488SWalter Erquinigo self.expect("thread trace start") 218d52ba488SWalter Erquinigo self.expect("c") 219d52ba488SWalter Erquinigo 220d52ba488SWalter Erquinigo ctf_test_file = self.getBuildArtifact("ctf-test.json") 221d52ba488SWalter Erquinigo 222d52ba488SWalter Erquinigo self.expect(f"thread trace export ctf --file {ctf_test_file}") 223d52ba488SWalter Erquinigo self.assertTrue(os.path.exists(ctf_test_file)) 224d52ba488SWalter Erquinigo 225d52ba488SWalter Erquinigo with open(ctf_test_file) as f: 226d52ba488SWalter Erquinigo data = json.load(f) 227d52ba488SWalter Erquinigo 228d52ba488SWalter Erquinigo num_units_by_layer = defaultdict(int) 229d52ba488SWalter Erquinigo index_of_first_layer_1_block = None 230d52ba488SWalter Erquinigo for i, event in enumerate(data): 2312238dcc3SJonas Devlieghere layer_id = event.get("pid") 232*9c246882SJordan Rupprecht self.assertIsNotNone(layer_id) 233d52ba488SWalter Erquinigo if layer_id == 1 and index_of_first_layer_1_block is None: 234d52ba488SWalter Erquinigo index_of_first_layer_1_block = i 235d52ba488SWalter Erquinigo num_units_by_layer[layer_id] += 1 236d52ba488SWalter Erquinigo 237ef28c783SWalter Erquinigo # Check that there are only two layers and that the layer IDs are correct 238ef28c783SWalter Erquinigo # Check that layer IDs are correct 2392238dcc3SJonas Devlieghere self.assertTrue( 2402238dcc3SJonas Devlieghere len(num_units_by_layer) == 2 2412238dcc3SJonas Devlieghere and 0 in num_units_by_layer 2422238dcc3SJonas Devlieghere and 1 in num_units_by_layer 2432238dcc3SJonas Devlieghere ) 244d52ba488SWalter Erquinigo 245ef28c783SWalter Erquinigo # The expected block names for the first 7 blocks of layer 1 246d52ba488SWalter Erquinigo expected_block_names = [ 2472238dcc3SJonas Devlieghere "0x4005f0", 2482238dcc3SJonas Devlieghere "0x4005fe", 2492238dcc3SJonas Devlieghere "0x400606: iterative_handle_request_by_id(int, int)", 2502238dcc3SJonas Devlieghere "0x4005a7", 2512238dcc3SJonas Devlieghere "0x4005af", 2522238dcc3SJonas Devlieghere "0x4005b9: fast_handle_request(int)", 2532238dcc3SJonas Devlieghere "0x4005d5: log_response(int)", 254d52ba488SWalter Erquinigo ] 255ef28c783SWalter Erquinigo 256d52ba488SWalter Erquinigo data_index = index_of_first_layer_1_block 257ef28c783SWalter Erquinigo for i in range(len(expected_block_names)): 2582238dcc3SJonas Devlieghere self.assertEqual(data[data_index + i]["name"], expected_block_names[i]) 259