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

Fix EventPipe.Enable() to be aware of multiple EventPipe sessions #34984

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 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
238 changes: 238 additions & 0 deletions src/coreclr/tests/src/tracing/regress/GitHub_34839/GitHub_34839.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
// 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.IO;
using System.Reflection;
using System.Threading;

/*

This test is a regression test for github.com/dotnet/runtime/issues/34839.

We test whether it's possible to enable many sessions via reflection on EventPipe.Enable method, and whether they can be disabled by calling corresponding Disable() method.

*/
namespace EventPipe.Issue34839
{
public enum EventPipeSerializationFormat
{
NetPerf,
NetTrace
}

public sealed class TraceConfiguration
{
private ConstructorInfo m_configurationCtor;
private MethodInfo m_enableProviderMethod;
private MethodInfo m_setProfilerSamplingRateMethod;

private object m_configurationObject;

public TraceConfiguration(
string outputFile,
uint circularBufferMB)
{
// Initialize reflection references.
if (!Initialize())
{
throw new InvalidOperationException("Reflection failed.");
}

m_configurationObject = m_configurationCtor.Invoke(
new object[]
{
outputFile,
EventPipeSerializationFormat.NetTrace,
circularBufferMB
});
}

public void EnableProvider(
string providerName,
UInt64 keywords,
uint level)
{
m_enableProviderMethod.Invoke(
m_configurationObject,
new object[]
{
providerName,
keywords,
level
});
}

internal object ConfigurationObject
{
get { return m_configurationObject; }
}

public void SetSamplingRate(TimeSpan minDelayBetweenSamples)
{
m_setProfilerSamplingRateMethod.Invoke(
m_configurationObject,
new object[]
{
minDelayBetweenSamples
});
}

private bool Initialize()
{
Assembly SPC = typeof(System.Diagnostics.Tracing.EventSource).Assembly;
if (SPC == null)
{
Console.WriteLine("System.Private.CoreLib assembly == null");
return false;
}

Type configurationType = SPC.GetType("System.Diagnostics.Tracing.EventPipeConfiguration");
if (configurationType == null)
{
Console.WriteLine("configurationType == null");
return false;
}
Type formatType = SPC.GetType("System.Diagnostics.Tracing.EventPipeSerializationFormat");
if (formatType == null)
{
Console.WriteLine("formatType == null");
return false;
}

m_configurationCtor = configurationType.GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type[] { typeof(string), formatType, typeof(uint) },
null);
if (m_configurationCtor == null)
{
Console.WriteLine("configurationCtor == null");
return false;
}

m_enableProviderMethod = configurationType.GetMethod(
"EnableProvider",
BindingFlags.NonPublic | BindingFlags.Instance);
if (m_enableProviderMethod == null)
{
Console.WriteLine("enableProviderMethod == null");
return false;
}

m_setProfilerSamplingRateMethod = configurationType.GetMethod(
"SetProfilerSamplingRate",
BindingFlags.NonPublic | BindingFlags.Instance);
if (m_setProfilerSamplingRateMethod == null)
{
Console.WriteLine("setProfilerSamplingRate == null");
return false;
}

return true;
}
}

class Program
{
private static MethodInfo m_enableMethod;
private static MethodInfo m_disableMethod;

public static void Enable(TraceConfiguration traceConfig)
{
m_enableMethod.Invoke(
null,
new object[]
{
traceConfig.ConfigurationObject
});
}

public static void Disable()
{
m_disableMethod.Invoke(
null,
null);
}

static int Main(string[] args)
{
TimeSpan profSampleDelay = TimeSpan.FromMilliseconds(1);

Assembly SPC = typeof(System.Diagnostics.Tracing.EventSource).Assembly;
Type eventPipeType = SPC.GetType("System.Diagnostics.Tracing.EventPipe");
m_enableMethod = eventPipeType.GetMethod("Enable", BindingFlags.NonPublic | BindingFlags.Static);
m_disableMethod = eventPipeType.GetMethod("Disable", BindingFlags.NonPublic | BindingFlags.Static);

// Setup the configuration values.
uint circularBufferMB = 1024; // 1 GB
uint level = 5; // Verbose

const uint configurationCnt = 5;

// Create 5 instances of EventPipeConfiguration.
TraceConfiguration[] configs = new TraceConfiguration[configurationCnt];

for (int i = 0; i < configurationCnt; i++)
{
string outputFile = $"default{i}.nettrace";
configs[i] = new TraceConfiguration(outputFile, circularBufferMB);

// Setup the provider values.
// Public provider.
string providerName = "Microsoft-Windows-DotNETRuntime";
UInt64 keywords = 0x4c14fccbd;

// Enable the provider.
configs[i].EnableProvider(providerName, keywords, level);

// Private provider.
providerName = "Microsoft-Windows-DotNETRuntimePrivate";
keywords = 0x4002000b;

// Enable the provider.
configs[i].EnableProvider(providerName, keywords, level);

// Sample profiler.
providerName = "Microsoft-DotNETCore-SampleProfiler";
keywords = 0x0;

// Enable the provider.
configs[i].EnableProvider(providerName, keywords, level);

// Set the sampling rate.
configs[i].SetSamplingRate(profSampleDelay);
}

// Enable tracing many times
for (int i = 0; i < configurationCnt; i++)
{
Enable(configs[i]);
}

// Sleep for 5 second to let some events to be written
Thread.Sleep(1000);
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment doesn't match code. Also, does the sleep need to be 1s or could it be something shorter, like 500ms?


// Disable
for (int i = 0; i < configurationCnt; i++)
{
Disable();
}

// Assert that all trace files exist now.
for (int i = 0; i < configurationCnt; i++)
{
string outputFile = $"default{i}.nettrace";
if (!File.Exists(outputFile))
{
Console.WriteLine($"The expected output file {i} does not exist");
return 1;
}
}

return 100;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<CLRTestKind>BuildAndRun</CLRTestKind>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CLRTestPriority>0</CLRTestPriority>
<!-- Test unsupported outside of windows -->
<TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
<DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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.Concurrent;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
Expand Down Expand Up @@ -177,7 +178,7 @@ internal void SetProfilerSamplingRate(TimeSpan minTimeBetweenSamples)

internal static class EventPipe
{
private static ulong s_sessionID = 0;
internal static ConcurrentQueue<ulong> s_sessionIDs = new ConcurrentQueue<ulong>();

internal static void Enable(EventPipeConfiguration configuration)
{
Expand All @@ -193,16 +194,19 @@ internal static void Enable(EventPipeConfiguration configuration)

EventPipeProviderConfiguration[] providers = configuration.Providers;

s_sessionID = EventPipeInternal.Enable(
s_sessionIDs.Enqueue(EventPipeInternal.Enable(
configuration.OutputFile,
configuration.Format,
configuration.CircularBufferSizeInMB,
providers);
providers));
}

internal static void Disable()
{
EventPipeInternal.Disable(s_sessionID);
if (s_sessionIDs.TryDequeue(out ulong sessionID))
{
EventPipeInternal.Disable(sessionID);
}
}
}

Expand Down