aboutsummaryrefslogtreecommitdiff
path: root/lldb/test/API/commands/trace/TestTraceTSC.py
blob: b20ba5255549cc082fee31820d9a2194d651b577 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import lldb
from intelpt_testcase import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test.decorators import *


@skipIfNoIntelPT
class TestTraceTimestampCounters(TraceIntelPTTestCaseBase):
    @testSBAPIAndCommands
    @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
    def testTscPerThread(self):
        self.expect(
            "file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
        )
        self.expect("b main")
        self.expect("r")

        self.traceStartThread(enableTsc=True)

        self.expect("n")
        self.expect(
            "thread trace dump instructions -t -c 1",
            patterns=[r": \[\d+.\d+ ns\] 0x0000000000400511    movl"],
        )

    @testSBAPIAndCommands
    @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
    def testMultipleTscsPerThread(self):
        self.expect(
            "file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
        )
        self.expect("b main")
        self.expect("r")

        self.traceStartThread(enableTsc=True)

        # After each stop there'll be a new TSC
        self.expect("si")
        self.expect("si")
        self.expect("si")

        # We'll get the most recent instructions, with at least 3 different TSCs
        self.runCmd("thread trace dump instructions -t --raw --forward")
        id_to_timestamp = {}
        for line in self.res.GetOutput().splitlines():
            m = re.search(r"    (.+): \[(.+)\ ns].*", line)
            if m:
                id_to_timestamp[int(m.group(1))] = m.group(2)
        self.assertEqual(len(id_to_timestamp), 3)

        # We check that the values are right when dumping a specific id
        for id, timestamp in id_to_timestamp.items():
            self.expect(
                f"thread trace dump instructions -t --id {id} -c 1",
                substrs=[f"{id}: [{timestamp} ns]"],
            )

    @testSBAPIAndCommands
    @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
    def testTscPerProcess(self):
        self.expect(
            "file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
        )
        self.expect("b main")
        self.expect("r")

        self.traceStartProcess(enableTsc=True)

        self.expect("n")
        self.expect(
            "thread trace dump instructions -t -c 1",
            patterns=[r": \[\d+.\d+ ns\] 0x0000000000400511    movl"],
        )

        self.expect(
            "thread trace dump instructions -t -c 1 --pretty-json",
            patterns=[r'''"timestamp_ns": "\d+.\d+"'''],
        )

    @testSBAPIAndCommands
    @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
    def testDumpingAfterTracingWithoutTsc(self):
        self.expect(
            "file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")
        )
        self.expect("b main")
        self.expect("r")

        self.traceStartThread(enableTsc=False)

        self.expect("n")
        self.expect(
            "thread trace dump instructions -t -c 1",
            patterns=[r": \[unavailable\] 0x0000000000400511    movl"],
        )

        self.expect(
            "thread trace dump instructions -t -c 1 --json",
            substrs=[""""timestamp_ns":null"""],
        )

    @testSBAPIAndCommands
    @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))
    def testPSBPeriod(self):
        def isPSBSupported():
            caps_file = "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc"
            if not os.path.exists(caps_file):
                return False
            with open(caps_file, "r") as f:
                val = int(f.readline())
                if val != 1:
                    return False
            return True

        def getValidPSBValues():
            values_file = "/sys/bus/event_source/devices/intel_pt/caps/psb_periods"
            values = []
            with open(values_file, "r") as f:
                mask = int(f.readline(), 16)
                for i in range(0, 32):
                    if (1 << i) & mask:
                        values.append(i)
            return values

        if not isPSBSupported():
            self.skipTest("PSB period unsupported")

        valid_psb_values = getValidPSBValues()
        # 0 should always be valid, and it's assumed by lldb-server
        self.assertEqual(valid_psb_values[0], 0)

        self.expect(
            "file " + (os.path.join(self.getSourceDir(), "intelpt-trace", "a.out"))
        )
        self.expect("b main")
        self.expect("r")

        # it's enough to test with two valid values
        for psb_period in (valid_psb_values[0], valid_psb_values[-1]):
            # we first test at thread level
            self.traceStartThread(psbPeriod=psb_period)
            self.traceStopThread()

            # we now test at process level
            self.traceStartProcess(psbPeriod=psb_period)
            self.traceStopProcess()

        # we now test invalid values
        self.traceStartThread(
            psbPeriod=valid_psb_values[-1] + 1,
            error=True,
            substrs=["Invalid psb_period. Valid values are: 0"],
        )

        # TODO: dump the perf_event_attr.config as part of the upcoming "trace dump info"
        # command and check that the psb period is included there.