227 lines · python
1import lldb2import json3from intelpt_testcase import *4from lldbsuite.test.lldbtest import *5from lldbsuite.test import lldbutil6from lldbsuite.test.decorators import *7 8 9@skipIfNoIntelPT10class TestTraceStartStopMultipleThreads(TraceIntelPTTestCaseBase):11 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))12 @testSBAPIAndCommands13 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 thread30 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 @testSBAPIAndCommands37 def testStartMultipleLiveThreadsWithStops(self):38 self.build()39 exe = self.getBuildArtifact("a.out")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 48 self.traceStartProcess()49 50 # We'll see here the first thread51 self.expect("continue")52 53 # We are in thread 254 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 all58 self.expect("thread trace stop all")59 60 # The trace is still in memory61 self.expect("thread trace dump instructions 2", substrs=["main.cpp:9"])62 63 # We'll stop at the next breakpoint in thread 3, thread 2 and 3 will be alive, but only 3 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 self.expect(68 "thread trace dump instructions 1", substrs=["not traced"], error=True69 )70 self.expect(71 "thread trace dump instructions 2", substrs=["not traced"], error=True72 )73 74 self.traceStopProcess()75 76 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))77 def testStartMultipleLiveThreadsWithThreadStartAll(self):78 self.build()79 exe = self.getBuildArtifact("a.out")80 target = self.dbg.CreateTarget(exe)81 82 self.expect("b main")83 self.expect("b 6")84 self.expect("b 11")85 86 self.expect("r")87 88 self.expect("continue")89 # We are in thread 290 self.expect("thread trace start all")91 # Now we have instructions in thread's 2 trace92 self.expect("n")93 94 self.expect("thread trace dump instructions 2", substrs=["main.cpp:11"])95 96 # We stop tracing all97 self.runCmd("thread trace stop all")98 99 # The trace is still in memory100 self.expect("thread trace dump instructions 2", substrs=["main.cpp:11"])101 102 # We'll stop at the next breakpoint in thread 3, and nothing should be traced103 self.expect("continue")104 self.expect(105 "thread trace dump instructions 3", substrs=["not traced"], error=True106 )107 self.expect(108 "thread trace dump instructions 1", substrs=["not traced"], error=True109 )110 self.expect(111 "thread trace dump instructions 2", substrs=["not traced"], error=True112 )113 114 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))115 @testSBAPIAndCommands116 def testStartMultipleLiveThreadsWithSmallTotalLimit(self):117 self.build()118 exe = self.getBuildArtifact("a.out")119 120 self.dbg.CreateTarget(exe)121 122 self.expect("b main")123 self.expect("r")124 125 # trace the entire process with enough total size for 1 thread trace126 self.traceStartProcess(processBufferSizeLimit=5000)127 128 # we get the stop event when trace 2 appears and can't be traced129 self.expect("c", substrs=["Thread", "can't be traced"])130 # we get the stop event when trace 3 appears and can't be traced131 self.expect("c", substrs=["Thread", "can't be traced"])132 133 self.traceStopProcess()134 135 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"]))136 @testSBAPIAndCommands137 def testStartPerCpuSession(self):138 self.skipIfPerCpuTracingIsNotSupported()139 140 self.build()141 exe = self.getBuildArtifact("a.out")142 self.dbg.CreateTarget(exe)143 144 self.expect("b main")145 self.expect("r")146 147 # We should fail if we hit the total buffer limit. Useful if the number148 # of cpus is huge.149 self.traceStartProcess(150 error="True",151 processBufferSizeLimit=100,152 perCpuTracing=True,153 substrs=[154 "The process can't be traced because the process trace size "155 "limit has been reached. Consider retracing with a higher limit."156 ],157 )158 159 self.traceStartProcess(perCpuTracing=True)160 self.traceStopProcess()161 162 self.traceStartProcess(perCpuTracing=True)163 # We can't support multiple per-cpu tracing sessions.164 self.traceStartProcess(165 error=True,166 perCpuTracing=True,167 substrs=["Process currently traced. Stop process tracing first"],168 )169 170 # We can't support tracing per thread is per cpu is enabled.171 self.traceStartThread(172 error="True", substrs=["Thread with tid ", "is currently traced"]173 )174 175 # We can't stop individual thread when per cpu is enabled.176 self.traceStopThread(177 error="True",178 substrs=[179 "Can't stop tracing an individual thread when per-cpu process tracing is enabled"180 ],181 )182 183 # We move forward a little bit to collect some data184 self.expect("b 19")185 self.expect("c")186 187 # We will assert that the trace state will contain valid context switch and intel pt trace buffer entries.188 # Besides that, we need to get tsc-to-nanos conversion information.189 190 # We first parse the json response from the custom packet191 self.runCmd(192 """process plugin packet send 'jLLDBTraceGetState:{"type":"intel-pt"}]'"""193 )194 response_header = "response: "195 output = None196 for line in self.res.GetOutput().splitlines():197 if line.find(response_header) != -1:198 response = line[199 line.find(response_header) + len(response_header) :200 ].strip()201 output = json.loads(response)202 203 self.assertIsNotNone(output)204 self.assertIn("cpus", output)205 self.assertIn("tscPerfZeroConversion", output)206 found_non_empty_context_switch = False207 208 for cpu in output["cpus"]:209 context_switch_size = None210 ipt_trace_size = None211 for binary_data in cpu["binaryData"]:212 if binary_data["kind"] == "iptTrace":213 ipt_trace_size = binary_data["size"]214 elif binary_data["kind"] == "perfContextSwitchTrace":215 context_switch_size = binary_data["size"]216 self.assertIsNotNone(context_switch_size)217 self.assertIsNotNone(ipt_trace_size)218 if context_switch_size > 0:219 found_non_empty_context_switch = True220 221 # We must have captured the context switch of when the target resumed222 self.assertTrue(found_non_empty_context_switch)223 224 self.expect("thread trace dump instructions")225 226 self.traceStopProcess()227