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