This repository is a collection of scripts, along with the corresponding directory structure, used by the author for his work on dotnet/runtime changes, specifically to the RyuJit compiler, using Visual Studio on Windows (10+).
This repository provides a "skeleton", so many of the pieces have to be filled in manually before the scripts can be used.
Note: throughout this document, $REPO_ROOT
will refer to the directory into which this reposirty was cloned (C:\Users\Accretion\source\dotnet
for the author).
- Powershell 7+.
- Visual Studio 2022 and all other prerequisites for bulding dotnet/runtime.
- Cygwin, for building PIN.
- Fully built https://github.com/dotnet/jitutils.
- The following environment variables:
SUPERPMI_CACHE_DIRECTORY
=$REPO_ROOT/diffs/spmi
.PATH
should include$REPO_ROOT/diffs
andjitutils/bin
.
- A remote (GH) fork of
dotnet/runtime
. - TODO: document things required for working with the RyuJit-LLVM runtimelab branch.
- Replace the occurences of
C:\Users\Accretion\source\dotnet
inRyuJitReproduction/RyuJit.sln
with$REPO_ROOT
. - Initialize and configure
runtime
andruntime-base
repositories:- Clone
dotnet/runtime
. - Add two remotes:
origin
for the fork,upstream
for the main repostory.
- Clone
- Install PIN into
diffs/pin
(the end result would bediffs/pin/pin-3.19-98425-gd666b2bee-msvc-windows
). Create a new PIN tool, namedSingleAccretionPinTool
, underdiffs/pin/pin-3.19-98425-gd666b2bee-msvc-windows/source/tools
and build it using "Native Tools Command Prompt", with theC:\cygwin64\bin
directory inPATH
:make obj-intel64/SingleAccretionPinTool.dll
(using the x64 prompt),make obj-ia32/SingleAccretionPinTool.dll TARGET=ia32
(using the x86 prompt). - Pull and build the upstream:
- Run
buid/regenerate-artifacts.ps1
. This will take a long time, as it buildsruntime
andruntime-base
in 3 configurations for CoreCLR and one (Release) for libraries. - In parallel, run
diffs/redownload-spmi-collections.ps1
. This may take even longer and will consume approximately 75 GB of disk space. - The above two steps are intended to be repeated each time upstream needs to be synced to (the author does them about once a week).
- Run
- TODO: document things required for working with the RyuJit-LLVM runtimelab branch.
This is mostly an infrastructural script, but can also be used directly. It allows building compilers with a number of #define
s that control various interesting dumping capabilities.
Parameters:
-base
: the Jits should be built out ofruntime-base
.-save
: whether the state of the source repository should be restored after the Jits have been built (otherwiseclrjit
artifacts will be overwritten). When this option is used, the built Jits will be placed underbuild/[Base]CustomJits
.-jitSubset
:clr.jit
orclr.alljits
.-arch
: the host architecture of the built compilers,x64
orx86
.-config
: the configuration (Debug
/Checked
/Release
).-stats
: which "stats" to "define". See the script source for how they correspond to#define
s injit.h
.
Also builds custom Jits with the ability to measure memory consumption (used by diff-mem.ps1
).
Parameters:
-arches
: the architectures to build,x64
andx86
.-save
: whether to purge the existing artifacts withgit clean -xdf
.-pull
: whether to pull the latest upstream before rebuilding (default when-save
is off).-baseOnly
: whether to only rebuildruntime-base
.
A number of scripts support overriding the base Jit (which is usually the one built out of runtime-base
) with a custom one, placed under diffs/base-jits-[x64|x86]
by this script.
Parameters:
-hostArch
: the architecture of the Jits to copy. Default isx64
.-config
: the configuration of the Jits to copy. Default isChecked
.-builtJitsPath
: path to the Jits to copy. By default, the script copies the Jits fromruntime
's artifacts.
Copies artifacts from the built repositories to "custom" core roots. These differ slightly in their construction from the ones created by the test build script, in particular, they are set up such that the runtime copied is Checked
, while the Jits are Debug
, for ease of debugging, and the crossgen2
custom core root employs a renaming trick so that the Jit compiling CG2 in its process has a name different than the one used by CG2 itself.
Parameters:
-arch
: the architecure of the core root. Default isx64
.-cg2
: whether to update the CG2 core root. Off by default.-ilc
: whether to update the ILC core root. Off by default.-llvmIlc
: whether to update the ILC core root for the RyuJit-LLVM runtimelab branch. Off by default.-mono
: whether to update the Mono core root (CoreCLR core root with the runtime binaries replaced with their Mono equivalents). Off by default.
Builds and copies the Jits from runtime
's artifacts to their location in the custom core root(s). This is the workhorse script in the workflow, it is expected to be used alongside editing the source code, to test the resulting binaries.
Parameters:
-hostArch|-a
: the architercture of the Jits to build. Default isx64
.-all
: whether to build "all" of the Jits (i. e.clr.alljits
). By default, only theclr.jit
subset is built.-release|-r
: whether to build the Jits inRelease
configuration. By default,Checked
andDebug
Jits are built.-refreshPdb|-p
: whether to regenerate the PDB files from scratch during the build. By default, the incremental build "appends" debugging information to the existing files, which can cause confusion in certain scenarios.-updateBaseJits|-b
: whether to make the built Jits "base" (copy them to the "base Jits" directory withsave-base-jits.ps1
). This is a very useful option when the "base" being diffed against (say, via SPMI) is not the same as theHEAD
ofruntime-base
(which is intended to always be in sync with theHEAD
of the remote fork and only infrequently updated). In such a case, the common sequence of actions to perform is the following:git rebase main -i
andbreak
after the intended "base" commit.update-jit -b [-all]
git rebase --continue
update-jit [-all]
- Run
diff-mem.ps1
,pin.ps1
,spmi.ps1
, etc.
-llvmRyuJit
: whether to build and update the Jit associated with the RyuJit-LLVM runtimelab branch.-pgo
: whether to apply native PGO to the built Jits. By default,Release
Jits are built with PGO off, to make PIN diffs reliable.-configs
: list of configurations to build the Jits in. Useful to override the defaults.-stats
: the list of "stats" to build the Jits with. See the description ofbuild-jit-with-stats-defined.ps1
.
This is the primary script for working with SPMI-generated diffs. It is intended to be invoked in the directory created by superpmi.py
(e. g. C:\Users\Accretion\source\dotnet\diffs\spmi\asm.libraries.pmi.windows.x64.checked.44
). Note that most of the parameters to the script can be shortened per the standard PowerShell rules (e. g. -log
=> -l
, -wordDiff
=> -w
, -basediffs
=> -b
, etc).
Parameters:
-spmiIndex
(positional): the SPMI context index. This is the only required parameter, and in absense of any others, it makes the script equivalent to invokinggit diff --no-index base/spmiIndex.dasm diff/spmiIndex.dasm
.-perfScore
: a shortcut forjit-analyze -b base -d diff -metric PerfScore
.-log
: whether to re-invoke SPMI on the provided diff and generate dump files, to begit diff
ed. Note that the script supports invocations without-spmiIndex
in case-log
was specificed, making it equivalent togit diff --no-index baselog.cs log.cs
. This is useful when analyzing large dumps, where regenerating them is relatively expensive.-native
: whether to use "native" cross-compilers when invoking SPMI. By default, the script will preferx86
-hosted compilers for allx86
andARM
diffs.-basediffs
: whether to use the "base" Jit with SPMI.-asm
: whether to re-invoke SPMI on the provided diff and generate.dasm
files. Useful for verifying changes have the intended impact on the diff (note, as with-log
, that the script creates the new.dasm
files in the current directory, and does not overwite the originals).-wordDiff
: whether to use--word-diff
ingit diff
invocations. Useful for diffing dump files, where changes to tree IDs can make ordinarygit diff
too noisy.-options
: an array of Jit options to provide to compilers invoked by SPMI. For example:-o JitNoCSE=1, JitNoInline=1
. Exceptionally useful for verifying causes of diffs in conjuction with variousJitNo
knobs.
As the name suggests, the script is intended for quick and simple verification of changes that could impact memory consumption of the Jit. Currently, it only supports diffs with CoreLib compiled via CG2. This script relies on base Jits capable of measuring memory stats being present under the build
directory.
Parameters:
- RID and host arch (positional): what host/target combination should be used for the diffs. The "RID" is a standard .NET RID (e. g.
win-x64
,linux-arm
, etc), while the host arch can be one ofx86
orx64
. Default iswin-x64 x64
. - `basediffs (positional): whether to use the "base" Jit for the diff.
This script downloads and applies the formatting patch generated by the AzDo jobs that run on Jit changes.
Parameters:
-download
(positional): the build ID for the formatting job. It is intended to be extracted from the URL, e. g.: https://dev.azure.com/dnceng/public/_build/results?__buildId=1927902__&view=logs&jobId=c8204876-824e-5bf9-8c45-a4628bfcec7d.-linux
: whether to use the Linux job's artifacts to obtain the formatting patch. By default, Windows' ones are used.
Simply passes through the provided arguments to the underlying tool, taken from runtime
's artifacts.
This script uses the PIN tool built earlier to make estimating the TP impact of a given change very simple and quick. It protects against the common mistake of not accounting for missing contexts, as well as allowing for diffs in cases where they can be filtered out.
Parameters:
- RID and host arch (positional): what host/target combination should be used for the diffs. The default is
win-x64 x64
. - Path to the
.mch
file to diff (positional): explicit path to the.mch
file to use for diffs. - Name of the collection to use for diffs, one of
aspnet
,bench
,clrtests
,cglibs
,libs
orlibstests
. By default, thebench
collection is used. - Comma-separated list of contexts, in the same format as that of
superpmi.exe
, e. g.1-100,90-9000
: the contexts to use for diffs. Diffing whole collections takes a considerable amount of time, so this option can be quite handy for quick estimates. - Jit options, in the format of
JitOption=Value
: options to use for both "base" and "diff" Jits when running them. basediffs
: whether to use the "base" Jit for the diff.- Path to a
.dll
file: the PIN tool library to use for the diffs. Useful for testing in-development PIN tools. trace
: whether to use the "trace" mode of the PIN tool. Traces will be saved todiffs/basetp.txt
anddiffs/difftp.txt
and analyzed withanalyze-pin-trace-diff.ps1
.tracediff
: same astrace
, but only instrument the "diff" Jit and use results fromdiffs/basetp.txt
as the base.
Analyzes the information obtained with the PIN tool's trace
option:
Base: 1039322782, Diff: 1040078986, +0.0728%
`Compiler::optCopyPropPushDef'::`2'::<lambda_1>::operator() : 1073512 : NA : 18.17% : +0.1033%
SsaBuilder::RenamePushDef : 911022 : NA : 15.42% : +0.0877%
`Compiler::fgValueNumberLocalStore'::`2'::<lambda_1>::operator() : 584435 : NA : 9.89% : +0.0562%
Compiler::lvaLclExactSize : 244692 : +60.09% : 4.14% : +0.0235%
ValueNumStore::VNForMapSelectWork : 87006 : +2.78% : 1.47% : +0.0084%
GenTree::DefinesLocal : 82633 : +1.63% : 1.40% : +0.0080%
Rationalizer::DoPhase : -91104 : -6.36% : 1.54% : -0.0088%
Compiler::gtCallGetDefinedRetBufLclAddr : -115926 : -98.78% : 1.96% : -0.0112%
Compiler::optBlockCopyProp : -272450 : -5.75% : 4.61% : -0.0262%
Compiler::fgValueNumberLocalStore : -313540 : -50.82% : 5.31% : -0.0302%
Compiler::GetSsaNumForLocalVarDef : -322826 : -100.00% : 5.46% : -0.0311%
SsaBuilder::RenameDef : -478441 : -28.33% : 8.10% : -0.0460%
Compiler::optCopyPropPushDef : -711380 : -55.34% : 12.04% : -0.0684%
The columns, in order:
- The instruction count difference for the given function.
- Same as
1
, but relative. May beNA
, indicating the base didn't contain the given function, or-100%
indicating the diff didn't. - Relative contribution to the diff. Calculated as
abs(instruction diff count) / sum-over-all-functions(abs(instruction diff count))
. - Relative difference, calculated as
instruction diff count / total base instruction count
.
Parameters:
-baseTracePath
: path to the base trace file.-diffTracePath
: path to the diff trace file.-noiseFilter
: filter out function with contributions lower than this number (specified as a percentage).0.1%
by default.-functionsFilter
: filter out functions with these names. All functions are shown by default.
Downloads SPMI collections for the win-x64
, win-x86
, win-arm64
, linux-arm
and linux-x64
targets. This is a wrapper over spmi.ps1
's redownload
functionality.
Performs binary search through method hashes to identify which method, when not run under MinOpts, leads to the test case failing. Relies on a custom JitMinOptsRange
Jit config toggle.
Parameters:
-command
: the command to run as the test case.-toggle
: the environment variable to use as the range, specified via a hexadecimal pair of numbers, inside which all methods will be compilerd without optimizations.-successExitCode
: the exit code ofcommand
which indicates "success". The default is100
, same as for CoreCLR tests, though note that test wrapper scripts actually use0
as the "success" value.-quiet
: suppress console output of the test case.
Under diffs
, there is a diffs-repository
directory, which is inteded to be used in conjuction with this script to store diffs in a git
-based database. While SPMI in CI has mostly eliminated the need for this, it is still occasionally useful, especially when the volume of diffs is too large for CI to handle.
Before using this, diffs-repository
must be initialized as a valid git
repository and connected to some default remote.
Parameters:
-prIndex
: number of the pull request for which the diffs are being commited.-mdIndex
: index of the.md
summary file to commit. This is as generated bysuperpmi.py
, e. g. forC:\Users\Accretion\source\dotnet\diffs\spmi\diff_summary.173.md
it would be173
.-repositoryName
: name of the repository for which the diffs are being commited. Default isruntime
.-showDiffs|-d
: whether to "show" the diffs (viagit show
) before committing them.
Very useful for quickly getting a new terminal instance configured for running CoreCLR tests, as well as switching between different core roots and stress configurations.
Parameters:
-arch
: architecture of the core root to use. Default isx64
.-nativeAot
: whether the test environment is to be set up for NativeAOT-LLVM testing. SetsCLRCustomTestLauncher
.-tieredCompilation
: whether to enable tiered compilation. By default, it is turned off.-base
: whether to use the core root from theruntime-base
repository. By default the "custom" core roots are used.-stressLevel
: the level to use forJitStress
, if any. By default, no stress is applied.
Ordinarily, invoking superpmy.py
, especially in cross-targeting and filtering scenarios, can be quite verbose. This script is meant to optimize that friction away. Additioanlly, it provides retry loop support for downloading collections, where one can kill the python process and have it start over, which can be useful in cases (such as accidentally putting the computer to sleep), where the download process "freezes".
Note the somewhat inordinate way in which the script takes arguments: they are all positional, and must be in strict order (defined below), except if the effective values used are the same as default ones. This means that, e. g., both spmi win-x64 bench
and spmi bench
are legal, but spmi bench win-x64
is not.
Parameters:
- Action: one of
replay
,asmdiffs
,basediffs
,perfdiffs
(PerfScore diffs),perfbasediffs
andredownload
.basediffs
andperfbasediffs
are the same asasmdiffs
andperfdiffs
, respectively, except that they use the "base" Jits. The default isasmdiffs
. - Target RID and host arch: the defaults are
win-x64
andx64
. Likediff-mem.ps1
anddiff-dasm.ps1
,spmi.ps1
will prefer to use thex86
-hosted compilers forx86
andARM
diffs. - Collection: one of
aspnet
,bench
,clrtests
,cglibs
,libs
orlibstests
. While replay and asmdiffs only support specifiying one collection, or none, in which case all are used, theredownload
action supports a whitespace-separated list of them. - Jit options:
b:JitOption=Value
if the option should apply only the the base compiler,d:JitOption=Value
for the opposite, and simplyJitOption=Value
if it should apply to both.
This simple script helps in quickly pulling down CI-produced diffs for local analysis.
Parameters:
-download
: the build ID to use when downloading the diffs (as withfmt.ps1
, this can be obtained from the AzDo URL).-zipFile
: the path to an existing ZIP file to unpack. This option is meant to be used when the diffs file has already been downloaded.-arch
: the host architecture of the SPMI job,x86
orx64
. Default isx64
.
This script works similarly to the "touch" Unix utility, except it does not create the file if it does not exit. This script is useful for working around MSBuild incrementality limitations: "touch" the project file before invoking dotnet build
to have it be fully rebuilt.