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

[Pytorch] Specialize guts of c10::optional for 32-bit scalars #47015

Closed
wants to merge 8 commits into from

Conversation

swolchok
Copy link
Contributor

@swolchok swolchok commented Oct 28, 2020

Stack from ghstack:

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use std::optional (or implement that functionality ourselves). We can't use std::optional because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: D24552280

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

[ghstack-poisoned]
swolchok added a commit that referenced this pull request Oct 28, 2020
c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

ghstack-source-id: 115395876
Pull Request resolved: #47015
@dr-ci
Copy link

dr-ci bot commented Oct 28, 2020

💊 CI failures summary and remediations

As of commit c6d8a51 (more details on the Dr. CI page):


💚 💚 Looks good so far! There are no failures yet. 💚 💚


This comment was automatically generated by Dr. CI (expand for details).Follow this link to opt-out of these comments for your Pull Requests.

Please report bugs/suggestions on the GitHub issue tracker or post in the (internal) Dr. CI Users group.

See how this bot performed.

This comment has been revised 26 times.

@swolchok
Copy link
Contributor Author

I tried to replicate the benchmark on #46598 so as to provide an apples-to-apple comparison, but I couldn't run the benchmark with the most recent version of that branch checked out.

…r 32-bit scalars"

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

[ghstack-poisoned]
swolchok added a commit that referenced this pull request Oct 28, 2020
Pull Request resolved: #47015

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.
ghstack-source-id: 115425175

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)
…tional for 32-bit scalars"

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

[ghstack-poisoned]
swolchok added a commit that referenced this pull request Oct 29, 2020
Pull Request resolved: #47015

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.
ghstack-source-id: 115447317

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)
std::is_nothrow_move_assignable<T>::value &&
std::is_nothrow_move_constructible<T>::value) {
if (init_ && !rhs.init_) {
clear();
Copy link
Contributor

Choose a reason for hiding this comment

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

clear() itself has a branch checking init_ again. The compiler might be able to optimize it away and branch prediction can probably handle it quite well too, but it might be safer to have a separate private method for clearing when we already know that init_==true.

Same above in the copy constructor and for the constexpr version.

constexpr_optional_base<typename std::remove_const<
T>::type>, // use base with trivial destructor
optional_base<typename std::remove_const<T>::type>>::type;
std::is_scalar<T>::value && sizeof(T) <= 4,
Copy link
Contributor

Choose a reason for hiding this comment

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

c10::ScalarType and c10::Layout are enums, so they'll hit the optimization here, but we'd also like to hit the optimization for c10::Device, which is a 32bit struct that can for most purposes be treated like a Scalar.

Should we use checks for trivial movability/copyability here instead of std::is_scalar? That might hit c10::Device too. Also not sure if we need the 32bit sizeof constraint. If a type is trivially movable/copyable, then the optimization could make sense even if the type is larger.

We might need to rewrite the optimization a bit though. What it currently does is it unconditionally calls the copy/move constructor, possibly on uninitialized elements. With scalars, that is likely within the standard. I'm not sure if doing that for trivially copy/movable types is within the standard or UB. Do you happen to know?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it unconditionally calls the copy/move constructor, possibly on uninitialized elements. With scalars, that is likely within the standard. I'm not sure if doing that for trivially copy/movable types is within the standard or UB. Do you happen to know?

We're not using a union, so all we require is that we can copy and move default-constructed objects of type T. If a type can't do that, it's broken. I'm not sure what's possibly uninitialized by the optional implementation; initialization is left up to T's default constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We're not using a union

Ah, and that's a problem because T may not have a default constructor. I'll see what I can do.

Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like, for all the types we care about this optimization applying to, we have default constructors

…ars"

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

[ghstack-poisoned]
swolchok added a commit that referenced this pull request Oct 29, 2020
Pull Request resolved: #47015

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.
ghstack-source-id: 115514082

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)
@ezyang
Copy link
Contributor

ezyang commented Oct 30, 2020

This was a very interesting and informative PR to review, learned something. Thanks!

c10/util/Optional.h Outdated Show resolved Hide resolved

template <class T>
class optional : private OptionalBase<T> {
template <class U> // re-declaration for nvcc on Windows.
using OptionalBase = typename std::conditional<
std::is_trivially_destructible<U>::value, // if possible
Copy link
Contributor

Choose a reason for hiding this comment

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

We could use this PR to fix the duplication here. But not mandatory, up to you.

…ars"

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

[ghstack-poisoned]
swolchok added a commit that referenced this pull request Nov 3, 2020
Pull Request resolved: #47015

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.
ghstack-source-id: 115769681

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)
…tional for 32-bit scalars"

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

[ghstack-poisoned]
… on "[Pytorch] Specialize guts of c10::optional for 32-bit scalars"

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

[ghstack-poisoned]
swolchok added a commit that referenced this pull request Nov 3, 2020
Pull Request resolved: #47015

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.
ghstack-source-id: 115804292

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)
…pecialize guts of c10::optional for 32-bit scalars"

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)

[ghstack-poisoned]
swolchok added a commit that referenced this pull request Nov 4, 2020
Pull Request resolved: #47015

c10::optional has non-trivial copy and move operations always. This change specializes it for 32-bit scalars so that it has trivial copy and move operations in that case. Ideally, we would instead rely on P0602 "variant and optional should propagate copy/move triviality" and use `std::optional` (or implement that functionality ourselves). We can't use `std::optional` because we are stuck with C++14. Implementing the full P0602 ourselves would add even more complexity. We could do it, but this should be a helpful first step.
ghstack-source-id: 115886743

Differential Revision: [D24552280](https://our.internmc.facebook.com/intern/diff/D24552280/)
@codecov
Copy link

codecov bot commented Nov 5, 2020

Codecov Report

Merging #47015 into gh/swolchok/4/base will decrease coverage by 0.01%.
The diff coverage is 86.79%.

@@                  Coverage Diff                   @@
##           gh/swolchok/4/base   #47015      +/-   ##
======================================================
- Coverage               60.82%   60.81%   -0.02%     
======================================================
  Files                    2749     2750       +1     
  Lines                  254038   254009      -29     
======================================================
- Hits                   154531   154481      -50     
- Misses                  99507    99528      +21     

@facebook-github-bot
Copy link
Contributor

This pull request has been merged in df5b469.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants