SeeJit
SeeJit copied to clipboard
Dump JIT compiled result for .NET from source code.
SeeJit
SeeJit is a small tool to dump JIT compiled result for .NET from source code. It works as a command line program to accept a C# source file as input, and then print the assembly code generated by the JIT compiler of the CLR. It's an useful tool to observe the behavior of the JIT compiler, and to avoid the unexpected performance flaws from the code pattern in your program.
Quick start
Please make sure you're using .NET Framework 4.5.2 or above. Previous versions of .NET Framework are not supported. CLR Core might be supported in the future, but there're still many other features to implement before working on that.
If the environment is ready, simply prepare a C# source file Test.cs
as input. For example:
using System;
class MyTest {
static string PrintSquare(int n) {
Console.WriteLine(Multiply(n, n));
}
static int Multiply(int x, int y) {
return x + y;
}
}
Execute SeeJit.exe in command line and it will print out the JIT compiled result for each method:
SeeJit -f Test.cs
And you'll see the output similar to:
; MyTest.PrintSquare(Int32)
00007ffd`79ea9da0 4883ec28 sub rsp, 0x28
00007ffd`79ea9da4 0fafc9 imul ecx, ecx
00007ffd`79ea9da7 e854014d5e call 00007ffd`d8379f00 (System.Console.WriteLine(Int32))
00007ffd`79ea9dac 90 nop
00007ffd`79ea9dad 4883c428 add rsp, 0x28
00007ffd`79ea9db1 c3 ret
; MyTest.Multiply(Int32, Int32)
00007ffd`79ea9dd0 8bc1 mov eax, ecx
00007ffd`79ea9dd2 0fafc2 imul eax, edx
00007ffd`79ea9dd5 c3 ret
Please note that the implementation of the JIT compiler is a subject to change with the CLR. If you're using a diffrent version of .NET Framework, you might see a different result from what I get here, although it's quite unlikely for the simple code we're using right now. Also, if you're running it in a 32-bit environment, you'll see all addresses printed as 4-byte hex strings (e.g, 22be94b0
) instead of 8-byte addresses showing above.
From the simple example above we can easily tell that the method Multiply
has been inlined so there won't be any call
instruction emitted for calling it in method PrintSquire
. That's a very common optimizaion done by the CLR.
Additional options
There're some additional options we can use when dumping JIT compiled result. We can always see the full list of available options by executing SeeJit with the --help
option.
Save dll into disk
Use -s
or --save
to save the compiled dll into disk. By default, SeeJit will compile the dll in memory and load it as binary data. But you can always get an additional copy of the compiled dll if you're going to do something additionally.
Disable optimization
Use -d
or --debug
options to compile the code without optimization. SeeJit will compile the input source with optimization by default, since it doesn't make much sense to see the result without optimization for performance investigation. But still, you can pass -d
or --debug
to disable the optimization.
For example, the JIT compiled result of the previous method PrintSquare
without optimization is:
; MyTest.PrintSquare(Int32)
00007ffd`79ebc9b0 55 push rbp
00007ffd`79ebc9b1 4883ec30 sub rsp, 0x30
00007ffd`79ebc9b5 488d6c2430 lea rbp, [rsp+0x30]
00007ffd`79ebc9ba 894d10 mov [rbp+0x10], ecx
00007ffd`79ebc9bd 833d2486270000 cmp dword [rip+0x278624], 0x0
00007ffd`79ebc9c4 7405 jz 00000000`79ebc9cb
00007ffd`79ebc9c6 e895fa185f call 00007ffd`d904c460
00007ffd`79ebc9cb 90 nop
00007ffd`79ebc9cc 8b4d10 mov ecx, [rbp+0x10]
00007ffd`79ebc9cf 8b5510 mov edx, [rbp+0x10]
00007ffd`79ebc9d2 e8a9a8ffff call 00007ffd`79eb7280 (MyTest.Multiply(Int32, Int32))
00007ffd`79ebc9d7 8945fc mov [rbp-0x4], eax
00007ffd`79ebc9da 8b4dfc mov ecx, [rbp-0x4]
00007ffd`79ebc9dd e81ed54b5e call 00007ffd`d8379f00 (System.Console.WriteLine(Int32))
00007ffd`79ebc9e2 90 nop
00007ffd`79ebc9e3 90 nop
00007ffd`79ebc9e4 488d6500 lea rsp, [rbp]
00007ffd`79ebc9e8 5d pop rbp
00007ffd`79ebc9e9 c3 ret
Print more messages
Use -v
or --verbose
to print more messages. Currently, it only prints out the stages and the time cost of each stage. For example:
; Parsing from file ... done. (142ms)
; Compiling ... done. (1263ms)
; Analyzing ... done. (72ms)
More features on the way
SeeJit is still in its early stage. It's originally a side project of mine - actually just some code for practice that I used for performance investigation. Since it's becoming more and more useful to the people around me, I decide to make it public as an open source project and take it much more seriously. I'll continue to migrate more features into this tool based on my own requirements. For example, the most important features to come is to support printing JIT compiled result for open generic types and methods by indicating concrete types.