Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cc40349
add run to counters
sywhang Sep 1, 2020
f9d96f7
Add trace run command
sywhang Sep 1, 2020
51dca9b
use acceptasync instead of sleeping... :p
sywhang Sep 2, 2020
907ada3
Counter run works now
sywhang Sep 2, 2020
4eaba69
Fix incorrect cpu-usage descriptor
sywhang Sep 23, 2020
7a873d0
Merge remote-tracking branch 'upstream/master'
sywhang Oct 2, 2020
e4e463e
Merge remote-tracking branch 'upstream/master'
sywhang Oct 5, 2020
c5e542d
Merge remote-tracking branch 'upstream/master' into dev/suwhang/tools…
sywhang Oct 5, 2020
643cc1c
use processlauncher to handle --
sywhang Oct 6, 2020
8df4435
Merge branch 'master' into dev/suwhang/tools-run
sywhang Oct 6, 2020
2229e45
remove unused code
sywhang Oct 6, 2020
583fcef
make dotnet-counters collect attachable at startup
sywhang Oct 7, 2020
8529324
cleanup
sywhang Oct 7, 2020
cd96473
more refactoring
sywhang Oct 7, 2020
0878632
Fix misbehaviors when stopping counters/child proc
sywhang Oct 7, 2020
c1b6003
dotnet-trace collect can attach at startup now
sywhang Oct 7, 2020
8c01c55
Fix IOException being thrown for Stop command
sywhang Oct 7, 2020
c451374
Defer ResumeRuntime after we create EventPipeSession
sywhang Oct 7, 2020
02451f6
Change the default behavior to not redirect stdin/stdout/stderr
sywhang Oct 7, 2020
f381430
terminate child proc upon exit
sywhang Oct 7, 2020
154bb17
remove useless code
sywhang Oct 7, 2020
70ebf8d
gracefully handle older versions that can't connect to reversed server.
sywhang Oct 8, 2020
8e80aa4
terminate child proc
sywhang Oct 8, 2020
7a16985
Fix build err'
sywhang Oct 8, 2020
326cdd3
code review feedback
sywhang Oct 8, 2020
bcdae64
Code review feedback
sywhang Oct 9, 2020
b32f366
Handle escape characters in argument string to child process
sywhang Oct 12, 2020
27a2565
fix build failure
sywhang Oct 12, 2020
2500d03
fix build failure
sywhang Oct 13, 2020
e25dd08
Remove unused code
sywhang Oct 13, 2020
ae4eec3
Enable --counters option for default scenario as well
sywhang Oct 13, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,16 @@ public void Stop()
Debug.Assert(_sessionId > 0);

byte[] payload = BitConverter.GetBytes(_sessionId);
var response = IpcClient.SendMessage(_endpoint, new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.StopTracing, payload));
IpcMessage response;
try
{
response = IpcClient.SendMessage(_endpoint, new IpcMessage(DiagnosticsServerCommandSet.EventPipe, (byte)EventPipeCommandId.StopTracing, payload));
}
// On non-abrupt exits (i.e. the target process has already exited and pipe is gone, sending Stop command will fail).
catch (IOException)
{
throw new ServerNotAvailableException("Could not send Stop command. The target process may have exited.");
}

switch ((DiagnosticsServerResponseId)response.Header.CommandId)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@
<InternalsVisibleTo Include="DotnetMonitor.UnitTests" />
<InternalsVisibleTo Include="Microsoft.Diagnostics.Monitoring" />
<InternalsVisibleTo Include="Microsoft.Diagnostics.NETCore.Client.UnitTests" />
<InternalsVisibleTo Include="dotnet-counters" />
<InternalsVisibleTo Include="dotnet-trace" />
</ItemGroup>
</Project>
152 changes: 152 additions & 0 deletions src/Tools/Common/ReversedServerHelpers/ReversedServerHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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.NETCore.Client;
using Microsoft.Diagnostics.Tracing.Parsers.Clr;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace Microsoft.Internal.Common.Utils
{
// <summary>
// ProcessLauncher is a child-process launcher for "diagnostics tools at startup" scenarios
// It launches the target process at startup and passes its processId to the corresponding Command handler.
// </summary>
internal class ProcessLauncher
{
private Process _childProc = null;

internal static ProcessLauncher Launcher = new ProcessLauncher();

public void PrepareChildProcess(string[] args)
{
int unparsedTokenIdx = FindUnparsedTokenIndex(args);
if (unparsedTokenIdx < 0)
{
return;
}

_childProc = new Process();
_childProc.StartInfo.FileName = args[unparsedTokenIdx];
string arguments = "";
for (int i = unparsedTokenIdx+1; i < args.Length; i++)
{
if (args[i].Contains(" "))
{
arguments += $"\"{args[i].Replace("\"", "\\\"")}\"";
}
else
{
arguments += args[i];
}

if (i != args.Length)
arguments += " ";
}
_childProc.StartInfo.Arguments = arguments;
}

private int FindUnparsedTokenIndex(string[] args)
{
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "--" && i < (args.Length - 1)) return i+1;
}
return -1;
}

public bool HasChildProc
{
get
{
return _childProc != null;
}
}

public Process ChildProc
{
get
{
return _childProc;
}
}
public bool Start(string diagnosticTransportName)
{
_childProc.StartInfo.UseShellExecute = false;
_childProc.StartInfo.RedirectStandardOutput = true;
_childProc.StartInfo.RedirectStandardError = true;
_childProc.StartInfo.RedirectStandardInput = true;
_childProc.StartInfo.Environment.Add("DOTNET_DiagnosticPorts", $"{diagnosticTransportName},suspend");
try
{
_childProc.Start();
}
catch (Exception e)
{
Console.WriteLine($"Cannot start target process: {_childProc.StartInfo.FileName} {_childProc.StartInfo.Arguments}");
Console.WriteLine(e.ToString());
return false;
}
return true;
}

public void Cleanup()
{
if (_childProc != null && !_childProc.HasExited)
{
try
{
_childProc.Kill();
}
// if process exited while we were trying to kill it, it can throw IOE
catch (InvalidOperationException) { }
}
}
}

// <summary>
// This class acts a helper class for building a DiagnosticsClient instance
// </summary>
internal class ReversedDiagnosticsClientBuilder
{
private static string GetTransportName(string toolName) => $"{toolName}-{Process.GetCurrentProcess().Id}-{DateTime.Now:yyyyMMdd_HHmmss}.socket";

// <summary>
// Starts the child process and returns the diagnostics client once the child proc connects to the reversed diagnostics pipe.
// The callee needs to resume the diagnostics client at appropriate time.
// </summary>
public static DiagnosticsClient Build(ProcessLauncher childProcLauncher, string toolName, int timeoutInSec)
{
if (!childProcLauncher.HasChildProc)
{
throw new InvalidOperationException("Must have a valid child process to launch.");
}
// Create and start the reversed server
string diagnosticTransportName = GetTransportName(toolName);
ReversedDiagnosticsServer server = new ReversedDiagnosticsServer(diagnosticTransportName);
server.Start();

// Start the child proc
if (!childProcLauncher.Start(diagnosticTransportName))
{
throw new InvalidOperationException("Failed to start dotnet-counters.");
}

// Wait for attach
IpcEndpointInfo endpointInfo = server.Accept(TimeSpan.FromSeconds(timeoutInSec));

// If for some reason a different process attached to us, wait until the expected process attaches.
while (endpointInfo.ProcessId != childProcLauncher.ChildProc.Id)
{
endpointInfo = server.Accept(TimeSpan.FromSeconds(timeoutInSec));
}
return new DiagnosticsClient(endpointInfo.Endpoint);
}
}
}
Loading