Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new DiagnosticClient commands for IPC features #2268

Merged
merged 9 commits into from
Jun 28, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
26 changes: 24 additions & 2 deletions documentation/diagnostics-client-library-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,36 @@ public static void PrintEventsLive(int processId)

This sample shows how to attach an ICorProfiler to a process (profiler attach).
```cs
public static int AttachProfiler(int processId, Guid profilerGuid, string profilerPath)
public static void AttachProfiler(int processId, Guid profilerGuid, string profilerPath)
{
var client = new DiagnosticsClient(processId);
return client.AttachProfiler(TimeSpan.FromSeconds(10), profilerGuid, profilerPath);
client.AttachProfiler(TimeSpan.FromSeconds(10), profilerGuid, profilerPath);
}
```

#### 8. Set an ICorProfiler to be used as the startup profiler

This sample shows how to request that the runtime use an ICorProfiler as the startup profiler (not as an attaching profiler). It is only valid to issue this command while the runtime is paused in "reverse server" mode.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the reversed server is orthogonal, the runtime just needs to be paused at startup? That startup pause can be accomplished regardless whether the port is listening or connecting:

export DOTNET_DiagnosticPorts=foo.sock,connect,suspend
OR
export DOTNET_DiagnosticPorts=foo.sock,listen,suspend


```cs
public static void SetStartupProfilerProfiler(Guid profilerGuid, string profilerPath)
{
var client = new DiagnosticsClient(processId);
client.SetStartupProfiler(profilerGuid, profilerPath);
}
```

#### 9. Resume the runtime when it is paused in reverse server mode

This sample shows how a client can instruct the runtime to resume loading after it has been paused in "reverse server" mode.

```cs
public static void ResumeRuntime(Guid profilerGuid, string profilerPath)
{
var client = new DiagnosticsClient(processId);
client.ResumeRuntime();
}
```

## API Description

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,15 @@ internal enum DumpCommandId : byte
internal enum ProfilerCommandId : byte
{
AttachProfiler = 0x01,
StartupProfiler = 0x02,
}

internal enum ProcessCommandId : byte
{
GetProcessInfo = 0x00,
ResumeRuntime = 0x01,
GetProcessEnvironment = 0x02,
GetEnvironmentVariable = 0x03,
davmason marked this conversation as resolved.
Show resolved Hide resolved
SetEnvironmentVariable = 0x04,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ internal enum DiagnosticsIpcError : uint
BadEncoding = 0x80131384,
UnknownCommand = 0x80131385,
UnknownMagic = 0x80131386,
UnknownError = 0x80131387
UnknownError = 0x80131387,
EnvVarNotFound = 0x800700CB,
davmason marked this conversation as resolved.
Show resolved Hide resolved
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,14 @@ public static ProcessEnvironmentHelper Parse(byte[] payload)
cursor += sizeof(UInt32);
while (cursor < envBlock.Length)
{
string pair = ReadString(envBlock, ref cursor);
string pair = IpcHelpers.ReadString(envBlock, ref cursor);
int equalsIdx = pair.IndexOf('=');
env[pair.Substring(0,equalsIdx)] = equalsIdx != pair.Length - 1 ? pair.Substring(equalsIdx+1) : "";
}

return env;
}

private static string ReadString(byte[] buffer, ref int index)
{
// Length of the string of UTF-16 characters
int length = (int)BitConverter.ToUInt32(buffer, index);
index += sizeof(UInt32);

int size = (int)length * sizeof(char);
// The string contains an ending null character; remove it before returning the value
string value = Encoding.Unicode.GetString(buffer, index, size).Substring(0, length - 1);
index += size;
return value;
}

private UInt32 ExpectedSizeInBytes { get; set; }
private UInt16 Future { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,13 @@ public static ProcessInfo Parse(byte[] payload)
processInfo.RuntimeInstanceCookie = new Guid(cookieBuffer);
index += GuidSizeInBytes;

processInfo.CommandLine = ReadString(payload, ref index);
processInfo.OperatingSystem = ReadString(payload, ref index);
processInfo.ProcessArchitecture = ReadString(payload, ref index);
processInfo.CommandLine = IpcHelpers.ReadString(payload, ref index);
processInfo.OperatingSystem = IpcHelpers.ReadString(payload, ref index);
processInfo.ProcessArchitecture = IpcHelpers.ReadString(payload, ref index);

return processInfo;
}

private static string ReadString(byte[] buffer, ref int index)
{
// Length of the string of UTF-16 characters
int length = (int)BitConverter.ToUInt32(buffer, index);
index += sizeof(UInt32);

int size = (int)length * sizeof(char);
// The string contains an ending null character; remove it before returning the value
string value = Encoding.Unicode.GetString(buffer, index, size).Substring(0, length - 1);
index += size;
return value;
}

public UInt64 ProcessId { get; private set; }
public Guid RuntimeInstanceCookie { get; private set; }
public string CommandLine { get; private set; }
Expand Down
22 changes: 22 additions & 0 deletions src/Microsoft.Diagnostics.NETCore.Client/IpcHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.Diagnostics.NETCore.Client
{
internal static class IpcHelpers
{
public static string ReadString(byte[] buffer, ref int index)
{
// Length of the string of UTF-16 characters
int length = (int)BitConverter.ToUInt32(buffer, index);
index += sizeof(UInt32);

int size = (int)length * sizeof(char);
// The string contains an ending null character; remove it before returning the value
string value = Encoding.Unicode.GetString(buffer, index, size).Substring(0, length - 1);
index += size;
return value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@


using System;
using System.Linq;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
using System.Collections.Generic;

namespace Microsoft.Diagnostics.NETCore.Client
{
Expand All @@ -22,13 +24,14 @@ public class TestRunner : IDisposable
private CancellationTokenSource cts;

public TestRunner(string testExePath, ITestOutputHelper _outputHelper = null,
bool redirectError = false, bool redirectInput = false)
bool redirectError = false, bool redirectInput = false, Dictionary<string, string> envVars = null)
{
startInfo = new ProcessStartInfo(CommonHelper.HostExe, testExePath);
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = redirectError;
startInfo.RedirectStandardInput = redirectInput;
envVars?.ToList().ForEach(item => startInfo.Environment.Add(item.Key, item.Value));
outputHelper = _outputHelper;
}

Expand Down