xref: /llvm-project/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py (revision 586114510c5fa71d1377c7f53e68a3b12c472aa2)
1from lldbsuite.test.lldbtest import *
2import os
3import time
4import json
5
6ADDRESS_REGEX = "0x[0-9a-fA-F]*"
7
8
9# Decorator that runs a test with both modes of USE_SB_API.
10# It assumes that no tests can be executed in parallel.
11def testSBAPIAndCommands(func):
12    def wrapper(*args, **kwargs):
13        TraceIntelPTTestCaseBase.USE_SB_API = True
14        func(*args, **kwargs)
15        TraceIntelPTTestCaseBase.USE_SB_API = False
16        func(*args, **kwargs)
17
18    return wrapper
19
20
21# Class that should be used by all python Intel PT tests.
22#
23# It has a handy check that skips the test if the intel-pt plugin is not enabled.
24#
25# It also contains many functions that can test both the SB API or the command line version
26# of the most important tracing actions.
27class TraceIntelPTTestCaseBase(TestBase):
28    NO_DEBUG_INFO_TESTCASE = True
29
30    # If True, the trace test methods will use the SB API, otherwise they'll use raw commands.
31    USE_SB_API = False
32
33    def setUp(self):
34        TestBase.setUp(self)
35        if "intel-pt" not in configuration.enabled_plugins:
36            self.skipTest("The intel-pt test plugin is not enabled")
37
38    def skipIfPerCpuTracingIsNotSupported(self):
39        def is_supported():
40            try:
41                with open("/proc/sys/kernel/perf_event_paranoid", "r") as permissions:
42                    value = int(permissions.readlines()[0])
43                    if value <= 0:
44                        return True
45            except:
46                return False
47
48        if not is_supported():
49            self.skipTest(
50                "Per cpu tracing is not supported. You need "
51                "/proc/sys/kernel/perf_event_paranoid to be 0 or -1. "
52                "You can use `sudo sysctl -w kernel.perf_event_paranoid=-1` for that."
53            )
54
55    def getTraceOrCreate(self):
56        if not self.target().GetTrace().IsValid():
57            error = lldb.SBError()
58            self.target().CreateTrace(error)
59        return self.target().GetTrace()
60
61    def assertSBError(self, sberror, error=False):
62        if error:
63            self.assertTrue(sberror.Fail())
64        else:
65            self.assertSuccess(sberror)
66
67    def createConfiguration(
68        self,
69        iptTraceSize=None,
70        processBufferSizeLimit=None,
71        enableTsc=False,
72        psbPeriod=None,
73        perCpuTracing=False,
74    ):
75        obj = {}
76        if processBufferSizeLimit is not None:
77            obj["processBufferSizeLimit"] = processBufferSizeLimit
78        if iptTraceSize is not None:
79            obj["iptTraceSize"] = iptTraceSize
80        if psbPeriod is not None:
81            obj["psbPeriod"] = psbPeriod
82        obj["enableTsc"] = enableTsc
83        obj["perCpuTracing"] = perCpuTracing
84
85        configuration = lldb.SBStructuredData()
86        configuration.SetFromJSON(json.dumps(obj))
87        return configuration
88
89    def traceStartThread(
90        self,
91        thread=None,
92        error=False,
93        substrs=None,
94        iptTraceSize=None,
95        enableTsc=False,
96        psbPeriod=None,
97    ):
98        if self.USE_SB_API:
99            trace = self.getTraceOrCreate()
100            thread = thread if thread is not None else self.thread()
101            configuration = self.createConfiguration(
102                iptTraceSize=iptTraceSize, enableTsc=enableTsc, psbPeriod=psbPeriod
103            )
104            self.assertSBError(trace.Start(thread, configuration), error)
105        else:
106            command = "thread trace start"
107            if thread is not None:
108                command += " " + str(thread.GetIndexID())
109            if iptTraceSize is not None:
110                command += " -s " + str(iptTraceSize)
111            if enableTsc:
112                command += " --tsc"
113            if psbPeriod is not None:
114                command += " --psb-period " + str(psbPeriod)
115            self.expect(command, error=error, substrs=substrs)
116
117    def traceStartProcess(
118        self,
119        processBufferSizeLimit=None,
120        error=False,
121        substrs=None,
122        enableTsc=False,
123        psbPeriod=None,
124        perCpuTracing=False,
125    ):
126        if self.USE_SB_API:
127            trace = self.getTraceOrCreate()
128            configuration = self.createConfiguration(
129                processBufferSizeLimit=processBufferSizeLimit,
130                enableTsc=enableTsc,
131                psbPeriod=psbPeriod,
132                perCpuTracing=perCpuTracing,
133            )
134            self.assertSBError(trace.Start(configuration), error=error)
135        else:
136            command = "process trace start"
137            if processBufferSizeLimit is not None:
138                command += " -l " + str(processBufferSizeLimit)
139            if enableTsc:
140                command += " --tsc"
141            if psbPeriod is not None:
142                command += " --psb-period " + str(psbPeriod)
143            if perCpuTracing:
144                command += " --per-cpu-tracing"
145            self.expect(command, error=error, substrs=substrs)
146
147    def traceStopProcess(self):
148        if self.USE_SB_API:
149            self.assertSuccess(self.target().GetTrace().Stop())
150        else:
151            self.expect("process trace stop")
152
153    def traceStopThread(self, thread=None, error=False, substrs=None):
154        if self.USE_SB_API:
155            thread = thread if thread is not None else self.thread()
156            self.assertSBError(self.target().GetTrace().Stop(thread), error)
157
158        else:
159            command = "thread trace stop"
160            if thread is not None:
161                command += " " + str(thread.GetIndexID())
162            self.expect(command, error=error, substrs=substrs)
163
164    def traceLoad(self, traceDescriptionFilePath, error=False, substrs=None):
165        if self.USE_SB_API:
166            traceDescriptionFile = lldb.SBFileSpec(traceDescriptionFilePath, True)
167            loadTraceError = lldb.SBError()
168            self.dbg.LoadTraceFromFile(loadTraceError, traceDescriptionFile)
169            self.assertSBError(loadTraceError, error)
170        else:
171            command = f"trace load -v {traceDescriptionFilePath}"
172            self.expect(command, error=error, substrs=substrs)
173
174    def traceSave(self, traceBundleDir, compact=False, error=False, substrs=None):
175        if self.USE_SB_API:
176            save_error = lldb.SBError()
177            self.target().GetTrace().SaveToDisk(
178                save_error, lldb.SBFileSpec(traceBundleDir), compact
179            )
180            self.assertSBError(save_error, error)
181        else:
182            command = f"trace save {traceBundleDir}"
183            if compact:
184                command += " -c"
185            self.expect(command, error=error, substrs=substrs)
186