Skip to content
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

Another big improvement to dynamic property access: Fix dynamic dispatch perf #36

Merged
merged 1 commit into from
Jan 24, 2025

Conversation

NHDaly
Copy link
Member

@NHDaly NHDaly commented Jan 22, 2025

There's a known issue with dynamic dispatch (Thanks to @topolarity to pointing this out) where it's super slow if you dispatch on a type / constructor.

Our code had a dispatch on Blob{FT} with an unknown FT in the case of a dynamic field access. That was causing very slow performance.

By changing this to a helper function (make_blob), we do a performant dispatch, dramatically improving perf.

Now, dynamic field access on a Blob has the same even better performance as dynamic field access on a regular julia object! :)

Before:

julia> @btime ((a)->a[1].y)($(Any[foo]))
  115.105 ns (2 allocations: 48 bytes)
Blob{Float32}(Ptr{Nothing} @0x000000016fe73d90, 8, 12)

After:

julia> @btime ((a)->a[1].y)($(Any[foo]))
  48.015 ns (1 allocation: 32 bytes)
Blob{Float32}(Ptr{Nothing} @0x000000016fe73d90, 8, 12)

# Comparison to getproperty on a normal struct:
julia> @btime ((a)->a[1].y)($(Any[Foo(2,3)]))
  52.550 ns (2 allocations: 48 bytes)
3.0f0

Follow up to #35.

@NHDaly NHDaly requested a review from Sacha0 January 23, 2025 01:40
Comment on lines +15 to +20
# OPTIMIZATION: Annoyingly julia dispatches on a *Type Constructor* are very expensive.
# So if you ever have a type unstable field access on a Blob, we will not know the type of
# the child Blob we will return, meaning a dynamic dispatch. Dispatching on Blob{FT}(...)
# for an unknown FT is very expensive. So instead, we dispatch to this function, which will
# be cheap because it has only one method. Then this function calls the constructor.
# This is a silly hack. :')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this comment, and looking forward to the pitfall going away! ❤️

Copy link
Contributor

@Sacha0 Sacha0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Nathan! :)

Base automatically changed from nhd-getindex-perf-dynamic to main January 24, 2025 21:43
@NHDaly NHDaly force-pushed the nhd-getindex-dynamic-dispatch branch from a55fc8d to 5aeb506 Compare January 24, 2025 21:44
…tch perf

There's a known issue with dynamic dispatch (Thanks to Cody to pointing
this out) where it's super slow if you dispatch on a type / constructor.

Our code had a dispatch on Blob{FT} with an unknown FT in the case of a
dynamic field access. That was causing very slow performance.

By changing this to a helper function (make_blob), we do a performant
dispatch, dramatically improving perf.

Now, dynamic field access on a Blob has the ~same~ even better
performance as dynamic field access on a regular julia object! :)

```julia
julia> @Btime getproperty($(foo), $(:y))
  19.057 ns (0 allocations: 0 bytes)
Blob{Float32}(Ptr{Nothing} @0x000000016fe73d90, 8, 12)

julia> @Btime getproperty($(Foo(1,2)), $(:y))
  25.477 ns (2 allocations: 48 bytes)
2.0f0
```
@NHDaly NHDaly force-pushed the nhd-getindex-dynamic-dispatch branch from 5aeb506 to 2e18db7 Compare January 24, 2025 21:45
@NHDaly NHDaly merged commit eb8d46d into main Jan 24, 2025
4 checks passed
@NHDaly NHDaly deleted the nhd-getindex-dynamic-dispatch branch January 24, 2025 21:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants