Skip to content

wipphj/SeeJit

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 

Repository files navigation

SeeJit

Status

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.

About

Dump JIT compiled result for .NET from source code.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%