# SOS stress log
StressLog.txt
-# EventPipe files
+# Tracing files
+*.etl
+*.etlx
*.netperf
--- /dev/null
+<Project>
+
+ <PropertyGroup Label="Repository information">
+ <RepositoryUrl>https://github.com/dotnet/diagnostics.git</RepositoryUrl>
+ <RepositoryType>git</RepositoryType>
+ </PropertyGroup>
+
+ <PropertyGroup Label="Common Build properties">
+ <UseSharedCompilation>False</UseSharedCompilation>
+ <LangVersion>Latest</LangVersion>
+ <WarningLevel>4</WarningLevel>
+ <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
+ </PropertyGroup>
+
+ <PropertyGroup Label="NuGet package information">
+ <PackageIconUrl>http://go.microsoft.com/fwlink/?LinkID=288859</PackageIconUrl>
+ <PackageProjectUrl>https://github.com/dotnet/diagnostics.git</PackageProjectUrl>
+ <PackageLicenseUrl>https://raw.githubusercontent.com/dotnet/diagnostics/master/LICENSE.TXT</PackageLicenseUrl>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <!--
+ Suppress warnings for using preview SDK:
+ You are working with a preview version of the .NET Core SDK.
+ You can define the SDK version via a global.json file in the current project.
+ More at https://go.microsoft.com/fwlink/?linkid=869452
+ -->
+ <SuppressNETCoreSdkPreviewMessage>True</SuppressNETCoreSdkPreviewMessage>
+ </PropertyGroup>
+
+</Project>
namespace Microsoft.Diagnostics.Tools.RuntimeClient
{
- enum DiagnosticMessageType : uint
+ public enum DiagnosticMessageType : uint
{
StartSession = 1024,
StopSession,
Stream,
- Attach,
- Detach,
}
}
".", pipeName, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation))
{
namedPipe.Connect((int)TimeSpan.FromSeconds(20).TotalMilliseconds);
+ namedPipe.Write(buffer, 0, buffer.Length);
- var sw = new BinaryWriter(namedPipe);
- sw.Write(buffer);
-
- var br = new BinaryReader(namedPipe);
- return br.ReadUInt64();
+ return new BinaryReader(namedPipe).ReadUInt64();
}
}
else
{
- //throw new PlatformNotSupportedException("TODO: Get the ApplicationGroupId to form the string: 'dotnetcore-diagnostic-{processId}-{ApplicationGroupId}-socket'");
var ipcPort = Directory.GetFiles(IpcRootPath) // Try best match.
.Select(namedPipe => (new FileInfo(namedPipe)).Name)
.Single(input => Regex.IsMatch(input, $"^dotnetcore-diagnostic-{processId}-(\\d+)-socket$"));
socket.Send(buffer);
var content = new byte[sizeof(ulong)];
- int nReceivedBytes = socket.Receive(content);
+ var nReceivedBytes = socket.Receive(content);
return (nReceivedBytes == sizeof(ulong)) ? BitConverter.ToUInt64(content, 0) : 0;
}
}
}
+ /// <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 migth have expired and not properly cleaned up.
+ /// </returns>
public static IEnumerable<int> ListAvailablePorts()
{
return Directory.GetFiles(IpcRootPath)
.Select(input => int.Parse(Regex.Match(input, DiagnosticPortPattern).Groups[1].Value, NumberStyles.Integer));
}
- public static BinaryReader StreamTracingToFile(int processId, SessionConfiguration configuration, out ulong sessionId)
+ public static Stream StreamTracingToFile(int processId, SessionConfiguration configuration, out ulong sessionId)
{
sessionId = 0;
".", pipeName, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation);
namedPipe.Connect((int)TimeSpan.FromSeconds(20).TotalMilliseconds);
- var sw = new BinaryWriter(namedPipe);
- sw.Write(serializedConfiguration);
+ // Request start-streaming
+ namedPipe.Write(serializedConfiguration, 0, serializedConfiguration.Length);
- var br = new BinaryReader(namedPipe);
- sessionId = br.ReadUInt64();
- return br;
+ sessionId = new BinaryReader(namedPipe).ReadUInt64();
+ return namedPipe;
}
else
{
- throw new PlatformNotSupportedException("TODO: Get the ApplicationGroupId to form the string: 'dotnetcore-diagnostic-{processId}-{ApplicationGroupId}-socket'");
+ // TODO: Determine ApplicationGroupId
+ var ipcPort = Directory.GetFiles(IpcRootPath) // Try best match.
+ .Select(namedPipe => (new FileInfo(namedPipe)).Name)
+ .Single(input => Regex.IsMatch(input, $"^dotnetcore-diagnostic-{processId}-(\\d+)-socket$"));
+ var path = Path.Combine(Path.GetTempPath(), ipcPort);
+ var remoteEP = new UnixDomainSocketEndPoint(path);
+
+ var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
+ socket.Connect(remoteEP);
+
+ // Request start-streaming
+ socket.Send(serializedConfiguration);
+
+ var content = new byte[sizeof(ulong)];
+ int nReceivedBytes = socket.Receive(content);
+ sessionId = (nReceivedBytes == sizeof(ulong)) ? BitConverter.ToUInt64(content, 0) : 0;
+
+ return new NetworkStream(socket, FileAccess.Read, true);
}
}
public static ulong DisableTracingToFile(int processId, ulong sessionId)
{
+ if (sessionId == 0)
+ return sessionId; // TODO: Throw here instead?
+
var header = new MessageHeader {
RequestType = DiagnosticMessageType.StopSession,
Pid = (uint)Process.GetCurrentProcess().Id,
bw.Write(header.Pid);
bw.Write(configuration.CircularBufferSizeInMB);
- bw.Write(configuration.MultiFileTraceLengthInSeconds);
bw.WriteString(configuration.OutputPath);
--- /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 SessionLoggingType : 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
+ }
+}
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Generic;
using System.Diagnostics.Tracing;
+using System.Linq;
namespace Microsoft.Diagnostics.Tools.RuntimeClient
{
FilterData = string.IsNullOrWhiteSpace(filterData) ? null : filterData;
}
- public static Provider ToProvider(string provider)
+ public static IReadOnlyCollection<Provider> ToProviders(string providers)
+ {
+ if (string.IsNullOrWhiteSpace(providers))
+ throw new ArgumentNullException(nameof(providers));
+ return providers.Split(',')
+ .Select(ToProvider)
+ .ToArray();
+ }
+
+ private static Provider ToProvider(string provider)
{
if (string.IsNullOrWhiteSpace(provider))
throw new ArgumentNullException(nameof(provider));
var tokens = provider.Split(new[] { ':' }, 4, StringSplitOptions.None); // Keep empty tokens;
+ // Provider name
string providerName = tokens.Length > 0 ? tokens[0] : null;
if (string.IsNullOrWhiteSpace(providerName))
throw new ArgumentException("Provider name was not specified.");
+ // Keywords
ulong keywords = tokens.Length > 1 ? Convert.ToUInt64(tokens[1], 16) : ulong.MaxValue;
+
+ // Level
EventLevel eventLevel = tokens.Length > 2 && uint.TryParse(tokens[2], out var level) ?
(EventLevel)level : EventLevel.Verbose;
+
+ // Event counters
string filterData = tokens.Length > 3 ? tokens[3] : null;
return new Provider(providerName, keywords, eventLevel, filterData);
{
public struct SessionConfiguration
{
- public SessionConfiguration(uint circularBufferSizeMB, ulong multiFileSec, string outputPath, IEnumerable<Provider> providers)
+ public SessionConfiguration(uint circularBufferSizeMB, string outputPath, IReadOnlyCollection<Provider> providers)
{
if (providers == null)
throw new ArgumentNullException(nameof(providers));
if (providers.Count() <= 0)
throw new ArgumentException($"Specified providers collection is empty.");
+ if (circularBufferSizeMB == 0)
+ throw new ArgumentException($"Buffer size cannot be zero.");
+ if (Directory.Exists(outputPath))
+ throw new ArgumentException($"Specified output file name: {outputPath}, refers to a directory.");
CircularBufferSizeInMB = circularBufferSizeMB;
- MultiFileTraceLengthInSeconds = multiFileSec;
- _outputPath = new FileInfo(fileName: outputPath ?? $"eventpipe-{DateTime.Now:yyyyMMdd_HHmmss}.netperf");
+
+ outputPath = outputPath ?? $"eventpipe-{DateTime.Now:yyyyMMdd_HHmmss}.netperf";
+ outputPath = !outputPath.EndsWith(".netperf") ? $"{outputPath}.netperf" : outputPath;
+ _outputPath = new FileInfo(fileName: outputPath);
_providers = new List<Provider>(providers);
}
public uint CircularBufferSizeInMB { get; }
- public ulong MultiFileTraceLengthInSeconds { get; }
-
public string OutputPath => _outputPath.FullName;
- public IEnumerable<Provider> Providers => _providers;
+ public IReadOnlyCollection<Provider> Providers => _providers.AsReadOnly();
private readonly FileInfo _outputPath;
private readonly List<Provider> _providers;
@this.Write(Encoding.Unicode.GetBytes(value + '\0'));
}
-
#if DEBUG
private static int GetByteCount(this string @this)
{
int size = 0;
size += Marshal.SizeOf(@this.CircularBufferSizeInMB.GetType());
- size += Marshal.SizeOf(@this.MultiFileTraceLengthInSeconds.GetType());
-
size += @this.OutputPath.GetByteCount();
-
size += Marshal.SizeOf(typeof(int));
+
foreach (var provider in @this.Providers)
{
size += Marshal.SizeOf(provider.Keywords.GetType());
<Project Sdk="Microsoft.NET.Sdk">
+ <Import Project="$(MSBuildThisFileDirectory)\..\Common.props" />
+
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>Microsoft.Diagnostics.Tools.RuntimeClient</RootNamespace>
+ </PropertyGroup>
+
+ <PropertyGroup>
<IsPackable>False</IsPackable>
</PropertyGroup>
<PropertyGroup>
- <UseSharedCompilation>False</UseSharedCompilation>
- <LangVersion>Latest</LangVersion>
- <WarningLevel>4</WarningLevel>
- <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.38" />
+ <PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.40" />
</ItemGroup>
- <PropertyGroup>
- <!--
- Suppress warnings for using preview SDK:
- You are working with a preview version of the .NET Core SDK.
- You can define the SDK version via a global.json file in the current project.
- More at https://go.microsoft.com/fwlink/?linkid=869452
- -->
- <SuppressNETCoreSdkPreviewMessage>True</SuppressNETCoreSdkPreviewMessage>
- </PropertyGroup>
-
</Project>
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using Microsoft.Diagnostics.Tools.RuntimeClient;
using System;
using System.CommandLine;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using System.CommandLine.Builder;
-using System.CommandLine.Invocation;
-
-using Microsoft.Diagnostics.Tools.RuntimeClient;
namespace Microsoft.Diagnostics.Tools.Counters
{
}
}
- private static IEnumerable<Provider> ToProviders(string providers)
- {
- if (string.IsNullOrWhiteSpace(providers))
- throw new ArgumentNullException(nameof(providers));
- return providers.Split(',')
- .Select(Provider.ToProvider);
- }
-
private async Task<int> StartMonitor()
{
if (_processId == 0) {
}
var configuration = new SessionConfiguration(
- 1000,
- 0,
- outputPath,
- ToProviders(providerString));
+ circularBufferSizeMB: 1000,
+ outputPath: outputPath,
+ providers: Provider.ToProviders(providerString));
sessionId = EventPipeClient.EnableTracingToFile(_processId, configuration);
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.38" />
- </ItemGroup>
-
- <ItemGroup>
- <ProjectReference Include="..\..\Microsoft.Diagnostic.Repl\Microsoft.Diagnostic.Repl.csproj" />
+ <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostic.Repl\Microsoft.Diagnostic.Repl.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Tools.RuntimeClient\Microsoft.Diagnostics.Tools.RuntimeClient.csproj" />
</ItemGroup>
using Microsoft.Diagnostics.Tools.RuntimeClient;
using System;
using System.CommandLine;
-using System.CommandLine.Invocation;
+using System.Diagnostics;
+using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.Diagnostics.Tools.Trace
{
try
{
- foreach (var pid in EventPipeClient.ListAvailablePorts())
- Console.Out.WriteLine($"{System.Diagnostics.Process.GetProcessById(pid).ProcessName}({pid})");
+ var processes = EventPipeClient.ListAvailablePorts()
+ .Select(GetProcessById)
+ .Where(process => process != null)
+ .OrderBy(process => process.ProcessName);
+
+ foreach (var process in processes)
+ Console.Out.WriteLine($"{process.Id, 10} {process.ProcessName, -10} - {process.MainModule.FileName}");
await Task.FromResult(0);
return 0;
}
catch (Exception ex)
{
- Console.Error.WriteLine($"[ERROR]: {ex.ToString()}");
+ Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
return 1;
}
}
+ private static Process GetProcessById(int processId)
+ {
+ try
+ {
+ return Process.GetProcessById(processId);
+ }
+ catch (ArgumentException)
+ {
+ return null;
+ }
+ }
+
public static Command ActivePortsCommand() =>
new Command(
name: "ports",
description: "List all active DotNet Core Diagnostic ports.",
- handler: CommandHandler.Create<IConsole>(GetActivePorts),
+ handler: System.CommandLine.Invocation.CommandHandler.Create<IConsole>(GetActivePorts),
isHidden: true);
}
}
}
catch (Exception ex)
{
- Console.Error.WriteLine($"[ERROR]: {ex.ToString()}");
+ Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
return 1;
}
}
using Microsoft.Diagnostics.Tools.RuntimeClient;
using System;
-using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
-using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.Diagnostics.Tools.Trace
{
internal static class StartCommandHandler
{
- public static async Task<int> Start(IConsole console, int pid, string output, uint buffersize, string providers, ulong multiFileSec)
+ public static async Task<int> Start(IConsole console, int pid, string output, uint buffersize, string providers)
{
try
{
var configuration = new SessionConfiguration(
circularBufferSizeMB: buffersize,
- multiFileSec: multiFileSec,
outputPath: output,
- ToProviders(providers));
+ Provider.ToProviders(providers));
var sessionId = EventPipeClient.EnableTracingToFile(pid, configuration);
Console.Out.WriteLine($"OutputPath={configuration.OutputPath}");
Console.Out.WriteLine($"SessionId=0x{sessionId:X16}");
}
catch (Exception ex)
{
- Console.Error.WriteLine($"[ERROR]: {ex.ToString()}");
+ Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
return 1;
}
}
OutputPathOption(),
CircularBufferOption(),
ProvidersOption(),
- MultiFileSecOption(),
},
- handler: CommandHandler.Create<IConsole, int, string, uint, string, ulong>(Start));
+ handler: CommandHandler.Create<IConsole, int, string, uint, string>(Start));
private static Option OutputPathOption() =>
new Option(
new Option(
new[] { "--buffersize" },
@"Sets the size of the in-memory circular buffer in megabytes.",
- new Argument<uint> { Name = "Size" }); // TODO: 1024 ? Default ?
+ new Argument<uint>(defaultValue: 1024) {
+ Name = "Size",
+ }); // TODO: Seems excesive, but this has been the value.
private static Option ProvidersOption() =>
new Option(
aliases: new[] { "--providers" },
description: @"A list EventPipe provider to be enabled in the form 'Provider[,Provider]', where Provider is in the form: '(GUID|KnownProviderName)[:Flags[:Level][:KeyValueArgs]]', and KeyValueArgs is in the form: '[key1=value1][;key2=value2]'",
argument: new Argument<string> { Name = "Providers" }); // TODO: Can we specify an actual type?
-
- private static Option MultiFileSecOption() =>
- new Option(
- aliases: new[] { "--multifilesec" },
- description: @"Enable a file switch timer every 'n' seconds (Default is 0)",
- argument: new Argument<ulong> { Name = "MultiFileSec" });
-
- private static IEnumerable<Provider> ToProviders(string providers)
- {
- if (string.IsNullOrWhiteSpace(providers))
- throw new ArgumentNullException(nameof(providers));
- return providers.Split(',')
- .Select(Provider.ToProvider);
- }
}
}
}
catch (Exception ex)
{
- Console.Error.WriteLine($"[ERROR]: {ex.ToString()}");
+ Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
return 1;
}
}
// See the LICENSE file in the project root for more information.
using Microsoft.Diagnostics.Tools.RuntimeClient;
+using Microsoft.Diagnostics.Tracing;
+using Microsoft.Diagnostics.Tracing.Etlx;
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
-using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.Diagnostics.Tools.Trace
{
var configuration = new SessionConfiguration(
circularBufferSizeMB: buffersize,
- multiFileSec: 0,
outputPath: output,
- ToProviders(providers));
- var binaryReader = EventPipeClient.StreamTracingToFile(pid, configuration, out var sessionId);
- Console.Out.WriteLine($"SessionId=0x{sessionId:X16}");
+ Provider.ToProviders(providers));
+ string filePath = null;
+ ulong sessionId = 0;
- if (sessionId != 0)
+ using (Stream stream = EventPipeClient.StreamTracingToFile(pid, configuration, out sessionId))
{
- var filePath = $"dotnetcore-eventpipe-{pid}-0x{sessionId:X16}.netperf";
+ if (sessionId == 0)
+ {
+ Console.Error.WriteLine("Unable to create streaming session.");
+ return -1;
+ }
+
+ filePath = $"dotnetcore-eventpipe-{pid}-0x{sessionId:X16}.netperf";
using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
+ Console.Out.WriteLine($"OutputPath={fs.Name}");
+ Console.Out.WriteLine($"SessionId=0x{sessionId:X16}");
+
while (true)
{
var buffer = new byte[1024];
- int nBytesRead = binaryReader.Read(buffer, 0, buffer.Length);
+ int nBytesRead = stream.Read(buffer, 0, buffer.Length);
if (nBytesRead <= 0)
break;
+ Console.WriteLine($"PACKET: {Convert.ToBase64String(buffer, 0, nBytesRead)}");
fs.Write(buffer, 0, nBytesRead);
}
}
}
+ if (sessionId != 0 && filePath != null)
+ {
+ var eventPipeResults = new List<TraceEvent>();
+ using (var trace = new TraceLog(TraceLog.CreateFromEventPipeDataFile(filePath)).Events.GetSource())
+ {
+ trace.Dynamic.All += (TraceEvent data) => {
+ eventPipeResults.Add(data);
+ };
+
+ trace.Process();
+ }
+
+ eventPipeResults.ForEach(e => {
+ if (!string.IsNullOrWhiteSpace(e.ProviderName) && !string.IsNullOrWhiteSpace(e.EventName))
+ {
+ Console.Out.WriteLine($"Event Provider: {e.ProviderName}");
+ Console.Out.WriteLine($" Event Name: {e.EventName}");
+ }
+ });
+ }
+
await Task.FromResult(0);
return sessionId != 0 ? 0 : 1;
}
catch (Exception ex)
{
- Console.Error.WriteLine($"[ERROR]: {ex.ToString()}");
+ Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
return 1;
}
}
aliases: new[] { "--providers" },
description: @"A list EventPipe provider to be enabled in the form 'Provider[,Provider]', where Provider is in the form: '(GUID|KnownProviderName)[:Flags[:Level][:KeyValueArgs]]', and KeyValueArgs is in the form: '[key1=value1][;key2=value2]'",
argument: new Argument<string> { Name = "Providers" }); // TODO: Can we specify an actual type?
-
- private static IEnumerable<Provider> ToProviders(string providers)
- {
- if (string.IsNullOrWhiteSpace(providers))
- throw new ArgumentNullException(nameof(providers));
- return providers.Split(',')
- .Select(Provider.ToProvider);
- }
}
}
--- /dev/null
+#!/bin/bash
+
+dotnet restore dotnet-trace.csproj
+dotnet build dotnet-trace.csproj -c Debug --no-restore
+
<Project Sdk="Microsoft.NET.Sdk">
+ <Import Project="$(MSBuildThisFileDirectory)\..\..\Common.props" />
+
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RootNamespace>Microsoft.Diagnostics.Tools.Trace</RootNamespace>
- <IsPackable>False</IsPackable>
- <PackAsTool>False</PackAsTool>
+ <GenerateDocumentationFile>False</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup>
- <UseSharedCompilation>False</UseSharedCompilation>
- <LangVersion>Latest</LangVersion>
- <WarningLevel>4</WarningLevel>
- <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
- <GenerateDocumentationFile>False</GenerateDocumentationFile>
+ <IsPackable>False</IsPackable>
+ <PackAsTool>False</PackAsTool>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="System.CommandLine.Experimental" Version="0.2.0-alpha.19167.2" />
+ <PackageReference Include="System.CommandLine.Experimental" Version="0.2.0-alpha.19179.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Microsoft.Diagnostics.Tools.RuntimeClient\Microsoft.Diagnostics.Tools.RuntimeClient.csproj" />
</ItemGroup>
- <PropertyGroup>
- <!--
- Suppress warnings for using preview SDK:
- You are working with a preview version of the .NET Core SDK.
- You can define the SDK version via a global.json file in the current project.
- More at https://go.microsoft.com/fwlink/?linkid=869452
- -->
- <SuppressNETCoreSdkPreviewMessage>True</SuppressNETCoreSdkPreviewMessage>
- </PropertyGroup>
-
-</Project>
\ No newline at end of file
+</Project>
--- /dev/null
+#!/bin/bash
+
+echo $USER@`hostname` "$PWD"
+echo [`date`] $ dotnet run -p dotnet-trace.csproj -c Debug --no-restore --no-build -- "$@"
+dotnet run -p dotnet-trace.csproj -c Debug --no-restore --no-build -- "$@"
+
--- /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 Tracing.Tests.Common;
+
+namespace Microsoft.Diagnostics.Tools.RuntimeClient.Tests
+{
+ class Program
+ {
+ static int Main(string[] args)
+ {
+ SendSmallerHeaderCommand();
+ SendInvalidDiagnosticMessageTypeCommand();
+
+ StartNewTracingToFileSession();
+ StartNewTracingToStreamSession();
+ 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)DiagnosticMessageType.StartSession);
+ 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 SendInvalidDiagnosticMessageTypeCommand()
+ {
+ 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 void StartNewTracingToFileSession()
+ {
+ Console.WriteLine("Start collection.");
+
+ ulong sessionId = 0;
+
+ try
+ {
+ uint circularBufferSizeMB = 64;
+ var filePath = Path.Combine(
+ Directory.GetCurrentDirectory(),
+ $"dotnetcore-eventpipe-{ThisProcess.Id}.netperf");
+ var providers = new[] {
+ new Provider(name: "Microsoft-Windows-DotNETRuntime"),
+ };
+ // "Microsoft-Windows-DotNETRuntime:0x00000004C14FCCBD:4"
+
+ var configuration = new SessionConfiguration(circularBufferSizeMB, filePath, providers);
+
+ // Start session.
+ sessionId = EventPipeClient.EnableTracingToFile(
+ processId: ThisProcess.Id,
+ configuration: configuration);
+
+ // Check that a session was created.
+ Assert.NotEqual("EventPipe Session Id", sessionId, (ulong)0);
+
+ // Check that file is created
+ // NOTE: This might change in the future, and file could be created only "OnDisable".
+ Assert.Equal("EventPipe output file", File.Exists(filePath), true);
+
+ {
+ // Attempt to create another session, and verify that is not possible.
+ var sessionId2 = EventPipeClient.EnableTracingToFile(
+ processId: ThisProcess.Id,
+ configuration: configuration);
+
+ // Check that a new session was not created.
+ Assert.Equal("EventPipe Session Id", sessionId2, (ulong)0);
+ }
+
+ Workload.DoWork(10);
+
+ var ret = EventPipeClient.DisableTracingToFile(ThisProcess.Id, sessionId);
+ Assert.Equal("Expect return value to be the disabled session Id", sessionId, ret);
+ sessionId = 0; // Reset session Id, we do not need to disable it later.
+
+ // Check file is valid.
+ 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);
+ }
+ finally
+ {
+ if (sessionId != 0)
+ EventPipeClient.DisableTracingToFile(ThisProcess.Id, sessionId);
+ }
+ }
+
+ private static void StartNewTracingToStreamSession()
+ {
+ Console.WriteLine("Start streaming.");
+ }
+ }
+}
--- /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">
+
+ <Import Project="$(MSBuildThisFileDirectory)\..\..\Common.props" />
+
+ <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>