-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Move EventPipe environment variable parsing logic to native code #32516
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
Merged
sywhang
merged 22 commits into
dotnet:master
from
sywhang:dev/suwhang/move-eventpipe-envvar-parsing
Mar 4, 2020
Merged
Changes from 3 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
967e672
Move environment variable parsing logic to native code
sywhang 7b5e97f
Fix multiple provider issue
sywhang 5df4b8d
Merging with master
sywhang d2a787b
Use env vars to set up eventpipe config
sywhang 9d2f0b8
Add default provider configuration if eventpipeconfig is not set
sywhang f2a9138
Remove EventPipeController
sywhang 73dbabd
Add Argument parsing logic to XplatEventLoggerConfiguration
sywhang 6098b6c
cleanup
sywhang d845bb0
Fix Linux build
sywhang 6515b7b
Check provider configuration before enabling them
sywhang 63a4a46
wrap new code under ifdef, put EventPipeController back
sywhang 217fbd3
pr feedback
sywhang bba1446
fix x86 build
sywhang d1632c5
fix typo
sywhang 75a5325
Fix loop condition
sywhang 0bbcaea
ifdef out call to EnableViaEnvironmentVariables()
sywhang 878e0f4
Use CLRConfigStringHolder
sywhang 8fcf438
pr comments
sywhang e6fa99d
Merge branch 'master' into dev/suwhang/move-eventpipe-envvar-parsing
sywhang fc849a6
Fix merge conflict
sywhang eee8f0e
Merge branch 'dev/suwhang/move-eventpipe-envvar-parsing' of github.co…
sywhang 3b0f1a8
use NewHolder to avoid leak
sywhang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
221 changes: 221 additions & 0 deletions
221
...coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipeController.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,221 @@ | ||
| // 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. | ||
| #if FEATURE_PERFTRACING | ||
| using System.IO; | ||
| using System.Reflection; | ||
| using System.Runtime.Versioning; | ||
|
|
||
| namespace System.Diagnostics.Tracing | ||
| { | ||
| /// <summary> | ||
| /// Simple out-of-process listener for controlling EventPipe. | ||
| /// The following environment variables are used to configure EventPipe: | ||
| /// - COMPlus_EnableEventPipe=1 : Enable EventPipe immediately for the life of the process. | ||
| /// - COMPlus_EventPipeConfig : Provides the configuration in xperf string form for which providers/keywords/levels to be enabled. | ||
| /// If not specified, the default configuration is used. | ||
| /// - COMPlus_EventPipeOutputFile : The full path to the netperf file to be written. | ||
| /// - COMPlus_EventPipeCircularMB : The size in megabytes of the circular buffer. | ||
| /// </summary> | ||
| internal static class EventPipeController | ||
| { | ||
| // Miscellaneous constants. | ||
| private const string DefaultAppName = "app"; | ||
| private const string NetPerfFileExtension = ".netperf"; | ||
| private const string NetTraceFileExtension = ".nettrace"; | ||
| private const uint DefaultCircularBufferMB = 256; // MB (PerfView and dotnet-trace default) | ||
| private const char ProviderConfigDelimiter = ','; | ||
| private const char ConfigComponentDelimiter = ':'; | ||
|
|
||
| // The default set of providers/keywords/levels. Used if an alternative configuration is not specified. | ||
| private static EventPipeProviderConfiguration[] DefaultProviderConfiguration => new EventPipeProviderConfiguration[] | ||
| { | ||
| new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntime", 0x4c14fccbd, 5, null), | ||
| new EventPipeProviderConfiguration("Microsoft-Windows-DotNETRuntimePrivate", 0x4002000b, 5, null), | ||
| new EventPipeProviderConfiguration("Microsoft-DotNETCore-SampleProfiler", 0x0, 5, null), | ||
| }; | ||
|
|
||
| private static bool IsControllerInitialized { get; set; } = false; | ||
|
|
||
| internal static void Initialize() | ||
| { | ||
| // Don't allow failures to propagate upstream. Ensure program correctness without tracing. | ||
| try | ||
| { | ||
| if (!IsControllerInitialized) | ||
| { | ||
| if (Config_EnableEventPipe > 0) | ||
| { | ||
| // Enable tracing immediately. | ||
| // It will be disabled automatically on shutdown. | ||
| EventPipe.Enable(BuildConfigFromEnvironment()); | ||
| } | ||
|
|
||
| RuntimeEventSource.Initialize(); | ||
|
|
||
| IsControllerInitialized = true; | ||
| } | ||
| } | ||
| catch { } | ||
| } | ||
|
|
||
| private static EventPipeConfiguration BuildConfigFromEnvironment() | ||
| { | ||
| // Build the full path to the trace file. | ||
| string traceFileName = BuildTraceFileName(); | ||
| string outputFilePath = Path.Combine(Config_EventPipeOutputPath, traceFileName); | ||
|
|
||
| // Create a new configuration object. | ||
| EventPipeConfiguration config = new EventPipeConfiguration( | ||
| outputFilePath, | ||
| (Config_NetTraceFormat != 0) ? EventPipeSerializationFormat.NetTrace : EventPipeSerializationFormat.NetPerf, | ||
| Config_EventPipeCircularMB); | ||
|
|
||
| // Get the configuration. | ||
| string? strConfig = Config_EventPipeConfig; | ||
| if (!string.IsNullOrEmpty(strConfig)) | ||
| { | ||
| // If the configuration is specified, parse it and save it to the config object. | ||
| SetProviderConfiguration(strConfig, config); | ||
| } | ||
| else | ||
| { | ||
| // Specify the default configuration. | ||
| config.EnableProviderRange(DefaultProviderConfiguration); | ||
| } | ||
|
|
||
| return config; | ||
| } | ||
|
|
||
| private static string BuildTraceFileName() | ||
| { | ||
| return GetAppName() + "." + Interop.GetCurrentProcessId().ToString() + | ||
| ((Config_NetTraceFormat != 0) ? NetTraceFileExtension : NetPerfFileExtension); | ||
| } | ||
|
|
||
| private static string GetAppName() | ||
| { | ||
| string? appName = null; | ||
| Assembly? entryAssembly = Assembly.GetEntryAssembly(); | ||
| if (entryAssembly != null) | ||
| { | ||
| AssemblyName? assemblyName = entryAssembly.GetName(); | ||
| if (assemblyName != null) | ||
| { | ||
| appName = assemblyName.Name; | ||
| } | ||
| } | ||
|
|
||
| if (string.IsNullOrEmpty(appName)) | ||
| { | ||
| appName = DefaultAppName; | ||
| } | ||
|
|
||
| return appName; | ||
| } | ||
|
|
||
| private static void SetProviderConfiguration(string strConfig, EventPipeConfiguration config) | ||
| { | ||
| if (string.IsNullOrEmpty(strConfig)) | ||
| { | ||
| throw new ArgumentNullException(nameof(strConfig)); | ||
| } | ||
|
|
||
| // Provider format: "(GUID|KnownProviderName)[:Flags[:Level][:KeyValueArgs]]" | ||
| // where KeyValueArgs are of the form: "[key1=value1][;key2=value2]" | ||
| // `strConfig` must be of the form "Provider[,Provider]" | ||
| string[] providers = strConfig.Split( | ||
| ProviderConfigDelimiter, | ||
| StringSplitOptions.RemoveEmptyEntries); // Remove "empty" providers. | ||
| foreach (string provider in providers) | ||
| { | ||
| // Split expecting a maximum of four tokens. | ||
| string[] components = provider.Split( | ||
| ConfigComponentDelimiter, | ||
| 4, // if there is ':' in the parameters then anything after it will not be ignored. | ||
| StringSplitOptions.None); // Keep empty tokens | ||
|
|
||
| string? providerName = components.Length > 0 ? components[0] : null; | ||
| if (string.IsNullOrEmpty(providerName)) | ||
| continue; // No provider name specified. | ||
|
|
||
| ulong keywords = ulong.MaxValue; | ||
| if (components.Length > 1) | ||
| { | ||
| // We use a try/catch block here because ulong.TryParse won't accept 0x at the beginning | ||
| // of a hex string. Thus, we either need to conditionally strip it or handle the exception. | ||
| // Given that this is not a perf-critical path, catching the exception is the simpler code. | ||
| try | ||
| { | ||
| keywords = Convert.ToUInt64(components[1], 16); | ||
| } | ||
| catch | ||
| { | ||
| } | ||
| } | ||
|
|
||
| uint level = 5; // Verbose | ||
| if (components.Length > 2) | ||
| { | ||
| uint.TryParse(components[2], out level); | ||
| } | ||
|
|
||
| string? filterData = components.Length > 3 ? components[3] : null; | ||
|
|
||
| config.EnableProviderWithFilter(providerName, keywords, level, filterData); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns -1 if the EnableEventPipe environment variable is not set at all (or is illegal) | ||
| /// </summary> | ||
| private static int Config_EnableEventPipe | ||
| { | ||
| get | ||
| { | ||
| string? stringValue = CompatibilitySwitch.GetValueInternal("EnableEventPipe"); | ||
| if ((stringValue == null) || (!int.TryParse(stringValue, out int value))) | ||
| { | ||
| value = -1; // Indicates no value (or is illegal) | ||
| } | ||
|
|
||
| return value; | ||
| } | ||
| } | ||
|
|
||
| private static int Config_NetTraceFormat | ||
| { | ||
| get | ||
| { | ||
| string? stringValue = CompatibilitySwitch.GetValueInternal("EventPipeNetTraceFormat"); | ||
| if ((stringValue == null) || (!int.TryParse(stringValue, out int value))) | ||
| { | ||
| value = -1; // Indicates no value (or is illegal) | ||
| } | ||
|
|
||
| return value; | ||
| } | ||
| } | ||
|
|
||
| private static string? Config_EventPipeConfig => CompatibilitySwitch.GetValueInternal("EventPipeConfig"); | ||
|
|
||
| private static uint Config_EventPipeCircularMB | ||
| { | ||
| get | ||
| { | ||
| string? stringValue = CompatibilitySwitch.GetValueInternal("EventPipeCircularMB"); | ||
| if ((stringValue == null) || (!uint.TryParse(stringValue, out uint value))) | ||
| { | ||
| value = DefaultCircularBufferMB; | ||
| } | ||
|
|
||
| return value; | ||
| } | ||
| } | ||
|
|
||
| private static string Config_EventPipeOutputPath => | ||
| CompatibilitySwitch.GetValueInternal("EventPipeOutputPath") ?? "."; | ||
| } | ||
| } | ||
|
|
||
| #endif // FEATURE_PERFTRACING |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.