Bug 33003 - Performance problem when in inlining methods
Summary: Performance problem when in inlining methods
Status: NEW
Alias: None
Product: Runtime
Classification: Mono
Component: JIT (show other bugs)
Version: 4.0.0
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2015-08-12 09:58 UTC by Moritz Uehling
Modified: 2015-08-13 13:56 UTC (History)
3 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description Moritz Uehling 2015-08-12 09:58:04 UTC
Sample code: https://gist.github.com/moritzuehling/b40921f4eeac744027f6

I have a very short method: 

	public void CalculatePoint(double cr, double ci, ref double zr, ref double zi) {
		var zr_old = zr;
		zr = (zr * zr - zi * zi) + cr;
		zi = 2 * (zi * zr_old) + ci;
	}

I call this in a normal instance-method many times. [MethodImpl(MethodImplOptions.NoInlining)] or AggressiveInlining make no difference in performance, inlining the method manually by copying the source-code speeds up the code significantly. See the gist for more details. 

Result:

| Arch | Inlining                | Time taken   | Relative Time |
|-----:|-------------------------|-------------:|--------------:|
|  x86 | Aggressive (Attribute)  |    147687387 |          100% |
|  x86 | No Inlining (Attribute) |    146419297 |        99.14% |
|  x86 | Manually Inlined        |     97312791 |        65.89% |

Expected Result:

Automatic inlining should be faster than no inlining, and be close / equal to the performance of the manually inlined code. 

https://github.com/akoeplinger has verified that the method is inlined on his system, and the performance-behavior was similar (https://gitter.im/mono/mono?at=55cb4d178f067d637599112e) on his system. 


> I checked with mono -v -v -v -v test.exe | grep INLINE and the method is indeed inlined, so the root cause may be somewhere else
> INLINE START 0x2680d40 LeckerBrot.Program:Main () -> LeckerBrot.RowCalulator:.ctor ()
> INLINE END LeckerBrot.Program:Main () -> LeckerBrot.RowCalulator:.ctor ()
> INLINE START 0x2680e40 LeckerBrot.RowCalulator:Calc () -> LeckerBrot.RowCalulator:CalculatePoint (double,double,double&,double&)
> INLINE END LeckerBrot.RowCalulator:Calc () -> LeckerBrot.RowCalulator:CalculatePoint (double,double,double&,double&)



System Information: 

Processor: Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz

$ uname -a
Linux moritz-P15SM 3.19.0-15-generic #15-Ubuntu SMP Thu Apr 16 23:32:37 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ mono --version
  Mono JIT compiler version 4.0.3 (Stable 4.0.3.20/d6946b4 Tue Aug  4 09:43:57 UTC 2015)
  Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
Comment 1 Zoltan Varga 2015-08-12 23:18:59 UTC
The mono JIT is not smart enough to get rid of the 'ref' modifiers, so even with the method inlined, it will load/store the values many times.
Comment 2 Moritz Uehling 2015-08-13 13:56:25 UTC
I have tried it on the same machine under Visual Studio, with the original VS JIT.

(Windows 10, VS15, Release, .NET 4.5.2, Default Console Project)

Results: (times relative to the time taken on Linux with agressive inlining)

Aggressive: 290886075 - 196.96%
NoInlining: 290073532 - 198.11%
  Manually: 6799670 - 46.04%

So the manually inlined variant is faster, but the rest is slower.

Note You need to log in before you can comment on or make changes to this bug.