summaryrefslogtreecommitdiff
path: root/Documentation/building/viewing-jit-dumps.md
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/building/viewing-jit-dumps.md')
-rw-r--r--Documentation/building/viewing-jit-dumps.md173
1 files changed, 173 insertions, 0 deletions
diff --git a/Documentation/building/viewing-jit-dumps.md b/Documentation/building/viewing-jit-dumps.md
new file mode 100644
index 0000000000..5303b47626
--- /dev/null
+++ b/Documentation/building/viewing-jit-dumps.md
@@ -0,0 +1,173 @@
+# Viewing JIT Dumps
+
+This document is intended for people interested in seeing the disassembly, GC info, or other details the JIT generates for a managed program.
+
+To make sense of the results, it is recommended you also read the [Reading a JitDump](../botr/ryujit-overview.md#reading-a-jitdump) section of the RyuJIT Overview.
+
+## Setting up our environment
+
+The first thing we want to do is setup the .NET Core app we want to dump. Here are the steps to do this, if you don't have one ready:
+
+* Perform a debug build of the CoreCLR repo
+* Install the [.NET CLI](http://microsoft.com/net/core), which we'll use to compile/publish our app
+* `cd` to where you want your app to be placed, and run `dotnet new`
+* Modify your `project.json` file so that it contains a RID (runtime ID) corresponding to the OS you're using in the `runtimes` section. For example, I have a Windows 10 x64 machine, so here's my project file:
+
+```json
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "Microsoft.NETCore.App": "1.0.0-*"
+ },
+ "frameworks": {
+ "netcoreapp1.0": {
+ "imports": [
+ "dnxcore50",
+ "portable-net45+win8"
+ ]
+ }
+ },
+ "runtimes": {
+ "win10-x64": {}
+ }
+}
+```
+
+You can find a list of RIDs and their corresponding OSes [here](http://dotnet.github.io/docs/core-concepts/rid-catalog.html).
+
+* Edit `Program.cs`, and call the method(s) you want to dump in there. Make sure they are, directly or indirectly, called from `Main`. In this example, we'll be looking at the disassembly of our custom function `InefficientJoin`:
+
+```cs
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+namespace ConsoleApplication
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ Console.WriteLine(InefficientJoin(args));
+ }
+
+ // Add NoInlining to prevent this from getting
+ // mixed up with the rest of the code in Main
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static string InefficientJoin(IEnumerable<string> args)
+ {
+ var result = string.Empty;
+ foreach (var arg in args) result += (arg + ' ');
+ return result.Substring(0, result.Length - 1);
+ }
+ }
+}
+```
+
+* After you've finished editing the code, run `dotnet publish -c Release`. This should drop all of the binaries needed to run your app in `bin/Release/<configuration>/<rid>/publish`.
+* Overwrite the CLR dlls with the ones you've built locally. If you're a fan of the command line, here are some shell commands for doing this:
+
+```shell
+# Windows
+robocopy /e <coreclr path>\bin\Product\Windows_NT.<arch>.Debug <app root>\bin\Release\netcoreapp1.0\<rid>\publish > NUL
+
+# Unix
+cp -rT <coreclr path>/bin/Product/<OS>.<arch>.Debug <app root>/bin/Release/netcoreapp1.0/<rid>/publish
+```
+
+* Set the configuration knobs you need (see below) and run your published app. The info you want should be dumped to stdout.
+
+Here's some sample output on my machine showing the disassembly for `InefficientJoin`:
+
+```asm
+G_M2530_IG01:
+ 55 push rbp
+ 4883EC40 sub rsp, 64
+ 488D6C2440 lea rbp, [rsp+40H]
+ 33C0 xor rax, rax
+ 488945F8 mov qword ptr [rbp-08H], rax
+ 488965E0 mov qword ptr [rbp-20H], rsp
+
+G_M2530_IG02:
+ 49BB60306927E5010000 mov r11, 0x1E527693060
+ 4D8B1B mov r11, gword ptr [r11]
+ 4C895DF8 mov gword ptr [rbp-08H], r11
+ 49BB200058F7FD7F0000 mov r11, 0x7FFDF7580020
+ 3909 cmp dword ptr [rcx], ecx
+ 41FF13 call gword ptr [r11]System.Collections.Generic.IEnumerable`1[__Canon][System.__Canon]:GetEnumerator():ref:this
+ 488945F0 mov gword ptr [rbp-10H], rax
+
+; ...
+```
+
+## Setting configuration variables
+
+The behavior of the JIT can be controlled via a number of configuration variables. These are declared in [inc/clrconfigvalues.h](https://github.com/dotnet/coreclr/blob/master/src/inc/clrconfigvalues.h). When used as an environment variable, the string name generally has “COMPlus_” prepended. When used as a registry value name, the configuration name is used directly.
+
+These can be set in one of three ways:
+
+* Setting the environment variable `COMPlus_<flagname>`. For example, the following will set the `JitDump` flag so that the compilation of all methods named ‘Main’ will be dumped:
+
+```shell
+# Windows
+set COMPlus_JitDump=Main
+
+# Unix
+export COMPlus_JitDump=Main
+```
+
+* *Windows-only:* Setting the registry key `HKCU\Software\Microsoft\.NETFramework`, Value `<flagName>`, type `REG_SZ` or `REG_DWORD` (depending on the flag).
+* *Windows-only:* Setting the registry key `HKLM\Software\Microsoft\.NETFramework`, Value `<flagName>`, type `REG_SZ` or `REG_DWORD` (depending on the flag).
+
+## Specifying method names
+
+The complete syntax for specifying a single method name (for a flag that takes a method name, such as `COMPlus_JitDump`) is:
+
+```
+[[<Namespace>.]<ClassName>::]<MethodName>[([<types>)]
+```
+
+For example
+
+```
+System.Object::ToString(System.Object)
+```
+
+The namespace, class name, and argument types are optional, and if they are not present, default to a wildcard. Thus stating:
+
+```
+Main
+```
+
+will match all methods named Main from any class and any number of arguments.
+
+<types> is a comma separated list of type names. Note that presently only the number of arguments and not the types themselves are used to distinguish methods. Thus, `Main(Foo, Bar)` and `Main(int, int)` will both match any main method with two arguments.
+
+The wildcard character ‘*’ can be used for <ClassName> and <MethodName>. In particular * by itself indicates every method.
+
+## Useful COMPlus variables
+
+Below are some of the most useful `COMPlus` variables. Where {method-list} is specified in the list below, you can supply a space-separated list of either fully-qualified or simple method names (the former is useful when running something that has many methods of the same name), or you can specific ‘*’ to mean all methods.
+
+* `COMPlus_JitDump`={method-list} – dump lots of useful information about what the JIT is doing. See [Reading a JitDump](../botr/ryujit-overview.md#reading-a-jitdump) for more on how to analyze this data.
+* `COMPlus_JitDisasm`={method-list} – dump a disassembly listing of each method.
+* `COMPlus_JitDiffableDasm` – set to 1 to tell the JIT to avoid printing things like pointer values that can change from one invocation to the next, so that the disassembly can be more easily compared.
+* `COMPlus_JitGCDump`={method-list} – dump the GC information.
+* `COMPlus_JitUnwindDump`={method-list} – dump the unwind tables.
+* `COMPlus_JitEHDump`={method-list} – dump the exception handling tables.
+* `COMPlus_JitTimeLogFile`={file name} – this specifies a log file to which timing information is written.
+* `COMPlus_JitTimeLogCsv`={file name} – this specifies a log file to which summary timing information can be written, in CSV form.
+
+See also: [CLR Configuration Knobs](../project-docs/clr-configuration-knobs.md)
+
+## Dumping native images
+
+If you followed the tutorial above and ran the sample app, you may be wondering why the disassembly for methods like `Substring` didn't show up in the output. This is because `Substring` lives in mscorlib, which (by default) is compiled ahead-of-time to a native image via [crossgen](../building/crossgen.md). Telling crossgen to dump the info works slightly differently.
+
+* First, perform a debug build of the native parts of the repo: `build skipmscorlib skiptests`.
+ * This should produce the binaries for crossgen in `bin/Product/<OS>.<arch>.Debug`.
+* Next, set the appropriate configuration knob for the info you want to dump. Usually, this is just the same as the corresponding JIT knob, except prefixed with `Ngen`; for example, to show the disassembly listing of a particular method you would `set COMPlus_NgenDisasm=Foo`.
+* Run crossgen on the assembly you want to dump: `crossgen MyLibrary.dll`
+ * If you want to see the output of crossgen specifically for mscorlib, invoke `build skipnative skiptests` from the repo root. The dumps should be written to a file in `bin/Logs` that you can just view.