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.PATHshould include$REPO_ROOT/diffsandjitutils/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\dotnetinRyuJitReproduction/RyuJit.slnwith$REPO_ROOT. - Initialize and configure
runtimeandruntime-baserepositories:- Clone
dotnet/runtime. - Add two remotes:
originfor the fork,upstreamfor 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/toolsand build it using "Native Tools Command Prompt", with theC:\cygwin64\bindirectory 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 buildsruntimeandruntime-basein 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 #defines 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 (otherwiseclrjitartifacts will be overwritten). When this option is used, the built Jits will be placed underbuild/[Base]CustomJits.-jitSubset:clr.jitorclr.alljits.-arch: the host architecture of the built compilers,x64orx86.-config: the configuration (Debug/Checked/Release).-stats: which "stats" to "define". See the script source for how they correspond to#defines injit.h.
Also builds custom Jits with the ability to measure memory consumption (used by diff-mem.ps1).
Parameters:
-arches: the architectures to build,x64andx86.-save: whether to purge the existing artifacts withgit clean -xdf.-pull: whether to pull the latest upstream before rebuilding (default when-saveis 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.jitsubset is built.-release|-r: whether to build the Jits inReleaseconfiguration. By default,CheckedandDebugJits 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 theHEADofruntime-base(which is intended to always be in sync with theHEADof the remote fork and only infrequently updated). In such a case, the common sequence of actions to perform is the following:git rebase main -iandbreakafter the intended "base" commit.update-jit -b [-all]git rebase --continueupdate-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,ReleaseJits 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 diffed. Note that the script supports invocations without-spmiIndexin case-logwas 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 allx86andARMdiffs.-basediffs: whether to use the "base" Jit with SPMI.-asm: whether to re-invoke SPMI on the provided diff and generate.dasmfiles. Useful for verifying changes have the intended impact on the diff (note, as with-log, that the script creates the new.dasmfiles in the current directory, and does not overwite the originals).-wordDiff: whether to use--word-diffingit diffinvocations. Useful for diffing dump files, where changes to tree IDs can make ordinarygit difftoo 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 variousJitNoknobs.
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 ofx86orx64. 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
.mchfile to diff (positional): explicit path to the.mchfile to use for diffs. - Name of the collection to use for diffs, one of
aspnet,bench,clrtests,cglibs,libsorlibstests. By default, thebenchcollection 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
.dllfile: 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.txtanddiffs/difftp.txtand analyzed withanalyze-pin-trace-diff.ps1.tracediff: same astrace, but only instrument the "diff" Jit and use results fromdiffs/basetp.txtas 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 ofcommandwhich indicates "success". The default is100, same as for CoreCLR tests, though note that test wrapper scripts actually use0as 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.mdsummary file to commit. This is as generated bysuperpmi.py, e. g. forC:\Users\Accretion\source\dotnet\diffs\spmi\diff_summary.173.mdit 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-baserepository. 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),perfbasediffsandredownload.basediffsandperfbasediffsare the same asasmdiffsandperfdiffs, respectively, except that they use the "base" Jits. The default isasmdiffs. - Target RID and host arch: the defaults are
win-x64andx64. Likediff-mem.ps1anddiff-dasm.ps1,spmi.ps1will prefer to use thex86-hosted compilers forx86andARMdiffs. - Collection: one of
aspnet,bench,clrtests,cglibs,libsorlibstests. While replay and asmdiffs only support specifiying one collection, or none, in which case all are used, theredownloadaction supports a whitespace-separated list of them. - Jit options:
b:JitOption=Valueif the option should apply only the the base compiler,d:JitOption=Valuefor the opposite, and simplyJitOption=Valueif 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,x86orx64. 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.