xref: /llvm-project/lldb/test/API/commands/trace/TestTraceExport.py (revision 9c2468821ec51defd09c246fea4a47886fff8c01)
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