├── .gitattributes
├── .gitignore
├── CODE-OF-CONDUCT.md
├── LICENSE.TXT
├── NuGet.Config
├── README.md
├── azure-pipelines.yml
├── bootstrap.cmd
├── bootstrap.sh
├── build-coredistools.cmd
├── build-coredistools.sh
├── build-tblgen.cmd
├── build-tblgen.sh
├── build.cmd
├── build.sh
├── coredistools.yml
├── doc
├── building-coredistools.md
├── cijobs.md
├── config.md
├── diffs.md
├── formatting.md
└── tools.md
├── eng
├── build.yml
└── download-checkout-llvm.yml
├── jitutils.sln
├── pack-coredistools.cmd
├── sample_config.json
├── src
├── AnalyzeAsm
│ ├── AnalyzeAsm.csproj
│ ├── OccurenceInfo.cs
│ ├── Program.cs
│ └── README.md
├── cijobs
│ ├── CIClient.cs
│ ├── CIJobsRootCommand.cs
│ ├── Models.cs
│ ├── Program.cs
│ ├── README.md
│ └── cijobs.csproj
├── coreclr_config_download
│ ├── README.md
│ └── coreclr_config_download.py
├── coredistools
│ ├── .nuget
│ │ └── Microsoft.NETCore.CoreDisTools.nuspec
│ ├── CMakeLists.txt
│ ├── coredistools.cpp
│ ├── coredistools.exports
│ └── coredistools.h
├── instructions-retired-explorer
│ ├── README.md
│ ├── instructions-retired-explorer.cs
│ └── instructions-retired-explorer.csproj
├── jit-analyze
│ ├── IEnumerableExtensions.cs
│ ├── JitAnalyzeRootCommand.cs
│ ├── MetricCollection.cs
│ ├── Metrics.cs
│ ├── Program.cs
│ ├── README.md
│ └── jit-analyze.csproj
├── jit-dasm-pmi
│ ├── JitDasmPmiRootCommand.cs
│ ├── Program.cs
│ ├── README.md
│ └── jit-dasm-pmi.csproj
├── jit-dasm
│ ├── JitDasmRootCommand.cs
│ ├── Program.cs
│ ├── README.md
│ └── jit-dasm.csproj
├── jit-decisions-analyze
│ ├── README.md
│ ├── jit-decisions-analyze.cs
│ └── jit-decisions-analyze.csproj
├── jit-diff
│ ├── README.md
│ ├── diff.cs
│ ├── install.cs
│ ├── jit-diff.cs
│ ├── jit-diff.csproj
│ └── uninstall.cs
├── jit-format
│ ├── README.md
│ ├── jit-format.cs
│ └── jit-format.csproj
├── jit-include.props
├── jit-pintool
│ ├── README.md
│ └── clrjit_inscount.cpp
├── jit-rl-cse
│ ├── MLCSE.cs
│ ├── MLCSE.csproj
│ ├── MLCSECommands.cs
│ ├── MarkovChain96689.png
│ ├── MarkovChain96689PG100.png
│ └── README.md
├── jit-tp-analyze
│ ├── Program.cs
│ ├── README.md
│ └── jit-tp-analyze.csproj
├── mutate-test
│ ├── MutateTestRootCommand.cs
│ ├── Program.cs
│ └── mutate-test.csproj
├── performance-explorer
│ ├── README.md
│ ├── benchmark-info.cs
│ ├── benchmark-json.cs
│ ├── cse-experiment.cs
│ ├── hot-function.cs
│ ├── performance-explorer.cs
│ └── performance-explorer.csproj
├── pmi
│ ├── JITDecisionEventListener.cs
│ ├── PMIDriver.cs
│ ├── pmi.cs
│ ├── pmi.csproj
│ └── readme.md
├── superpmi
│ ├── superpmicollect.cs
│ └── superpmicollect.csproj
├── target-framework.props
└── util
│ ├── CommandLineHelpers.cs
│ └── util.cs
└── test
├── jit-analyze
├── base
│ ├── test1.dasm
│ ├── test2.dasm
│ └── test3.dasm
├── baseline1.out
├── baseline2.out
├── baseline3.out
├── diff
│ ├── test1.dasm
│ ├── test2.dasm
│ └── test3.dasm
└── runtest.sh
├── jit-dasm
└── runtest.sh
└── jit-format
├── .clang-format
├── runtest.cmd
├── test-fixed.cpp
└── test.cpp
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set default behavior to automatically normalize line endings.
2 | * text=auto
3 |
4 | *.doc diff=astextplain
5 | *.DOC diff=astextplain
6 | *.docx diff=astextplain
7 | *.DOCX diff=astextplain
8 | *.dot diff=astextplain
9 | *.DOT diff=astextplain
10 | *.pdf diff=astextplain
11 | *.PDF diff=astextplain
12 | *.rtf diff=astextplain
13 | *.RTF diff=astextplain
14 |
15 | *.jpg binary
16 | *.png binary
17 | *.gif binary
18 |
19 | # Force bash scripts to always use lf line endings so that if a repo is accessed
20 | # in Unix via a file share from Windows, the scripts will work.
21 | *.in text eol=lf
22 | *.sh text eol=lf
23 |
24 | # Likewise, force cmd and batch scripts to always use crlf
25 | *.cmd text eol=crlf
26 | *.bat text eol=crlf
27 |
28 | *.cs text=auto diff=csharp
29 | *.vb text=auto
30 | *.resx text=auto
31 | *.c text=auto
32 | *.cpp text=auto
33 | *.cxx text=auto
34 | *.h text=auto
35 | *.hxx text=auto
36 | *.py text=auto
37 | *.rb text=auto
38 | *.java text=auto
39 | *.html text=auto
40 | *.htm text=auto
41 | *.css text=auto
42 | *.scss text=auto
43 | *.sass text=auto
44 | *.less text=auto
45 | *.js text=auto
46 | *.lisp text=auto
47 | *.clj text=auto
48 | *.sql text=auto
49 | *.php text=auto
50 | *.lua text=auto
51 | *.m text=auto
52 | *.asm text=auto
53 | *.erl text=auto
54 | *.fs text=auto
55 | *.fsx text=auto
56 | *.hs text=auto
57 |
58 | *.csproj text=auto
59 | *.vbproj text=auto
60 | *.fsproj text=auto
61 | *.dbproj text=auto
62 | *.sln text=auto eol=crlf
63 |
64 | # Set linguist language for .h files explicitly based on
65 | # https://github.com/github/linguist/issues/1626#issuecomment-401442069
66 | # this only affects the repo's language statistics
67 | *.h linguist-language=C
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Hides dotnet cli build artifacts as well as project system cookies.
2 | ##
3 |
4 | # ignore default binary/obj locations
5 | **/bin
6 | **/obj
7 | .vscode
8 |
9 | # project system lock files
10 | project.lock.json
11 |
12 | # vs files
13 | .vs
14 | browse.VC.db
15 |
16 | # vi
17 |
18 | *~
19 |
--------------------------------------------------------------------------------
/CODE-OF-CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | This project has adopted the code of conduct defined by the Contributor Covenant
4 | to clarify expected behavior in our community.
5 |
6 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
7 |
--------------------------------------------------------------------------------
/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) .NET Foundation and Contributors
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.
--------------------------------------------------------------------------------
/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dotnet JIT code gen utilities - jitutils
2 |
3 | This repo holds a collection of utilities used by RyuJIT developers to
4 | automate tasks when working on CoreCLR.
5 |
6 | ## Summary
7 |
8 | Current tools include:
9 |
10 | 1. [Assembly diffs](doc/diffs.md): jit-diff, jit-dasm, jit-dasm-pmi, jit-analyze, jit-tp-analyze.
11 | 2. [CI jobs information](doc/cijobs.md): cijobs.
12 | 3. [JIT source code formatting](doc/formatting.md): jit-format.
13 | 4. [General tools](doc/tools.md): pmi
14 | 5. [Experimental tools](src/performance-explorer/README.md): performance-explorer
15 | 6. [BenchmarkDotNet Analysis](src/instructions-retired-explorer/README.md)
16 |
17 |
18 | ## Getting started
19 |
20 | 1. Clone the jitutils repo:
21 | ```
22 | git clone https://github.com/dotnet/jitutils
23 | ```
24 |
25 | 2. Install a recent .NET Core SDK (including the `dotnet` command-line interface, or CLI) from [here](https://dot.net).
26 |
27 | 3. Build the tools:
28 | ```
29 | cd jitutils
30 | bootstrap.cmd
31 | ```
32 | (on non-Windows, run bootstrap.sh. NOTE: On Mac, you need to first use `ulimit -n 2048` or the `dotnet restore` part of the build will fail.)
33 |
34 | 4. Optionally, add the built tools directory to your path, e.g.:
35 | ```
36 | set PATH=%PATH%;\jitutils\bin
37 | ```
38 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | - main
3 |
4 | pr:
5 | - main
6 |
7 | # Schedule a twice monthly build to ensure the pipeline isn't marked as inactive.
8 | schedules:
9 | - cron: '0 0 1,15 * *'
10 | displayName: Twice monthly build
11 | branches:
12 | include:
13 | - main
14 | always: true
15 |
16 | jobs:
17 | - template: /eng/build.yml
18 | parameters:
19 | agentOs: Windows_NT
20 | pool:
21 | vmImage: windows-latest
22 |
23 | - template: /eng/build.yml
24 | parameters:
25 | agentOs: Linux
26 | pool:
27 | vmImage: ubuntu-latest
28 |
29 | - template: /eng/build.yml
30 | parameters:
31 | agentOs: macOS
32 | pool:
33 | vmImage: macOS-latest
34 |
--------------------------------------------------------------------------------
/bootstrap.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM Bootstrap the jitutils tools:
4 | REM 1. If this script is run not from within the jitutils directory (e.g., you've downloaded
5 | REM a copy of this file directly), then "git clone" the jitutils project first. Otherwise,
6 | REM if we can tell we're being run from within an existing "git clone", don't do that.
7 | REM 2. Build the jitutils tools.
8 | REM 3. Download (if necessary) clang-format.exe and clang-tidy.exe (used by the jit-format tool).
9 |
10 | set __ExitCode=0
11 |
12 | where /q dotnet.exe
13 | if %errorlevel% NEQ 0 echo Can't find dotnet.exe! Please install this ^(e.g., from https://www.microsoft.com/net/core^) and add dotnet.exe to PATH&set __ExitCode=1&goto :script_exit
14 |
15 | where /q git.exe
16 | if %errorlevel% NEQ 0 echo Can't find git.exe! Please add to PATH&set __ExitCode=1&goto :script_exit
17 |
18 | set __root=%~dp0
19 | setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
20 |
21 | REM Are we already in the dotnet/jitutils repo? Or do we need to clone it? We look for build.cmd
22 | REM in the current directory (which is the directory this script was invoked from).
23 |
24 | if not exist %__root%build.cmd goto clone_jitutils
25 |
26 | pushd %__root%
27 |
28 | REM Check if build.cmd is in the root of the repo.
29 | set __tempfile=%TEMP%\gittemp-%RANDOM%.txt
30 | git rev-parse --show-toplevel >%__tempfile% 2>&1
31 | if errorlevel 1 (
32 | echo Error: git failure:
33 | type %__tempfile%
34 | echo Cloning jitutils repo.
35 | del %__tempfile%
36 | popd
37 | goto clone_jitutils
38 | )
39 | set /P gitroot=<%__tempfile%
40 | del %__tempfile%
41 | set gitroot=%gitroot:/=\%
42 | if not %gitroot:~-1%==\ set gitroot=%gitroot%\
43 | if /I not %__root%==%gitroot% (
44 | echo It doesn't looks like bootstrap.cmd is at the root of the repo.
45 | echo Cloning jitutils repo.
46 | popd
47 | goto clone_jitutils
48 | )
49 |
50 | REM Is this actually the jitutils repo?
51 | git remote -v | findstr /i /c:"/jitutils" >nul
52 | if errorlevel 1 (
53 | echo It doesn't looks like we're in the jitutils repo.
54 | echo Cloning jitutils repo.
55 | popd
56 | goto clone_jitutils
57 | )
58 |
59 | REM Now go ahead and build it.
60 | call :build_jitutils
61 |
62 | popd
63 |
64 | REM If the build failed, we need to check it here, before the "endlocal".
65 | if %__ExitCode% NEQ 0 goto :script_exit
66 |
67 | :: Add utilites to the current path, but only if not already there
68 | endlocal
69 | call :AddToPath %__root%bin
70 | set __root=
71 | goto :script_exit
72 |
73 | REM ===================================================================
74 | REM == This is top-level, not a "call".
75 | REM ==
76 | :clone_jitutils
77 |
78 | pushd %__root%
79 |
80 | :: Clone the jitutils repo
81 |
82 | git clone https://github.com/dotnet/jitutils.git
83 | if errorlevel 1 echo ERROR: clone failed.&set __ExitCode=1&goto :script_exit
84 | if not exist .\jitutils echo ERROR: can't find jitutils directory.&set __ExitCode=1goto :script_exit
85 |
86 | pushd .\jitutils
87 |
88 | call :build_jitutils
89 |
90 | popd
91 |
92 | popd
93 |
94 | REM If the build failed, we need to check it here, before the "endlocal".
95 | if %__ExitCode% NEQ 0 goto :script_exit
96 |
97 | :: Add utilites to the current path
98 | endlocal
99 | call :AddToPath %__root%jitutils\bin
100 | set __root=
101 | goto :script_exit
102 |
103 | REM ===================================================================
104 | :build_jitutils
105 |
106 | if not exist .\build.cmd echo Can't find build.cmd.&set __ExitCode=1&goto :eof
107 |
108 | :: Pull in needed packages. This works globally (due to jitutils.sln).
109 |
110 | dotnet restore
111 | if errorlevel 1 echo ERROR: dotnet restore failed.&set __ExitCode=1&goto :eof
112 |
113 | :: Build and publish all the utilities
114 |
115 | call .\build.cmd -p
116 | if errorlevel 1 echo ERROR: build failed.&set __ExitCode=1&goto :eof
117 |
118 | :: Check to see if clang-format and clang-tidy are available. Since we're going
119 | :: to add the 'bin' directory to the path, and they most likely already live there
120 | :: if you're running bootstrap.cmd not for the first time, add 'bin' to the path
121 | :: here (within the setlocal scope for now) before checking for them. Add 'bin'
122 | :: at the end of the path, to prefer other user downloaded versions, if any.
123 |
124 | set _clang_version=17.0.6
125 |
126 | set PATH=%PATH%;.\bin
127 |
128 | where /Q clang-format
129 | IF %errorlevel% NEQ 0 GOTO DownloadTools
130 |
131 | where /Q clang-tidy
132 | IF %errorlevel% NEQ 0 GOTO DownloadTools
133 |
134 | REM We found the tools on the path; now make sure the versions are good.
135 |
136 | clang-format --version | findstr /c:"version %_clang_version%" > NUL
137 | IF %errorlevel% EQU 0 GOTO build_done
138 |
139 | echo jit-format requires clang-format and clang-tidy version %_clang_version%. Currently installed:
140 | clang-format --version
141 | clang-tidy --version
142 | echo Please install version %_clang_version% and put the tools on the PATH to use jit-format.
143 | echo Tools can be found at https://github.com/llvm/llvm-project/releases/tag/llvmorg-%_clang_version%
144 |
145 | :DownloadTools
146 |
147 | echo Downloading formatting tools
148 |
149 | set _azdo_root=https://clrjit2.blob.core.windows.net/clang-tools
150 | set _platform=windows-x64
151 | set _azdo_dir=%_azdo_root%/%_clang_version%/%_platform%
152 |
153 | call :download_url clang-format "%_azdo_dir%/clang-format.exe" bin\clang-format.exe
154 | if %__ExitCode% NEQ 0 goto :eof
155 |
156 | call :download_url clang-tidy "%_azdo_dir%/clang-tidy.exe" bin\clang-tidy.exe
157 | if %__ExitCode% NEQ 0 goto :eof
158 |
159 | :build_done
160 | goto :eof
161 |
162 | REM ===================================================================
163 | REM Download helper, with retry on failure. Args:
164 | REM %1 - friendly name of download
165 | REM %2 - URL to download
166 | REM %3 - target of download
167 | REM
168 | REM We'd like to use Invoke-WebRequest `-MaximumRetryCount 8 -RetryIntervalSec 15`, but those aren't
169 | REM available on all versions of PowerShell.
170 | :download_url
171 | set _friendly_name=%1
172 | set _url=%2
173 | set _target_file=%3
174 | set _retry_count=1
175 | :start_download
176 | echo call powershell Invoke-WebRequest -Uri %_url% -OutFile %_target_file%
177 | call powershell Invoke-WebRequest -Uri %_url% -OutFile %_target_file%
178 | if %errorlevel% EQU 0 goto :eof
179 | echo ERROR: attempt #%_retry_count% failed to download %_friendly_name%.
180 | if %_retry_count% GEQ 4 echo ERROR: giving up attempting to download %_friendly_name%.&set __ExitCode=1&goto :eof
181 | echo Waiting 15 seconds to retry...
182 | powershell -command "Start-Sleep -Seconds 15"
183 | set /A _retry_count=_retry_count + 1
184 | goto start_download
185 |
186 | REM ===================================================================
187 | :script_exit
188 | REM Note, this entire line gets variable expanded before execution, so the "exit" use of %__ExitCode% gets expanded before it is cleared during execution.
189 | set __ExitCode=&exit /b %__ExitCode%
190 |
191 | REM ===================================================================
192 | :AddToPath
193 | set PATH | findstr /i %1 >nul
194 | if %errorlevel% NEQ 0 set PATH=%PATH%;%1
195 | goto :eof
196 |
--------------------------------------------------------------------------------
/bootstrap.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Bootstrap the jitutils tools:
4 | # 1. If this script is run not from within the jitutils directory (e.g., you've downloaded
5 | # a copy of this file directly), then "git clone" the jitutils project first. Otherwise,
6 | # if we can tell we're being run from within an existing "git clone", don't do that.
7 | # 2. Build the jitutils tools.
8 | # 3. Download (if necessary) clang-format and clang-tidy (used by the jit-format tool).
9 |
10 | function get_host_os {
11 | # Use uname to determine what the OS is.
12 | OSName=$(uname -s)
13 | case $OSName in
14 | Linux)
15 | __HostOS=Linux
16 | ;;
17 |
18 | Darwin)
19 | __HostOS=OSX
20 | ;;
21 |
22 | FreeBSD)
23 | __HostOS=FreeBSD
24 | ;;
25 |
26 | OpenBSD)
27 | __HostOS=OpenBSD
28 | ;;
29 |
30 | NetBSD)
31 | __HostOS=NetBSD
32 | ;;
33 |
34 | SunOS)
35 | __HostOS=SunOS
36 | ;;
37 |
38 | *)
39 | echo "Unsupported OS $OSName detected, configuring as if for Linux"
40 | __HostOS=Linux
41 | ;;
42 | esac
43 | }
44 |
45 | _machineHasCurl=
46 |
47 | function validate_url {
48 | if (( _machineHasCurl == 1 )); then
49 | status="$(curl -sLIo /dev/null "$1" -w '%{http_code}\n')"
50 | else
51 | response=($(wget -S --spider "$1" 2>&1 | grep "HTTP/"))
52 | status="${response[1]}"
53 | fi
54 |
55 | if (( status >= 200 || status < 400 )); then
56 | return 0;
57 | else
58 | return 1;
59 | fi
60 | }
61 |
62 | function download_tools {
63 |
64 | echo "Installing clang ${clangVersion} tools"
65 |
66 | # Do we have wget or curl?
67 |
68 | if command -v curl 2>/dev/null; then
69 | _machineHasCurl=1
70 | elif ! command -v wget 2>/dev/null; then
71 | echo "Error: curl or wget not found; not downloading clang-format and clang-tidy."
72 | return 1
73 | fi
74 |
75 | # Figure out which version to download. Use the "RID:" value from "dotnet --info".
76 | # It looks like one of these:
77 | # RID: osx-arm64
78 | # RID: linux-x64
79 | # RID: osx.10.12-x64
80 | # RID: ubuntu.22.04-x64
81 | #
82 | # If the RID doesn't work directly, it could be used to pick the appropriate platform.
83 | # Note that we currently don't support osx-x64 clang tools.
84 |
85 | clangToolsRootUrl="https://clrjit2.blob.core.windows.net/clang-tools"
86 |
87 | clangPlatform="$(dotnet --info | grep 'RID:')"
88 | clangPlatform="${clangPlatform##*RID:* }"
89 |
90 | # override common RIDs with compatible version so we don't need to upload binaries for each RID
91 | case $clangPlatform in
92 | osx*-x64)
93 | echo "clang-tidy/clang-format are not supported on osx-x64."
94 | return 0
95 | ;;
96 | ubuntu.*-x64)
97 | clangPlatform=linux-x64
98 | ;;
99 | esac
100 |
101 | clangFormatUrl="${clangToolsRootUrl}/${clangVersion}/${clangPlatform}/clang-format"
102 |
103 | if validate_url "$clangFormatUrl" > /dev/null; then
104 | echo "Downloading clang-format from ${clangFormatUrl} to bin directory"
105 | if (( _machineHasCurl == 1 )); then
106 | curl --retry 4 --progress-bar --location --fail "$clangFormatUrl" -o bin/clang-format
107 | else
108 | wget --tries 4 --progress=dot:giga "$clangFormatUrl" -O bin/clang-format
109 | fi
110 | chmod 751 bin/clang-format
111 | else
112 | echo "clang-format not found here: $clangFormatUrl"
113 | fi
114 |
115 | clangTidyUrl="${clangToolsRootUrl}/${clangVersion}/${clangPlatform}/clang-tidy"
116 |
117 | if validate_url "$clangTidyUrl" > /dev/null; then
118 | echo "Downloading clang-tidy from ${clangTidyUrl} to bin directory"
119 | if (( _machineHasCurl == 1 )); then
120 | curl --retry 4 --progress-bar --location --fail "$clangTidyUrl" -o bin/clang-tidy
121 | else
122 | wget --tries 4 --progress=dot:giga "$clangTidyUrl" -O bin/clang-tidy
123 | fi
124 | chmod 751 bin/clang-tidy
125 | else
126 | echo "clang-tidy not found here: $clangTidyUrl"
127 | fi
128 |
129 | if [ ! -f bin/clang-format -o ! -f bin/clang-tidy ]; then
130 | echo "Either clang-tidy or clang-format was not installed. Please install and put them on the PATH to use jit-format."
131 | echo "Tools can be found at https://github.com/llvm/llvm-project/releases/tag/llvmorg-${clangVersion}"
132 | return 1
133 | fi
134 |
135 | return 0
136 | }
137 |
138 | # Start the non-functions.
139 |
140 | __ErrMsgPrefix="ERROR: "
141 |
142 | get_host_os
143 |
144 | # Check if our required tools exist.
145 |
146 | if ! hash dotnet 2>/dev/null; then
147 | echo "${__ErrMsgPrefix}Can't find dotnet! Please install from https://dot.net and add to PATH."
148 | exit 1
149 | fi
150 |
151 | if ! hash git 2>/dev/null; then
152 | echo "${__ErrMsgPrefix}Can't find git! Please add to PATH."
153 | exit 1
154 | fi
155 |
156 | # Are we already in the dotnet/jitutils repo? Or do we need to clone it? We look for build.cmd
157 | # in the directory this script was invoked from.
158 |
159 | # Obtain the location of the bash script.
160 | __root="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
161 |
162 | # Check if the bootstrap script is in the root of the jitutils repo.
163 | # By default, we're going to clone the repo.
164 | __clone_repo=1
165 | if [ -e ${__root}/build.cmd ]; then
166 | # We found build.cmd. But make sure it's the root of the repo.
167 | __root="$( cd ${__root} && git rev-parse --show-toplevel )"
168 | pushd ${__root} >/dev/null
169 | git remote -v | grep "/jitutils" >/dev/null
170 | if [ $? == 0 ]; then
171 | # We've proven that we're at the root of the jitutils repo.
172 | __clone_repo=0
173 | fi
174 | popd >/dev/null
175 | fi
176 |
177 | if [ ${__clone_repo} == 1 ]; then
178 | git clone https://github.com/dotnet/jitutils.git
179 | exit_code=$?
180 | if [ $exit_code != 0 ]; then
181 | echo "${__ErrMsgPrefix}git clone failed."
182 | exit $exit_code
183 | fi
184 | if [ ! -d ${__root}/jitutils ]; then
185 | echo "${__ErrMsgPrefix}can't find ${__root}/jitutils."
186 | exit 1
187 | fi
188 | pushd ${__root}/jitutils >/dev/null
189 | else
190 | pushd . >/dev/null
191 | fi
192 |
193 | # Pull in needed packages. This works globally (due to jitutils.sln).
194 |
195 | dotnet restore
196 | exit_code=$?
197 | if [ $exit_code != 0 ]; then
198 | echo "${__ErrMsgPrefix}Failed to restore packages."
199 | exit $exit_code
200 | fi
201 |
202 | # Build and publish all the utilities
203 |
204 | ./build.sh -p
205 | exit_code=$?
206 | if [ $exit_code != 0 ]; then
207 | echo "${__ErrMsgPrefix}Build failed."
208 | exit $exit_code
209 | fi
210 |
211 | # Check for the formatting tools, and download them if necessary.
212 |
213 | clangVersion="17.0.6"
214 |
215 | exit_code=0
216 | if ! hash clang-format 2>/dev/null || ! hash clang-tidy 2>/dev/null; then
217 | download_tools
218 | exit_code=$?
219 | else
220 | if ! clang-format --version | grep -q "version ${clangVersion}" || ! clang-tidy --version | grep -q "version ${clangVersion}"; then
221 | echo "jit-format requires clang-format and clang-tidy version ${clangVersion}. Currently installed: "
222 | clang-format --version
223 | clang-tidy --version
224 |
225 | download_tools
226 | exit_code=$?
227 | fi
228 | fi
229 | if [ $exit_code != 0 ]; then
230 | echo "${__ErrMsgPrefix}Failed to download clang-format and clang-tidy."
231 | exit $exit_code
232 | fi
233 |
234 | popd >/dev/null
235 |
236 | echo "Adding ${__root}/jitutils/bin to PATH"
237 | export PATH=$PATH:${__root}/jitutils/bin
238 |
239 | echo "Done setting up!"
240 | exit 0
241 |
--------------------------------------------------------------------------------
/build-coredistools.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal EnableDelayedExpansion EnableExtensions
3 |
4 | set TargetOSArchitecture=%1
5 | set LLVMTargetsToBuild=AArch64;ARM;X86;LoongArch;RISCV
6 |
7 | if /i "%TargetOSArchitecture%" == "win-arm64" (
8 | set GeneratorPlatform=ARM64
9 | set LLVMHostTriple=aarch64-pc-windows-msvc
10 | ) else if /i "%TargetOSArchitecture%" == "win-x64" (
11 | set GeneratorPlatform=x64
12 | set LLVMHostTriple=x86_64-pc-windows-msvc
13 | ) else if /i "%TargetOSArchitecture%" == "win-x86" (
14 | set GeneratorPlatform=Win32
15 | set LLVMHostTriple=i686-pc-windows-msvc
16 | set LLVMTargetsToBuild=ARM;X86
17 | ) else (
18 | echo ERROR: Unknown target OS and architecture: %TargetOSArchitecture%
19 | echo Use one of win-arm64, win-x64, win-x86.
20 | exit /b 1
21 | )
22 |
23 | set BuildFlavor=%2
24 | if "%BuildFlavor%"=="" set BuildFlavor=Release
25 |
26 | if /i "%BuildFlavor%" == "Release" (
27 | @REM ok
28 | ) else if /i "%BuildFlavor%" == "Debug" (
29 | @REM ok
30 | ) else (
31 | echo ERROR: Unknown build flavor: %BuildFlavor%
32 | exit /b 1
33 | )
34 |
35 | if not defined LLVMDefaultTargetTriple (
36 | set LLVMDefaultTargetTriple=%LLVMHostTriple%
37 | )
38 |
39 | set RootDirectory=%~dp0
40 | set SourcesDirectory=%RootDirectory%src
41 | set BinariesDirectory=%RootDirectory%obj\%TargetOSArchitecture%
42 | set StagingDirectory=%RootDirectory%artifacts\%TargetOSArchitecture%
43 |
44 | where /q cmake.exe
45 |
46 | if %ERRORLEVEL% neq 0 (
47 | echo ERROR: cmake.exe is not found in the PATH
48 | exit /b 1
49 | )
50 |
51 | where /q llvm-tblgen.exe
52 |
53 | if %ERRORLEVEL% equ 0 goto found_llvm_tblgen
54 |
55 | @REM We expect it to be in the `bin` directory, so add that to the PATH if it's there.
56 | if not exist %RootDirectory%bin\llvm-tblgen.exe (
57 | echo ERROR: llvm-tblgen.exe is not found in the PATH
58 | exit /b 1
59 | )
60 |
61 | echo Found llvm-tblgen.exe in %RootDirectory%bin; adding that directory to PATH.
62 | set PATH=%RootDirectory%bin;%PATH%
63 |
64 | :found_llvm_tblgen
65 |
66 | for /f %%I in ('where llvm-tblgen.exe') do (
67 | set LLVMTableGen=%%~I
68 | )
69 |
70 | if not exist "%BinariesDirectory%" (
71 | mkdir "%BinariesDirectory%"
72 | )
73 |
74 | pushd "%BinariesDirectory%"
75 |
76 | @REM To use the Debug CRT, use:
77 | @REM -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug
78 | @REM
79 | @REM To build a Debug version (asserts, debug info):
80 | @REM -DCMAKE_BUILD_TYPE=Debug
81 | @REM To build a Release version (no asserts, no debug info):
82 | @REM -DCMAKE_BUILD_TYPE=Release
83 | @REM
84 | @REM Misc. LLVM CMake documentation: https://llvm.org/docs/CMake.html
85 |
86 | cmake.exe ^
87 | -G "Visual Studio 17 2022" ^
88 | -A %GeneratorPlatform% ^
89 | -DCMAKE_INSTALL_PREFIX="%StagingDirectory%" ^
90 | -DCMAKE_BUILD_TYPE=%BuildFlavor% ^
91 | -DLLVM_DEFAULT_TARGET_TRIPLE=%LLVMDefaultTargetTriple% ^
92 | -DLLVM_EXTERNAL_PROJECTS=coredistools ^
93 | -DLLVM_EXTERNAL_COREDISTOOLS_SOURCE_DIR="%SourcesDirectory%\coredistools" ^
94 | -DLLVM_HOST_TRIPLE=%LLVMHostTriple% ^
95 | -DLLVM_INCLUDE_TESTS=OFF ^
96 | -DLLVM_TABLEGEN="%LLVMTableGen%" ^
97 | -DLLVM_TARGETS_TO_BUILD=%LLVMTargetsToBuild% ^
98 | -DLLVM_TOOL_COREDISTOOLS_BUILD=ON ^
99 | -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^
100 | "%SourcesDirectory%\llvm-project\llvm"
101 |
102 | popd
103 |
104 | if %ERRORLEVEL% neq 0 goto :CMakeNonZeroExitStatus
105 |
106 | @REM Use `--config Release` for release build, `--config Debug` for debug build
107 |
108 | cmake.exe ^
109 | --build "%BinariesDirectory%" ^
110 | --target coredistools ^
111 | --config %BuildFlavor%
112 |
113 | if %ERRORLEVEL% neq 0 goto :CMakeNonZeroExitStatus
114 |
115 | cmake.exe ^
116 | --install "%BinariesDirectory%" ^
117 | --component coredistools
118 |
119 | if %ERRORLEVEL% neq 0 goto :CMakeNonZeroExitStatus
120 |
121 | exit /b 0
122 |
123 | :CMakeNonZeroExitStatus
124 |
125 | echo ERROR: cmake exited with code %ERRORLEVEL%
126 | exit /b 1
127 |
--------------------------------------------------------------------------------
/build-coredistools.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | TargetOSArchitecture=$1
4 | CrossRootfsDirectory=$2
5 |
6 | # Set this to 1 to build using Azure Linux 3
7 | BuildUsingAzureLinux=1
8 |
9 | EnsureCrossRootfsDirectoryExists () {
10 | if [ ! -d "$CrossRootfsDirectory" ]; then
11 | echo "Invalid or unspecified CrossRootfsDirectory: $CrossRootfsDirectory"
12 | exit 1
13 | fi
14 | }
15 |
16 | CMakeOSXArchitectures=
17 | LLVMTargetsToBuild="AArch64;ARM;X86;LoongArch;RISCV"
18 |
19 | # Figure out which `strip` to use. Prefer `llvm-strip` if it is available.
20 | # `llvm-strip` is available in Azure Linux 3 container,
21 | # `llvm-strip-` is available on standard cross build Ubuntu container,
22 | # `strip` is available on macOS.
23 | StripTool=$(command -v llvm-strip{,-{20..15}} strip | head -n 1)
24 | if [ -z "$StripTool" ]; then
25 | echo "Strip tool not found"
26 | exit 1
27 | fi
28 |
29 | TblGenTool=$(command -v llvm-tblgen)
30 | if [ -z "$TblGenTool" ]; then
31 | echo "llvm-tblgen tool not found"
32 | exit 1
33 | fi
34 |
35 | # Take first match from: clang clang-20 clang-19 .. clang-15
36 | C_COMPILER=$(command -v clang{,-{20..15}} | head -n 1)
37 | if [ -z "$C_COMPILER" ]; then
38 | echo "C compiler not found"
39 | # Keep going in case cmake can find one?
40 | fi
41 |
42 | CXX_COMPILER=$(command -v clang++{,-{20..15}} | head -n 1)
43 | if [ -z "$CXX_COMPILER" ]; then
44 | echo "C++ compiler not found"
45 | # Keep going in case cmake can find one?
46 | fi
47 |
48 | echo "Using C compiler: $C_COMPILER"
49 | echo "Using C++ compiler: $CXX_COMPILER"
50 | echo "Using llvm-tablegen: $TblGenTool"
51 |
52 | case "$TargetOSArchitecture" in
53 | linux-arm)
54 | CMakeCrossCompiling=ON
55 | LLVMDefaultTargetTriple=thumbv7-linux-gnueabihf
56 | LLVMHostTriple=arm-linux-gnueabihf
57 | LLVMTargetsToBuild="ARM"
58 | EnsureCrossRootfsDirectoryExists
59 | ;;
60 |
61 | linux-arm64)
62 | CMakeCrossCompiling=ON
63 | LLVMHostTriple=aarch64-linux-gnu
64 | EnsureCrossRootfsDirectoryExists
65 | ;;
66 |
67 | linux-x64)
68 | LLVMHostTriple=x86_64-linux-gnu
69 | if [ $BuildUsingAzureLinux -eq 1 ]; then
70 | CMakeCrossCompiling=ON
71 | EnsureCrossRootfsDirectoryExists
72 | else
73 | CMakeCrossCompiling=OFF
74 | fi
75 | ;;
76 |
77 | linux-loongarch64)
78 | CMakeCrossCompiling=OFF
79 | LLVMHostTriple=loongarch64-linux-gnu
80 | LLVMTargetsToBuild="LoongArch"
81 | ;;
82 |
83 | linux-riscv64)
84 | CMakeCrossCompiling=ON
85 | LLVMHostTriple=riscv64-linux-gnu
86 | LLVMTargetsToBuild="RISCV"
87 | EnsureCrossRootfsDirectoryExists
88 | ;;
89 |
90 | osx-arm64)
91 | CMakeCrossCompiling=ON
92 | CMakeOSXArchitectures=arm64
93 | LLVMHostTriple=arm64-apple-macos
94 | BuildUsingAzureLinux=1
95 | ;;
96 |
97 | osx-x64)
98 | CMakeCrossCompiling=OFF
99 | CMakeOSXArchitectures=x86_64
100 | LLVMHostTriple=x86_64-apple-darwin
101 | ;;
102 |
103 | *)
104 | echo "Unknown target OS and architecture: $TargetOSArchitecture"
105 | exit 1
106 | esac
107 |
108 | LLVMDefaultTargetTriple=${LLVMDefaultTargetTriple:-$LLVMHostTriple}
109 |
110 | RootDirectory="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
111 | SourcesDirectory=$RootDirectory/src
112 | BinariesDirectory=$RootDirectory/obj/$TargetOSArchitecture
113 | StagingDirectory=$RootDirectory/artifacts/$TargetOSArchitecture
114 |
115 | command -v cmake >/dev/null 2>&1
116 |
117 | if [ "$?" -ne 0 ]; then
118 | echo "ERROR: cmake is not found in the PATH"
119 | exit 1
120 | fi
121 |
122 | if [ ! -d $BinariesDirectory ]; then
123 | mkdir -p $BinariesDirectory
124 | fi
125 |
126 | pushd "$BinariesDirectory"
127 |
128 | if [ -z "$CrossRootfsDirectory" ]; then
129 | C_BUILD_FLAGS="-target $LLVMHostTriple"
130 | CXX_BUILD_FLAGS="-target $LLVMHostTriple"
131 | cmake \
132 | -G "Unix Makefiles" \
133 | -DCMAKE_BUILD_TYPE=Release \
134 | -DCMAKE_CROSSCOMPILING=$CMakeCrossCompiling \
135 | -DCMAKE_C_COMPILER=${C_COMPILER} \
136 | -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \
137 | -DCMAKE_C_FLAGS="${C_BUILD_FLAGS}" \
138 | -DCMAKE_CXX_FLAGS="${CXX_BUILD_FLAGS}" \
139 | -DCMAKE_INSTALL_PREFIX=$StagingDirectory \
140 | -DCMAKE_OSX_ARCHITECTURES=$CMakeOSXArchitectures \
141 | -DCMAKE_STRIP=$StripTool \
142 | -DLLVM_DEFAULT_TARGET_TRIPLE=$LLVMDefaultTargetTriple \
143 | -DLLVM_ENABLE_TERMINFO=OFF \
144 | -DLLVM_EXTERNAL_PROJECTS=coredistools \
145 | -DLLVM_EXTERNAL_COREDISTOOLS_SOURCE_DIR=$SourcesDirectory/coredistools \
146 | -DLLVM_HOST_TRIPLE=$LLVMHostTriple \
147 | -DLLVM_INCLUDE_TESTS=OFF \
148 | -DLLVM_TABLEGEN=$TblGenTool \
149 | -DLLVM_TARGETS_TO_BUILD=$LLVMTargetsToBuild \
150 | -DLLVM_TOOL_COREDISTOOLS_BUILD=ON \
151 | $SourcesDirectory/llvm-project/llvm
152 | elif [ $BuildUsingAzureLinux -eq 1 ]; then
153 | C_BUILD_FLAGS="--sysroot=$CrossRootfsDirectory -target $LLVMHostTriple"
154 | CXX_BUILD_FLAGS="--sysroot=$CrossRootfsDirectory -target $LLVMHostTriple"
155 | # Azure Linux 3 doesn't have `ld` so need to tell clang to use `lld` with "-fuse-ld=lld"
156 | cmake \
157 | -G "Unix Makefiles" \
158 | -DCMAKE_BUILD_TYPE=Release \
159 | -DCMAKE_SYSTEM_NAME=Linux \
160 | -DCMAKE_C_COMPILER=${C_COMPILER} \
161 | -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \
162 | -DCMAKE_C_FLAGS="${C_BUILD_FLAGS}" \
163 | -DCMAKE_CXX_FLAGS="${CXX_BUILD_FLAGS}" \
164 | -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld" \
165 | -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=lld" \
166 | -DCMAKE_INCLUDE_PATH=$CrossRootfsDirectory/usr/include \
167 | -DCMAKE_INSTALL_PREFIX=$StagingDirectory \
168 | -DCMAKE_LIBRARY_PATH=$CrossRootfsDirectory/usr/lib/$LLVMHostTriple \
169 | -DCMAKE_STRIP=$StripTool \
170 | -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
171 | -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
172 | -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
173 | -DLLVM_DEFAULT_TARGET_TRIPLE=$LLVMDefaultTargetTriple \
174 | -DLLVM_TABLEGEN=$TblGenTool \
175 | -DLLVM_ENABLE_TERMINFO=OFF \
176 | -DLLVM_EXTERNAL_PROJECTS=coredistools \
177 | -DLLVM_EXTERNAL_COREDISTOOLS_SOURCE_DIR=$SourcesDirectory/coredistools \
178 | -DLLVM_HOST_TRIPLE=$LLVMHostTriple \
179 | -DLLVM_INCLUDE_TESTS=OFF \
180 | -DLLVM_TARGETS_TO_BUILD=$LLVMTargetsToBuild \
181 | -DLLVM_TOOL_COREDISTOOLS_BUILD=ON \
182 | $SourcesDirectory/llvm-project/llvm
183 | else
184 | C_BUILD_FLAGS="--sysroot=$CrossRootfsDirectory -target $LLVMHostTriple"
185 | CXX_BUILD_FLAGS="--sysroot=$CrossRootfsDirectory -target $LLVMHostTriple"
186 | cmake \
187 | -G "Unix Makefiles" \
188 | -DCMAKE_BUILD_TYPE=Release \
189 | -DCMAKE_CROSSCOMPILING=$CMakeCrossCompiling \
190 | -DCMAKE_C_COMPILER=${C_COMPILER} \
191 | -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \
192 | -DCMAKE_C_FLAGS="${C_BUILD_FLAGS}" \
193 | -DCMAKE_CXX_FLAGS="${CXX_BUILD_FLAGS}" \
194 | -DCMAKE_INCLUDE_PATH=$CrossRootfsDirectory/usr/include \
195 | -DCMAKE_INSTALL_PREFIX=$StagingDirectory \
196 | -DCMAKE_LIBRARY_PATH=$CrossRootfsDirectory/usr/lib/$LLVMHostTriple \
197 | -DCMAKE_STRIP=$StripTool \
198 | -DLLVM_DEFAULT_TARGET_TRIPLE=$LLVMDefaultTargetTriple \
199 | -DLLVM_ENABLE_TERMINFO=OFF \
200 | -DLLVM_EXTERNAL_PROJECTS=coredistools \
201 | -DLLVM_EXTERNAL_COREDISTOOLS_SOURCE_DIR=$SourcesDirectory/coredistools \
202 | -DLLVM_HOST_TRIPLE=$LLVMHostTriple \
203 | -DLLVM_INCLUDE_TESTS=OFF \
204 | -DLLVM_TABLEGEN=$TblGenTool \
205 | -DLLVM_TARGETS_TO_BUILD=$LLVMTargetsToBuild \
206 | -DLLVM_TOOL_COREDISTOOLS_BUILD=ON \
207 | $SourcesDirectory/llvm-project/llvm
208 | fi
209 |
210 | popd
211 |
212 | if [ "$?" -ne 0 ]; then
213 | echo "ERROR: cmake exited with code $?"
214 | exit 1
215 | fi
216 |
217 | cmake \
218 | --build $BinariesDirectory \
219 | --parallel 4 \
220 | --target install-coredistools-stripped
221 |
222 | if [ "$?" -ne 0 ]; then
223 | echo "ERROR: cmake exited with code $?"
224 | exit 1
225 | fi
226 |
227 | exit 0
228 |
--------------------------------------------------------------------------------
/build-tblgen.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal EnableDelayedExpansion EnableExtensions
3 |
4 | set RootDirectory=%~dp0
5 | set SourcesDirectory=%RootDirectory%src
6 | set BinariesDirectory=%RootDirectory%obj
7 | set StagingDirectory=%RootDirectory%bin
8 |
9 | where /q cmake.exe
10 |
11 | if %ERRORLEVEL% neq 0 (
12 | echo ERROR: cmake.exe is not found in the PATH
13 | exit /b 1
14 | )
15 |
16 | if not exist "%BinariesDirectory%" (
17 | mkdir "%BinariesDirectory%"
18 | )
19 |
20 | pushd "%BinariesDirectory%"
21 |
22 | cmake.exe ^
23 | -G "Visual Studio 17 2022" ^
24 | -DCMAKE_INSTALL_PREFIX="%RootDirectory%\" ^
25 | -DLLVM_TARGETS_TO_BUILD=AArch64;ARM;X86;LoongArch;RISCV ^
26 | "%SourcesDirectory%\llvm-project\llvm"
27 |
28 | popd
29 |
30 | cmake.exe ^
31 | --build %BinariesDirectory% ^
32 | --target llvm-tblgen ^
33 | --config Release
34 |
35 | if %ERRORLEVEL% neq 0 (
36 | echo llvm-tblgen compilation has failed
37 | exit /b 1
38 | )
39 |
40 | if not exist "%StagingDirectory%" (
41 | mkdir "%StagingDirectory%"
42 | )
43 |
44 | for /r "%BinariesDirectory%" %%I in (llvm-tblgen.ex?) do (
45 | if "%%~nxI" == "llvm-tblgen.exe" (
46 | xcopy "%%~I" "%StagingDirectory%"
47 | exit /b 0
48 | )
49 | )
50 |
51 | echo llvm-tblgen.exe is not found in "%BinariesDirectory%"
52 | exit /b 1
53 |
--------------------------------------------------------------------------------
/build-tblgen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Build the Linux/Mac llvm-tblgen tool. Note that this will be run during the
4 | # Linux/Mac coredistools build. So, we only build the versions that we'll use
5 | # during those builds. Thus, we need a linux-x64 version (used for
6 | # linux-x64, linux-arm, linux-arm64 builds) and osx-x64 version (used for
7 | # osx-x64 and osx-arm64 builds).
8 |
9 | set -x
10 |
11 | TargetOSArchitecture=$1
12 | CrossRootfsDirectory=$2
13 |
14 | # Set this to 1 to build using Azure Linux
15 | BuildUsingAzureLinux=1
16 |
17 | CMakeOSXArchitectures=
18 | LLVMTargetsToBuild="AArch64;ARM;X86;LoongArch;RISCV"
19 |
20 | case "$TargetOSArchitecture" in
21 | linux-x64)
22 | LLVMHostTriple=x86_64-linux-gnu
23 | ;;
24 |
25 | linux-loongarch64)
26 | LLVMHostTriple=loongarch64-linux-gnu
27 | LLVMTargetsToBuild="LoongArch"
28 | ;;
29 |
30 | osx-x64)
31 | CMakeOSXArchitectures=x86_64
32 | LLVMHostTriple=x86_64-apple-darwin
33 | BuildUsingAzureLinux=0
34 | ;;
35 |
36 | *)
37 | echo "Unknown target OS and architecture: $TargetOSArchitecture"
38 | exit 1
39 | esac
40 |
41 | RootDirectory="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
42 | SourcesDirectory=$RootDirectory/src
43 | BinariesDirectory=$RootDirectory/obj
44 | StagingDirectory=$RootDirectory/bin
45 |
46 | command -v cmake >/dev/null 2>&1
47 |
48 | if [ "$?" -ne 0 ]; then
49 | echo "ERROR: cmake is not found in the PATH"
50 | exit 1
51 | fi
52 |
53 | if [ ! -d $BinariesDirectory ]; then
54 | mkdir -p $BinariesDirectory
55 | fi
56 |
57 | pushd "$BinariesDirectory"
58 |
59 | # Take first match from: clang clang-20 clang-19 .. clang-15
60 | C_COMPILER=$(command -v clang{,-{20..15}} | head -n 1)
61 | CXX_COMPILER=$(command -v clang++{,-{20..15}} | head -n 1)
62 |
63 | echo "============== Configuring build"
64 | if [ $BuildUsingAzureLinux -eq 1 ]; then
65 | C_BUILD_FLAGS=""
66 | CXX_BUILD_FLAGS=""
67 | # Azure Linux doesn't have `ld` so need to tell clang to use `lld` with "-fuse-ld=lld"
68 | cmake \
69 | -G "Unix Makefiles" \
70 | -DCMAKE_BUILD_TYPE=Release \
71 | -DCMAKE_ASM_COMPILER=$C_COMPILER \
72 | -DCMAKE_C_COMPILER=$C_COMPILER \
73 | -DCMAKE_CXX_COMPILER=$CXX_COMPILER \
74 | -DCMAKE_ASM_COMPILER_TARGET="$LLVMHostTriple" \
75 | -DCMAKE_C_COMPILER_TARGET="$LLVMHostTriple" \
76 | -DCMAKE_CXX_COMPILER_TARGET="$LLVMHostTriple" \
77 | -DCMAKE_C_FLAGS="${C_BUILD_FLAGS}" \
78 | -DCMAKE_CXX_FLAGS="${CXX_BUILD_FLAGS}" \
79 | -DCMAKE_INSTALL_PREFIX=$RootDirectory \
80 | -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
81 | -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=lld" \
82 | -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=lld" \
83 | -DLLVM_USE_LINKER=lld \
84 | -DLLVM_ENABLE_RUNTIMES="libcxx" \
85 | -DLIBCXX_ENABLE_SHARED=OFF \
86 | -DLIBCXX_CXX_ABI=libstdc++ \
87 | -DLIBCXX_CXX_ABI_INCLUDE_PATHS="$CPP_INCLUDES;$TRIPLET_INCLUDES" \
88 | -DLLVM_TARGETS_TO_BUILD=$LLVMTargetsToBuild \
89 | $SourcesDirectory/llvm-project/llvm
90 | elif [ -z "$CrossRootfsDirectory" ]; then
91 | BUILD_FLAGS=""
92 | cmake \
93 | -G "Unix Makefiles" \
94 | -DCMAKE_BUILD_TYPE=Release \
95 | -DCMAKE_SYSTEM_NAME=$CMakeSystemName \
96 | -DCMAKE_C_COMPILER=$C_COMPILER \
97 | -DCMAKE_CXX_COMPILER=$CXX_COMPILER \
98 | -DCMAKE_C_FLAGS="${BUILD_FLAGS}" \
99 | -DCMAKE_CXX_FLAGS="${BUILD_FLAGS}" \
100 | -DCMAKE_INSTALL_PREFIX=$RootDirectory \
101 | -DCMAKE_OSX_ARCHITECTURES=$CMakeOSXArchitectures \
102 | -DLLVM_TARGETS_TO_BUILD=$LLVMTargetsToBuild \
103 | $SourcesDirectory/llvm-project/llvm
104 | else
105 | BUILD_FLAGS="--sysroot=$CrossRootfsDirectory"
106 | cmake \
107 | -G "Unix Makefiles" \
108 | -DCMAKE_BUILD_TYPE=Release \
109 | -DCMAKE_INSTALL_PREFIX=$RootDirectory \
110 | -DCMAKE_SYSTEM_NAME=$CMakeSystemName \
111 | -DCMAKE_C_COMPILER=$C_COMPILER \
112 | -DCMAKE_CXX_COMPILER=$CXX_COMPILER \
113 | -DCMAKE_C_FLAGS="${BUILD_FLAGS}" \
114 | -DCMAKE_CXX_FLAGS="${BUILD_FLAGS}" \
115 | -DCMAKE_INCLUDE_PATH=$CrossRootfsDirectory/usr/include \
116 | -DCMAKE_LIBRARY_PATH=$CrossRootfsDirectory/usr/lib/$LLVMHostTriple \
117 | -DLLVM_TARGETS_TO_BUILD=$LLVMTargetsToBuild \
118 | $SourcesDirectory/llvm-project/llvm
119 | fi
120 |
121 | popd
122 |
123 | if [ "$?" -ne 0 ]; then
124 | echo "ERROR: cmake exited with code $?"
125 | exit 1
126 | fi
127 |
128 | echo "============== Building llvm-tblgen"
129 | cmake \
130 | --build $BinariesDirectory \
131 | --parallel 4 \
132 | --target llvm-tblgen \
133 | --config Release
134 |
135 | if [ "$?" -ne 0 ]; then
136 | echo "ERROR: cmake exited with code $?"
137 | exit 1
138 | fi
139 |
140 | if [ ! -d $StagingDirectory ]; then
141 | mkdir -p $StagingDirectory
142 | fi
143 |
144 | # Copy llvm-tblgen from BinariesDirectory to StagingDirectory
145 | find $BinariesDirectory -name llvm-tblgen -type f -exec cp -v {} $StagingDirectory \;
146 |
147 | exit 0
148 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal EnableDelayedExpansion
3 |
4 | REM Build and optionally publish sub projects
5 | REM
6 | REM This script will by default build release versions of the tools.
7 | REM If publish (-p) is requested it will create standalone versions of the
8 | REM tools in /src//bin///netcoreapp.
9 |
10 | set scriptDir=%~dp0
11 | set appInstallDir=%scriptDir%bin
12 | set buildType=Release
13 | set publish=false
14 |
15 | for /f "usebackq tokens=1,2" %%a in (`dotnet --info`) do (
16 | if "%%a"=="RID:" set rid=%%b
17 | )
18 |
19 | :argLoop
20 | if "%1"=="" goto :build
21 |
22 | if /i "%1"=="-b" (
23 | set buildType=%2
24 | shift
25 | goto :nextArg
26 | )
27 | if /i "%1"=="-p" (
28 | set publish=true
29 | goto :nextArg
30 | )
31 | if /i "%1" == "-h" (
32 | goto :usage
33 | )
34 | echo ERROR: unknown argument %1
35 | goto :usage
36 |
37 | :nextArg
38 | shift
39 | goto :argLoop
40 |
41 | :build
42 |
43 | REM Do as many builds as possible; don't stop on first failure (if any).
44 | set __ExitCode=0
45 |
46 | REM Declare the list of projects
47 | set projects=jit-diff jit-dasm jit-analyze jit-tp-analyze jit-format pmi jit-dasm-pmi jit-decisions-analyze performance-explorer instructions-retired-explorer
48 |
49 | REM Build each project
50 | for %%p in (%projects%) do (
51 | if %publish%==true (
52 | REM Publish src/pmi project without single-file, so it can be executed with a custom build of the runtime/JIT
53 | if "%%p"=="pmi" (
54 | dotnet publish -c %buildType% -o %appInstallDir% .\src\%%p
55 | ) else (
56 | dotnet publish -c %buildType% -o %appInstallDir% .\src\%%p --self-contained -r:%rid% -p:PublishSingleFile=true
57 | )
58 | if errorlevel 1 echo ERROR: dotnet publish failed for .\src\%%p.&set __ExitCode=1
59 | ) else (
60 | dotnet build -c %buildType% .\src\%%p
61 | if errorlevel 1 echo ERROR: dotnet build failed for .\src\%%p.&set __ExitCode=1
62 | )
63 | )
64 |
65 | REM Done
66 | exit /b %__ExitCode%
67 |
68 | :usage
69 | echo.
70 | echo build.cmd [-b ^] [-h] [-p]
71 | echo.
72 | echo -b ^ : Build type, can be Debug or Release.
73 | echo -h : Show this message.
74 | echo -p : Publish utilities.
75 | echo.
76 | exit /b 1
77 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ## Build and optionally publish sub projects
4 | ##
5 | ## This script will by default build release versions of the tools.
6 | ## If publish (-p) is requested it will create standalone versions of the
7 | ## tools in /bin.
8 |
9 | function usage
10 | {
11 | echo ""
12 | echo "build.sh [-b ] [-h] [-p]"
13 | echo ""
14 | echo " -b : Build type, can be Debug or Release."
15 | echo " -h : Show this message."
16 | echo " -p : Publish utilities."
17 | echo ""
18 | }
19 |
20 | # defaults
21 | __ErrMsgPrefix="ERROR: "
22 | final_exit_code=0
23 | buildType="Release"
24 | publish=0
25 | scriptDir="$(cd "$(dirname "$0")" || exit; pwd -P)"
26 | # default install in 'bin' dir at script location
27 | appInstallDir="$scriptDir/bin"
28 | rid=$(dotnet --info | grep RID:)
29 | rid=${rid##*RID:* }
30 |
31 | # process for '-h', '-p', '-b '
32 | while getopts "hpb:" opt; do
33 | case "$opt" in
34 | h)
35 | usage
36 | exit 0
37 | ;;
38 | b)
39 | buildType=$OPTARG
40 | ;;
41 | p)
42 | publish=1
43 | ;;
44 | *) echo "ERROR: unknown argument $opt"
45 | exit 1
46 | ;;
47 | esac
48 | done
49 |
50 | # declare the array of projects
51 | declare -a projects=(jit-dasm jit-diff jit-analyze jit-tp-analyze jit-format pmi jit-dasm-pmi jit-decisions-analyze performance-explorer instructions-retired-explorer)
52 |
53 | # for each project either build or publish
54 | for proj in "${projects[@]}"
55 | do
56 | if [ "$publish" = 1 ]; then
57 | case "$proj" in
58 | # Publish src/pmi project without single-file, so it can be executed with a custom build of the runtime/JIT
59 | pmi) dotnet publish -c "$buildType" -o "$appInstallDir" ./src/"$proj" ;;
60 | *) dotnet publish -c "$buildType" -o "$appInstallDir" ./src/"$proj" --self-contained -r $rid -p:PublishSingleFile=true ;;
61 | esac
62 | exit_code=$?
63 | if [ $exit_code != 0 ]; then
64 | echo "${__ErrMsgPrefix}dotnet publish of ./src/${proj} failed."
65 | final_exit_code=1
66 | fi
67 | else
68 | dotnet build -c "$buildType" ./src/"$proj"
69 | exit_code=$?
70 | if [ $exit_code != 0 ]; then
71 | echo "${__ErrMsgPrefix}dotnet build of ./src/${proj} failed."
72 | final_exit_code=1
73 | fi
74 | fi
75 | done
76 |
77 | exit "$final_exit_code"
78 |
--------------------------------------------------------------------------------
/doc/building-coredistools.md:
--------------------------------------------------------------------------------
1 | # Building coredistools
2 |
3 | ## Building on Windows with Visual Studio 2022
4 |
5 | 1. Checkout the jitutils repository:
6 | ```
7 | git clone https://github.com/dotnet/jitutils.git
8 | cd jitutils
9 | ```
10 |
11 | 2. Checkout the LLVM project repository into a subdirectory named src/llvm-project:
12 | ```
13 | git clone --depth 1 --branch llvmorg-20.1.0 https://github.com/llvm/llvm-project.git src\llvm-project
14 | ```
15 |
16 | 3. Build `llvm-tblgen.exe`:
17 | ```
18 | build-tblgen.cmd
19 | ```
20 |
21 | This builds llvm-tblgen.exe and puts it in the `bin` subdirectory.
22 |
23 | 4. Add the `bin` subdirectory to the `PATH`:
24 | ```
25 | set "PATH=%cd%\bin;%PATH%"
26 | ```
27 |
28 | This puts the just built lldb-tblgen.exe on the `PATH`.
29 |
30 | 5. Build `coredistools.dll` for a combination of target OS and architecture.
31 | Build Windows x64, Windows x86, and Windows ARM64 binaries:
32 | ```
33 | build-coredistools.cmd win-x64
34 | build-coredistools.cmd win-x86
35 | build-coredistools.cmd win-arm64
36 | ```
37 |
38 | The file will be copied to subdirectory `artifacts` after the command finishes. E.g., for win-x64:
39 | ```
40 | dir /A:-D /B /S artifacts\win-x64
41 | F:\echesako\git\jitutils\artifacts\win-x64\bin\coredistools.dll
42 | F:\echesako\git\jitutils\artifacts\win-x64\lib\coredistools.lib
43 | ```
44 |
45 | ### Building Debug binaries
46 |
47 | The `build-coredistools.cmd` script is set up to build a Release build. To create a Debug build with a PDB file
48 | for debugging, change the `--config Release` line to `--config Debug`.
49 |
50 | ## Building on Linux / Mac
51 |
52 | 1. Checkout the jitutils repository:
53 | ```
54 | git clone https://github.com/dotnet/jitutils.git
55 | cd jitutils
56 | ```
57 |
58 | 2. Checkout the LLVM project repository:
59 | ```
60 | git clone --depth 1 --branch llvmorg-20.1.0 https://github.com/llvm/llvm-project.git src/llvm-project
61 | ```
62 |
63 | 3. Start the Docker container in which the build will be run:
64 | ```
65 | docker run -it --rm --entrypoint /bin/bash -v ~/git/jitutils:/opt/code -w /opt/code mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net10.0-cross-amd64
66 | ```
67 |
68 | 4. Install necessary dependencies (in Docker):
69 | You need to install the `ncurses-compat` package because the Azure Linux container we use doesn't have libtinfo.so.5, which the built
70 | llvm-tblgen needs to be able to run. (Note that we build in the Azure Linux container, but we also run some built binaries, namely llvm-tblgen,
71 | as part of the build process.)
72 | ```
73 | sudo tdnf install -y ncurses-compat
74 | ```
75 |
76 | 5. Build `llvm-tblgen` (in Docker):
77 | ```
78 | ./build-tblgen.sh linux-x64 /crossrootfs/x64
79 | ```
80 |
81 | This builds llvm-tblgen and puts it in the `bin` subdirectory.
82 |
83 | 6. Add `llvm-tblgen` to the PATH (in Docker):
84 | ```
85 | export PATH=$(pwd)/bin:$PATH
86 | ```
87 |
88 | 7. Build `libcoredistools.so` for Linux x64 (in Docker):
89 | ```
90 | ./build-coredistools.sh linux-x64 /crossrootfs/x64
91 | ```
92 |
93 | The file will be copied to subdirectory `artifacts` after the command finishes:
94 | ```
95 | find ./artifacts -name libcoredistools.so
96 | ./artifacts/linux-x64/bin/libcoredistools.so
97 | ./artifacts/linux-x64/lib/libcoredistools.so
98 | ```
99 |
100 | 8. Build `libcoredistools.so` for Linux arm64 under Docker:
101 | ```
102 | docker run -it --rm --entrypoint /bin/bash -v ~/git/jitutils:/opt/code -w /opt/code mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net10.0-cross-arm64
103 | sudo tdnf install -y ncurses-compat
104 | export PATH=$(pwd)/bin:$PATH
105 | ./build-coredistools.sh linux-arm64 /crossrootfs/arm64
106 | ```
107 |
108 | 9. Build `libcoredistools.so` for Linux arm under Docker:
109 | ```
110 | docker run -it --rm --entrypoint /bin/bash -v ~/git/jitutils:/opt/code -w /opt/code mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net10.0-cross-arm
111 | sudo tdnf install -y ncurses-compat
112 | export PATH=$(pwd)/bin:$PATH
113 | ./build-coredistools.sh linux-arm /crossrootfs/arm
114 | ```
115 |
116 | 10. Build `libcoredistools.so` for Linux riscv64 under Docker:
117 | There is no Azure Linux container for RISC-V so use the standard Ubuntu cross build container used for e.g. dotnet/runtime.
118 | ```
119 | docker run -it --rm --entrypoint /bin/bash -v ~/git/jitutils:/opt/code -w /opt/code mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-cross-riscv64
120 | apt install libtinfo5
121 |
122 | # If you haven't built llvm-tblgen in step 5, you can do so in the same docker (pass "/" as crossrootfs).
123 | ./build-tblgen.sh linux-x64 /
124 |
125 | # Now, the main course
126 | export PATH=$(pwd)/bin:$PATH
127 | ./build-coredistools.sh linux-riscv64 /crossrootfs/riscv64
128 | ```
129 |
--------------------------------------------------------------------------------
/doc/cijobs.md:
--------------------------------------------------------------------------------
1 | # CI jobs information
2 |
3 | The .NET team maintains a "continuous integration" (CI) system for testing .NET, using Jenkins.
4 | In particular, each source code change submitted for consideration is tested.
5 | The "cijobs" command-line tool allows for querying the CI for per-job information,
6 | and for downloading archived per-job artifacts. These artifacts can be used for
7 | generating assembly code output, instead of building your own baseline JIT, for example.
8 |
9 | ## cijobs
10 |
11 | cijobs has two commands: (1) list, and (2) copy.
12 |
13 | cijobs help message:
14 | ```
15 | $ cijobs --help
16 | usage: cijobs []
17 |
18 | list List jobs on ci.dot.net for the repo.
19 | copy Copies job artifacts from ci.dot.net. This
20 | command copies a zip of artifacts from a repo (defaulted to
21 | dotnet_coreclr). The default location of the zips is the
22 | Product sub-directory, though that can be changed using the
23 | ContentPath(p) parameter
24 | ```
25 |
26 | The "cijobs list" command has the following help message:
27 | ```
28 | $ cijobs list --help
29 | usage: cijobs list [-j ] [-b ] [-r ] [-m ]
30 | [-n ] [-l] [-c ] [-a]
31 |
32 | -s, --server Url of the server. Defaults to
33 | https://ci.dot.net/
34 | -j, --job Name of the job.
35 | -b, --branch Name of the branch (default is master).
36 | -r, --repo Name of the repo (e.g. dotnet_corefx or
37 | dotnet_coreclr). Default is dotnet_coreclr
38 | -m, --match Regex pattern used to select jobs output.
39 | -n, --number Job number.
40 | -l, --last_successful List last successful build.
41 | -c, --commit List build at this commit.
42 | -a, --artifacts List job artifacts on server.
43 | ```
44 |
45 | The "cijobs copy" command has the following help message:
46 | ```
47 | usage: cijobs copy [-j ] [-n ] [-l] [-c ] [-b ]
48 | [-r ] [-o ] [-u] [-p ]
49 |
50 | -s, --server Url of the server. Defaults to
51 | https://ci.dot.net/
52 | -j, --job Name of the job.
53 | -n, --number Job number.
54 | -l, --last_successful Copy last successful build.
55 | -c, --commit Copy this commit.
56 | -b, --branch Name of the branch (default is master).
57 | -r, --repo Name of the repo (e.g. dotnet_corefx or
58 | dotnet_coreclr). Default is
59 | dotnet_coreclr
60 | -o, --output Output path.
61 | -u, --unzip Unzip copied artifacts
62 | -p, --ContentPath Relative product zip path. Default is
63 | artifact/bin/Product/*zip*/Product.zip
64 | ```
65 |
66 | ## Using cijobs
67 |
68 | A common question for a developer might be "what is the last successful OSX checked build?"
69 |
70 | ```
71 | $ cijobs list --match "osx"
72 |
73 | job checked_osx
74 | job checked_osx_flow
75 | job checked_osx_flow_prtest
76 | job checked_osx_prtest
77 | job checked_osx_tst
78 | job checked_osx_tst_prtest
79 | job debug_osx
80 | job debug_osx_flow
81 | job debug_osx_flow_prtest
82 | job debug_osx_prtest
83 | job debug_osx_tst
84 | job debug_osx_tst_prtest
85 | job release_osx
86 | job release_osx_flow
87 | ...
88 | ```
89 |
90 | The previous example shows searching for job names that match "osx". The checked_osx jobs is the
91 | one the developer wants. (Some familiarity with the jobs running on the server is helpful.
92 | Visit https://ci.dot.net to familarize yourself with what's available.)
93 |
94 | Further querying the `checked_osx` job for the last successful build can be done with this command
95 | line.
96 |
97 | ```
98 | $ cijobs list --job checked_osx --last_successful
99 |
100 | Last successful build:
101 | build 1609 - SUCCESS : commit 74798b5b95aca1b27050038202034448a523c9f9
102 | ```
103 |
104 | With this in hand two things can be accomplished. First, new development for a feature could be
105 | started based on the commit hash returned. Second, the tools generated by this job can be downloaded
106 | for use locally.
107 |
108 | ```
109 | $ cijobs copy --job checked_osx --last_successful --output ../output/mytools --unzip
110 |
111 | Downloading: job/dotnet_coreclr/job/master/job/checked_osx/1609/artifact/bin/Product/*zip*/Product.zip
112 | ```
113 |
114 | Results are unzipped in the output after they are downloaded.
115 |
116 | ```
117 | $ ls ../output/mytools/
118 | Product Product.zip
119 |
120 | ```
121 |
122 | One comment on the underlying Jenkins feature. The artifacts are kept and managed by a Jenkins plug-in
123 | used by the system. This plug-in will ZIP compress on demand at any point in the defined artifacts output tree.
124 | Today we only use the Product sub-directory but this could be extended in the future.
125 |
--------------------------------------------------------------------------------
/doc/config.md:
--------------------------------------------------------------------------------
1 | # Configuring defaults
2 |
3 | Several jitutils tools support specifying default command line arguments via a configuration
4 | file. This file is described here.
5 |
6 | The tools which currently support this configuration mechanism are: jit-diff, jit-format.
7 |
8 | ## Overview
9 |
10 | When the environment variable `JIT_UTILS_ROOT` is defined, it specifies the directory where a
11 | config.json file can be found that specifies various configuration data that will be used
12 | while running the jitutils tools. It also specifies the root directory where the tools can
13 | create subdirectories to copy various things.
14 |
15 | ```
16 | $ export JIT_UTILS_ROOT=~/Work/output
17 | $ ls -1 $JIT_UTILS_ROOT
18 | config.json
19 | dasmset_1
20 | dasmset_2
21 | dasmset_3
22 | dasmset_4
23 | dasmset_5
24 | tools
25 | ```
26 |
27 | The above example shows a populated `JIT_UTILS_ROOT` directory. The config.json file contains defaults,
28 | the `dasmset_(x)` contain multiple iterations of output from jit-diff, and the tools directory
29 | contains installed tools.
30 |
31 | ### config.json
32 |
33 | A sample config.json file is included in the jitutils repo as an example that can be modified
34 | for a developer's own use. We will go through the different elements here for added detail.
35 | This file supplies the configuration options for both jit-diff and jit-format. The most interesting
36 | section of the file is the `"default"` section. Each sub element of `"default"` maps directly to a jit-diff
37 | or jit-format option name. Setting a default value here will cause the tools to
38 | use the given value on start up and then only override that value if new options are passed
39 | on the command line.
40 |
41 | In the jit-diff section, the `"base"` and `"diff"` entries are worth going into
42 | in more detail. The `"base"` is set to `"checked_osx-1526"`. Looking down in the `"tools"` section
43 | shows that the tool is installed in the `tools` sub-directory of the directory specified by
44 | `JIT_UTILS_ROOT`. Any of the tools listed like this can be used in the default section
45 | as a value, but they can also be passed on the command line
46 | as the value for `--base` or `--diff`.
47 |
48 | Sample config.json:
49 | ```
50 | {
51 | "format": {
52 | "default": {
53 | "arch": "x64",
54 | "build": "Checked",
55 | "os": "windows",
56 | "coreclr": "C:\\michelm\\coreclr",
57 | "verbose": "true",
58 | "fix": "true"
59 | }
60 | },
61 | "asmdiff": {
62 | "default": {
63 | "base": "checked_osx-1526",
64 | "diff": "/Users/russellhadley/Work/dotnet/coreclr/bin/Product/OSX.x64.Checked",
65 | "frameworks": "true",
66 | "output": "/Users/russellhadley/Work/dotnet/output",
67 | "core_root": "/Users/russellhadley/Work/dotnet/runtime/artifacts/tests/coreclr/OSX.x64.Checked/Tests/Core_Root"
68 | },
69 | "tools": [
70 | {
71 | "tag": "checked_osx-1439",
72 | "path": "/Users/russellhadley/Work/dotnet/output/tools/checked_osx-1439/Product/OSX.x64.Checked"
73 | },
74 | {
75 | "tag": "checked_osx-1442",
76 | "path": "/Users/russellhadley/Work/dotnet/output/tools/checked_osx-1442/Product/OSX.x64.Checked"
77 | },
78 | {
79 | "tag": "checked_osx-1443",
80 | "path": "/Users/russellhadley/Work/dotnet/output/tools/checked_osx-1443/Product/OSX.x64.Checked"
81 | },
82 | {
83 | "tag": "checked_osx-1526",
84 | "path": "/Users/russellhadley/Work/dotnet/output/tools/checked_osx-1526/Product/OSX.x64.Checked"
85 | }
86 | ]
87 | }
88 | }
89 | ```
90 |
91 | ### Listing current defaults
92 |
93 | The jit-diff command `list` will read the config.json file in the specified `JIT_UTILS_ROOT` path, and list
94 | the results. Adding `--verbose` will show the associated file system paths for installed tools as well.
95 |
96 | For example:
97 | ```
98 | $ jit-diff list
99 |
100 | Defaults:
101 | base: checked_osx-1526
102 | diff: /Users/russellhadley/Work/dotnet/coreclr/bin/Product/OSX.x64.Checked
103 | output: /Users/russellhadley/Work/dotnet/output
104 | core_root: /Users/russellhadley/Work/dotnet/runtime/artifacts/tests/coreclr/OSX.x64.Checked/Tests/Core_Root
105 | frameworks: true
106 |
107 | Installed tools:
108 | checked_osx-1439
109 | checked_osx-1442
110 | checked_osx-1443
111 | checked_osx-1526
112 | ```
113 |
114 | ### Installing new tools
115 |
116 | The jit-diff command `install` will download and install a new tool to the default location
117 | and update the config.json so it can be found.
118 |
119 | The options to `install` are the same as you would use for the cijobs copy command since jit-diff
120 | uses cijobs to download the appropriate tools. I.e. the `install` command is just a wrapper over
121 | cijobs to simplify getting tools into the default location correctly.
122 |
--------------------------------------------------------------------------------
/doc/formatting.md:
--------------------------------------------------------------------------------
1 | # JIT source code formatting
2 |
3 | JIT source code is automatically formatted by the jit-format tool.
4 | The idea is to automatically enforce the
5 | [CLR JIT Coding Conventions](https://github.com/dotnet/coreclr/blob/master/Documentation/coding-guidelines/clr-jit-coding-conventions.md)
6 | where possible, although the tool by its nature ends up defining the
7 | coding conventions by the formatting it enforces. The tool invokes clang-format and clang-tidy
8 | to do its work.
9 |
10 | ## jit-format
11 |
12 | The jit-format tool runs over all jit source, or specific files if they are specified.
13 | It can either tell the user that code needs to be reformatted or it
14 | can fix the source itself.
15 |
16 | Sample help command line
17 | ```
18 | $ jit-format --help
19 | usage: jit-format [-a ] [-o ] [-b ] [-c ]
20 | [--compile-commands ] [-v] [--untidy]
21 | [--noformat] [-f] [-i] [--projects ...] [--]
22 | ...
23 |
24 | -a, --arch The architecture of the build (options:
25 | x64, x86)
26 | -o, --os The operating system of the build
27 | (options: Windows, OSX, Ubuntu, Fedora,
28 | etc.)
29 | -b, --build The build type of the build (options:
30 | Release, Checked, Debug)
31 | -c, --coreclr Full path to base coreclr directory
32 | --compile-commands Full path to compile_commands.json
33 | -v, --verbose Enable verbose output.
34 | --untidy Do not run clang-tidy
35 | --noformat Do not run clang-format
36 | -f, --fix Fix formatting errors discovered by
37 | clang-format and clang-tidy.
38 | -i, --ignore-errors Ignore clang-tidy errors
39 | --projects ... List of build projects clang-tidy should
40 | consider (e.g. dll, standalone,
41 | protojit, etc.). Default: dll
42 | ... Optional list of files that should be
43 | formatted.
44 | ```
45 |
46 | ## Using jit-format
47 |
48 | A common task for developers is to format their changes before submitting a GitHub pull request.
49 | A developer can run the tool using the tests/scripts/format.py script in the coreclr repo:
50 |
51 | ```
52 | python src\coreclr\scripts\jitformat.py --coreclr C:\gh\runtime\src\coreclr --arch x64 --os windows
53 | ```
54 |
55 | This will run all build flavors and all projects for the user. This should be done on both
56 | Windows and Linux.
57 |
58 | A developer can also run the tool manually:
59 |
60 | ```
61 | jit-format -c c:\gh\coreclr -f
62 | ```
63 |
64 | or, specifically passing architecture, build type, and operating system:
65 |
66 | ```
67 | jit-format -a x64 -b Debug -o Windows -c C:\gh\coreclr -f
68 | ```
69 |
70 | This will run both clang-tidy and clang-format on all of the jit code and fix all the
71 | formatting to match the rules.
72 |
73 | Often a developer is only interested in a few files. For example,
74 | you can invoke jit-format as follows to just examine lower.cpp and codegenxarch.cpp:
75 |
76 | ```
77 | jit-format -a x64 -b Debug -o Windows -c C:\gh\coreclr -v lower.cpp codegenxarch.cpp
78 |
79 | Formatting jit directory.
80 | Formatting dll project.
81 | Building compile_commands.json.
82 | Using compile_commands.json found at C:\gh\coreclr\bin\obj\windows.x64.Checked\compile_commands.json
83 | Running clang-tidy.
84 | Running:
85 | clang-tidy -checks=-*,readability-braces*,modernize-use-nullptr -header-filter=.* -p C:\gh\coreclr\bin\obj\windows.x64.Checked\compile_commands.json C:\gh\coreclr\src\jit\codegenxarch.cpp
86 |
87 | Running:
88 | clang-tidy -checks=-*,readability-braces*,modernize-use-nullptr -header-filter=.* -p C:\gh\coreclr\bin\obj\windows.x64.Checked\compile_commands.json C:\gh\coreclr\src\jit\lower.cpp
89 |
90 | Running: clang-format C:\gh\coreclr\src\jit\codegenxarch.cpp
91 | Running: clang-format C:\gh\coreclr\src\jit\lower.cpp
92 | ```
93 |
94 | jit-format runs over only those files. The verbose flag shows the user what
95 | clang-tidy and clang-format invocations are being executed.
96 |
97 | When the developer is ready to check in, they will want to make sure they fix any formatting
98 | errors that clang-tidy and clang-format identified. This can be done with the --fix flag:
99 |
100 | ```
101 | jit-format -a x64 -b Debug -o Windows -c C:\gh\coreclr -v --fix lower.cpp codegenxarch.cpp
102 |
103 | Formatting jit directory.
104 | Formatting dll project.
105 | Building compile_commands.json.
106 | Using compile_commands.json found at C:\gh\coreclr\bin\obj\windows.x64.Checked\compile_commands.json
107 | Running clang-tidy.
108 | Running:
109 | clang-tidy -fix -checks=-*,readability-braces*,modernize-use-nullptr -header-filter=.* -p C:\gh\coreclr\bin\obj\windows.x64.Checked\compile_commands.json C:\gh\coreclr\src\jit\codegenxarch.cpp
110 |
111 | Running:
112 | clang-tidy -fix -checks=-*,readability-braces*,modernize-use-nullptr -header-filter=.* -p C:\gh\coreclr\bin\obj\windows.x64.Checked\compile_commands.json C:\gh\coreclr\src\jit\lower.cpp
113 |
114 | Running: clang-format -i C:\gh\coreclr\src\jit\codegenxarch.cpp
115 | Running: clang-format -i C:\gh\coreclr\src\jit\lower.cpp
116 | ```
117 |
118 | The developer may also only be interested in only running clang-tidy or clang-format without
119 | running the other tool. This can be done by using the --noformat (no clang-format) or
120 | --untidy (no clang-tidy) flags.
121 |
122 | Finally, the developer can pass their own compile_commands.json database to jit-format
123 | if they already have one built:
124 |
125 | ```
126 | jit-format.cmd --fix --noformat --compile-commands C:\gh\jitutils\test\jit-format\compile_commands.json --coreclr C:\gh\jitutils\test\jit-format C:\gh\jitutils\test\jit-format\test.cpp
127 | Formatting jit directory.
128 | Formatting dll project.
129 | Using compile_commands.json found at C:\gh\jitutils\test\jit-format\compile_commands.json
130 | Running clang-tidy.
131 | Running:
132 | clang-tidy -fix -checks=-*,readability-braces*,modernize-use-nullptr -header-filter=.* -p C:\gh\jitutils\test\jit-format\compile_commands.json C:\gh\jitutils\test\jit-format\test.cpp
133 | ```
134 |
135 | ## clang-format and clang-tidy
136 |
137 | jit-format uses clang-format and clang-tidy to do its work.
138 |
139 | Currently, clang-tidy will run the `modernize-use-nullptr` and `readability-braces`
140 | checks. Clang-format will use the `.clang-format` specification found in the jit directory.
141 | A summary of what each of the options does can be found
142 | [here](https://llvm.org/releases/3.8.0/tools/clang/docs/ClangFormatStyleOptions.html).
143 |
144 | Because jit-format will build a `compile_commands.json` database from the build log on Windows,
145 | developers must do a full build of coreclr before running jit-format.
146 |
147 | ## Limitations
148 |
149 | The clang-format and clang-tidy tools cannot enforce all the rules specified in the CLR JIT Coding Conventions.
150 | Developers still need to be aware of these conventions and follow the parts that can't be automatically
151 | enforced.
152 |
153 | Clang-format and clang-tidy have bugs and limitations to their enforcement. One particular example: a comment
154 | line followed by an `#ifdef`, typically placed at the leftmost column, will cause the comment line to be also
155 | aligned to the leftmost column. To avoid this, the JIT sources introduced the `CLANG_FORMAT_COMMENT_ANCHOR`
156 | macro to prevent this from happening, used as follows:
157 |
158 | ```
159 | // Some kind of comment
160 | CLANG_FORMAT_COMMENT_ANCHOR;
161 |
162 | #ifdef SOME_KIND_OF_IFDEF
163 | ```
164 |
165 | ## Configuring defaults
166 |
167 | See the document [configuring defaults](config.md) for details on setting up a set of default configurations.
168 |
--------------------------------------------------------------------------------
/doc/tools.md:
--------------------------------------------------------------------------------
1 | # Other Tools
2 |
3 | ## pmi
4 |
5 | `pmi` is a low-level tool for running the jit across the methods in an assembly.
6 | It can be used as a component to create diffs or to simply test whether the jit
7 | encounters any internal issues when jitting methods.
8 | ```
9 | $pmi --help
10 |
11 | Usage:
12 |
13 | pmi Count PATH_TO_ASSEMBLY
14 | Count the number of types and methods in an assembly.
15 |
16 | pmi PrepOne PATH_TO_ASSEMBLY INDEX_OF_TARGET_METHOD
17 | JIT a single method, specified by a method number.
18 |
19 | pmi PrepAll PATH_TO_ASSEMBLY [INDEX_OF_FIRST_METHOD_TO_PROCESS]
20 | JIT all the methods in an assembly. If INDEX_OF_FIRST_METHOD_TO_PROCESS
21 | is specified, it is the first method compiled, followed by all subsequent
22 | methods.
23 |
24 | pmi DriveAll PATH_TO_ASSEMBLY
25 | The same as PrepAll, but is more robust. While PrepAll will stop at the
26 | first JIT assert, DriveAll will continue by skipping that method.
27 |
28 | Environment variable PMIPATH is a semicolon-separated list of paths used to find
29 | dependent assemblies.
30 |
31 | Use PrepAll-Quiet and PrepOne-Quiet if less verbose output is desired.
32 | ```
33 |
--------------------------------------------------------------------------------
/eng/build.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | agentOs: ''
3 | pool: ''
4 |
5 | jobs:
6 | - job: ${{ parameters.agentOs }}
7 | pool: ${{ parameters.pool }}
8 | steps:
9 | - checkout: self
10 | clean: true
11 |
12 | - task: UseDotNet@2
13 | displayName: 'Install .NET Core SDK'
14 | inputs:
15 | packageType: sdk
16 | version: 8.x
17 | installationPath: $(Agent.ToolsDirectory)/dotnet
18 |
19 | - ${{ if eq(parameters.agentOs, 'Windows_NT') }}:
20 | - script: bootstrap.cmd
21 | displayName: Build the tools
22 | - ${{ if ne(parameters.agentOs, 'Windows_NT') }}:
23 | - script: ./bootstrap.sh
24 | displayName: Build the tools
25 |
--------------------------------------------------------------------------------
/eng/download-checkout-llvm.yml:
--------------------------------------------------------------------------------
1 | steps:
2 | - download: current
3 | artifact: $(LLVMSourceBundle)
4 | displayName: Download LLVM bundle
5 |
6 | - script: git clone $(Pipeline.Workspace)\$(LLVMSourceBundle)\$(LLVMSourceBundle) $(Build.SourcesDirectory)\src\llvm-project
7 | displayName: Checkout LLVM from bundle (Windows)
8 | condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
9 |
10 | - script: git clone $(Pipeline.Workspace)/$(LLVMSourceBundle)/$(LLVMSourceBundle) $(Build.SourcesDirectory)/src/llvm-project
11 | displayName: Checkout LLVM from bundle (Linux or macOS)
12 | condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
13 |
--------------------------------------------------------------------------------
/pack-coredistools.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal EnableDelayedExpansion EnableExtensions
3 |
4 | set RootDirectory=%~dp0
5 | set SourcesDirectory=%RootDirectory%src
6 | set PackagesDirectory=%RootDirectory%artifacts\pkg
7 |
8 | set BinariesDirectory=%~f1
9 |
10 | if "%BinariesDirectory%"=="" (
11 | echo ERROR: Binaries directory is not specified
12 | exit /b 1
13 | ) else if not exist "%BinariesDirectory%" (
14 | echo ERROR: Binaries directory does not exist: %BinariesDirectory%
15 | exit /b 1
16 | )
17 |
18 | where /q nuget.exe
19 |
20 | if %ERRORLEVEL% neq 0 (
21 | echo ERROR: nuget.exe is not found in the PATH
22 | exit /b 1
23 | )
24 |
25 | nuget.exe pack ^
26 | "%SourcesDirectory%\coredistools\.nuget\Microsoft.NETCore.CoreDisTools.nuspec" ^
27 | -OutputDirectory "%PackagesDirectory%" ^
28 | -BasePath %RootDirectory% ^
29 | -Properties BinariesDirectory="%BinariesDirectory%" ^
30 | -NonInteractive
31 |
32 | if %ERRORLEVEL% neq 0 (
33 | echo ERROR: nuget pack exited with code %ERRORLEVEL%
34 | exit /b 1
35 | )
36 |
37 | exit /b 0
38 |
--------------------------------------------------------------------------------
/sample_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "asmdiff" : {
3 | "default": {
4 | "base": "e:\\gh\\runtime2\\artifacts\\bin\\coreclr\\windows.x64.checked",
5 | "diff": "c:\\gh\\runtime\\artifacts\\bin\\coreclr\\windows.x64.checked",
6 | "frameworks": "true",
7 | "output": "c:\\diffs",
8 | "core_root": "c:\\gh\\runtime\\artifacts\\tests\\coreclr\\windows.x64.checked\\Tests\\Core_Root",
9 | "test_root": "c:\\gh\\runtime\\artifacts\\tests\\coreclr\\windows.x64.Release"
10 | },
11 | "tools": [
12 | {
13 | "tag": "checked_osx-1439",
14 | "path": "/Users/russellhadley/Work/glue/output/tools/checked_osx-1439/Product/OSX.x64.Checked"
15 | },
16 | {
17 | "tag": "checked_osx-1442",
18 | "path": "/Users/russellhadley/Work/glue/output/tools/checked_osx-1442/Product/OSX.x64.Checked"
19 | },
20 | {
21 | "tag": "checked_osx-1443",
22 | "path": "/Users/russellhadley/Work/glue/output/tools/checked_osx-1443/Product/OSX.x64.Checked"
23 | },
24 | {
25 | "tag": "checked_osx-1526",
26 | "path": "/Users/russellhadley/Work/glue/output/tools/checked_osx-1526/Product/OSX.x64.Checked"
27 | }
28 | ]
29 | },
30 | "format" : {
31 | "default": {
32 | "arch": "x64",
33 | "build": "Checked",
34 | "os": "windows",
35 | "coreclr": "C:\\gh\\runtime",
36 | "verbose": "true",
37 | "fix": "true",
38 | "untidy": "false"
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/AnalyzeAsm/AnalyzeAsm.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/AnalyzeAsm/README.md:
--------------------------------------------------------------------------------
1 | Notes:
2 |
3 | * The code in `Program.cs` has **lot of redundant code**. Most of the methods are copied from previous methods with little tweak.
4 | * All the methods rely on `ngen_arm64.txt` / `ngen_amd64.txt` file that are produced by doing the following:
5 | * `set DOTNET_NGenDisasm=1`
6 | * Running `build-test.cmd crossgen > ngen_arm64.txt`
7 | * The path locations of these files are hardcoded too.
8 |
9 |
10 | `FindLdrGroups_1()` finds patterns:
11 |
12 | ```asm
13 | ldr x1, [x0]
14 | ldr x2, [x0, #8]
15 | ; becomes
16 | ldp x1, x2 [x0]
17 | ```
18 |
19 | `FindLdrGroups_2()` finds patterns:
20 | ```asm
21 | ldr x1, [fp]
22 | ldr x2, [fp, #8]
23 | ; becomes
24 | ldp x1, x2 [fp]
25 | ```
26 |
27 | `FindStrGroups_1()` finds patterns:
28 | ```asm
29 | str x1, [x0]
30 | str x2, [x0, #8]
31 | ; becomes
32 | stp x1, x2, [x0]
33 | ```
34 |
35 | `FindStrGroups_2()` finds patterns:
36 | ```asm
37 | str x1, [fp]
38 | str x2, [fp, #8]
39 | ; becomes
40 | stp x1, x2, [fp]
41 | ```
42 |
43 | `FindStrGroups_wzr()` finds patterns:
44 | ```asm
45 | str wzr, [x1]
46 | str wzr, [x1, #8]
47 | ; becomes
48 | str xzr, [x1]
49 | ```
50 |
51 | `FindLdrLdrToMovGroups()` finds patterns:
52 | ```asm
53 | add x0, x0, x1
54 | ldr x1, [x0]
55 | ; becomes
56 | ldr x1, [x0, x1]
57 | ```
58 |
59 | `FindPostIndexAddrMode1()` finds patterns:
60 | ```asm
61 | ldr x0, [x2]
62 | add x2, x2, #4
63 | ; becomes
64 | ldr x0, [x2], #4
65 | ```
66 |
67 | `FindPreIndexAddrMode1()` finds patterns:
68 | ```asm
69 | ldr x0, [x2, #4]
70 | add x2, x2, #4
71 | ;becomes
72 | ldr x0, [x2, #4]!
73 | ```
74 |
75 | `FindPreIndexAddrMode2()` finds patterns:
76 | ```asm
77 | add x2, x2, #4
78 | ldr x0, [x2, #4]
79 | ;becomes
80 | ldr x0, [x2, #4]!
81 | ```
82 |
83 | `RedundantMovs1()` finds patterns:
84 | ```asm
85 | mov x0, x0
86 | ```
87 |
88 | `RedundantMovs2()` finds patterns:
89 | ```asm
90 | mov x0, x20
91 | mov x20, x0
92 | ```
93 |
94 | `RedundantMovs3()` finds patterns:
95 | ```asm
96 | ldr w0, [x0] ; <-- this should zero extend the register so next mov is not needed.
97 | mov w0, w0
98 | ```
99 |
100 | `AdrpAddPairs()` finds patterns:
101 | ```asm
102 | adrp x11, [RELOC #0x1f40fb92b00]
103 | add x11, x11, #0
104 | adrp x0, [RELOC #0x1f40fb92b00]
105 | add x0, x0, #0
106 | ldr x0, [x0]
107 | ```
108 |
109 | `ArrayAccess()` finds patterns:
110 | ```asm
111 | sxtw x4, x4
112 | lsl x4, x4, #3
113 | add x4, x4, #16
114 | ```
115 |
116 | `PrologEpilogInx64()` finds methods that don't have prolog/epilog in x64
117 |
118 | `BasePlusRegisterOffset()` finds patterns:
119 | ```asm
120 | ldr w11, [x11, x1, LSL #2]
121 | ```
122 |
123 | `FindMovZMovKGroups()` finds groups of `movz/movk` instructions.
124 |
125 | `OptimizeDmbs` finds patterns to remove unnecessary `dmb` instructions. Motivation from clang's [ARMOptimizeBarriersPass](https://github.com/llvm/llvm-project/blob/2946cd701067404b99c39fb29dc9c74bd7193eb3/llvm/lib/Target/ARM/ARMOptimizeBarriersPass.cpp).
--------------------------------------------------------------------------------
/src/cijobs/CIClient.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Net.Http;
10 | using System.Net.Http.Headers;
11 | using System.Text.Json;
12 | using System.Threading;
13 | using System.Threading.Tasks;
14 |
15 | namespace ManagedCodeGen
16 | {
17 | // Wrap CI httpClient with focused APIs for product, job, and build.
18 | // This logic is seperate from listing/copying and just extracts data.
19 | internal sealed class CIClient
20 | {
21 | private HttpClient _client;
22 |
23 | public CIClient(string server)
24 | {
25 | _client = new HttpClient();
26 | _client.BaseAddress = new Uri(server);
27 | _client.DefaultRequestHeaders.Accept.Clear();
28 | _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
29 | _client.Timeout = Timeout.InfiniteTimeSpan;
30 | }
31 |
32 | public async Task DownloadProduct(string messageString, string outputPath, string contentPath)
33 | {
34 | Console.WriteLine("Downloading: {0}", messageString);
35 |
36 | HttpResponseMessage response = await _client.GetAsync(messageString);
37 |
38 | bool downloaded = false;
39 |
40 | if (response.IsSuccessStatusCode)
41 | {
42 | var zipPath = Path.Combine(outputPath, Path.GetFileName(contentPath));
43 | using (var outputStream = System.IO.File.Create(zipPath))
44 | {
45 | Stream inputStream = await response.Content.ReadAsStreamAsync();
46 | inputStream.CopyTo(outputStream);
47 | }
48 | downloaded = true;
49 | }
50 | else
51 | {
52 | Console.Error.WriteLine("Zip not found!");
53 | }
54 |
55 | return downloaded;
56 | }
57 |
58 | public async Task> GetProductJobs(string productName, string branchName)
59 | {
60 | string productString = $"job/{productName}/job/{branchName}/api/json?&tree=jobs[name,url]";
61 |
62 | try
63 | {
64 | using HttpResponseMessage response = await _client.GetAsync(productString);
65 |
66 | if (response.IsSuccessStatusCode)
67 | {
68 | var json = await response.Content.ReadAsStringAsync();
69 | var productJobs = JsonSerializer.Deserialize(json);
70 | return productJobs.jobs;
71 | }
72 | }
73 | catch (Exception ex)
74 | {
75 | Console.Error.WriteLine("Error enumerating jobs: {0} {1}", ex.Message, ex.InnerException.Message);
76 | }
77 |
78 | return Enumerable.Empty();
79 | }
80 |
81 | public async Task> GetJobBuilds(string productName, string branchName,
82 | string jobName, bool lastSuccessfulBuild, int number, string commit)
83 | {
84 | var jobString
85 | = String.Format(@"job/{0}/job/{1}/job/{2}", productName, branchName, jobName);
86 | var messageString
87 | = String.Format("{0}/api/json?&tree=builds[number,url],lastSuccessfulBuild[number,url]",
88 | jobString);
89 | HttpResponseMessage response = await _client.GetAsync(messageString);
90 |
91 | if (response.IsSuccessStatusCode)
92 | {
93 | var json = await response.Content.ReadAsStringAsync();
94 | var jobBuilds = JsonSerializer.Deserialize(json);
95 |
96 | if (lastSuccessfulBuild)
97 | {
98 | var lastSuccessfulNumber = jobBuilds.lastSuccessfulBuild.number;
99 | jobBuilds.lastSuccessfulBuild.info = await GetJobBuildInfo(productName, branchName, jobName, lastSuccessfulNumber);
100 | return Enumerable.Repeat(jobBuilds.lastSuccessfulBuild, 1);
101 | }
102 | else if (number != 0)
103 | {
104 | var builds = jobBuilds.builds;
105 |
106 | var count = builds.Count();
107 | for (int i = 0; i < count; i++)
108 | {
109 | var build = builds[i];
110 | if (build.number == number)
111 | {
112 | build.info = await GetJobBuildInfo(productName, branchName, jobName, build.number);
113 | return Enumerable.Repeat(build, 1);
114 | }
115 | }
116 | return Enumerable.Empty();
117 | }
118 | else if (commit != null)
119 | {
120 | var builds = jobBuilds.builds;
121 |
122 | var count = builds.Count();
123 | for (int i = 0; i < count; i++)
124 | {
125 | var build = builds[i];
126 | build.info = await GetJobBuildInfo(productName, branchName, jobName, build.number);
127 | var actions = build.info.actions.Where(x => x.lastBuiltRevision.SHA1 != null);
128 | foreach (var action in actions)
129 | {
130 | if (action.lastBuiltRevision.SHA1.Equals(commit, StringComparison.OrdinalIgnoreCase))
131 | {
132 | return Enumerable.Repeat(build, 1);
133 | }
134 | }
135 | }
136 | return Enumerable.Empty();
137 | }
138 | else
139 | {
140 | var builds = jobBuilds.builds;
141 |
142 | var count = builds.Count();
143 | for (int i = 0; i < count; i++)
144 | {
145 | var build = builds[i];
146 | // fill in build info
147 | build.info = await GetJobBuildInfo(productName, branchName, jobName, build.number);
148 | builds[i] = build;
149 | }
150 |
151 | return jobBuilds.builds;
152 | }
153 | }
154 | else
155 | {
156 | return Enumerable.Empty();
157 | }
158 | }
159 |
160 | public async Task GetJobBuildInfo(string repoName, string branchName, string jobName, int number)
161 | {
162 | string buildString = String.Format("job/{0}/job/{1}/job/{2}/{3}",
163 | repoName, branchName, jobName, number);
164 | string buildMessage = String.Format("{0}/{1}", buildString,
165 | "api/json?&tree=actions[lastBuiltRevision[SHA1]],artifacts[fileName,relativePath],result");
166 | HttpResponseMessage response = await _client.GetAsync(buildMessage);
167 |
168 | if (response.IsSuccessStatusCode)
169 | {
170 | var buildInfoJson = await response.Content.ReadAsStringAsync();
171 | var info = JsonSerializer.Deserialize(buildInfoJson);
172 | return info;
173 | }
174 | else
175 | {
176 | return null;
177 | }
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/cijobs/Models.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Collections.Generic;
6 |
7 | namespace ManagedCodeGen
8 | {
9 | internal class Artifact
10 | {
11 | public string fileName { get; set; }
12 | public string relativePath { get; set; }
13 | }
14 |
15 | internal class Revision
16 | {
17 | public string SHA1 { get; set; }
18 | }
19 |
20 | internal class Action
21 | {
22 | public Revision lastBuiltRevision { get; set; }
23 | }
24 |
25 | internal class BuildInfo
26 | {
27 | public List actions { get; set; }
28 | public List artifacts { get; set; }
29 | public string result { get; set; }
30 | }
31 |
32 | internal class Job
33 | {
34 | public string name { get; set; }
35 | public string url { get; set; }
36 | }
37 |
38 | internal class ProductJobs
39 | {
40 | public List jobs { get; set; }
41 | }
42 |
43 | internal class Build
44 | {
45 | public int number { get; set; }
46 | public string url { get; set; }
47 | public BuildInfo info { get; set; }
48 | }
49 |
50 | internal class JobBuilds
51 | {
52 | public List builds { get; set; }
53 | public Build lastSuccessfulBuild { get; set; }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/cijobs/README.md:
--------------------------------------------------------------------------------
1 | # cijobs - List or copy job info/artifacts from the CI to a local machine
2 |
3 | Continuous integration build jobs tool enables the listing of
4 | jobs built in the CI system as well as downloading their artifacts. This
5 | functionality allows for the speed up of some common dev tasks but taking
6 | advantage of work being done in the cloud.
7 |
8 | ###Scenario 1: Start new work.
9 | When beginning a new set of changes, listing
10 | job status can help you find a commit to start your work from. The tool
11 | answers questions like "are the CentOS build jobs passing?" and "what was
12 | the commit hash for the last successful tizen arm32 build?"
13 |
14 | ###Scenario 2: Copy artifacts to speed up development flow. The tool enables
15 | developers to download builds from the cloud so that developers can avoid
16 | rebuilding baseline tools on a local machine. Need the crossgen tool for
17 | the baseline commit for OSX diffs? Cijobs makes this easy to copy to your
18 | system.
19 |
20 | To build/setup:
21 |
22 | * Download dotnet cli. Follow install instructions and get dotnet on your
23 | your path.
24 | * Do 'dotnet restore' to create lock file and
25 | pull down required packages.
26 | * Issue a 'dotnet build' command. Build artifacts will be generated under
27 | a local 'bin' dir.
28 | * cijobs is included in the `build.{cmd|sh}` in the root. Building the whole
29 | repo will install the tool in addition to the other diff utilities in a
30 | bin directory.
31 |
--------------------------------------------------------------------------------
/src/cijobs/cijobs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/coreclr_config_download/README.md:
--------------------------------------------------------------------------------
1 | **CoreClr Config Download**
2 |
3 | Download all of the config.xml files for each coreclr job. This will will download into two different folders /base and .
4 |
5 | You can then diff the two folders with whatever your favorite diff tool is. An example on unix would be:
6 |
7 | >$diff -rq /base /diff
8 |
9 | **Requirements**
10 |
11 | In order to grab the config.xml files you will need to authenticate with jenkins and Github. This requires an OAuth token.
12 |
13 | Note that you are able to do this both from the command line (see [these](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/) instructions) and using the web api [here](https://github.com/settings/tokens).
14 |
15 | The minimum access you need is the user information.
16 |
17 | **Usage**
18 |
19 | Please use -h to see the full help.
20 |
21 | ```
22 | usage: coreclr_config_download.py [-h] [-api_token [API_TOKEN]]
23 | [-branch [BRANCH]]
24 | [-output_location [OUTPUT_LOCATION]]
25 | [-sim_connections [SIM_CONNECTIONS]]
26 | [-username [USERNAME]] [--baseline_only]
27 | [--diff_only]
28 |
29 | Simple script to grab all of the config.xml files for jobs. Note that the
30 | api_token can either be the token or the path to a file containing the token.
31 | If you are having a problem with connecting try passing the, download basline
32 | only then download the diff only after waiting a little. Github will
33 | unforuntately rate limit OAuth connections.
34 |
35 | optional arguments:
36 | -h, --help show this help message and exit
37 | -api_token [API_TOKEN]
38 | Github API Token. Can be the path to a file or string.
39 | -branch [BRANCH]
40 | -output_location [OUTPUT_LOCATION]
41 | -sim_connections [SIM_CONNECTIONS]
42 | The amount of parrallel conntections to launch.
43 | -username [USERNAME] Github username for the API Token.
44 | --baseline_only Download the baseline config files only.
45 | --diff_only Download the diff config files only.
46 | ```
47 |
48 | **Example usage**
49 |
50 | >$./coreclr_config_download.py -branch master -output_location ~/output -username jashook -api_token ~/jenkins_api_token
51 |
52 | >$./coreclr_config_download.py -branch master -output_location ~/output -username jashook -api_token ~/jenkins_api_token --baseline_only
53 |
54 | >$./coreclr_config_download.py -branch master -output_location ~/output -username jashook -api_token ~/jenkins_api_token --diff_only
55 |
56 | **Caveats**
57 |
58 | Each GET Request to download the config.xml must authenticate. Therefore, after around 2k GET Requests Github will start rate limiting the requests. From what it looks like it will require you to wait about an hour before being able to authenticate you from jenkins.
59 |
60 | To work around this annoying problem the script has a --baseline_only and --diff_only option. Which will allow you to download the --baseline_only, wait then download --diff_only.
--------------------------------------------------------------------------------
/src/coredistools/.nuget/Microsoft.NETCore.CoreDisTools.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft.NETCore.CoreDisTools
5 | 1.5.0
6 | Microsoft.NETCore Instruction-wise Disassembler
7 | Microsoft
8 | Microsoft
9 | LICENSE.TXT
10 | https://github.com/dotnet/jitutils
11 | true
12 | Disassembly Tools for dotnet/runtime
13 | Initial release
14 | Copyright © Microsoft Corporation
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/coredistools/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | project(coredistools)
2 |
3 | set(LLVM_LINK_COMPONENTS
4 | AllTargetsAsmParsers
5 | AllTargetsDescs
6 | AllTargetsDisassemblers
7 | AllTargetsInfos
8 | MC
9 | Support)
10 |
11 | set(SOURCES coredistools.cpp)
12 |
13 | set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/coredistools.exports)
14 |
15 | include_directories(${CMAKE_CURRENT_SOURCE_DIR})
16 |
17 | add_llvm_library(coredistools SHARED ${SOURCES} DEPENDS intrinsics_gen)
18 |
19 | install(TARGETS coredistools LIBRARY DESTINATION bin COMPONENT coredistools
20 | ARCHIVE DESTINATION lib COMPONENT coredistools)
21 |
--------------------------------------------------------------------------------
/src/coredistools/coredistools.exports:
--------------------------------------------------------------------------------
1 | InitDisasm
2 | InitBufferedDisasm
3 | NewDisasm
4 | FinishDisasm
5 | InitBufferedDiffer
6 | NewDiffer
7 | NewDiffer2
8 | FinishDiff
9 | DisasmInstruction
10 | DumpInstruction
11 | NearDiffCodeBlocks
12 | DumpCodeBlock
13 | DumpDiffBlocks
14 | GetOutputBuffer
15 | ClearOutputBuffer
16 |
--------------------------------------------------------------------------------
/src/coredistools/coredistools.h:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 |
4 | //===--------- coredistools.h - Disassembly tools for CoreClr ------------===
5 | // Core Disassembly Tools API
6 | // Disassembly tools required by CoreCLR for utilities like
7 | // GCStress, SuperPMI, and R2RDump.
8 | //===---------------------------------------------------------------------===
9 |
10 | #if !defined(_COREDISTOOLS_H_)
11 | #define _COREDISTOOLS_H_
12 |
13 | #include
14 |
15 | #if defined(__cplusplus)
16 | #define EXTERN_C extern "C"
17 | #else
18 | #define EXTERN_C
19 | #endif // defined(__cplusplus)
20 |
21 | #if defined(_MSC_VER)
22 | #if defined(DllInterfaceExporter)
23 | #define DllIface EXTERN_C __declspec(dllexport)
24 | #else
25 | #define DllIface EXTERN_C __declspec(dllimport)
26 | #endif // defined(DllInterfaceExporter)
27 | #else
28 | #if !defined(__cdecl)
29 | #if defined(__i386__)
30 | #define __cdecl __attribute__((cdecl))
31 | #else
32 | #define __cdecl
33 | #endif
34 | #endif
35 | #define DllIface EXTERN_C
36 | #endif // defined(_MSC_VER)
37 |
38 | enum TargetArch {
39 | Target_Host, // Target is the same as host architecture
40 | Target_X86,
41 | Target_X64,
42 | Target_Thumb,
43 | Target_Arm64,
44 | Target_LoongArch64,
45 | Target_RiscV64,
46 | };
47 |
48 | struct CorDisasm;
49 | struct CorAsmDiff;
50 |
51 | // The custom print functionality to be provide by the
52 | // users of this Library
53 | typedef void(__cdecl *Printer)(const char *msg, ...);
54 | struct PrintControl {
55 | const Printer Error;
56 | const Printer Warning;
57 | const Printer Log;
58 | const Printer Dump;
59 | };
60 |
61 | // The type of a custom function provided by the user to determine
62 | // if two offsets are considered equivalent wrt diffing code blocks.
63 | // Offset1 and Offset2 are the two offsets to be compared.
64 | // BlockOffset is the offset of the instructions (that contain Offset1
65 | // and Offset2) from the beginning of their respective code blocks.
66 | // InstructionLength is the length of the current instruction being
67 | // compared for equivalency.
68 | typedef bool(__cdecl *OffsetComparator)(const void *UserData, size_t BlockOffset,
69 | size_t InstructionLength, uint64_t Offset1,
70 | uint64_t Offset2);
71 |
72 | // If an OffsetMunger function is defined, it is called before the OffsetComparator.
73 | // If it returns `true` then:
74 | // 1. the instructions are considered equivalent
75 | // 2. the offsets have been decoded and "munged" (changed), and
76 | // *Offset1 and *Offset2 are set to the values to use.
77 | // 3. *SkipInstructions1 instructions in code stream 1 are skipped
78 | // 4. *SkipInstructions2 instructions in code stream 2 are skipped
79 | //
80 | // This is typically used on arm32 to treat "movw/movt" as a single instruction
81 | // generating a single constant. Similarly, for arm64 mov/movk/movk/movk sequences.
82 | typedef bool(__cdecl *OffsetMunger)(const void *UserData, size_t BlockOffset,
83 | size_t InstructionLength, uint64_t* Offset1, uint64_t* Offset2,
84 | uint32_t* SkipInstructions1, uint32_t* SkipInstructions2);
85 |
86 | // The Export/Import definitions for CoreDistools library are defined below.
87 | // A typedef for each interface function's type is defined in order to aid
88 | // the importer.
89 |
90 | // Initialize the disassembler, using default print controls
91 | typedef CorDisasm * __cdecl InitDisasm_t(enum TargetArch Target);
92 | DllIface InitDisasm_t InitDisasm;
93 |
94 | // Initialize the disassembler, using buffered print controls
95 | typedef CorDisasm * __cdecl InitBufferedDisasm_t(enum TargetArch Target);
96 | DllIface InitBufferedDisasm_t InitBufferedDisasm;
97 |
98 | // Initialize the disassembler using custom print controls
99 | typedef CorDisasm * __cdecl NewDisasm_t(enum TargetArch Target,
100 | const PrintControl *PControl);
101 | DllIface NewDisasm_t NewDisasm;
102 |
103 | // Delete the disassembler
104 | typedef void __cdecl FinishDisasm_t(const CorDisasm *Disasm);
105 | DllIface FinishDisasm_t FinishDisasm;
106 |
107 | // Initialize a code differ using buffered output.
108 | typedef CorDisasm * __cdecl InitBufferedDiffer_t(enum TargetArch Target,
109 | const OffsetComparator Comparator);
110 | DllIface InitBufferedDiffer_t InitBufferedDiffer;
111 |
112 | // Initialize the Code Differ
113 | typedef CorAsmDiff * __cdecl NewDiffer_t(enum TargetArch Target,
114 | const PrintControl *PControl,
115 | const OffsetComparator Comparator);
116 | DllIface NewDiffer_t NewDiffer;
117 |
118 | // Initialize the Code Differ, with an offset munger.
119 | typedef CorAsmDiff * __cdecl NewDiffer2_t(enum TargetArch Target,
120 | const PrintControl *PControl,
121 | const OffsetComparator Comparator,
122 | const OffsetMunger Munger);
123 | DllIface NewDiffer2_t NewDiffer2;
124 |
125 | // Delete the Code Differ
126 | typedef void __cdecl FinishDiff_t(const CorAsmDiff *AsmDiff);
127 | DllIface FinishDiff_t FinishDiff;
128 |
129 | // DisasmInstruction -- Disassemble one instruction
130 | // Arguments:
131 | // Disasm -- The Disassembler
132 | // Address -- The address at which the bytes of the instruction
133 | // are intended to execute
134 | // Bytes -- Pointer to the actual bytes which need to be disassembled
135 | // MaxLength -- Number of bytes available in Bytes buffer
136 | // Returns:
137 | // -- The Size of the disassembled instruction
138 | // -- Zero on failure
139 | typedef size_t __cdecl DisasmInstruction_t(const CorDisasm *Disasm,
140 | const uint8_t *Address,
141 | const uint8_t *Bytes, size_t Maxlength);
142 | DllIface DisasmInstruction_t DisasmInstruction;
143 |
144 | // DumpInstruction -- Disassemble one instruction and output it
145 | // Arguments:
146 | // Disasm -- The Disassembler
147 | // Address -- The address at which the bytes of the instruction
148 | // are intended to execute
149 | // Bytes -- Pointer to the actual bytes which need to be disassembled
150 | // MaxLength -- Number of bytes available in Bytes buffer
151 | // Returns:
152 | // -- The Size of the disassembled instruction
153 | // -- Zero on failure
154 | typedef size_t __cdecl DumpInstruction_t(const CorDisasm *Disasm,
155 | const uint8_t *Address, const uint8_t *Bytes,
156 | size_t Maxlength);
157 | DllIface DumpInstruction_t DumpInstruction;
158 |
159 | // NearDiffCodeBlocks -- Compare two code blocks for semantic
160 | // equivalence
161 | // Arguments:
162 | // AsmDiff -- The Asm-differ
163 | // UserData -- Any data the user wishes to pass through into
164 | // the OffsetComparator/OffsetMunger
165 | // Address1 -- Address at which first block will execute
166 | // Bytes1 -- Pointer to the actual bytes of the first block
167 | // Size1 -- The size of the first block
168 | // Address2 -- Address at which second block will execute
169 | // Bytes2 -- Pointer to the actual bytes of the second block
170 | // Size2 -- The size of the second block
171 | // Returns:
172 | // -- true if the two blocks are equivalent, false if not.
173 | typedef bool __cdecl NearDiffCodeBlocks_t(const CorAsmDiff *AsmDiff,
174 | const void *UserData,
175 | const uint8_t *Address1,
176 | const uint8_t *Bytes1, size_t Size1,
177 | const uint8_t *Address2,
178 | const uint8_t *Bytes2, size_t Size2);
179 | DllIface NearDiffCodeBlocks_t NearDiffCodeBlocks;
180 |
181 | // Print a code block according to the Disassembler's Print Controls
182 | typedef void __cdecl DumpCodeBlock_t(const CorDisasm *Disasm, const uint8_t *Address,
183 | const uint8_t *Bytes, size_t Size);
184 | DllIface DumpCodeBlock_t DumpCodeBlock;
185 |
186 | // Print the two code blocks being diffed, according to
187 | // AsmDiff's PrintControls.
188 | typedef void __cdecl DumpDiffBlocks_t(const CorAsmDiff *AsmDiff,
189 | const uint8_t *Address1, const uint8_t *Bytes1,
190 | size_t Size1, const uint8_t *Address2,
191 | const uint8_t *Bytes2, size_t Size2);
192 | DllIface DumpDiffBlocks_t DumpDiffBlocks;
193 |
194 | // Get a pointer to the buffered output buffer.
195 | typedef const char* __cdecl GetOutputBuffer_t();
196 | DllIface GetOutputBuffer_t GetOutputBuffer;
197 |
198 | // Clear the buffered output buffer.
199 | typedef void __cdecl ClearOutputBuffer_t();
200 | DllIface ClearOutputBuffer_t ClearOutputBuffer;
201 |
202 | #endif // !defined(_COREDISTOOLS_H_)
203 |
--------------------------------------------------------------------------------
/src/instructions-retired-explorer/README.md:
--------------------------------------------------------------------------------
1 | ### Instructions Retired Explorer
2 |
3 | Instructions Retired Explorer is a tool to parse ETW files like those produced by BenchmarkDotNet (aka BDN) (via `-p ETW`) or PerfView.
4 |
5 | It understands profile, jit, and method events, and can attribute profile or PMU
6 | samples to jitted code.
7 |
8 | It also understands BDN's profiling events, and can filter profiles to just those taken when BDN is actively measuring performance (that is, it will ignore the various warmup and overhead phases, as well as time spent within BDN itself).
9 |
10 | ### Usage
11 |
12 | ```
13 | dotnet run -- file.etl [-process process-name] [-pid pid] [-show-events] [-show-jit-times] [-benchmark] [-instructions-retired]
14 |
15 | -process: defaults to corerun
16 | -pid: choose process to summarize via ID
17 | -benchmark: only count samples made during BechmarkDotNet intervals. Changes default process to dotnet
18 | -show-events: show counts of raw ETL events
19 | -show-jit-times: summarize data on time spent jitting
20 | -show-samples : show raw method-relative hits for some methods
21 | -instructions-retired: if ETL has instructions retired events, summarize those instead of profile samples
22 | ```
23 |
24 | ### Sample Output
25 |
26 | This shows some output from analyzing a BDN produced file, with `-benchmark`:
27 |
28 | ```
29 | Samples for corerun: 6830 events for Benchmark Intervals
30 | Jitting : 01.66% 6.4E+05 samples 1507 methods
31 | JitInterface : 00.78% 3E+05 samples
32 | Jit-generated code: 83.95% 3.23E+07 samples
33 | Jitted code : 83.95% 3.23E+07 samples
34 | MinOpts code : 00.00% 0 samples
35 | FullOpts code : 00.81% 3.1E+05 samples
36 | Tier-0 code : 00.00% 0 samples
37 | Tier-1 code : 83.14% 3.2E+07 samples
38 | R2R code : 00.00% 0 samples
39 |
40 | 02.13% 8.2E+05 ? Unknown
41 | 42.38% 1.629E+07 Tier-1 [System.Private.CoreLib]DateTimeFormat.FormatCustomized(value class System.DateTime,value class System.ReadOnlySpan`1,class System.Globalization.DateTimeFormatInfo,value class System.TimeSpan,value class System.Collections.Generic.ValueListBuilder`1&)
42 | 19.30% 7.42E+06 Tier-1 [System.Private.CoreLib]DateTimeFormat.FormatDigits(value class System.Collections.Generic.ValueListBuilder`1&,int32,int32)
43 | 11.81% 4.54E+06 native coreclr.dll
44 | 09.26% 3.56E+06 Tier-1 [System.Private.CoreLib]DateTimeFormat.Format(value class System.DateTime,class System.String,class System.IFormatProvider,value class System.TimeSpan)
45 | 04.37% 1.68E+06 Tier-1 [System.Private.CoreLib]System.Collections.Generic.ValueListBuilder`1[System.Char].AppendMultiChar(value class System.ReadOnlySpan`1)
46 | 03.23% 1.24E+06 Tier-1 [System.Private.CoreLib]Buffer.Memmove(unsigned int8&,unsigned int8&,unsigned int)
47 | 01.61% 6.2E+05 Tier-1 [System.Private.CoreLib]System.ReadOnlySpan`1[System.Char].ToString()
48 | 01.27% 4.9E+05 Tier-1 [System.Private.CoreLib]String.Ctor(value class System.ReadOnlySpan`1)
49 | 01.17% 4.5E+05 Tier-1 [System.Private.CoreLib]DateTimeFormat.ExpandStandardFormatToCustomPattern(wchar,class System.Globalization.DateTimeFormatInfo)
50 | 00.88% 3.4E+05 native clrjit.dll
51 | 00.81% 3.1E+05 FullOpt [d0c2a6e2-c859-4adf-aa32-e1950c899716]Runnable_0.WorkloadActionUnroll(int64)
52 | 00.62% 2.4E+05 native ntoskrnl.exe
53 | 00.55% 2.1E+05 Tier-1 [MicroBenchmarks]Perf_DateTime.ToString(class System.String)
54 | 00.39% 1.5E+05 native ntdll.dll
55 | 00.13% 5E+04 native intelppm.sys
56 | 00.05% 2E+04 native KernelBase.dll
57 |
58 | Benchmark: found 15 intervals; mean interval 252.122ms
59 | 000 3243.972 -- 3506.304 : 262.332
60 | 001 3508.081 -- 3766.636 : 258.554
61 | 002 3768.304 -- 4027.688 : 259.384
62 | 003 4029.104 -- 4275.982 : 246.878
63 | 004 4277.706 -- 4529.997 : 252.291
64 | 005 4531.510 -- 4781.650 : 250.140
65 | 006 4783.191 -- 5032.090 : 248.899
66 | 007 5033.857 -- 5283.478 : 249.621
67 | 008 5285.356 -- 5538.937 : 253.581
68 | 009 5540.676 -- 5791.375 : 250.699
69 | 010 5792.768 -- 6044.684 : 251.916
70 | 011 6046.395 -- 6295.090 : 248.694
71 | 012 6296.746 -- 6547.423 : 250.677
72 | 013 6549.081 -- 6796.750 : 247.669
73 | 014 6798.383 -- 7048.879 : 250.496
74 | ```
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/instructions-retired-explorer/instructions-retired-explorer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/jit-analyze/IEnumerableExtensions.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 |
9 | namespace ManagedCodeGen
10 | {
11 | // Allow Linq to be able to sum up MetricCollections
12 | public static class IEnumerableExtensions
13 | {
14 | public static MetricCollection Sum(this IEnumerable source)
15 | {
16 | MetricCollection result = new MetricCollection();
17 |
18 | foreach (MetricCollection s in source)
19 | {
20 | result.Add(s);
21 | }
22 |
23 | return result;
24 | }
25 |
26 | public static MetricCollection Sum(this IEnumerable source, Func selector)
27 | {
28 | return source.Select(x => selector(x)).Sum();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/jit-analyze/JitAnalyzeRootCommand.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.CommandLine;
8 | using System.Globalization;
9 |
10 | namespace ManagedCodeGen
11 | {
12 | internal sealed class JitAnalyzeRootCommand : RootCommand
13 | {
14 | public Option BasePath { get; } =
15 | new("--base", "-b") { Description = "Base file or directory" };
16 | public Option DiffPath { get; } =
17 | new("--diff", "-d") { Description = "Diff file or directory" };
18 | public Option Recursive { get; } =
19 | new("--recursive", "-r") { Description = "Search directories recursively" };
20 | public Option FileExtension { get; } =
21 | new("--file-extension") { DefaultValueFactory = _ => ".dasm", Description = "File extension to look for" };
22 | public Option Count { get; } =
23 | new("--count", "-c") { DefaultValueFactory = _ => 20, Description = "Count of files and methods (at most) to output in the summary. (count) improvements and (count) regressions of each will be included" };
24 | public Option Warn { get; } =
25 | new("--warn", "-w") { Description = "Generate warning output for files/methods that only exists in one dataset or the other (only in base or only in diff)" };
26 | public Option> Metrics { get; } =
27 | new("--metrics", "-m") { DefaultValueFactory = _ => new List { "CodeSize" }, Description = $"Metrics to use for diff computations. Available metrics: {MetricCollection.ListMetrics()}" };
28 | public Option Note { get; } =
29 | new("--note") { Description = "Descriptive note to add to summary output" };
30 | public Option NoReconcile { get; } =
31 | new("--no-reconcile") { Description = "Do not reconcile unique methods in base/diff" };
32 | public Option Json { get; } =
33 | new("--json") { Description = "Dump analysis data to specified file in JSON format" };
34 | public Option Tsv { get; } =
35 | new("--tsv") { Description = "Dump analysis data to specified file in tab-separated format" };
36 | public Option MD { get; } =
37 | new("--md") { Description = "Dump analysis data to specified file in markdown format" };
38 | public Option Filter { get; } =
39 | new("--filter") { Description = "Only consider assembly files whose names match the filter" };
40 | public Option SkipTextDiff { get; } =
41 | new("--skip-text-diff") { Description = "Skip analysis that checks for files that have textual diffs but no metric diffs" };
42 | public Option RetainOnlyTopFiles { get; } =
43 | new("--retain-only-top-files") { Description = "Retain only the top 'count' improvements/regressions .dasm files. Delete other files. Useful in CI scenario to reduce the upload size" };
44 | public Option OverrideTotalBaseMetric { get; } =
45 | new("--override-total-base-metric") { CustomParser = result =>
46 | {
47 | string optionValue = result.Tokens[0].Value;
48 | if (double.TryParse(optionValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var parsedValue))
49 | return parsedValue;
50 |
51 | result.AddError($"Cannot parse argument '{optionValue}' for option '--override-total-base-metric' as expected type '{typeof(double).FullName}'.");
52 | return 0;
53 | }, Description = "Override the total base metric shown in the output with this value. Useful when only changed .dasm files are present and these values are known" };
54 | public Option OverrideTotalDiffMetric { get; } =
55 | new("--override-total-diff-metric") { CustomParser = result =>
56 | {
57 | string optionValue = result.Tokens[0].Value;
58 | if (double.TryParse(optionValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var parsedValue))
59 | return parsedValue;
60 |
61 | result.AddError($"Cannot parse argument '{optionValue}' for option '--override-total-diff-metric' as expected type '{typeof(double).FullName}'.");
62 | return 0;
63 | }, Description = "Override the total diff metric shown in the output with this value. Useful when only changed .dasm files are present and these values are known" };
64 | public Option IsDiffsOnly { get; } =
65 | new("--is-diffs-only") { Description = "Specify that the disassembly files are only produced for contexts with diffs, so avoid producing output making assumptions about the number of contexts" };
66 | public Option IsSubsetOfDiffs { get; } =
67 | new("--is-subset-of-diffs") { Description = "Specify that the disassembly files are only a subset of the contexts with diffs, so avoid producing output making assumptions about the remaining diffs" };
68 | public Option ConcatFiles { get; } =
69 | new("--concat-files") { Description = "Consider all files in the base and diff to be part of the same logical unit of functions" };
70 |
71 | public ParseResult Result;
72 |
73 | public JitAnalyzeRootCommand(string[] args) : base("Compare and analyze `*.dasm` files from baseline/diff")
74 | {
75 | Options.Add(BasePath);
76 | Options.Add(DiffPath);
77 | Options.Add(Recursive);
78 | Options.Add(FileExtension);
79 | Options.Add(Count);
80 | Options.Add(Warn);
81 | Options.Add(Metrics);
82 | Options.Add(Note);
83 | Options.Add(NoReconcile);
84 | Options.Add(Json);
85 | Options.Add(Tsv);
86 | Options.Add(MD);
87 | Options.Add(Filter);
88 | Options.Add(SkipTextDiff);
89 | Options.Add(RetainOnlyTopFiles);
90 | Options.Add(OverrideTotalBaseMetric);
91 | Options.Add(OverrideTotalDiffMetric);
92 | Options.Add(IsDiffsOnly);
93 | Options.Add(IsSubsetOfDiffs);
94 | Options.Add(ConcatFiles);
95 |
96 | SetAction(result =>
97 | {
98 | Result = result;
99 |
100 | try
101 | {
102 | List errors = new();
103 | if (Result.GetValue(BasePath) == null)
104 | {
105 | errors.Add("Base path (--base) is required");
106 | }
107 |
108 | if (Result.GetValue(DiffPath) == null)
109 | {
110 | errors.Add("Diff path (--diff) is required");
111 | }
112 |
113 | foreach (string metricName in Result.GetValue(Metrics))
114 | {
115 | if (!MetricCollection.ValidateMetric(metricName))
116 | {
117 | errors.Add($"Unknown metric '{metricName}'. Available metrics: {MetricCollection.ListMetrics()}");
118 | }
119 | }
120 |
121 | if ((Result.GetResult(OverrideTotalBaseMetric) == null) != (Result.GetResult(OverrideTotalDiffMetric) == null))
122 | {
123 | errors.Add("override-total-base-metric and override-total-diff-metric must either both be specified or both not be specified");
124 | }
125 |
126 | if (errors.Count > 0)
127 | {
128 | throw new Exception(string.Join(Environment.NewLine, errors));
129 | }
130 |
131 | return new Program(this).Run();
132 | }
133 | catch (Exception e)
134 | {
135 | Console.ResetColor();
136 | Console.ForegroundColor = ConsoleColor.Red;
137 |
138 | Console.Error.WriteLine("Error: " + e.Message);
139 | Console.Error.WriteLine(e.ToString());
140 |
141 | Console.ResetColor();
142 |
143 | return 1;
144 | }
145 | });
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/jit-analyze/MetricCollection.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Reflection;
8 | using System.Text;
9 | using System.Text.Json.Serialization;
10 |
11 | namespace ManagedCodeGen
12 | {
13 | public class MetricCollection
14 | {
15 | private static Dictionary s_metricNameToIndex;
16 | private static Metric[] s_metrics;
17 |
18 | static MetricCollection()
19 | {
20 | var derivedType = typeof(Metric);
21 | var currentAssembly = Assembly.GetAssembly(derivedType);
22 | s_metrics = currentAssembly.GetTypes()
23 | .Where(t => t != derivedType && derivedType.IsAssignableFrom(t))
24 | .Select(t => currentAssembly.CreateInstance(t.FullName)).Cast().ToArray();
25 |
26 | s_metricNameToIndex = new Dictionary(s_metrics.Length);
27 |
28 | for (int i = 0; i < s_metrics.Length; i++)
29 | {
30 | Metric m = s_metrics[i];
31 | s_metricNameToIndex[m.Name] = i;
32 | }
33 | }
34 |
35 | [JsonInclude]
36 | private Metric[] metrics;
37 |
38 | public MetricCollection()
39 | {
40 | metrics = new Metric[s_metrics.Length];
41 | for (int i = 0; i < s_metrics.Length; i++)
42 | {
43 | metrics[i] = s_metrics[i].Clone();
44 | }
45 | }
46 |
47 | public MetricCollection(MetricCollection other) : this()
48 | {
49 | this.SetValueFrom(other);
50 | }
51 |
52 | public static IEnumerable AllMetrics => s_metrics;
53 |
54 | public Metric GetMetric(string metricName)
55 | {
56 | int index;
57 | if (s_metricNameToIndex.TryGetValue(metricName, out index))
58 | {
59 | return metrics[index];
60 | }
61 | return null;
62 | }
63 |
64 | public static bool ValidateMetric(string name)
65 | {
66 | return s_metricNameToIndex.TryGetValue(name, out _);
67 | }
68 |
69 | public static string DisplayName(string metricName)
70 | {
71 | int index;
72 | if (s_metricNameToIndex.TryGetValue(metricName, out index))
73 | {
74 | return s_metrics[index].DisplayName;
75 | }
76 | return "Unknown metric";
77 | }
78 |
79 | public static string ListMetrics()
80 | {
81 | StringBuilder sb = new StringBuilder();
82 | bool isFirst = true;
83 | foreach (string s in s_metricNameToIndex.Keys)
84 | {
85 | if (!isFirst) sb.Append(", ");
86 | sb.Append(s);
87 | isFirst = false;
88 | }
89 | return sb.ToString();
90 | }
91 |
92 | public override string ToString()
93 | {
94 | StringBuilder sb = new StringBuilder();
95 | bool isFirst = true;
96 | foreach (Metric m in metrics)
97 | {
98 | if (!isFirst) sb.Append(", ");
99 | sb.Append($"{m.Name} {m.Unit} {m.ValueString}");
100 | isFirst = false;
101 | }
102 | return sb.ToString();
103 | }
104 |
105 | public void Add(MetricCollection other)
106 | {
107 | for (int i = 0; i < metrics.Length; i++)
108 | {
109 | metrics[i].Add(other.metrics[i]);
110 | }
111 | }
112 |
113 | public void Add(string metricName, double value)
114 | {
115 | Metric m = GetMetric(metricName);
116 | m.Value += value;
117 | }
118 |
119 | public void Sub(MetricCollection other)
120 | {
121 | for (int i = 0; i < metrics.Length; i++)
122 | {
123 | metrics[i].Sub(other.metrics[i]);
124 | }
125 | }
126 |
127 | public void Rel(MetricCollection other)
128 | {
129 | for (int i = 0; i < metrics.Length; i++)
130 | {
131 | metrics[i].Rel(other.metrics[i]);
132 | }
133 | }
134 |
135 | public void SetValueFrom(MetricCollection other)
136 | {
137 | for (int i = 0; i < metrics.Length; i++)
138 | {
139 | metrics[i].SetValueFrom(other.metrics[i]);
140 | }
141 | }
142 |
143 | public bool IsZero()
144 | {
145 | for (int i = 0; i < metrics.Length; i++)
146 | {
147 | if (metrics[i].Value != 0) return false;
148 | }
149 | return true;
150 | }
151 | }
152 | }
--------------------------------------------------------------------------------
/src/jit-analyze/Metrics.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | namespace ManagedCodeGen
6 | {
7 | public abstract class Metric
8 | {
9 | public virtual string Name { get; }
10 | public virtual string DisplayName { get; }
11 | public virtual string Unit { get; }
12 | public virtual bool LowerIsBetter { get; }
13 | public abstract Metric Clone();
14 | public abstract string ValueString { get; }
15 | public double Value { get; set; }
16 |
17 | public void Add(Metric m)
18 | {
19 | Value += m.Value;
20 | }
21 |
22 | public void Sub(Metric m)
23 | {
24 | Value -= m.Value;
25 | }
26 |
27 | public void Rel(Metric m)
28 | {
29 | Value = (Value - m.Value) / m.Value;
30 | }
31 |
32 | public void SetValueFrom(Metric m)
33 | {
34 | Value = m.Value;
35 | }
36 |
37 | public override string ToString()
38 | {
39 | return Name;
40 | }
41 | }
42 |
43 | public class CodeSizeMetric : Metric
44 | {
45 | public override string Name => "CodeSize";
46 | public override string DisplayName => "Code Size";
47 | public override string Unit => "byte";
48 | public override bool LowerIsBetter => true;
49 | public override Metric Clone() => new CodeSizeMetric();
50 | public override string ValueString => $"{Value}";
51 | }
52 |
53 | public class PrologSizeMetric : Metric
54 | {
55 | public override string Name => "PrologSize";
56 | public override string DisplayName => "Prolog Size";
57 | public override string Unit => "byte";
58 | public override bool LowerIsBetter => true;
59 | public override Metric Clone() => new PrologSizeMetric();
60 | public override string ValueString => $"{Value}";
61 | }
62 |
63 | public class PerfScoreMetric : Metric
64 | {
65 | public override string Name => "PerfScore";
66 | public override string DisplayName => "Perf Score";
67 | public override string Unit => "PerfScoreUnit";
68 | public override bool LowerIsBetter => true;
69 | public override Metric Clone() => new PerfScoreMetric();
70 | public override string ValueString => $"{Value:F2}";
71 | }
72 |
73 | public class InstrCountMetric : Metric
74 | {
75 | public override string Name => "InstrCount";
76 | public override string DisplayName => "Instruction Count";
77 | public override string Unit => "Instruction";
78 | public override bool LowerIsBetter => true;
79 | public override Metric Clone() => new InstrCountMetric();
80 | public override string ValueString => $"{Value}";
81 | }
82 |
83 | public class AllocSizeMetric : Metric
84 | {
85 | public override string Name => "AllocSize";
86 | public override string DisplayName => "Allocation Size";
87 | public override string Unit => "byte";
88 | public override bool LowerIsBetter => true;
89 | public override Metric Clone() => new AllocSizeMetric();
90 | public override string ValueString => $"{Value}";
91 | }
92 |
93 | public class ExtraAllocBytesMetric : Metric
94 | {
95 | public override string Name => "ExtraAllocBytes";
96 | public override string DisplayName => "Extra Allocation Size";
97 | public override string Unit => "byte";
98 | public override bool LowerIsBetter => true;
99 | public override Metric Clone() => new ExtraAllocBytesMetric();
100 | public override string ValueString => $"{Value}";
101 | }
102 | public class DebugClauseMetric : Metric
103 | {
104 | public override string Name => "DebugClauseCount";
105 | public override string DisplayName => "Debug Clause Count";
106 | public override string Unit => "Clause";
107 | public override bool LowerIsBetter => true;
108 | public override Metric Clone() => new DebugClauseMetric();
109 | public override string ValueString => $"{Value}";
110 | }
111 |
112 | public class DebugVarMetric : Metric
113 | {
114 | public override string Name => "DebugVarCount";
115 | public override string DisplayName => "Debug Variable Count";
116 | public override string Unit => "Variable";
117 | public override bool LowerIsBetter => true;
118 | public override Metric Clone() => new DebugVarMetric();
119 | public override string ValueString => $"{Value}";
120 | }
121 |
122 | /* LSRA specific */
123 | public class SpillCountMetric : Metric
124 | {
125 | public override string Name => "SpillCount";
126 | public override string DisplayName => "Spill Count";
127 | public override string Unit => "Count";
128 | public override bool LowerIsBetter => true;
129 | public override Metric Clone() => new SpillCountMetric();
130 | public override string ValueString => $"{Value}";
131 | }
132 |
133 | public class SpillWeightMetric : Metric
134 | {
135 | public override string Name => "SpillWeight";
136 | public override string DisplayName => "Spill Weighted";
137 | public override string Unit => "Count";
138 | public override bool LowerIsBetter => true;
139 | public override Metric Clone() => new SpillWeightMetric();
140 | public override string ValueString => $"{Value}";
141 | }
142 |
143 | public class ResolutionCountMetric : Metric
144 | {
145 | public override string Name => "ResolutionCount";
146 | public override string DisplayName => "Resolution Count";
147 | public override string Unit => "Count";
148 | public override bool LowerIsBetter => true;
149 | public override Metric Clone() => new ResolutionCountMetric();
150 | public override string ValueString => $"{Value}";
151 | }
152 |
153 | public class ResolutionWeightMetric : Metric
154 | {
155 | public override string Name => "ResolutionWeight";
156 | public override string DisplayName => "Resolution Weighted";
157 | public override string Unit => "Count";
158 | public override bool LowerIsBetter => true;
159 | public override Metric Clone() => new ResolutionWeightMetric();
160 | public override string ValueString => $"{Value}";
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/jit-analyze/README.md:
--------------------------------------------------------------------------------
1 | # jit-analyze - Managed CodeGen difference analysis tool
2 |
3 | jit-analyze is a utility to provide feedback on generated disassembly.
4 | The tool will produce the total bytes of difference and list of files
5 | and methods sorted by contribution (size in bytes of regression/improvement)
6 |
7 | To build/setup:
8 |
9 | * Download dotnet cli. Follow install instructions and get dotnet on your
10 | your path.
11 | * Follow publish directions for the jitutils repo in the root. This will
12 | put the tools on your path.
13 | * Generate corediff disasm run. See [Getting Started](../../doc/getstarted.md)
14 | for directions how.
15 | * Run analyze --base `` --diff `` to produce a summary of the
16 | differences.
17 |
18 | The output of analyze looks like the following:
19 | ```
20 | $ jit-analyze --base ~/Work/output/base --diff ~/Work/output/diff
21 |
22 | (Note: Lower is better)
23 |
24 | Total bytes of diff: -4124
25 | diff is an improvement.
26 |
27 | Top file regressions by size (bytes):
28 | 193 : Microsoft.CodeAnalysis.dasm
29 | 154 : System.Dynamic.Runtime.dasm
30 | 60 : System.IO.Compression.dasm
31 | 43 : System.Net.Security.dasm
32 | 43 : System.Xml.ReaderWriter.dasm
33 |
34 | Top file improvements by size (bytes):
35 | -1804 : mscorlib.dasm
36 | -1532 : Microsoft.CodeAnalysis.CSharp.dasm
37 | -726 : System.Xml.XmlDocument.dasm
38 | -284 : System.Linq.Expressions.dasm
39 | -239 : System.Net.Http.dasm
40 |
41 | 21 total files with diffs.
42 |
43 | Top method regressions by size (bytes):
44 | 328 : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.DocumentationCommentXmlTokens:.cctor()
45 | 266 : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.MethodTypeInferrer:Fix(int,byref):bool:this
46 | 194 : mscorlib.dasm - System.DefaultBinder:BindToMethod(int,ref,byref,ref,ref,ref,byref):ref:this
47 | 187 : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LanguageParser:ParseModifiers(ref):this
48 | 163 : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.Symbols.SourceAssemblySymbol:DecodeWellKnownAttribute(byref,int,bool):this
49 |
50 | Top method improvements by size (bytes):
51 | -160 : System.Xml.XmlDocument.dasm - System.Xml.XmlTextWriter:AutoComplete(int):this
52 | -124 : System.Xml.XmlDocument.dasm - System.Xml.XmlTextWriter:WriteEndStartTag(bool):this
53 | -110 : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.MemberSemanticModel:GetEnclosingBinder(ref,int):ref:this
54 | -95 : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.CSharpDataFlowAnalysis:AnalyzeReadWrite():this
55 | -85 : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LanguageParser:ParseForStatement():ref:this
56 |
57 | 3762 total methods with diffs
58 | ```
--------------------------------------------------------------------------------
/src/jit-analyze/jit-analyze.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/jit-dasm-pmi/JitDasmPmiRootCommand.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.CommandLine;
8 | using System.IO;
9 |
10 | namespace ManagedCodeGen
11 | {
12 | internal sealed class JitDasmPmiRootCommand : RootCommand
13 | {
14 | public Option AltJit { get; } =
15 | new("--altjit") { Description = "If set, the name of the altjit to use (e.g., clrjit_win_arm64_x64.dll)" };
16 | public Option CorerunPath { get; } =
17 | new("--corerun", "-c") { CustomParser = Helpers.GetResolvedPath, DefaultValueFactory = Helpers.GetResolvedPath, Description = "The corerun compiler exe" };
18 | public Option JitPath { get; } =
19 | new("--jit", "-j") { CustomParser = Helpers.GetResolvedPath, DefaultValueFactory = Helpers.GetResolvedPath, Description = "The full path to the jit library" };
20 | public Option OutputPath { get; } =
21 | new("--output", "-o") { Description = "The output path" };
22 | public Option Filename { get; } =
23 | new("--file", "-f") { Description = "Name of file to take list of assemblies from. Both a file and assembly list can be used" };
24 | public Option DumpGCInfo { get; } =
25 | new("--gcinfo") { Description = "Add GC info to the disasm output" };
26 | public Option DumpDebugInfo { get; } =
27 | new("--debuginfo") { Description = "Add Debug info to the disasm output" };
28 | public Option Verbose { get; } =
29 | new("--verbose") { Description = "Enable verbose output" };
30 | public Option NoDiffable { get; } =
31 | new("--nodiffable") { Description = "Generate non-diffable asm (pointer values will be left in output)" };
32 | public Option Tier0 { get; } =
33 | new("--tier0") { Description = "Generate tier0 code" };
34 | public Option Cctors { get; } =
35 | new("--cctors") { Description = "Jit and run cctors before jitting other methods" };
36 | public Option Recursive { get; } =
37 | new("--recursive", "-r") { Description = "Search directories recursively" };
38 | public Option> PlatformPaths { get; } =
39 | new("--platform", "-p") { Description = "Path to platform assemblies" };
40 | public Option> Methods { get; } =
41 | new("--methods", "-m") { Description = "List of methods to disasm" };
42 | public Argument> AssemblyList { get; } =
43 | new("--assembly") { Description = "The list of assemblies or directories to scan for assemblies" };
44 | public Option WaitForDebugger { get; } =
45 | new("--wait", "-w") { Description = "Wait for debugger to attach" };
46 | public Option NoCopyJit { get; } =
47 | new("--nocopy") { Description = "Correct jit has already been copied into the corerun directory" };
48 |
49 | public ParseResult Result;
50 |
51 | public JitDasmPmiRootCommand(string[] args) : base("Managed code gen diff tool")
52 | {
53 | Options.Add(AltJit);
54 | Options.Add(CorerunPath);
55 | Options.Add(JitPath);
56 | Options.Add(OutputPath);
57 | Options.Add(Filename);
58 | Options.Add(DumpGCInfo);
59 | Options.Add(DumpDebugInfo);
60 | Options.Add(Verbose);
61 | Options.Add(NoDiffable);
62 | Options.Add(Tier0);
63 | Options.Add(Cctors);
64 | Options.Add(Recursive);
65 | Options.Add(PlatformPaths);
66 | Options.Add(Methods);
67 | Options.Add(WaitForDebugger);
68 | Options.Add(NoCopyJit);
69 |
70 | Arguments.Add(AssemblyList);
71 |
72 | SetAction(result =>
73 | {
74 | Result = result;
75 |
76 | try
77 | {
78 | List errors = new();
79 | string corerun = Result.GetValue(CorerunPath);
80 | if (corerun == null || !File.Exists(corerun))
81 | {
82 | errors.Add("Can't find --corerun tool.");
83 | }
84 |
85 | if (Result.GetResult(Filename) == null && Result.GetValue(AssemblyList).Count == 0)
86 | {
87 | errors.Add("No input: Specify --file or list input assemblies.");
88 | }
89 |
90 | string jitPath = Result.GetValue(JitPath);
91 | if (jitPath != null && !File.Exists(jitPath))
92 | {
93 | errors.Add("Can't find --jit library.");
94 | }
95 |
96 | string filename = Result.GetValue(Filename);
97 | if (filename != null && !File.Exists(filename))
98 | {
99 | errors.Add($"Error reading input file {filename}, file not found.");
100 | }
101 |
102 | if (errors.Count > 0)
103 | {
104 | throw new Exception(string.Join(Environment.NewLine, errors));
105 | }
106 |
107 | return new Program(this).Run();
108 | }
109 | catch (Exception e)
110 | {
111 | Console.ResetColor();
112 | Console.ForegroundColor = ConsoleColor.Red;
113 |
114 | Console.Error.WriteLine("Error: " + e.Message);
115 | Console.Error.WriteLine(e.ToString());
116 |
117 | Console.ResetColor();
118 |
119 | return 1;
120 | }
121 | });
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/jit-dasm-pmi/README.md:
--------------------------------------------------------------------------------
1 | # jit-dasm-pmi - Managed CodeGen Dasm Generator
2 |
3 | jit-dasm-pmi is a utility to drive the dotnet runtime to produce
4 | binary disassembly from the JIT compiler. This can be used to create
5 | diffs to check ongoing development.
6 |
7 | To build/setup:
8 |
9 | * Download the 2.1 dotnet cli. Follow install instructions and get
10 | dotnet on your path.
11 | * Do 'dotnet restore' to create lock file and pull down required packages.
12 | * Issue a 'dotnet build' command. This will create a jit-dasm-pmi in the bin
13 | directory that you can use to drive creation of diffs.
14 | * jit-dasm-pmi can be installed by running the project build script in the root
15 | of this repo via
16 |
17 | ```
18 | $ ./build.{cmd|sh} -p
19 | ```
--------------------------------------------------------------------------------
/src/jit-dasm-pmi/jit-dasm-pmi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/jit-dasm/JitDasmRootCommand.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.CommandLine;
8 | using System.IO;
9 |
10 | namespace ManagedCodeGen
11 | {
12 | internal sealed class JitDasmRootCommand : RootCommand
13 | {
14 | public Option AltJit { get; } =
15 | new("--altjit") { Description = "If set, the name of the altjit to use (e.g., clrjit_win_arm64_x64.dll)" };
16 | public Option CrossgenPath { get; } =
17 | new("--crossgen", "-c") { CustomParser = Helpers.GetResolvedPath, DefaultValueFactory = Helpers.GetResolvedPath, Description = "The crossgen or crossgen2 compiler exe." };
18 | public Option JitPath { get; } =
19 | new("--jit", "-j") { CustomParser = Helpers.GetResolvedPath, DefaultValueFactory = Helpers.GetResolvedPath, Description = "The full path to the jit library" };
20 | public Option OutputPath { get; } =
21 | new("--output", "-o") { Description = "The output path" };
22 | public Option Filename { get; } =
23 | new("--file", "-f") { Description = "Name of file to take list of assemblies from. Both a file and assembly list can be used" };
24 | public Option DumpGCInfo { get; } =
25 | new("--gcinfo") { Description = "Add GC info to the disasm output" };
26 | public Option DumpDebugInfo { get; } =
27 | new("--debuginfo") { Description = "Add Debug info to the disasm output" };
28 | public Option Verbose { get; } =
29 | new("--verbose") { Description = "Enable verbose output" };
30 | public Option NoDiffable { get; } =
31 | new("--nodiffable") { Description = "Generate non-diffable asm (pointer values will be left in output)" };
32 | public Option Recursive { get; } =
33 | new("--recursive", "-r") { Description = "Search directories recursively" };
34 | public Option> PlatformPaths { get; } =
35 | new("--platform", "-p") { Description = "Path to platform assemblies" };
36 | public Option> Methods { get; } =
37 | new("--methods", "-m") { Description = "List of methods to disasm" };
38 | public Argument> AssemblyList { get; } =
39 | new("--assembly") { Description = "The list of assemblies or directories to scan for assemblies" };
40 | public Option WaitForDebugger { get; } =
41 | new("--wait", "-w") { Description = "Wait for debugger to attach" };
42 |
43 | public ParseResult Result;
44 | public bool CodeGeneratorV1 { get; private set; }
45 |
46 | public JitDasmRootCommand(string[] args) : base("Managed codegen diff tool (crossgen/AOT)")
47 | {
48 | Options.Add(AltJit);
49 | Options.Add(CrossgenPath);
50 | Options.Add(JitPath);
51 | Options.Add(OutputPath);
52 | Options.Add(Filename);
53 | Options.Add(DumpGCInfo);
54 | Options.Add(DumpDebugInfo);
55 | Options.Add(Verbose);
56 | Options.Add(NoDiffable);
57 | Options.Add(Recursive);
58 | Options.Add(PlatformPaths);
59 | Options.Add(Methods);
60 | Options.Add(WaitForDebugger);
61 |
62 | Arguments.Add(AssemblyList);
63 |
64 | SetAction(result =>
65 | {
66 | Result = result;
67 |
68 | try
69 | {
70 | List errors = new();
71 | string crossgen = Result.GetValue(CrossgenPath);
72 | if (crossgen == null || !File.Exists(crossgen))
73 | {
74 | errors.Add("Can't find --crossgen tool.");
75 | }
76 | else
77 | {
78 | string crossgenFilename = Path.GetFileNameWithoutExtension(crossgen).ToLower();
79 | if (crossgenFilename == "crossgen")
80 | {
81 | CodeGeneratorV1 = true;
82 | }
83 | else if (crossgenFilename != "crossgen2")
84 | {
85 | errors.Add("--crossgen tool should be crossgen or crossgen2.");
86 | }
87 | }
88 |
89 | if (Result.GetResult(Filename) == null && Result.GetValue(AssemblyList).Count == 0)
90 | {
91 | errors.Add("No input: Specify --file or list input assemblies.");
92 | }
93 |
94 | string jitPath = Result.GetValue(JitPath);
95 | if (jitPath != null && !File.Exists(jitPath))
96 | {
97 | errors.Add("Can't find --jit library.");
98 | }
99 |
100 | string filename = Result.GetValue(Filename);
101 | if (filename != null && !File.Exists(filename))
102 | {
103 | errors.Add($"Error reading input file {filename}, file not found.");
104 | }
105 |
106 | if (errors.Count > 0)
107 | {
108 | throw new Exception(string.Join(Environment.NewLine, errors));
109 | }
110 |
111 | return new Program(this).Run();
112 | }
113 | catch (Exception e)
114 | {
115 | Console.ResetColor();
116 | Console.ForegroundColor = ConsoleColor.Red;
117 |
118 | Console.Error.WriteLine("Error: " + e.Message);
119 | Console.Error.WriteLine(e.ToString());
120 |
121 | Console.ResetColor();
122 |
123 | return 1;
124 | }
125 | });
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/jit-dasm/README.md:
--------------------------------------------------------------------------------
1 | # jit-dasm - Managed CodeGen Dasm Generator
2 |
3 | jit-dasm is a utility to drive the dotnet crossgen tool to produce
4 | binary disassembly from the JIT compiler. This can be used to create
5 | diffs to check ongoing development.
6 |
7 | To build/setup:
8 |
9 | * Download dotnet cli. Follow install instructions and get dotnet on your
10 | your path.
11 | * Do 'dotnet restore' to create lock file and
12 | pull down required packages.
13 | * Issue a 'dotnet build' command. This will create a jit-dasm in the bin
14 | directory that you can use to drive creation of diffs.
15 | * jit-dasm can be installed by running the project build script in the root of this repo
16 | via
17 |
18 | ```
19 | $ ./build.{cmd|sh} -p
20 | ```
--------------------------------------------------------------------------------
/src/jit-dasm/jit-dasm.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/jit-decisions-analyze/README.md:
--------------------------------------------------------------------------------
1 | # jit-decisions-analyze - Managed JIT decisions analysis tool
2 |
--------------------------------------------------------------------------------
/src/jit-decisions-analyze/jit-decisions-analyze.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 |
6 | namespace jit_decisions_analyze
7 | {
8 | internal class Program
9 | {
10 | private static void Main(string[] args)
11 | {
12 | List events = new List();
13 | int malformed = 0;
14 | static void WriteProgress(double pct)
15 | {
16 | Console.CursorLeft = 0;
17 | Console.Write("{0:F2}% done", pct);
18 | }
19 |
20 | using (var sr = new StreamReader(File.OpenRead(args[0])))
21 | {
22 | int lines = 0;
23 | string line;
24 | while ((line = sr.ReadLine()) != null)
25 | {
26 | if (!line.StartsWith("JITTracing: "))
27 | continue;
28 |
29 | line = line.Substring("JITTracing: ".Length);
30 | Event evt = ToEvent(line);
31 | if (evt != null)
32 | events.Add(evt);
33 | else
34 | malformed++;
35 |
36 | if (lines++ % 10000 == 0)
37 | WriteProgress(sr.BaseStream.Position / (double)sr.BaseStream.Length * 100);
38 | }
39 | }
40 |
41 | WriteProgress(100);
42 | Console.WriteLine();
43 |
44 | Console.WriteLine("{0} total well-formed events ({1} filtered away because they were malformed)", events.Count, malformed);
45 | List tailCalls = events.OfType().ToList();
46 | WriteInfo("Implicit", tailCalls.Where(t => !t.TailPrefix));
47 | WriteInfo("Explicit", tailCalls.Where(t => t.TailPrefix));
48 | WriteInfo("Inlining", events.OfType());
49 | }
50 |
51 | private static Event ToEvent(string l)
52 | {
53 | string[] data = l.Split("@!@!@");
54 | if (data.Length % 2 == 0)
55 | return null;
56 |
57 | Dictionary payload = new Dictionary();
58 | for (int i = 1; i < data.Length; i += 2)
59 | payload.Add(data[i], data[i + 1]);
60 |
61 | string tailPrefix;
62 | string failReason;
63 | switch (data[0])
64 | {
65 | case "MethodJitTailCallSucceeded":
66 | tailPrefix = payload.GetValueOrDefault("TailPrefix");
67 | if (tailPrefix == null)
68 | return null;
69 |
70 | return new TailCallSucceededEvent { TailPrefix = tailPrefix == "True" };
71 | case "MethodJitTailCallFailed":
72 | tailPrefix = payload.GetValueOrDefault("TailPrefix");
73 | failReason = payload.GetValueOrDefault("FailReason");
74 | if (failReason == null || tailPrefix == null)
75 | return null;
76 |
77 | return new TailCallFailedEvent { FailReason = failReason, TailPrefix = tailPrefix == "True" };
78 | case "MethodJitInliningSucceeded":
79 | return new InliningSucceededEvent();
80 | case "MethodJitInliningFailed":
81 | failReason = payload.GetValueOrDefault("FailReason");
82 | if (failReason == null)
83 | return null;
84 |
85 | return new InliningFailedEvent { FailReason = failReason };
86 | default:
87 | return null;
88 | }
89 | }
90 |
91 | private static void WriteInfo(string name, IEnumerable events)
92 | {
93 | List list = events.ToList();
94 | int sites = list.Count;
95 | int sitesSuccessful = list.Count(IsSuccessEvent);
96 | Console.WriteLine("{0} call sites: {1}/{2} converted", name, sitesSuccessful, sites);
97 | if (sites == 0)
98 | return;
99 |
100 | string GetInfoString(Event e)
101 | {
102 | switch (e)
103 | {
104 | case TailCallSucceededEvent f: return "Successfully converted";
105 | case InliningSucceededEvent f: return "Successfully converted";
106 | case TailCallFailedEvent f: return f.FailReason;
107 | case InliningFailedEvent f: return f.FailReason;
108 | default: throw new ArgumentException("No fail reason on event");
109 | }
110 | }
111 |
112 | var groupedFailures = list.GroupBy(GetInfoString).OrderByDescending(g => g.Count());
113 | foreach (var g in groupedFailures)
114 | Console.WriteLine("[{0:00.00}%] {1}", g.Count() / (double)sites * 100, g.Key);
115 |
116 | Console.WriteLine();
117 | }
118 |
119 | private static bool IsSuccessEvent(Event e) => e is TailCallSucceededEvent || e is InliningSucceededEvent;
120 | }
121 |
122 | internal abstract class Event
123 | {
124 | }
125 |
126 | internal abstract class TailCallEvent : Event
127 | {
128 | public bool TailPrefix { get; set; }
129 | }
130 |
131 | internal class TailCallSucceededEvent : TailCallEvent
132 | {
133 | }
134 |
135 | internal class TailCallFailedEvent : TailCallEvent
136 | {
137 | public string FailReason { get; set; }
138 | }
139 |
140 | internal abstract class InliningEvent : Event
141 | {
142 | }
143 |
144 | internal class InliningSucceededEvent : InliningEvent
145 | {
146 | }
147 |
148 | internal class InliningFailedEvent : InliningEvent
149 | {
150 | public string FailReason { get; set; }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/jit-decisions-analyze/jit-decisions-analyze.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/jit-diff/README.md:
--------------------------------------------------------------------------------
1 | # jit-diff - Diff CoreCLR tree
2 |
3 | jit-diff is a utility to produce diffs from a CoreCLR test layout via
4 | the jit-dasm tool.
5 |
6 | To build/setup:
7 |
8 | * Download dotnet cli. Follow install instructions and get dotnet on your
9 | your path.
10 | * Do 'dotnet restore' to create lock file and
11 | pull down required packages.
12 | * Issue a 'dotnet build' command. This will create a jit-diff in the bin
13 | directory that you can use to drive creation of diffs.
14 | * Ensure that jit-dasm is on your path. (See jit-dasm README.md for details
15 | on how to build)
16 | * invoke jit-diff --frameworks --base `` --diff ``
17 | --coreroot `` --testroot ``
18 | * jit-diff can be installed by running the project build script in the root of this repo
19 | via
20 |
21 | ```
22 | $ ./build.{cmd|sh} -p
23 | ```
24 |
--------------------------------------------------------------------------------
/src/jit-diff/install.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.CommandLine;
8 | using System.Diagnostics;
9 | using System.IO;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Text.Json;
13 | using System.Text.Json.Nodes;
14 | using System.Text.RegularExpressions;
15 | using System.Threading;
16 | using System.Threading.Tasks;
17 | using System.Xml;
18 |
19 | namespace ManagedCodeGen
20 | {
21 | public partial class jitdiff
22 | {
23 | public static int InstallCommand(Config config)
24 | {
25 | var configFilePath = Path.Combine(config.JitUtilsRoot, s_configFileName);
26 | string configJson = File.ReadAllText(configFilePath);
27 | var jObj = JsonObject.Parse(configJson);
28 |
29 | if ((jObj[s_configFileRootKey] == null) || (jObj[s_configFileRootKey]["tools"] == null))
30 | {
31 | Console.Error.WriteLine("\"install\" doesn't know how to add the \"" + s_configFileRootKey + "\":\"tools\" section to the config file");
32 | return -1;
33 | }
34 |
35 | if ((config.PlatformMoniker == null) || (GetOSArtifactDirComponent(config.PlatformMoniker) == null))
36 | {
37 | return -1;
38 | }
39 |
40 | var tools = (JsonArray)jObj[s_configFileRootKey]["tools"];
41 |
42 | // Early out if the tool is already installed. We can only do this if we're not doing
43 | // "--last_successful", in which case we don't know what the build number (and hence
44 | // tag) is.
45 | string tag = null;
46 | if (!config.DoLastSucessful)
47 | {
48 | tag = String.Format("{0}-{1}", config.JobName, config.Number);
49 | if (tools.Where(x => (string)x["tag"] == tag).Any())
50 | {
51 | Console.Error.WriteLine("{0} is already installed in the " + s_configFileName + ". Remove before re-install.", tag);
52 | return -1;
53 | }
54 | }
55 |
56 | string toolPath = Path.Combine(config.JitUtilsRoot, "tools");
57 |
58 | // Issue cijobs command to download bits
59 | List cijobsArgs = new List();
60 |
61 | cijobsArgs.Add("copy");
62 |
63 | cijobsArgs.Add("--job");
64 | cijobsArgs.Add(config.JobName);
65 |
66 | if (config.BranchName != null)
67 | {
68 | cijobsArgs.Add("--branch");
69 | cijobsArgs.Add(config.BranchName);
70 | }
71 |
72 | if (config.DoLastSucessful)
73 | {
74 | cijobsArgs.Add("--last_successful");
75 | }
76 | else
77 | {
78 | cijobsArgs.Add("--number");
79 | cijobsArgs.Add(config.Number);
80 | }
81 |
82 | cijobsArgs.Add("--unzip");
83 |
84 | cijobsArgs.Add("--output_root");
85 | cijobsArgs.Add(toolPath);
86 |
87 | if (config.Verbose)
88 | {
89 | Console.WriteLine("Command: {0} {1}", "cijobs", String.Join(" ", cijobsArgs));
90 | }
91 |
92 | ProcessResult result = Utility.ExecuteProcess("cijobs", cijobsArgs);
93 |
94 | if (result.ExitCode != 0)
95 | {
96 | Console.Error.WriteLine("cijobs command returned with {0} failures", result.ExitCode);
97 | return result.ExitCode;
98 | }
99 |
100 | // There is a convention that cijobs creates a directory to store the job within
101 | // the toolPath named:
102 | // -
103 | // for example:
104 | // checked_windows_nt-1234
105 | //
106 | // However, if we passed "--last_successful", we don't know that number! So, figure it out.
107 |
108 | if (config.DoLastSucessful)
109 | {
110 | // Find the largest numbered build with this job name.
111 | int maxBuildNum = -1;
112 | foreach (var dir in Directory.EnumerateDirectories(toolPath))
113 | {
114 | var lastComponent = Path.GetFileName(dir);
115 | Regex dirPattern = new Regex(@"(.*)-(.*)");
116 | Match dirMatch = dirPattern.Match(lastComponent);
117 | if (dirMatch.Success)
118 | {
119 | var value = dirMatch.Groups[2].Value;
120 | if (int.TryParse(value, out int thisBuildNum))
121 | {
122 | if (thisBuildNum > maxBuildNum)
123 | {
124 | maxBuildNum = thisBuildNum;
125 | }
126 | }
127 | }
128 | }
129 |
130 | if (maxBuildNum == -1)
131 | {
132 | Console.Error.WriteLine("Error: couldn't determine last successful build directory in {0}", toolPath);
133 | return -1;
134 | }
135 |
136 | string buildNum = maxBuildNum.ToString();
137 | tag = String.Format("{0}-{1}", config.JobName, buildNum);
138 | }
139 |
140 | toolPath = Path.Combine(toolPath, tag);
141 |
142 | string platformPath = Path.Combine(toolPath, "Product");
143 | if (!Directory.Exists(platformPath))
144 | {
145 | Console.Error.WriteLine("cijobs didn't create or populate directory {0}", platformPath);
146 | return 1;
147 | }
148 |
149 | string buildOS = GetOSArtifactDirComponent(config.PlatformMoniker).ToUpper();
150 | foreach (var dir in Directory.EnumerateDirectories(platformPath))
151 | {
152 | if (Path.GetFileName(dir).ToUpper().Contains(buildOS))
153 | {
154 | tools.Add(new JsonObject
155 | {
156 | ["tag"] = tag,
157 | ["path"] = Path.GetFullPath(dir)
158 | });
159 | break;
160 | }
161 | }
162 |
163 | // Overwrite current config.json with new data.
164 | using (var sw = File.CreateText(configFilePath))
165 | {
166 | var json = JsonSerializer.Serialize (jObj, new JsonSerializerOptions { WriteIndented = true });
167 | sw.Write(json);
168 | }
169 |
170 | return 0;
171 | }
172 | }
173 | }
174 |
175 |
--------------------------------------------------------------------------------
/src/jit-diff/jit-diff.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Exe
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/jit-diff/uninstall.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.CommandLine;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Text.Json;
10 | using System.Text.Json.Nodes;
11 |
12 | namespace ManagedCodeGen
13 | {
14 | public partial class jitdiff
15 | {
16 | public static int UninstallCommand(Config config)
17 | {
18 | var configFilePath = Path.Combine(config.JitUtilsRoot, s_configFileName);
19 | string configJson = File.ReadAllText(configFilePath);
20 | var jObj = JsonObject.Parse(configJson);
21 |
22 | if ((jObj[s_configFileRootKey] == null) || (jObj[s_configFileRootKey]["tools"] == null))
23 | {
24 | Console.Error.WriteLine("Error: no \"" + s_configFileRootKey + "\":\"tools\" section in the config file");
25 | return -1;
26 | }
27 |
28 | var tools = (JsonArray)jObj[s_configFileRootKey]["tools"];
29 | var elem = tools.Where(x => (string)x["tag"] == config.Tag);
30 | if (!elem.Any())
31 | {
32 | Console.WriteLine("{0} is not installed in {1}.", config.Tag, s_configFileName);
33 | return -1;
34 | }
35 |
36 | var jobj = elem.First();
37 | string path = (string)jobj["path"];
38 | if (path != null)
39 | {
40 | Console.WriteLine("Warning: you should remove install directory {0}.", path);
41 |
42 | // We could do this:
43 | // Directory.Delete(path, true);
44 | // However, the "install" command copies down a lot more than just this directory,
45 | // so removing this directory still leaves around a lot of stuff.
46 | }
47 |
48 | Console.WriteLine("Removing tag {0} from config file.", config.Tag);
49 | tools.Remove(jobj);
50 |
51 | // Overwrite current config.json with new data.
52 | using (var sw = File.CreateText(configFilePath))
53 | {
54 | var json = JsonSerializer.Serialize (jObj, new JsonSerializerOptions { WriteIndented = true });
55 | sw.Write(json);
56 | }
57 |
58 | return 0;
59 | }
60 | }
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/src/jit-format/README.md:
--------------------------------------------------------------------------------
1 | # jit-format - Code Formatting Tool for JIT Source
2 |
3 | jit-format is a utility to maintain formatting standards in jit source.
4 | The tool will analyze the code for formatting errors using clang-tidy
5 | and clang-format, and potentially fix errors.
6 |
7 | To build/setup:
8 |
9 | * Download dotnet cli. Follow install instructions and get dotnet on your
10 | your path.
11 | * Do 'dotnet restore' to create lock file and
12 | pull down required packages.
13 | * Issue a 'dotnet build' command. This will create a jit-format in the bin
14 | directory that you can use to check the formatting of your changes.
15 | * Invoke jit-format -a `` -b `` -p ``
16 | --runtime ``
17 | * jit-format can be installed by running the project build script in the root of this repo
18 | via
19 |
20 | ```
21 | $ ./build.{cmd|sh} -p
22 | ```
23 |
24 |
--------------------------------------------------------------------------------
/src/jit-format/jit-format.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Exe
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/jit-include.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/jit-pintool/README.md:
--------------------------------------------------------------------------------
1 | # clrjit pintool
2 |
3 | This directory contains the source code of a pintool that can be used with
4 | [PIN](https://www.intel.com/content/www/us/en/developer/articles/tool/pin-a-dynamic-binary-instrumentation-tool.html)
5 | to measure throughput of the JIT on x64 and x86. The pintool counts the number
6 | of instructions executed inside the JIT only. Furthermore it has some special
7 | support to integrate with SuperPMI's metric collection to allow support for
8 | diffing throughput.
9 |
10 | ## Building
11 | The easiest way to build it is to follow PIN's manual and adding the pintool
12 | here as another example. See the "Building the Example Tools" and "Building Your
13 | Own Tool" sections in the manual.
14 | Note that this requires cygwin on Windows.
15 |
--------------------------------------------------------------------------------
/src/jit-rl-cse/MLCSE.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 | enable
9 | enable
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/jit-rl-cse/MarkovChain96689.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet/jitutils/b19db6c8a30fc1717a554f5ef0f7f8dc14778188/src/jit-rl-cse/MarkovChain96689.png
--------------------------------------------------------------------------------
/src/jit-rl-cse/MarkovChain96689PG100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet/jitutils/b19db6c8a30fc1717a554f5ef0f7f8dc14778188/src/jit-rl-cse/MarkovChain96689PG100.png
--------------------------------------------------------------------------------
/src/jit-tp-analyze/Program.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.CommandLine;
8 | using System.IO;
9 | using System.Linq;
10 | using System.Runtime.InteropServices;
11 | using System.Text.RegularExpressions;
12 |
13 | namespace ManagedCodeGen;
14 |
15 | internal class Program
16 | {
17 | private static readonly Regex _traceLineRegex = new("(\\d+) +: (.*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
18 |
19 | private readonly string _baseTracePath;
20 | private readonly string _diffTracePath;
21 | private readonly double _noise;
22 |
23 | public Program(JitTpAnalyzeRootCommand command, ParseResult result)
24 | {
25 | _baseTracePath = result.GetValue(command.BasePath);
26 | _diffTracePath = result.GetValue(command.DiffPath);
27 | _noise = result.GetValue(command.Noise);
28 | }
29 |
30 | public void Run()
31 | {
32 | TextWriter output = Console.Out;
33 | Dictionary baseTrace = ParseTrace(_baseTracePath);
34 | Dictionary diffTrace = ParseTrace(_diffTracePath);
35 | HashSet allRecordedFunctions = new();
36 | foreach (var function in baseTrace)
37 | {
38 | allRecordedFunctions.Add(function.Key);
39 | }
40 | foreach (var function in diffTrace)
41 | {
42 | allRecordedFunctions.Add(function.Key);
43 | }
44 |
45 | long baseTotalInsCount = baseTrace.Sum(x => x.Value);
46 | long diffTotalInsCount = diffTrace.Sum(x => x.Value);
47 | double totalPercentageDiff = GetPercentageDiff(baseTotalInsCount, diffTotalInsCount);
48 | output.WriteLine($"Base: {baseTotalInsCount}, Diff: {diffTotalInsCount}, {FormatPercentageDiff(totalPercentageDiff, "0000")}");
49 | output.WriteLine();
50 |
51 | // Now create a list of functions which contributed to the difference.
52 | long totalAbsInsCountDiff = 0;
53 | List diffs = new();
54 | foreach (string functionName in allRecordedFunctions)
55 | {
56 | long diffInsCount = diffTrace.GetValueOrDefault(functionName);
57 | long baseInsCount = baseTrace.GetValueOrDefault(functionName);
58 | long insCountDiff = diffInsCount - baseInsCount;
59 | if (insCountDiff == 0)
60 | {
61 | continue;
62 | }
63 |
64 | diffs.Add(new()
65 | {
66 | Name = functionName,
67 | InsCountDiff = insCountDiff,
68 | InsPercentageDiff = GetPercentageDiff(baseInsCount, diffInsCount),
69 | TotalInsPercentageDiff = (double)insCountDiff / baseTotalInsCount * 100
70 | });
71 |
72 | totalAbsInsCountDiff += Math.Abs(insCountDiff);
73 | }
74 |
75 | foreach (ref FunctionDiff diff in CollectionsMarshal.AsSpan(diffs))
76 | {
77 | diff.ContributionPercentage = (double)Math.Abs(diff.InsCountDiff) / totalAbsInsCountDiff * 100;
78 | }
79 |
80 | // Filter out functions below the noise level.
81 | diffs = diffs.Where(d => d.ContributionPercentage > _noise).ToList();
82 | diffs.Sort((x, y) => y.InsCountDiff.CompareTo(x.InsCountDiff));
83 |
84 | int maxNameLength = 0;
85 | int maxInsCountDiffLength = 0;
86 | int maxInsPercentageDiffLength = 0;
87 | foreach (ref FunctionDiff diff in CollectionsMarshal.AsSpan(diffs))
88 | {
89 | maxNameLength = Math.Max(maxNameLength, diff.Name.Length);
90 | maxInsCountDiffLength = Math.Max(maxInsCountDiffLength, $"{diff.InsCountDiff}".Length);
91 | maxInsPercentageDiffLength = Math.Max(maxInsPercentageDiffLength, FormatPercentageDiff(diff.InsPercentageDiff).Length);
92 | }
93 |
94 | foreach (ref FunctionDiff diff in CollectionsMarshal.AsSpan(diffs))
95 | {
96 | output.WriteLine(
97 | $"{{0,-{maxNameLength}}} : {{1,-{maxInsCountDiffLength}}} : {{2,-{maxInsPercentageDiffLength}}} : {{3,-6:P2}} : {{4}}",
98 | diff.Name,
99 | diff.InsCountDiff,
100 | double.IsInfinity(diff.InsPercentageDiff) ? "NA" : FormatPercentageDiff(diff.InsPercentageDiff),
101 | diff.ContributionPercentage / 100,
102 | FormatPercentageDiff(diff.TotalInsPercentageDiff, "0000"));
103 | }
104 | }
105 |
106 | private Dictionary ParseTrace(string path)
107 | {
108 | Dictionary trace = new();
109 | foreach (string line in File.ReadLines(path))
110 | {
111 | Match match = _traceLineRegex.Match(line);
112 | if (match.Success)
113 | {
114 | trace.Add(match.Groups[2].Value, long.Parse(match.Groups[1].Value));
115 | }
116 | }
117 |
118 | return trace;
119 | }
120 |
121 | private static double GetPercentageDiff(double baseValue, double diffValue) =>
122 | (diffValue - baseValue) / baseValue * 100;
123 |
124 | private static string FormatPercentageDiff(double value, string precision = "00") =>
125 | (value > 0 ? "+" : "") + value.ToString($"0.{precision}") + "%";
126 |
127 | private static void Main(string[] args) =>
128 | new CommandLineConfiguration(new JitTpAnalyzeRootCommand().UseVersion()).Invoke(args);
129 |
130 | private struct FunctionDiff
131 | {
132 | public string Name;
133 | public long InsCountDiff;
134 | public double InsPercentageDiff;
135 | public double ContributionPercentage;
136 | public double TotalInsPercentageDiff;
137 | }
138 | }
139 |
140 | internal class JitTpAnalyzeRootCommand : RootCommand
141 | {
142 | public JitTpAnalyzeRootCommand() : base("Compare PIN-based throughput traces")
143 | {
144 | Options.Add(BasePath);
145 | Options.Add(DiffPath);
146 | Options.Add(Noise);
147 |
148 | SetAction(result =>
149 | {
150 | try
151 | {
152 | Program jitTpDiff = new(this, result);
153 | jitTpDiff.Run();
154 | }
155 | catch (Exception e)
156 | {
157 | Console.ResetColor();
158 | Console.ForegroundColor = ConsoleColor.Red;
159 | Console.Error.WriteLine("Error: " + e.Message);
160 | Console.Error.WriteLine(e.ToString());
161 | Console.ResetColor();
162 | return 1;
163 | }
164 |
165 | return 0;
166 | });
167 | }
168 |
169 | public Option BasePath { get; } =
170 | new("--base", "-b") { Description = "Base trace file", DefaultValueFactory = (_) => "basetp.txt" };
171 | public Option DiffPath { get; } =
172 | new("--diff", "-d") { Description = "Diff trace file", DefaultValueFactory = (_) => "difftp.txt" };
173 | public Option Noise { get; } =
174 | new("--noise", "-n") { Description = "Minimal contribution percentage for inclusion into the summary", DefaultValueFactory = (_) => 0.1 };
175 | }
176 |
--------------------------------------------------------------------------------
/src/jit-tp-analyze/README.md:
--------------------------------------------------------------------------------
1 | # jit-tp-analyze - throughput difference analysis tool
2 |
3 | jit-tp-analyze is a utility to parse traces generated by PIN-based
4 | instrumentation over runs of the JIT. The tool reads all lines in
5 | the following format from the two input files:
6 | ```
7 | :
8 | ```
9 | The tool ignores all lines that do not match this pattern and so can be
10 | run directly against superpmi.exe's usual output.
11 |
12 | The tool produces the following summary:
13 | ```
14 | Base: 1039322782, Diff: 1040078986, +0.0728%
15 |
16 | `Compiler::optCopyPropPushDef'::`2'::::operator() : 1073512 : NA : 18.17% : +0.1033%
17 | SsaBuilder::RenamePushDef : 911022 : NA : 15.42% : +0.0877%
18 | `Compiler::fgValueNumberLocalStore'::`2'::::operator() : 584435 : NA : 9.89% : +0.0562%
19 | Compiler::lvaLclExactSize : 244692 : +60.09% : 4.14% : +0.0235%
20 | ValueNumStore::VNForMapSelectWork : 87006 : +2.78% : 1.47% : +0.0084%
21 | GenTree::DefinesLocal : 82633 : +1.63% : 1.40% : +0.0080%
22 | Rationalizer::DoPhase : -91104 : -6.36% : 1.54% : -0.0088%
23 | Compiler::gtCallGetDefinedRetBufLclAddr : -115926 : -98.78% : 1.96% : -0.0112%
24 | Compiler::optBlockCopyProp : -272450 : -5.75% : 4.61% : -0.0262%
25 | Compiler::fgValueNumberLocalStore : -313540 : -50.82% : 5.31% : -0.0302%
26 | Compiler::GetSsaNumForLocalVarDef : -322826 : -100.00% : 5.46% : -0.0311%
27 | SsaBuilder::RenameDef : -478441 : -28.33% : 8.10% : -0.0460%
28 | Compiler::optCopyPropPushDef : -711380 : -55.34% : 12.04% : -0.0684%
29 | ```
30 | The columns, in order:
31 | 1. Method name.
32 | 2. The instruction count difference for the given function.
33 | 3. Same as `1`, but relative. May be `NA`, indicating the base didn't contain the given function, or `-100%` indicating the diff didn't.
34 | 4. Relative contribution to the diff. Calculated as `abs(instruction diff count) / sum-over-all-functions(abs(instruction diff count))`.
35 | 5. Relative difference, calculated as `instruction diff count / total base instruction count`.
36 |
37 | To use:
38 | 1. Obtain the base and diff traces, by compiling and running a PIN tool that counts instructions retired for each function.
39 | 2. Invoke `./jit-tp-analyze --base base-trace.txt --diff diff-trace.txt`.
40 |
41 | For convenience, both arguments have default values: `basetp.txt` for `--base`, `difftp.txt` for `--diff`, and so can be omitted.
42 |
43 | By default, the tool will hide functions that contributed less than `0.1%` to the difference. You can change this value with the `--noise` argument.
44 |
--------------------------------------------------------------------------------
/src/jit-tp-analyze/jit-tp-analyze.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/mutate-test/MutateTestRootCommand.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.CommandLine;
7 |
8 | namespace MutateTest
9 | {
10 | internal sealed class MutateTestRootCommand : CliRootCommand
11 | {
12 | public CliArgument InputFilePath { get; } =
13 | new("input-test-case") { Description = "Input test case file or directory (for --recursive)", Arity = ArgumentArity.OneOrMore };
14 | public CliOption EHStress { get; } =
15 | new("--ehStress") { Description = "Add EH to methods" };
16 | public CliOption StructStress { get; } =
17 | new("--structStress") { Description = "Replace locals with structs" };
18 | public CliOption ShowResults { get; } =
19 | new("--showResults") { Description = "Add EH to methods" };
20 | public CliOption Verbose { get; } =
21 | new("--verbose") { Description = "Describe each transformation" };
22 | public CliOption Quiet { get; } =
23 | new("--quiet") { Description = "Produce minimal output" };
24 | public CliOption Recursive { get; } =
25 | new("--recursive") { Description = "Process each file recursively" };
26 | public CliOption Seed { get; } =
27 | new("--seed") { DefaultValueFactory = _ => 42, Description = "Random seed" };
28 | public CliOption StopAtFirstFailure { get; } =
29 | new("--stopAtFirstFailure") { Description = "Stop each test at first failure" };
30 | public CliOption EmptyBlocks { get; } =
31 | new("--emptyBlocks") { Description = "Transform empty blocks" };
32 | public CliOption SizeLimit { get; } =
33 | new("--sizeLimit") { DefaultValueFactory = _ => 10000, Description = "Don't process programs larger than this size" };
34 | public CliOption TimeLimit { get; } =
35 | new("--timeLimit") { DefaultValueFactory = _ => 10000, Description = "Don't stress programs where compile + run takes more than this many milliseconds" };
36 | public CliOption Projects { get; } =
37 | new("--projects") { Description = "Look for .csproj files instead of .cs files when doing recursive exploration" };
38 | public CliOption OnlyFailures { get; } =
39 | new("--onlyFailures") { Description = "Only emit output for cases that fail at runtime" };
40 |
41 | public ParseResult Result { get; private set; }
42 |
43 | public MutateTestRootCommand(string[] args) : base(".NET JIT mutate test utility")
44 | {
45 | Arguments.Add(InputFilePath);
46 | Options.Add(EHStress);
47 | Options.Add(StructStress);
48 | Options.Add(ShowResults);
49 | Options.Add(Verbose);
50 | Options.Add(Quiet);
51 | Options.Add(Recursive);
52 | Options.Add(Seed);
53 | Options.Add(StopAtFirstFailure);
54 | Options.Add(EmptyBlocks);
55 | Options.Add(SizeLimit);
56 | Options.Add(TimeLimit);
57 | Options.Add(Projects);
58 | Options.Add(OnlyFailures);
59 |
60 | SetAction(result =>
61 | {
62 | Result = result;
63 |
64 | try
65 | {
66 | return new Program(this).Run();
67 | }
68 | catch (Exception e)
69 | {
70 | Console.ResetColor();
71 | Console.ForegroundColor = ConsoleColor.Red;
72 |
73 | Console.Error.WriteLine("Error: " + e.Message);
74 | Console.Error.WriteLine(e.ToString());
75 |
76 | Console.ResetColor();
77 |
78 | return 1;
79 | }
80 | });
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/mutate-test/mutate-test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Exe
7 | net6.0
8 | Mutate
9 | Mutate
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/performance-explorer/README.md:
--------------------------------------------------------------------------------
1 | ### Performance Explorer
2 |
3 | Performance Explorer is a tool to examine the impact of changing JIT behavior on key methods in a benchmark.
4 | It is currently specialized to explore varying the CSEs in the most dominant Tier-1 method of a benchmark.
5 |
6 | ### Setup
7 |
8 | This tool currently only works on Windows.
9 |
10 | To run Performance Explorer, you must have local enlistments of:
11 | * [the runtime repo](https://github.com/dotnet/runtime)
12 | * [the performance repo](https://github.com/dotnet/performance)
13 | * [instructions retired explorer](https://github.com/AndyAyersMS/InstructionsRetiredExplorer)
14 |
15 | You will need to do both release and checked builds of the runtime repo, and create the associated
16 | test directories (aka Core_Roots).
17 |
18 | You will need to build the instructions retired explorer.
19 |
20 | You will need to modify file paths in the performance explorer code to refer to the locations
21 | of the above repos and builds, an to specify a results directory.
22 |
23 | Finally, you will likely want to customize the list of benchmarks to explore; the names of these
24 | are the names used in the performance repo. Note the names often contain quotes or other special
25 | characters so you will likely need to read up on how to handle these when they appear in C# literal strings.
26 |
27 | Once you have made these modifications, you can then build the performance explorer.
28 |
29 | The tool must be run as admin, in order to perform the necessary profiling.
30 |
31 | ### How It Works
32 |
33 | For each benchmark in the list, performance explorer will:
34 | * run the benchmark from the perf directory, with `-p ETW` so that profile data is collected
35 | * parse the profile data using instructions retired explorer to find the hot methods
36 | * also parse the BenchmarkDotNet json to determine the performance of the benchmark
37 | * determine if there's a hot method that would be a good candidate for exploration. Currently we look for a Tier-1 method that accounts for at least 20% of the benchmark time.
38 | * if there is a suitable hot method:
39 | * run an SPMI collection for that benchmark
40 | * use that SPMI to get an assembly listing for the hot method
41 | * determine from that listing how many CSEs were performed (the "default set" of N CSEs)
42 | * if there were any CSEs, start the experimentation process:
43 | * run the benchmark with all CSEs disabled (0 CSEs), and measure perf. Add to the exploration queue.
44 | * then, repeatedly, until we have run out of experiment to try, or hit some predetermined limit
45 | * pick the best performing experiment from the queue
46 | * Determine which CSEs in the default set were not done in the experiment. Say there are M (<=N) of these
47 | * Run M more experiments, each adding one of the missing CSEs
48 |
49 | Each benchmark's data is stored in a subfolder in the results directory; we also create disassembly for all the
50 | experiments tried, and copies of all the intermediate files.
51 |
52 | There is also a master results.csv that has data from all experiments in all benchmarks, suitable for use
53 | in excel or as input to a machine learning algorithm.
54 |
55 | If you re-run the tool with the same benchmark list and results directory, it will use the cached copies of
56 | data and won't re-run the experiments.
57 |
58 | If along the way anything goes wrong then an "error.txt" file is added to the results subdirectory for
59 | that benchmark, and future runs will skip that benchmark.
60 |
61 | So say there are 2 CSEs by default. The explorer will run:
62 | * one experiment with 0 CSEs
63 | * two experiments each with 1 CSE
64 | * one experiment with 2 CSEs
65 | and then stop as all possibilities have been explored.
66 |
67 | For larger values of N the number of possible experiments 2^N grows rapidly and we cannot hope to explore
68 | the full space. The exploration process is intended to prioritize for those experiments that likely have
69 | the largest impact on performance.
70 |
71 | ### Future Enhancements
72 |
73 | * add option to offload benchmark runs to the perf lab
74 | * capture more details about CSEs so we can use the data to develop better CSE heuristics
75 | * generalize the experiment processing to allow other kinds of experiments
76 | * parameterize the config settings so we don't need to modify the sources
77 | * add options to characterize the noise level of benchmarks and (perhaps) do more runs if noisy
78 | * leverage SPMI instead of perf runs, if we can trust perf scores
79 |
80 |
--------------------------------------------------------------------------------
/src/performance-explorer/benchmark-info.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.IO;
6 | using System;
7 |
8 | public class BenchmarkInfo
9 | {
10 | public string Name { get; init; }
11 | public double Ratio { get; set; }
12 |
13 | public string CleanName
14 | {
15 | get
16 | {
17 | string cleanName = Name;
18 | if (cleanName.Length > 100)
19 | {
20 | int parensIndex = cleanName.IndexOf('(');
21 | static string Last(string s, int num) => s.Length < num ? s : s[^num..];
22 | if (parensIndex == -1)
23 | {
24 | cleanName = Last(cleanName, 100);
25 | }
26 | else
27 | {
28 | string benchmarkName = cleanName[..parensIndex];
29 | string paramsStr = cleanName[(parensIndex + 1)..^1];
30 | cleanName = Last(benchmarkName, Math.Max(50, 100 - paramsStr.Length)) + "(" + Last(paramsStr, Math.Max(50, 100 - benchmarkName.Length)) + ")";
31 | }
32 | }
33 |
34 | foreach (char illegalChar in Path.GetInvalidFileNameChars())
35 | {
36 | cleanName = cleanName.Replace(illegalChar, '_');
37 | }
38 |
39 | cleanName = cleanName.Replace(' ', '_');
40 |
41 | return cleanName;
42 | }
43 | }
44 |
45 | public string CsvName => CleanName.Replace(',', '_');
46 |
47 | }
--------------------------------------------------------------------------------
/src/performance-explorer/benchmark-json.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | // Classes for deserializing BenchmarkDotNet .json result files
6 |
7 | using System;
8 | using System.Collections.Generic;
9 | using System.IO;
10 | using System.Text.Json;
11 |
12 | public class ChronometerFrequency
13 | {
14 | public int Hertz { get; set; }
15 | }
16 |
17 | public class HostEnvironmentInfo
18 | {
19 | public string BenchmarkDotNetCaption { get; set; }
20 | public string BenchmarkDotNetVersion { get; set; }
21 | public string OsVersion { get; set; }
22 | public string ProcessorName { get; set; }
23 | public int? PhysicalProcessorCount { get; set; }
24 | public int? PhysicalCoreCount { get; set; }
25 | public int? LogicalCoreCount { get; set; }
26 | public string RuntimeVersion { get; set; }
27 | public string Architecture { get; set; }
28 | public bool? HasAttachedDebugger { get; set; }
29 | public bool? HasRyuJit { get; set; }
30 | public string Configuration { get; set; }
31 | public string JitModules { get; set; }
32 | public string DotNetCliVersion { get; set; }
33 | public ChronometerFrequency ChronometerFrequency { get; set; }
34 | public string HardwareTimerKind { get; set; }
35 | }
36 |
37 | public class ConfidenceInterval
38 | {
39 | public int N { get; set; }
40 | public double Mean { get; set; }
41 | public double StandardError { get; set; }
42 | public int Level { get; set; }
43 | public double Margin { get; set; }
44 | public double Lower { get; set; }
45 | public double Upper { get; set; }
46 | }
47 |
48 | public class Percentiles
49 | {
50 | public double P0 { get; set; }
51 | public double P25 { get; set; }
52 | public double P50 { get; set; }
53 | public double P67 { get; set; }
54 | public double P80 { get; set; }
55 | public double P85 { get; set; }
56 | public double P90 { get; set; }
57 | public double P95 { get; set; }
58 | public double P100 { get; set; }
59 | }
60 |
61 | public class Statistics
62 | {
63 | public double[] OriginalValues { get; set; }
64 | public int N { get; set; }
65 | public double Min { get; set; }
66 | public double LowerFence { get; set; }
67 | public double Q1 { get; set; }
68 | public double Median { get; set; }
69 | public double Mean { get; set; }
70 | public double Q3 { get; set; }
71 | public double UpperFence { get; set; }
72 | public double Max { get; set; }
73 | public double InterquartileRange { get; set; }
74 | public List LowerOutliers { get; set; }
75 | public List UpperOutliers { get; set; }
76 | public List AllOutliers { get; set; }
77 | public double StandardError { get; set; }
78 | public double Variance { get; set; }
79 | public double StandardDeviation { get; set; }
80 | public double? Skewness { get; set; }
81 | public double? Kurtosis { get; set; }
82 | public ConfidenceInterval ConfidenceInterval { get; set; }
83 | public Percentiles Percentiles { get; set; }
84 | }
85 |
86 | public class Memory
87 | {
88 | public int Gen0Collections { get; set; }
89 | public int Gen1Collections { get; set; }
90 | public int Gen2Collections { get; set; }
91 | public long TotalOperations { get; set; }
92 | public long BytesAllocatedPerOperation { get; set; }
93 | }
94 |
95 | public class Measurement
96 | {
97 | public string IterationStage { get; set; }
98 | public int LaunchIndex { get; set; }
99 | public int IterationIndex { get; set; }
100 | public long Operations { get; set; }
101 | public double Nanoseconds { get; set; }
102 | }
103 |
104 | public class Metric
105 | {
106 | public double Value { get; set; }
107 | public MetricDescriptor Descriptor { get; set; }
108 | }
109 |
110 | public class MetricDescriptor
111 | {
112 | public string Id { get; set; }
113 | public string DisplayName { get; set; }
114 | public string Legend { get; set; }
115 | public string NumberFormat { get; set; }
116 | public int UnitType { get; set; }
117 | public string Unit { get; set; }
118 | public bool TheGreaterTheBetter { get; set; }
119 | public int PriorityInCategory { get; set; }
120 | }
121 |
122 | public class Benchmark
123 | {
124 | public string DisplayInfo { get; set; }
125 | public string Namespace { get; set; }
126 | public string Type { get; set; }
127 | public string Method { get; set; }
128 | public string MethodTitle { get; set; }
129 | public string Parameters { get; set; }
130 | public string FullName { get; set; }
131 | public Statistics Statistics { get; set; }
132 | public Memory Memory { get; set; }
133 | public List Measurements { get; set; }
134 | public List Metrics { get; set; }
135 | }
136 |
137 | public class BdnResult
138 | {
139 | public string Title { get; set; }
140 | public HostEnvironmentInfo HostEnvironmentInfo { get; set; }
141 | public List Benchmarks { get; set; }
142 | }
143 |
144 | public class BdnParser
145 | {
146 | // Return performance of this benchmark (in microseconds)
147 | public static double GetPerf(string bdnJsonFile)
148 | {
149 | double perf = 0;
150 | string bdnJsonLines = File.ReadAllText(bdnJsonFile);
151 | BdnResult bdnResult = JsonSerializer.Deserialize(bdnJsonLines)!;
152 |
153 | // Assume all runs are for the same benchmark
154 | // Handle possibility of multiple runs (via --LaunchCount)
155 | //
156 | foreach (Benchmark b in bdnResult.Benchmarks)
157 | {
158 | double sum = 0;
159 | long ops = 0;
160 |
161 | foreach (Measurement m in b.Measurements)
162 | {
163 | if (!m.IterationStage.Equals("Result"))
164 | {
165 | continue;
166 | }
167 |
168 | sum += m.Nanoseconds;
169 | ops += m.Operations;
170 | }
171 |
172 | perf = (sum / ops) / 1000;
173 | }
174 |
175 | return perf;
176 | }
177 | }
--------------------------------------------------------------------------------
/src/performance-explorer/cse-experiment.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 |
6 | using PerformanceExplorer;
7 | using System.Globalization;
8 | using System.IO;
9 | using System.Text.Json;
10 | using System;
11 | using System.Xml.Serialization;
12 |
13 | public class CseExperiment
14 | {
15 | public BenchmarkInfo Benchmark { get; set; }
16 | public CseExperiment Baseline { get; set; }
17 | public HotFunction Method { get; set; }
18 | public uint Mask { get; set; }
19 | public uint NumCse { get; set; }
20 | public uint CodeSize { get; set; }
21 | public double PerfScore { get; set; }
22 | public double Perf { get; set; }
23 | public bool Explored { get; set; }
24 |
25 | public string Hash { get; set; }
26 |
27 | public uint Index { get; set; }
28 |
29 | public bool IsImprovement { get { return Perf < Baseline.Perf; } }
30 |
31 | public static string Schema
32 | {
33 | get
34 | {
35 | return "Benchmark,Index,Mask,NumCse,CodeSize,PerfScore,PerfScoreRatio,Perf,PerfRatio";
36 | }
37 | }
38 |
39 | public string Info
40 | {
41 | get
42 | {
43 | double perfRatio = (Baseline == null) ? 1.0 : Perf / Baseline.Perf;
44 | double perfScoreRatio = (Baseline == null) ? 1.0 : PerfScore / Baseline.PerfScore;
45 | return $"{Benchmark.CsvName},{Index},{Mask:x8},{NumCse},{CodeSize},{PerfScore:F2},{perfScoreRatio:F3},{Perf:F4},{perfRatio:F3}";
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/src/performance-explorer/hot-function.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using System.IO;
7 | using System.Text;
8 |
9 | public class HotFunction
10 | {
11 | public double Fraction { get; set; }
12 | public string CodeType { get; set; }
13 | public string Name { get; set; }
14 |
15 | string disasmName;
16 | string friendlyName;
17 |
18 | public string DisasmName { get { SetNames(); return disasmName; } }
19 | public string FriendlyName { get { SetNames(); return friendlyName; } }
20 |
21 | void SetNames()
22 | {
23 | int classNameStart = Name.IndexOf(']') + 1;
24 | int classInstantiationStart = Name.IndexOf('[', classNameStart); // skip module name
25 | // Remove all instantiations, module name, and parameters
26 | string name = RemoveMatched(Name, '(', ')');
27 | name = RemoveMatched(name, '[', ']');
28 |
29 | int lastDot = name.LastIndexOf('.');
30 | while (name[lastDot - 1] == '.')
31 | {
32 | lastDot--;
33 | }
34 | string methodName = name[(lastDot + 1)..];
35 | string className = name[..lastDot];
36 | if (classInstantiationStart != -1 && classInstantiationStart < lastDot)
37 | {
38 | className = Name[classNameStart..classInstantiationStart];
39 | }
40 | disasmName = $"*{className}:*{methodName}";
41 | friendlyName = $"{className}.{methodName}";
42 | }
43 |
44 | private static string RemoveMatched(string text, char open, char close)
45 | {
46 | StringBuilder newString = new StringBuilder(text.Length);
47 | int nest = 0;
48 | for (int i = 0; i < text.Length; i++)
49 | {
50 | if (text[i] == open)
51 | {
52 | nest++;
53 | }
54 | else if (nest > 0 && text[i] == close)
55 | {
56 | nest--;
57 | }
58 | else if (nest == 0)
59 | {
60 | newString.Append(text[i]);
61 | }
62 | }
63 |
64 | return newString.ToString();
65 | }
66 |
67 | public string DasmFileName
68 | {
69 | get
70 | {
71 | string fileName = FriendlyName + ".dasm";
72 | foreach (char illegalChar in Path.GetInvalidFileNameChars())
73 | fileName = fileName.Replace(illegalChar, '_');
74 | fileName = fileName.Replace(' ', '_');
75 | return fileName;
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/src/performance-explorer/performance-explorer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Exe
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/pmi/JITDecisionEventListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.Tracing;
4 |
5 | namespace pmi
6 | {
7 | internal class JITDecisionEventListener : EventListener
8 | {
9 | // We cannot use a parameter to this event listener because
10 | // EventListener constructor calls OnEventWritten, which will happen
11 | // before we have been able to run our own constructor.
12 | internal static readonly HashSet s_enabledEvents = new HashSet();
13 |
14 | protected override void OnEventSourceCreated(EventSource eventSource)
15 | {
16 | if (eventSource.Name != "Microsoft-Windows-DotNETRuntime")
17 | return;
18 |
19 | EventKeywords jitTracing = (EventKeywords)0x1000; // JITTracing
20 | EnableEvents(eventSource, EventLevel.Verbose, jitTracing);
21 | }
22 |
23 | protected override void OnEventWritten(EventWrittenEventArgs data)
24 | {
25 | if (!s_enabledEvents.Contains(data.EventName))
26 | return;
27 |
28 | List dataStrings = new List { data.EventName };
29 |
30 | for (int i = 0; i < data.Payload.Count; i++)
31 | {
32 | dataStrings.Add(data.PayloadNames[i]);
33 | dataStrings.Add(data.Payload[i] != null ? data.Payload[i].ToString() : "");
34 | }
35 |
36 | // Log payload separated by @!@!@. This is somewhat ugly, but easy enough to parse
37 | // and avoids pulling in a dependency here.
38 | Console.WriteLine("JITTracing: {0}", string.Join("@!@!@", dataStrings));
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/pmi/pmi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/pmi/readme.md:
--------------------------------------------------------------------------------
1 | # PMI - use Prepare Method (Instantiation) to jit all methods in an assembly
2 |
3 | PMI uses reflection to locate all the types in an assembly and all methods
4 | each type. Then it calls `PrepareMethod` on each method in turn.
5 |
6 | This gives us the ability to look at the code the jit will generate for a large
7 | number of methods without needing to have test cases that call the methods. So
8 | it is very useful for doing widespread jit-time testing and analysis of jit
9 | codegen.
10 |
11 | The methods jitted are not called, so PMI is not as useful for finding bugs in
12 | the jit-generated code.
13 |
14 | This initial commit is a preliminary port of the PMI tool we have developed for
15 | .Net Framework testing. Over time we'll improve it and adapt it better for use
16 | with .Net Core.
17 |
18 | Improvements to come:
19 | * proper subprocess launching for core
20 | * integrated support for alt jits and/or alternate codegen modes
21 | * jitting of methods in generic types
22 | * jitting of generic methods
23 | * support for corelib
24 | * (possibly) the ability to fetch code via nuget
25 | * integration into jit-diffs
26 |
27 |
--------------------------------------------------------------------------------
/src/superpmi/superpmicollect.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/target-framework.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | net8.0
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/util/CommandLineHelpers.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System.CommandLine;
6 | using System.CommandLine.Parsing;
7 | using System.IO;
8 |
9 | public static class Helpers
10 | {
11 | public static RootCommand UseVersion(this RootCommand command)
12 | {
13 | for (int i = 0; i < command.Options.Count; i++)
14 | {
15 | if (command.Options[i] is VersionOption)
16 | {
17 | command.Options[i] = new VersionOption("--version", "-v");
18 | break;
19 | }
20 | }
21 |
22 | return command;
23 | }
24 |
25 | #nullable enable
26 | public static string? GetResolvedPath(ArgumentResult result) =>
27 | result.Tokens.Count > 0 ? Path.GetFullPath(result.Tokens[0].Value) : null;
28 | #nullable disable
29 | }
30 |
--------------------------------------------------------------------------------
/test/jit-analyze/baseline1.out:
--------------------------------------------------------------------------------
1 | No diffs found.
2 |
--------------------------------------------------------------------------------
/test/jit-analyze/baseline2.out:
--------------------------------------------------------------------------------
1 | Found files with textual diffs.
2 |
3 | Summary:
4 | (Note: Lower is better)
5 |
6 | Total bytes of diff: 0
7 |
8 | 0 total files with size differences.
9 |
10 | Top method regessions by size (bytes):
11 | 2 : test2.dasm - DomainNeutralILStubClass:IL_STUB_ReversePInvoke(long,int,ubyte,long,long,long,long)
12 |
13 | Top method improvements by size (bytes):
14 | -2 : test2.dasm - System.ArraySegment`1[__Canon][System.__Canon]:System.Collections.Generic.IReadOnlyList.get_Item(int):ref:this
15 |
16 | 2 total methods with size differences.
17 |
--------------------------------------------------------------------------------
/test/jit-analyze/baseline3.out:
--------------------------------------------------------------------------------
1 | Found files with textual diffs.
2 |
3 | Summary:
4 | (Note: Lower is better)
5 |
6 | Total bytes of diff: -26
7 | diff is an improvement.
8 |
9 | Top file improvements by size (bytes):
10 | -26 : test3.dasm
11 |
12 | 1 total files with size differences.
13 |
14 | Top method regessions by size (bytes):
15 | 6 : test3.dasm - System.ArraySegment`1[__Canon][System.__Canon]:System.Collections.Generic.IReadOnlyList.get_Item(int):ref:this
16 | 2 : test2.dasm - DomainNeutralILStubClass:IL_STUB_ReversePInvoke(long,int,ubyte,long,long,long,long)
17 |
18 | Top method improvements by size (bytes):
19 | -18 : test3.dasm - DomainNeutralILStubClass:IL_STUB_PInvoke(int):int
20 | -6 : test3.dasm - DomainNeutralILStubClass:IL_STUB_PInvoke(ref,ref):bool
21 | -3 : test3.dasm - Microsoft.Win32.SafeHandles.SafeFileHandle:.ctor():this
22 | -2 : test3.dasm - Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid:get_IsInvalid():bool:this
23 | -2 : test3.dasm - DomainNeutralILStubClass:IL_STUB_PInvoke(long,int,long,long):int
24 |
25 | 9 total methods with size differences.
26 |
--------------------------------------------------------------------------------
/test/jit-analyze/runtest.sh:
--------------------------------------------------------------------------------
1 | # Run analysis tool with indentical input and ensure that we get no diffs.
2 |
3 | if jit-analyze --base ./base/test1.dasm --diff ./diff/test1.dasm > test1.out; then
4 | echo "Test1: Passed null diff test"
5 | else
6 | echo "Test1: Failed"
7 | fi
8 |
9 | if diff ./test1.out ./baseline1.out; then
10 | echo "Test1: Passed baseline check"
11 | else
12 | echo "Test1: Failed baseline check"
13 | fi
14 |
15 | jit-analyze --base ./base/test2.dasm --diff ./diff/test2.dasm > test2.out
16 | RESULT=$?
17 | #echo $RESULT
18 | if [ $RESULT == 0 ]; then
19 | echo "Test2: Passed diff command"
20 | else
21 | echo "Test2: Failed"
22 | fi
23 |
24 | if diff ./test2.out ./baseline2.out; then
25 | echo "Test2: Passed baseline check"
26 | else
27 | echo "Test2: Failed baseline check"
28 | fi
29 |
30 | jit-analyze --base ./base --diff ./diff > test3.out
31 | RESULT=$?
32 | #echo $RESULT
33 | if [ $RESULT == 26 ]; then
34 | echo "Test3: Passed diff command"
35 | else
36 | echo "Test3: Failed"
37 | fi
38 |
39 | if diff ./test3.out ./baseline3.out; then
40 | echo "Test3: Passed baseline check"
41 | else
42 | echo "Test3: Failed baseline check"
43 | fi
--------------------------------------------------------------------------------
/test/jit-dasm/runtest.sh:
--------------------------------------------------------------------------------
1 | # Runs a set of simple tests to validate that JITDASM is working
2 | #
3 | # Required input is a path to a single built CoreCLR repo as well as
4 | # the built JITDASM executable.
5 | #
6 | # Tests will run through the simple scenarios to ensure that the flags work,
7 | # as well as output structure being laid out as expected.
8 | #
9 |
10 | # Test 1: Run JITDASM with the same crossgen to verify that --base, --diff
11 | # work with --frameworks and that the output is generated with the correct
12 | # 'base' and 'diff' tags.
13 |
14 | #set -x #echo on
15 |
16 | # Process the incoming arguments and extract the location info needed.
17 |
18 | while getopts :d:c:o: opt; do
19 | case $opt in
20 | d)
21 | JITDASM=$OPTARG
22 | ;;
23 | o)
24 | OUTPUT=$OPTARG
25 | ;;
26 | c)
27 | CROSSGEN=$OPTARG
28 | ;;
29 | :)
30 | echo "-$OPTARG requires an argument"
31 | exit -1
32 | ;;
33 | esac
34 | done
35 |
36 | # Test that we have the needed info to run the test.
37 |
38 | if [ -z "$JITDASM" ]; then
39 | echo "Missing JITDASM path."
40 | exit -1
41 | fi
42 |
43 | if [ -z "$CROSSGEN" ]; then
44 | echo "Missing crossgen path."
45 | exit -1
46 | fi
47 |
48 | if [ -z "$OUTPUT" ]; then
49 | echo "Missing output."
50 | exit -1
51 | fi
52 |
53 | # Create disasm of mscorlib in base/diff form.
54 |
55 | echo Running: $JITDASM --base $CROSSGEN --diff $CROSSGEN --output $OUTPUT ${CROSSGEN%/*}/mscorlib.dll
56 |
57 | if ! $JITDASM --base $CROSSGEN --diff $CROSSGEN --output $OUTPUT ${CROSSGEN%/*}/mscorlib.dll; then
58 | echo "Error! Managed code gen diff failed to generate disasm."
59 | exit -1
60 | fi
61 |
62 | # test that output has 'base' and 'diff' and
63 | # that mscorlib.dasm appears.
64 |
65 | if ! ls $OUTPUT/base/mscorlib.dasm; then
66 | echo "missing base disasm!"
67 | exit -1
68 | fi
69 |
70 | if ! ls $OUTPUT/diff/mscorlib.dasm; then
71 | echo "missing diff disasm!"
72 | exit -1
73 | fi
74 |
75 | # verify that mscorlib.dasm is nodiff.
76 |
77 | if ! diff $OUTPUT/diff/mscorlib.dasm $OUTPUT/base/mscorlib.dasm; then
78 | echo "Error! Found differences."
79 | exit -1
80 | fi
81 |
82 | echo $JITDASM passed validation.
--------------------------------------------------------------------------------
/test/jit-format/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | Language: Cpp
3 | AccessModifierOffset: -4
4 | AlignAfterOpenBracket: Align
5 | AlignConsecutiveAssignments: true
6 | AlignConsecutiveDeclarations: true
7 | AlignEscapedNewlinesLeft: false
8 | AlignOperands: true
9 | AlignTrailingComments: true
10 | AllowAllParametersOfDeclarationOnNextLine: true
11 | AllowShortBlocksOnASingleLine: false
12 | AllowShortCaseLabelsOnASingleLine: false
13 | AllowShortFunctionsOnASingleLine: Empty
14 | AllowShortIfStatementsOnASingleLine: false
15 | AllowShortLoopsOnASingleLine: false
16 | AlwaysBreakAfterDefinitionReturnType: None
17 | AlwaysBreakBeforeMultilineStrings: false
18 | AlwaysBreakTemplateDeclarations: true
19 | BinPackArguments: true
20 | BinPackParameters: false
21 | BraceWrapping:
22 | AfterClass: true
23 | AfterControlStatement: true
24 | AfterEnum: false
25 | AfterFunction: true
26 | AfterNamespace: false
27 | AfterObjCDeclaration: false
28 | AfterStruct: true
29 | AfterUnion: true
30 | BeforeCatch: true
31 | BeforeElse: true
32 | IndentBraces: false
33 | BreakBeforeBinaryOperators: None
34 | BreakBeforeBraces: Allman
35 | BreakBeforeTernaryOperators: true
36 | BreakConstructorInitializersBeforeComma: false
37 | ColumnLimit: 120
38 | CommentPragmas: '^ IWYU pragma:'
39 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
40 | ConstructorInitializerIndentWidth: 4
41 | ContinuationIndentWidth: 4
42 | Cpp11BracedListStyle: true
43 | DerivePointerAlignment: false
44 | DisableFormat: false
45 | ExperimentalAutoDetectBinPacking: false
46 | ForEachMacros: [ ]
47 | IndentCaseLabels: true
48 | IndentWidth: 4
49 | IndentWrappedFunctionNames: false
50 | KeepEmptyLinesAtTheStartOfBlocks: true
51 | MacroBlockBegin: ''
52 | MacroBlockEnd: ''
53 | MaxEmptyLinesToKeep: 1
54 | NamespaceIndentation: None
55 | ObjCBlockIndentWidth: 2
56 | ObjCSpaceAfterProperty: false
57 | ObjCSpaceBeforeProtocolList: true
58 | PenaltyBreakBeforeFirstCallParameter: 400
59 | PenaltyBreakComment: 50
60 | PenaltyBreakFirstLessLess: 500
61 | PenaltyBreakString: 1000
62 | PenaltyExcessCharacter: 1000000
63 | PenaltyReturnTypeOnItsOwnLine: 100000
64 | PointerAlignment: Left
65 | ReflowComments: true
66 | SortIncludes: false
67 | SpaceAfterCStyleCast: false
68 | SpaceBeforeAssignmentOperators: true
69 | SpaceBeforeParens: ControlStatements
70 | SpaceInEmptyParentheses: false
71 | SpacesBeforeTrailingComments: 1
72 | SpacesInAngles: false
73 | SpacesInContainerLiterals: true
74 | SpacesInCStyleCastParentheses: false
75 | SpacesInParentheses: false
76 | SpacesInSquareBrackets: false
77 | Standard: Cpp11
78 | TabWidth: 4
79 | UseTab: Never
80 | ...
81 |
--------------------------------------------------------------------------------
/test/jit-format/runtest.cmd:
--------------------------------------------------------------------------------
1 | rem Run jit-format tool on test.cpp and compare the output to test-fixed.cpp
2 |
3 | setlocal
4 |
5 | set testroot=%~dp0
6 | set testrootReplace=%testroot:\=/%
7 | set jitUtilsBin=%testroot%\..\..\bin
8 |
9 | copy test.cpp test-pre.cpp
10 |
11 | echo [> %testroot%\compile_commands.json
12 | echo {>> %testroot%\compile_commands.json
13 | echo "directory": "%testrootReplace%",>> %testroot%\compile_commands.json
14 | echo "command": "cl.exe %testrootReplace%test.cpp",>> %testroot%\compile_commands.json
15 | echo "file": "%testrootReplace%test.cpp">> %testroot%\compile_commands.json
16 | echo }>> %testroot%\compile_commands.json
17 | echo ]>> %testroot%\compile_commands.json
18 |
19 | rem Because we specified full paths, we will ignore the --coreclr argument, but it is required
20 | call %jitUtilsBin%\jit-format.cmd --fix --compile-commands %testroot%\compile_commands.json --coreclr %testroot% %testroot%\test.cpp
21 |
22 | timeout 1 > NUL
23 |
24 | fc test.cpp test-fixed.cpp
25 |
26 | if "%errorlevel%" == "0" (
27 | echo Test Passed
28 | ) else (
29 | echo Test Failed
30 | )
31 |
32 | move /Y test-pre.cpp test.cpp
33 |
--------------------------------------------------------------------------------
/test/jit-format/test-fixed.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | // This is a really long comment that needs to be reflowed. Clang-format should take care of this for us. This function
5 | // is just a test for the code below.
6 | static void testFunction(int* ptr)
7 | {
8 | if (ptr)
9 | {
10 | printf("You passed a pointer!\n");
11 | }
12 | else
13 | {
14 | printf("You passed a nullptr!\n");
15 | }
16 | }
17 |
18 | int main(void)
19 | {
20 | int i;
21 |
22 | // clang-tidy should insert braces in the below for loop. clang-format should removed the spaces above, and move the
23 | // braces clang-tidy adds below to the following line and re-indent them. Clang-formatting should fix all of the
24 | // indentation in this function.
25 | for (i = 0; i < 3; i++)
26 | {
27 | printf("Hello World!\n");
28 | }
29 |
30 | // clang-tidy should replace both of these instances with nullptr.
31 | testFunction(nullptr);
32 | testFunction(nullptr);
33 |
34 | return 0;
35 | }
36 |
--------------------------------------------------------------------------------
/test/jit-format/test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | // This is a really long comment that needs to be reflowed. Clang-format should take care of this for us. This function is just a test for the code below.
5 | static void testFunction(int* ptr)
6 | {
7 | if (ptr)
8 | printf("You passed a pointer!\n");
9 | else
10 | printf("You passed a nullptr!\n");
11 | }
12 |
13 | int main(void)
14 | {
15 | int i;
16 |
17 | // clang-tidy should insert braces in the below for loop. clang-format should removed the spaces above, and move the
18 | // braces clang-tidy adds below to the following line and re-indent them. Clang-formatting should fix all of the
19 | // indentation in this function.
20 | for (i = 0; i < 3; i++)
21 | printf("Hello World!\n");
22 |
23 | // clang-tidy should replace both of these instances with nullptr.
24 | testFunction(NULL);
25 | testFunction(0);
26 |
27 | return 0;
28 | }
29 |
--------------------------------------------------------------------------------