-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
RFC: syntax: add noinline/inline support overrides for structs #51495
base: master
Are you sure you want to change the base?
Conversation
An example: ```julia julia> @noinline struct NoinlineSingleton end julia> @inline struct NormalSingleton end julia> @inline struct Impossible; x::Impossible; end ERROR: Cannot apply @inline to this struct which is self-referential Stacktrace: [1] top-level scope @ REPL[5]:1 julia> sizeof(Tuple{NoinlineSingleton}) 8 julia> sizeof(Tuple{NormalSingleton}) 0 ```
This looks nice to have! However, I think it'd typically be more useful to have something like this in the field position rather than a universal decorator for a given type -- that is I want to be able to write struct Foo
@inline x::Bar
end to have struct Foo{T, U, V, W}
x::Tuple{T, U, V, W}
end is not always the same as having struct Foo{T, U, V, W}
a::T
b::U
c::V
d::W
end and I have no control over the definition of |
Can we use something different than |
What else would you call it though? In lisp languages (like Julia), code is simply data, and both are decisions of whether to copy data inline into a parent object or not. Should we be more precise like @MasonProtter you are welcome to implement that, but I specifically mentioned that is harder and a long-term idea, but not one for this PR |
@@ -8,6 +8,7 @@ New language features | |||
difference between `public` and `export` is that `public` names do not become | |||
available when `using` a package/module. ([#50105]) | |||
* `ScopedValue` implement dynamic scope with inheritance across tasks ([#50958]). | |||
* A struct definition can be marked with `@inline` or `@noinline` to allow/prohibit it from being treated as inline-alloc eligable. |
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.
* A struct definition can be marked with `@inline` or `@noinline` to allow/prohibit it from being treated as inline-alloc eligable. | |
* A struct definition can be marked with `@inline` or `@noinline` to allow/prohibit it from being treated as inline-alloc eligible |
Yes, I think something like |
I'm interested in a feature like this to be able to do atomic operations on inner structs like: struct Foo
@atomic data::Bar
meta::Baz
end If I think in an "ideal world", the atomic field would be non-inline-allocated by default (preferring word size atomics), and then I could annotate the field with However, I don't really want to decide that behavior globally like this PR does now. I think it doesn't make any more sense to declare |
Citation needed? It only has one extra atomic operation (on the same cache line) compared to the pointer case but elides an allocation, so it would be expected to be faster to inline in nearly all cases where it is possible |
Sure, this example is about ~113x slower when inline-allocated: julia> struct Inner
a::UInt
b::UInt
c::UInt
d::UInt
e::UInt
end
julia> mutable struct Foo
@atomic inner::Inner
const y::UInt
end
julia> function swapalot(o, a, b)
for i = 1:1_000_000
inner = @atomic :acquire o.inner
if inner.a == 1
@atomic :release o.inner = a
elseif inner.a == 0
@atomic :release o.inner = b
end
end
end
julia> a = Inner(0,0,0,0,0); b = Inner(1,0,0,0,0); o = Foo(a, 0)
julia> using BenchmarkTools
julia> @btime swapalot(o, a, b)
22.156 ms (0 allocations: 0 bytes) Changing the code to julia> @btime swapalot(o, a, b)
196.052 μs (0 allocations: 0 bytes) |
Sure, if you are comparing 2 unrelated operations, that may be the case. But it you compare similar things, then the difference is much reduced:
As far as I know, the remaining difference could be solved by using a better design for the lock itself, since right now it is a very generic jl_mutex_unlock_nogc and is thus may be somewhat slow for this particular exact use case |
I have wanted to this sometimes, to be able to control whether a particularly large struct is stored by reference or value. This was somewhat of a quick job, so it feels like a bit of a hacky implementation, but maybe that is okay. Long term, I would probably also like
@noinline
to work if applied to a field (but that is hard) or when syntactically written in the struct instead of outside of it. But this seemed to at least get the feature working.An example preview: