Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,125 | Comments: 45,492

filter by tags archive

Reducing the cost of getting a stack trace

time to read 6 min | 1100 words

image I am trying to find ways to reduce the cost of the stack trace used in NH Prof. The access to the stack trace is extremely valuable, but there is a significant cost of using it, so we need a better way of handling this. I decided to run a couple of experiment running this.

All experiments were run 5,000 times, on a stack trace of 7 levels.

  • new StackTrace(true) - ~600ms
  • new StackTrace(false) - ~150ms

So right there, we have a huge cost saving, but let us continue a bit.

  • throwing exception - ~400ms

That is not so good, I have to say.

Well, when in doubt, cheat!

Using reflector and some _really_ nasty stuff, I came up with this:

var stackFrameHelperType = typeof(object).Assembly.GetType("System.Diagnostics.StackFrameHelper");
var GetStackFramesInternal = Type.GetType("System.Diagnostics.StackTrace, mscorlib").GetMethod("GetStackFramesInternal",BindingFlags.Static|BindingFlags.NonPublic);
var method = new DynamicMethod("GetStackTraceFast",typeof(object),new Type[0],typeof(StackTrace),true);
var generator = method.GetILGenerator();
generator.Emit(OpCodes.Newobj, stackFrameHelperType.GetConstructor(new[] { typeof(bool), typeof(Thread) }));
generator.Emit(OpCodes.Call, GetStackFramesInternal);
getTheStackTrace = (Func<object>)method.CreateDelegate(typeof(Func<object>));

Calling getTheStackTrace 5000 times with depth of 7 frames is… 54ms. And now that is a horse of a different color indeed.

And the best part is, I can use the StackFrameHelper as a key into cached stack traces.

And yes, I am aware that if anyone from the CLR team is reading this, a ninja team will be dispatched to… discuss with me the notion of supported operations vs. unsupported operation.


Benny Thomas

I hate internal types and method that clearly would help when extending the .net enviroment!

I almost created my own CheckedListBox in pure frustration.


What do you do with the StackFrameHelper you receive?


We have cows all over downtown calgary that are painted up like that horse. I had almost forgotten the atroscities until this post.


Whats the trust level to invoke that method? only a lot of web hosting is medium trust.

Ayende Rahien

I can use that to get RuntimeMethodHandle, which is good enough to create a cache key.

Ayende Rahien


I am assuming FullTrust, but I haven't considered this.


I don't think its a huge problem, you can probably use the old style in the event you can't use the cheat right?

Fabian Schmied


you can probably form a compound cache key from the rgMethodHandle field inside of the StackFrameHelper (but beware of generic methods, where the handles are not unique per specialization!). Apart from that, the names of the methods on the stack are only available via StackFrameHelper.GetMethodBase.

And once you iterate over the frames and call GetMethodBase, you're basically back to what the "official" StackTrace class does. (Minus a few ms, maybe, when you optimize it for your needs, but never a two-third reduction...) And this at the cost of using some extremely brittle code, which is bound to break sooner or later, especially if you have a heterogeneous user base. (Which, I guess, you would have with NH Prof.)

Maybe in your current use case the advantages outweigh the disadvantages, but in most cases, I think it wouldn't be worth the trouble.

Ayende Rahien


I am using rgMethodHandle and rgiILOffset as compound cache key, which will work just fine for my needs, since it match a location in a the source file.

Generic methods are actually not a problem for me, since I am only interested in the source line.

And since I only care about the uniqueness of the stack trace, I don't need to get GetMethodBase(), and can use the RuntimeMethodHandle

Laptop Repair

Thanks for posting this kind of ideas and tips, it's an additional knowledge from what I know before, keep up the good work

Comment preview

Comments have been closed on this topic.


  1. RavenDB 3.5 Whirlwind tour: I need to be free to explore my data - 17 hours from now
  2. RavenDB 3.5 whirl wind tour: I'll have the 3+1 goodies to go, please - 4 days from now
  3. The design of RavenDB 4.0: Voron has a one track mind - 5 days from now
  4. RavenDB 3.5 whirl wind tour: Digging deep into the internals - 6 days from now
  5. The design of RavenDB 4.0: Separation of indexes and documents - 7 days from now

And 11 more posts are pending...

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    05 May 2016 - Physically segregating collections
  2. RavenDB 3.5 whirl wind tour (14):
    04 May 2016 - I’ll find who is taking my I/O bandwidth and they SHALL pay
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats