-
Notifications
You must be signed in to change notification settings - Fork 5.4k
ZJIT: Profile type+shape distributions #13901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
54f34ca
to
4a17446
Compare
ec9a182
to
5e9a46e
Compare
5e9a46e
to
9c12d58
Compare
How can I fix the build so we let these special shape symbols leak? Or should I do something else? |
The failure is saying that you published symbols that do not follow our naming convention. It seems like you actually didn't use those symbols from other object files (even If you want to just use the value of |
RB_INVALID_SHAPE_ID = INVALID_SHAPE_ID; | ||
|
||
bool | ||
rb_zjit_singleton_class_p(VALUE klass) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Until we share them with YJIT, they should be defined in zjit.c. It's confusing to put non-shared things in the shared place, and ZJIT-only implementations should not bloat the YJIT-only binaries.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
pub struct ProfiledType { | ||
class: VALUE, | ||
shape: ShapeId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For non-ivar instructions, is there any plan to use any information other than SPECIAL_CONST_SHAPE_ID
?
I feel like immediate: bool
(or a set of object flags including that) is what you actually wanted to use. Object shapes in Ruby are basically a cache key to access ivars today, so using all those 32 bits to store the single flag SPECIAL_CONST_SHAPE_ID
seems space-inefficient.
For shapes, some instructions would need to query non-class
/immediate
information, so it might make sense to prepare a storage for instruction-specific profiling data, and store shapes only for ivar instructions.
ZJIT uses the interpreter to take type profiles of what objects pass through
the code. It stores a compressed record of the history per opcode for the
opcodes we select.
Before this change, we re-used the HIR Type data-structure, a shallow type
lattice, to store historical type information. This was quick for bringup but
is quite lossy as profiles go: we get one bit per built-in type seen, and if we
see a non-built-in type in addition, we end up with BasicObject. Not very
helpful. Additionally, it does not give us any notion of cardinality: how many
of each type did we see?
This change brings with it a much more interesting slice of type history: a
histogram. A Distribution holds a record of the top-N (where N is fixed at Ruby
compile-time)
(Class, ShapeId)
pairs and their counts. It also holds another count in case we see more than N pairs.
Using this distribution, we can make more informed decisions about when we
should use type information. We can determine if we are strictly monomorphic,
very nearly monomorphic, or something else. Maybe the call-site is polymorphic,
so we should have a polymorphic inline cache. Exciting stuff.
I also plumb this new distribution into the HIR part of the compilation
pipeline.