From: Alex Clark on 11 Dec 2009 00:18 Hi all, Does anyone know if making calls to System.Reflection.MethodBase.GetCurrentMethod is reliable in an optimised, Release Build .NET app? I know the JITter can do some inline optimisations, and if it does will GetCurrentMethod reflect the calling method (i.e. the one this method was inlined into), or the containing method? I've Googled but have found contradicting information, and there is no indication in the MSDN online help about what to expect (whereas there is for the StackFrame methods). Can anyone shed some light on this? Thanks, Alex
From: Mark Hurd on 13 Dec 2009 08:50 "Alex Clark" <quanta(a)noemail.noemail> wrote in message news:uTZd2FieKHA.4952(a)TK2MSFTNGP06.phx.gbl... > Hi all, > > Does anyone know if making calls to > System.Reflection.MethodBase.GetCurrentMethod is reliable in an > optimised, Release Build .NET app? I know the JITter can do some > inline optimisations, and if it does will GetCurrentMethod reflect the > calling method (i.e. the one this method was inlined into), or the > containing method? I've Googled but have found contradicting > information, and there is no indication in the MSDN online help about > what to expect (whereas there is for the StackFrame methods). > > Can anyone shed some light on this? No. Some quick tests produced GetCurrentMethod always returning the current method, but any extra code added to the routine to try to confirm if it was inlined (by accessing New StackTrace()) stopped the method from being inlined. Removing the call to GetCurrentMethod, and just leaving New StackTrace().ToString showed the method /was/ then being inlined. And I tried "hiding" the call to GetCurrentMethod in a delegate to try to ensure the JIT doesn't just avoid inlining routines that call GetCurrentMethod. > > Thanks, > Alex Sorry I couldn't help. BTW Remember to use Ctrl+F5 from within VS to allow the JITter to do its thing without any debugging getting in the way. Here's my code just in case it helps someone else confirm or contradict this: Module Module1 Sub Main() Dim fn As Func(Of Object) = AddressOf System.Reflection.MethodBase.GetCurrentMethod Dim fn2 As Func(Of Object) = Function() (New StackTrace()) TestRoutine(fn) CallsTestRoutine(fn) 'CallIt(AddressOf TestRoutine) 'CallIt(AddressOf CallsTestRoutine) TestRoutine2(fn) CallsTestRoutine2(fn) 'CallIt(AddressOf TestRoutine2) 'CallIt(AddressOf CallsTestRoutine2) TestRoutine(fn2) CallsTestRoutine(fn2) TestRoutine2(fn2) CallsTestRoutine2(fn2) Console.ReadLine() End Sub 'Private Function TestRoutineExtracted() As System.Reflection.MethodBase ' Console.WriteLine(New StackTrace().ToString) ' Return System.Reflection.MethodBase.GetCurrentMethod() 'End Function Sub TestRoutine(ByVal fn As Func(Of Object)) 'Console.WriteLine(TestRoutineExtracted().Name) 'Console.WriteLine(New StackTrace().ToString) 'Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name) Console.WriteLine(fn().ToString) End Sub Sub CallsTestRoutine(ByVal fn As Func(Of Object)) TestRoutine(fn) 'Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name) 'Console.WriteLine(fn().ToString) End Sub Sub CallIt(ByVal Fn As Action) Fn() End Sub 'Private Function TestRoutine2Extracted() As System.Reflection.MethodBase ' Console.WriteLine(New StackTrace().ToString) ' Return System.Reflection.MethodBase.GetCurrentMethod() 'End Function <System.Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.NoInlining)> _ Sub TestRoutine2(ByVal fn As Func(Of Object)) 'Console.WriteLine(TestRoutine2Extracted().Name) 'Console.WriteLine(New StackTrace().ToString) 'Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name) Console.WriteLine(fn().ToString) End Sub Sub CallsTestRoutine2(ByVal fn As Func(Of Object)) TestRoutine2(fn) 'Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name) 'Console.WriteLine(fn().ToString) End Sub End Module -- Regards, Mark Hurd, B.Sc.(Ma.) (Hons.)
From: Jeroen Mostert on 13 Dec 2009 17:49 On 2009-12-11 6:18, Alex Clark wrote: > Does anyone know if making calls to > System.Reflection.MethodBase.GetCurrentMethod is reliable in an optimised, > Release Build .NET app? Yes, because any method that calls MethodBase.GetCurrentMethod() will not be inlined. This is because .GetCurrentMethod() includes a StackCrawlMark, a special magical enum for methods that need to walk the stack (like ..GetCurrentMethod() predictably needs, to look for its caller) that prevents the caller from being inlined. Trying to be clever by sticking the call in a delegate like Mark did won't upset this, because methods that call delegates aren't inlined either. If for some reason you need methods that use functionality like this to be inlined, consider using LCG (Lightweight Code Generation) instead. It's very fiddly and requires a good understanding of IL, but it does allow you to "hand-optimize" just about anything. Again: only use it if it's necessary, not because you like the illusion of speed. -- J.
From: Alex Clark on 13 Dec 2009 17:51 Thanks Mark, I appreciate the help. I'm still Googling but details on the JIT and how/when it decides to inline are hard to come by, and oftentimes is just guesswork by various .NET bloggers. Some imply that the JIT will intentionally *not* inline methods if they have any metadata-dependent code in them, such as GetCurrentMethod. If you're still interested, see "inline" (lol): "Mark Hurd" <markhurd(a)ozemail.com.au> wrote in message news:%237DqOt$eKHA.3792(a)TK2MSFTNGP02.phx.gbl... > > No. Some quick tests produced GetCurrentMethod always returning the > current method, but any extra code added to the routine to try to confirm > if it was inlined (by accessing New StackTrace()) stopped the method from > being inlined. From what I learned, there appears to be some special 32-byte IL limit for inlining. If the JITer determines the routine being called to be larger than that, then it won't inline it. It may well be that GetCurrentMethod followed by instantiation of the StackTrace breaches that limit. > Removing the call to GetCurrentMethod, and just leaving New > StackTrace().ToString showed the method /was/ then being inlined. Which might confirm my findings that reflection/metadata calls actually prohibit inlining, but then it may also be that removing GetCurrentMethod and just leaving the calls to StackTrace put the IL below the 32 byte limit. Heisenberg's uncertainty principle, anyone? :-) > Sorry I couldn't help. On the contrary, a fresh set of eyes (not to mention experimental results) is always helpful, thanks Mark. Regards, Alex
|
Pages: 1 Prev: [ANN] IronPython Training in New York, January 21st 2010 Next: Help with TCP Server. |