Example #1
0
        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);
        }
Example #2
0
        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));
        }
Example #3
0
        public static async Task <bool> TEST_RuntimeConnectsToExistingServer()
        {
            bool   fSuccess   = true;
            string serverName = ReverseServer.MakeServerAddress();
            Task <IpcAdvertise> advertiseTask = ReverseServer.CreateServerAndReceiveAdvertisement(serverName);

            Logger.logger.Log($"Server name is `{serverName}`");
            Task <bool> subprocessTask = Utils.RunSubprocess(
                currentAssembly: Assembly.GetExecutingAssembly(),
                environment: new Dictionary <string, string>
            {
                { Utils.DiagnosticsMonitorAddressEnvKey, serverName },
                { Utils.DiagnosticsMonitorPauseOnStartEnvKey, "0" }
            },
                duringExecution: async(_) =>
            {
                IpcAdvertise advertise = await advertiseTask;
                Logger.logger.Log(advertise.ToString());
            }
                );

            fSuccess &= await subprocessTask;

            return(fSuccess);
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        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);
        }
Example #7
0
        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);
        }
Example #8
0
        public static async Task <bool> TEST_RuntimeConnectsToExistingServer()
        {
            string serverName = ReverseServer.MakeServerAddress();
            Task <IpcAdvertise> advertiseTask = ReverseServer.CreateServerAndReceiveAdvertisement(serverName);

            Logger.logger.Log($"Server name is `{serverName}`");
            await RunSubprocess(
                serverName : serverName,
                duringExecution : async(_) =>
            {
                IpcAdvertise advertise = await WaitTillTimeout(advertiseTask, TimeSpan.FromMilliseconds(_maxPollTimeMS));
                Logger.logger.Log(advertise.ToString());
            }
                );

            return(true);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
        }
Example #11
0
        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);
        }
Example #12
0
        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);
        }
Example #13
0
        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);
        }
Example #14
0
        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);
        }
Example #15
0
        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);
        }