brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.8 KiB · a6ca736 Raw
259 lines · python
1from collections import defaultdict2import lldb3import json4from intelpt_testcase import *5from lldbsuite.test.lldbtest import *6from lldbsuite.test import lldbutil7from lldbsuite.test.decorators import *8import os9 10 11class TestTraceExport(TraceIntelPTTestCaseBase):12    def testErrorMessages(self):13        ctf_test_file = self.getBuildArtifact("ctf-test.json")14        # We first check the output when there are no targets15        self.expect(16            f"thread trace export ctf --file {ctf_test_file}",17            substrs=[18                "error: invalid target, create a target using the 'target create' command"19            ],20            error=True,21        )22 23        # We now check the output when there's a non-running target24        self.expect(25            "target create "26            + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")27        )28 29        self.expect(30            f"thread trace export ctf --file {ctf_test_file}",31            substrs=["error: Command requires a current process."],32            error=True,33        )34 35        # Now we check the output when there's a running target without a trace36        self.expect("b main")37        self.expect("run")38 39        self.expect(40            f"thread trace export ctf --file {ctf_test_file}",41            substrs=["error: Process is not being traced"],42            error=True,43        )44 45    def _testHtrBasicSuperBlockPassFullCheck(self):46        """47        Test the BasicSuperBlock pass of HTR.48 49        This test uses a very small trace so that the expected output is digestible and50        it's possible to manually verify the behavior of the algorithm.51 52        This test exhaustively checks that each entry53        in the output JSON is equal to the expected value.54 55        """56 57        self.expect(58            "trace load -v "59            + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"),60            substrs=["intel-pt"],61        )62 63        ctf_test_file = self.getBuildArtifact("ctf-test.json")64 65        self.expect(f"thread trace export ctf --file {ctf_test_file}")66        self.assertTrue(os.path.exists(ctf_test_file))67 68        with open(ctf_test_file) as f:69            data = json.load(f)70 71        """72        The expected JSON contained by "ctf-test.json"73 74        dur: number of instructions in the block75 76        name: load address of the first instruction of the block and the77        name of the most frequently called function from the block (if applicable)78 79        ph: 'X' for Complete events (see link to documentation below)80 81        pid: the ID of the HTR layer the blocks belong to82 83        ts: offset from the beginning of the trace for the first instruction in the block84 85        See https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.j75x71ritcoy86        for documentation on the Trace Event Format87        """88        # Comments on the right indicate if a block is a "head" and/or "tail"89        # See BasicSuperBlockMerge in TraceHTR.h for a description of the algorithm90        expected = [91            {"dur": 1, "name": "0x400511", "ph": "X", "pid": 0, "ts": 0},92            {"dur": 1, "name": "0x400518", "ph": "X", "pid": 0, "ts": 1},93            {"dur": 1, "name": "0x40051f", "ph": "X", "pid": 0, "ts": 2},94            {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 3},  # head95            {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 4},  # tail96            {"dur": 1, "name": "0x400521", "ph": "X", "pid": 0, "ts": 5},97            {"dur": 1, "name": "0x400525", "ph": "X", "pid": 0, "ts": 6},98            {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 7},  # head99            {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 8},  # tail100            {"dur": 1, "name": "0x400521", "ph": "X", "pid": 0, "ts": 9},101            {"dur": 1, "name": "0x400525", "ph": "X", "pid": 0, "ts": 10},102            {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 11},  # head103            {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 12},  # tail104            {"dur": 1, "name": "0x400521", "ph": "X", "pid": 0, "ts": 13},105            {"dur": 1, "name": "0x400525", "ph": "X", "pid": 0, "ts": 14},106            {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 15},  # head107            {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 16},  # tail108            {"dur": 1, "name": "0x400521", "ph": "X", "pid": 0, "ts": 17},109            {"dur": 1, "name": "0x400525", "ph": "X", "pid": 0, "ts": 18},110            {"dur": 1, "name": "0x400529", "ph": "X", "pid": 0, "ts": 19},  # head111            {"dur": 1, "name": "0x40052d", "ph": "X", "pid": 0, "ts": 20},  # tail112            {113                "args": {"Metadata": {"Functions": [], "Number of Instructions": 3}},114                "dur": 3,115                "name": "0x400511",116                "ph": "X",117                "pid": 1,118                "ts": 0,119            },120            {121                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},122                "dur": 2,123                "name": "0x400529",124                "ph": "X",125                "pid": 1,126                "ts": 3,127            },  # head, tail128            {129                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},130                "dur": 2,131                "name": "0x400521",132                "ph": "X",133                "pid": 1,134                "ts": 5,135            },136            {137                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},138                "dur": 2,139                "name": "0x400529",140                "ph": "X",141                "pid": 1,142                "ts": 7,143            },  # head, tail144            {145                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},146                "dur": 2,147                "name": "0x400521",148                "ph": "X",149                "pid": 1,150                "ts": 9,151            },152            {153                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},154                "dur": 2,155                "name": "0x400529",156                "ph": "X",157                "pid": 1,158                "ts": 11,159            },  # head, tail160            {161                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},162                "dur": 2,163                "name": "0x400521",164                "ph": "X",165                "pid": 1,166                "ts": 13,167            },168            {169                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},170                "dur": 2,171                "name": "0x400529",172                "ph": "X",173                "pid": 1,174                "ts": 15,175            },  # head, tail176            {177                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},178                "dur": 2,179                "name": "0x400521",180                "ph": "X",181                "pid": 1,182                "ts": 17,183            },184            {185                "args": {"Metadata": {"Functions": [], "Number of Instructions": 2}},186                "dur": 2,187                "name": "0x400529",188                "ph": "X",189                "pid": 1,190                "ts": 19,191            },  # head, tail192        ]193 194        # Check that the length of the expected JSON array is equal to the actual195        self.assertEqual(len(data), len(expected))196        for i in range(len(data)):197            # Check each individual JSON object in "ctf-test.json" against the expected value above198            self.assertEqual(data[i], expected[i])199 200    def _testHtrBasicSuperBlockPassSequenceCheck(self):201        """202        Test the BasicSuperBlock pass of HTR.203 204        This test exports a modest sized trace and only checks that a particular sequence of blocks are205        expected, see `testHtrBasicSuperBlockPassFullCheck` for a more "exhaustive" test.206 207        TODO: Once the "trace save" command is implemented, gather Intel PT208        trace of this program and load it like the other tests instead of209        manually executing the commands to trace the program.210        """211        self.expect(212            f"target create {os.path.join(self.getSourceDir(), 'intelpt-trace', 'export_ctf_test_program.out')}"213        )214        self.expect("b main")215        self.expect("r")216        self.expect("b exit")217        self.expect("thread trace start")218        self.expect("c")219 220        ctf_test_file = self.getBuildArtifact("ctf-test.json")221 222        self.expect(f"thread trace export ctf --file {ctf_test_file}")223        self.assertTrue(os.path.exists(ctf_test_file))224 225        with open(ctf_test_file) as f:226            data = json.load(f)227 228        num_units_by_layer = defaultdict(int)229        index_of_first_layer_1_block = None230        for i, event in enumerate(data):231            layer_id = event.get("pid")232            self.assertIsNotNone(layer_id)233            if layer_id == 1 and index_of_first_layer_1_block is None:234                index_of_first_layer_1_block = i235            num_units_by_layer[layer_id] += 1236 237        # Check that there are only two layers and that the layer IDs are correct238        # Check that layer IDs are correct239        self.assertTrue(240            len(num_units_by_layer) == 2241            and 0 in num_units_by_layer242            and 1 in num_units_by_layer243        )244 245        # The expected block names for the first 7 blocks of layer 1246        expected_block_names = [247            "0x4005f0",248            "0x4005fe",249            "0x400606: iterative_handle_request_by_id(int, int)",250            "0x4005a7",251            "0x4005af",252            "0x4005b9: fast_handle_request(int)",253            "0x4005d5: log_response(int)",254        ]255 256        data_index = index_of_first_layer_1_block257        for i in range(len(expected_block_names)):258            self.assertEqual(data[data_index + i]["name"], expected_block_names[i])259