-
-
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
Limit the unioncomplexity
instead of the unionlen
in tmerge
#27417
Conversation
base/compiler/typelimits.jl
Outdated
@@ -349,7 +349,7 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb)) | |||
# if we didn't start with any unions, then always OK to form one now | |||
if !(typea isa Union || typeb isa Union) | |||
# except if we might have switched Union and Tuple below, or would do so | |||
if (isconcretetype(typea) && isconcretetype(typeb)) || !(typea <: Tuple && typeb <: Tuple) | |||
if (isconcretetype(typea) && isconcretetype(typeb)) || !(typea <: Tuple || typeb <: Tuple) |
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.
This was the minimal change to make the recursive test case (f27316
below) work. It's rather ad-hoc though. Could we just simplify this to the inconcretetype
part?
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.
Yes (the second test was wrong anyways, it should have been typeintersect
)
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.
No, isconcretetype(typea) && isconcretetype(typeb)
is a little too strict, it makes these tests fail:
julia/test/compiler/compiler.jl
Line 334 in 83ce7ba
@test Base.return_types(eltype, (NInt,)) == Any[Union{Type{Int}, Type{Union{}}}] # issue 21763 |
julia/test/compiler/compiler.jl
Line 383 in 83ce7ba
@test Base.return_types(f18037, (Int,)) == Any[Union{Type{T1},Type{T2}}] |
We probably want to allow
isType(...)
, too.
base/compiler/typelimits.jl
Outdated
@@ -399,7 +399,7 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb)) | |||
end | |||
end | |||
u = Union{types...} | |||
if unionlen(u) <= MAX_TYPEUNION_LEN | |||
if unioncomplexity(u) <= MAX_TYPEUNION_LEN |
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.
Worth renaming the constant? MAX_TYPEUNION_COMPLEXITY
?
base/compiler/typeutils.jl
Outdated
end | ||
return c | ||
end | ||
unioncomplexity(u::UnionAll) = unioncomplexity(u.body) * unioncomplexity(u.var.ub) |
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.
Not sure we need this case. But then again, it probably doesn't hurt, either.
AV timeout seems to be wide-spread these days... |
Bump. |
Who is best to review this: @vtjnash, @Keno, @JeffBezanson? |
base/compiler/typeutils.jl
Outdated
@@ -125,3 +125,17 @@ function _switchtupleunion(t::Vector{Any}, i::Int, tunion::Vector{Any}, @nospeci | |||
end | |||
return tunion | |||
end | |||
|
|||
# unioncomplexity correspondens to unionlen after recursively pulling out all unions in | |||
# covariant positions to the top level, e.g. Tuple{Union{A,B}} -> Union{Tuple{A},Tuple{B}} |
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.
maybe add the statement # as may be produced by tuplemerge
?
test/compiler/compiler.jl
Outdated
end | ||
return x | ||
end | ||
@test Tuple{Tuple{Nothing}} <: Base.return_types(g27316, Tuple{})[1] |
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.
should make these ==
tests, so we are more likely to be alerted if the test breaks and stops testing what we intended it to test
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.
Only if that's actually the right condition. Otherwise an arbitrarily overstrict test with no comment about what to do if it starts failing is pretty bad and will cause future pain and confusion.
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.
The test's intention is to verify that inference finishes in a finite amount of time. In this case, it now returns Any
, which I'm not sure we want to test for explicitly. The lower bounds I'm using instead are chosen somewhat arbitrarily.
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.
We can also write this test as S <: T == Any # we may be able to improve this bound in the future
037a7b8
to
4ee62ae
Compare
@nanosoldier |
That looks like it might well be related to this PR ... but why does it only happen on OSX!? Also, I would have expected the |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan |
The julia> Core.Compiler.return_type(iterate, Tuple{Base.Iterators.Zip2{Array{Union{Nothing, Bool},1},Array{Union{Nothing, Bool},1}}})
Union{Nothing, Tuple{Tuple{Union{Nothing, Bool},Union{Nothing, Bool}},Tuple{Int64,Int64}}} #master
Union{Nothing, Tuple{Tuple{Any,Any},Tuple{Any,Any}}} # this PR For this example, increasing the cutoff to |
4ee62ae
to
ad49de7
Compare
@nanosoldier |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan |
OK, benchmark regressions resolved and OSX failure is gone, too. |
Thinking some more about this, it might be better to limit the structural complexity. So I've tried with counting the number of (pairwise) @vtjnash, would you say that makes more sense? Then I'll push an update. |
I’m not sure. I think you understand this issue better than me, so I’ll go with whatever you end up recommending. The bound 23 seems high. I think instead of calling computing the size as a multiplication (the max size of the tuple-switch), it seems like a min over the parameters might be better (the min size set of tuples that could have formed this input). The reasoning is that we’re trying to limit here the number of times that tmerge has been called on the variable. So we care more about how we could have formed this, than we do about what might happen to it later. |
ad49de7
to
a1954b6
Compare
Yes! I think that's exactly what I was trying to achieve, except I wasn't actually aware of it. |
a1954b6
to
3921171
Compare
@nanosoldier I'll merge if CI goes well and benchmarks looks good, unless anyone objects. |
32bit travis:
Anyone seen that before? Or caused by this PR? |
Haven't seen it before at least. |
Does Documenters tests pass on this branch? |
I've built a 32bit version locally and I'm restarting the Travis job to see whether it reproduces, old log backed up to https://gist.github.com/martinholters/5603c378db04df2de477740485111ee6 |
The restarted Travis build is past building the docs, and the nanosoldier failure is a segfault running the benchmarks d3c1ae3, the master commit to compare against. So I guess this PR is not to blame, but we do have an issue. |
3921171
to
44c7a3b
Compare
And another try on top of #27702... @nanosoldier |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan |
base/compiler/typeutils.jl
Outdated
end | ||
return c | ||
end | ||
unioncomplexity(@nospecialize(x)) = 0 |
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.
What about UnionAll
? It looks like we should unwrap them in case there are tuples or unions inside.
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.
I actually had that but apparently lost it in one of the updates. I wasn't sure whether it was necessary, but have now managed to come up with a test case. I also think it might be a good idea to also recurse down the upper bound, but couldn't come up with a test case. Ideas how to construct one?
The `unioncomplexity` is used as an estimate for the number of times `tmerge` had to be called to form the type.
44c7a3b
to
4a43aa4
Compare
Another try... @nanosoldier I'll merge if CI goes well and benchmarks looks good, unless anyone objects. |
unioncomplexity
instead of the unionlen
in tmerge
unioncomplexity
instead of the unionlen
in tmerge
Restarted freebsd ci after it hit
|
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan |
The test failures on travis 32bit look interesting: IIUC correctly, 65535 is chosen as port number and furthermore, it is assumed that adding 1 to a port number gives a valid port number again, which in this case is obviously not true. Anyway does not look related, benchmarks are within noise threshold, so I'm finally merging this. |
This seems to have caused a regression in |
The difference in code seems to enter here:
At this point, it seems a whole bunch of broadcast code has been inlined in spite of relatively weak type information. In contrast, the prior, faster version looks like this:
|
Drilled down to: julia> Core.Compiler.tmerge(SubArray{_1,_2,_3,_4,false} where _4 where _3 where _2 where _1, SubArray{_1,_2,_3,_4,true} where _4 where _3 where _2 where _1)
# before:
Union{SubArray{_1,_2,_3,_4,false} where _4 where _3 where _2 where _1, SubArray{_1,_2,_3,_4,true} where _4 where _3 where _2 where _1}
# after:
SubArray I guess we need to be a bit more promiscuous about when we allow a |
That said, the fact that the wider type information leads to more aggressive inlining which is then less performant seems to be an issue by itself. |
PR that addresses the regression at #27843. |
Yes I think this is mostly an inlining issue. |
…7417) The `unioncomplexity` is used as an estimate for the number of times `tmerge` had to be called to form the type.
Fixes #27316.