Closed cortner closed 2 years ago
struct Wrapper{SYMS, TT}
x::NamedTuple{SYMS, TT}
end
randnt() = Wrapper((a = randn(), b = rand(), c = rand(1:5),
d = randn(SVector{3, Float64})))
X = randnt()
@allocated randnt() # 64
isbits(X) # false
isbits(X.x) # true
bizarrely,
struct Wrapper1{NT}
x::NT
end
randnt1() = Wrapper1((a = randn(), b = rand(), c = rand(1:5),
d = randn(SVector{3, Float64})))
X = randnt1()
@allocated randnt1() # 0
isbits(X) # true
isbits(X.x) # true
Looks like this will lead to a solution:
struct Wrapper{NT}
x::NT
end
@generated function syms(w::Wrapper{NamedTuple{SYMS, TT}}
) where {SYMS, TT}
code = "(" * prod( (":" * string(sym) * ",") for sym in SYMS ) * ")"
quote
$(Meta.parse(code))
end
end
nt = (a = 1, b = 2, c = 5)
w = Wrapper(nt)
syms(w)
Isn't randnt and randnt1 exactly the same?
Bad copy-pasting - now corrected.
I'm guessing the problem is related to the fact that symbols are not isbits
and the NamedTuple
implementation does some deeper magic that I don't have access to, to get around this? But I really don't understand it at all.
The difference in allocations between randnt()
and randnt1()
is quite bizarre indeed. My best guess is that this is an artefact of some optimisation heuristic of Julia - sometimes Julia deliberately does not optimise some function calls to avoid excessive compiler overhead for functions which are likely not used very often. But I couldn't come up with a minimal example which would demonstrate this.
Maybe I should file an issue if I don’t get a response in discourse.
But also can it really be an optimisation issue? It’s the fact that Wrapper and a boy isbits that bugs me most
Fair point, that part can't be an optimisation issue. On the other hand, I observed that Wrapper((a = rand(), b = rand()))
allocates while Wrapper((a = 1, b = 1)))
doesn't. This looks a lot like Julia optimises in the simplest of cases but chickens out once things get even slightly more complicated.
Very interesting
I've just rewritten the State implementation now; cf. #93
How could I have missed this? A struct wrapping a NamedTuple is no longer
isbits
. Therefore generating aState
always allocates. How bizarre.