1import lldb
2from intelpt_testcase import *
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test import lldbutil
5from lldbsuite.test.decorators import *
6
7class TestTraceStartStopMultipleThreads(TraceIntelPTTestCaseBase):
8
9    mydir = TestBase.compute_mydir(__file__)
10
11    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
12    @testSBAPIAndCommands
13    def testStartMultipleLiveThreads(self):
14        self.build()
15        exe = self.getBuildArtifact("a.out")
16
17        self.dbg.CreateTarget(exe)
18
19        self.expect("b main")
20        self.expect("b 6")
21        self.expect("b 11")
22
23        self.expect("r")
24        self.traceStartProcess()
25
26        self.expect("continue")
27        self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
28
29        # We'll see here the second thread
30        self.expect("continue")
31        self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
32
33        self.traceStopProcess()
34
35    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
36    @testSBAPIAndCommands
37    def testStartMultipleLiveThreadsWithStops(self):
38        self.build()
39        exe = self.getBuildArtifact("a.out")
40
41        self.dbg.CreateTarget(exe)
42
43        self.expect("b main")
44        self.expect("b 6")
45        self.expect("b 11")
46
47        self.expect("r")
48        self.traceStartProcess()
49
50        # We'll see here the first thread
51        self.expect("continue")
52
53        # We are in thread 2
54        self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
55        self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
56
57        # We stop tracing it
58        self.expect("thread trace stop 2")
59
60        # The trace is still in memory
61        self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
62
63        # We'll stop at the next breakpoint, thread 2 will be still alive, but not traced. Thread 3 will be traced
64        self.expect("continue")
65        self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
66        self.expect("thread trace dump instructions 3", substrs=['main.cpp:4'])
67
68        self.expect("thread trace dump instructions 2", substrs=['not traced'])
69
70        self.traceStopProcess()
71
72    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
73    @testSBAPIAndCommands
74    def testStartMultipleLiveThreadsWithStops(self):
75        self.build()
76        exe = self.getBuildArtifact("a.out")
77        self.dbg.CreateTarget(exe)
78
79        self.expect("b main")
80        self.expect("b 6")
81        self.expect("b 11")
82
83        self.expect("r")
84
85        self.traceStartProcess()
86
87        # We'll see here the first thread
88        self.expect("continue")
89
90        # We are in thread 2
91        self.expect("thread trace dump instructions", substrs=['main.cpp:9'])
92        self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
93
94        # We stop tracing all
95        self.expect("thread trace stop all")
96
97        # The trace is still in memory
98        self.expect("thread trace dump instructions 2", substrs=['main.cpp:9'])
99
100        # We'll stop at the next breakpoint in thread 3, thread 2 and 3 will be alive, but only 3 traced.
101        self.expect("continue")
102        self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
103        self.expect("thread trace dump instructions 3", substrs=['main.cpp:4'])
104        self.expect("thread trace dump instructions 1", substrs=['not traced'])
105        self.expect("thread trace dump instructions 2", substrs=['not traced'])
106
107        self.traceStopProcess()
108
109    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
110    def testStartMultipleLiveThreadsWithThreadStartAll(self):
111        self.build()
112        exe = self.getBuildArtifact("a.out")
113        target = self.dbg.CreateTarget(exe)
114
115        self.expect("b main")
116        self.expect("b 6")
117        self.expect("b 11")
118
119        self.expect("r")
120
121        self.expect("continue")
122        # We are in thread 2
123        self.expect("thread trace start all")
124        # Now we have instructions in thread's 2 trace
125        self.expect("n")
126
127        self.expect("thread trace dump instructions 2", substrs=['main.cpp:11'])
128
129        # We stop tracing all
130        self.runCmd("thread trace stop all")
131
132        # The trace is still in memory
133        self.expect("thread trace dump instructions 2", substrs=['main.cpp:11'])
134
135        # We'll stop at the next breakpoint in thread 3, and nothing should be traced
136        self.expect("continue")
137        self.expect("thread trace dump instructions 3", substrs=['not traced'])
138        self.expect("thread trace dump instructions 1", substrs=['not traced'])
139        self.expect("thread trace dump instructions 2", substrs=['not traced'])
140
141    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
142    @testSBAPIAndCommands
143    def testStartMultipleLiveThreadsWithSmallTotalLimit(self):
144        self.build()
145        exe = self.getBuildArtifact("a.out")
146
147        self.dbg.CreateTarget(exe)
148
149        self.expect("b main")
150        self.expect("r")
151
152        # trace the entire process with enough total size for 1 thread trace
153        self.traceStartProcess(processBufferSizeLimit=5000)
154
155        # we get the stop event when trace 2 appears and can't be traced
156        self.expect("c", substrs=['Thread', "can't be traced"])
157        # we get the stop event when trace 3 appears and can't be traced
158        self.expect("c", substrs=['Thread', "can't be traced"])
159
160        self.traceStopProcess()
161
162    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
163    @testSBAPIAndCommands
164    def testStartPerCoreSession(self):
165        self.skipIfPerCoreTracingIsNotSupported()
166
167        self.build()
168        exe = self.getBuildArtifact("a.out")
169        self.dbg.CreateTarget(exe)
170
171        self.expect("b main")
172        self.expect("r")
173
174        # We should fail if we hit the total buffer limit. Useful if the number
175        # of cores is huge.
176        self.traceStartProcess(error="True", processBufferSizeLimit=100,
177            perCoreTracing=True,
178            substrs=["The process can't be traced because the process trace size "
179            "limit has been reached. Consider retracing with a higher limit."])
180
181        self.traceStartProcess(perCoreTracing=True)
182        self.traceStopProcess()
183
184        self.traceStartProcess(perCoreTracing=True)
185        # We can't support multiple per-core tracing sessions.
186        self.traceStartProcess(error=True, perCoreTracing=True,
187            substrs=["Process currently traced. Stop process tracing first"])
188
189        # We can't support tracing per thread is per core is enabled.
190        self.traceStartThread(
191            error="True",
192            substrs=["Process currently traced with per-core tracing. Stop process tracing first"])
193
194        # We can't stop individual thread when per core is enabled.
195        self.traceStopThread(error="True",
196            substrs=["Can't stop tracing an individual thread when per-core process tracing is enabled"])
197
198        # The GetState packet should return trace buffers per core and at least one traced thread
199        self.expect("""process plugin packet send 'jLLDBTraceGetState:{"type":"intel-pt"}]'""",
200            substrs=['''[{"kind":"traceBuffer","size":4096}],"coreId":''', '"tid":'])
201
202        self.traceStopProcess()
203