-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[UserEvents] Add end-to-end runtime test #121316
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
47231e1
963efe1
e712df6
2b246be
a7afeb9
c41916a
963af3f
005cc94
5d09bd2
146b348
a8d5d97
f9531d2
ffc0c16
a0c37b6
9009189
7395930
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| let Microsoft_Windows_DotNETRuntime_flags = new_dotnet_provider_flags(); | ||
| record_dotnet_provider("Microsoft-Windows-DotNETRuntime", 0x100003801D, 4, Microsoft_Windows_DotNETRuntime_flags); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System; | ||
| using System.Diagnostics; | ||
| using System.IO; | ||
| using System.Runtime.InteropServices; | ||
| using System.Threading; | ||
| using Microsoft.Diagnostics.Tracing; | ||
| using Microsoft.Diagnostics.Tracing.Etlx; | ||
|
|
||
| namespace Tracing.Tests.UserEvents | ||
| { | ||
| public class UserEventsTest | ||
| { | ||
| private static readonly string trace = "trace.nettrace"; | ||
| private const int SIGINT = 2; | ||
|
|
||
| [DllImport("libc", SetLastError = true)] | ||
| private static extern int kill(int pid, int sig); | ||
|
|
||
| public static int Main(string[] args) | ||
| { | ||
| if (args.Length > 0 && args[0] == "tracee") | ||
| { | ||
| UserEventsTracee.Run(); | ||
| return 0; | ||
| } | ||
|
|
||
| return TestEntryPoint(); | ||
| } | ||
|
|
||
| public static int TestEntryPoint() | ||
| { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should add checks for:
Its likely at some point this test will be run in the wrong environment and the logs should make it trivial to diagnose.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should not even build the test on none linux platforms. CLRTestTargetUnsupported msbuild property could be used to exclude a test on specific platforms.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The CLRTestTargetUnsupported is in the csproj, so it should hopefully prevent this test from running on non linux-x64/linux-arm64 platforms. Then again, I think more logic is needed to check for Alpine. Added checks for geteuid and checking if sys/kernel/tracing/user_events_data exists |
||
| string appBaseDir = AppContext.BaseDirectory; | ||
| string recordTracePath = Path.Combine(appBaseDir, "record-trace"); | ||
| string scriptFilePath = Path.Combine(appBaseDir, "dotnet-common.script"); | ||
| string traceFilePath = Path.Combine(appBaseDir, trace); | ||
|
||
|
|
||
| if (!File.Exists(recordTracePath) || !File.Exists(scriptFilePath)) | ||
| { | ||
| Console.WriteLine("record-trace or dotnet-common.script not found. Test cannot run."); | ||
|
||
| return -1; | ||
| } | ||
|
|
||
| Process traceeProcess = new(); | ||
| traceeProcess.StartInfo.FileName = Process.GetCurrentProcess().MainModule.FileName; | ||
| traceeProcess.StartInfo.Arguments = $"{typeof(UserEventsTest).Assembly.Location} tracee"; | ||
| traceeProcess.StartInfo.WorkingDirectory = appBaseDir; | ||
| traceeProcess.Start(); | ||
| int traceePid = traceeProcess.Id; | ||
|
|
||
| Process recordTraceProcess = new(); | ||
mdh1418 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| recordTraceProcess.StartInfo.FileName = recordTracePath; | ||
| recordTraceProcess.StartInfo.Arguments = $"--script-file {scriptFilePath} --pid {traceePid}"; | ||
| recordTraceProcess.StartInfo.WorkingDirectory = appBaseDir; | ||
| recordTraceProcess.StartInfo.RedirectStandardOutput = true; | ||
| recordTraceProcess.StartInfo.RedirectStandardError = true; | ||
| recordTraceProcess.OutputDataReceived += (_, args) => Console.WriteLine($"[record-trace] {args.Data}"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should redirect the tracee output as well to ensure we aren't losing useful error diagnostics that it might print.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
| recordTraceProcess.ErrorDataReceived += (_, args) => Console.Error.WriteLine($"[record-trace] {args.Data}"); | ||
| recordTraceProcess.Start(); | ||
| recordTraceProcess.BeginOutputReadLine(); | ||
| recordTraceProcess.BeginErrorReadLine(); | ||
|
|
||
| if (!recordTraceProcess.HasExited && !traceeProcess.WaitForExit(15000)) | ||
mdh1418 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| traceeProcess.Kill(); | ||
| } | ||
|
|
||
| // Until record-trace supports duration, the only way to stop it is to send SIGINT (ctrl+c) | ||
| kill(recordTraceProcess.Id, SIGINT); | ||
|
||
| if (!recordTraceProcess.HasExited && !recordTraceProcess.WaitForExit(20000)) | ||
| { | ||
| // record-trace needs to stop gracefully to generate the trace file | ||
| recordTraceProcess.Kill(); | ||
| } | ||
|
|
||
mdh1418 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (!File.Exists(traceFilePath)) | ||
| { | ||
| Console.Error.WriteLine($"Expected trace file not found at `{traceFilePath}`"); | ||
| return -1; | ||
| } | ||
|
|
||
| if (!ValidateTraceeEvents(traceFilePath)) | ||
| { | ||
| Console.Error.WriteLine($"Trace file `{traceFilePath}` does not contain expected events."); | ||
| return -1; | ||
| } | ||
|
|
||
| if (File.Exists(traceFilePath)) | ||
| { | ||
| try | ||
| { | ||
| File.Delete(traceFilePath); | ||
| } | ||
| catch {} | ||
mdh1418 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
mdh1418 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| return 100; | ||
| } | ||
|
|
||
| private static bool ValidateTraceeEvents(string traceFilePath) | ||
| { | ||
| string etlxPath = TraceLog.CreateFromEventPipeDataFile(traceFilePath); | ||
|
||
| using TraceLog log = new(etlxPath); | ||
| using TraceLogEventSource source = log.Events.GetSource(); | ||
| bool startEventFound = false; | ||
| bool stopEventFound = false; | ||
|
|
||
| source.AllEvents += (TraceEvent e) => | ||
|
||
| { | ||
| if (e.ProviderName == "Microsoft-Windows-DotNETRuntime") | ||
| { | ||
| if (e.EventName == "GC/Start") | ||
| { | ||
| startEventFound = true; | ||
| } | ||
| else if (e.EventName == "GC/Stop") | ||
| { | ||
| stopEventFound = true; | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| source.Process(); | ||
| return startEventFound && stopEventFound; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <CLRTestTargetUnsupported Condition="'$(TargetOS)' != 'linux' or ('$(TargetArchitecture)' != 'x64' and '$(TargetArchitecture)' != 'arm64')">true</CLRTestTargetUnsupported> | ||
| <RequiresProcessIsolation>true</RequiresProcessIsolation> | ||
| <ReferenceXUnitWrapperGenerator>false</ReferenceXUnitWrapperGenerator> | ||
| <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier> | ||
|
||
| <IlasmRoundTripIncompatible>true</IlasmRoundTripIncompatible> | ||
| <MicrosoftOneCollectRecordTraceVersion>0.1.32221</MicrosoftOneCollectRecordTraceVersion> | ||
|
||
| </PropertyGroup> | ||
|
|
||
| <PropertyGroup> | ||
| <RestoreAdditionalProjectSources>$(RestoreAdditionalProjectSources);https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-diagnostics-tests/nuget/v3/index.json</RestoreAdditionalProjectSources> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.OneCollect.RecordTrace" Version="$(MicrosoftOneCollectRecordTraceVersion)" PrivateAssets="All" Condition="'$(TargetOS)' == 'linux'" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <Compile Include="$(MSBuildProjectName).cs" /> | ||
| <Compile Include="usereventstracee.cs" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <None Include="dotnet-common.script" CopyToOutputDirectory="PreserveNewest" /> | ||
| </ItemGroup> | ||
|
|
||
| <Target Name="CopyRecordTraceBinary" AfterTargets="Build" Condition="'$(TargetOS)' == 'linux'"> | ||
| <PropertyGroup> | ||
| <RecordTracePath>$(NuGetPackageRoot)microsoft.onecollect.recordtrace/$(MicrosoftOneCollectRecordTraceVersion)/runtimes/$(TargetOS)-$(TargetArchitecture)/native/record-trace</RecordTracePath> | ||
| </PropertyGroup> | ||
|
|
||
| <Copy SourceFiles="$(RecordTracePath)" DestinationFolder="$(OutputPath)" Condition="Exists('$(RecordTracePath)')" /> | ||
| <Error Text="record-trace not found at $(RecordTracePath)" Condition="!Exists('$(RecordTracePath)')" /> | ||
| </Target> | ||
| </Project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System; | ||
| using System.Diagnostics; | ||
| using System.Threading; | ||
|
|
||
| namespace Tracing.Tests.UserEvents | ||
| { | ||
| public class UserEventsTracee | ||
| { | ||
| private static byte[] s_array; | ||
|
|
||
| public static void Run() | ||
| { | ||
| long startTimestamp = Stopwatch.GetTimestamp(); | ||
| long targetTicks = Stopwatch.Frequency * 10; // 10s | ||
|
||
|
|
||
| while (Stopwatch.GetTimestamp() - startTimestamp < targetTicks) | ||
| { | ||
| for (int i = 0; i < 100; i++) | ||
| { | ||
| s_array = new byte[1024 * 10]; | ||
| } | ||
|
|
||
| GC.Collect(); | ||
| Thread.Sleep(100); | ||
| } | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.