EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-counters", "src\Tools\dotnet-counters\dotnet-counters.csproj", "{2A9B5988-982F-4E26-9E44-D38AC5978C30}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Tools.RuntimeClient", "src\Microsoft.Diagnostics.Tools.RuntimeClient\Microsoft.Diagnostics.Tools.RuntimeClient.csproj", "{54C240C5-7932-4421-A5FB-75205DE0B824}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SOS.Package", "src\SOS\SOS.Package\SOS.Package.csproj", "{234416E9-EA5F-4018-AC34-67682C5D3E04}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.DebugServices", "src\Microsoft.Diagnostics.DebugServices\Microsoft.Diagnostics.DebugServices.csproj", "{A1CE682A-12C4-4FF9-B864-A9A15A8726D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.NETCore.Client.UnitTests", "src\tests\Microsoft.Diagnostics.NETCore.Client\Microsoft.Diagnostics.NETCore.Client.UnitTests.csproj", "{6F4DD2F8-1C7B-4A87-B7E5-1BEE9F5AC128}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tracee", "src\tests\Tracee\Tracee.csproj", "{C79D6069-2C18-48CB-846E-71F7168C2F7D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tracee", "src\tests\Tracee\Tracee.csproj", "{C79D6069-2C18-48CB-846E-71F7168C2F7D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventPipe.UnitTests", "src\tests\eventpipe\EventPipe.UnitTests.csproj", "{CED9ABBA-861E-4C0A-9359-22351208EF27}"
EndProject
{2A9B5988-982F-4E26-9E44-D38AC5978C30}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{2A9B5988-982F-4E26-9E44-D38AC5978C30}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
{2A9B5988-982F-4E26-9E44-D38AC5978C30}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|Any CPU.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|Any CPU.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|ARM.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|ARM.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|ARM64.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|ARM64.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|x64.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|x64.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|x86.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Checked|x86.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|ARM.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|ARM64.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|ARM64.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|x64.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|x64.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|x86.ActiveCfg = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Debug|x86.Build.0 = Debug|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|Any CPU.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|ARM.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|ARM.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|ARM64.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|ARM64.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|x64.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|x64.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|x86.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.Release|x86.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|ARM.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|ARM.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|ARM64.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|ARM64.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
- {54C240C5-7932-4421-A5FB-75205DE0B824}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
{234416E9-EA5F-4018-AC34-67682C5D3E04}.Checked|Any CPU.ActiveCfg = Debug|Any CPU
{234416E9-EA5F-4018-AC34-67682C5D3E04}.Checked|Any CPU.Build.0 = Debug|Any CPU
{234416E9-EA5F-4018-AC34-67682C5D3E04}.Checked|ARM.ActiveCfg = Debug|Any CPU
{ED27F39F-DF5C-4E22-87E0-EC5B5873B503} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
{90CF2633-58F0-44EE-943B-D70207455F20} = {19FAB78C-3351-4911-8F0C-8C6056401740}
{2A9B5988-982F-4E26-9E44-D38AC5978C30} = {B62728C8-1267-4043-B46F-5537BBAEC692}
- {54C240C5-7932-4421-A5FB-75205DE0B824} = {19FAB78C-3351-4911-8F0C-8C6056401740}
{234416E9-EA5F-4018-AC34-67682C5D3E04} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
{A1CE682A-12C4-4FF9-B864-A9A15A8726D2} = {19FAB78C-3351-4911-8F0C-8C6056401740}
{410394E0-7F4F-42D5-B5FA-30956F44ACBC} = {41638A4C-0DAF-47ED-A774-ECBBAC0315D7}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Diagnostics.Tools.RuntimeClient.DiagnosticsIpc;
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.InteropServices;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient
-{
- public static class DiagnosticsHelpers
- {
- /// <summary>
- /// Controls the contents of the dump
- /// </summary>
- public enum DumpType : uint
- {
- Normal = 1,
- WithHeap = 2,
- Triage = 3,
- Full = 4
- }
-
- /// <summary>
- /// Initiate a core dump in the target process runtime.
- /// </summary>
- /// <param name="processId">.NET Core process id</param>
- /// <param name="dumpName">Path and file name of core dump</param>
- /// <param name="dumpType">Type of dump</param>
- /// <param name="diagnostics">If true, log to console the dump generation diagnostics</param>
- /// <returns>DiagnosticsServerErrorCode</returns>
- public static int GenerateCoreDump(int processId, string dumpName, DumpType dumpType, bool diagnostics)
- {
- if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
- throw new PlatformNotSupportedException($"Unsupported operating system: {RuntimeInformation.OSDescription}");
-
- if (string.IsNullOrEmpty(dumpName))
- throw new ArgumentNullException($"{nameof(dumpName)} required");
-
-
- var payload = SerializeCoreDump(dumpName, dumpType, diagnostics);
- var message = new IpcMessage(DiagnosticsServerCommandSet.Dump, (byte)DumpCommandId.GenerateCoreDump, payload);
-
- var response = IpcClient.SendMessage(processId, message);
-
- var hr = 0;
- switch ((DiagnosticsServerCommandId)response.Header.CommandId)
- {
- case DiagnosticsServerCommandId.Error:
- case DiagnosticsServerCommandId.OK:
- hr = BitConverter.ToInt32(response.Payload, 0);
- break;
- default:
- return -1;
- }
-
- return hr;
- }
-
- /// <summary>
- /// Attach a profiler to the target process runtime.
- /// </summary>
- /// <param name="processId">.NET Core process id</param>
- /// <param name="attachTimeout">The timeout (in ms) for the runtime to wait while attempting to attach.</param>
- /// <param name="profilerGuid">CLSID of the profiler to load</param>
- /// <param name="profilerPath">Path to the profiler library on disk</param>
- /// <param name="additionalData">additional data to pass to the profiler on attach</param>
- /// <returns>HRESULT</returns>
- public static int AttachProfiler(int processId, uint attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData)
- {
- if (profilerGuid == null || profilerGuid == Guid.Empty)
- {
- throw new ArgumentException($"{nameof(profilerGuid)} must be a valid Guid");
- }
-
- if (String.IsNullOrEmpty(profilerPath))
- {
- throw new ArgumentException($"{nameof(profilerPath)} must be non-null");
- }
-
- var header = new MessageHeader {
- RequestType = DiagnosticsMessageType.AttachProfiler,
- Pid = (uint)Process.GetCurrentProcess().Id,
- };
-
- byte[] serializedConfiguration = SerializeProfilerAttach(attachTimeout, profilerGuid, profilerPath, additionalData);
- var message = new IpcMessage(DiagnosticsServerCommandSet.Profiler, (byte)ProfilerCommandId.AttachProfiler, serializedConfiguration);
-
- var response = IpcClient.SendMessage(processId, message);
-
- var hr = 0;
- switch ((DiagnosticsServerCommandId)response.Header.CommandId)
- {
- case DiagnosticsServerCommandId.Error:
- case DiagnosticsServerCommandId.OK:
- hr = BitConverter.ToInt32(response.Payload, 0);
- break;
- default:
- hr = -1;
- break;
- }
-
- // TODO: the call to set up the pipe and send the message operates on a different timeout than attachTimeout, which is for the runtime.
- // We should eventually have a configurable timeout for the message passing, potentially either separately from the
- // runtime timeout or respect attachTimeout as one total duration.
- return hr;
- }
-
- private static byte[] SerializeProfilerAttach(uint attachTimeout, Guid profilerGuid, string profilerPath, byte[] additionalData)
- {
- using (var stream = new MemoryStream())
- using (var writer = new BinaryWriter(stream))
- {
- writer.Write(attachTimeout);
- writer.Write(profilerGuid.ToByteArray());
- writer.WriteString(profilerPath);
-
- if (additionalData == null)
- {
- writer.Write(0);
- }
- else
- {
- writer.Write(additionalData.Length);
- writer.Write(additionalData);
- }
-
- writer.Flush();
- return stream.ToArray();
- }
- }
-
- private static byte[] SerializeCoreDump(string dumpName, DumpType dumpType, bool diagnostics)
- {
- using (var stream = new MemoryStream())
- using (var writer = new BinaryWriter(stream))
- {
- writer.WriteString(dumpName);
- writer.Write((uint)dumpType);
- writer.Write((uint)(diagnostics ? 1 : 0));
-
- writer.Flush();
- return stream.ToArray();
- }
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.IO.Pipes;
-using System.Linq;
-using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Security.Principal;
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient.DiagnosticsIpc
-{
- public class IpcClient
- {
- private static string DiagnosticsPortPattern { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"^dotnet-diagnostic-(\d+)$" : @"^dotnet-diagnostic-(\d+)-(\d+)-socket$";
-
- private static string IpcRootPath { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"\\.\pipe\" : Path.GetTempPath();
-
- private static double ConnectTimeoutMilliseconds { get; } = TimeSpan.FromSeconds(3).TotalMilliseconds;
-
- /// <summary>
- /// Get the OS Transport to be used for communicating with a dotnet process.
- /// </summary>
- /// <param name="processId">The PID of the dotnet process to get the transport for</param>
- /// <returns>A System.IO.Stream wrapper around the transport</returns>
- private static Stream GetTransport(int processId)
- {
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- string pipeName = $"dotnet-diagnostic-{processId}";
- var namedPipe = new NamedPipeClientStream(
- ".", pipeName, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation);
- namedPipe.Connect((int)ConnectTimeoutMilliseconds);
- return namedPipe;
- }
- else
- {
- string ipcPort = Directory.GetFiles(IpcRootPath) // Try best match.
- .Select(namedPipe => (new FileInfo(namedPipe)).Name)
- .SingleOrDefault(input => Regex.IsMatch(input, $"^dotnet-diagnostic-{processId}-(\\d+)-socket$"));
- if (ipcPort == null)
- {
- throw new PlatformNotSupportedException($"Process {processId} not running compatible .NET Core runtime");
- }
- string path = Path.Combine(Path.GetTempPath(), ipcPort);
- var remoteEP = new UnixDomainSocketEndPoint(path);
-
- var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
- socket.Connect(remoteEP);
- return new NetworkStream(socket);
- }
- }
-
- /// <summary>
- /// Sends a single DiagnosticsIpc Message to the dotnet process with PID processId.
- /// </summary>
- /// <param name="processId">The PID of the dotnet process</param>
- /// <param name="message">The DiagnosticsIpc Message to be sent</param>
- /// <returns>The response DiagnosticsIpc Message from the dotnet process</returns>
- public static IpcMessage SendMessage(int processId, IpcMessage message)
- {
- using (var stream = GetTransport(processId))
- {
- Write(stream, message);
- return Read(stream);
- }
- }
-
- /// <summary>
- /// Sends a single DiagnosticsIpc Message to the dotnet process with PID processId
- /// and returns the Stream for reuse in Optional Continuations.
- /// </summary>
- /// <param name="processId">The PID of the dotnet process</param>
- /// <param name="message">The DiagnosticsIpc Message to be sent</param>
- /// <param name="response">out var for response message</param>
- /// <returns>The response DiagnosticsIpc Message from the dotnet process</returns>
- public static Stream SendMessage(int processId, IpcMessage message, out IpcMessage response)
- {
- var stream = GetTransport(processId);
- Write(stream, message);
- response = Read(stream);
- return stream;
- }
-
- private static void Write(Stream stream, byte[] buffer)
- {
- using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
- {
- writer.Write(buffer);
- }
- }
-
- private static void Write(Stream stream, IpcMessage message)
- {
- using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
- {
- writer.Write(message.Serialize());
- }
- }
-
-
- private static IpcMessage Read(Stream stream)
- {
- return IpcMessage.Parse(stream);
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient.DiagnosticsIpc
-{
- public enum DiagnosticsServerCommandSet : byte
- {
- Dump = 0x01,
- EventPipe = 0x02,
- Profiler = 0x03,
-
- Server = 0xFF,
- }
-
- public enum DiagnosticsServerCommandId : byte
- {
- OK = 0x00,
- Error = 0xFF,
- }
-
- public enum EventPipeCommandId : byte
- {
- StopTracing = 0x01,
- CollectTracing = 0x02,
- CollectTracing2 = 0x03,
- }
-
- public enum DumpCommandId : byte
- {
- GenerateCoreDump = 0x01,
- }
-
- public enum ProfilerCommandId : byte
- {
- AttachProfiler = 0x01,
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient.DiagnosticsIpc
-{
- public class IpcHeader
- {
- IpcHeader() { }
-
- public IpcHeader(DiagnosticsServerCommandSet commandSet, byte commandId)
- {
- CommandSet = (byte)commandSet;
- CommandId = commandId;
- }
-
- // the number of bytes for the DiagnosticsIpc::IpcHeader type in native code
- public static readonly UInt16 HeaderSizeInBytes = 20;
- private static readonly UInt16 MagicSizeInBytes = 14;
-
- public byte[] Magic = ASCIIEncoding.ASCII.GetBytes("DOTNET_IPC_V1" + '\0'); // byte[14] in native code
- public UInt16 Size = HeaderSizeInBytes;
- public byte CommandSet;
- public byte CommandId;
- public UInt16 Reserved = 0x0000;
-
-
- // Helper expression to quickly get V1 magic string for comparison
- // should be 14 bytes long
- public static byte[] DOTNET_IPC_V1 => ASCIIEncoding.ASCII.GetBytes("DOTNET_IPC_V1" + '\0');
-
- public byte[] Serialize()
- {
- using (var stream = new MemoryStream())
- using (var writer = new BinaryWriter(stream))
- {
- writer.Write(Magic);
- Debug.Assert(Magic.Length == MagicSizeInBytes);
- writer.Write(Size);
- writer.Write(CommandSet);
- writer.Write(CommandId);
- writer.Write((UInt16)0x0000);
- writer.Flush();
- return stream.ToArray();
- }
- }
-
- public static IpcHeader TryParse(BinaryReader reader)
- {
- IpcHeader header = new IpcHeader
- {
- Magic = reader.ReadBytes(14),
- Size = reader.ReadUInt16(),
- CommandSet = reader.ReadByte(),
- CommandId = reader.ReadByte(),
- Reserved = reader.ReadUInt16()
- };
-
- // TODO: Validate it is correct!
-
- return header;
- }
-
- override public string ToString()
- {
- return $"{{ Magic={Magic}; Size={Size}; CommandSet={CommandSet}; CommandId={CommandId}; Reserved={Reserved} }}";
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient.DiagnosticsIpc
-{
- public class IpcMessage
- {
- public IpcMessage()
- { }
-
- public IpcMessage(IpcHeader header, byte[] payload)
- {
- Payload = payload;
- Header = header;
- }
-
- internal IpcMessage(DiagnosticsServerCommandSet commandSet, byte commandId, byte[] payload = null)
- {
- Header = new IpcHeader(commandSet, commandId);
- Payload = payload;
- }
-
- public byte[] Payload { get; private set; } = null;
- public IpcHeader Header { get; private set; } = default;
-
- public byte[] Serialize()
- {
- byte[] serializedData = null;
- // Verify things will fit in the size capacity
- Header.Size = checked((UInt16)(IpcHeader.HeaderSizeInBytes + Payload.Length)); ;
- byte[] headerBytes = Header.Serialize();
-
- using (var stream = new MemoryStream())
- using (var writer = new BinaryWriter(stream))
- {
- writer.Write(headerBytes);
- writer.Write(Payload);
- writer.Flush();
- serializedData = stream.ToArray();
- }
-
- return serializedData;
- }
-
- public static IpcMessage Parse(Stream stream)
- {
- IpcMessage message = new IpcMessage();
- using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
- {
- message.Header = IpcHeader.TryParse(reader);
- message.Payload = reader.ReadBytes(message.Header.Size - IpcHeader.HeaderSizeInBytes);
- return message;
- }
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient
-{
- /// <summary>
- /// Different diagnostic message types that are handled by the runtime.
- /// </summary>
- public enum DiagnosticsMessageType : uint
- {
- /// <summary>
- /// Initiates core dump generation
- /// </summary>
- GenerateCoreDump = 1,
- /// <summary>
- /// Starts an EventPipe session that writes events to a file when the session is stopped or the application exits.
- /// </summary>
- StartEventPipeTracing = 1024,
- /// <summary>
- /// Stops an EventPipe session.
- /// </summary>
- StopEventPipeTracing,
- /// <summary>
- /// Starts an EventPipe session that sends events out-of-proc through IPC.
- /// </summary>
- CollectEventPipeTracing,
- /// <summary>
- /// Attaches a profiler to an existing process
- /// </summary>
- AttachProfiler = 2048,
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Diagnostics.Tools.RuntimeClient.DiagnosticsIpc;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.IO.Pipes;
-using System.Linq;
-using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Security.Principal;
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient
-{
- public enum EventPipeErrorCode : uint
- {
- BAD_ENCODING = 0x80131384,
- UNKNOWN_COMMAND = 0x80131385,
- UNKNOWN_MAGIC = 0x80131386,
- UNKNOWN_ERROR = 0x80131387
- }
-
- public class EventPipeBadEncodingException : Exception
- {
- public EventPipeBadEncodingException(string msg) : base(msg) {}
- }
- public class EventPipeUnknownCommandException : Exception
- {
- public EventPipeUnknownCommandException(string msg) : base(msg) {}
- }
-
- public class EventPipeUnknownMagicException : Exception
- {
- public EventPipeUnknownMagicException(string msg) : base(msg) {}
- }
-
- public class EventPipeUnknownErrorException : Exception
- {
- public EventPipeUnknownErrorException(string msg) : base(msg) {}
- }
-
- public static class EventPipeClient
- {
- private static string DiagnosticsPortPattern { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"^dotnet-diagnostic-(\d+)$" : @"^dotnet-diagnostic-(\d+)-(\d+)-socket$";
-
- private static string IpcRootPath { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"\\.\pipe\" : Path.GetTempPath();
-
- /// <summary>
- /// Get the files associated with the opened IPC Ports for DotNet Core applications.
- /// </summary>
- /// <returns>
- /// A collection of process identifiers associated with the list of opened files (IPC ports).
- /// These process Ids might have expired and not properly cleaned up.
- /// </returns>
- public static IEnumerable<int> ListAvailablePorts()
- {
- return Directory.GetFiles(IpcRootPath)
- .Select(namedPipe => (new FileInfo(namedPipe)).Name)
- .Where(input => Regex.IsMatch(input, DiagnosticsPortPattern))
- .Select(input => int.Parse(Regex.Match(input, DiagnosticsPortPattern).Groups[1].Value, NumberStyles.Integer));
- }
-
- /// <summary>
- /// Start trace collection.
- /// </summary>
- /// <param name="processId">Runtime process to trace</param>
- /// <param name="configuration">buffer size and provider configuration</param>
- /// <param name="sessionId">session id</param>
- /// <returns>Stream</returns>
- public static Stream CollectTracing(int processId, SessionConfiguration configuration, out ulong sessionId)
- {
- sessionId = 0;
- var message = new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.CollectTracing, configuration.Serialize());
- var stream = IpcClient.SendMessage(processId, message, out var response);
-
- switch ((DiagnosticsServerCommandId)response.Header.CommandId)
- {
- case DiagnosticsServerCommandId.OK:
- sessionId = BitConverter.ToUInt64(response.Payload, 0);
- break;
- case DiagnosticsServerCommandId.Error:
- // bad...
- var hr = BitConverter.ToInt32(response.Payload, 0);
- throw new Exception($"Session start FAILED 0x{hr:X8}");
- default:
- break;
- }
-
- return stream;
- }
-
- public static Stream CollectTracing2(int processId, SessionConfigurationV2 configuration, out ulong sessionId)
- {
- sessionId = 0;
- var message = new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.CollectTracing2, configuration.Serialize());
- var stream = IpcClient.SendMessage(processId, message, out var response);
-
- switch ((DiagnosticsServerCommandId)response.Header.CommandId)
- {
- case DiagnosticsServerCommandId.OK:
- sessionId = BitConverter.ToUInt64(response.Payload, 0);
- break;
- case DiagnosticsServerCommandId.Error:
- // bad...
- uint hr = BitConverter.ToUInt32(response.Payload, 0);
- Exception ex = ConvertHRToException(hr, $"Session start FAILED 0x{hr:X8}");
- throw ex;
- default:
- break;
- }
-
- return stream;
- }
-
- /// <summary>
- /// Turn off EventPipe logging session for the specified process Id.
- /// </summary>
- /// <param name="processId">Process Id to turn off logging session.</param>
- /// <param name="sessionId">EventPipe session Id to turn off.</param>
- /// <returns>It returns sessionId if success, otherwise 0.</returns>
- public static ulong StopTracing(int processId, ulong sessionId)
- {
- if (sessionId == 0)
- return sessionId; // TODO: Throw here instead?
-
- byte[] payload = BitConverter.GetBytes(sessionId);
-
- var response = IpcClient.SendMessage(processId, new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.StopTracing, payload));
-
- switch ((DiagnosticsServerCommandId)response.Header.CommandId)
- {
- case DiagnosticsServerCommandId.OK:
- return BitConverter.ToUInt64(response.Payload, 0);
- case DiagnosticsServerCommandId.Error:
- return 0;
- default:
- return 0;
- }
- }
-
- private static Exception ConvertHRToException(uint hr, string msg)
- {
- if (hr == (uint)EventPipeErrorCode.BAD_ENCODING)
- {
- return new EventPipeBadEncodingException(msg);
- }
- else if (hr == (uint)EventPipeErrorCode.UNKNOWN_COMMAND)
- {
- return new EventPipeUnknownCommandException(msg);
- }
- else if (hr == (uint)EventPipeErrorCode.UNKNOWN_MAGIC)
- {
- return new EventPipeUnknownMagicException(msg);
- }
- else
- {
- return new EventPipeUnknownErrorException(msg);
- }
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient
-{
- /// <summary>
- /// Defines constants for EventPipe logging sessions.
- /// </summary>
- public enum EventPipeSessionType : uint
- {
- /// <summary>
- /// The events will be written to file at the end of the session.
- /// </summary>
- TraceToFile,
-
- /// <summary>
- /// Events will be passed to the EventListener.
- /// </summary>
- CallbackListener,
-
- /// <summary>
- /// Events will be sent out-of-proc by writing them to the underlying IPC stream implementation.
- /// </summary>
- TraceToStream
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient
-{
- /// <summary>
- /// Message header used to send commands to the .NET Core runtime through IPC.
- /// </summary>
- [StructLayout(LayoutKind.Sequential)]
- public struct MessageHeader
- {
- /// <summary>
- /// Request type.
- /// </summary>
- public DiagnosticsMessageType RequestType;
-
- /// <summary>
- /// Remote process Id.
- /// </summary>
- public uint Pid;
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Diagnostics.Tracing;
-using System.Text.RegularExpressions;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient
-{
- public struct Provider
- {
- public Provider(
- string name,
- ulong keywords = ulong.MaxValue,
- EventLevel eventLevel = EventLevel.Verbose,
- string filterData = null)
- {
- if (string.IsNullOrWhiteSpace(name))
- throw new ArgumentNullException(nameof(name));
- Name = name;
- Keywords = keywords;
- EventLevel = eventLevel;
- FilterData = string.IsNullOrWhiteSpace(filterData) ? null : Regex.Unescape(filterData);
- }
-
- public ulong Keywords { get; }
-
- public EventLevel EventLevel { get; }
-
- public string Name { get; }
-
- public string FilterData { get; }
-
- public override string ToString() =>
- $"{Name}:0x{Keywords:X16}:{(uint)EventLevel}{(FilterData == null ? "" : $":{FilterData}")}";
-
- public string ToDisplayString() =>
- String.Format("{0, -40}", Name) + String.Format("0x{0, -18}", $"{Keywords:X16}") + String.Format("{0, -8}", EventLevel.ToString() + $"({(int)EventLevel})");
-
- public static bool operator ==(Provider left, Provider right)
- {
- return left.Name == right.Name &&
- left.Keywords == right.Keywords &&
- left.EventLevel == right.EventLevel &&
- left.FilterData == right.FilterData;
- }
-
- public static bool operator !=(Provider left, Provider right)
- {
- return !(left == right);
- }
-
- public override bool Equals(object obj)
- {
-
- if (obj == null || GetType() != obj.GetType())
- {
- return false;
- }
-
- return this == (Provider)obj;
- }
-
- public override int GetHashCode()
- {
- int hash = 0;
- hash ^= this.Name.GetHashCode();
- hash ^= this.Keywords.GetHashCode();
- hash ^= this.EventLevel.GetHashCode();
- hash ^= this.FilterData.GetHashCode();
- return hash;
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient
-{
- public enum EventPipeSerializationFormat
- {
- NetPerf,
- NetTrace
- }
-
- public class SessionConfiguration
- {
- public SessionConfiguration(uint circularBufferSizeMB, EventPipeSerializationFormat format, IReadOnlyCollection<Provider> providers)
- {
- if (circularBufferSizeMB == 0)
- throw new ArgumentException($"Buffer size cannot be zero.");
- if (format != EventPipeSerializationFormat.NetPerf && format != EventPipeSerializationFormat.NetTrace)
- throw new ArgumentException("Unrecognized format");
- if (providers == null)
- throw new ArgumentNullException(nameof(providers));
- if (providers.Count() <= 0)
- throw new ArgumentException($"Specified providers collection is empty.");
-
- CircularBufferSizeInMB = circularBufferSizeMB;
- Format = format;
- string extension = format == EventPipeSerializationFormat.NetPerf ? ".netperf" : ".nettrace";
- _providers = new List<Provider>(providers);
- }
-
- public uint CircularBufferSizeInMB { get; }
- public EventPipeSerializationFormat Format { get; }
-
- public IReadOnlyCollection<Provider> Providers => _providers.AsReadOnly();
-
- private readonly List<Provider> _providers;
-
- public virtual byte[] Serialize()
- {
- byte[] serializedData = null;
- using (var stream = new MemoryStream())
- using (var writer = new BinaryWriter(stream))
- {
- writer.Write(CircularBufferSizeInMB);
- writer.Write((uint)Format);
-
- writer.Write(Providers.Count());
- foreach (var provider in Providers)
- {
- writer.Write(provider.Keywords);
- writer.Write((uint)provider.EventLevel);
-
- writer.WriteString(provider.Name);
- writer.WriteString(provider.FilterData);
- }
-
- writer.Flush();
- serializedData = stream.ToArray();
- }
-
- return serializedData;
- }
- }
-
- public class SessionConfigurationV2 : SessionConfiguration
- {
- public SessionConfigurationV2(uint circularBufferSizeMB, EventPipeSerializationFormat format, bool requestRundown, IReadOnlyCollection<Provider> providers) : base(circularBufferSizeMB, format, providers)
- {
- RequestRundown = requestRundown;
- }
-
- public bool RequestRundown { get; }
-
- public override byte[] Serialize()
- {
- byte[] serializedData = null;
- using (var stream = new MemoryStream())
- using (var writer = new BinaryWriter(stream))
- {
- writer.Write(CircularBufferSizeInMB);
- writer.Write((uint)Format);
- writer.Write(RequestRundown);
-
- writer.Write(Providers.Count());
- foreach (var provider in Providers)
- {
- writer.Write(provider.Keywords);
- writer.Write((uint)provider.EventLevel);
-
- writer.WriteString(provider.Name);
- writer.WriteString(provider.FilterData);
- }
-
- writer.Flush();
- serializedData = stream.ToArray();
- }
-
- return serializedData;
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient
-{
- public static class Extensions
- {
- public static void WriteString(this BinaryWriter @this, string value)
- {
- if (@this == null)
- throw new ArgumentNullException(nameof(@this));
-
- @this.Write(value != null ? (value.Length + 1) : 0);
- if (value != null)
- @this.Write(Encoding.Unicode.GetBytes(value + '\0'));
- }
-
-#if DEBUG
- private static int GetByteCount(this string @this)
- {
- if (@this == null)
- throw new ArgumentNullException(nameof(@this));
-
- var strLength = @this == null ? 0 : Encoding.Unicode.GetByteCount(@this + '\0');
- return Marshal.SizeOf(typeof(int)) + strLength;
- }
-
- public static int GetByteCount(this SessionConfiguration @this)
- {
- int size = 0;
-
- size += Marshal.SizeOf(@this.CircularBufferSizeInMB.GetType());
- size += Marshal.SizeOf(typeof(int));
-
- foreach (var provider in @this.Providers)
- {
- size += Marshal.SizeOf(provider.Keywords.GetType());
- size += Marshal.SizeOf(typeof(uint)); // provider.EventLevel.GetType()
- size += provider.Name.GetByteCount();
- size += provider.FilterData.GetByteCount();
- }
-
- return size;
- }
-#endif // DEBUG
- }
-}
+++ /dev/null
-<Project Sdk="Microsoft.NET.Sdk">
- <PropertyGroup>
- <OutputType>Library</OutputType>
- <TargetFramework>netcoreapp2.1</TargetFramework>
- <RootNamespace>Microsoft.Diagnostics.Tools.RuntimeClient</RootNamespace>
- <Description>.NET Core Diagnostics Runtime Client</Description>
- <IsPackable>true</IsPackable>
- <PackageTags>Diagnostic</PackageTags>
- <PackageReleaseNotes>$(Description)</PackageReleaseNotes>
- <GenerateDocumentationFile>true</GenerateDocumentationFile>
- <IncludeSymbols>true</IncludeSymbols>
- <IsShippingAssembly>true</IsShippingAssembly>
- </PropertyGroup>
-</Project>
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-
-namespace Tracing.Tests.Common
-{
- public static class Assert
- {
- public static void True(string name, bool condition)
- {
- if (!condition)
- {
- throw new Exception(
- string.Format("Condition '{0}' is not true", name));
- }
- }
-
- public static void Equal<T>(string name, T left, T right) where T : IEquatable<T>
- {
- if (left == null && right != null)
- {
- throw new Exception(
- string.Format("Values for '{0}' are not equal! Left=NULL Right='{1}'", name, right));
- }
- else if (left != null && right == null)
- {
- throw new Exception(
- string.Format("Values for '{0}' are not equal! Left='{1}' Right=NULL", name, left));
- }
- else if (!left.Equals(right))
- {
- throw new Exception(
- string.Format("Values for '{0}' are not equal! Left='{1}' Right='{2}'", name, left, right));
- }
- }
-
- public static void NotEqual<T>(string name, T left, T right) where T : IEquatable<T>
- {
- if (left == null && right == null)
- {
- throw new Exception(
- string.Format("Values for '{0}' are equal! Left=NULL Right=NULL", name));
- }
- else if (left != null && left.Equals(right))
- {
- throw new Exception(
- string.Format("Values for '{0}' are equal! Left='{1}' Right='{2}'", name, left, right));
- }
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Diagnostics.Tracing;
-using Microsoft.Diagnostics.Tracing.Etlx;
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Tracing.Tests.Common;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient.Tests
-{
- class Program
- {
- static int Main(string[] args)
- {
- SendSmallerHeaderCommand();
- SendInvalidDiagnosticsMessageTypeCommand();
- SendInvalidInputData();
- TestCollectEventPipeTracing();
- return 100;
- }
-
- private static Process ThisProcess { get; } = Process.GetCurrentProcess();
-
- private static void SendSmallerHeaderCommand()
- {
- Console.WriteLine("Send a small payload as header.");
-
- ulong sessionId = 0;
-
- try
- {
- byte[] bytes;
- using (var stream = new MemoryStream())
- {
- using (var bw = new BinaryWriter(stream))
- {
- bw.Write((uint)DiagnosticsMessageType.StartEventPipeTracing);
- bw.Flush();
- stream.Position = 0;
-
- bytes = new byte[stream.Length];
- stream.Read(bytes, 0, bytes.Length);
- }
- }
-
- sessionId = EventPipeClient.SendCommand(ThisProcess.Id, bytes);
- }
- catch (EndOfStreamException)
- {
- Assert.Equal("EventPipe Session Id", sessionId, (ulong)0);
- }
- catch
- {
- Assert.True("Send command threw unexpected exception", false);
- }
- }
-
- private static void SendInvalidDiagnosticsMessageTypeCommand()
- {
- Console.WriteLine("Send a wrong message type as the diagnostic header header.");
- ulong sessionId = 0;
-
- try
- {
- byte[] bytes;
- using (var stream = new MemoryStream())
- {
- using (var bw = new BinaryWriter(stream))
- {
- bw.Write(uint.MaxValue);
- bw.Write(ThisProcess.Id);
- bw.Flush();
- stream.Position = 0;
-
- bytes = new byte[stream.Length];
- stream.Read(bytes, 0, bytes.Length);
- }
- }
-
- sessionId = EventPipeClient.SendCommand(ThisProcess.Id, bytes);
- }
- catch (EndOfStreamException)
- {
- Assert.Equal("EventPipe Session Id", sessionId, (ulong)0);
- }
- catch
- {
- Assert.True("Send command threw unexpected exception", false);
- }
- }
-
- private static byte[] Serialize(MessageHeader header, TestSessionConfiguration configuration, Stream stream)
- {
- using (var bw = new BinaryWriter(stream))
- {
- bw.Write((uint)header.RequestType);
- bw.Write(header.Pid);
-
- bw.Write(configuration.CircularBufferSizeInMB);
-
- bw.WriteString(null);
-
- if (configuration.Providers == null)
- {
- bw.Write(0);
- }
- else
- {
- bw.Write(configuration.Providers.Count());
- foreach (var provider in configuration.Providers)
- {
- bw.Write(provider.Keywords);
- bw.Write((uint)provider.EventLevel);
-
- bw.WriteString(provider.Name);
- bw.WriteString(provider.FilterData);
- }
- }
-
- bw.Flush();
- stream.Position = 0;
-
- var bytes = new byte[stream.Length];
- stream.Read(bytes, 0, bytes.Length);
- return bytes;
- }
-
- }
-
- private static void SendInvalidInputData()
- {
- var configs = new TestSessionConfiguration[] {
- new TestSessionConfiguration {
- CircularBufferSizeInMB = 0,
- TestName = "0 size circular buffer",
- Providers = new TestProvider[] {
- new TestProvider{
- Name = "Microsoft-Windows-DotNETRuntime"
- },
- },
- },
- new TestSessionConfiguration {
- CircularBufferSizeInMB = 64,
- TestName = "null providers",
- Providers = null,
- },
- new TestSessionConfiguration {
- CircularBufferSizeInMB = 64,
- TestName = "no providers",
- Providers = new TestProvider[]{ },
- },
- new TestSessionConfiguration {
- CircularBufferSizeInMB = 64,
- TestName = "null provider name",
- Providers = new TestProvider[]{ new TestProvider { Name = null, }, },
- },
- new TestSessionConfiguration {
- CircularBufferSizeInMB = 64,
- TestName = "empty provider name",
- Providers = new TestProvider[]{ new TestProvider { Name = string.Empty, }, },
- },
- new TestSessionConfiguration {
- CircularBufferSizeInMB = 64,
- TestName = "white space provider name",
- Providers = new TestProvider[]{ new TestProvider { Name = " ", }, },
- },
- };
-
- foreach (var config in configs)
- {
- ulong sessionId = 0;
-
- try
- {
- var header = new MessageHeader {
- RequestType = DiagnosticsMessageType.CollectEventPipeTracing,
- Pid = (uint)Process.GetCurrentProcess().Id,
- };
-
- byte[] bytes;
- using (var stream = new MemoryStream())
- bytes = Serialize(header, config, stream);
-
- Console.WriteLine($"Test: {config.TestName}");
- sessionId = EventPipeClient.SendCommand(ThisProcess.Id, bytes);
-
- // Check that a session was created.
- Assert.Equal("EventPipe Session Id", sessionId, (ulong)0);
- }
- catch (EndOfStreamException)
- {
- Assert.Equal("EventPipe Session Id", sessionId, (ulong)0);
- }
- catch
- {
- Assert.True("Send command threw unexpected exception", false);
- }
- }
- }
-
- private static void SendInvalidPayloadToCollectCommand()
- {
- Console.WriteLine("Send Invalid Payload To Collect Command.");
-
- ulong sessionId = 0;
-
- try
- {
- uint circularBufferSizeMB = 64;
- var filePath = Path.Combine(
- Directory.GetCurrentDirectory(),
- $"dotnetcore-eventpipe-{ThisProcess.Id}.nettrace");
- var providers = new[] {
- new Provider(name: "Microsoft-Windows-DotNETRuntime"),
- };
-
- var configuration = new SessionConfiguration(circularBufferSizeMB, filePath, providers);
-
- // Start session #1.
- sessionId = EventPipeClient.StartTracingToFile(
- processId: ThisProcess.Id,
- configuration: configuration);
-
- // Check that a session was created.
- Assert.Equal("EventPipe Session Id", sessionId, (ulong)0);
- }
- finally
- {
- if (sessionId != 0)
- EventPipeClient.StopTracing(ThisProcess.Id, sessionId);
- }
- }
-
- private static void TestCollectEventPipeTracing()
- {
- ulong sessionId = 0;
-
- try
- {
- uint circularBufferSizeMB = 64;
- var filePath = Path.Combine(
- Directory.GetCurrentDirectory(),
- $"dotnetcore-eventpipe-{ThisProcess.Id}.nettrace");
- var providers = new[] {
- new Provider(name: "Microsoft-Windows-DotNETRuntime"),
- };
-
- var configuration = new SessionConfiguration(circularBufferSizeMB, filePath, providers);
-
- Console.WriteLine("Start collecting.");
- using (Stream stream = EventPipeClient.CollectTracing(
- processId: ThisProcess.Id,
- configuration: configuration,
- sessionId: out sessionId))
- {
- // Check that a session was created.
- Assert.NotEqual("EventPipe Session Id", sessionId, (ulong)0);
-
- var collectingTask = new Task(() => {
- using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
- {
- while (true)
- {
- var buffer = new byte[16 * 1024];
- int nBytesRead = stream.Read(buffer, 0, buffer.Length);
- if (nBytesRead <= 0)
- break;
- fs.Write(buffer, 0, nBytesRead);
- }
- }
- });
- collectingTask.Start();
-
- { // Attempt to create another session, and verify that is not possible.
- Console.WriteLine("Attempt to create another session.");
-
- ulong sessionId2 = 0;
- try
- {
- using (var stream2 = EventPipeClient.CollectTracing(
- processId: ThisProcess.Id,
- configuration: configuration,
- sessionId: out sessionId2))
- {
- var buffer = new byte[16 * 1024];
- int nBytesRead = stream.Read(buffer, 0, buffer.Length);
- }
- }
- catch (EndOfStreamException)
- {
- }
- catch
- {
- Assert.True("EventPipeClient.CollectTracing threw unexpected exception", false);
- }
-
- Assert.Equal("EventPipe Session Id", sessionId2, (ulong)0);
- }
-
- Console.WriteLine("Doing some work.");
- Workload.DoWork(10);
-
- var ret = EventPipeClient.StopTracing(ThisProcess.Id, sessionId);
- Assert.Equal("Expect return value to be the disabled session Id", sessionId, ret);
- collectingTask.Wait();
-
- sessionId = 0; // Reset session Id, we do not need to disable it later.
-
- Assert.Equal("EventPipe output file", File.Exists(filePath), true);
-
- // Check file is valid.
- Console.WriteLine("Validating nettrace file.");
- ValidateNetTrace(filePath);
- }
- }
- finally
- {
- if (sessionId != 0)
- EventPipeClient.StopTracing(ThisProcess.Id, sessionId);
- }
- }
-
- private static void ValidateNetTrace(string filePath)
- {
- var nEventPipeResults = 0;
- using (var trace = new TraceLog(TraceLog.CreateFromEventPipeDataFile(filePath)).Events.GetSource())
- {
- trace.Dynamic.All += (TraceEvent data) => {
- ++nEventPipeResults;
- };
- trace.Process();
- }
-
- // Assert there were events in the file.
- Assert.NotEqual("Found events in trace file", nEventPipeResults, 0);
- }
-
- [Conditional("DEBUG")]
- private static void DumpNetTrace(string filePath)
- {
- using (var trace = new TraceLog(TraceLog.CreateFromEventPipeDataFile(filePath)).Events.GetSource())
- {
- trace.Dynamic.All += (TraceEvent e) => {
- if (!string.IsNullOrWhiteSpace(e.ProviderName) && !string.IsNullOrWhiteSpace(e.EventName))
- {
- Debug.WriteLine($"Event Provider: {e.ProviderName}");
- Debug.WriteLine($" Event Name: {e.EventName}");
- }
- };
- trace.Process();
- }
- }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics.Tracing;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient.Tests
-{
- internal sealed class TestProvider
- {
- public ulong Keywords { get; set; }
-
- public EventLevel EventLevel { get; set; }
-
- public string Name { get; set; }
-
- public string FilterData { get; set; }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient.Tests
-{
- internal sealed class TestSessionConfiguration
- {
- public uint CircularBufferSizeInMB { get; set; }
-
- public string TestName { get; set; }
-
- public IEnumerable<TestProvider> Providers { get; set; }
- }
-}
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-
-namespace Microsoft.Diagnostics.Tools.RuntimeClient.Tests
-{
- internal static class Workload
- {
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void DoWork(int nIterations)
- {
- for (int i = 0; i < nIterations; ++i)
- {
- MemoryAccessPerformance();
- BranchPredictionPerformance(seed: i);
- }
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static double MemoryAccessPerformance()
- {
- var doubles = new double[8 * 1024 * 1024];
- for (int i = 0; i < doubles.Length; i += 100)
- doubles[i] = 2.0;
- for (int i = 0; i < doubles.Length; i += 200)
- doubles[i] *= 3.0;
- for (int i = 0; i < doubles.Length; i += 400)
- doubles[i] *= 5.0;
- for (int i = 0; i < doubles.Length; i += 800)
- doubles[i] *= 7.0;
- for (int i = 0; i < doubles.Length; i += 1600)
- doubles[i] *= 11.0;
- return doubles.Average();
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static IEnumerable<int> BranchPredictionPerformance(int seed)
- {
- const int nCards = 52;
- var deck = new List<int>(Enumerable.Range(0, nCards));
- var rnd = new Random((int)DateTime.Now.Ticks + seed);
-
- for (int i = 0; i < deck.Count(); ++i)
- {
- var pos = rnd.Next(nCards);
- if (pos % 3 != 0)
- pos = rnd.Next(nCards);
- var temp = deck[i];
- deck[i] = deck[pos];
- deck[pos] = temp;
- }
-
- return deck;
- }
- }
-}
+++ /dev/null
-<Project Sdk="Microsoft.NET.Sdk">
- <PropertyGroup>
- <OutputType>Exe</OutputType>
- <TargetFramework>netcoreapp3.0</TargetFramework>
- <RootNamespace>Microsoft.Diagnostics.Tools.RuntimeClient.Tests</RootNamespace>
- <GenerateDocumentationFile>false</GenerateDocumentationFile>
- </PropertyGroup>
-
- <PropertyGroup>
- <IsPackable>false</IsPackable>
- <PackAsTool>false</PackAsTool>
- </PropertyGroup>
-
- <ItemGroup>
- <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Tools.RuntimeClient\Microsoft.Diagnostics.Tools.RuntimeClient.csproj" />
- </ItemGroup>
-</Project>