Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b7bb77a
Remove legacy KernelTraceControl support
brianrob Oct 2, 2026
6e2670b
Require Windows 10 for Windows hosts
brianrob Oct 2, 2026
e3e80c8
Build PerfView applications for x64
brianrob Oct 2, 2026
1cd7351
Remove ARM32 PerfView paths
brianrob Oct 2, 2026
77f6809
Trim host-only PerfView native resources
brianrob Oct 2, 2026
03f4d88
Simplify x64 profiler registration
brianrob Oct 2, 2026
234da82
Remove 32-bit host heap-dump branches
brianrob Oct 2, 2026
5209d5f
Remove cross-bitness counter relaunch
brianrob Oct 2, 2026
46bd81e
Remove 32-bit host command redirection
brianrob Oct 2, 2026
383ceea
Remove the app-permissions OS gate
brianrob Oct 2, 2026
10f9cda
Remove obsolete kernel-paging commands
brianrob Oct 2, 2026
4a656a9
Remove the custom-session OS restriction
brianrob Oct 2, 2026
73f7ef2
Remove the CPU-counter UI OS gate
brianrob Oct 2, 2026
b2d3157
Always log CPU-counter settings on stop
brianrob Oct 2, 2026
c2c2cf5
Remove legacy network-capture OS arguments
brianrob Oct 2, 2026
ef997a9
Remove the old-host trace warning
brianrob Oct 2, 2026
462c8e4
Remove JavaScript heap OS gates
brianrob Oct 2, 2026
9172741
Remove the package-lookup OS gate
brianrob Oct 2, 2026
fe89d10
Remove Win61 from TraceEvent packaging
brianrob Oct 2, 2026
58ced5c
Remove Windows 7 real-time session emulation
brianrob Oct 2, 2026
53e4059
Remove legacy ETW provider-control fallbacks
brianrob Oct 2, 2026
cca3daf
Remove the pre-Vista ETW consumer API
brianrob Oct 2, 2026
142de68
Remove obsolete kernel-session version checks
brianrob Oct 2, 2026
f92b918
Remove profile-source OS gates
brianrob Oct 2, 2026
51603c7
Remove the relogger OS gate
brianrob Oct 2, 2026
d98175d
Simplify the kernel keyword mask
brianrob Oct 2, 2026
47835c7
Remove the merge-compression OS fallback
brianrob Oct 2, 2026
0b6e8b2
Replace the obsolete ETL error explanation
brianrob Oct 2, 2026
824801f
Retire pre-Windows 8.1 filtering fallbacks
brianrob Oct 2, 2026
fd17789
Remove dead version scaffolding
brianrob Oct 2, 2026
f0c982e
Retire Windows 7 tracing samples
brianrob Oct 2, 2026
8a047e7
Update samples for Windows 10
brianrob Oct 2, 2026
8547d43
Remove EventRegister's WinRT OS gate
brianrob Oct 2, 2026
80d4756
Refresh supported-platform guidance
brianrob Oct 2, 2026
f834c39
Dispose the invalid-handle test fixture
brianrob Oct 2, 2026
8bfcba7
Fix compiler typo in TraceEvent guide
brianrob Oct 6, 2026
4120c13
Clarify ARM64 trace capture support
brianrob Oct 6, 2026
3ee63ae
Link latest download in release information
brianrob Oct 6, 2026
7be4dea
Clarify Windows package identity
brianrob Oct 6, 2026
598c3db
Remove constant PerfView architecture helpers
brianrob Oct 6, 2026
5ec234d
Centralize the host architecture directory
brianrob Oct 6, 2026
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
30 changes: 27 additions & 3 deletions .pipelines/perfview-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,45 @@ steps:
customFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json'

- task: VSTest@3
displayName: 'Run Tests'
displayName: 'Run TraceEvent Tests (x86)'
inputs:
testAssemblyVer2: |
**\bin\**\LinuxTracingTests.dll
**\bin\**\CtfTracingTests.dll
**\bin\**\SymbolsAuthTests.dll
**\bin\**\TraceEventTests.dll
**\bin\**\PerfViewTests.dll
**\bin\**\TraceParserGen.Tests.dll
testRunTitle: 'PerfView - ${{ parameters.flavor }}'
testRunTitle: 'TraceEvent x86 - ${{ parameters.flavor }}'
vsTestVersion: 'toolsInstaller'
runTestsInIsolation: true
donotPublishTestResults: true
otherConsoleOptions: '--blame'

- task: VSTest@3
displayName: 'Run TraceEvent Tests (x64)'
inputs:
testAssemblyVer2: |
**\bin\**\LinuxTracingTests.dll
**\bin\**\CtfTracingTests.dll
**\bin\**\SymbolsAuthTests.dll
**\bin\**\TraceEventTests.dll
**\bin\**\TraceParserGen.Tests.dll
testRunTitle: 'TraceEvent x64 - ${{ parameters.flavor }}'
vsTestVersion: 'toolsInstaller'
runTestsInIsolation: true
donotPublishTestResults: true
otherConsoleOptions: '--blame /Platform:x64'

- task: VSTest@3
displayName: 'Run PerfView Tests'
inputs:
testAssemblyVer2: '**\bin\**\PerfViewTests.dll'
testRunTitle: 'PerfView x64 - ${{ parameters.flavor }}'
vsTestVersion: 'toolsInstaller'
runTestsInIsolation: true
donotPublishTestResults: true
otherConsoleOptions: '--blame /Platform:x64'

- task: CopyFiles@2
displayName: 'Copy Files to Artifacts Staging'
inputs:
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ current version of PerfView.

PerfView requires .NET Framework 4.7.2 or later, which is widely available for all supported versions of Windows.

PerfView and TraceEvent require Windows 10 or Windows Server 2016 or later when running on Windows.

There is no native ARM64 PerfView application build. PerfViewCollect requires the matching
x64 .NET runtime, whose supported Windows releases may be more restrictive.
Historical trace files and older target runtimes remain supported for analysis.

### Are you here about the TraceEvent Library?

PerfView is built on a library called Microsoft.Diagnostics.Tracing.TraceEvent, that knows how to both collect and parse Event Tracing for Windows (ETW) and EventPipe (.NET Core trace) data. Thus if there is any information that PerfView collects and processes that you would like to manipulate yourself programmatically, you would probably be interested in the [TraceEvent Library Documentation](documentation/TraceEvent/TraceEventLibrary.md)
Expand Down
10 changes: 7 additions & 3 deletions documentation/Downloading.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ PerfView is a free profiling tool from Microsoft. This page tells you how to g
See the [PerfView Overview](https://github.com/Microsoft/perfview#perfview-overview) for general information
about PerfView.

PerfView is an x64 application requiring Windows 10 or Windows Server 2016 or later
and .NET Framework 4.7.2 or later. It can collect from both x86 and x64 target processes.
Windows-provided x64 emulation may be used where available; there is no native ARM64
Comment thread
brianrob marked this conversation as resolved.
Resolved
PerfView application build.

# PerfView Releases

The [PerfView GitHub Releases page](https://github.com/Microsoft/perfview/releases) is now the official
Expand Down Expand Up @@ -50,8 +55,8 @@ This confirms that software is authentic. You can also do this by running the si
# Additional Release Information

The link above allows you to quickly download PerfView.exe which is what you need 95% of the time.
If you wish to get other files associated with the release (e.g. the 64 bit version, or
the debugging symbols), or wish to download older releases (not recommended), you can do
If you wish to get other files associated with the release (e.g. debugging symbols),
or wish to download older releases (not recommended), you can do
so by visiting the [PerfView GitHub Releases](https://github.com/Microsoft/perfview/releases).


Expand All @@ -60,4 +65,3 @@ The Microsoft Download Site for PerfView has
been retired as the official download site for PerfView. It has been replaced by
[PerfView GitHub Releases page](https://github.com/Microsoft/perfview/releases) referenced above.
Comment thread
brianrob marked this conversation as resolved.
Resolved


11 changes: 8 additions & 3 deletions documentation/TraceEvent/TraceEventLibrary.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,18 @@ class Program
}
```

## Supported Windows Versions

On Windows, TraceEvent requires Windows 10 or Windows Server 2016 or later.
Its module initializer throws `PlatformNotSupportedException` on older Windows;
the CLR may wrap this in an initialization exception. This check is skipped on
Linux and macOS, preserving the library's existing cross-platform capabilities.
Older traces and target runtimes can still be analyzed on supported hosts.

## TraceEvent Samples

To see more complete samples that use the APIs in more sophisticated (but not too sophisticated ways). In the [Samples directory](https://github.com/Microsoft/perfview/tree/main/src/TraceEvent/Samples) here are one or two page samples doing interesting things (collecting data, parsing from files or in real time, transforming one ETL file to another etc). Each sample is independent of the others.

One way of getting the samples is to walk through the step by step guide in [Vance's Walkthough on TraceEvent](https://blogs.msdn.microsoft.com/vancem/2014/03/15/walk-through-getting-started-with-etw-traceevent-nuget-samples-package/). This walkthrough uses TraceEvent Samples package, however this code is old (but still completely relevant
the APIs have not changed). These samples are exactly the samples in Github mentioned above.

The easiest way to build the latest samples is to simply clone the [PerfView Repository](https://github.com/Microsoft/perfview) and and build it. The samples are in the _TraceEventSamples_ project in the PerfView solution. Simply set this project to be your _Startup Project_ (right click on it in Solution Explorer -> Set as Startup Project) and run it (F5). By default will run all the samples.

## Release Notes for the Microsoft.Diagnostics.Tracing.TraceEvent library
Expand Down
12 changes: 6 additions & 6 deletions documentation/TraceEvent/TraceEventProgrammersGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ Capabilities include:
* The ability to turn on event providers selectively using ETW 'Keywords' and verbosity 'Levels'. You can also pass additional arguments to your provider which `EventSource` sources can pick up. In that way you can create very sophisticated filtering specification as well as execute simple commands (e.g. force a GC, flush the working set, and etc.).
* The ability to enumerate the ETW providers on the system as well as in a particular process, and the ability to determine what ETW groups (Keywords) you can turn on.
* Ability to take ETL files and merge them together into a single file.
* Ability to read an ETL file or real time session and write an ETL file from it, filtering it or adding new events (Windows 8 only).
* Ability to read an ETL file or real time session and write an ETL file from it, filtering it or adding new events.
* The ability to capture stack traces when events are being logged.
* The ability to convert the stacks to symbolic form both for .NET, Jscript, as well as native code.
* The ability to store events in a new format (ETLX) that allows the events to be accessed efficiently in a random fashion as well as to enumerate the events backwards as well as forwards, and to efficiently represent the stack information.
Expand All @@ -456,7 +456,7 @@ Capabilities include:
* Network I/O.
* Every packet (with compete data) that comes on or off the network (network sniffer).
* Every system call.
* Sampling of processor CPU counters (instructions executed, branch mispredicts, cache misses, ...) (Windows 8 only).
* Sampling of processor CPU counters (instructions executed, branch mispredicts, cache misses, ...).
* Remote procedure calls.
* How the machine is configured (disk, memory, CPUs, ...).
* Access CLR (.NET Runtime) events, including:
Expand All @@ -481,13 +481,13 @@ You can also get a reasonably good idea of what is possible by taking a look at

Unfortunately, there are some limitations in ETW that sometimes block it from being used in scenarios where it would otherwise be a natural fit. They are listed here for emphasis.

* You send commands to providers on a machine wide basis. Thus you can't target particular processes (however if you own the event provider code you can pass it extra information as arguments to 'enable' command to the provider and have your provider implement logic to ignore 'enable' commands not intended for it). (Fixed in Windows 8.1).
* Provider control is machine-wide, but `TraceEventProviderOptions.ProcessIDFilter` and `ProcessNameFilter` can limit collected events to selected processes on supported Windows hosts.
* Because commands are machine wide and thus give you access to all information on the system, you have to be Elevated (Admin) to turn an ETW session on or off.
* By design the communication between the controllers and the providers is 'fire and forget'. Thus ETW is not intended to be a general purpose cross process communication mechanism. Don't try to use it as such.
* In real time mode, events are buffered and there is at least a second or so delay (typically 3 sec) between the firing of the event and the reception by the session (to allow events to be delivered in efficient clumps of many events).
* Before Windows 8, there could only one kernel session. Thus using kernel mode events for 'monitoring' scenarios was problematic because any other tools that used kernel sessions were likely to interfere by overriding the single Kernel model event logging session.
* Named sessions can combine kernel and user providers. The special `NT Kernel Logger` session remains kernel-only; reusing its name can interfere with another tool using that session.
* In general scenarios having multiple controllers (sessions) controlling the same providers is dangerous. It can be done in some cases, but there is a significant potential for interference between the sessions.
* The file format is private, and before Windows 8 could be quite space inefficient (it compresses 8-to-1). Files can get big fast.
* ETL files can get large. Compression is available on supported Windows hosts; historical uncompressed traces may be substantially larger.
* Logging more than 10K events/sec will load the system noticeably (5%). Logging more frequently than 10K/sec should be avoided if possible. Logging 1M events/sec will completely swamp a typical machine.

## Next Step: Code Samples
Expand Down Expand Up @@ -827,7 +827,7 @@ Below are the steps in converting logging an event with a stack to a resolved sy
1. When the event is logged, the ETW system tries to crawl the stack at runtime. However this can fail for various reasons:

1. On 32-bit machines the crawler assumes the compiler stores unwinding information (EBP frames) on the stack. If the compile does not do this the stack 'breaks' (can't be unwound) and you lose any frames 'toward thread start'.
Comment thread
brianrob marked this conversation as resolved.
Resolved
2. On 64-bit processes on 64-bit machines the crawler needs 'unwind' information. For native code this is stored in the EXE, but for Just In Time (JIT) compiled code on Systems **before Windows 8 (or Win2012 server)** the ETW system did not know how to find this unwind information and break at the first frame with JIT compiled code. This is the most common reason for stack breakage, but will diminish machines are upgraded to new OSes.
2. For 64-bit processes, the crawler needs unwind information. Historical traces collected **before Windows 8 (or Windows Server 2012)** may have stacks broken at JIT-compiled frames because ETW could not locate that information. This old-host limitation is not a restriction on current collection, but reading an old trace cannot recover frames that were never recorded.

If either of these happen there is nothing wrong with your code as it is an issue with the APP or with the ETW infrastructure. PerfView should have the same problem.

Expand Down
13 changes: 3 additions & 10 deletions src/HeapDump/GCHeapDumper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -684,11 +684,11 @@ private void ResumeProcessIfNecessary(int processID)
throw new HeapDumpException("Could not find process with ID " + processID, HR.CouldNotFindProcessId);
}

// Determine if we are a Win8 Application.
// Resume packaged applications before collection.
Comment thread
brianrob marked this conversation as resolved.
Resolved
var fullPackageName = PackageUtil.FullPackageNameForProcess(process);
if (fullPackageName != null)
{
m_log.WriteLine("Process {0} is a Windows 8 application, resuming that process.", processID);
m_log.WriteLine("Process {0} is a packaged application, resuming that process.", processID);
var pkgDebugSettings = (IPackageDebugSettings)new PackageDebugSettingsClass();
// pkgDebugSettings.EnableDebugging(fullPackageName, null, IntPtr.Zero);
pkgDebugSettings.Resume(fullPackageName);
Expand Down Expand Up @@ -1609,18 +1609,12 @@ private NodeTypeIndex GetTypeIndexForName(string typeName, string moduleName, in
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);

/// <summary>
/// Gets at Win8 Package information.
/// Gets package information for a process.
/// </summary>
internal class PackageUtil
{
public static string FullPackageNameForProcess(Process process)
{
var version = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor;
if (version < 62)
{
return null; // Packages only exist on Windows 8
}

var packageFullNameBuff = new StringBuilder(512);
int packageFullNameBuffLen = packageFullNameBuff.Capacity;
var hr = GetPackageFullName(process.Handle, ref packageFullNameBuffLen, packageFullNameBuff);
Expand Down Expand Up @@ -1656,4 +1650,3 @@ internal interface IPackageDebugSettings
#endregion



50 changes: 50 additions & 0 deletions src/PerfView.Tests/HeapDumperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using PerfView;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Xunit;

namespace PerfViewTests
{
public class HeapDumperTests
{
[Fact]
public void DetectsX64Target()
{
using (var process = Process.GetCurrentProcess())
{
Assert.Equal(ProcessorArchitecture.Amd64, HeapDumper.GetArchForProcess(process.Id));
}
}

[Fact]
public void DetectsX86TargetFromX64Host()
{
var startInfo = new ProcessStartInfo(
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.SystemX86), "cmd.exe"),
"/d /c set /p PERFVIEW_TEST=")
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardInput = true
};
using (var process = Process.Start(startInfo))
{
try
{
Assert.Equal(ProcessorArchitecture.X86, HeapDumper.GetArchForProcess(process.Id));
}
finally
{
process.StandardInput.Close();
if (!process.WaitForExit(5000))
{
process.Kill();
process.WaitForExit();
}
}
}
}
}
}
1 change: 1 addition & 0 deletions src/PerfView.Tests/PerfView.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<TargetFrameworks>net462</TargetFrameworks>
<RootNamespace>PerfViewTests</RootNamespace>
<AssemblyName>PerfViewTests</AssemblyName>
<PlatformTarget>x64</PlatformTarget>
<Description>Unit tests for PerfView.</Description>
<Copyright>Copyright © Microsoft 2016</Copyright>

Expand Down
68 changes: 68 additions & 0 deletions src/PerfView.Tests/StartupTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using PerfView;
using System;
using System.ComponentModel;
using Xunit;

namespace PerfViewTests
{
public class StartupTests
{
[Fact]
public void ApplicationAndTestHostAreX64()
{
Assert.Equal(8, IntPtr.Size);
Assert.Equal(System.Reflection.ProcessorArchitecture.Amd64, typeof(Startup).Assembly.GetName().ProcessorArchitecture);
}

[Fact]
public void HostResourcesUseX64AndKeepBothHelpers()
{
Assert.Equal("amd64", global::Utilities.SupportFiles.ProcessArchitectureDirectory);
var resources = typeof(Startup).Assembly.GetManifestResourceNames();
Assert.Contains(@".\runtimes\win-x64\native\WebView2Loader.dll", resources);
Assert.DoesNotContain(@".\runtimes\win-x86\native\WebView2Loader.dll", resources);
Assert.DoesNotContain(@".\runtimes\win-arm64\native\WebView2Loader.dll", resources);
Assert.Contains(@".\amd64\msdia140.dll", resources);
Assert.DoesNotContain(@".\x86\msdia140.dll", resources);
Assert.DoesNotContain(resources, name => name.StartsWith(@".\arm\", StringComparison.Ordinal));
foreach (var arch in new[] { "x86", "amd64" })
{
foreach (var file in new[] { "HeapDump.exe", "EtwClrProfiler.dll", "KernelTraceControl.dll" })
{
Assert.Contains(@".\" + arch + @"\" + file, resources);
}
}
}

[Fact]
public void UnsupportedWindowsReportsOnceWithoutStarting()
{
int reports = 0;
int result = Startup.Run(() => false, message =>
{
reports++;
Assert.Contains("Windows 10", message);
}, () => throw new InvalidOperationException("Application must not start."));

Assert.Equal(1, result);
Assert.Equal(1, reports);
}

[Fact]
public void SupportedWindowsReturnsApplicationStatus()
{
Assert.Equal(42, Startup.Run(() => true,
message => throw new InvalidOperationException(message), () => 42));
}

[Fact]
public void VersionQueryFailureReportsWithoutStarting()
{
string reported = null;
int result = Startup.Run(() => throw new Win32Exception("Version query failed."),
message => reported = message, () => throw new InvalidOperationException("Application must not start."));
Assert.Equal(1, result);
Assert.Equal("Version query failed.", reported);
}
}
}
Loading
Loading