1import lldb 2import json 3from intelpt_testcase import * 4from lldbsuite.test.lldbtest import * 5from lldbsuite.test import lldbutil 6from lldbsuite.test.decorators import * 7 8class TestTraceStartStopMultipleThreads(TraceIntelPTTestCaseBase): 9 10 mydir = TestBase.compute_mydir(__file__) 11 12 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 13 @testSBAPIAndCommands 14 def testStartMultipleLiveThreads(self): 15 self.build() 16 exe = self.getBuildArtifact("a.out") 17 18 self.dbg.CreateTarget(exe) 19 20 self.expect("b main") 21 self.expect("b 6") 22 self.expect("b 11") 23 24 self.expect("r") 25 self.traceStartProcess() 26 27 self.expect("continue") 28 self.expect("thread trace dump instructions", substrs=['main.cpp:9']) 29 30 # We'll see here the second thread 31 self.expect("continue") 32 self.expect("thread trace dump instructions", substrs=['main.cpp:4']) 33 34 self.traceStopProcess() 35 36 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 37 @testSBAPIAndCommands 38 def testStartMultipleLiveThreadsWithStops(self): 39 self.build() 40 exe = self.getBuildArtifact("a.out") 41 42 self.dbg.CreateTarget(exe) 43 44 self.expect("b main") 45 self.expect("b 6") 46 self.expect("b 11") 47 48 self.expect("r") 49 self.traceStartProcess() 50 51 # We'll see here the first thread 52 self.expect("continue") 53 54 # We are in thread 2 55 self.expect("thread trace dump instructions", substrs=['main.cpp:9']) 56 self.expect("thread trace dump instructions 2", substrs=['main.cpp:9']) 57 58 # We stop tracing it 59 self.expect("thread trace stop 2") 60 61 # The trace is still in memory 62 self.expect("thread trace dump instructions 2", substrs=['main.cpp:9']) 63 64 # We'll stop at the next breakpoint, thread 2 will be still alive, but not traced. Thread 3 will be traced 65 self.expect("continue") 66 self.expect("thread trace dump instructions", substrs=['main.cpp:4']) 67 self.expect("thread trace dump instructions 3", substrs=['main.cpp:4']) 68 69 self.expect("thread trace dump instructions 2", substrs=['not traced']) 70 71 self.traceStopProcess() 72 73 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 74 @testSBAPIAndCommands 75 def testStartMultipleLiveThreadsWithStops(self): 76 self.build() 77 exe = self.getBuildArtifact("a.out") 78 self.dbg.CreateTarget(exe) 79 80 self.expect("b main") 81 self.expect("b 6") 82 self.expect("b 11") 83 84 self.expect("r") 85 86 self.traceStartProcess() 87 88 # We'll see here the first thread 89 self.expect("continue") 90 91 # We are in thread 2 92 self.expect("thread trace dump instructions", substrs=['main.cpp:9']) 93 self.expect("thread trace dump instructions 2", substrs=['main.cpp:9']) 94 95 # We stop tracing all 96 self.expect("thread trace stop all") 97 98 # The trace is still in memory 99 self.expect("thread trace dump instructions 2", substrs=['main.cpp:9']) 100 101 # We'll stop at the next breakpoint in thread 3, thread 2 and 3 will be alive, but only 3 traced. 102 self.expect("continue") 103 self.expect("thread trace dump instructions", substrs=['main.cpp:4']) 104 self.expect("thread trace dump instructions 3", substrs=['main.cpp:4']) 105 self.expect("thread trace dump instructions 1", substrs=['not traced']) 106 self.expect("thread trace dump instructions 2", substrs=['not traced']) 107 108 self.traceStopProcess() 109 110 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 111 def testStartMultipleLiveThreadsWithThreadStartAll(self): 112 self.build() 113 exe = self.getBuildArtifact("a.out") 114 target = self.dbg.CreateTarget(exe) 115 116 self.expect("b main") 117 self.expect("b 6") 118 self.expect("b 11") 119 120 self.expect("r") 121 122 self.expect("continue") 123 # We are in thread 2 124 self.expect("thread trace start all") 125 # Now we have instructions in thread's 2 trace 126 self.expect("n") 127 128 self.expect("thread trace dump instructions 2", substrs=['main.cpp:11']) 129 130 # We stop tracing all 131 self.runCmd("thread trace stop all") 132 133 # The trace is still in memory 134 self.expect("thread trace dump instructions 2", substrs=['main.cpp:11']) 135 136 # We'll stop at the next breakpoint in thread 3, and nothing should be traced 137 self.expect("continue") 138 self.expect("thread trace dump instructions 3", substrs=['not traced']) 139 self.expect("thread trace dump instructions 1", substrs=['not traced']) 140 self.expect("thread trace dump instructions 2", substrs=['not traced']) 141 142 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 143 @testSBAPIAndCommands 144 def testStartMultipleLiveThreadsWithSmallTotalLimit(self): 145 self.build() 146 exe = self.getBuildArtifact("a.out") 147 148 self.dbg.CreateTarget(exe) 149 150 self.expect("b main") 151 self.expect("r") 152 153 # trace the entire process with enough total size for 1 thread trace 154 self.traceStartProcess(processBufferSizeLimit=5000) 155 156 # we get the stop event when trace 2 appears and can't be traced 157 self.expect("c", substrs=['Thread', "can't be traced"]) 158 # we get the stop event when trace 3 appears and can't be traced 159 self.expect("c", substrs=['Thread', "can't be traced"]) 160 161 self.traceStopProcess() 162 163 @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64'])) 164 @testSBAPIAndCommands 165 def testStartPerCoreSession(self): 166 self.skipIfPerCoreTracingIsNotSupported() 167 168 self.build() 169 exe = self.getBuildArtifact("a.out") 170 self.dbg.CreateTarget(exe) 171 172 self.expect("b main") 173 self.expect("r") 174 175 # We should fail if we hit the total buffer limit. Useful if the number 176 # of cores is huge. 177 self.traceStartProcess(error="True", processBufferSizeLimit=100, 178 perCoreTracing=True, 179 substrs=["The process can't be traced because the process trace size " 180 "limit has been reached. Consider retracing with a higher limit."]) 181 182 self.traceStartProcess(perCoreTracing=True) 183 self.traceStopProcess() 184 185 self.traceStartProcess(perCoreTracing=True) 186 # We can't support multiple per-core tracing sessions. 187 self.traceStartProcess(error=True, perCoreTracing=True, 188 substrs=["Process currently traced. Stop process tracing first"]) 189 190 # We can't support tracing per thread is per core is enabled. 191 self.traceStartThread( 192 error="True", 193 substrs=["Thread with tid ", "is currently traced"]) 194 195 # We can't stop individual thread when per core is enabled. 196 self.traceStopThread(error="True", 197 substrs=["Can't stop tracing an individual thread when per-core process tracing is enabled"]) 198 199 # We move forward a little bit to collect some data 200 self.expect("b 19") 201 self.expect("c") 202 203 # We will assert that the trace state will contain valid context switch and trace buffer entries. 204 # Besides that, we need to get tsc-to-nanos conversion information. 205 206 # We first parse the json response from the custom packet 207 self.runCmd("""process plugin packet send 'jLLDBTraceGetState:{"type":"intel-pt"}]'""") 208 response_header = 'response: ' 209 output = None 210 for line in self.res.GetOutput().splitlines(): 211 if line.find(response_header) != -1: 212 response = line[line.find(response_header) + len(response_header):].strip() 213 output = json.loads(response) 214 215 self.assertTrue(output is not None) 216 self.assertIn("cores", output) 217 self.assertIn("tscPerfZeroConversion", output) 218 found_non_empty_context_switch = False 219 220 for core in output["cores"]: 221 context_switch_size = None 222 trace_buffer_size = None 223 for binary_data in core["binaryData"]: 224 if binary_data["kind"] == "traceBuffer": 225 trace_buffer_size = binary_data["size"] 226 elif binary_data["kind"] == "perfContextSwitchTrace": 227 context_switch_size = binary_data["size"] 228 self.assertTrue(context_switch_size is not None) 229 self.assertTrue(trace_buffer_size is not None) 230 if context_switch_size > 0: 231 found_non_empty_context_switch = True 232 233 # We must have captured the context switch of when the target resumed 234 self.assertTrue(found_non_empty_context_switch) 235 236 237 self.traceStopProcess() 238