├── src ├── OETW │ ├── MsoEtwAS.res │ ├── MsoEtwCM.res │ ├── MsoEtwDQ.res │ ├── MsoEtwTP.res │ ├── MsoEtwDQ.man │ ├── MsoEtwTP.man │ ├── MsoEtwAS.man │ ├── MsoEtwCM.man │ └── ReadMe.txt ├── BETA │ ├── OETW │ │ ├── EdgeETW.res │ │ ├── ChromeETW.res │ │ ├── ChromeETW.man │ │ ├── ReadMe.txt │ │ └── EdgeETW.man │ ├── ADDIN │ │ └── ReadMe.txt │ ├── Generate-PmuRegFile.bat │ ├── TracePMC.bat │ ├── TraceEdgeChrome.bat │ ├── TraceNetwork.bat │ ├── ReadMe.txt │ ├── PMCs.bat │ ├── PMC.bat │ ├── WPRP │ │ └── RPC.wprp │ ├── WPAP │ │ └── Network.wpaProfile │ └── TraceEdgeChrome.ps1 ├── NetBlame │ ├── .editorconfig │ ├── Providers │ │ ├── OTaskPool.Classic.cs │ │ ├── WinsockNameRes.cs │ │ ├── WebIO-Layout.md │ │ ├── WebIO.Connection.cs │ │ ├── WebIO.Session.cs │ │ ├── WThreadPool.cs │ │ └── Thread.Classic.cs │ ├── NetBlameAddIn.csproj │ ├── NetBlameAddIn.sln │ ├── ClassicDataProcessor.cs │ ├── README.md │ ├── NetBlameDataSource.cs │ ├── .gitattributes │ ├── Auxiliary │ │ ├── GeoLocation.cs │ │ └── Extensions.cs │ └── .gitignore ├── PreWin10 │ ├── TraceCPU.bat │ ├── TraceHeap.bat │ ├── TraceHandles.bat │ ├── TraceHeapEx.bat │ ├── TraceMemory.bat │ ├── TraceMondo.bat │ ├── TraceNetwork.bat │ ├── TraceOffice.bat │ ├── TraceOutlook.bat │ ├── TraceFileDiskIO.bat │ ├── WPRP │ │ ├── JS.wprp │ │ ├── CLR.wprp │ │ ├── ThreadPool.wprp │ │ ├── VirtualAlloc.wprp │ │ ├── Defender.wprp │ │ ├── Handles.wprp │ │ └── CPU.wprp │ ├── TraceNetwork.ps1 │ ├── TraceMondo.ps1 │ ├── TraceCPU.ps1 │ ├── TraceFileDiskIO.ps1 │ ├── TraceHandles.ps1 │ └── TraceMemory.ps1 ├── WPAP │ ├── ETW-Overhead-for-CPU.stacktags │ ├── ETW-Overhead.wpaProfile │ ├── OfficeSpecial.regions.xml │ ├── VirtualAlloc.stacktags │ └── Threads.wpaProfile ├── ResetWPA.bat ├── SymbolScan.bat ├── TraceCPU.bat ├── TraceHeap.bat ├── TraceHandles.bat ├── TraceHeapEx.bat ├── TraceMemory.bat ├── TraceMondo.bat ├── TraceNetwork.bat ├── TraceOffice.bat ├── TraceOutlook.bat ├── TraceRegistry.bat ├── TraceFileDiskIO.bat ├── ResetWPA.ps1 ├── WPRP │ ├── CLR.wprp │ └── ThreadPool.wprp ├── ReadMe.txt ├── SymbolScan.ps1 └── TraceRegistry.ps1 ├── CODE_OF_CONDUCT.md ├── LICENSE ├── .github └── workflows │ └── release.yml ├── make └── CreateRelease.ps1 ├── SUPPORT.md ├── SECURITY.md └── README.md /src/OETW/MsoEtwAS.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSO-Scripts/HEAD/src/OETW/MsoEtwAS.res -------------------------------------------------------------------------------- /src/OETW/MsoEtwCM.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSO-Scripts/HEAD/src/OETW/MsoEtwCM.res -------------------------------------------------------------------------------- /src/OETW/MsoEtwDQ.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSO-Scripts/HEAD/src/OETW/MsoEtwDQ.res -------------------------------------------------------------------------------- /src/OETW/MsoEtwTP.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSO-Scripts/HEAD/src/OETW/MsoEtwTP.res -------------------------------------------------------------------------------- /src/BETA/OETW/EdgeETW.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSO-Scripts/HEAD/src/BETA/OETW/EdgeETW.res -------------------------------------------------------------------------------- /src/BETA/OETW/ChromeETW.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/MSO-Scripts/HEAD/src/BETA/OETW/ChromeETW.res -------------------------------------------------------------------------------- /src/NetBlame/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # IDE0024: Use block body for operators 4 | csharp_style_expression_bodied_operators = false:silent 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /src/PreWin10/TraceCPU.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceHeap.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceHandles.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceHeapEx.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceMemory.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceMondo.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceNetwork.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceOffice.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceOutlook.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/PreWin10/TraceFileDiskIO.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _CMD=-file "%~dpn0.ps1" %* 6 | echo PowerShell %_CMD% 7 | 8 | REM Set a temporary Bypass execution policy in Process scope to run the PowerShell script without interruption. 9 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 10 | PowerShell -EP Unrestricted %_CMD% 11 | -------------------------------------------------------------------------------- /src/BETA/ADDIN/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. Licensed under the MIT License. 2 | 3 | This component uses the free IP-GeoLocation API from ip-api at: https://ip-api.com 4 | 5 | This is the _only_ folder with binary executable code, consisting of WPA add-ins. 6 | It can be removed with only limited loss of functionality for the WPA viewer. 7 | 8 | https://github.com/microsoft/MSO-Scripts/wiki/Network-Activity#plugin 9 | 10 | This version is for use with: 11 | WPA.exe v11.7.383+ 12 | Microsoft.Performance.SDK.dll v1.2.2+ 13 | -------------------------------------------------------------------------------- /src/NetBlame/Providers/OTaskPool.Classic.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | /* 5 | Generate the Office TaskPool events from the raw generic events. 6 | Ideally we shouldn't need to do this. 7 | However, it is not uncommon that the manifest for this provider is missing or out-of-date. 8 | That causes an exception storm in WPA's GenericEvents mechanism, and we lose the events. 9 | */ 10 | 11 | namespace NetBlameCustomDataSource.OTaskPool.Classic 12 | { 13 | // TODO: Do this or not!? 14 | } 15 | -------------------------------------------------------------------------------- /src/OETW/MsoEtwDQ.man: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/OETW/MsoEtwTP.man: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/BETA/OETW/ChromeETW.man: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/WPAP/ETW-Overhead-for-CPU.stacktags: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/OETW/MsoEtwAS.man: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/ResetWPA.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | (more < "%~dpn0.ps1:Zone.Identifier") >nul 2>nul && ( 10 | echo Unblocking downloaded PowerShell script: %~n0.ps1 11 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 12 | echo:>"%~dpn0.ps1:Zone.Identifier" 13 | powershell unblock-file '%~dpn0.ps1' 2>nul 14 | echo: 15 | ) 16 | 17 | REM Escape spaces and quotes for use with: -command 18 | set _CMD=-command %_PATH: =` % 19 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 20 | echo PowerShell %_CMD% 21 | 22 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 23 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 24 | PowerShell -EP Unrestricted %_CMD% 25 | -------------------------------------------------------------------------------- /src/SymbolScan.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | (more < "%~dpn0.ps1:Zone.Identifier") >nul 2>nul && ( 10 | echo Unblocking downloaded PowerShell script: %~n0.ps1 11 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 12 | echo:>"%~dpn0.ps1:Zone.Identifier" 13 | powershell unblock-file '%~dpn0.ps1' 2>nul 14 | echo: 15 | ) 16 | 17 | REM Escape spaces and quotes for use with: -command 18 | set _CMD=-command %_PATH: =` % 19 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 20 | echo PowerShell %_CMD% 21 | 22 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 23 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 24 | PowerShell -EP Unrestricted %_CMD% 25 | -------------------------------------------------------------------------------- /src/BETA/Generate-PmuRegFile.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | (more < "%~dpn0.ps1:Zone.Identifier") >nul 2>nul && ( 10 | echo Unblocking downloaded PowerShell script: %~n0.ps1 11 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 12 | echo:>"%~dpn0.ps1:Zone.Identifier" 13 | powershell unblock-file '%~dpn0.ps1' 2>nul 14 | echo: 15 | ) 16 | 17 | REM Escape spaces and quotes for use with: -command 18 | set _CMD=-command %_PATH: =` % 19 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 20 | echo PowerShell %_CMD% 21 | 22 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 23 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 24 | PowerShell -EP Unrestricted %_CMD% 25 | -------------------------------------------------------------------------------- /src/OETW/MsoEtwCM.man: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 16 | 17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/TraceCPU.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceHeap.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceHandles.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceHeapEx.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceMemory.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceMondo.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceNetwork.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceOffice.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceOutlook.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceRegistry.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/WPAP/ETW-Overhead.wpaProfile: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/BETA/TracePMC.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=..\INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/TraceFileDiskIO.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/BETA/TraceEdgeChrome.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=..\INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/BETA/TraceNetwork.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | REM The powershell script has the same path and base name as this batch script. 5 | set _PATH="%~dpn0.ps1" 6 | set _ARGS=%* 7 | 8 | REM Detect, warn, and remove Mark of the Web. 9 | set TraceThis=%~n0.ps1 10 | set Include=..\INCLUDE*.ps1 11 | (more < "%~dp0%TraceThis%:Zone.Identifier") >nul 2>nul && ( 12 | echo Unblocking downloaded PowerShell scripts: %TraceThis%, %Include% 13 | echo https://github.com/microsoft/MSO-Scripts/wiki/Frequently-Asked-Questions#policy 14 | for %%f in ("%~dp0%TraceThis%","%~dp0%Include%") do echo %%~nxf & echo:>"%%~f:Zone.Identifier" 15 | echo: 16 | ) 17 | 18 | REM Escape spaces and quotes for use with: -command 19 | set _CMD=-command %_PATH: =` % 20 | if defined _ARGS set _CMD=%_CMD% %_ARGS:"='% 21 | echo PowerShell %_CMD% 22 | 23 | REM Set a temporary execution policy in Process scope to run the PowerShell script without interruption. 24 | REM https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?#powershell-execution-policies 25 | PowerShell -EP Unrestricted %_CMD% 26 | -------------------------------------------------------------------------------- /src/NetBlame/NetBlameAddIn.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | AnyCPU 6 | true 7 | 1.6.0 8 | 9 | 10 | 11 | AUX_TABLES 12 | 13 | 14 | 15 | AUX_TABLES 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: make-release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: 'Release version' 8 | required: true 9 | type: string 10 | 11 | jobs: 12 | create-release: 13 | runs-on: windows-latest 14 | permissions: 15 | contents: write 16 | steps: 17 | - name: Check out repository 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup .NET 21 | uses: actions/setup-dotnet@v4 22 | with: 23 | dotnet-version: '6.0' 24 | 25 | - name: Build NetBlame addin 26 | run: | 27 | dotnet build src\NetBlame\NetBlameAddIn.sln --configuration Release -p:Version=${{ inputs.version }} 28 | shell: cmd 29 | 30 | - name: Create ZIP archive with all scripts and binaries 31 | shell: pwsh 32 | run: make\CreateRelease.ps1 -NetBlameBuild "src\NetBlame\bin\Release\net6.0" -WorkingDir bin -OutputZip "bin\MSO-Scripts-${{ inputs.version }}.zip" 33 | 34 | - name: Publish release 35 | run: gh release create version_${{ inputs.version }} --title "Release ${{ inputs.version }}" "bin\MSO-Scripts-${{ inputs.version }}.zip" --notes "Manual release" 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | -------------------------------------------------------------------------------- /src/BETA/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. Licensed under the MIT License. 2 | 3 | Tracing CPU Counters / Processor Performance Monitor Unit (PMU) Events 4 | 5 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/recording-pmu-events 6 | https://devblogs.microsoft.com/performance-diagnostics/recording-hardware-performance-pmu-events-with-complete-examples/ 7 | 8 | - To list available CPU Counters, run: WPR -PMCSources 9 | Or run: XPerf -PMCSources 10 | If there is only one counter listed, your machine is probably configured for HYPER-V. 11 | 12 | - To add additional CPU-specific counters: 13 | For Intel CPUs, run: Generate-PmuRegFile -Description 14 | Then run RegEdit on the generated .REG file. Then restart the OS. 15 | 16 | - To trace Cycles per Instruction, run: TracePMC Start -CPI 17 | Or run: PMC.bat 18 | 19 | - To trace Branch Mispredicts and Cache Misses, run: TracePMC Start -PMC * 20 | Or run: PMCs.bat 21 | 22 | - To sample-trace specific CPU counters, run: TracePMC start -PMC Counter1[,Counter2[,...]] 23 | Or run: PMCs.bat Counter1 [Counter2 [...]] 24 | 25 | - To trace specific CPU counters at each CSwitch, run: PMC Counter1 [Counter2 [...]] 26 | 27 | - To view the resulting trace file, run: TracePMC View [-Path \.etl] 28 | Or run: WPA \.etl -profile .\WPAP\CPUCounters.wpaProfile 29 | -------------------------------------------------------------------------------- /src/NetBlame/Providers/WinsockNameRes.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Net; 6 | 7 | using Microsoft.Windows.EventTracing.Events; 8 | 9 | 10 | namespace NetBlameCustomDataSource.WinsockNameRes 11 | { 12 | public class WinsockNameResolution 13 | { 14 | public static readonly Guid guid = new Guid("{55404e71-4db9-4deb-a5f5-8f86e46dde56}"); // Microsoft-Windows-Winsock-NameResolution 15 | 16 | readonly AllTables allTables; 17 | 18 | public WinsockNameResolution(in AllTables _allTables) { this.allTables = _allTables; } 19 | 20 | public void Dispatch(in IGenericEvent evtGeneric) 21 | { 22 | const int GetAddrInfo_Stop = 1001; 23 | const int GetAddrInfoX_Stop = 1004; 24 | const uint S_OK = 0; 25 | 26 | switch (evtGeneric.Id) 27 | { 28 | case GetAddrInfo_Stop: 29 | case GetAddrInfoX_Stop: 30 | if (evtGeneric.GetUInt32("Status") == S_OK) 31 | { 32 | // If the server name is NOT an address, add it to the DNS table. 33 | string strNodeName = evtGeneric.GetString("NodeName"); 34 | if (String.IsNullOrWhiteSpace(strNodeName) || !IPAddress.TryParse(strNodeName, out IPAddress ipAddress)) 35 | { 36 | this.allTables.dnsTable.ParseDNSEntries(strNodeName, evtGeneric.GetString("Result")); 37 | } 38 | } 39 | break; 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/BETA/OETW/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. Licensed under the MIT License. 2 | 3 | These are manifest files for Office ETW logging providers. 4 | https://learn.microsoft.com/en-us/windows-hardware/test/weg/instrumenting-your-code-with-etw#implementing-etw-instrumentation 5 | 6 | MSO-Scripts registers these providers automatically when needed. 7 | 8 | A. MSEdge_Stable {3A5F2396-5C8F-4F1F-9B67-6CCA6C990E61} EdgeETW.man 9 | B. MSEdge_Canary {C56B8664-45C5-4E65-B3C7-A8D6BD3F2E67} EdgeETW.man 10 | C. MSEdge_Beta {BD089BAA-4E52-4794-A887-9E96868570D2} EdgeETW.man 11 | D. MSEdge_Dev {D30B5C9F-B58F-4DC9-AFAF-134405D72107} EdgeETW.man 12 | E. MSEdge_Internal {49C85E08-E8A5-49D6-81EA-7270531EC8AF} EdgeETW.man 13 | F. MSEdge_WebView {E16EC3D2-BB0F-4E8F-BDB8-DE0BEA82DC3D} EdgeETW.man 14 | G. Chrome {D2D578D9-2936-45B6-A09f-30E32715F42D} ChromeETW.man 15 | 16 | Present in: 17 | .\WPRP\MSEdge.wprp 18 | ..\WPRP\EdgeChrome.wprp 19 | 20 | To register the provider in a Trace* script: 21 | - Call: EnsureETWProvider(".\OETW\MsoEtwXX.man") 22 | 23 | To manually register the provider on your machine: 24 | - Copy MsoEtwXX.man and MsoEtwXX.res to your machine. 25 | - Run as Admin: wevtutil im \MsoEtwXX.man /rf:"\MsoEtwXX.res" /mf:"\MsoEtwXX.res" 26 | 27 | To manually unregister the provider: 28 | - Run as Admin: wevtutil um \MsoEtwXX.man 29 | -------------------------------------------------------------------------------- /src/NetBlame/NetBlameAddIn.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30320.27 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetBlameAddIn", "NetBlameAddIn.csproj", "{1EC08A8C-7085-46E6-9360-6A6FF7CA062E}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{89CCB51E-BA45-4F6A-8C22-1EC840263081}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {1EC08A8C-7085-46E6-9360-6A6FF7CA062E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {1EC08A8C-7085-46E6-9360-6A6FF7CA062E}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {1EC08A8C-7085-46E6-9360-6A6FF7CA062E}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {1EC08A8C-7085-46E6-9360-6A6FF7CA062E}.Release|Any CPU.Build.0 = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(SolutionProperties) = preSolution 25 | HideSolutionNode = FALSE 26 | EndGlobalSection 27 | GlobalSection(ExtensibilityGlobals) = postSolution 28 | SolutionGuid = {6E14B2BE-D7E9-4B12-8950-5149603255D5} 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /src/OETW/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. Licensed under the MIT License. 2 | 3 | These are manifest files for Office ETW logging providers. 4 | https://learn.microsoft.com/en-us/windows-hardware/test/weg/instrumenting-your-code-with-etw#implementing-etw-instrumentation 5 | 6 | MSO-Scripts registers these providers automatically when needed. 7 | 8 | A. Microsoft-Office-Events {8736922d-E8B2-47eb-8564-23E77E728CF3} MsoEtwCM.man 9 | B. OfficeLoggingLiblet {F50D9315-E17E-43C1-8370-3EDF6CC057BE} MsoEtwCM.man 10 | C. Microsoft-Office-Threadpool {a019725f-cff1-47e8-8c9e-8fe2635b6388} MsoEtwTP.man 11 | D. OfficeDispatchQueue {559a5658-8100-4d84-b756-0a47a476280c} MsoEtwDQ.man 12 | E. OfficeAirSpace {f562bb8e-422d-4b5c-b20e-90d710f7d11c} MsoEtwAS.man 13 | 14 | Present in: 15 | A. Microsoft-Office-Events is present in most WPRP files. It is (usually) pre-registered. 16 | B. OfficeProviders.wprp 17 | C. ThreadPool*.wprp, Network*.wprp 18 | D. ThreadPool*.wprp, Network*.wprp 19 | E. OfficeProviders.wprp 20 | 21 | To register the provider in a Trace* script: 22 | - Call: EnsureETWProvider(".\OETW\MsoEtwXX.man") 23 | 24 | To manually register the provider on your machine: 25 | - Copy MsoEtwXX.man and MsoEtwXX.res to your machine. 26 | - Run as Admin: wevtutil im \MsoEtwXX.man /rf:"\MsoEtwXX.res" /mf:"\MsoEtwXX.res" 27 | 28 | To manually unregister the provider: 29 | - Run as Admin: wevtutil um \MsoEtwXX.man 30 | -------------------------------------------------------------------------------- /make/CreateRelease.ps1: -------------------------------------------------------------------------------- 1 | Param 2 | ( 3 | [string]$NetBlameBuild, 4 | [string]$WorkingDir, 5 | [string]$OutputZip 6 | ) 7 | 8 | $WorkingDir = "$WorkingDir\MSO-Scripts" 9 | 10 | # Create working directory to copy artifacts 11 | New-Item -ItemType Directory -Path $WorkingDir 12 | 13 | # Copy all main scripts 14 | Get-ChildItem -Path "src" -File | Copy-Item -Destination $WorkingDir 15 | 16 | # Copy BETA scripts 17 | Copy-Item -Path "src\BETA" -Destination "$WorkingDir\BETA" -Recurse 18 | 19 | # Copy ADDIN binaries from NetBlame build 20 | $AddinDir = "$WorkingDir\BETA\ADDIN" 21 | Get-ChildItem -Path $NetBlameBuild -File | Copy-Item -Destination $AddinDir 22 | 23 | $Platforms = 'arm64', 'x64' 24 | $Binaries = 'msdia140.dll', 'perfcore.dll', 'perf_nt.dll', 'perf_dynamic.dll', 'symcache.dll', 'symsrv.dll' 25 | 26 | ForEach ($platform in $Platforms) { 27 | $PlatformDir = "$AddinDir\$platform" 28 | New-Item -ItemType Directory -Path "$PlatformDir\wpt" 29 | ForEach ($binary in $Binaries) { 30 | Copy-Item -Path "$NetBlameBuild\$platform\wpt\$binary" -Destination "$PlatformDir\wpt" 31 | } 32 | } 33 | 34 | # Copy remaing data 35 | Copy-Item -Path "src\OETW" -Destination "$WorkingDir\OETW" -Recurse 36 | Copy-Item -Path "src\PreWin10" -Destination "$WorkingDir\PreWin10" -Recurse 37 | Copy-Item -Path "src\WPAP" -Destination "$WorkingDir\WPAP" -Recurse 38 | Copy-Item -Path "src\WPRP" -Destination "$WorkingDir\WPRP" -Recurse 39 | 40 | Compress-Archive -Path $WorkingDir -DestinationPath $OutputZip 41 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | MSO-Scripts facilitates the use of Microsoft's Event Tracing for Windows ([ETW](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-)) technology, including [WPR](https://learn.microsoft.com/en-us/windows-hardware/test/wpt/introduction-to-wpr) and [WPA](https://learn.microsoft.com/en-us/windows-hardware/test/wpt/windows-performance-analyzer). 4 | 5 | The scripts are intended to be self-service, [well documented](../../wiki), and highly customizable: 6 | - Start with the 'CUSTOMIZE THIS' section of any script file: Trace*.ps1 7 | - Run any script (Trace*.ps1) with `-Verbose` to reveal its underlying actions and how it invokes WPR or WPA. 8 | - Refer to the wiki topic: [Customize Tracing](../../wiki/Customize-Tracing) 9 | 10 | For new combinations of tracing and logging providers to suit your needs, please make use of these resources to create your own customized version. 11 | 12 | ## How to file issues and get help 13 | 14 | These scripts are designed to simplify complex tracing/logging scenarios on Microsoft Windows and also handle potential error conditions. The ever evolving Windows platform may necessitate occasional script updates and corrections to operate well in common environments. Similarly, [stacktags](https://learn.microsoft.com/en-us/windows-hardware/test/wpt/stack-tags) are based on module and function names, while [regions-of-interested](https://learn.microsoft.com/en-us/windows-hardware/test/wpt/creating-a-regions-of-interest-file) are based on internal logging mechanisms, all of which are subject to change. 15 | 16 | Contributions are welcome. 17 | 18 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. 19 | 20 | ## Microsoft Support Policy 21 | 22 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 23 | -------------------------------------------------------------------------------- /src/NetBlame/Providers/WebIO-Layout.md: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. Licensed under the MIT License. 2 | 3 | ``` 4 | WebIO (the core of the WinHTTP Network Stack) 5 | Session -> Request -> Connection -> Socket -> (TCB) 6 | 7 | There may be multiple Requests per Session. 8 | Connections may be shared/reused across Requests. 9 | Here, separate/linked Connection objects represent a shared Connection, one copy per Request. 10 | A Connection can link to several Sockets, when several IP addresses correspond to a server. 11 | Each socket is tied to a TCB: Transfer Control Block (TcpIp) 12 | 13 | Session1 14 | Request1 <- Connection1a -> Socket1a -> TCB1 15 | ^ / Socket1b -> TCB2 16 | Session2 | / Socket1c -> TCB3 17 | Request2 <- Connection1b/ 18 | 19 | Session1 20 | Request3 <- Connection2 -> Socket2 -> TCB4 21 | 22 | 23 | Session Request Connection Socket | TCB 24 | ID ID ID ID | ID 25 | Times Times Times Times | Times 26 | iReqFirst-> URL ----- URLx -- | PID 27 | XLink ---- XLink <-iRequest iTCB-> | TID 28 | <-iSession PID ^ TID | cbSend 29 | Method iCxnNext \ <-iCxn | cbRecv 30 | iDNS iAddr ^ | 31 | iSocketFirst->iSocketNext \ | 32 | cbSend 33 | cbRecv 34 | 35 | XLink = callstack info which is also linked to their invoking threadpool objects 36 | iDNS = index into the DNS table: server & various IP Addresses 37 | iAddr = index into the IP Address list of a DNS entry 38 | iSocketFirst/Next = linked list (by index) of related Sockets 39 | iCxn/Next = linked list (by index) of Connection objects which represent a connection shared across Request objects 40 | 41 | Traversal links look like this, with Sockets and Connections also linking themselves into subgroups. 42 | TCB <- Socket[<] -> Connection[<] -> Request -> Session 43 | ``` -------------------------------------------------------------------------------- /src/NetBlame/ClassicDataProcessor.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | using Microsoft.Windows.EventTracing; // ClassicEvent 8 | 9 | using NetBlameCustomDataSource.Thread; 10 | using NetBlameCustomDataSource.Thread.Classic; 11 | using NetBlameCustomDataSource.WThreadPool; 12 | using NetBlameCustomDataSource.WThreadPool.Classic; 13 | 14 | using static NetBlameCustomDataSource.Util; 15 | 16 | using Addr32 = System.UInt32; 17 | using Addr64 = System.UInt64; 18 | 19 | 20 | namespace NetBlameCustomDataSource.Classic 21 | { 22 | /* 23 | Parse classic events as they are pre-processed via: traceProcessor.Process() 24 | */ 25 | class ClassicEventConsumer : IFilteredEventConsumer 26 | { 27 | public WThreadPoolEventConsumer wtpEventConsumer; 28 | public ThreadEventConsumer threadEventConsumer; 29 | 30 | public IReadOnlyList ProviderIds { get; } 31 | 32 | public ClassicEventConsumer(Guid[] rgGuid) 33 | { 34 | this.ProviderIds = rgGuid; 35 | 36 | wtpEventConsumer = new WThreadPoolEventConsumer(); 37 | threadEventConsumer = new ThreadEventConsumer(); 38 | } 39 | 40 | public void Process(EventContext ectx) 41 | { 42 | AssertCritical(ectx.Event.IsClassic); 43 | 44 | var evtClassic = ectx.Event.AsClassicEvent; 45 | 46 | if (!evtClassic.HasValue) return; 47 | if (evtClassic.Data.IsEmpty) return; 48 | 49 | if (evtClassic.ProviderId == WThreadPoolTable.guid) // Windows-ThreadPool 50 | { 51 | if (evtClassic.Is32Bit) 52 | wtpEventConsumer.WThreadPoolEvent(in evtClassic); 53 | else 54 | wtpEventConsumer.WThreadPoolEvent(in evtClassic); 55 | } 56 | else if (evtClassic.ProviderId == ThreadTable.guid) // Thread 57 | { 58 | threadEventConsumer.Process(in evtClassic); 59 | } 60 | else 61 | { 62 | AssertCritical(false); 63 | } 64 | } // Process 65 | } // ClassicEventConsumer 66 | } // NetBlameCustomDataSource.Classic -------------------------------------------------------------------------------- /src/BETA/OETW/EdgeETW.man: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 13 | 19 | 20 | 26 | 27 | 33 | 34 | 40 | 41 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/NetBlame/README.md: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. Licensed under the MIT License. 2 | 3 | # NetBlame Add-in 4 | 5 | This add-in analyzes and summarizes network and thread pool ETW events: 6 | 7 | Microsoft-Windows-Winsock-NameResolution {55404e71-4db9-4deb-a5f5-8f86e46dde56} 8 | Microsoft-Windows-Winsock-AFD {e53c6823-7bb8-44bb-90dc-3f86090d48a6} 9 | Microsoft-Windows-DNS-Client {1c95126e-7eea-49a9-a3fe-a378b03ddb4d} 10 | Microsoft-Windows-WinINet {43d1a55c-76d6-4f7e-995c-64c711e5cafe} 11 | Microsoft-Windows-WinHttp {7d44233d-3055-4b9c-ba64-0d47ca40a232} 12 | Microsoft-Windows-WebIO {50b3e73c-9370-461d-bb9f-26f32d68887d} 13 | Microsoft-Windows-TCPIP {2f07e2ee-15db-40f1-90ef-9d7ba282188a} 14 | Windows-ThreadPool {c861d0e2-a2c1-4d36-9f9c-970bab943a12} 15 | Office-ThreadPool {A019725F-CFF1-47E8-8C9E-8FE2635B6388} 16 | OfficeDispatchQueue {559A5658-8100-4D84-B756-0A47A476280C} 17 | 18 | It is based on the [Microsoft Performance Toolkit SDK](https://github.com/microsoft/microsoft-performance-toolkit-sdk) 19 | 20 | This product includes GeoLocation data created by ip-api, available at https://ip-api.com 21 | 22 | # Build 23 | 24 | When a Release of this project is downloaded and unzipped, the NetBlame plug-in is ready to go. 25 | 26 | When this repository is cloned, the NetBlame plug-in must be built. 27 | 28 | See: https://github.com/microsoft/MSO-Scripts/wiki/Network-Activity#plugin 29 | 30 | `DotNet.exe build -c Release` 31 | 32 | # Run 33 | 34 | Requires WPA v11.7.383+ and SDK v1.2.2+ 35 | 36 | `c:\MSO-Scripts\BETA\TraceNetwork View` 37 | 38 | The above script executes this WPA command to load the NetBlame plug-in and process the ETW trace: 39 | 40 | ``` 41 | WPA -i "$Env:LocalAppData\MSO-Scripts\MSO-Trace-Network.etl" 42 | -processors "Event Tracing for Windows","Office_NetBlame" 43 | -addsearchdir "c:\MSO_Scripts\NetBlame\bin\Release\net6.0" 44 | -profile "c:\MSO-Scripts\BETA\WPAP\Network.wpaProfile" 45 | ``` 46 | 47 | The script chooses one of these paths for -addsearchdir : 48 | - `"c:\MSO_Scripts\NetBlame\bin\Release\net6.0"` 49 | - `"c:\MSO_Scripts\NetBlame\bin\Debug\net6.0"` 50 | - `"c:\MSO_Scripts\BETA\ADDIN"` 51 | -------------------------------------------------------------------------------- /src/NetBlame/NetBlameDataSource.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | using Microsoft.Performance.SDK; // Guard 8 | using Microsoft.Performance.SDK.Processing; 9 | 10 | 11 | namespace NetBlameCustomDataSource 12 | { 13 | // In order for a CustomDataSource to be recognized, it MUST satisfy the following: 14 | // a) Be a public type 15 | // b) Have a public parameterless constructor 16 | // c) Implement the ICustomDataSource interface 17 | // d) Be decorated with the CustomDataSource[Attribute] attribute 18 | // e) Be decorated with at least one of the derivatives of the DataSource[Attribute] attribute 19 | 20 | [ProcessingSource( 21 | "{67AE371A-9D97-4584-BCC1-F62B4D14737A}", // The GUID must be unique for your Custom Data Source. 22 | "Office_NetBlame", // The Custom Data Source MUST have a name. 23 | "Data source for the NetBlame Tool")] // The Custom Data Source MUST have a description. 24 | [FileDataSource( 25 | ".etl", // A file extension is REQUIRED. 26 | "Event Trace Log")] // A description is OPTIONAL. The description is what appears in the file open menu to help users understand what the file type actually is. 27 | 28 | public class NetBlameDataSource : ProcessingSource 29 | { 30 | public override ProcessingSourceInfo GetAboutInfo() 31 | { 32 | return new ProcessingSourceInfo() 33 | { 34 | Owners = null, 35 | ProjectInfo = new ProjectInfo() { Uri = "https://github.com/microsoft/MSO-Scripts" }, 36 | CopyrightNotice = $"Copyright (C) Microsoft Corporation. Licensed under the MIT License.", 37 | LicenseInfo = null, 38 | AdditionalInformation = new string[] { GeoLocation.Attribution } 39 | }; 40 | } 41 | 42 | protected override ICustomDataProcessor CreateProcessorCore( 43 | IEnumerable files, 44 | IProcessorEnvironment processorEnvironment, 45 | ProcessorOptions options) 46 | { 47 | Guard.NotNull(files, nameof(files)); 48 | IDataSource[] allFiles = files.ToArray(); 49 | Guard.IsTrue(allFiles.Length == 1); 50 | 51 | return new NetBlameDataProcessor( 52 | allFiles[0].Uri.LocalPath, 53 | options, 54 | this.ApplicationEnvironment, 55 | processorEnvironment); 56 | } 57 | 58 | // Already limited to ETL via: [FileDataSource()] 59 | protected override bool IsDataSourceSupportedCore(IDataSource ids) => true; 60 | } 61 | 62 | } // NetBlameCustomDataSource 63 | -------------------------------------------------------------------------------- /src/NetBlame/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/NetBlame/Providers/WebIO.Connection.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System.Diagnostics; 5 | using IDVal = System.Int32; // type of Event.pid/tid / ideally: System.UInt32 6 | using QWord = System.UInt64; 7 | 8 | using static NetBlameCustomDataSource.Util; 9 | 10 | namespace NetBlameCustomDataSource.WebIO 11 | { 12 | public class Connection 13 | { 14 | public QWord qwConnection; // Other Requests may reference this Connection value. 15 | public uint cbSend; 16 | public uint cbRecv; 17 | public uint error; 18 | public Socket socket; // Other Requests may reference this socket. 19 | public string strHeader; 20 | 21 | // Thread for matching TcpIpEvents: ConnectionSocketConnect_Start matches TcpRequestConnect 22 | public IDVal tidTCB; 23 | 24 | // Thread of most recent Receive activity: ConnectionSocketReceive_Stop 25 | public IDVal tidRecv; 26 | 27 | // Because of a defect in the way ConnectionSocketSend.Stop works (in earlier versions of Windows), 28 | // we may have to collect cbSend indirectly. See SendSocketTCB. 29 | 30 | // Thread of most recent Send activity, between: ConnectionSocketSend_Start/Stop 31 | public IDVal tidSend; 32 | public uint cbSendTCB; 33 | 34 | public QWord ctxSend; 35 | public QWord ctxRecv; 36 | 37 | // There's another one of these used by an earlier Request. 38 | public bool fDuplicate; 39 | #if DEBUG 40 | public bool fOutdated; 41 | public bool fTransferred; 42 | #endif // DEBUG 43 | 44 | public Connection(QWord qwConnection, Socket socket) 45 | { 46 | this.qwConnection = qwConnection; 47 | this.socket = socket; 48 | socket?.AddRef(); 49 | } 50 | 51 | public bool MatchTCB(uint iTCB, uint iDNS, uint iAddr, IDVal tid) 52 | { 53 | if (tid != 0 && this.tidTCB != tid) return false; 54 | if (this.socket.iTCB != 0) 55 | return this.socket.iTCB == iTCB; // TCB + maybe tid: fairly confident 56 | else if (tid != 0) 57 | return this.socket.iDNS == iDNS && this.socket.iAddr == iAddr; // DNS + tid: fairly confident 58 | else 59 | return false; // no TCB, no tid: very uncertain 60 | } 61 | 62 | [Conditional("DEBUG")] 63 | public void TestSocket(in Microsoft.Windows.EventTracing.Events.IGenericEvent evt, QWord qwCxn) 64 | { 65 | QWord qwSocket = evt.TryGetUInt64("SocketHandle"); // ConnectSocketStop, etc. 66 | if (qwSocket == 0) 67 | qwSocket = evt.TryGetUInt64("Socket"); // ConnectSocketClose 68 | #if DEBUG 69 | AssertCritical(qwSocket != 0); 70 | AssertCritical(this.socket != null); 71 | AssertImportant(this.socket.qwSocket == qwSocket || (this.socket.FClosed && qwSocket == QWord.MaxValue)); 72 | AssertImportant(this.socket.qwConnection == qwCxn); 73 | AssertImportant(this.qwConnection == qwCxn); 74 | #endif // DEBUG 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /src/BETA/PMCs.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM Copyright (c) Microsoft Corporation. 4 | REM Licensed under the MIT License. 5 | 6 | setlocal 7 | 8 | set _ETL_PATH="%LOCALAPPDATA%\MSO-Scripts\PMCs_XPerf.etl" 9 | 10 | REM Min Interval is usually 4096. Run: XPerf -PMCSources 11 | set _INTERVAL_=4096 12 | 13 | call :ParsePMC CacheMisses BranchMispredictions 14 | 15 | if [%1]==[-?] goto :Usage 16 | if [%1]==[/?] goto :Usage 17 | 18 | if not [%1]==[] call :ParsePMC %* 19 | 20 | set _TEMP_PATH="%TEMP%\PMCs_xperfT.etl" 21 | set _XPERF_PARAMS=-on PROC_THREAD+LOADER+PMC_PROFILE -StackWalk PmcInterrupt -PmcProfile %_PROFILE% %_PROFINT% -f %_TEMP_PATH% 22 | 23 | if defined OVerbose echo xperf %_XPERF_PARAMS% 24 | call xperf %_XPERF_PARAMS% || ( 25 | if not defined OVerbose echo xperf %_XPERF_PARAMS% 26 | echo: 27 | call :TestAdmin 28 | if errorlevel 1 echo Be sure to run with Administrator permissions.& exit /b 2 29 | echo Run: XPerf -PMCSources 30 | echo Check that the counter is listed: %_PROFILE% 31 | echo If there is only one entry listed then this may be a HyperV server. 32 | exit /b 3 33 | ) 34 | 35 | echo Tracing has begun. Exercise the code. 36 | @pause 37 | echo Processing... 38 | 39 | set _XPERF_PARAMS=-stop -d %_ETL_PATH% 40 | if defined OVerbose echo xperf %_XPERF_PARAMS% 41 | call xperf %_XPERF_PARAMS% || ( 42 | if not defined OVerbose echo xperf %_XPERF_PARAMS% 43 | exit /b errorlevel 44 | ) 45 | 46 | set _WPA_PARAMS=%_ETL_PATH% -symbols 47 | if not defined _NT_SYMBOL_PATH if defined _NT_SYMCACHE_PATH ( 48 | set _WPA_PARAMS=%_WPA_PARAMS% -symcacheonly 49 | if defined OVerbose echo: & echo Enabling only SymCache: %_NT_SYMCACHE_PATH% 50 | if defined OVerbose echo https://learn.microsoft.com/en-us/windows-hardware/test/wpt/loading-symbols#symcache-path 51 | ) 52 | set _WPA_PARAMS=%_WPA_PARAMS% -profile "%~dp0WPAP\CPUCounters.wpaProfile" 53 | echo: 54 | echo Launching WPA 55 | if defined OVerbose echo wpa %_WPA_PARAMS% 56 | start "WPA" /MAX /ABOVENORMAL wpa %_WPA_PARAMS% 57 | 58 | exit /b errorlevel 59 | 60 | :ParsePMC 61 | REM Expect names of Processor Monitor Counters. Run: WPR -PMCSources 62 | set _PROFILE=%1 63 | set _PROFINT=-SetProfInt %1 4096 64 | :PMCLoop 65 | shift 66 | if [%1]==[] exit /b 67 | set _PROFILE=%_PROFILE%,%1 68 | set _PROFINT=%_PROFINT% -SetProfInt %1 %_INTERVAL_% 69 | goto :PMCLoop 70 | 71 | :TestAdmin 72 | net session >nul 2>&1 73 | exit /b errorlevel 74 | 75 | :Usage 76 | echo Usage: 77 | echo %~nx0 78 | echo Sampled profiling: %_PROFILE% 79 | echo: 80 | echo %~nx0 [PMC1 [PMC2 ...]] 81 | echo Sampled profiling: PMC1,PMC2,... 82 | echo: 83 | echo PMC = Processor/Performance Monitor Counter 84 | echo For a list of available PMCs, run: XPerf -PMCSources 85 | echo To expand the list, run: Generate-PmuRegFile 86 | if not defined OVerbose echo: & echo Verbose output: set OVerbose=1 87 | echo: 88 | echo https://github.com/microsoft/MSO-Scripts/wiki/Customize-Tracing#pmu 89 | echo https://learn.microsoft.com/en-us/windows-hardware/test/wpt/recording-pmu-events 90 | exit /b 1 91 | -------------------------------------------------------------------------------- /src/WPAP/OfficeSpecial.regions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/NetBlame/Providers/WebIO.Session.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | 6 | using Microsoft.Windows.EventTracing.Symbols; 7 | 8 | using NetBlameCustomDataSource.Link; 9 | 10 | using static NetBlameCustomDataSource.Util; 11 | 12 | using TimestampUI = Microsoft.Performance.SDK.Timestamp; 13 | 14 | using IDVal = System.Int32; // type of Event.pid/tid / ideally: System.UInt32 15 | using QWord = System.UInt64; 16 | 17 | 18 | namespace NetBlameCustomDataSource.WebIO 19 | { 20 | public class Session 21 | { 22 | public readonly QWord qwSession; 23 | #if DEBUG 24 | public readonly QWord qwHandle; 25 | #endif // DEBUG 26 | 27 | public readonly TimestampUI timeOpen; 28 | public TimestampUI timeClose; 29 | 30 | public uint iRequestFirst; 31 | 32 | public IDVal pid; 33 | public IDVal tidStack; 34 | public IStackSnapshot stack; 35 | public XLink xlink; 36 | 37 | public Session(QWord qwSession, QWord qwHandle, in TimestampUI timeStamp) 38 | { 39 | this.qwSession = qwSession; 40 | #if DEBUG 41 | this.qwHandle = qwHandle; 42 | #endif // DEBUG 43 | 44 | this.timeOpen = timeStamp; 45 | this.timeClose.SetMaxValue(); 46 | } 47 | } 48 | 49 | public class SessionTable : List 50 | { 51 | // TODO: smarter capacity? 52 | public SessionTable(int capacity) : base(capacity) { } 53 | 54 | // 1-based index -> session or null 55 | public Session SessionFromI(uint iSession) => (iSession != 0) ? this[(int)iSession - 1] : null; 56 | 57 | public uint IFindSession(QWord qwSession, QWord qwHandle, in TimestampUI timeStamp) 58 | { 59 | for (int iSession = this.Count - 1; iSession >= 0; --iSession) 60 | { 61 | Session session = this[iSession]; 62 | if (session.qwSession == qwSession && timeStamp.Between(session.timeOpen, session.timeClose)) 63 | { 64 | #if DEBUG 65 | AssertImportant(FImplies(qwHandle != 0, qwHandle == session.qwHandle)); 66 | #endif // DEBUG 67 | return (uint)iSession+1; 68 | } 69 | } 70 | return 0; 71 | } 72 | 73 | public void AddSession(QWord qwSession, QWord qwHandle, IDVal pidT, IDVal tidT, in TimestampUI timeStampUI, in IStackSnapshot stackT, in Thread.ThreadTable threadTable) 74 | { 75 | AssertImportant(IFindSession(qwSession, qwHandle, in timeStampUI) == 0); 76 | 77 | Session session = new Session(qwSession, qwHandle, in timeStampUI) 78 | { 79 | pid = pidT, 80 | tidStack = tidT, 81 | stack = stackT 82 | }; 83 | session.xlink.GetLink(tidT, timeStampUI, in threadTable); 84 | this.Add(session); 85 | } 86 | 87 | public void CloseSession(QWord qwSession, QWord qwHandle, in TimestampUI timeStamp) 88 | { 89 | uint iSession = IFindSession(qwSession, qwHandle, timeStamp); 90 | if (iSession != 0) 91 | { 92 | Session session = SessionFromI(iSession); 93 | AssertImportant(timeStamp.Between(session.timeOpen, session.timeClose)); 94 | AssertImportant(session.timeClose.HasMaxValue()); 95 | session.timeClose = timeStamp; 96 | } 97 | } 98 | } // SessionTable 99 | } // namespace NetBlameCustomDataSource.WebIO -------------------------------------------------------------------------------- /src/PreWin10/WPRP/JS.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 47 | 48 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 63 | 64 | 65 | 66 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/BETA/PMC.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM Copyright (c) Microsoft Corporation. 4 | REM Licensed under the MIT License. 5 | 6 | setlocal 7 | 8 | REM This is the kernel event which collects the PMC events. 9 | REM Run: XPerf -providers K 10 | set _COLLECTOR=CSWITCH 11 | 12 | REM Run: XPerf -help stackwalk 13 | set _CSTACK=CSWITCH 14 | 15 | set _ETL_PATH="%LOCALAPPDATA%\MSO-Scripts\PMC_XPerf.etl" 16 | 17 | call :ParsePMC TotalCycles InstructionRetired 18 | 19 | if [%1]==[-?] goto :Usage 20 | if [%1]==[/?] goto :Usage 21 | 22 | if not [%1]==[] call :ParsePMC %* 23 | 24 | set _TEMP_PATH="%TEMP%\PMC_xperfT.etl" 25 | set _XPERF_PARAMS=-on PROC_THREAD+LOADER+%_COLLECTOR% -stackwalk %_CSTACK% -Pmc %_PROFILE% %_COLLECTOR% strict -f %_TEMP_PATH% 26 | 27 | if defined OVerbose echo xperf %_XPERF_PARAMS% 28 | call xperf %_XPERF_PARAMS% || ( 29 | if not defined OVerbose echo xperf %_XPERF_PARAMS% 30 | echo: 31 | call :TestAdmin 32 | if errorlevel 1 echo Be sure to run with Administrator permissions.& exit /b 2 33 | echo Run: XPerf -PMCSources 34 | echo Check that the counter is listed: %_PROFILE% 35 | echo If there is only one entry listed then this may be a HyperV server. 36 | exit /b 3 37 | ) 38 | 39 | echo Exercise the code. Tracing has begun: %_PROFILE% on %_COLLECTOR% 40 | @pause 41 | echo Processing... 42 | 43 | set _XPERF_PARAMS=-stop -d %_ETL_PATH% 44 | if defined OVerbose echo xperf %_XPERF_PARAMS% 45 | call xperf %_XPERF_PARAMS% || ( 46 | if not defined OVerbose echo xperf %_XPERF_PARAMS% 47 | exit /b errorlevel 48 | ) 49 | 50 | set _WPA_PARAMS=%_ETL_PATH% -symbols 51 | if not defined _NT_SYMBOL_PATH if defined _NT_SYMCACHE_PATH ( 52 | set _WPA_PARAMS=%_WPA_PARAMS% -symcacheonly 53 | if defined OVerbose echo: & echo Enabling only SymCache: %_NT_SYMCACHE_PATH% 54 | if defined OVerbose echo https://learn.microsoft.com/en-us/windows-hardware/test/wpt/loading-symbols#symcache-path 55 | ) 56 | set _WPA_PARAMS=%_WPA_PARAMS% -profile "%~dp0WPAP\CPUCounters.wpaProfile" 57 | echo: 58 | echo Launching WPA 59 | if defined OVerbose echo wpa %_WPA_PARAMS% 60 | start "WPA" /MAX /ABOVENORMAL wpa %_WPA_PARAMS% 61 | 62 | exit /b errorlevel 63 | 64 | :ParsePMC 65 | REM Expect names of Processor Monitor Counters. Run: WPR -PMCSources 66 | set _PROFILE=%1 67 | :PMCLoop 68 | shift 69 | if [%1]==[] exit /b 70 | set _PROFILE=%_PROFILE%,%1 71 | goto :PMCLoop 72 | 73 | :TestAdmin 74 | net session >nul 2>&1 75 | exit /b errorlevel 76 | 77 | :Usage 78 | echo Usage: 79 | echo %~nx0 80 | echo Tracing: %_PROFILE% 81 | echo Collected at each %_COLLECTOR% 82 | echo This is the Cycles per Instruction (CPI) configuration understood by WPA. 83 | echo: 84 | echo %~nx0 [PMC1 [PMC2 ...]] 85 | echo Tracing: PMC1,PMC2,... 86 | echo: 87 | echo PMC = Processor/Performance Monitor Counter 88 | echo For a list of available PMCs, run: XPerf -PMCSources 89 | echo To expand the list, run: Generate-PmuRegFile 90 | if not defined OVerbose echo: & echo Verbose output: set OVerbose=1 91 | echo: 92 | echo https://github.com/microsoft/MSO-Scripts/wiki/Customize-Tracing#pmu 93 | echo https://learn.microsoft.com/en-us/windows-hardware/test/wpt/recording-pmu-events 94 | exit /b 1 95 | -------------------------------------------------------------------------------- /src/ResetWPA.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Reset the Windows Performance Analyzer (WPA) 10 | by removing data and configuration files. 11 | 12 | Preserves Window Preferences (including the Symbol Paths) if not -All. 13 | Saves a copy of WindowPreferences.xml to %TEMP%. 14 | #> 15 | [CmdletBinding()] 16 | Param ( 17 | # Remove All: Do not preserve Window Preferences or Symbol Settings. 18 | [switch]$All = $false 19 | ) 20 | 21 | $WPA_1A = "$env:TEMP\WpaPackage" 22 | $WPA_1B = "$env:TEMP\WPA" 23 | $WPA_1C = "$env:TEMP\WPA Recovered Profile" 24 | $WPA_1D = "$env:TEMP\Windows Performance Analyzer" 25 | $WPA_2 = "$env:USERPROFILE\Documents\WPA Files" 26 | $WPA_3 = "$env:LOCALAPPDATA\Windows Performance Analyzer" 27 | $WPA_4 = "$env:LOCALAPPDATA\wpa" 28 | $WPA_PREF = "WindowPreferences.xml" 29 | 30 | 31 | function DeleteFolder 32 | { 33 | Param ( 34 | [string]$Path 35 | ) 36 | Write-Verbose "Testing: $Path" 37 | 38 | if (Test-Path $Path -ErrorAction:SilentlyContinue -ErrorVariable Err) 39 | { 40 | Write-Output "Removing: $Path" 41 | 42 | # Avoid overlong path issues by using CMD's rmdir: 43 | Invoke-Expression "cmd.exe /c rmdir /s /q `"$Path`" 2>&1" -ErrorVariable Err >$Null 44 | # rmdir -Recurse "$Path" -ErrorAction:SilentlyContinue -ErrorVariable Err 45 | } 46 | 47 | if ($Err) 48 | { 49 | $Err = $($Err[0] -split "`n") # convert to one line 50 | Write-Output "$Err : $Path" 51 | } 52 | } 53 | 54 | # Main 55 | 56 | Write-Output "Resetting WPA settings and storage." 57 | 58 | DeleteFolder $WPA_1A 59 | 60 | DeleteFolder $WPA_1B 61 | 62 | DeleteFolder $WPA_1C 63 | 64 | DeleteFolder $WPA_1D 65 | 66 | DeleteFolder $WPA_2 67 | 68 | if ($All) 69 | { 70 | DeleteFolder $WPA_4 71 | } 72 | 73 | # Delete the "Windows Performance Analyzer" folder, but optionally save/restore WPA Window Settings: WindowsPreferences.xml 74 | 75 | $WPA_PREF_Src = "$WPA_3\$WPA_PREF" 76 | $WPA_PREF_Dst = "$env:TEMP\$WPA_PREF" 77 | 78 | $Err = $True 79 | if (Test-Path -PathType Leaf $WPA_PREF_Src -ErrorAction:SilentlyContinue) 80 | { 81 | # Save a copy of WindowPreferences.xml to %TEMP%. 82 | # Possibly restore it. 83 | 84 | Copy-Item $WPA_PREF_Src -Destination $WPA_PREF_Dst -Force -ErrorAction:SilentlyContinue -ErrorVariable Err 85 | } 86 | 87 | DeleteFolder $WPA_3 88 | 89 | if (!$Err) 90 | { 91 | # A copy of the WPA Windows Settings file was successfully saved. 92 | # Either restore it or (verbose) note that it was saved. 93 | 94 | $dir = mkdir $WPA_3 -ErrorAction:SilentlyContinue 95 | 96 | if (!$All) 97 | { 98 | Copy-Item $WPA_PREF_Dst $WPA_PREF_Src -ErrorAction:SilentlyContinue -ErrorVariable Err2 99 | 100 | if (!$Err2) 101 | { 102 | Write-Output "Restoring WPA Window Settings" 103 | } 104 | else 105 | { 106 | Write-Output "WPA Window Settings could not be restored to: `"$WPA_PREF_Src`"" 107 | Write-Output "A copy was saved to: `"$WPA_PREF_Dst`"" 108 | } 109 | } 110 | else 111 | { 112 | Write-Verbose "WPA Windows Settings were saved to: `"$WPA_PREF_Dst`"" 113 | Write-Verbose "From: `"$WPA_PREF_Src`"" 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/WPAP/VirtualAlloc.stacktags: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/NetBlame/Providers/WThreadPool.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | using NetBlameCustomDataSource.WThreadPool.Callback; 7 | using NetBlameCustomDataSource.WThreadPool.Classic; 8 | using NetBlameCustomDataSource.WThreadPool.Timer; 9 | 10 | 11 | namespace NetBlameCustomDataSource.WThreadPool 12 | { 13 | public enum WTP : byte 14 | { 15 | // These are opcodes, not record IDs. 16 | // See ntwmi.w "Event Types for ThreadPool" 17 | 18 | CallbackEnqueue = 0x20, // 32 19 | CallbackDequeue = 0x21, // 33 20 | CallbackStart = 0x22, // 34 21 | CallbackStop = 0x23, // 35 22 | CallbackCancel = 0x24, // 36 23 | /* 24 | PoolCreate = 0x25, // 37 // PoolId:PTR 25 | PoolClose = 0x26, // 38 // PoolId:PTR 26 | */ 27 | TimerSet = 0x2A, // 42 28 | TimerCancel = 0x2B, // 43 29 | TimerSetNTTimer = 0x2C, // 44 // unused 30 | TimerExpireBegin = 0x2E, // 46 31 | TimerExpireEnd = 0x2F, // 47 32 | TimerExpiration = 0x30, // 48 33 | } 34 | 35 | 36 | public class WThreadPoolTable 37 | { 38 | public readonly WTPCallbackTable wtpCallbackTable; 39 | public readonly WTPTimerTable wtpTimerTable; 40 | 41 | public WThreadPoolTable(int capacity, in AllTables _allTables) 42 | { 43 | wtpCallbackTable = new WTPCallbackTable(capacity, in _allTables); 44 | wtpTimerTable = new WTPTimerTable(capacity, in _allTables); 45 | } 46 | 47 | 48 | public static readonly Guid guid = new Guid("{c861d0e2-a2c1-4d36-9f9c-970bab943a12}"); // Windows-ThreadPool 49 | 50 | public void Dispatch(in AltClassicEvent evtClassic) 51 | { 52 | switch (evtClassic.IdEvent) 53 | { 54 | // ThreadPool Callback Events 55 | 56 | case WTP.CallbackEnqueue: 57 | wtpCallbackTable.Enqueue(in evtClassic); 58 | break; 59 | 60 | case WTP.CallbackDequeue: 61 | // Ensure that this thread is marked as WThreadPool. 62 | wtpCallbackTable.allTables.threadTable.SetThreadPoolType(evtClassic.idThread, Thread.ThreadClass.WThreadPool); 63 | 64 | wtpCallbackTable.Dequeue(in evtClassic); 65 | break; 66 | 67 | case WTP.CallbackStart: // High Traffic? 68 | wtpCallbackTable.StartExec(in evtClassic); 69 | break; 70 | 71 | case WTP.CallbackStop: // High Traffic? 72 | wtpCallbackTable.EndExec(in evtClassic); 73 | break; 74 | 75 | case WTP.CallbackCancel: // TODO: Test this! 76 | wtpCallbackTable.Cancel(in evtClassic); 77 | break; 78 | 79 | // Timer Events 80 | 81 | case WTP.TimerSet: 82 | wtpTimerTable.Set(in evtClassic); 83 | break; 84 | 85 | case WTP.TimerExpiration: 86 | // Ensure that this thread is marked as WThreadPool. 87 | wtpTimerTable.allTables.threadTable.SetThreadPoolType(evtClassic.idThread, Thread.ThreadClass.WThreadPool); 88 | 89 | wtpTimerTable.Expiration(in evtClassic); 90 | break; 91 | 92 | case WTP.TimerExpireBegin: // TODO: DEBUG 93 | wtpTimerTable.ExpireBegin(in evtClassic); 94 | break; 95 | 96 | case WTP.TimerExpireEnd: 97 | wtpTimerTable.ExpireEnd(in evtClassic); 98 | break; 99 | 100 | case WTP.TimerCancel: 101 | wtpTimerTable.Cancel(in evtClassic); 102 | break; 103 | } // switch evtClassic.IdEvent 104 | } // Dispatch 105 | } // WThreadPool 106 | } // WThreadPoolNS -------------------------------------------------------------------------------- /src/WPRP/CLR.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 53 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 72 | 73 | 74 | 75 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/PreWin10/WPRP/CLR.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 54 | 55 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 71 | 72 | 73 | 74 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MSO-Scripts 2 | 3 | ### _Democratizing Windows Performance Analysis_ 4 | 5 | ## Documentation 6 | 7 | MSO-Scripts substantially facilitates the use of Microsoft's Event Tracing for Windows (ETW) technology for analyzing the resource consumption (CPU, Memory, I/O, Handles, Registry, ...) and performance behavior of Windows and its applications, particularly Microsoft Office. 8 | 9 | MSO-Scripts also [reveals detailed network activity](https://github.com/microsoft/MSO-Scripts/wiki/Network-Activity) by way of an add-in for the Windows Performance Analyzer (WPA). 10 | 11 | Please see [the wiki](../../wiki) for detailed documentation. 12 | 13 | ## Quick Start 14 | 15 | There are eleven customizable scripts for tracing various system resources: 16 | * TraceCPU 17 | * TraceFileDiskIO 18 | * TraceHandles   (_Kernel, GDI, and USER handles_) 19 | * TraceHeap        (_Windows Heap + VirtualAlloc_) 20 | * TraceHeapEx     (_Windows Heap + VirtualAlloc + Handles_) 21 | * TraceMemory   (_RAM usage, etc._) 22 | * TraceMondo     (_CPU + FileDiskIO + Handles + Network + Defender_) 23 | * TraceNetwork   (_Chromium, WinHTTP, WinINet, LDAP, WinSock, TcpIp_) 24 | * TraceOffice       (_Excel, OneNote, PowerPoint, Word: ETW Trace and Office Logs_) 25 | * TraceOutlook   (_ETW Trace and Office/Outlook Logs_) 26 | * TraceRegistry 27 | 28 | The scripts accept these tracing commands: Start, Stop, View, Status, Cancel
29 | These commands, except View, require Administrator privilege. 30 | 31 | To trace CPU activity: 32 | * Download and unzip [a recent Release of MSO-Scripts](https://github.com/microsoft/MSO-Scripts/releases), or clone the Repository: `<> Code ↓`
33 | * _MSO-Scripts_\\`TraceCPU Start`
34 | _Exercise the application/scenario._ 35 | * _MSO-Scripts_\\`TraceCPU Stop` 36 | * _MSO-Scripts_\\`TraceCPU View`   _Launches the [Windows Performance Analyzer](https://devblogs.microsoft.com/performance-diagnostics/wpa-intro/)_ 37 | 38 | List all options for TraceCPU: 39 | * _MSO-Scripts_\\`TraceCPU -?` 40 | 41 | [See the Wiki: TraceCPU](https://github.com/microsoft/MSO-Scripts/wiki/CPU-and-Threads) 42 | 43 | ## Contributing 44 | 45 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 46 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 47 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 48 | 49 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 50 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 51 | provided by the bot. You will only need to do this once across all repos using our CLA. 52 | 53 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 54 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 55 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 56 | 57 | ## Trademarks 58 | 59 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 60 | trademarks or logos is subject to and must follow 61 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 62 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 63 | Any use of third-party trademarks or logos are subject to those third-party's policies. 64 | -------------------------------------------------------------------------------- /src/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. Licensed under the MIT License. 2 | 3 | GOALS 4 | 5 | - It's easy to capture basic ETW traces of Office and other apps: CPU, Wait Analysis, Memory, Handles, File & Disk I/O, etc. 6 | - It's easy to analyze and understand the results. 7 | - It's easy to modify and to configure many combinations of data providers. 8 | - It works on Windows 10/11+, and as far back as Windows 7 / Server 2008-R2. 9 | - It requires no extra executables to be installed for trace collection (if Windows 10+). 10 | - It works with PowerShell (v2+), WPR (Windows Performance Recorder), and WPA (Windows Performance Analyzer). 11 | 12 | CUSTOMIZING RECORDING PROFILES 13 | 14 | MSO-Scripts includes a set of optimized recording profiles that will work well for many situations. 15 | They can also be customized. 16 | 17 | In Trace*.ps1, customize the recording profiles here: 18 | 19 | $TraceParams = 20 | @{ 21 | RecordingProfiles = 22 | @( 23 | # This is the base recording profile: 24 | ".\WPRP\.wprp!" 25 | 26 | # *** Additional recording profile strings go here. *** 27 | ) 28 | 29 | ... 30 | } 31 | 32 | Note that no .wprp file can be used more than once in a profiling session. 33 | 34 | Recording Profiles (Trace Collection Configuration Files) can take several forms: 35 | 36 | 1) Local profiles: ".\WPRP\SomeProfile.wprp!ProfileName" 37 | To list available profile names, run: WPR -profiles .\WPRP\.wprp 38 | 39 | ".\WPRP\FileDiskIO.wprp!FileIO" 40 | ".\WPRP\Handles.wprp!KernelHandles" 41 | 42 | Certain .wprp files have a version number in their name, which corresponds to the minimum version of WPR. 43 | For example, if the WPR version is 10.0.15002 or greater, then the newer version of Network.wprp will be used: 44 | 45 | ".\WPRP\Network.wprp!NetworkFull" becomes: ".\WPRP\Network.15002.wprp!NetworkFull" 46 | 47 | 2) OR built-in profiles 48 | To see a complete list, run: WPR -profiles 49 | 50 | "Registry" 51 | "DotNet" 52 | 53 | 3) OR other WPRP Recording Profiles: "\MyRecordingProfile.wprp!ProfileName" 54 | 55 | To see a list of available profiles, run: WPR -profiles \MyRecordingProfile.wprp 56 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/recording-profile-xml-reference 57 | 58 | "c:\MyProfiles\MyRecordingProfile.wprp!ProfileName" 59 | 60 | OPTIONAL ENVIRONMENT VARIABLES 61 | 62 | TRACE_PATH 63 | Path which receives generated traces and intermediate files. (Default = %LocalAppData%\MSO-Scripts) 64 | 65 | WPT_PATH 66 | Find wpr.exe and/or wpa.exe here from the Windows Performance Toolkit. 67 | 68 | WPT_WPRP 69 | Semi-colon separated list of additional WPR Recording Profiles (in any of the three formats listed above). 70 | 71 | WPT_XPERF 72 | Plus-sign separated list of additional ETW Providers (in XPerf -ON format): GUID|Name:KeywordFlags:Level:Stack 73 | 74 | WPT_MODE 75 | Special tracing mode - Shutdown 76 | 77 | _NT_SYMBOL_PATH 78 | Defines where to find and store symbol files (*.PDB). *** These files can be HUGE! *** 79 | 80 | _NT_SYMCACHE_PATH 81 | Defines where to find and store optimized symbol files (*.symcache). 82 | 83 | SYMBOL RESOLUTION 84 | 85 | https://github.com/microsoft/MSO-Scripts/wiki/Symbol-Resolution#native 86 | 87 | https://github.com/microsoft/MSO-Scripts/wiki/Advanced-Symbols#optimize 88 | 89 | If the _NT_SYM*_PATH environment variables are not set, the script for launching WPA will set default values. 90 | _NT_SYMBOL_PATH=cache*C:\Symbols;srv*https://msdl.microsoft.com/download/symbols 91 | _NT_SYMCACHE_PATH=C:\SymCache 92 | 93 | OLDER VERSIONS of the Windows Performance Toolkit WPT / WPA / WPR 94 | 95 | Scripts under the PreWin10 subfolder are for earlier versions of the Windows Performance Toolkit (WPT). 96 | They should run automatically, or they can be run directly from the PreWin10 subfolder. 97 | -------------------------------------------------------------------------------- /src/PreWin10/TraceNetwork.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Capture and View an ETW trace: 10 | Network Activity 11 | 12 | .DESCRIPTION 13 | 14 | .\TraceNetwork Start [-Loop] [-CLR] [-JS] 15 | .\TraceNetwork Stop [-WPA] 16 | .\TraceNetwork View [-Path \MSO-Trace-Network.etl] 17 | .\TraceNetwork Status 18 | .\TraceNetwork Cancel 19 | -CLR: Resolve call stacks for C# (Common Language Runtime). 20 | -JS: Resolve call stacks for JavaScript. 21 | -WPA: Launch the WPA viewer (Windows Performance Analyzer) with the collected trace. 22 | -Path: Optional path to a previously collected trace. 23 | -Verbose 24 | 25 | These scripts work with pre-Win10 versions of the Windows Performance Toolkit (WPT). 26 | 27 | .LINK 28 | 29 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows 30 | https://learn.microsoft.com/en-us/shows/defrag-tools/39-windows-performance-toolkit 31 | #> 32 | 33 | [CmdletBinding(DefaultParameterSetName = "Start")] 34 | Param( 35 | # "Start, Stop, Status, Cancel, View" 36 | [Parameter(Position=0)] 37 | [string]$Command, 38 | 39 | # Record only the last few minutes of activity (circular memory buffer). 40 | [Parameter(ParameterSetName="Start")] 41 | [switch]$Loop, 42 | 43 | # "Support Common Language Runtime / C#" 44 | [Parameter(ParameterSetName="Start")] 45 | [switch]$CLR, 46 | 47 | # "Support JavaScript" 48 | [Parameter(ParameterSetName="Start")] 49 | [switch]$JS, 50 | 51 | # "Launch WPA after collecting the trace" 52 | [Parameter(ParameterSetName="Stop")] 53 | [switch]$WPA, 54 | 55 | # "Optional path to a previously collected trace: MSO-Trace-Network.etl" 56 | [Parameter(ParameterSetName="View")] 57 | [string]$Path 58 | 59 | # [switch]$Verbose # implicit 60 | ) 61 | 62 | if (!$Path) { $Path = $Null } # for PSv2 63 | 64 | # ===== CUSTOMIZE THIS ===== 65 | 66 | $TraceParams = 67 | @{ 68 | RecordingProfiles = 69 | @( 70 | # This XML file contains tracing parameters organized by ProfileName. 71 | # To see the available profiles, run: wpr -profiles .\WPRP\Network.wprp 72 | ".\WPRP\Network.wprp.Verbose" 73 | ".\WPRP\OfficeProviders.wprp.Light" # Code Markers 74 | <# 75 | ^^^ The first entry is the base recording profile for this script. 76 | vvv Additional recording profile string(s) follow. See ReadMe.txt 77 | 78 | "Registry" # Built-in 79 | ".\WPRP\FileDiskIO.wprp.Verbose" 80 | "c:\MyProfiles\MyRecordingProfile.wprp" 81 | #> 82 | ) 83 | 84 | # This is the arbitrary name of the tracing session/instance. 85 | InstanceName = "MSO-Trace-Network" 86 | } 87 | 88 | $ViewerParams = 89 | @{ 90 | # This configuration file organizes the data in the WPA viewer. 91 | # https://learn.microsoft.com/en-us/windows-hardware/test/wpt/view-profiles 92 | ViewerConfig = ".\WPAP\Network.wpaProfile" 93 | 94 | # The trace file name is: .etl 95 | TraceName = $TraceParams.InstanceName 96 | 97 | # Optional alternate path to a previously collected ETL trace: 98 | TraceFilePath = $Path 99 | } 100 | # ===== END CUSTOMIZE ==== 101 | 102 | if (!$script:PSScriptRoot) { $script:PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition } # for PSv2 103 | $script:ScriptHomePath = $PSScriptRoot 104 | $script:ScriptRootPath = Resolve-Path "$PSScriptRoot\.." 105 | $script:PSScriptParams = $script:PSBoundParameters # volatile 106 | 107 | . "$ScriptRootPath\INCLUDE.ps1" 108 | 109 | # Main 110 | 111 | $Result = ProcessTraceCommand $Command @TraceParams -Loop:$Loop -CLR:$CLR -JS:$JS 112 | ValidateResult "ProcessTraceCommand" $Result 113 | 114 | switch ($Result) 115 | { 116 | Started { Write-Msg "ETW Network tracing has begun.`nExercise the application, then run: $(GetScriptCommand) Stop [-WPA]`n" } 117 | Collected { WriteTraceCollected $TraceParams.InstanceName; if ($WPA) { LaunchViewer @ViewerParams } } 118 | View { LaunchViewer @ViewerParams } 119 | Error { exit 1 } 120 | } 121 | 122 | exit 0 # Success 123 | -------------------------------------------------------------------------------- /src/BETA/WPRP/RPC.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 42 | 43 | 44 | 45 | 46 | 47 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 62 | 67 | 68 | 69 | 70 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 89 | 90 | 91 | 92 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/NetBlame/Auxiliary/GeoLocation.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.IO; 7 | 8 | using System.Text.Json; 9 | using System.Text.Json.Serialization; 10 | 11 | using static NetBlameCustomDataSource.Util; 12 | 13 | namespace NetBlameCustomDataSource 14 | { 15 | /* 16 | This component uses the free IP-GeoLocation API from ip-api. 17 | - Service: https://ip-api.com 18 | - Attribution: Geolocation data provided by ip-api.com 19 | - License: Free for non-commercial use only 20 | - Rate limit: 45 requests per minute (free tier) 21 | */ 22 | static class GeoLocation 23 | { 24 | public static string Attribution => "\nIP GeoLocation powered by ip-api.com – the free, non-commercial API.\nhttps://www.ip-api.com"; 25 | 26 | static string strGeoService = "ip-api.com"; 27 | static string strGetGeoService1 = "http://ip-api.com/json/"; 28 | static string strGetGeoService2 = "?fields=status,message,country,regionName,city"; 29 | 30 | public class Place 31 | { 32 | [JsonPropertyName("status")] 33 | public string Status { get; set; } 34 | 35 | [JsonPropertyName("message")] 36 | public string Message { get; set; } 37 | 38 | [JsonPropertyName("country")] 39 | public string Country { get; set; } 40 | 41 | [JsonPropertyName("regionName")] 42 | public string Region { get; set; } 43 | 44 | [JsonPropertyName("city")] 45 | public string City { get; set; } 46 | } 47 | 48 | /* 49 | Return a string representing the geolocation of this IPAddress. 50 | Check first for special ranges representing LocalHost or a Local/Private Network. 51 | Then contact geoplugin.com to get a geo-location string. 52 | */ 53 | public static string GetGeoLocation(IPAddress ipAddr) 54 | { 55 | if (ipAddr == null) 56 | return string.Empty; 57 | 58 | string strAddrType = Util.AddressType(ipAddr); 59 | if (strAddrType != null) 60 | return strAddrType; 61 | 62 | if (ipAddr.IsIPv4MappedToIPv6) 63 | ipAddr = ipAddr.MapToIPv4(); 64 | 65 | string strRequest = strGetGeoService1 + ipAddr.ToString() + strGetGeoService2; 66 | 67 | Place place = null; 68 | 69 | try 70 | { 71 | HttpClient client = new HttpClient(); 72 | using HttpResponseMessage response = client.GetAsync(strRequest).GetAwaiter().GetResult(); 73 | 74 | if (response.StatusCode == HttpStatusCode.TooManyRequests) 75 | return "Too Many Requests: " + strGeoService; 76 | 77 | AssertImportant(response.StatusCode == HttpStatusCode.OK); 78 | 79 | response.EnsureSuccessStatusCode(); // may throw 80 | 81 | Stream stream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult(); 82 | AssertImportant(stream?.CanRead ?? false); 83 | 84 | // Parse the response JSON into: Country / Region / City 85 | 86 | if (stream?.CanRead ?? false) 87 | place = JsonSerializer.Deserialize(stream); 88 | } 89 | catch (System.Exception x) 90 | { 91 | return x.Message; 92 | } 93 | 94 | if (place == null) 95 | return Util.strNA; // N/A 96 | 97 | if (!place.Status.Equals("success")) 98 | return place.Message; 99 | 100 | // Turn the three location strings into one. 101 | 102 | System.Text.StringBuilder sbLocation = new System.Text.StringBuilder(32); 103 | 104 | if (!string.IsNullOrWhiteSpace(place.Country)) 105 | { 106 | if (!string.IsNullOrWhiteSpace(place.Region) && place.Country.Equals("United States")) 107 | place.Country = "USA"; 108 | 109 | sbLocation.Append(place.Country); 110 | } 111 | if (!string.IsNullOrWhiteSpace(place.Region)) // This is the State if the Country is USA. 112 | { 113 | sbLocation.Append(" / "); 114 | sbLocation.Append(place.Region); 115 | } 116 | if (!string.IsNullOrWhiteSpace(place.City)) 117 | { 118 | sbLocation.Append(" / "); 119 | sbLocation.Append(place.City); 120 | } 121 | 122 | AssertImportant(sbLocation.Length > 0); 123 | if (sbLocation.Length == 0) 124 | return Util.strNA; // N/A 125 | 126 | return sbLocation.ToString(); 127 | } // GetGeoLocation 128 | } // class GeoLocation 129 | } 130 | -------------------------------------------------------------------------------- /src/PreWin10/WPRP/ThreadPool.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 60 | 61 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 79 | 80 | 81 | 82 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/PreWin10/TraceMondo.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Capture and View an ETW trace: 10 | CPU Samples, Thread Dispatch, File I/O, Office Logging Providers, ThreadPool, Processes, Modules 11 | 12 | .DESCRIPTION 13 | 14 | .\TraceMondo Start [-Loop] [-CLR] [-JS] 15 | .\TraceMondo Stop [-WPA] 16 | .\TraceMondo View [-Path \MSO-Trace-CPU.etl] 17 | .\TraceMondo Status 18 | .\TraceMondo Cancel 19 | -Loop: Record only the last few minutes of activity (circular memory buffer). 20 | -CLR: Resolve call stacks for C# (Common Language Runtime). 21 | -JS: Resolve call stacks for JavaScript. 22 | -WPA: Launch the WPA viewer (Windows Performance Analyzer) with the collected trace. 23 | -Path: Optional path to a previously collected trace. 24 | -Verbose 25 | 26 | These scripts work with pre-Win10 versions of the Windows Performance Toolkit (WPT). 27 | 28 | .LINK 29 | 30 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows 31 | https://learn.microsoft.com/en-us/shows/defrag-tools/39-windows-performance-toolkit 32 | #> 33 | 34 | [CmdletBinding(DefaultParameterSetName = "Start")] 35 | Param( 36 | # "Start, Stop, Status, Cancel, View" 37 | [Parameter(Position=0)] 38 | [string]$Command, 39 | 40 | # Record only the last few minutes of activity (circular memory buffer). 41 | [Parameter(ParameterSetName="Start")] 42 | [switch]$Loop, 43 | 44 | # "Support Common Language Runtime / C#" 45 | [Parameter(ParameterSetName="Start")] 46 | [switch]$CLR, 47 | 48 | # "Support JavaScript" 49 | [Parameter(ParameterSetName="Start")] 50 | [switch]$JS, 51 | 52 | # "Launch WPA after collecting the trace" 53 | [Parameter(ParameterSetName="Stop")] 54 | [switch]$WPA, 55 | 56 | # "Optional path to a previously collected trace: MSO-Trace-Mondo.etl" 57 | [Parameter(ParameterSetName="View")] 58 | [string]$Path 59 | 60 | # [switch]$Verbose # implicit 61 | ) 62 | 63 | if (!$Path) { $Path = $Null } # for PSv2 64 | 65 | # ===== CUSTOMIZE THIS ===== 66 | 67 | $TraceParams = 68 | @{ 69 | RecordingProfiles = 70 | @( 71 | ".\WPRP\CPU.wprp.Verbose" 72 | ".\WPRP\FileDiskIO.wprp.Light" 73 | ".\WPRP\OfficeProviders.wprp" 74 | ".\WPRP\Network.wprp.Verbose" 75 | ".\WPRP\ThreadPool.wprp" 76 | ".\WPRP\Defender.wprp.Light" 77 | 78 | <# ^^^ The first entry is the base recording profile for this script. 79 | vvv Additional recording profile string(s) follow. See ReadMe.txt 80 | 81 | "Registry" # Built-in 82 | ".\WPRP\FileDiskIO.wprp.Verbose" 83 | "c:\MyProfiles\MyRecordingProfile.wprp" 84 | #> 85 | ) 86 | 87 | # This is the arbitrary name of the tracing session/instance: 88 | InstanceName = "MSO-Trace-Mondo" 89 | } 90 | 91 | $ViewerParams = 92 | @{ 93 | # This configuration file organizes the data in the WPA viewer. 94 | # https://learn.microsoft.com/en-us/windows-hardware/test/wpt/view-profiles 95 | ViewerConfig = ".\WPAP\CPU-FileIO.wpaProfile" 96 | 97 | # The default trace file name is: .etl 98 | TraceName = $TraceParams.InstanceName 99 | 100 | # Optional alternate path to a previously collected ETL trace: 101 | TraceFilePath = $Path 102 | } 103 | 104 | # ===== END CUSTOMIZE ==== 105 | 106 | if (!$script:PSScriptRoot) { $script:PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition } # for PSv2 107 | $script:ScriptHomePath = $PSScriptRoot 108 | $script:ScriptRootPath = Resolve-Path "$PSScriptRoot\.." 109 | $script:PSScriptParams = $script:PSBoundParameters # volatile 110 | 111 | . "$ScriptRootPath\INCLUDE.ps1" 112 | 113 | # Main 114 | $Result = ProcessTraceCommand $Command @TraceParams -Loop:$Loop -CLR:$CLR -JS:$JS 115 | ValidateResult "ProcessTraceCommand" $Result 116 | 117 | switch ($Result) 118 | { 119 | Started 120 | { 121 | # Call stacks with symbols are available for File I/O in Windows 8.0 (v6.2) and above. Disk I/O traces do collect call stacks. 122 | if (!(CheckOSVersion '6.2.0')) { Write-Warn "Warning: Call stacks with symbols for File I/O traces are available starting with Windows 8.0`n" } 123 | 124 | Write-Msg "ETW tracing has begun.`nExercise the application, then run: $(GetScriptCommand) Stop [-WPA]`n" 125 | } 126 | Collected { WriteTraceCollected $TraceParams.InstanceName; if ($WPA) { LaunchViewer @ViewerParams } } 127 | View { LaunchViewer @ViewerParams } 128 | Error { exit 1 } 129 | } 130 | 131 | exit 0 # Success 132 | -------------------------------------------------------------------------------- /src/PreWin10/TraceCPU.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Capture and View an ETW trace: 10 | CPU Samples, Thread Dispatch, Processes, Modules 11 | 12 | .DESCRIPTION 13 | 14 | .\TraceCPU Start [-Lean] [-Loop] [-CLR] [-JS] 15 | .\TraceCPU Stop [-WPA] 16 | .\TraceCPU View [-Path \MSO-Trace-CPU.etl] 17 | .\TraceCPU Status 18 | .\TraceCPU Cancel 19 | -Lean: Reduced data collection: no call stacks. 20 | -Loop: Record only the last few minutes of activity (circular memory buffer). 21 | -CLR: Resolve call stacks for C# (Common Language Runtime). 22 | -JS: Resolve call stacks for JavaScript. 23 | -WPA: Launch the WPA viewer (Windows Performance Analyzer) with the collected trace. 24 | -Path: Optional path to a previously collected trace. 25 | -Verbose 26 | 27 | These scripts work with pre-Win10 versions of the Windows Performance Toolkit (WPT). 28 | 29 | .LINK 30 | 31 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows 32 | https://learn.microsoft.com/en-us/shows/defrag-tools/39-windows-performance-toolkit 33 | #> 34 | 35 | [CmdletBinding(DefaultParameterSetName = "Start")] 36 | Param( 37 | # "Start, Stop, Status, Cancel, View" 38 | [Parameter(Position=0)] 39 | [string]$Command, 40 | 41 | # "Reduced data collection: no call stacks" 42 | [Parameter(ParameterSetName="Start")] 43 | [switch]$Lean, 44 | 45 | # Compatibility only 46 | [Parameter(ParameterSetName="Start")] 47 | [switch]$Lite, 48 | 49 | # Record only the last few minutes of activity (circular memory buffer). 50 | [Parameter(ParameterSetName="Start")] 51 | [switch]$Loop, 52 | 53 | # "Support Common Language Runtime / C#" 54 | [Parameter(ParameterSetName="Start")] 55 | [switch]$CLR, 56 | 57 | # "Support JavaScript" 58 | [Parameter(ParameterSetName="Start")] 59 | [switch]$JS, 60 | 61 | # "Launch WPA after collecting the trace" 62 | [Parameter(ParameterSetName="Stop")] 63 | [switch]$WPA, 64 | 65 | # "Optional path to a previously collected trace: MSO-Trace-CPU.etl" 66 | [Parameter(ParameterSetName="View")] 67 | [string]$Path 68 | 69 | # [switch]$Verbose # implicit 70 | ) 71 | 72 | if (!$Path) { $Path = $Null } # for PSv2 73 | 74 | # ===== CUSTOMIZE THIS ===== 75 | 76 | $TraceParams = 77 | @{ 78 | RecordingProfiles = 79 | @( 80 | # Capture CPU Samples and Dispatcher Info with call stacks for all processes. 81 | ".\WPRP\CPU.wprp.Verbose" 82 | ".\WPRP\OfficeProviders.wprp.Light" # Code Markers 83 | <# 84 | ^^^ The first entry is the base recording profile for this script. 85 | vvv Additional recording profile string(s) follow. See ReadMe.txt 86 | 87 | "Registry" # Built-in 88 | ".\WPRP\FileDiskIO.wprp.Verbose" 89 | "c:\MyProfiles\MyRecordingProfile.wprp" 90 | #> 91 | ) 92 | 93 | # This is the arbitrary name of the tracing session/instance: 94 | InstanceName = "MSO-Trace-CPU" 95 | } 96 | 97 | # Change the base recording profile: 98 | # Capture only "Lean" CPU Samples for all processes/modules. 99 | if ($Lean -or $Lite) { $TraceParams.RecordingProfiles = @( ".\WPRP\CPU.wprp.Light" ) } # Just this one recording profile. 100 | 101 | $ViewerParams = 102 | @{ 103 | # This configuration file organizes the data in the WPA viewer. 104 | # https://learn.microsoft.com/en-us/windows-hardware/test/wpt/view-profiles 105 | ViewerConfig = ".\WPAP\CPU.wpaProfile" 106 | 107 | # The default trace file name is: .etl 108 | TraceName = $TraceParams.InstanceName 109 | 110 | # Optional alternate path to a previously collected ETL trace: 111 | TraceFilePath = $Path 112 | } 113 | 114 | # ===== END CUSTOMIZE ==== 115 | 116 | if (!$script:PSScriptRoot) { $script:PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition } # for PSv2 117 | $script:ScriptHomePath = $PSScriptRoot 118 | $script:ScriptRootPath = Resolve-Path "$PSScriptRoot\.." 119 | $script:PSScriptParams = $script:PSBoundParameters # volatile 120 | 121 | . "$ScriptRootPath\INCLUDE.ps1" 122 | 123 | # Main 124 | 125 | $Result = ProcessTraceCommand $Command @TraceParams -Loop:$Loop -CLR:$CLR -JS:$JS 126 | ValidateResult "ProcessTraceCommand" $Result 127 | 128 | switch ($Result) 129 | { 130 | Started { Write-Msg "ETW CPU tracing has begun.`nExercise the application, then run: $(GetScriptCommand) Stop [-WPA]`n" } 131 | Collected { WriteTraceCollected $TraceParams.InstanceName; if ($WPA) { LaunchViewer @ViewerParams } } 132 | View { LaunchViewer @ViewerParams } 133 | Error { exit 1 } 134 | } 135 | 136 | exit 0 # Success 137 | -------------------------------------------------------------------------------- /src/PreWin10/TraceFileDiskIO.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Capture and View an ETW trace: 10 | File I/O, Disk I/O, Modules 11 | 12 | .DESCRIPTION 13 | 14 | .\TraceFileDiskIO Start [-Lean] [-Loop] [-CLR] [-JS] 15 | .\TraceFileDiskIO Stop [-WPA] 16 | .\TraceFileDiskIO View [-Path \MSO-Trace-FileDiskIO.etl] 17 | .\TraceFileDiskIO Status 18 | .\TraceFileDiskIO Cancel 19 | -Lean: Reduced data collection: no Disk I/O. 20 | -Loop: Record only the last few minutes of activity (circular memory buffer). 21 | -CLR: Resolve call stacks for C# (Common Language Runtime). 22 | -JS: Resolve call stacks for JavaScript. 23 | -WPA: Launch the WPA viewer (Windows Performance Analyzer) with the collected trace. 24 | -Path: Optional path to a previously collected trace. 25 | -Verbose 26 | 27 | These scripts work with pre-Win10 versions of the Windows Performance Toolkit (WPT). 28 | 29 | .LINK 30 | 31 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows 32 | https://learn.microsoft.com/en-us/shows/defrag-tools/39-windows-performance-toolkit 33 | #> 34 | 35 | [CmdletBinding(DefaultParameterSetName = "Start")] 36 | Param( 37 | # "Start, Stop, Status, Cancel, View" 38 | [Parameter(Position=0)] 39 | [string]$Command, 40 | 41 | # "Reduced data collection: no Disk I/O" 42 | [Parameter(ParameterSetName="Start")] 43 | [switch]$Lean, 44 | 45 | # Record only the last few minutes of activity (circular memory buffer). 46 | [Parameter(ParameterSetName="Start")] 47 | [switch]$Loop, 48 | 49 | # "Support Common Language Runtime / C#" 50 | [Parameter(ParameterSetName="Start")] 51 | [switch]$CLR, 52 | 53 | # "Support JavaScript" 54 | [Parameter(ParameterSetName="Start")] 55 | [switch]$JS, 56 | 57 | # "Launch WPA after collecting the trace" 58 | [Parameter(ParameterSetName="Stop")] 59 | [switch]$WPA, 60 | 61 | # "Optional path to a previously collected trace: MSO-Trace-FileDiskIO.etl" 62 | [Parameter(ParameterSetName="View")] 63 | [string]$Path 64 | 65 | # [switch]$Verbose # implicit 66 | ) 67 | 68 | if (!$Path) { $Path = $Null } # for PSv2 69 | 70 | # ===== CUSTOMIZE THIS ===== 71 | 72 | $TraceParams = 73 | @{ 74 | RecordingProfiles = 75 | @( 76 | # Capture FileIO and DiskIO events with call stacks for all processes. 77 | ".\WPRP\FileDiskIO.wprp" 78 | ".\WPRP\OfficeProviders.wprp.Light" # Code Markers 79 | <# 80 | ^^^ The first entry is the base recording profile for this script. 81 | vvv Additional recording profile string(s) follow. See ReadMe.txt 82 | 83 | "Registry" # Built-in 84 | ".\WPRP\Handles.wprp.Verbose" 85 | "c:\MyProfiles\MyRecordingProfile.wprp" 86 | #> 87 | ) 88 | 89 | # This is the arbitrary name of the tracing session/instance. 90 | InstanceName = "MSO-Trace-FileDiskIO" 91 | } 92 | 93 | if ($Lean) { $TraceParams.RecordingProfiles[0] = ".\WPRP\FileDiskIO.wprp.Light" } 94 | 95 | $ViewerParams = 96 | @{ 97 | # This configuration file organizes the data in the WPA viewer. 98 | ViewerConfig = ".\WPAP\FileDiskIO.wpaProfile" 99 | 100 | # The trace file name is: .etl 101 | TraceName = $TraceParams.InstanceName 102 | 103 | # Optional alternate path to a previously collected ETL trace: 104 | TraceFilePath = $Path 105 | } 106 | 107 | # ===== END CUSTOMIZE ==== 108 | 109 | if (!$script:PSScriptRoot) { $script:PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition } # for PSv2 110 | $script:ScriptHomePath = $PSScriptRoot 111 | $script:ScriptRootPath = Resolve-Path "$PSScriptRoot\.." 112 | $script:PSScriptParams = $script:PSBoundParameters # volatile 113 | 114 | . "$ScriptRootPath\INCLUDE.ps1" 115 | 116 | # Main 117 | 118 | $Result = ProcessTraceCommand $Command @TraceParams -Loop:$Loop -CLR:$CLR -JS:$JS 119 | ValidateResult "ProcessTraceCommand" $Result 120 | 121 | switch ($Result) 122 | { 123 | Started 124 | { 125 | # Call stacks with symbols are available for File I/O in Windows 8.0 (v6.2) and above. Disk I/O traces do collect call stacks. 126 | if (!(CheckOSVersion '6.2.0')) { Write-Warn "Warning: Call stacks with symbols for File I/O traces are available starting with Windows 8.0`n" } 127 | 128 | Write-Msg "ETW File and Disk I/O tracing has begun.`nExercise the application, then run: $(GetScriptCommand) Stop [-WPA]`n" 129 | } 130 | Collected { WriteTraceCollected $TraceParams.InstanceName; if ($WPA) { LaunchViewer @ViewerParams } } 131 | View { LaunchViewer @ViewerParams } 132 | Error { exit 1 } 133 | } 134 | 135 | exit 0 # Success 136 | -------------------------------------------------------------------------------- /src/PreWin10/TraceHandles.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Capture and View an ETW trace: 10 | Kernel Handles, Modules 11 | 12 | .DESCRIPTION 13 | 14 | .\TraceHandles Start [-Loop] [-CLR] [-JS] 15 | .\TraceHandles Stop [-WPA] 16 | .\TraceHandles View [-Path \MSO-Trace-Handles.etl] 17 | .\TraceHandles Status 18 | .\TraceHandles Cancel 19 | -Loop: Record only the last few minutes of activity (circular memory buffer). 20 | -CLR: Resolve call stacks for C# (Common Language Runtime). 21 | -JS: Resolve call stacks for JavaScript. 22 | -WPA: Launch the WPA viewer (Windows Performance Analyzer) with the collected trace. 23 | -Path: Optional path to a previously collected trace. 24 | -Verbose 25 | 26 | These scripts work with pre-Win10 versions of the Windows Performance Toolkit (WPT). 27 | 28 | .LINK 29 | 30 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows 31 | https://learn.microsoft.com/en-us/shows/defrag-tools/39-windows-performance-toolkit 32 | https://learn.microsoft.com/en-us/windows/desktop/SysInfo/object-categories 33 | #> 34 | 35 | [CmdletBinding(DefaultParameterSetName = "Start")] 36 | Param( 37 | # "Start, Stop, Status, Cancel, View" 38 | [Parameter(Position=0)] 39 | [string]$Command, 40 | 41 | # Record only the last few minutes of activity (circular memory buffer). 42 | [Parameter(ParameterSetName="Start")] 43 | [switch]$Loop, 44 | 45 | # "Support Common Language Runtime / C#" 46 | [Parameter(ParameterSetName="Start")] 47 | [switch]$CLR, 48 | 49 | # "Support JavaScript" 50 | [Parameter(ParameterSetName="Start")] 51 | [switch]$JS, 52 | 53 | # "Launch WPA after collecting the trace" 54 | [Parameter(ParameterSetName="Stop")] 55 | [switch]$WPA, 56 | 57 | # "Optional path to a previously collected trace: MSO-Trace-Handles.etl" 58 | [Parameter(ParameterSetName="View")] 59 | [string]$Path 60 | 61 | # [switch]$Verbose # implicit 62 | ) 63 | 64 | if (!$Path) { $Path = $Null } # for PSv2 65 | 66 | # ===== CUSTOMIZE THIS ===== 67 | 68 | $TraceParams = 69 | @{ 70 | RecordingProfiles = 71 | @( 72 | # This XML file contains tracing parameters for Windows Kernel Object Handles. 73 | ".\WPRP\Handles.wprp.Light" 74 | ".\WPRP\OfficeProviders.wprp.Light" # Code Markers 75 | <# 76 | ^^^ The first entry is the base recording profile for this script. 77 | vvv Additional recording profile string(s) follow. See ReadMe.txt 78 | 79 | "Registry" # Built-in 80 | ".\WPRP\FileDiskIO.wprp" 81 | "c:\MyProfiles\MyRecordingProfile.wprp" 82 | #> 83 | ) 84 | 85 | # This is the arbitrary name of the tracing session/instance. 86 | InstanceName = "MSO-Trace-Handles" 87 | } 88 | 89 | $ViewerParams = 90 | @{ 91 | # This configuration file organizes the data in the WPA viewer. 92 | # https://learn.microsoft.com/en-us/windows-hardware/test/wpt/view-profiles 93 | ViewerConfig = ".\WPAP\Handles.wpaProfile" 94 | 95 | # The trace file name is: .etl 96 | TraceName = $TraceParams.InstanceName 97 | 98 | # Optional alternate path to a previously collected ETL trace: 99 | TraceFilePath = $Path 100 | } 101 | 102 | # ===== END CUSTOMIZE ==== 103 | 104 | if (!$script:PSScriptRoot) { $script:PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition } # for PSv2 105 | $script:ScriptHomePath = $PSScriptRoot 106 | $script:ScriptRootPath = Resolve-Path "$PSScriptRoot\.." 107 | $script:PSScriptParams = $script:PSBoundParameters # volatile 108 | 109 | . "$ScriptRootPath\INCLUDE.ps1" 110 | 111 | # Main 112 | 113 | # Tracing kernel handles is available in Windows 8.0 (v6.2) and above. 114 | 115 | if (!(CheckOSVersion '6.2.0')) 116 | { 117 | Write-Err "`nHandle tracing is available starting with Windows 8.0" 118 | exit 1 119 | } 120 | 121 | $Result = ProcessTraceCommand $Command @TraceParams -Loop:$Loop -CLR:$CLR -JS:$JS 122 | ValidateResult "ProcessTraceCommand" $Result 123 | 124 | switch ($Result) 125 | { 126 | Started 127 | { 128 | Write-Msg "ETW Handle tracing has begun.`nExercise the application, then run: $(GetScriptCommand) Stop [-WPA]`n" 129 | 130 | if (CheckOSVersion '10.0.18315') { break } 131 | 132 | Write-Warn "Tracing only Kernel Object Handles: Process, Thread, Registry Key, File, etc." 133 | Write-Warn "To trace GDI and User Handles, a more recent version of Windows is required (10.0.18315+)." 134 | Write-Warn "See: https://learn.microsoft.com/en-us/windows/desktop/SysInfo/object-categories" 135 | Write-Warn 136 | } 137 | 138 | Collected { WriteTraceCollected $TraceParams.InstanceName; if ($WPA) { LaunchViewer @ViewerParams } } 139 | View { LaunchViewer @ViewerParams } 140 | Error { exit 1 } 141 | } 142 | 143 | exit 0 # Success 144 | -------------------------------------------------------------------------------- /src/PreWin10/WPRP/VirtualAlloc.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 106 | 107 | 108 | 109 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /src/PreWin10/TraceMemory.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Capture and View an ETW trace: 10 | RAM Usage (Reference Set), VirtualAlloc, Processes, Modules 11 | 12 | .DESCRIPTION 13 | 14 | .\TraceMemory Start [-Lean] [-Loop] [-CLR] [-JS] 15 | .\TraceMemory Stop [-WPA] 16 | .\TraceMemory View [-Path \MSO-Trace-Memory.etl] 17 | .\TraceMemory Status 18 | .\TraceMemory Cancel 19 | -Lean: Reduced data collection: memory snapshots every 0.5 sec. 20 | -Loop: Record only the last few minutes of activity (circular memory buffer). 21 | -CLR: Resolve call stacks for C# (Common Language Runtime). 22 | -JS: Resolve call stacks for JavaScript. 23 | -WPA: Launch the WPA viewer (Windows Performance Analyzer) with the collected trace. 24 | -Path: Optional path to a previously collected trace. 25 | -Verbose 26 | 27 | These scripts work with pre-Win10 versions of the Windows Performance Toolkit (WPT). 28 | 29 | .LINK 30 | 31 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows 32 | https://learn.microsoft.com/en-us/shows/defrag-tools/39-windows-performance-toolkit 33 | #> 34 | 35 | [CmdletBinding(DefaultParameterSetName = "Start")] 36 | Param( 37 | # "Start, Stop, Status, Cancel, View" 38 | [Parameter(Position=0)] 39 | [string]$Command, 40 | 41 | # "Reduced data collection: memory snapshots every 0.5 sec." 42 | [Parameter(ParameterSetName="Start")] 43 | [switch]$Lean, 44 | 45 | # "Same as 'Lean' (for compatiblity)" 46 | [Parameter(ParameterSetName="Start")] 47 | [switch]$Sample, 48 | 49 | # Record only the last few minutes of activity (circular memory buffer). 50 | [Parameter(ParameterSetName="Start")] 51 | [switch]$Loop, 52 | 53 | # "Support Common Language Runtime / C#" 54 | [Parameter(ParameterSetName="Start")] 55 | [switch]$CLR, 56 | 57 | # "Support JavaScript" 58 | [Parameter(ParameterSetName="Start")] 59 | [switch]$JS, 60 | 61 | # "Launch WPA after collecting the trace" 62 | [Parameter(ParameterSetName="Stop")] 63 | [switch]$WPA, 64 | 65 | # "Optional path to a previously collected trace: MSO-Trace-Memory.etl" 66 | [Parameter(ParameterSetName="View")] 67 | [string]$Path 68 | 69 | # [switch]$Verbose # implicit 70 | ) 71 | 72 | if (!$Path) { $Path = $Null } # for PSv2 73 | 74 | # ===== CUSTOMIZE THIS ===== 75 | $TraceParams = 76 | @{ 77 | RecordingProfiles = 78 | @( 79 | # Capture Memory Info (Reference Set, etc.) with call stacks for all processes. 80 | # To see the available profiles, run: wpr -profiles .\WPRP\Memory.wprp 81 | ".\WPRP\Memory.wprp.Verbose" 82 | ".\WPRP\OfficeProviders.wprp.Light" # Code Markers 83 | <# 84 | ^^^ The first entry is the base recording profile for this script. 85 | vvv Additional recording profile string(s) follow. See ReadMe.txt 86 | 87 | "Registry" # Built-in 88 | ".\WPRP\FileDiskIO.wprp" 89 | "c:\MyProfiles\MyRecordingProfile.wprp.Light" 90 | #> 91 | ) 92 | 93 | # This is the arbitrary name of the tracing session/instance. 94 | InstanceName = "MSO-Trace-Memory" 95 | } 96 | 97 | # Capture only snapshots per process every 1/2 second: 98 | if ($Lean -or $Sample) { $TraceParams.RecordingProfiles = @( ".\WPRP\Memory.wprp.Light" ) } # Just this one recording profile. 99 | 100 | $ViewerParams = 101 | @{ 102 | # This configuration file organizes the data in the WPA viewer. 103 | ViewerConfig = ".\WPAP\Memory.wpaProfile" 104 | 105 | # The trace file name is: .etl 106 | TraceName = $TraceParams.InstanceName 107 | 108 | # Optional alternate path to a previously collected ETL trace: 109 | TraceFilePath = $Path 110 | } 111 | # ===== END CUSTOMIZE ==== 112 | 113 | if (!$script:PSScriptRoot) { $script:PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition } # for PSv2 114 | $script:ScriptHomePath = $PSScriptRoot 115 | $script:ScriptRootPath = Resolve-Path "$PSScriptRoot\.." 116 | $script:PSScriptParams = $script:PSBoundParameters # volatile 117 | 118 | . "$ScriptRootPath\INCLUDE.ps1" 119 | 120 | # Main 121 | 122 | # Memory tracing of this type is very limited before Win8.0 (v6.2). 123 | if ($Lean -or $Sample) 124 | { 125 | if (!(CheckOSVersion '6.2.0')) 126 | { 127 | Write-Err "`nThis type of memory sampling is available only in Windows 8.0 and later." 128 | exit 1 129 | } 130 | } 131 | 132 | $Result = ProcessTraceCommand $Command @TraceParams -Loop:$Loop -CLR:$CLR -JS:$JS 133 | ValidateResult "ProcessTraceCommand" $Result 134 | 135 | switch ($Result) 136 | { 137 | Started 138 | { 139 | if (!(CheckOSVersion '6.2.0')) { Write-Warn "Warning: Call stacks for this type of memory tracing are available in Windows 8.0 and later.`n" } 140 | 141 | Write-Msg "ETW Memory tracing has begun." 142 | Write-Msg "Exercise the application, then run: $(GetScriptCommand) Stop [-WPA]" 143 | Write-Msg "(Do not quit the application until tracing is stopped!)" 144 | Write-Msg 145 | } 146 | Collected { WriteTraceCollected $TraceParams.InstanceName; if ($WPA) { LaunchViewer @ViewerParams } } 147 | View { LaunchViewer @ViewerParams } 148 | Error { exit 1 } 149 | } 150 | 151 | exit 0 # Success 152 | -------------------------------------------------------------------------------- /src/PreWin10/WPRP/Defender.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 70 | 71 | 72 | 73 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 90 | 91 | 92 | 93 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 111 | 112 | 113 | 114 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /src/SymbolScan.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | SymbolScan [-Allow | -Prevent] [-Verbose] 10 | -Allow: Let Windows Defender scan symbol and trace files (default). 11 | -Prevent: Windows Defender should not scan symbol and trace files (for speed). 12 | 13 | .DESCRIPTION 14 | 15 | Virus scanners may slow down symbol resolution by scanning the potentially large symbol files downloaded/created by WPA: *.pdb, *.symcache 16 | (Windows Performance Analyzer [WPA] downloads *.pdb files as *.error, and *.symcache files as *.pending, then renames them once completed.) 17 | 18 | To increase performance, add the symbol file extensions to the Windows Defender Exclusion List: .pdb, .symcache, .pending, .error 19 | Also add the ETW log extensions: .etl, .wpapk 20 | 21 | .LINK 22 | 23 | https://learn.microsoft.com/en-us/powershell/module/defender/add-mppreference 24 | #> 25 | 26 | Param ( 27 | # Windows Defender should scan trace/symbol files. 28 | #[Parameter(ParameterSetName="Scan")] 29 | [switch]$Allow, 30 | 31 | # Windows Defender should not scan trace/symbol files. 32 | [Parameter(ParameterSetName="NoScan")] 33 | [switch]$Prevent 34 | ) 35 | 36 | 37 | function GetArgs { return $Args } 38 | 39 | 40 | [array]$SymbolFileExtensions = GetArgs .etl .wpapk .pdb .symcache .pending .error 41 | 42 | 43 | <# 44 | Determine whether this script has Administrator privileges. 45 | #> 46 | function CheckAdminPrivilege 47 | { 48 | $Principal = [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent() 49 | $Administrator = [Security.Principal.WindowsBuiltInRole]::Administrator 50 | return $Principal.IsInRole($Administrator) 51 | } 52 | 53 | 54 | <# 55 | Add the file extensions to the Windows Defender Exclusion List: .etl, .wpapk, .pdb, .symcache, .pending, .error 56 | The -Undo switch removes these file extensions from the Wndows Defender Exclusion List. 57 | #> 58 | function ExcludeSymbolExtensions 59 | { 60 | Param( 61 | [switch]$Undo 62 | ) 63 | Write-Verbose "(Get-MpPreference).ExclusionExtension" 64 | [array]$ExclusionExtensions = (Get-MPPreference -ErrorAction:SilentlyContinue).ExclusionExtension 65 | 66 | # Get the intersection of the Symbol File Extensions with the current list of file extension exclusions. 67 | 68 | [array]$CommonExtensions = @() 69 | if ($ExclusionExtensions.length -ne 0) 70 | { 71 | Write-Verbose "$ExclusionExtensions" 72 | 73 | $CommonExtensions = Compare-Object -IncludeEqual -ExcludeDifferent -PassThru $SymbolFileExtensions $ExclusionExtensions 74 | } 75 | 76 | if ($Undo) 77 | { 78 | if ($CommonExtensions.length -eq 0) { return } # nothing to remove 79 | 80 | # Remove Symbol File Exclusions 81 | 82 | Write-Output "Allowing Windows Defender to scan the Symbol/Trace File Extensions:" 83 | Write-Output $CommonExtensions 84 | Write-Verbose "Remove-MpPreference -ExclusionExtension $CommonExtensions" 85 | Remove-MPPreference -ErrorAction:SilentlyContinue -ExclusionExtension $CommonExtensions >$Null 86 | } 87 | else 88 | { 89 | if ($CommonExtensions.length -eq $SymbolFileExtensions.length) { return } # nothing to add 90 | 91 | # Add Symbol File Exclusions 92 | 93 | Write-Verbose "Add-MpPreference -ExclusionExtension $SymbolFileExtensions" 94 | Add-MpPreference -ErrorAction:SilentlyContinue -ExclusionExtension $SymbolFileExtensions >$Null 95 | } 96 | 97 | # Double-check the result. 98 | 99 | Write-Verbose "(Get-MpPreference).ExclusionExtension" 100 | [array]$ExclusionExtensions = (Get-MPPreference -ErrorAction:SilentlyContinue).ExclusionExtension 101 | 102 | if ($ExclusionExtensions.length -eq 0) { return } 103 | 104 | Write-Verbose "$ExclusionExtensions" 105 | 106 | [array]$CommonExtensions = Compare-Object -IncludeEqual -ExcludeDifferent -PassThru $SymbolFileExtensions $ExclusionExtensions 107 | 108 | if ($CommonExtensions.length -eq 0) { return } 109 | 110 | if ($Undo) 111 | { 112 | Write-Output "Warning: These Symbol/Trace File Extensions remain on the Windows Defender Exclusion List:" $CommonExtensions 113 | } 114 | else 115 | { 116 | Write-Output "For speed, these Symbol/Trace File Extensions will not be scanned by Windows Defender:" 117 | Write-Output $CommonExtensions 118 | Write-Output $Null 119 | Write-Output "To undo this, run: $($script:MyInvocation.InvocationName -Replace ".ps1$") -Allow" 120 | } 121 | } # ExcludeSymbolExtensions 122 | 123 | 124 | function ListSymbolExtensions 125 | { 126 | Write-Verbose "(Get-MpPreference).ExclusionExtension" 127 | [array]$ExclusionExtensions = (Get-MPPreference -ErrorAction:SilentlyContinue).ExclusionExtension 128 | 129 | if ($ExclusionExtensions.length -ne 0) 130 | { 131 | Write-Verbose "$ExclusionExtensions" 132 | 133 | [array]$CommonExtensions = Compare-Object -IncludeEqual -ExcludeDifferent -PassThru $SymbolFileExtensions $ExclusionExtensions 134 | 135 | if ($CommonExtensions.length -ne 0) 136 | { 137 | Write-Output "These Symbol/Trace File Extensions will not be scanned by Windows Defender:" 138 | Write-Output $CommonExtensions 139 | return 140 | } 141 | } 142 | 143 | Write-Output "There are no Symbol/Trace File Extensions on the Windows Defender Exclusion List." 144 | } 145 | 146 | 147 | # Main 148 | 149 | if ([Environment]::OSVersion.Version.Major -lt 10) 150 | { 151 | Write-Output "Windows 10+ is required." 152 | return 153 | } 154 | 155 | if (!(CheckAdminPrivilege)) 156 | { 157 | Write-Output "Administrator Privilege is required." 158 | return 159 | } 160 | 161 | if ($Prevent) { ExcludeSymbolExtensions } 162 | elseif ($Allow) { ExcludeSymbolExtensions -Undo } 163 | else { ListSymbolExtensions } 164 | Write-Output $Null 165 | -------------------------------------------------------------------------------- /src/TraceRegistry.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Capture and View an ETW trace: 10 | Office Code Markers, Kernel Handles (including Registry Keys), Registry 11 | 12 | .DESCRIPTION 13 | 14 | Trace Registry activity. 15 | TraceRegistry Start [Start_Options] 16 | TraceRegistry Stop [-WPA [-FastSym]] 17 | 18 | Trace Windows Restart: Registry activity. 19 | TraceRegistry Start -Boot [Start_Options] 20 | TraceRegistry Stop -Boot [-WPA [-FastSym]] 21 | 22 | TraceRegistry View [-Path \MSO-Trace-Registry.etl|.wpapk] [-FastSym] 23 | TraceRegistry Status [-Boot] 24 | TraceRegistry Cancel [-Boot] 25 | 26 | -Boot: Trace Registry activity during the next Windows Restart. 27 | -WPA : Launch the WPA viewer (Windows Performance Analyzer) with the collected trace. 28 | -Path: Optional path to a previously collected trace. 29 | -FastSym: Load symbols only from cached/transcoded SymCache, not from slower PDB files. 30 | See: https://github.com/microsoft/MSO-Scripts/wiki/Advanced-Symbols#optimize 31 | -Verbose 32 | 33 | Start_Options 34 | -Loop: Record only the last few minutes of activity (circular memory buffer). 35 | -CLR : Resolve symbolic stackwalks for C# (Common Language Runtime). 36 | -JS : Resolve symbolic stackwalks for JavaScript. 37 | 38 | .LINK 39 | 40 | https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry 41 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows 42 | https://learn.microsoft.com/en-us/shows/defrag-tools/39-windows-performance-toolkit 43 | #> 44 | 45 | [CmdletBinding(DefaultParameterSetName = "View")] 46 | Param( 47 | # "Start, Stop, Status, Cancel, View" 48 | [Parameter(Position=0)] 49 | [string]$Command, 50 | 51 | # Record only the last few minutes of activity (circular memory buffer)."" 52 | [Parameter(ParameterSetName="Start")] 53 | [switch]$Loop, 54 | 55 | # "Trace Registry activity during the next Windows Restart." 56 | [switch]$Boot, 57 | 58 | # "Support Common Language Runtime / C#" 59 | [Parameter(ParameterSetName="Start")] 60 | [switch]$CLR, 61 | 62 | # "Support JavaScript" 63 | [Parameter(ParameterSetName="Start")] 64 | [switch]$JS, 65 | 66 | # "Launch WPA after collecting the trace" 67 | [Parameter(ParameterSetName="Stop")] 68 | [switch]$WPA, 69 | 70 | # "Optional path to a previously collected trace: MSO-Trace-Registry.etl" 71 | [Parameter(ParameterSetName="View")] 72 | [string]$Path = $Null, 73 | 74 | # "Faster symbol resolution by loading only from SymCache, not PDB" 75 | [Parameter(ParameterSetName="Stop")] 76 | [Parameter(ParameterSetName="View")] 77 | [switch]$FastSym 78 | 79 | # [switch]$Verbose # implicit 80 | ) 81 | 82 | # ===== CUSTOMIZE THIS ===== 83 | 84 | $TraceParams = 85 | @{ 86 | RecordingProfiles = 87 | @( 88 | ".\WPRP\Registry.wprp!Registry" # Includes Office CodeMarkers 89 | ".\WPRP\Handles.wprp!KernelHandles" 90 | ".\WPRP\OfficeProviders.wprp!CodeMarkers" # Code Markers, HVAs, other light logging 91 | 92 | <# ^^^ The first entry is the base recording profile for this script. 93 | vvv Additional recording profile string(s) follow. See ReadMe.txt 94 | 95 | "Registry" # Built-in 96 | ".\WPRP\FileDiskIO.wprp!FileIO" 97 | "c:\MyProfiles\MyRecordingProfile.wprp!CustomProfile" 98 | 99 | Other recording profiles can be added via the WPT_WPRP environment variable. 100 | $Env:WPT_WPRP="c:\path\MyProfile.wprp!ProfileName;c:\path\MyProfile2.wprp!ProfileName2" 101 | set WPT_WPRP=c:\path\MyProfile.wprp!ProfileName;c:\path\MyProfile2.wprp!ProfileName2 102 | 103 | Other recording providers can be added via the WPT_XPERF environment variable (in "XPerf -ON" format). 104 | $Env:WPT_XPERF="GUIDorNAME1 + GUIDorNAME2:::Stack + GUIDorNAME3:KeywordFlags:Level + ..." 105 | set WPT_XPERF=GUIDorNAME1 + GUIDorNAME2:::Stack + GUIDorNAME3:KeywordFlags:Level + ... 106 | 107 | See: https://github.com/microsoft/MSO-Scripts/wiki/Customize-Tracing#envvar 108 | #> 109 | ) 110 | 111 | ProviderManifests = 112 | @( 113 | # Optional: Register Office ETW Provider Manifests not registered by default. 114 | # See: .\OETW\ReadMe.txt 115 | ".\OETW\MsoEtwCM.man" # Office Code Markers 116 | ) 117 | 118 | # This is the arbitrary name of the tracing session/instance: 119 | InstanceName = "MSO-Trace-Registry" 120 | } 121 | 122 | $ViewerParams = 123 | @{ 124 | # The configuration files define the data tabs in the WPA viewer. 125 | # https://learn.microsoft.com/en-us/windows-hardware/test/wpt/view-profiles 126 | ViewerConfig = ".\WPAP\BasicInfo.wpaProfile", ".\WPAP\Registry.wpaProfile" 127 | 128 | # The default trace file name is: .etl 129 | TraceName = $TraceParams.InstanceName 130 | 131 | # Optional alternate path to a previously collected ETL trace: 132 | TraceFilePath = $Path 133 | } 134 | 135 | # ===== END CUSTOMIZE ==== 136 | 137 | if (!$script:PSScriptRoot) { $script:PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition } # for PSv2 138 | $script:ScriptHomePath = $PSScriptRoot 139 | $script:ScriptRootPath = $PSScriptRoot 140 | $script:PSScriptParams = $script:PSBoundParameters # volatile 141 | 142 | . "$ScriptRootPath\INCLUDE.ps1" 143 | 144 | # Main 145 | 146 | # Use Windows Performance Recorder. It's much simpler, but requires Admin privileges. 147 | 148 | $Result = ProcessTraceCommand $Command @TraceParams -Loop:$Loop -Boot:$Boot -CLR:$CLR -JS:$JS 149 | 150 | switch ($Result) 151 | { 152 | Started { Write-Msg "ETW tracing has begun.`nExercise the application, then run: $(GetScriptCommand) Stop [-WPA]`n" } 153 | Collected { WriteTraceCollected $TraceParams.InstanceName } # $WPA switch 154 | View { $WPA = $True } 155 | Success { $WPA = $False } 156 | Error { exit 1 } 157 | } 158 | 159 | if ($WPA) { LaunchViewer @ViewerParams -FastSym:$FastSym } 160 | 161 | exit 0 # Success 162 | -------------------------------------------------------------------------------- /src/PreWin10/WPRP/Handles.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 95 | 96 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 118 | 119 | 120 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 133 | 134 | 135 | 136 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/NetBlame/Auxiliary/Extensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Net; 8 | 9 | using Microsoft.Windows.EventTracing.Events; // IGenericEvent 10 | using Microsoft.Windows.EventTracing.Symbols; // IStackSnapshot 11 | 12 | using TimestampETW = Microsoft.Windows.EventTracing.TraceTimestamp; 13 | using TimestampUI = Microsoft.Performance.SDK.Timestamp; 14 | 15 | using AddressETW = Microsoft.Windows.EventTracing.Address; 16 | using AddrVal = System.UInt64; 17 | 18 | namespace NetBlameCustomDataSource 19 | { 20 | [System.Diagnostics.DebuggerStepThrough()] 21 | public static class Extensions 22 | { 23 | public static bool IsNA(this string str) => System.String.IsNullOrWhiteSpace(str) || str == Util.strNA; // "N/A" 24 | 25 | public static bool HasValue(this in TimestampUI time) => (time.ToNanoseconds != 0); // zero-initialized struct 26 | 27 | public static bool HasMaxValue(this in TimestampUI time) => (time == TimestampUI.MaxValue); 28 | 29 | public static void SetMaxValue(this ref TimestampUI time) { time = TimestampUI.MaxValue; } 30 | 31 | public static bool Between(this in TimestampUI tRef, in TimestampUI tFirst, in TimestampUI tLast) => tRef >= tFirst && tRef <= tLast; 32 | 33 | public static TimestampUI ToGraphable(this in TimestampETW time) => new TimestampUI(time.RelativeTimestamp.Nanoseconds); 34 | 35 | public static TimestampETW Zero(this in TimestampETW time) => new TimestampETW(time.Context, time.Context.ReferenceValue); 36 | 37 | public static AddrVal ToValue(this in AddressETW addr) => (AddrVal)addr.Value; 38 | 39 | public static bool Empty(this IPAddress ipAddr) => ipAddr == null || ipAddr.Equals(IPAddress.Any/*0.0.0.0*/) || ipAddr.AddressFamily == System.Net.Sockets.AddressFamily.Unspecified; 40 | 41 | public static bool Empty(this IPEndPoint ipep) => ipep == null || (ipep.Port == 0 && ipep.Address.Empty()); 42 | 43 | public static string ToGraphable(this IPAddress ipAddr) => ipAddr?.ToString() ?? String.Empty; 44 | 45 | public static string ToGraphable(this IPEndPoint ipEndPoint) => !ipEndPoint.Empty() ? ipEndPoint.ToString() : String.Empty; 46 | public static string AddrGraphable(this IPEndPoint ipEndPoint) => !ipEndPoint.Empty() ? ipEndPoint.Address.ToString() : String.Empty; 47 | public static uint PortGraphable(this IPEndPoint ipEndPoint) => (uint?)ipEndPoint?.Port ?? 0; 48 | 49 | public static bool Empty(this SocketAddress socket) => (socket == null || socket[0]/*family*/ == 0); 50 | 51 | // SocketAddress.Equals may give false negatives when the socket contains random padding bytes! 52 | public static bool SafeEquals(this SocketAddress socket, SocketAddress comparand) 53 | { 54 | if (socket == null || comparand == null) 55 | return false; 56 | 57 | if (socket.Family != comparand.Family) 58 | return false; 59 | 60 | if (socket.Port() != comparand.Port()) 61 | return false; 62 | 63 | if (socket.Equals(comparand)) 64 | return true; 65 | 66 | // Expensive! 67 | return Util.NewEndPoint(socket).Equals(Util.NewEndPoint(comparand)); 68 | } 69 | 70 | public static bool IsAddrZero(this SocketAddress socket) 71 | { 72 | #if DEBUG 73 | if (socket.Empty()) return true; 74 | 75 | switch (socket.Family) 76 | { 77 | case System.Net.Sockets.AddressFamily.InterNetwork: // IPv4 78 | return Util.NewEndPoint(socket).Address.Equals(IPAddress.Any); 79 | case System.Net.Sockets.AddressFamily.InterNetworkV6: // IPv6 80 | return Util.NewEndPoint(socket).Address.Equals(IPAddress.IPv6Any); 81 | } 82 | return false; 83 | #else 84 | throw new NotImplementedException("IsAddrZero: Not intended for release."); 85 | #endif // DEBUG 86 | } 87 | 88 | public static ushort Port(this SocketAddress socket) => (ushort)((socket[2] << 8) + socket[3]); 89 | 90 | public static UInt16 GetUInt16(this IGenericEvent evt, string strField) => evt.Fields[strField].AsUInt16; 91 | 92 | public static UInt32 GetUInt32(this IGenericEvent evt, string strField) => evt.Fields[strField].AsUInt32; 93 | 94 | public static UInt64 GetUInt64(this IGenericEvent evt, string strField) => evt.Fields[strField].AsUInt64; 95 | 96 | public static UInt64 TryGetUInt64(this IGenericEvent evt, string strField) => evt.Fields.TryGetValue(strField, out IGenericEventField field) ? field.AsUInt64 : 0; 97 | 98 | public static IReadOnlyList GetBinary(this IGenericEvent evt, string strField) => evt.Fields[strField].AsBinary; 99 | 100 | public static UInt64 GetAddrValue(this IGenericEvent evt, string strField) => evt.Fields[strField].AsAddress.ToValue(); 101 | 102 | public static UInt64 TryGetAddrValue(this IGenericEvent evt, string strField) => evt.Fields.TryGetValue(strField, out IGenericEventField field) ? field.AsAddress.ToValue() : 0; 103 | 104 | public static string GetString(this IGenericEvent evt, string strField) => evt.Fields[strField].AsString; 105 | 106 | public static string GetAddressString(this IGenericEvent evt) => (evt.GetUInt32("AddressLength") > 1) ? evt.GetString("Address") : null; // AddressLength includes 0 107 | 108 | public static SocketAddress GetSocketAddress(this IGenericEvent evt, string strField = "Address") => evt.Fields[strField].AsSocketAddress; 109 | 110 | public static SocketAddress GetLocalAddress(this IGenericEvent evt) => (evt.GetUInt32("LocalAddressLength") != 0) ? evt.GetSocketAddress("LocalAddress") : null; 111 | 112 | public static SocketAddress GetRemoteAddress(this IGenericEvent evt) => (evt.GetUInt32("RemoteAddressLength") != 0) ? evt.GetSocketAddress("RemoteAddress") : null; 113 | 114 | // Simple hash of all addresses in the stack. Returns 0 if none. 115 | public static int Hash(this IStackSnapshot ss) 116 | { 117 | if (ss?.Frames == null) return 0; 118 | 119 | int hash = 0; 120 | foreach (var frame in ss.Frames) 121 | hash ^= frame.Address.GetHashCode(); 122 | 123 | return hash; 124 | } 125 | } 126 | 127 | } // NetBlameCustomDataSource.Events 128 | -------------------------------------------------------------------------------- /src/NetBlame/Providers/Thread.Classic.cs: -------------------------------------------------------------------------------- 1 | // Copyright(c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Runtime.InteropServices; // StructLayout 7 | 8 | using Microsoft.Windows.EventTracing; // ClassicEvent 9 | 10 | using static NetBlameCustomDataSource.Util; 11 | 12 | using TimestampETW = Microsoft.Windows.EventTracing.TraceTimestamp; 13 | 14 | using DWId = System.Int32; // Process/ThreadID (ideally UInt32) 15 | 16 | using Addr32 = System.UInt32; 17 | using Addr64 = System.UInt64; 18 | 19 | 20 | namespace NetBlameCustomDataSource.Thread.Classic 21 | { 22 | #pragma warning disable 649 // StructFromBytes initializes the fields. 23 | 24 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 25 | public class ThreadClassicEvent 26 | { 27 | public readonly TimestampETW timeStamp; 28 | public readonly DWId pidInitiator; 29 | public DWId tidInitiator; 30 | public readonly byte opEvent; 31 | 32 | /* 33 | Initialize a sequential struct from payload bytes. 34 | */ 35 | public static void StructFromBytes(in ReadOnlySpan data, out T payload) where T : struct 36 | { 37 | bool fSuccess = MemoryMarshal.TryRead(data, out payload); 38 | AssertCritical(fSuccess); 39 | } 40 | 41 | public ThreadClassicEvent(in ClassicEvent evt) 42 | { 43 | this.pidInitiator = (DWId)evt.ProcessId; 44 | this.tidInitiator = (DWId)evt.ThreadId; 45 | this.opEvent = (byte)evt.Id; 46 | 47 | this.timeStamp = evt.Timestamp; 48 | 49 | if ((TEID)evt.Id != TEID.Rundown) return; 50 | 51 | // This is apparently what WPA does for rundown events: sets the (struct) timestamp to 0. 52 | this.timeStamp = evt.Timestamp.Zero(); 53 | 54 | AssertCritical(this.timeStamp.TotalMicroseconds == 0); 55 | } 56 | } // ThreadClassicEvent 57 | 58 | [StructLayout(LayoutKind.Sequential, Pack = 4)] 59 | public readonly struct ThreadEventPayload 60 | { 61 | public readonly DWId ProcessId; 62 | public readonly DWId ThreadId; 63 | } 64 | 65 | public class THREAD_EVENT : ThreadClassicEvent 66 | { 67 | public readonly ThreadEventPayload ThreadEvt; 68 | public readonly Addr64 ThreadProc; 69 | 70 | const DWId tidUnknown = -1; 71 | 72 | private Addr32 GetThreadProc32(in ClassicEvent evt) 73 | { 74 | if (evt.Data.Length < 2*sizeof(UInt32) + 6*sizeof(UInt32)) 75 | return 0; 76 | 77 | // Layout (wmicore.mof): PID (DW), TID (DW), (PTR)[5], ThreadProc (PTR) 78 | StructFromBytes(evt.Data.Slice(2*sizeof(UInt32) + 5*sizeof(UInt32), sizeof(UInt32)), out UInt32 threadProc); 79 | return threadProc; 80 | } 81 | 82 | private Addr64 GetThreadProc64(in ClassicEvent evt) 83 | { 84 | if (evt.Data.Length < 2*sizeof(UInt32) + 6*sizeof(UInt64)) 85 | return 0; 86 | 87 | // Layout (wmicore.mof): PID (DW), TID (DW), (PTR)[5], ThreadProc (PTR) 88 | StructFromBytes(evt.Data.Slice(2*sizeof(UInt32) + 5*sizeof(UInt64), sizeof(UInt64)), out UInt64 threadProc); 89 | return threadProc; 90 | } 91 | 92 | public THREAD_EVENT(in ClassicEvent evt) : base(in evt) 93 | { 94 | // There are multiple versions of this event class. 95 | // In any case, just get the first two DWORDs. 96 | StructFromBytes(evt.Data.Slice(0, 2*sizeof(UInt32)), out this.ThreadEvt); 97 | 98 | // If the thread "created itself" then the creator/initiator is unknown. 99 | if (this.tidInitiator == this.ThreadEvt.ThreadId && (TEID)evt.Id != TEID.Exit) 100 | this.tidInitiator = tidUnknown; 101 | 102 | // Get the ThreadProc address if available. (See wmicore.mof: "Thread Create/Exit Event") 103 | if (evt.Version > 0) 104 | { 105 | if (evt.Is32Bit) 106 | this.ThreadProc = GetThreadProc32(evt); 107 | else 108 | this.ThreadProc = GetThreadProc64(evt); 109 | } 110 | } 111 | } // THREAD_EVENT 112 | 113 | 114 | // Thread Event ID 115 | // cf. wmicore.mof 116 | enum TEID : byte 117 | { 118 | Create = 1, // EVENT_TRACE_TYPE_START 119 | Exit = 2, // EVENT_TRACE_TYPE_END 120 | Rundown = 3,// EVENT_TRACE_TYPE_DC_START 121 | } 122 | 123 | 124 | /* 125 | Parse classic events as they are pre-processed via: traceProcessor.Process() 126 | */ 127 | class ThreadEventConsumer 128 | { 129 | public Queue threadEventQueue; 130 | public Queue threadRundownQueue; 131 | #if DEBUG 132 | public bool FHaveRundown { get; set; } 133 | #else 134 | public bool FHaveRundown { get => true; set {} } 135 | #endif // DEBUG 136 | 137 | public ThreadEventConsumer() 138 | { 139 | const int capacity = 2048; // TODO: Intelligent initial capacity? 140 | threadEventQueue = new Queue(capacity); 141 | threadRundownQueue = new Queue(capacity/2); 142 | } 143 | 144 | 145 | /* 146 | By separating the rundown events (time=0) from the others (time>0), 147 | we join them together here, and thus the events are sorted by time. 148 | */ 149 | public void Complete() 150 | { 151 | this.FHaveRundown = this.threadRundownQueue.Count > 0; 152 | 153 | while (this.threadEventQueue.Count > 0) 154 | this.threadRundownQueue.Enqueue(this.threadEventQueue.Dequeue()); 155 | 156 | this.threadEventQueue = this.threadRundownQueue; 157 | this.threadRundownQueue = null; 158 | } 159 | 160 | 161 | public void Process(in ClassicEvent evt) 162 | { 163 | THREAD_EVENT te; 164 | 165 | AssertCritical(evt.ProviderId == ThreadTable.guid); 166 | 167 | switch ((TEID)evt.Id) 168 | { 169 | case TEID.Create: 170 | case TEID.Exit: 171 | te = new THREAD_EVENT(evt); 172 | 173 | if (te.ThreadEvt.ThreadId != 0 && te.ThreadEvt.ProcessId > TcpIp.TcbRecord.pidSystem/*4*/) 174 | threadEventQueue.Enqueue(te); 175 | 176 | break; 177 | 178 | case TEID.Rundown: 179 | te = new THREAD_EVENT(evt); 180 | 181 | if (te.ThreadEvt.ThreadId != 0 && te.ThreadEvt.ProcessId > TcpIp.TcbRecord.pidSystem/*4*/) 182 | threadRundownQueue.Enqueue(te); 183 | 184 | break; 185 | } 186 | } // Process 187 | } // ThreadEventConsumer 188 | } // namespace NetBlameCustomDataSource.Thread.Classic -------------------------------------------------------------------------------- /src/BETA/WPAP/Network.wpaProfile: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 0 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/WPAP/Threads.wpaProfile: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 0 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/NetBlame/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | 223 | # Business Intelligence projects 224 | *.rdl.data 225 | *.bim.layout 226 | *.bim_*.settings 227 | 228 | # Microsoft Fakes 229 | FakesAssemblies/ 230 | 231 | # GhostDoc plugin setting file 232 | *.GhostDoc.xml 233 | 234 | # Node.js Tools for Visual Studio 235 | .ntvs_analysis.dat 236 | node_modules/ 237 | 238 | # Typescript v1 declaration files 239 | typings/ 240 | 241 | # Visual Studio 6 build log 242 | *.plg 243 | 244 | # Visual Studio 6 workspace options file 245 | *.opt 246 | 247 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 248 | *.vbw 249 | 250 | # Visual Studio LightSwitch build output 251 | **/*.HTMLClient/GeneratedArtifacts 252 | **/*.DesktopClient/GeneratedArtifacts 253 | **/*.DesktopClient/ModelManifest.xml 254 | **/*.Server/GeneratedArtifacts 255 | **/*.Server/ModelManifest.xml 256 | _Pvt_Extensions 257 | 258 | # Paket dependency manager 259 | .paket/paket.exe 260 | paket-files/ 261 | 262 | # FAKE - F# Make 263 | .fake/ 264 | 265 | # JetBrains Rider 266 | .idea/ 267 | *.sln.iml 268 | 269 | # CodeRush 270 | .cr/ 271 | 272 | # Python Tools for Visual Studio (PTVS) 273 | __pycache__/ 274 | *.pyc 275 | 276 | # Cake - Uncomment if you are using it 277 | # tools/** 278 | # !tools/packages.config 279 | 280 | # vim temp (~) files 281 | *~ 282 | -------------------------------------------------------------------------------- /src/BETA/TraceEdgeChrome.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | Copyright (c) Microsoft Corporation. 5 | Licensed under the MIT License. 6 | 7 | .SYNOPSIS 8 | 9 | Capture and View an ETW trace: 10 | CPU Samples, Thread Dispatch, File I/O, Office Logging Providers, ThreadPool, Processes, Modules 11 | 12 | .DESCRIPTION 13 | 14 | .\TraceEdgeChrome Start [-Loop] [-CLR] 15 | .\TraceEdgeChrome Stop [-WPA [-FastSym]] 16 | .\TraceEdgeChrome View [-Path \MSO-Trace-EdgeChrome.etl|.wpapk] [-FastSym] 17 | .\TraceEdgeChrome Status 18 | .\TraceEdgeChrome Cancel 19 | -Loop: Record only the last few minutes of activity (circular memory buffer). 20 | -CLR: Resolve call stacks for C# (Common Language Runtime). 21 | -WPA: Launch the WPA viewer (Windows Performance Analyzer) with the collected trace. 22 | -Path: Optional path to a previously collected trace. 23 | -FastSym: Load symbols only from cached/transcoded SymCache, not from slower PDB files. 24 | See: https://github.com/microsoft/MSO-Scripts/wiki/Advanced-Symbols#optimize 25 | -Verbose 26 | 27 | .LINK 28 | 29 | https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows 30 | https://learn.microsoft.com/en-us/shows/defrag-tools/39-windows-performance-toolkit 31 | #> 32 | 33 | [CmdletBinding(DefaultParameterSetName = "View")] 34 | Param( 35 | # "Start, Stop, Status, Cancel, View" 36 | [Parameter(Position=0)] 37 | [string]$Command, 38 | 39 | # Record only the last few minutes of activity (circular memory buffer). 40 | [Parameter(ParameterSetName="Start")] 41 | [switch]$Loop, 42 | 43 | # "Support Common Language Runtime / C#" 44 | [Parameter(ParameterSetName="Start")] 45 | [switch]$CLR, 46 | 47 | # "Launch WPA after collecting the trace" 48 | [Parameter(ParameterSetName="Stop")] 49 | [switch]$WPA, 50 | 51 | # "Optional path to a previously collected trace: MSO-Trace-EdgeChrome.etl" 52 | [Parameter(ParameterSetName="View")] 53 | [string]$Path = $Null, 54 | 55 | # "Faster symbol resolution by loading only from SymCache, not PDB" 56 | [Parameter(ParameterSetName="Stop")] 57 | [Parameter(ParameterSetName="View")] 58 | [switch]$FastSym 59 | 60 | # [switch]$Verbose # implicit 61 | ) 62 | 63 | # ===== CUSTOMIZE THIS ===== 64 | 65 | $TraceParams = 66 | @{ 67 | RecordingProfiles = 68 | @( 69 | ".\WPRP\MSEdge.wprp!MSEdge_Filtered" # Includes Chrome 70 | "..\WPRP\JS.wprp!JS" 71 | # "..\WPRP\CPU.wprp!CPU-Dispatch" 72 | # "..\WPRP\FileDiskIO.wprp!FileAndDiskIO" 73 | # "..\WPRP\OfficeProviders.wprp!OfficeLogging" 74 | # "..\WPRP\Handles.wprp!AllHandles" 75 | # "..\WPRP\Defender.wprp!DefenderFull" 76 | 77 | <# ^^^ The first entry is the base recording profile for this script. 78 | vvv Additional recording profile string(s) follow. See ..\ReadMe.txt 79 | 80 | "Registry" # Built-in 81 | "..\WPRP\FileDiskIO.wprp!FileIO" 82 | "c:\MyProfiles\MyRecordingProfile.wprp!CustomProfile" 83 | 84 | Other recording profiles can be added via the WPT_WPRP environment variable. 85 | $Env:WPT_WPRP="c:\path\MyProfile.wprp!ProfileName;c:\path\MyProfile2.wprp!ProfileName2" 86 | set WPT_WPRP=c:\path\MyProfile.wprp!ProfileName;c:\path\MyProfile2.wprp!ProfileName2 87 | 88 | Other recording providers can be added via the WPT_XPERF environment variable (in "XPerf -ON" format). 89 | $Env:WPT_XPERF="GUIDorNAME1 + GUIDorNAME2:::Stack + GUIDorNAME3:KeywordFlags:Level + ..." 90 | set WPT_XPERF=GUIDorNAME1 + GUIDorNAME2:::Stack + GUIDorNAME3:KeywordFlags:Level + ... 91 | 92 | See: https://github.com/microsoft/MSO-Scripts/wiki/Customize-Tracing#envvar 93 | #> 94 | ) 95 | 96 | ProviderManifests = 97 | @( 98 | # Optional: Register ETW Provider Manifests not registered by default. 99 | # See: .\OETW\ReadMe.txt 100 | ".\OETW\EdgeETW.man" 101 | ".\OETW\ChromeETW.man" 102 | ) 103 | 104 | # This is the arbitrary name of the tracing session/instance: 105 | InstanceName = "MSO-Trace-EdgeChrome" 106 | } 107 | 108 | $ViewerParams = 109 | @{ 110 | # The configuration files define the data tabs in the WPA viewer. 111 | # https://learn.microsoft.com/en-us/windows-hardware/test/wpt/view-profiles 112 | ViewerConfig = ".\WPAP\MSEdge.wpaProfile" 113 | 114 | # The default trace file name is: .etl 115 | TraceName = $TraceParams.InstanceName 116 | 117 | # Optional alternate path to a previously collected ETL trace: 118 | TraceFilePath = $Path 119 | } 120 | 121 | # ===== END CUSTOMIZE ==== 122 | 123 | if (!$script:PSScriptRoot) { $script:PSScriptRoot = Split-Path -Parent -Path $script:MyInvocation.MyCommand.Definition } # for PSv2 124 | $script:ScriptHomePath = $PSScriptRoot 125 | $script:ScriptRootPath = "$PSScriptRoot\.." 126 | $script:PSScriptParams = $script:PSBoundParameters # volatile 127 | 128 | . "$ScriptRootPath\INCLUDE.ps1" 129 | 130 | # Main 131 | 132 | if ($Command -ne "View") 133 | { 134 | $Win10VerMin = '10.0.15002' # Min version for both Windows and WPR for 135 | $Win10VerCur = [Environment]::OSVersion.Version 136 | 137 | if ($Win10VerCur -lt $Win10VerMin) 138 | { 139 | Write-Err "This trace requires Windows 10 v$Win10VerMin. Current version is: v$Win10VerCur" 140 | exit 1 141 | } 142 | 143 | CheckPrerequisites # Sets script:WPR_Win10Ver 144 | 145 | if (!(!$script:WPR_PreWin10 -and ($script:WPR_Win10Ver -ge $Win10VerMin))) 146 | { 147 | Write-Err "This trace requires WPR.exe v$Win10VerMin. Current version is: v$script:WPR_Win10Ver" 148 | Write-Err $script:WPR_Path 149 | exit 1 150 | } 151 | } 152 | 153 | $Result = ProcessTraceCommand $Command @TraceParams -Loop:$Loop -CLR:$CLR 154 | 155 | switch ($Result) 156 | { 157 | Started { Write-Msg "ETW tracing has begun.`nExercise the application, then run: $(GetScriptCommand) Stop [-WPA]`n" } 158 | Collected { WriteTraceCollected $TraceParams.InstanceName } # $WPA switch 159 | View { $WPA = $True } 160 | Success { $WPA = $False } 161 | Error { exit 1 } 162 | } 163 | 164 | if ($WPA) 165 | { 166 | LaunchViewer @ViewerParams -FastSym:$FastSym 167 | 168 | Write-Warn "`nPlease be patient, as it may take several minutes for WPA to organize the thousands of events." 169 | Write-Status "This is mainly due to the Regions of Interest (Timelines View)." 170 | } 171 | 172 | exit 0 # Success 173 | -------------------------------------------------------------------------------- /src/WPRP/ThreadPool.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 64 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 96 | 97 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 115 | 116 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 129 | 130 | 131 | 132 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /src/PreWin10/WPRP/CPU.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 102 | 103 | 107 | 108 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 121 | 122 | 123 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 146 | 147 | 148 | 149 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | --------------------------------------------------------------------------------