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

Let tmerge form a Union more often #27843

Merged
merged 2 commits into from
Jan 12, 2021
Merged

Conversation

martinholters
Copy link
Member

This addresses the performance regression of mapslices introduced by #27417 and noticed in #27828. I think replacing isconcretetype(typea) || isType(typea) with unioncomplexity(typea) == 0 makes a lot of sense and is in the same spirit as the original PR.

However, I had to introduce another condition due to this quirk (which happens both before #27417 and with this PR):

julia> foo(a,b,c,d) = SubArray(a,b,c,d)
foo (generic function with 1 method)

julia> atypes = Tuple{Union{IndexCartesian, IndexLinear}, Any, Union{Tuple{}, Tuple{Any,Vararg{Any,N} where N}}, Tuple}
Tuple{Union{IndexCartesian, IndexLinear},Any,Union{Tuple{}, Tuple{Any,Vararg{Any,N} where N}},Tuple}

julia> atypes2 = Tuple{Union{IndexCartesian, IndexLinear}, Any, Tuple, Tuple}
Tuple{Union{IndexCartesian, IndexLinear},Any,Tuple,Tuple}

julia> atypes <: atypes2
true

julia> code_typed(foo, atypes)
1-element Array{Any,1}:
 CodeInfo(
1 1%1 = Main.SubArray(%%a, %%b, %%c, %%d)::SubArray                      │
  └──      return %1                                                        │
) => SubArray

julia> code_typed(foo, atypes2)
1-element Array{Any,1}:
 CodeInfo(
1 1%1 = Main.SubArray(%%a, %%b, %%c, %%d)::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}
  └──      return %1                                                        │
) => 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}

Note that the wider atypes2 gives the narrower inference result. Hence the additional Tuple condition to turn Union{Tuple{}, Tuple{Any,Vararg{Any,N} where N}} into Tuple. (They should probably be type-equal anyway, but that's a different issue.) This leaves me a bit unsatisfied, but seems to be necessary to fix the regression.

@KristofferC KristofferC changed the title Let tmerge from a Union more often Let tmerge form a Union more often Jun 28, 2018
@JeffBezanson
Copy link
Member

A non-monotonicity is pretty bad; I think it would be better to fix that and address the regression by improving the inlining logic (which I'm working on now).

Copy link
Member

@vtjnash vtjnash left a comment

Choose a reason for hiding this comment

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

Monotonicity is certainly very nice, but I assume v0.6 would have shown the same behavior? It’s only recently that I tried to push hard on these edge cases - they’re definitely very difficult to design.

@@ -331,8 +331,10 @@ function tmerge(@nospecialize(typea), @nospecialize(typeb))
# XXX: this should never happen
return Any
end
# it's always ok to form a Union of two concrete types
if (isconcretetype(typea) || isType(typea)) && (isconcretetype(typeb) || isType(typeb))
# it's always ok to form a Union of two Union-free types
Copy link
Member

Choose a reason for hiding this comment

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

I think an alternate literal translation of this would be isa(unwrap_unionall(T), DataType)

@martinholters
Copy link
Member Author

I've looked a little bit into the non-montonicity. Union-splitting the atypes case gives these four combinations:

argtypes return type
Tuple{IndexCartesian,Any,Tuple{},Tuple} SubArray{_1,_2,_3,Tuple{},false} where _3 where _2 where _1
Tuple{IndexLinear,Any,Tuple{},Tuple} SubArray{_1,_2,_3,Tuple{},true} where _3 where _2 where _1
Tuple{IndexCartesian,Any,Tuple{Any,Vararg{Any,N} where N},Tuple} SubArray{_1,_2,_3,_4,false} where _4 where _3 where _2 where _1
Tuple{IndexLinear,Any,Tuple{Any,Vararg{Any,N} where N},Tuple} SubArray{_1,_2,_3,_4,true} where _4 where _3 where _2 where _1

Then tmerge'ing the first two gives a Union and then tmerge'ing the third widens to SubArray. On the other hand, with atypes2, union-splitting only gives two combinations:

argtypes return type
Tuple{IndexCartesian,Any,Tuple,Tuple} SubArray{_1,_2,_3,_4,false} where _4 where _3 where _2 where _1
Tuple{IndexLinear,Any,Tuple,Tuple} SubArray{_1,_2,_3,_4,true} where _4 where _3 where _2 where _1

These are tmerged into the Union, done.

Now interestingly, if the order of the tmerge operations in the first case was changed, one could obtain the same results, as the first return type is a subtype of the third and the second one is a subtype of the fourth. I have an idea how to make tmerge also give a Union in this case. I'll give it a try. Meanwhile, #27857 might be the better fix to address the issue that brought me here.

@martinholters martinholters force-pushed the mh/tmerge_to_union_more_often branch from d778622 to af3c79e Compare June 29, 2018 08:52
@martinholters
Copy link
Member Author

Ok, this is now much more elegant. However, as the original issue is better tackled with #27857 (addressing the underlying problem instead of working around it), the need for this is much lower. It may still give slightly better inference results, but whether they give tangible benefits is another question. It does fix above-mentioned quirk, though, as now

julia> code_typed(foo, atypes)
1-element Array{Any,1}:
 CodeInfo(
1 1%1 = Main.SubArray(%%a, %%b, %%c, %%d)::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}
  └──      return %1                                                        │
) => 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}

julia> code_typed(foo, atypes2)
1-element Array{Any,1}:
 CodeInfo(
1 1%1 = Main.SubArray(%%a, %%b, %%c, %%d)::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}
  └──      return %1                                                        │
) => 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}

@martinholters martinholters added compiler:inference Type inference needs nanosoldier run This PR should have benchmarks run on it labels Jun 29, 2018
@martinholters
Copy link
Member Author

@nanosoldier runbenchmarks(ALL, vs=":master")

@nanosoldier
Copy link
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan

@martinholters
Copy link
Member Author

@nanosoldier runbenchmarks(ALL, vs=":master")

1 similar comment
@martinholters
Copy link
Member Author

@nanosoldier runbenchmarks(ALL, vs=":master")

@martinholters
Copy link
Member Author

@ararslan is the soldier down? I wanted to check how the recent changes, in particular wrt inlining, interact with this PR.

@ararslan
Copy link
Member

Yeah there was a server error so I restarted it.

@nanosoldier runbenchmarks(ALL, vs=":master")

@ararslan ararslan removed the needs nanosoldier run This PR should have benchmarks run on it label Jul 11, 2018
@nanosoldier
Copy link
Collaborator

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan

@martinholters
Copy link
Member Author

Ok, this doesn't make much of a difference performance-wise now. Mostly that's a hint that the inlining heuristics are saner now. I still find this change esthetically pleasing, but there is little to no tangible benefit, so I leave it to others to make the call here.

@StefanKarpinski
Copy link
Member

It does seem nicer to me as well in my very mildly informed opinion. @JeffBezanson?

@JeffBezanson
Copy link
Member

I would worry about compiler performance here; using more Union types will cause us to infer more signatures.

@vtjnash
Copy link
Member

vtjnash commented Jul 12, 2018

I think this seems good

@JeffBezanson
Copy link
Member

JeffBezanson commented Jul 12, 2018

If we're going to merge this it would be good to add some sort of test related to #27843 (comment) (the example from the OP basically).

@martinholters martinholters force-pushed the mh/tmerge_to_union_more_often branch from af3c79e to f72bb13 Compare July 13, 2018 07:06
@martinholters
Copy link
Member Author

Not sure how good a benchmark of compiler performance building the sysmimg is, but:
master:

Total ─────── 140.776988 seconds 
Base: ───────  32.209240 seconds 22.8796%
Stdlibs: ────  92.753201 seconds 65.8866%
Precompile: ─  15.812288 seconds 11.2322%

this PR:

Total ─────── 147.342998 seconds 
Base: ───────  34.227599 seconds 23.2299%
Stdlibs: ────  97.176708 seconds 65.9527%
Precompile: ─  15.936632 seconds 10.816%

So, yes, might cost us a few percent.

Test to the same effect as OP, but not relying on the specifics of the SubArray constructor added.

@vtjnash
Copy link
Member

vtjnash commented Dec 28, 2020

They both give SubArray now, but apparently I said this is good, if you care to rebase

Let tmerge decide whether to directly form a Union based on unioncomplexity, not
concreteness.
@martinholters martinholters force-pushed the mh/tmerge_to_union_more_often branch from f72bb13 to 2c45fc2 Compare January 7, 2021 07:01
@martinholters
Copy link
Member Author

Rebased. Let's see whether CI still likes it.

@martinholters
Copy link
Member Author

Added a test to address #27843 (comment). CI had been all green, now there is a fail in SHA on tester_linux64 which I don't understand but assume unrelated. If someone can confirm it's unrelated to this PR, I'll go ahead and merge unless anyone objects.

@vtjnash
Copy link
Member

vtjnash commented Jan 12, 2021

It is an AMD cpu bug

@vtjnash vtjnash merged commit 6c1824d into master Jan 12, 2021
@vtjnash vtjnash deleted the mh/tmerge_to_union_more_often branch January 12, 2021 17:51
JeffBezanson added a commit that referenced this pull request Jan 26, 2021
JeffBezanson added a commit that referenced this pull request Jan 27, 2021
vtjnash pushed a commit that referenced this pull request Jan 27, 2021
This reverts commit 6c1824d.

Fixes #39349. The extra inference precision is nice, but seems to carry too much risk of blowup.
@KristofferC KristofferC mentioned this pull request Jan 27, 2021
60 tasks
ElOceanografo pushed a commit to ElOceanografo/julia that referenced this pull request May 4, 2021
Let tmerge decide whether to directly form a Union based on unioncomplexity, not
concreteness.
ElOceanografo pushed a commit to ElOceanografo/julia that referenced this pull request May 4, 2021
…ang#39406)

This reverts commit 6c1824d.

Fixes JuliaLang#39349. The extra inference precision is nice, but seems to carry too much risk of blowup.
antoine-levitt pushed a commit to antoine-levitt/julia that referenced this pull request May 9, 2021
…ang#39406)

This reverts commit 6c1824d.

Fixes JuliaLang#39349. The extra inference precision is nice, but seems to carry too much risk of blowup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:inference Type inference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants