in src/PerfView/CommandProcessor.cs [304:999]
public void Start(CommandLineArgs parsedArgs)
{
LaunchPerfViewElevatedIfNeeded("Start", parsedArgs);
// Are we on an X86 machine?
if (Environment.Is64BitOperatingSystem)
{
if (!IsKernelStacks64Enabled())
{
var ver = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor;
if (ver <= 61)
{
LogFile.WriteLine("Warning: This trace is being collected on a X64 machine on a Pre Win8 OS");
LogFile.WriteLine(" And paging is allowed in the kernel. This can cause stack breakage");
LogFile.WriteLine(" when samples are taken in the kernel and there is memory pressure.");
LogFile.WriteLine(" It is recommended that you disable paging in the kernel to decrease");
LogFile.WriteLine(" the number of broken stacks. To do this run the command:");
LogFile.WriteLine("");
LogFile.WriteLine(" PerfView EnableKernelStacks ");
LogFile.WriteLine("");
LogFile.WriteLine(" A reboot will be required for the change to have an effect.");
LogFile.WriteLine("");
}
}
}
ETWClrProfilerTraceEventParser.Keywords profilerKeywords = 0;
if (parsedArgs.DotNetCalls)
{
profilerKeywords |= ETWClrProfilerTraceEventParser.Keywords.Call;
}
if (parsedArgs.DotNetCallsSampled)
{
profilerKeywords |= ETWClrProfilerTraceEventParser.Keywords.CallSampled;
}
if (parsedArgs.DotNetAlloc)
{
profilerKeywords |= ETWClrProfilerTraceEventParser.Keywords.GCAlloc;
}
if (parsedArgs.DotNetAllocSampled)
{
profilerKeywords |= ETWClrProfilerTraceEventParser.Keywords.GCAllocSampled;
}
if (parsedArgs.DisableInlining)
{
profilerKeywords |= ETWClrProfilerTraceEventParser.Keywords.DisableInlining;
}
if (parsedArgs.RuntimeLoading)
{
parsedArgs.ClrEvents |= ClrTraceEventParser.Keywords.CompilationDiagnostic;
parsedArgs.ClrEvents |= ClrTraceEventParser.Keywords.MethodDiagnostic;
parsedArgs.ClrEvents |= ClrTraceEventParser.Keywords.TypeDiagnostic;
}
if (profilerKeywords != 0)
{
InstallETWClrProfiler(LogFile, (int)profilerKeywords);
LogFile.WriteLine("WARNING: Only processes that start after this point will log object allocation events.");
}
if (parsedArgs.DataFile == null)
{
parsedArgs.DataFile = "PerfViewData.etl";
}
// The DataFile does not have the .zip associated with it (it is implied)
if (parsedArgs.DataFile.EndsWith(".etl.zip", StringComparison.OrdinalIgnoreCase))
{
parsedArgs.DataFile = parsedArgs.DataFile.Substring(0, parsedArgs.DataFile.Length - 4);
}
else if(!parsedArgs.DataFile.EndsWith(".etl"))
{
parsedArgs.DataFile = parsedArgs.DataFile + ".etl";
}
// Don't clobber the results file if we were told not to.
if (parsedArgs.CollectMultiple > 1)
{
var finalResultFile = parsedArgs.DataFile;
if (parsedArgs.ShouldZip)
{
finalResultFile = finalResultFile + ".zip";
}
finalResultFile = GetNewFile(finalResultFile);
if (parsedArgs.ShouldZip)
{
finalResultFile = finalResultFile.Substring(0, finalResultFile.Length - 4);
}
parsedArgs.DataFile = finalResultFile;
}
string zipFileName = Path.ChangeExtension(parsedArgs.DataFile, ".etl.zip");
string userFileName = Path.ChangeExtension(parsedArgs.DataFile, ".etl");
string kernelFileName = Path.ChangeExtension(parsedArgs.DataFile, ".kernel.etl");
string heapFileName = Path.ChangeExtension(parsedArgs.DataFile, ".userheap.etl");
string rundownFileName = Path.ChangeExtension(parsedArgs.DataFile, ".clrRundown.etl");
string kernelRundownFileName = Path.ChangeExtension(parsedArgs.DataFile, ".kernelRundown.etl");
// Ensure that old data is gone
var fileNames = new string[] { zipFileName, userFileName, kernelFileName, heapFileName, rundownFileName, kernelRundownFileName };
try
{
foreach (var fileName in fileNames)
{
FileUtilities.ForceDelete(fileName);
}
}
catch (IOException)
{
LogFile.WriteLine("Files in use, aborting and trying again.");
Abort(parsedArgs);
foreach (var fileName in fileNames)
{
FileUtilities.ForceDelete(fileName);
}
}
if (parsedArgs.Wpr)
{
// Just creating this directory is enough for the rest to 'just work'
var ngenPdbs = parsedArgs.DataFile + ".ngenpdb";
LogFile.WriteLine("Putting NGEN pdbs into {0}", ngenPdbs);
Directory.CreateDirectory(ngenPdbs);
}
CollectingData = true;
// Create the sessions
if (parsedArgs.InMemoryCircularBuffer)
{
kernelFileName = null; // In memory buffers dont have a file name
}
else
{
LogFile.WriteLine("[Kernel Log: {0}]", Path.GetFullPath(kernelFileName));
}
using (TraceEventSession kernelModeSession = new TraceEventSession(s_KernelessionName, kernelFileName))
{
if (parsedArgs.CpuCounters != null)
{
SetCpuCounters(parsedArgs.CpuCounters);
parsedArgs.KernelEvents |= KernelTraceEventParser.Keywords.PMCProfile;
}
else
{
if ((parsedArgs.KernelEvents & KernelTraceEventParser.Keywords.PMCProfile) != 0)
{
throw new ApplicationException("The PMCProfile should not be set explicitly. Simply set the CpuCounters.");
}
}
LogFile.WriteLine("Kernel keywords enabled: {0}", parsedArgs.KernelEvents);
if (parsedArgs.KernelEvents != KernelTraceEventParser.Keywords.None)
{
if ((parsedArgs.KernelEvents & (KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.ImageLoad)) == 0 &&
(parsedArgs.KernelEvents & (KernelTraceEventParser.Keywords.Profile | KernelTraceEventParser.Keywords.ContextSwitch)) != 0)
{
LogFile.WriteLine("Kernel process and image thread events not present, adding them");
parsedArgs.KernelEvents |= (
KernelTraceEventParser.Keywords.Process |
KernelTraceEventParser.Keywords.ImageLoad |
KernelTraceEventParser.Keywords.Thread);
}
// If these are on, turn on Virtual Allocs as well.
if (parsedArgs.OSHeapProcess != 0 || parsedArgs.OSHeapExe != null || parsedArgs.DotNetAlloc || parsedArgs.DotNetAllocSampled)
{
parsedArgs.KernelEvents |= KernelTraceEventParser.Keywords.VirtualAlloc;
}
kernelModeSession.BufferSizeMB = parsedArgs.BufferSizeMB;
kernelModeSession.StackCompression = parsedArgs.StackCompression;
kernelModeSession.CpuSampleIntervalMSec = parsedArgs.CpuSampleMSec;
if (parsedArgs.CircularMB != 0)
{
kernelModeSession.CircularBufferMB = parsedArgs.CircularMB;
}
kernelModeSession.EnableKernelProvider(parsedArgs.KernelEvents, parsedArgs.KernelEvents);
}
// Turn on the OS Heap stuff if anyone asked for it.
TraceEventSession heapSession = null;
if (parsedArgs.OSHeapProcess != 0 || parsedArgs.OSHeapExe != null)
{
if (parsedArgs.OSHeapProcess != 0 && parsedArgs.OSHeapExe != null)
{
throw new ApplicationException("OSHeapProcess and OSHeapExe cannot both be specified simultaneously.");
}
heapSession = new TraceEventSession(s_HeapSessionName, heapFileName);
// Default is 256Meg and twice whatever the others are
heapSession.BufferSizeMB = Math.Max(256, parsedArgs.BufferSizeMB * 2);
if (parsedArgs.CircularMB != 0)
{
LogFile.WriteLine("[Warning: OS Heap provider does not use Circular buffering.]");
}
if (parsedArgs.OSHeapProcess != 0)
{
heapSession.EnableWindowsHeapProvider(parsedArgs.OSHeapProcess);
LogFile.WriteLine("[Enabling heap logging for process {0} to : {1}]", parsedArgs.OSHeapProcess, Path.GetFullPath(heapFileName));
}
else
{
parsedArgs.OSHeapExe = Path.ChangeExtension(parsedArgs.OSHeapExe, ".exe");
heapSession.EnableWindowsHeapProvider(parsedArgs.OSHeapExe);
LogFile.WriteLine("[Enabling heap logging for process with EXE {0} to : {1}]", parsedArgs.OSHeapExe, Path.GetFullPath(heapFileName));
}
}
if (parsedArgs.InMemoryCircularBuffer)
{
userFileName = null; // In memory buffers don't have a file name
}
else
{
LogFile.WriteLine("[User mode Log: {0}]", Path.GetFullPath(userFileName));
}
using (TraceEventSession userModeSession = new TraceEventSession(s_UserModeSessionName, userFileName))
{
TraceEventProviderOptions options = new TraceEventProviderOptions();
if (parsedArgs.FocusProcess != null)
{
int processId;
if (Int32.TryParse(parsedArgs.FocusProcess, out processId))
{
options.ProcessIDFilter = new List<int>(1) { processId };
LogFile.WriteLine("**** /FocusProcess specified LIMITING user mode events to process with ID {0}", processId);
}
else
{
if (!parsedArgs.FocusProcess.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
LogFile.WriteLine("**** WARNING: process name does not end in .exe, likely you will exclude processes of interest");
LogFile.WriteLine("**** /FocusProcess specified LIMITING user mode events to process with name {0}", parsedArgs.FocusProcess);
options.ProcessNameFilter = new List<string>(1) { parsedArgs.FocusProcess };
}
}
if (parsedArgs.EnableEventsInContainers)
{
options.EnableInContainers = true;
}
if (parsedArgs.EnableSourceContainerTracking)
{
options.EnableSourceContainerTracking = true;
}
var stacksEnabled = options.Clone();
stacksEnabled.StacksEnabled = true;
userModeSession.BufferSizeMB = parsedArgs.BufferSizeMB;
// DotNetAlloc needs a large buffer size too.
if (parsedArgs.DotNetAlloc || parsedArgs.DotNetCalls)
{
userModeSession.BufferSizeMB = Math.Max(512, parsedArgs.BufferSizeMB * 2);
}
// Note that you don't need the rundown 300Meg if you are V4.0.
if (parsedArgs.CircularMB != 0)
{
// Typically you only need less than 1/5 the space + rundown. However, some scenarios primarily
// use the user mode session so we keep it the full size.
userModeSession.CircularBufferMB = parsedArgs.CircularMB + 300;
}
// Turn on PerfViewLogger
EnableUserProvider(userModeSession, "PerfViewLogger", PerfViewLogger.Log.Guid,
TraceEventLevel.Verbose, ulong.MaxValue, options);
Thread.Sleep(100); // Give it at least some time to start, it is not synchronous.
PerfViewLogger.Log.StartTracing();
PerfViewLogger.StartTime = DateTime.UtcNow;
PerfViewLogger.Log.SessionParameters(s_KernelessionName, kernelFileName ?? "",
kernelModeSession.BufferSizeMB, kernelModeSession.CircularBufferMB);
PerfViewLogger.Log.KernelEnableParameters(parsedArgs.KernelEvents, parsedArgs.KernelEvents);
PerfViewLogger.Log.SessionParameters(s_UserModeSessionName, userFileName ?? "",
userModeSession.BufferSizeMB, userModeSession.CircularBufferMB);
// If you turn on allocation sampling, then you also need the types and names and deaths.
if ((parsedArgs.ClrEvents & (ClrTraceEventParser.Keywords.GCSampledObjectAllocationHigh | ClrTraceEventParser.Keywords.GCSampledObjectAllocationLow)) != 0)
{
parsedArgs.ClrEvents |= ClrTraceEventParser.Keywords.Type | ClrTraceEventParser.Keywords.GCHeapSurvivalAndMovement;
}
if (parsedArgs.Wpr)
{
SetWPRProviders(userModeSession, options);
}
else if (parsedArgs.ClrEvents != ClrTraceEventParser.Keywords.None)
{
// If we don't change the core set then we should assume the user wants more stuff.
var coreClrEvents = ClrTraceEventParser.Keywords.Default &
~ClrTraceEventParser.Keywords.NGen & ~ClrTraceEventParser.Keywords.SupressNGen;
if ((parsedArgs.ClrEvents & coreClrEvents) == coreClrEvents)
{
LogFile.WriteLine("Turning on more CLR GC, JScript and ASP.NET Events.");
// Turn on DotNet Telemetry
EnableUserProvider(userModeSession, "DotNet",
new Guid("319dc449-ada5-50f7-428e-957db6791668"), TraceEventLevel.Verbose, ulong.MaxValue, stacksEnabled);
// Turn on ETW logging about etw logging (so we get lost event info) ... (Really need a separate session to get the lost event Info properly).
EnableUserProvider(userModeSession, "Microsoft-Windows-Kernel-EventTracing",
new Guid("B675EC37-BDB6-4648-BC92-F3FDC74D3CA2"), TraceEventLevel.Verbose, 0x70, stacksEnabled);
// Turn on File Create (open) logging as it is useful for investigations and lightweight.
// Don't bother if the Kernel FileIOInit events are on because they are strictly better
// and you end up with annoying redundancy.
if ((parsedArgs.KernelEvents & KernelTraceEventParser.Keywords.FileIOInit) == 0)
{
// 0x80 = CREATE_FILE (which is any open, including GetFileAttributes etc.
EnableUserProvider(userModeSession, "Microsoft-Windows-Kernel-File",
new Guid("EDD08927-9CC4-4E65-B970-C2560FB5C289"), TraceEventLevel.Verbose, 0x80, stacksEnabled);
}
// Turn on the user-mode Process start events. This allows you to get the stack of create-process calls
// 0x10 = Process
EnableUserProvider(userModeSession, "Microsoft-Windows-Kernel-Process",
new Guid("22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716"), TraceEventLevel.Informational, 0x10, stacksEnabled);
// Default CLR events also means ASP.NET and private events.
// Turn on ASP.NET at informational by default.
EnableUserProvider(userModeSession, "ASP.NET", AspNetTraceEventParser.ProviderGuid,
parsedArgs.ClrEventLevel, ulong.MaxValue - 0x2, options); // the - 0x2 will turn off Module level logging, which is very verbose
CheckAndWarnAboutAspNet(AspNetTraceEventParser.ProviderGuid);
// Turn on the new V4.5.1 ASP.Net EventSource (TODO Not clear we should do this, and how much to turn on).
// TODO turned on stacks for debugging probably should turn off in the long run.
EnableUserProvider(userModeSession, "*Microsoft-Windows-ASPNET",
new Guid("ee799f41-cfa5-550b-bf2c-344747c1c668"), TraceEventLevel.Informational, ulong.MaxValue, stacksEnabled);
// Turn on just minimum (start and stop) for IIS)
EnableUserProvider(userModeSession, "Microsoft-Windows-IIS",
new Guid("DE4649C9-15E8-4FEA-9D85-1CDDA520C334"), TraceEventLevel.Critical, 0, options);
// These let you see IE in and have few events.
EnableUserProvider(userModeSession, "Microsoft-PerfTrack-IEFRAME",
new Guid("B2A40F1F-A05A-4DFD-886A-4C4F18C4334C"), TraceEventLevel.Verbose, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-PerfTrack-MSHTML",
new Guid("FFDB9886-80F3-4540-AA8B-B85192217DDF"), TraceEventLevel.Verbose, ulong.MaxValue, options);
// Set you see the URLs that IE is processing.
EnableUserProvider(userModeSession, "Microsoft-Windows-WinINet",
new Guid("43D1A55C-76D6-4F7E-995C-64C711E5CAFE"), TraceEventLevel.Verbose, 2, options);
// Turn on WCF. This can be very verbose. We need to figure out a balance
EnableUserProvider(userModeSession, "Microsoft-Windows-Application Server-Applications",
ApplicationServerTraceEventParser.ProviderGuid, TraceEventLevel.Informational, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-IE",
new Guid("9E3B3947-CA5D-4614-91A2-7B624E0E7244"), TraceEventLevel.Informational, 0x1300, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-DNS-Client",
new Guid("1C95126E-7EEA-49A9-A3FE-A378B03DDB4D"), TraceEventLevel.Informational, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-DirectComposition",
new Guid("C44219D0-F344-11DF-A5E2-B307DFD72085"), TraceEventLevel.Verbose, 0x4, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-Immersive-Shell",
new Guid("315A8872-923E-4EA2-9889-33CD4754BF64"), TraceEventLevel.Informational, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-XAML",
new Guid("531A35AB-63CE-4BCF-AA98-F88C7A89E455"), TraceEventLevel.Informational, ulong.MaxValue, options);
// Turn on JScript events too
EnableUserProvider(userModeSession, "Microsoft-JScript", JScriptTraceEventParser.ProviderGuid,
TraceEventLevel.Verbose, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "CLRPrivate", ClrPrivateTraceEventParser.ProviderGuid,
TraceEventLevel.Informational,
(ulong)(
ClrPrivateTraceEventParser.Keywords.GC |
ClrPrivateTraceEventParser.Keywords.Binding |
ClrPrivateTraceEventParser.Keywords.Fusion |
ClrPrivateTraceEventParser.Keywords.MulticoreJit | /* only works on verbose */
// ClrPrivateTraceEventParser.Keywords.LoaderHeap | /* only verbose */
// ClrPrivateTraceEventParser.Keywords.Startup
ClrPrivateTraceEventParser.Keywords.Stack
), options);
if (parsedArgs.TplEvents != TplEtwProviderTraceEventParser.Keywords.None)
{
// Used to determine what is going on with tasks.
var netTaskStacks = stacksEnabled;
if (TraceEventProviderOptions.FilteringSupported)
{
// This turns on stacks only for TaskScheduled (7) TaskWaitSend (10) and AwaitTaskContinuationScheduled (12)
netTaskStacks = options.Clone();
netTaskStacks.EventIDStacksToEnable = new List<int>(3) { 7, 10, 12 };
}
EnableUserProvider(userModeSession, ".NETTasks",
TplEtwProviderTraceEventParser.ProviderGuid, parsedArgs.ClrEventLevel,
(ulong)parsedArgs.TplEvents,
netTaskStacks);
}
EnableUserProvider(userModeSession, ".NETFramework",
FrameworkEventSourceTraceEventParser.ProviderGuid,
parsedArgs.ClrEventLevel,
(ulong)(
FrameworkEventSourceTraceEventParser.Keywords.ThreadPool |
FrameworkEventSourceTraceEventParser.Keywords.ThreadTransfer |
FrameworkEventSourceTraceEventParser.Keywords.NetClient),
stacksEnabled);
// Turn on the Nuget package provider that tracks activity IDs.
EnableUserProvider(userModeSession, "Microsoft.Tasks.Nuget", TraceEventProviders.GetEventSourceGuidFromName("Microsoft.Tasks.Nuget"), TraceEventLevel.Informational, 0x80, options);
// Turn on new SQL client logging
EnableUserProvider(userModeSession, "Microsoft-AdoNet-SystemData",
TraceEventProviders.GetEventSourceGuidFromName("Microsoft-AdoNet-SystemData"),
TraceEventLevel.Informational,
1, // This enables just the client events.
stacksEnabled);
EnableUserProvider(userModeSession, "ETWCLrProfiler Diagnostics",
new Guid(unchecked((int)0x6652970f), unchecked((short)0x1756), unchecked((short)0x5d8d), 0x08, 0x05, 0xe9, 0xaa, 0xd1, 0x52, 0xaa, 0x79),
TraceEventLevel.Verbose, ulong.MaxValue, options);
// TODO should we have stacks on for everything?
var diagSourceOptions = stacksEnabled.Clone();
// The removal of IgnoreShortCutKeywords turns on HTTP incoming and SQL events
// The spec below turns on outgoing Http requests.
string filterSpec =
"HttpHandlerDiagnosticListener/System.Net.Http.Request@Activity2Start:" +
"Request.RequestUri" +
"\n" +
"HttpHandlerDiagnosticListener/System.Net.Http.Response@Activity2Stop:" +
"Response.StatusCode";
diagSourceOptions.AddArgument("FilterAndPayloadSpecs", filterSpec);
const ulong IgnoreShortCutKeywords = 0x0800; // Turing this OFF enables all the shortcut keywords (ASP.NET and Entity Framework).
EnableUserProvider(userModeSession, "Microsoft-Diagnostics-DiagnosticSource",
new Guid("adb401e1-5296-51f8-c125-5fda75826144"),
TraceEventLevel.Informational, ulong.MaxValue - IgnoreShortCutKeywords, diagSourceOptions);
// This is likely redundant with the diagnosticSource above, but is simpler to parse on the reader side.
EnableUserProvider(userModeSession, "Microsoft-AspNetCore-Hosting",
new Guid("9e620d2a-55d4-5ade-deb7-c26046d245a8"), TraceEventLevel.Verbose, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-ApplicationInsights-Core",
new Guid("74af9f20-af6a-5582-9382-f21f674fb271"),
TraceEventLevel.Verbose, ulong.MaxValue, stacksEnabled);
// Turn on Power stuff
EnableUserProvider(userModeSession, "Microsoft-Windows-Kernel-Power",
new Guid("331C3B3A-2005-44C2-AC5E-77220C37D6B4"), TraceEventLevel.Informational, 0xFFB, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-Kernel-Processor-Power",
new Guid("0F67E49F-FE51-4E9F-B490-6F2948CC6027"), TraceEventLevel.Informational, 0xE5D, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-PowerCpl",
new Guid("B1F90B27-4551-49D6-B2BD-DFC6453762A6"), TraceEventLevel.Informational, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-PowerCfg",
new Guid("9F0C4EA8-EC01-4200-A00D-B9701CBEA5D8"), TraceEventLevel.Informational, ulong.MaxValue, options);
// If we have turned on CSwitch and ReadyThread events, go ahead and turn on networking stuff and antimalware too.
// It does not increase the volume in a significant way and they can be pretty useful.
if ((parsedArgs.KernelEvents & (KernelTraceEventParser.Keywords.Dispatcher | KernelTraceEventParser.Keywords.ContextSwitch))
== (KernelTraceEventParser.Keywords.Dispatcher | KernelTraceEventParser.Keywords.ContextSwitch))
{
EnableUserProvider(userModeSession, MicrosoftAntimalwareEngineTraceEventParser.ProviderName,
MicrosoftAntimalwareEngineTraceEventParser.ProviderGuid,
TraceEventLevel.Verbose, ulong.MaxValue, stacksEnabled);
EnableUserProvider(userModeSession, MicrosoftAntimalwareAMFilterTraceEventParser.ProviderName,
MicrosoftAntimalwareAMFilterTraceEventParser.ProviderGuid,
TraceEventLevel.Verbose, ulong.MaxValue, stacksEnabled);
EnableUserProvider(userModeSession, "Microsoft-Antimalware-Service",
new Guid("751ef305-6c6e-4fed-b847-02ef79d26aef"),
TraceEventLevel.Verbose, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-Antimalware-RTP",
new Guid("8e92deef-5e17-413b-b927-59b2f06a3cfc"),
TraceEventLevel.Verbose, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-Antimalware-Protection",
new Guid("e4b70372-261f-4c54-8fa6-a5a7914d73da"),
TraceEventLevel.Verbose, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-HttpService",
new Guid("DD5EF90A-6398-47A4-AD34-4DCECDEF795F"),
parsedArgs.ClrEventLevel, ulong.MaxValue, stacksEnabled);
// TODO this can be expensive. turned it down (not clear what we lose).
EnableUserProvider(userModeSession, "Microsoft-Windows-TCPIP",
new Guid("2F07E2EE-15DB-40F1-90EF-9D7BA282188A"), TraceEventLevel.Informational, ulong.MaxValue, stacksEnabled);
// This actually will not cause any events to fire unless you first also enable
// the kernel in a special way. Basically doing
// netsh trace start scenario=InternetClient capture=yes correlation=no report=disabled maxSize=250 traceFile=NetMonTrace.net.etl
EnableUserProvider(userModeSession, "Microsoft-Windows-NDIS-PacketCapture",
new Guid("2ED6006E-4729-4609-B423-3EE7BCD678EF"),
TraceEventLevel.Informational, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-WebIO",
new Guid("50B3E73C-9370-461D-BB9F-26F32D68887D"), TraceEventLevel.Informational, ulong.MaxValue, options);
// This provider is verbose in high volume networking scnearios and its value is dubious.
//EnableUserProvider(userModeSession, "Microsoft-Windows-Winsock-AFD",
// new Guid("E53C6823-7BB8-44BB-90DC-3F86090D48A6"),
// parsedArgs.ClrEventLevel, ulong.MaxValue);
// This is probably too verbose, but we will see
EnableUserProvider(userModeSession, "Microsoft-Windows-WinINet",
new Guid("43D1A55C-76D6-4F7E-995C-64C711E5CAFE"), TraceEventLevel.Verbose, ulong.MaxValue, options);
// This is probably too verbose, but we will see
EnableUserProvider(userModeSession, "Microsoft-Windows-WinHttp",
new Guid("7D44233D-3055-4B9C-BA64-0D47CA40A232"), TraceEventLevel.Verbose, ulong.MaxValue, options);
// This has proven to be too expensive. Wait until we need it.
// EnableUserProvider(userModeSession, "Microsoft-Windows-Networking-Correlation",
// new Guid("83ED54F0-4D48-4E45-B16E-726FFD1FA4AF"), (TraceEventLevel)255, 0);
EnableUserProvider(userModeSession, "Microsoft-Windows-RPC",
new Guid("6AD52B32-D609-4BE9-AE07-CE8DAE937E39"), TraceEventLevel.Informational, 0, options);
// This is what WPA turns on in its 'GENERAL' setting
//Microsoft-Windows-Immersive-Shell: 0x0000000000100000: 0x04
//Microsoft-Windows-Kernel-Power: 0x0000000000000004: 0xff
//Microsoft-Windows-Win32k: 0x0000000000402000: 0xff
//Microsoft-Windows-WLAN-AutoConfig: 0x0000000000000200: 0xff
//.NET Common Language Runtime: 0x0000000000000098: 0x05
//Microsoft-JScript: 0x0000000000000001: 0xff e7ef96be-969f-414f-97d7-3ddb7b558ccc: 0x0000000000002000: 0xff
//MUI Resource Trace: : 0xff
//Microsoft-Windows-COMRuntime: 0x0000000000000003: 0xff
//Microsoft-Windows-Networking-Correlation: : 0xff
//Microsoft-Windows-RPCSS: : 0x04
//Microsoft-Windows-RPC: : 0x04 a669021c-c450-4609-a035-5af59af4df18: : 0x00
//Microsoft-Windows-Kernel-Processor-Power: : 0xff
//Microsoft-Windows-Kernel-StoreMgr: : 0xff e7ef96be-969f-414f-97d7-3ddb7b558ccc: : 0xff
//Microsoft-Windows-UserModePowerService: : 0xff
//Microsoft-Windows-Win32k: : 0xff
//Microsoft-Windows-ReadyBoostDriver: : 0xff
#if false // TODO FIX NOW remove
var networkProviders = new List<string>();
networkProviders.Add("Microsoft-Windows-WebIO:*:5:stack");
networkProviders.Add("Microsoft-Windows-WinINet:*:5:stack");
networkProviders.Add("Microsoft-Windows-TCPIP:*:5:stack");
networkProviders.Add("Microsoft-Windows-NCSI:*:5:stack");
networkProviders.Add("Microsoft-Windows-WFP:*:5:stack");
networkProviders.Add("Microsoft-Windows-Iphlpsvc-Trace:*:5:stack");
networkProviders.Add("Microsoft-Windows-WinHttp:*:5:stack");
networkProviders.Add("Microsoft-Windows-NDIS-PacketCapture");
networkProviders.Add("Microsoft-Windows-NWiFi:*:5:stack");
networkProviders.Add("Microsoft-Windows-NlaSvc:*:5:stack");
networkProviders.Add("Microsoft-Windows-NDIS:*:5:stack");
EnableAdditionalProviders(userModeSession, networkProviders.ToArray());
#endif
}
}
else if ((parsedArgs.ClrEvents & ClrTraceEventParser.Keywords.GC) != 0)
{
LogFile.WriteLine("Turned on additional CLR GC events");
EnableUserProvider(userModeSession, "CLRPrivate", ClrPrivateTraceEventParser.ProviderGuid,
TraceEventLevel.Informational, (ulong)ClrPrivateTraceEventParser.Keywords.GC, options);
}
if ((parsedArgs.KernelEvents & KernelTraceEventParser.Keywords.ReferenceSet) != 0)
{
// ALso get heap ranges if ReferenceSet is on.
EnableUserProvider(userModeSession, "Win32HeapRanges", HeapTraceProviderTraceEventParser.HeapRangeProviderGuid,
TraceEventLevel.Verbose, 0, options);
}
if (profilerKeywords != 0)
{
// Turn on allocation profiling if the user asked for it.
EnableUserProvider(userModeSession, "ETWClrProfiler",
ETWClrProfilerTraceEventParser.ProviderGuid, TraceEventLevel.Verbose,
(ulong)profilerKeywords,
stacksEnabled);
}
LogFile.WriteLine("Turning on VS CodeMarkers and MeasurementBlock Providers.");
EnableUserProvider(userModeSession, "MeasurementBlock",
new Guid("143A31DB-0372-40B6-B8F1-B4B16ADB5F54"), TraceEventLevel.Verbose, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "CodeMarkers",
new Guid("641D7F6C-481C-42E8-AB7E-D18DC5E5CB9E"), TraceEventLevel.Verbose, ulong.MaxValue, options);
// Turn off NGEN if they asked for it.
if (parsedArgs.NoNGenRundown)
{
parsedArgs.ClrEvents &= ~ClrTraceEventParser.Keywords.NGen;
}
// Force NGEN rundown if they asked for it.
if (parsedArgs.ForceNgenRundown)
{
parsedArgs.ClrEvents &= ~ClrTraceEventParser.Keywords.SupressNGen;
}
LogFile.WriteLine("Enabling CLR Events: {0}", parsedArgs.ClrEvents);
EnableUserProvider(userModeSession, "CLR", ClrTraceEventParser.ProviderGuid,
parsedArgs.ClrEventLevel, (ulong)parsedArgs.ClrEvents, options);
}
// Start network monitoring capture if needed
if (parsedArgs.NetMonCapture)
{
parsedArgs.NetworkCapture = true;
}
if (parsedArgs.NetworkCapture)
{
string maxSize = "maxSize=1";
string correlation = "correlation=no";
string report = "report=disabled";
string scenario = "InternetClient";
string perfMerge = "perfMerge=no";
string traceFile = CacheFiles.FindFile(parsedArgs.DataFile, ".netmon.etl");
var osVer = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor;
if (parsedArgs.NetMonCapture || osVer < 62)
{
traceFile = Path.GetFileNameWithoutExtension(parsedArgs.DataFile) + "_netmon.etl"; // We use the _ to avoid conventions about merging.
maxSize = "";
correlation = "";
perfMerge = "";
report = "";
}
FileUtilities.ForceDelete(traceFile);
EnableUserProvider(userModeSession, "Microsoft-Windows-NDIS-PacketCapture",
new Guid("2ED6006E-4729-4609-B423-3EE7BCD678EF"), TraceEventLevel.Informational, ulong.MaxValue, options);
EnableUserProvider(userModeSession, "Microsoft-Windows-TCPIP",
new Guid("2F07E2EE-15DB-40F1-90EF-9D7BA282188A"), TraceEventLevel.Informational, ulong.MaxValue, stacksEnabled);
string commandLine = string.Format("netsh trace start scenario={0} capture=yes {1} {2} {3} {4} \"traceFile={5}\"",
scenario, correlation, report, maxSize, perfMerge, traceFile);
LogFile.WriteLine("Turning on network packet monitoring");
LogFile.WriteLine("Can turn off running 'netsh trace stop' or rebooting.");
LogFile.WriteLine("Executing the command: {0}", commandLine);
// Make sure that if we are on a 64 bit machine we run the 64 bit version of netsh.
var cmdExe = Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "SysNative", "cmd.exe");
if (!File.Exists(cmdExe))
{
cmdExe = cmdExe.Replace("SysNative", "System32");
}
commandLine = cmdExe + " /c " + commandLine;
var command = Command.Run(commandLine, new CommandOptions().AddNoThrow().AddOutputStream(LogFile));
string netMonFile = Path.Combine(CacheFiles.CacheDir, "NetMonActive.txt");
File.WriteAllText(netMonFile, ""); // mark that Network monitoring is potentially active
if (command.ExitCode != 0)
{
throw new ApplicationException("Could not turn on network packet monitoring with the 'netsh trace' command.");
}
LogFile.WriteLine("netsh trace command succeeded.");
}
if (parsedArgs.CCWRefCount)
{
EnableUserProvider(userModeSession, "InteropEventProvider", new Guid("c4ac552a-e1eb-4fa2-a651-b200efd7aa91"), TraceEventLevel.Verbose, ulong.MaxValue, stacksEnabled);
}
LogFile.WriteLine("Enabling Providers specified by the user.");
if (parsedArgs.Providers != null)
{
EnableAdditionalProviders(userModeSession, parsedArgs.Providers, parsedArgs.CommandLine, options);
}
// OK at this point, we want to leave both sessions for an indefinite period of time (even past process exit)
kernelModeSession.StopOnDispose = false;
userModeSession.StopOnDispose = false;
if (heapSession != null)
{
heapSession.StopOnDispose = false;
}
PerfViewLogger.Log.CommandLineParameters(ParsedArgsAsString(null, parsedArgs), Environment.CurrentDirectory, AppLog.VersionNumber);
}
}
}