public static async Task <bool> TEST_TracesHaveRelevantEvents() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); using var memoryStream = new MemoryStream(); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, $"{serverName}" } }, duringExecution: async(pid) => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose) }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); Task readerTask = eventStream.CopyToAsync(memoryStream); Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command"); // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid) var message = new IpcMessage(0x04, 0x01); Logger.logger.Log($"Sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); await Task.Delay(TimeSpan.FromSeconds(2)); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); } ); fSuccess &= await subprocessTask; memoryStream.Seek(0, SeekOrigin.Begin); using var source = new EventPipeEventSource(memoryStream); var parser = new ClrPrivateTraceEventParser(source); bool isStartupEventPresent = false; parser.StartupEEStartupStart += (eventData) => isStartupEventPresent = true; source.Process(); Logger.logger.Log($"isStartupEventPresent: {isStartupEventPresent}"); return(isStartupEventPresent && fSuccess); }
public static int Main(string[] args) { if (args.Length > 0 && args[0].Equals("RunTest", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("In RunTest, exiting."); return(100); } string serverName = ReverseServer.MakeServerAddress(); Task backgroundTask = Task.Run(() => { ReverseServer server = null; try { Task task = Task.Run(async() => { server = new ReverseServer(serverName); using (Stream serverStream = await server.AcceptAsync()) { IpcAdvertise advertise = IpcAdvertise.Parse(serverStream); Console.WriteLine($"Got IpcAdvertise: {advertise}"); int processId = (int)advertise.ProcessId; // While we are paused in startup send the profiler startup command string profilerPath = GetProfilerPath(); DiagnosticsIPCWorkaround client = new DiagnosticsIPCWorkaround(processId); client.SetStartupProfiler(ReverseStartupProfilerGuid, profilerPath); // Resume runtime message IpcMessage resumeMessage = new IpcMessage(0x04, 0x01); Console.WriteLine($"Sent resume runtime message: {resumeMessage.ToString()}"); IpcMessage resumeResponse = IpcClient.SendMessage(serverStream, resumeMessage); Logger.logger.Log($"Received: {resumeResponse.ToString()}"); } }); task.Wait(); } catch (Exception e) { Console.WriteLine($"ReverseServer saw exception {e.Message}"); Console.WriteLine(e.StackTrace); Console.WriteLine($"Inner exception {e.InnerException?.Message}"); Console.WriteLine(e.InnerException?.StackTrace); } finally { server?.Shutdown(); } }); return(ProfilerTestRunner.Run(profileePath: System.Reflection.Assembly.GetExecutingAssembly().Location, testName: "ReverseStartup", profilerClsid: Guid.Empty, profileeOptions: ProfileeOptions.NoStartupAttach | ProfileeOptions.ReverseDiagnosticsMode, reverseServerName: serverName)); }
public static async Task <bool> TEST_RuntimeResumesExecutionWithCommand() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, $"{serverName}" } }, duringExecution: async(_) => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid) var message = new IpcMessage(0x04, 0x01); Logger.logger.Log($"Sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); } ); fSuccess &= await subprocessTask; return(fSuccess); }
public static async Task <bool> TEST_CanConnectServerAndClientAtSameTime() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticsMonitorAddressEnvKey, serverName }, { Utils.DiagnosticsMonitorPauseOnStartEnvKey, "0" } }, duringExecution: async(int pid) => { Task reverseTask = Task.Run(async() => { Logger.logger.Log($"Waiting for reverse connection"); Stream reverseStream = await server.AcceptAsync(); Logger.logger.Log("Got reverse connection"); IpcAdvertise advertise = IpcAdvertise.Parse(reverseStream); Logger.logger.Log(advertise.ToString()); }); Task regularTask = Task.Run(async() => { var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); using var source = new EventPipeEventSource(stream); Task readerTask = Task.Run(() => source.Process()); await Task.Delay(500); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); }); await Task.WhenAll(reverseTask, regularTask); } ); fSuccess &= await Utils.WaitTillTimeout(subprocessTask, TimeSpan.FromMinutes(1)); server.Shutdown(); return(fSuccess); }
public static async Task <bool> TEST_DisabledCommandsError() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); using var memoryStream1 = new MemoryStream(); using var memoryStream2 = new MemoryStream(); using var memoryStream3 = new MemoryStream(); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, $"{serverName}" } }, duringExecution: async(pid) => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); Logger.logger.Log($"Send profiler attach Diagnostics IPC Command"); // send profiler attach command (0x03=ProfilerCommandId, 0x01=attach commandid) var message = new IpcMessage(0x03, 0x01); Logger.logger.Log($"Sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); if (response.Header.CommandSet != 0xFF && response.Header.CommandId != 0xFF) { throw new Exception("Command did not fail!"); } stream = await server.AcceptAsync(); advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command"); // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid) message = new IpcMessage(0x04, 0x01); Logger.logger.Log($"Sent: {message.ToString()}"); response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); } ); fSuccess &= await subprocessTask; return(fSuccess); }
public static async Task <bool> TEST_CanConnectServerAndClientAtSameTime() { string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); await RunSubprocess( serverName : serverName, duringExecution : async(int pid) => { Task reverseTask = Task.Run(async() => { Logger.logger.Log($"Waiting for reverse connection"); Stream reverseStream = await server.AcceptAsync(); Logger.logger.Log("Got reverse connection"); IpcAdvertise advertise = IpcAdvertise.Parse(reverseStream); Logger.logger.Log(advertise.ToString()); }); Task regularTask = Task.Run(async() => { var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); using var source = new EventPipeEventSource(stream); Task readerTask = Task.Run(() => source.Process()); await Task.Delay(500); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); }); await Task.WhenAll(reverseTask, regularTask); } ); server.Shutdown(); return(true); }
public static async Task <bool> TEST_AdvertiseAndProcessInfoCookiesMatch() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); using var memoryStream = new MemoryStream(); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, $"{serverName},nosuspend" } }, duringExecution: async(pid) => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); Logger.logger.Log($"Send ProcessInfo Diagnostics IPC Command"); // send ProcessInfo command (0x04=ProcessCommandSet, 0x00=ProcessInfo commandid) var message = new IpcMessage(0x04, 0x00); Logger.logger.Log($"Sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); ProcessInfo info = ProcessInfo.TryParse(response.Payload); Logger.logger.Log($"ProcessInfo: {{ id={info.ProcessId}, cookie={info.RuntimeCookie}, cmdline={info.Commandline}, OS={info.OS}, arch={info.Arch} }}"); Utils.Assert(info.RuntimeCookie.Equals(advertise.RuntimeInstanceCookie), $"The runtime cookie reported by ProcessInfo and Advertise must match. ProcessInfo: {info.RuntimeCookie.ToString()}, Advertise: {advertise.RuntimeInstanceCookie.ToString()}"); Logger.logger.Log($"ProcessInfo and Advertise Cookies are equal"); } ); fSuccess &= await subprocessTask; return(fSuccess); }
public static async Task <bool> TEST_MultipleConnectPortsSuspend() { bool fSuccess = true; var serverAndNames = new List <(ReverseServer, string)>(); string dotnetDiagnosticPorts = ""; for (int i = 0; i < s_NumberOfPorts; i++) { string serverName = ReverseServer.MakeServerAddress(); var server = new ReverseServer(serverName); Logger.logger.Log($"Server {i} address is '{serverName}'"); serverAndNames.Add((server, serverName)); dotnetDiagnosticPorts += $"{serverName};"; } Logger.logger.Log($"export DOTNET_DiagnosticPorts={dotnetDiagnosticPorts}"); var advertisements = new List <IpcAdvertise>(); Object sync = new Object(); int subprocessId = -1; Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, dotnetDiagnosticPorts } }, duringExecution: async(int pid) => { subprocessId = pid; // Create an eventpipe session that will tell us when // the EEStartupStarted event happens. This will tell us // the the runtime has been resumed. This should only happen // AFTER all suspend ports have sent the resume command. var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose), // workaround for https://github.com/dotnet/runtime/issues/44072 which happens because the // above provider only sends 2 events and that can cause EventPipeEventSource (from TraceEvent) // to not dispatch the events if the EventBlock is a size not divisible by 8 (the reading alignment in TraceEvent). // Adding this provider keeps data flowing over the pipe so the reader doesn't get stuck waiting for data // that won't come otherwise. new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); var mre = new ManualResetEvent(false); Task readerTask = Task.Run(async() => { Logger.logger.Log($"Creating EventPipeEventSource"); using var source = new EventPipeEventSource(eventStream); var parser = new ClrPrivateTraceEventParser(source); parser.StartupEEStartupStart += (eventData) => mre.Set(); Logger.logger.Log($"Created EventPipeEventSource"); Logger.logger.Log($"Starting processing"); await Task.Run(() => source.Process()); Logger.logger.Log($"Finished processing"); }); for (int i = 0; i < s_NumberOfPorts; i++) { fSuccess &= !mre.WaitOne(0); Logger.logger.Log($"Runtime HAS NOT resumed (expects: true): {fSuccess}"); var(server, _) = serverAndNames[i]; int serverIndex = i; Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); lock (sync) advertisements.Add(advertise); Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}"); // send resume command on this connection var message = new IpcMessage(0x04, 0x01); Logger.logger.Log($"Port {serverIndex} sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"Port {serverIndex} received: {response.ToString()}"); } Logger.logger.Log($"Waiting on EEStartupStarted event"); mre.WaitOne(); Logger.logger.Log($"Saw EEStartupStarted Event"); Logger.logger.Log($"Stopping EventPipeSession"); EventPipeClient.StopTracing(pid, sessionId); await readerTask; Logger.logger.Log($"Stopped EventPipeSession"); // runtime should have resumed now fSuccess &= mre.WaitOne(0); Logger.logger.Log($"Runtime HAS resumed (expects: true): {fSuccess}"); } ); fSuccess &= await subprocessTask; foreach (var(server, _) in serverAndNames) { server.Shutdown(); } if (advertisements.Count() > 0) { Guid referenceCookie = advertisements[0].RuntimeInstanceCookie; foreach (var adv in advertisements) { fSuccess &= (int)adv.ProcessId == subprocessId; fSuccess &= adv.RuntimeInstanceCookie.Equals(referenceCookie); } } else { fSuccess &= false; } return(fSuccess); }
public static async Task <bool> TEST_ConfigValidation() { // load the env var with good and bad configs. Operation of good configs shouldn't be impeded by bad ones. // This test assumes all good configs have a server at the other end of the specified path. // Note that while a bad config might not crash the application, it may still degrade the process, e.g., // a bad configuration that specifies at least a path, will most likely still be built and consume resources polling // for a server that won't exist. bool fSuccess = true; var serverAndNames = new List <(ReverseServer, string)>(); string dotnetDiagnosticPorts = ""; // TODO: Make sure these don't hang the test when the default is suspend dotnetDiagnosticPorts += ";;;;;;"; // empty configs shouldn't cause a crash dotnetDiagnosticPorts += " ; ; ; ; ; ; ; ; ;"; // whitespace only configs shouldn't cause a crash dotnetDiagnosticPorts += " , , , , , ,;,,,,,;;"; // whitespace configs and empty tags with no path shouldn't cause a crash dotnetDiagnosticPorts += "connect,connect,connect,nosuspend,nosuspend,nosuspend,,,;"; // path that is the same as a tag name and duplicate tags shouldn't cause a crash dotnetDiagnosticPorts += "SomeRandomPath,nosuspend,suspend,suspend,suspend,suspend;"; // only the first tag from a pair is respected (this should result in a nosuspend port) dotnetDiagnosticPorts += "%%bad_Path^* fasdf----##2~~,bad tag$$@#@%_)*)@!#(&%.>, , , , ,nosuspend,:::;"; // invalid path chars and tag chars won't cause a crash for (int i = 0; i < s_NumberOfPorts; i++) { string serverName = ReverseServer.MakeServerAddress(); var server = new ReverseServer(serverName); Logger.logger.Log($"Server {i} address is '{serverName}'"); serverAndNames.Add((server, serverName)); dotnetDiagnosticPorts += $"{serverName},nosuspend;"; dotnetDiagnosticPorts += $"{serverName},nosuspend;"; // duplicating port configs shouldn't cause issues } Logger.logger.Log($"export DOTNET_DiagnosticPorts={dotnetDiagnosticPorts}"); var advertisements = new List <IpcAdvertise>(); Object sync = new Object(); int subprocessId = -1; Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, dotnetDiagnosticPorts } }, duringExecution: async(int pid) => { subprocessId = pid; var tasks = new List <Task>(); for (int i = 0; i < s_NumberOfPorts; i++) { var(server, _) = serverAndNames[i]; int serverIndex = i; tasks.Add(Task.Run(async() => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); lock (sync) advertisements.Add(advertise); Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}"); })); } await Task.WhenAll(tasks); } ); fSuccess &= await subprocessTask; foreach (var(server, _) in serverAndNames) { server.Shutdown(); } Guid referenceCookie = advertisements[0].RuntimeInstanceCookie; foreach (var adv in advertisements) { fSuccess &= (int)adv.ProcessId == subprocessId; fSuccess &= adv.RuntimeInstanceCookie.Equals(referenceCookie); } return(fSuccess); }
public static async Task <bool> TEST_MultipleConnectPortsNoSuspend() { bool fSuccess = true; var serverAndNames = new List <(ReverseServer, string)>(); string dotnetDiagnosticPorts = ""; for (int i = 0; i < s_NumberOfPorts; i++) { string serverName = ReverseServer.MakeServerAddress(); var server = new ReverseServer(serverName); Logger.logger.Log($"Server {i} address is '{serverName}'"); serverAndNames.Add((server, serverName)); dotnetDiagnosticPorts += $"{serverName},nosuspend;"; } Logger.logger.Log($"export DOTNET_DiagnosticPorts={dotnetDiagnosticPorts}"); var advertisements = new List <IpcAdvertise>(); Object sync = new Object(); int subprocessId = -1; Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, dotnetDiagnosticPorts } }, duringExecution: async(int pid) => { subprocessId = pid; var tasks = new List <Task>(); for (int i = 0; i < s_NumberOfPorts; i++) { var(server, _) = serverAndNames[i]; int serverIndex = i; tasks.Add(Task.Run(async() => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); lock (sync) advertisements.Add(advertise); Logger.logger.Log($"Server {serverIndex} got advertise {advertise.ToString()}"); })); } await Task.WhenAll(tasks); } ); fSuccess &= await subprocessTask; foreach (var(server, _) in serverAndNames) { server.Shutdown(); } Guid referenceCookie = advertisements[0].RuntimeInstanceCookie; foreach (var adv in advertisements) { fSuccess &= (int)adv.ProcessId == subprocessId; fSuccess &= adv.RuntimeInstanceCookie.Equals(referenceCookie); } return(fSuccess); }
public static async Task <bool> TEST_ProcessInfoBeforeAndAfterSuspension() { // This test only applies to platforms where the PAL is used if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return(true); } // This test only applies to CoreCLR (this checks if we're running on Mono) if (Type.GetType("Mono.RuntimeStructs") != null) { return(true); } bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); using var memoryStream1 = new MemoryStream(); using var memoryStream2 = new MemoryStream(); using var memoryStream3 = new MemoryStream(); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, $"{serverName}" } }, duringExecution: async(pid) => { Process currentProcess = Process.GetCurrentProcess(); Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); Logger.logger.Log($"Get ProcessInfo while process is suspended"); // 0x04 = ProcessCommandSet, 0x04 = ProcessInfo2 var message = new IpcMessage(0x04, 0x04); Logger.logger.Log($"Sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); ProcessInfo2 pi2Before = ProcessInfo2.TryParse(response.Payload); Utils.Assert(pi2Before.Commandline.Equals(currentProcess.MainModule.FileName), $"Before resuming, the commandline should be the mock value of the host executable path '{currentProcess.MainModule.FileName}'. Observed: '{pi2Before.Commandline}'"); // recycle stream = await server.AcceptAsync(); advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); // Start EP session to know when runtime is resumed var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose), new Provider("Microsoft-DotNETCore-SampleProfiler") }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream = EventPipeClient.CollectTracing(pid, config, out var sessionId); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); TaskCompletionSource <bool> runtimeResumed = new(false, TaskCreationOptions.RunContinuationsAsynchronously); var eventPipeTask = Task.Run(() => { Logger.logger.Log("Creating source"); using var source = new EventPipeEventSource(eventStream); var parser = new ClrPrivateTraceEventParser(source); parser.StartupEEStartupStart += (_) => runtimeResumed.SetResult(true); source.Process(); Logger.logger.Log("stopping processing"); }); Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command"); // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid) message = new IpcMessage(0x04, 0x01); Logger.logger.Log($"Sent: {message.ToString()}"); response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); // recycle stream = await server.AcceptAsync(); advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); // wait a little bit to make sure the runtime of the target is fully up, i.e., g_EEStarted == true // on resource constrained CI machines this may not be instantaneous Logger.logger.Log($"awaiting resume"); await Utils.WaitTillTimeout(runtimeResumed.Task, TimeSpan.FromSeconds(10)); Logger.logger.Log($"resumed"); // await Task.Delay(TimeSpan.FromSeconds(1)); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId); Logger.logger.Log($"Await reader task"); await eventPipeTask; Logger.logger.Log("Stopped EventPipeSession over standard connection"); ProcessInfo2 pi2After = default; // The timing is not exact. There is a small window after resuming where the mock // value is still present. Retry several times to catch it. var retryTask = Task.Run(async() => { int i = 0; do { Logger.logger.Log($"Get ProcessInfo after resumption: attempt {i++}"); // 0x04 = ProcessCommandSet, 0x04 = ProcessInfo2 message = new IpcMessage(0x04, 0x04); Logger.logger.Log($"Sent: {message.ToString()}"); response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); pi2After = ProcessInfo2.TryParse(response.Payload); // recycle stream = await server.AcceptAsync(); advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); } while (pi2After.Commandline.Equals(pi2Before.Commandline)); }); await Utils.WaitTillTimeout(retryTask, TimeSpan.FromSeconds(10)); Utils.Assert(!pi2After.Commandline.Equals(pi2Before.Commandline), $"After resuming, the commandline should be the correct value. Observed: Before='{pi2Before.Commandline}' After='{pi2After.Commandline}'"); } ); fSuccess &= await subprocessTask; return(fSuccess); }
public static async Task <bool> TEST_CanStartAndStopSessionWhilepaused() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); using var memoryStream1 = new MemoryStream(); using var memoryStream2 = new MemoryStream(); using var memoryStream3 = new MemoryStream(); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticPortsEnvKey, $"{serverName}" } }, duringExecution: async(pid) => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-Windows-DotNETRuntime", UInt64.MaxValue, EventLevel.Verbose) }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream1 = EventPipeClient.CollectTracing(pid, config, out var sessionId1); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId1:x}"); Task readerTask1 = eventStream1.CopyToAsync(memoryStream1); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream2 = EventPipeClient.CollectTracing(pid, config, out var sessionId2); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId2:x}"); Task readerTask2 = eventStream2.CopyToAsync(memoryStream2); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream3 = EventPipeClient.CollectTracing(pid, config, out var sessionId3); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId3:x}"); Task readerTask3 = eventStream3.CopyToAsync(memoryStream3); await Task.Delay(TimeSpan.FromSeconds(1)); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId1); EventPipeClient.StopTracing(pid, sessionId2); EventPipeClient.StopTracing(pid, sessionId3); await readerTask1; await readerTask2; await readerTask3; Logger.logger.Log("Stopped EventPipeSession over standard connection"); Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command"); // send ResumeRuntime command (0x04=ProcessCommandSet, 0x01=ResumeRuntime commandid) var message = new IpcMessage(0x04, 0x01); Logger.logger.Log($"Sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); } ); fSuccess &= await subprocessTask; return(fSuccess); }
public static async Task <bool> TEST_MultipleSessionsCanBeStartedWhilepaused() { bool fSuccess = true; string serverName = ReverseServer.MakeServerAddress(); Logger.logger.Log($"Server name is '{serverName}'"); var server = new ReverseServer(serverName); using var memoryStream1 = new MemoryStream(); using var memoryStream2 = new MemoryStream(); using var memoryStream3 = new MemoryStream(); Task <bool> subprocessTask = Utils.RunSubprocess( currentAssembly: Assembly.GetExecutingAssembly(), environment: new Dictionary <string, string> { { Utils.DiagnosticsMonitorAddressEnvKey, serverName } }, duringExecution: async(pid) => { Stream stream = await server.AcceptAsync(); IpcAdvertise advertise = IpcAdvertise.Parse(stream); Logger.logger.Log(advertise.ToString()); var config = new SessionConfiguration( circularBufferSizeMB: 1000, format: EventPipeSerializationFormat.NetTrace, providers: new List <Provider> { new Provider("Microsoft-Windows-DotNETRuntimePrivate", 0x80000000, EventLevel.Verbose) }); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream1 = EventPipeClient.CollectTracing(pid, config, out var sessionId1); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId1:x}"); Task readerTask1 = eventStream1.CopyToAsync(memoryStream1); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream2 = EventPipeClient.CollectTracing(pid, config, out var sessionId2); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId2:x}"); Task readerTask2 = eventStream2.CopyToAsync(memoryStream2); Logger.logger.Log("Starting EventPipeSession over standard connection"); using Stream eventStream3 = EventPipeClient.CollectTracing(pid, config, out var sessionId3); Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId3:x}"); Task readerTask3 = eventStream3.CopyToAsync(memoryStream3); Logger.logger.Log($"Send ResumeRuntime Diagnostics IPC Command"); // send ResumeRuntime command (0xFF=ServerCommandSet, 0x01=ResumeRuntime commandid) var message = new IpcMessage(0xFF, 0x01); Logger.logger.Log($"Sent: {message.ToString()}"); IpcMessage response = IpcClient.SendMessage(stream, message); Logger.logger.Log($"received: {response.ToString()}"); await Task.Delay(TimeSpan.FromSeconds(2)); Logger.logger.Log("Stopping EventPipeSession over standard connection"); EventPipeClient.StopTracing(pid, sessionId1); EventPipeClient.StopTracing(pid, sessionId2); EventPipeClient.StopTracing(pid, sessionId3); await readerTask1; await readerTask2; await readerTask3; Logger.logger.Log("Stopped EventPipeSession over standard connection"); } ); fSuccess &= await Utils.WaitTillTimeout(subprocessTask, TimeSpan.FromMinutes(1)); int nStartupEventsSeen = 0; memoryStream1.Seek(0, SeekOrigin.Begin); using (var source = new EventPipeEventSource(memoryStream1)) { var parser = new ClrPrivateTraceEventParser(source); parser.StartupEEStartupStart += (eventData) => nStartupEventsSeen++; source.Process(); } memoryStream2.Seek(0, SeekOrigin.Begin); using (var source = new EventPipeEventSource(memoryStream2)) { var parser = new ClrPrivateTraceEventParser(source); parser.StartupEEStartupStart += (eventData) => nStartupEventsSeen++; source.Process(); } memoryStream3.Seek(0, SeekOrigin.Begin); using (var source = new EventPipeEventSource(memoryStream3)) { var parser = new ClrPrivateTraceEventParser(source); parser.StartupEEStartupStart += (eventData) => nStartupEventsSeen++; source.Process(); } Logger.logger.Log($"nStartupEventsSeen: {nStartupEventsSeen}"); return(nStartupEventsSeen == 3 && fSuccess); }