1import lldb 2from intelpt_testcase import * 3from lldbsuite.test.lldbtest import * 4from lldbsuite.test import lldbutil 5from lldbsuite.test.decorators import * 6 7 8class TestTraceTimestampCounters(TraceIntelPTTestCaseBase): 9 @testSBAPIAndCommands 10 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) 11 def testTscPerThread(self): 12 self.expect( 13 "file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 14 ) 15 self.expect("b main") 16 self.expect("r") 17 18 self.traceStartThread(enableTsc=True) 19 20 self.expect("n") 21 self.expect( 22 "thread trace dump instructions -t -c 1", 23 patterns=[": \[\d+.\d+ ns\] 0x0000000000400511 movl"], 24 ) 25 26 @testSBAPIAndCommands 27 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) 28 def testMultipleTscsPerThread(self): 29 self.expect( 30 "file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 31 ) 32 self.expect("b main") 33 self.expect("r") 34 35 self.traceStartThread(enableTsc=True) 36 37 # After each stop there'll be a new TSC 38 self.expect("si") 39 self.expect("si") 40 self.expect("si") 41 42 # We'll get the most recent instructions, with at least 3 different TSCs 43 self.runCmd("thread trace dump instructions -t --raw --forward") 44 id_to_timestamp = {} 45 for line in self.res.GetOutput().splitlines(): 46 m = re.search(" (.+): \[(.+)\ ns].*", line) 47 if m: 48 id_to_timestamp[int(m.group(1))] = m.group(2) 49 self.assertEqual(len(id_to_timestamp), 3) 50 51 # We check that the values are right when dumping a specific id 52 for id, timestamp in id_to_timestamp.items(): 53 self.expect( 54 f"thread trace dump instructions -t --id {id} -c 1", 55 substrs=[f"{id}: [{timestamp} ns]"], 56 ) 57 58 @testSBAPIAndCommands 59 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) 60 def testTscPerProcess(self): 61 self.expect( 62 "file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 63 ) 64 self.expect("b main") 65 self.expect("r") 66 67 self.traceStartProcess(enableTsc=True) 68 69 self.expect("n") 70 self.expect( 71 "thread trace dump instructions -t -c 1", 72 patterns=[": \[\d+.\d+ ns\] 0x0000000000400511 movl"], 73 ) 74 75 self.expect( 76 "thread trace dump instructions -t -c 1 --pretty-json", 77 patterns=['''"timestamp_ns": "\d+.\d+"'''], 78 ) 79 80 @testSBAPIAndCommands 81 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) 82 def testDumpingAfterTracingWithoutTsc(self): 83 self.expect( 84 "file " + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 85 ) 86 self.expect("b main") 87 self.expect("r") 88 89 self.traceStartThread(enableTsc=False) 90 91 self.expect("n") 92 self.expect( 93 "thread trace dump instructions -t -c 1", 94 patterns=[": \[unavailable\] 0x0000000000400511 movl"], 95 ) 96 97 self.expect( 98 "thread trace dump instructions -t -c 1 --json", 99 substrs=[""""timestamp_ns":null"""], 100 ) 101 102 @testSBAPIAndCommands 103 @skipIf(oslist=no_match(["linux"]), archs=no_match(["i386", "x86_64"])) 104 def testPSBPeriod(self): 105 def isPSBSupported(): 106 caps_file = "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc" 107 if not os.path.exists(caps_file): 108 return False 109 with open(caps_file, "r") as f: 110 val = int(f.readline()) 111 if val != 1: 112 return False 113 return True 114 115 def getValidPSBValues(): 116 values_file = "/sys/bus/event_source/devices/intel_pt/caps/psb_periods" 117 values = [] 118 with open(values_file, "r") as f: 119 mask = int(f.readline(), 16) 120 for i in range(0, 32): 121 if (1 << i) & mask: 122 values.append(i) 123 return values 124 125 if not isPSBSupported(): 126 self.skipTest("PSB period unsupported") 127 128 valid_psb_values = getValidPSBValues() 129 # 0 should always be valid, and it's assumed by lldb-server 130 self.assertEqual(valid_psb_values[0], 0) 131 132 self.expect( 133 "file " + (os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) 134 ) 135 self.expect("b main") 136 self.expect("r") 137 138 # it's enough to test with two valid values 139 for psb_period in (valid_psb_values[0], valid_psb_values[-1]): 140 # we first test at thread level 141 self.traceStartThread(psbPeriod=psb_period) 142 self.traceStopThread() 143 144 # we now test at process level 145 self.traceStartProcess(psbPeriod=psb_period) 146 self.traceStopProcess() 147 148 # we now test invalid values 149 self.traceStartThread( 150 psbPeriod=valid_psb_values[-1] + 1, 151 error=True, 152 substrs=["Invalid psb_period. Valid values are: 0"], 153 ) 154 155 # TODO: dump the perf_event_attr.config as part of the upcoming "trace dump info" 156 # command and check that the psb period is included there. 157