1602497d6SWalter Erquinigoimport lldb 2fc5ef57cSWalter Erquinigoimport json 3602497d6SWalter Erquinigofrom intelpt_testcase import * 4602497d6SWalter Erquinigofrom lldbsuite.test.lldbtest import * 5602497d6SWalter Erquinigofrom lldbsuite.test import lldbutil 6602497d6SWalter Erquinigofrom lldbsuite.test.decorators import * 7602497d6SWalter Erquinigo 82238dcc3SJonas Devlieghere 9fc5ef57cSWalter Erquinigodef find(predicate, seq): 10fc5ef57cSWalter Erquinigo for item in seq: 11fc5ef57cSWalter Erquinigo if predicate(item): 12fc5ef57cSWalter Erquinigo return item 13fc5ef57cSWalter Erquinigo 14602497d6SWalter Erquinigo 152238dcc3SJonas Devlieghereclass TestTraceSave(TraceIntelPTTestCaseBase): 16602497d6SWalter Erquinigo def testErrorMessages(self): 17602497d6SWalter Erquinigo # We first check the output when there are no targets 182238dcc3SJonas Devlieghere self.expect( 192238dcc3SJonas Devlieghere "trace save", 202238dcc3SJonas Devlieghere substrs=[ 212238dcc3SJonas Devlieghere "error: invalid target, create a target using the 'target create' command" 222238dcc3SJonas Devlieghere ], 232238dcc3SJonas Devlieghere error=True, 242238dcc3SJonas Devlieghere ) 25602497d6SWalter Erquinigo 26602497d6SWalter Erquinigo # We now check the output when there's a non-running target 272238dcc3SJonas Devlieghere self.expect( 282238dcc3SJonas Devlieghere "target create " 292238dcc3SJonas Devlieghere + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 302238dcc3SJonas Devlieghere ) 31602497d6SWalter Erquinigo 322238dcc3SJonas Devlieghere self.expect( 332238dcc3SJonas Devlieghere "trace save", 34b7d525adSWalter Erquinigo substrs=["error: Command requires a current process."], 352238dcc3SJonas Devlieghere error=True, 362238dcc3SJonas Devlieghere ) 37602497d6SWalter Erquinigo 38602497d6SWalter Erquinigo # Now we check the output when there's a running target without a trace 39602497d6SWalter Erquinigo self.expect("b main") 40602497d6SWalter Erquinigo self.expect("run") 41602497d6SWalter Erquinigo 422238dcc3SJonas Devlieghere self.expect( 432238dcc3SJonas Devlieghere "trace save", substrs=["error: Process is not being traced"], error=True 442238dcc3SJonas Devlieghere ) 45602497d6SWalter Erquinigo 46602497d6SWalter Erquinigo def testSaveToInvalidDir(self): 472238dcc3SJonas Devlieghere self.expect( 482238dcc3SJonas Devlieghere "target create " 492238dcc3SJonas Devlieghere + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 502238dcc3SJonas Devlieghere ) 51602497d6SWalter Erquinigo self.expect("b main") 52602497d6SWalter Erquinigo self.expect("r") 53602497d6SWalter Erquinigo self.expect("thread trace start") 54602497d6SWalter Erquinigo self.expect("n") 55602497d6SWalter Erquinigo 56602497d6SWalter Erquinigo # Check the output when saving without providing the directory argument 572238dcc3SJonas Devlieghere self.expect( 582238dcc3SJonas Devlieghere "trace save ", 592238dcc3SJonas Devlieghere substrs=[ 602238dcc3SJonas Devlieghere "error: a single path to a directory where the trace bundle will be created is required" 612238dcc3SJonas Devlieghere ], 622238dcc3SJonas Devlieghere error=True, 632238dcc3SJonas Devlieghere ) 64602497d6SWalter Erquinigo 65602497d6SWalter Erquinigo # Check the output when saving to an invalid directory 662238dcc3SJonas Devlieghere self.expect( 672238dcc3SJonas Devlieghere "trace save /", substrs=["error: couldn't write to the file"], error=True 682238dcc3SJonas Devlieghere ) 69602497d6SWalter Erquinigo 70602497d6SWalter Erquinigo def testSaveWhenNotLiveTrace(self): 712238dcc3SJonas Devlieghere self.expect( 722238dcc3SJonas Devlieghere "trace load -v " 732238dcc3SJonas Devlieghere + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"), 742238dcc3SJonas Devlieghere substrs=["intel-pt"], 752238dcc3SJonas Devlieghere ) 76602497d6SWalter Erquinigo 77602497d6SWalter Erquinigo # Check the output when not doing live tracing 782238dcc3SJonas Devlieghere self.expect( 792238dcc3SJonas Devlieghere "trace save " 802238dcc3SJonas Devlieghere + os.path.join(self.getBuildDir(), "intelpt-trace", "trace_not_live_dir") 812238dcc3SJonas Devlieghere ) 82602497d6SWalter Erquinigo 836a5355e8SWalter Erquinigo def testSaveMultiCpuTrace(self): 842238dcc3SJonas Devlieghere """ 856a5355e8SWalter Erquinigo This test starts a per-cpu tracing session, then saves the session to disk, and 86fc5ef57cSWalter Erquinigo finally it loads it again. 872238dcc3SJonas Devlieghere """ 886a5355e8SWalter Erquinigo self.skipIfPerCpuTracingIsNotSupported() 89fc5ef57cSWalter Erquinigo 902238dcc3SJonas Devlieghere self.expect( 912238dcc3SJonas Devlieghere "target create " 922238dcc3SJonas Devlieghere + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 932238dcc3SJonas Devlieghere ) 94fc5ef57cSWalter Erquinigo self.expect("b main") 95fc5ef57cSWalter Erquinigo self.expect("r") 966a5355e8SWalter Erquinigo self.expect("process trace start --per-cpu-tracing") 97fc5ef57cSWalter Erquinigo self.expect("b 7") 98fc5ef57cSWalter Erquinigo 99fc5ef57cSWalter Erquinigo output_dir = os.path.join(self.getBuildDir(), "intelpt-trace", "trace_save") 100b532dd54SWalter Erquinigo self.expect("trace save " + output_dir) 101fc5ef57cSWalter Erquinigo 102fc5ef57cSWalter Erquinigo def checkSessionBundle(session_file_path): 103fc5ef57cSWalter Erquinigo with open(session_file_path) as session_file: 104fc5ef57cSWalter Erquinigo session = json.load(session_file) 105fc5ef57cSWalter Erquinigo # We expect tsc conversion info 1069c246882SJordan Rupprecht self.assertIn("tscPerfZeroConversion", session) 1076a5355e8SWalter Erquinigo # We expect at least one cpu 1086a5355e8SWalter Erquinigo self.assertGreater(len(session["cpus"]), 0) 109fc5ef57cSWalter Erquinigo 110fc5ef57cSWalter Erquinigo # We expect the required trace files to be created 1116a5355e8SWalter Erquinigo for cpu in session["cpus"]: 1126a5355e8SWalter Erquinigo cpu_files_prefix = os.path.join(output_dir, "cpus", str(cpu["id"])) 1136a5355e8SWalter Erquinigo self.assertTrue(os.path.exists(cpu_files_prefix + ".intelpt_trace")) 1142238dcc3SJonas Devlieghere self.assertTrue( 1152238dcc3SJonas Devlieghere os.path.exists(cpu_files_prefix + ".perf_context_switch_trace") 1162238dcc3SJonas Devlieghere ) 117fc5ef57cSWalter Erquinigo 118fc5ef57cSWalter Erquinigo # We expect at least one one process 119fc5ef57cSWalter Erquinigo self.assertGreater(len(session["processes"]), 0) 120fc5ef57cSWalter Erquinigo for process in session["processes"]: 121fc5ef57cSWalter Erquinigo # We expect at least one thread 122fc5ef57cSWalter Erquinigo self.assertGreater(len(process["threads"]), 0) 123fc5ef57cSWalter Erquinigo # We don't expect thread traces 124fc5ef57cSWalter Erquinigo for thread in process["threads"]: 1252238dcc3SJonas Devlieghere self.assertTrue( 1262238dcc3SJonas Devlieghere ("iptTrace" not in thread) or (thread["iptTrace"] is None) 1272238dcc3SJonas Devlieghere ) 128fc5ef57cSWalter Erquinigo 129fc5ef57cSWalter Erquinigo original_trace_session_file = os.path.join(output_dir, "trace.json") 130fc5ef57cSWalter Erquinigo checkSessionBundle(original_trace_session_file) 131fc5ef57cSWalter Erquinigo 132fc5ef57cSWalter Erquinigo output_dir = os.path.join(self.getBuildDir(), "intelpt-trace", "trace_save") 133fc5ef57cSWalter Erquinigo self.expect("trace load " + os.path.join(output_dir, "trace.json")) 1342238dcc3SJonas Devlieghere output_copy_dir = os.path.join( 1352238dcc3SJonas Devlieghere self.getBuildDir(), "intelpt-trace", "copy_trace_save" 1362238dcc3SJonas Devlieghere ) 137b532dd54SWalter Erquinigo self.expect("trace save " + output_copy_dir) 138fc5ef57cSWalter Erquinigo 139fc5ef57cSWalter Erquinigo # We now check that the new bundle is correct on its own 140fc5ef57cSWalter Erquinigo copied_trace_session_file = os.path.join(output_copy_dir, "trace.json") 141fc5ef57cSWalter Erquinigo checkSessionBundle(copied_trace_session_file) 142fc5ef57cSWalter Erquinigo 143fc5ef57cSWalter Erquinigo # We finally check that the new bundle has the same information as the original one 144fc5ef57cSWalter Erquinigo with open(original_trace_session_file) as original_file: 145fc5ef57cSWalter Erquinigo original = json.load(original_file) 146fc5ef57cSWalter Erquinigo with open(copied_trace_session_file) as copy_file: 147fc5ef57cSWalter Erquinigo copy = json.load(copy_file) 148fc5ef57cSWalter Erquinigo 149fc5ef57cSWalter Erquinigo self.assertEqual(len(original["processes"]), len(copy["processes"])) 150fc5ef57cSWalter Erquinigo 151fc5ef57cSWalter Erquinigo for process in original["processes"]: 1522238dcc3SJonas Devlieghere copied_process = find( 1532238dcc3SJonas Devlieghere lambda proc: proc["pid"] == process["pid"], copy["processes"] 1542238dcc3SJonas Devlieghere ) 1559c246882SJordan Rupprecht self.assertIsNotNone(copied_process) 156fc5ef57cSWalter Erquinigo 157fc5ef57cSWalter Erquinigo for thread in process["threads"]: 1582238dcc3SJonas Devlieghere copied_thread = find( 1592238dcc3SJonas Devlieghere lambda thr: thr["tid"] == thread["tid"], 1602238dcc3SJonas Devlieghere copied_process["threads"], 1612238dcc3SJonas Devlieghere ) 1629c246882SJordan Rupprecht self.assertIsNotNone(copied_thread) 163fc5ef57cSWalter Erquinigo 1646a5355e8SWalter Erquinigo for cpu in original["cpus"]: 1656a5355e8SWalter Erquinigo copied_cpu = find(lambda cor: cor["id"] == cpu["id"], copy["cpus"]) 1669c246882SJordan Rupprecht self.assertIsNotNone(copied_cpu) 167602497d6SWalter Erquinigo 168602497d6SWalter Erquinigo def testSaveTrace(self): 1692238dcc3SJonas Devlieghere self.expect( 1702238dcc3SJonas Devlieghere "target create " 1712238dcc3SJonas Devlieghere + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out") 1722238dcc3SJonas Devlieghere ) 173602497d6SWalter Erquinigo self.expect("b main") 174602497d6SWalter Erquinigo self.expect("r") 175602497d6SWalter Erquinigo self.expect("thread trace start") 176602497d6SWalter Erquinigo self.expect("b 7") 177602497d6SWalter Erquinigo 178602497d6SWalter Erquinigo ci = self.dbg.GetCommandInterpreter() 179602497d6SWalter Erquinigo res = lldb.SBCommandReturnObject() 180602497d6SWalter Erquinigo 181602497d6SWalter Erquinigo ci.HandleCommand("thread trace dump instructions -c 10 --forwards", res) 182*1eeeab82SJordan Rupprecht self.assertTrue(res.Succeeded()) 183602497d6SWalter Erquinigo first_ten_instructions = res.GetOutput() 184602497d6SWalter Erquinigo 185602497d6SWalter Erquinigo ci.HandleCommand("thread trace dump instructions -c 10", res) 186*1eeeab82SJordan Rupprecht self.assertTrue(res.Succeeded()) 187602497d6SWalter Erquinigo last_ten_instructions = res.GetOutput() 188602497d6SWalter Erquinigo 189602497d6SWalter Erquinigo # Now, save the trace to <trace_copy_dir> 1902238dcc3SJonas Devlieghere self.expect( 1912238dcc3SJonas Devlieghere "trace save " 1922238dcc3SJonas Devlieghere + os.path.join(self.getBuildDir(), "intelpt-trace", "trace_copy_dir") 1932238dcc3SJonas Devlieghere ) 194602497d6SWalter Erquinigo 195602497d6SWalter Erquinigo # Load the trace just saved 1962238dcc3SJonas Devlieghere self.expect( 1972238dcc3SJonas Devlieghere "trace load -v " 1982238dcc3SJonas Devlieghere + os.path.join( 1992238dcc3SJonas Devlieghere self.getBuildDir(), "intelpt-trace", "trace_copy_dir", "trace.json" 2002238dcc3SJonas Devlieghere ), 2012238dcc3SJonas Devlieghere substrs=["intel-pt"], 2022238dcc3SJonas Devlieghere ) 203602497d6SWalter Erquinigo 204602497d6SWalter Erquinigo # Compare with instructions saved at the first time 205602497d6SWalter Erquinigo ci.HandleCommand("thread trace dump instructions -c 10 --forwards", res) 206*1eeeab82SJordan Rupprecht self.assertTrue(res.Succeeded()) 207602497d6SWalter Erquinigo self.assertEqual(res.GetOutput(), first_ten_instructions) 208602497d6SWalter Erquinigo 209602497d6SWalter Erquinigo ci.HandleCommand("thread trace dump instructions -c 10", res) 210*1eeeab82SJordan Rupprecht self.assertTrue(res.Succeeded()) 211602497d6SWalter Erquinigo self.assertEqual(res.GetOutput(), last_ten_instructions) 2126fb744beSWalter Erquinigo 2136fb744beSWalter Erquinigo def testSaveKernelTrace(self): 2142238dcc3SJonas Devlieghere original_trace_file = os.path.join( 2152238dcc3SJonas Devlieghere self.getSourceDir(), "intelpt-kernel-trace", "trace.json" 2162238dcc3SJonas Devlieghere ) 2176fb744beSWalter Erquinigo copied_trace_dir = os.path.join(self.getBuildDir(), "intelpt-kernel-trace") 2186fb744beSWalter Erquinigo copied_trace_file = os.path.join(copied_trace_dir, "trace.json") 2196fb744beSWalter Erquinigo 2206fb744beSWalter Erquinigo self.expect("trace load -v " + original_trace_file, substrs=["intel-pt"]) 2216fb744beSWalter Erquinigo self.expect("trace save " + copied_trace_dir) 2226fb744beSWalter Erquinigo 2236fb744beSWalter Erquinigo # We finally check that the new json has the same information as the original one 2246fb744beSWalter Erquinigo with open(original_trace_file) as original_file: 2256fb744beSWalter Erquinigo original_file = json.load(original_file) 2266fb744beSWalter Erquinigo with open(copied_trace_file) as copy_file: 2276fb744beSWalter Erquinigo copy_file = json.load(copy_file) 2289c246882SJordan Rupprecht self.assertIn("kernel", copy_file) 2296fb744beSWalter Erquinigo 2302238dcc3SJonas Devlieghere self.assertEqual( 2312238dcc3SJonas Devlieghere os.path.basename(original_file["kernel"]["file"]), 2322238dcc3SJonas Devlieghere os.path.basename(copy_file["kernel"]["file"]), 2332238dcc3SJonas Devlieghere ) 234