-
Notifications
You must be signed in to change notification settings - Fork 14
Description
@k0kubun has recently taken the time to gather some stats about the most common C and Ruby method calls in our headline benchmarks: ruby/ruby-bench#163
One of the things that is somewhat surprising is that Hash#[]
is the most frequently called C method, and often by a long shot. For example, in activerecord
, it makes up over 10% of the C method calls, with 87K calls, and the most called Ruby method is "only" called 26K times. It's also the topmost method in railsbench, where it's called about 4x more than the most frequently called Ruby methodsOn liquid-render
it's at 6.3%. Note that in theory, in liquid-render
, we already optimize Kernel#respond_to?
and Array#[]
, so the overhead taken by Hash#[]
is probably significant.
All of this is to say, Hash#[]
gets called a lot on our benchmarks, more than basically any other C or Ruby method. Therefore, we should probably care about making sure that it runs fast. We probably don't want to generate JITted code for every single hash variable access because that might tie us a little too deeply with the specifics of the Ruby hash map implementation, which could get pretty messy, but there might still be some clever things we can do.
Right now, from what I can see, we do have some special handling for hash reads in opt_aref
, which calls rb_hash_aref
.
Some ideas:
- For hash keys that are symbols or string constants, could we precompute the hashed value somehow?
- For objects that we know are of the symbol or string class, could we avoid the
jit_prepare_routine_call
? We should be able to know that there will be no call into Ruby methods and no GC alloc in some cases?- That would have the benefit of avoiding clearing local types as well
- I guess that might be somewhat tricky because we have to know
String#hash
andSymbol#hash
wasn't redefined?
- At the moment, as far as I can tell, we have a
Type::Hash
, and we guard that the receiver is anrb_cHash
, but we never upgrade the type in the context, so successive hash reads would always have to run the guards