<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/zjit/src/distribution.rs, branch v4.0.2</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>ZJIT: Profile specific objects for invokeblock (#15051)</title>
<updated>2025-11-05T20:01:17+00:00</updated>
<author>
<name>Max Bernstein</name>
<email>rubybugs@bernsteinbear.com</email>
</author>
<published>2025-11-05T20:01:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=02267417da32bf480f7050ff2ab182076aa0ad83'/>
<id>02267417da32bf480f7050ff2ab182076aa0ad83</id>
<content type='text'>
I made a special kind of `ProfiledType` that looks at specific objects, not just their classes/shapes (https://github.com/ruby/ruby/pull/15051). Then I profiled some of our benchmarks.

For lobsters:

```
Top-6 invokeblock handler (100.0% of total 1,064,155):
        megamorphic: 494,931 (46.5%)
   monomorphic_iseq: 337,171 (31.7%)
        polymorphic: 113,381 (10.7%)
  monomorphic_ifunc:  52,260 ( 4.9%)
  monomorphic_other:  38,970 ( 3.7%)
        no_profiles:  27,442 ( 2.6%)
```

For railsbench:

```
Top-6 invokeblock handler (100.0% of total 2,529,104):
   monomorphic_iseq: 834,452 (33.0%)
        megamorphic: 818,347 (32.4%)
        polymorphic: 632,273 (25.0%)
  monomorphic_ifunc: 224,243 ( 8.9%)
  monomorphic_other:  19,595 ( 0.8%)
        no_profiles:     194 ( 0.0%)
```

For shipit:

```
Top-6 invokeblock handler (100.0% of total 2,104,148):
        megamorphic: 1,269,889 (60.4%)
        polymorphic:   411,475 (19.6%)
        no_profiles:   173,367 ( 8.2%)
  monomorphic_other:   118,619 ( 5.6%)
   monomorphic_iseq:    84,891 ( 4.0%)
  monomorphic_ifunc:    45,907 ( 2.2%)
```

Seems like a monomorphic case for a specific ISEQ actually isn't a bad way of going about this, at least to start...</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
I made a special kind of `ProfiledType` that looks at specific objects, not just their classes/shapes (https://github.com/ruby/ruby/pull/15051). Then I profiled some of our benchmarks.

For lobsters:

```
Top-6 invokeblock handler (100.0% of total 1,064,155):
        megamorphic: 494,931 (46.5%)
   monomorphic_iseq: 337,171 (31.7%)
        polymorphic: 113,381 (10.7%)
  monomorphic_ifunc:  52,260 ( 4.9%)
  monomorphic_other:  38,970 ( 3.7%)
        no_profiles:  27,442 ( 2.6%)
```

For railsbench:

```
Top-6 invokeblock handler (100.0% of total 2,529,104):
   monomorphic_iseq: 834,452 (33.0%)
        megamorphic: 818,347 (32.4%)
        polymorphic: 632,273 (25.0%)
  monomorphic_ifunc: 224,243 ( 8.9%)
  monomorphic_other:  19,595 ( 0.8%)
        no_profiles:     194 ( 0.0%)
```

For shipit:

```
Top-6 invokeblock handler (100.0% of total 2,104,148):
        megamorphic: 1,269,889 (60.4%)
        polymorphic:   411,475 (19.6%)
        no_profiles:   173,367 ( 8.2%)
  monomorphic_other:   118,619 ( 5.6%)
   monomorphic_iseq:    84,891 ( 4.0%)
  monomorphic_ifunc:    45,907 ( 2.2%)
```

Seems like a monomorphic case for a specific ISEQ actually isn't a bad way of going about this, at least to start...</pre>
</div>
</content>
</entry>
<entry>
<title>ZJIT: Ensure `clippy` passes and silence unnecessary warnings (#14439)</title>
<updated>2025-09-03T21:45:54+00:00</updated>
<author>
<name>Aiden Fox Ivey</name>
<email>aiden.foxivey@shopify.com</email>
</author>
<published>2025-09-03T21:45:54+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=a6d397e29c61030f130f8d83e6bfe6d99ebbae91'/>
<id>a6d397e29c61030f130f8d83e6bfe6d99ebbae91</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>ZJIT: Add missing module doc comments</title>
<updated>2025-09-03T20:18:42+00:00</updated>
<author>
<name>Aiden Fox Ivey</name>
<email>aiden.foxivey@shopify.com</email>
</author>
<published>2025-09-03T19:41:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=8a350775aab898ea0f0fad5663b259caa840fc1f'/>
<id>8a350775aab898ea0f0fad5663b259caa840fc1f</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>ZJIT: Fix documentation build warnings</title>
<updated>2025-09-03T20:18:42+00:00</updated>
<author>
<name>Aiden Fox Ivey</name>
<email>aiden.foxivey@shopify.com</email>
</author>
<published>2025-09-03T19:28:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=a8a2f1f06c3435aaa47c82512f5bf0e3a605132e'/>
<id>a8a2f1f06c3435aaa47c82512f5bf0e3a605132e</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>ZJIT: Profile type+shape distributions (#13901)</title>
<updated>2025-08-05T20:56:04+00:00</updated>
<author>
<name>Max Bernstein</name>
<email>rubybugs@bernsteinbear.com</email>
</author>
<published>2025-08-05T20:56:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=ef95e5ba3de65d42fe0e1d41519dcf05db11a4e8'/>
<id>ef95e5ba3de65d42fe0e1d41519dcf05db11a4e8</id>
<content type='text'>
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 an
*other* 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.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 an
*other* 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.</pre>
</div>
</content>
</entry>
</feed>
