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

Avoid calling size() in empty() member functions #1836

Merged

Conversation

N-Dekker
Copy link
Contributor

Might slightly improve the speed of applications built in Debug mode.

Having empty() call size() is somewhat disappointing for users who follow the guideline to replace their size() calls by the corresponding empty() calls. For example by Clang-Tidy:
https://clang.llvm.org/extra/clang-tidy/checks/readability-container-size-empty.html

Might slightly improve the speed of applications built in Debug mode.

Having `empty()` call `size()` is somewhat disappointing for users who follow the guideline to replace their `size()` calls by the corresponding `empty()` calls. For example by Clang-Tidy:
https://clang.llvm.org/extra/clang-tidy/checks/readability-container-size-empty.html
@N-Dekker N-Dekker requested a review from a team as a code owner April 14, 2021 16:52
@StephanTLavavej StephanTLavavej added the performance Must go faster label Apr 14, 2021
@N-Dekker
Copy link
Contributor Author

Thank you for adding this pull request to Initial Review, @StephanTLavavej

Further motivation (if necessary): Users expect v.empty() to be at least as fast as (and possibly faster than) v.size() == 0. For any container type, on any build configuration. It seems to me that the extra size() function call within empty() should be avoided, in order to fulfill this expectation.

@seanmiddleditch
Copy link

General note on the value of these kinds of small optimizations in some industries:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4456.pdf (I'm a co-author)
https://github.com/electronicarts/EASTL

Note that EASTL is by no means unique, it's just the only major implementation of a gaming-focused STL replacement that is available publicly of which I'm aware. (We have our own - several of our own - such libraries at Blizzard, for example.)

@N-Dekker
Copy link
Contributor Author

@seanmiddleditch

General note on the value of these kinds of small optimizations in some industries:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4456.pdf (I'm a co-author)
https://github.com/electronicarts/EASTL

Thanks for your encouraging comment, Sean!

I just had a look at EASTL. Interesting! Unfortunately, it appears that EASTL also has an empty() member function defined in terms of size() ! Looking at span<T, Extent>::empty(): https://github.com/electronicarts/EASTL/blob/3.17.06/include/EASTL/span.h#L279-L283 Obviously this particular case could be fixed easily by returning mnSize == 0 instead. 😃

@seanmiddleditch
Copy link

@N-Dekker:

Unfortunately, it appears that EASTL also has an empty() member function defined in terms of size() ! Looking at span<T, Extent>::empty(): https://github.com/electronicarts/EASTL/blob/3.17.06/include/EASTL/span.h#L279-L283

Haha, wow, that's definitely against its original spirit. span is much newer than the original EA where the concerns were more focused on vector and the like. Probably should be filed as a bug on EASTL itself... not relevant to this bug, other than making my point look goofy and weak. :)

@MikeGitb
Copy link

Just curious: Has anyone seen benchmarks that show a perf difference or is this "only" about debug performance (which of course is an important aspect by itself)?

Copy link
Contributor

@sam20908 sam20908 left a comment

Choose a reason for hiding this comment

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

LGTM. Although I haven't benchmarked this yet, this change is very simple.

Are there any other occurrences of empty that needs this treatment?

@StephanTLavavej
Copy link
Member

I searched and didn't find any other occurrences of member empty() implementations that should be changed similarly. There's a non-member empty(initializer_list):

STL/stl/inc/xutility

Lines 2045 to 2048 in f675d68

template <class _Elem>
_NODISCARD constexpr bool empty(initializer_list<_Elem> _Ilist) noexcept {
return _Ilist.size() == 0;
}

Replacing this with a first() == last() comparison would be worse for debug codegen but possibly slightly better for release mode; in any event I don't think this overload is used frequently enough to matter.

@StephanTLavavej StephanTLavavej self-assigned this Apr 30, 2021
@StephanTLavavej StephanTLavavej merged commit b95ba0e into microsoft:main May 1, 2021
@StephanTLavavej
Copy link
Member

Thanks for improving debug codegen - and congratulations on your first microsoft/STL commit! 🎉 😸 🚀

@N-Dekker
Copy link
Contributor Author

N-Dekker commented May 3, 2021

@StephanTLavavej

Thanks for improving debug codegen - and congratulations on your first microsoft/STL commit! 🎉 😸 🚀

Thank you for merging my pull request. That's one tiny little step for Microsoft's STL, but one giant leap for me 😸

Thanks also to the reviewers and the other participants! Cool!

N-Dekker added a commit to SuperElastix/elastix that referenced this pull request May 23, 2021
Ran Clang-Tidy (LLVM 11.1.0) `readability-container-size-empty`, as motivated at https://clang.llvm.org/extra/clang-tidy/checks/readability-container-size-empty.html :

"The emptiness of a container should be checked using the empty() method instead of the size() method. It is not guaranteed that size() is a constant-time function, and it is generally more efficient and also shows clearer intent to use empty(). Furthermore some containers may implement the empty() method but not implement the size() method. Using empty() whenever possible makes it easier to switch to another container in the future."

Got extra motivated by having my very first microsoft/STL commit on this topic: microsoft/STL@b95ba0e "Avoid calling size() in empty() member functions" (merged from pull request microsoft/STL#1836)

Follows ITK pull request InsightSoftwareConsortium/ITK#414 commit InsightSoftwareConsortium/ITK@c82a5f2 "PERF: readability container size empty", Hans Johnson, January 2019.
N-Dekker added a commit to SuperElastix/elastix that referenced this pull request May 23, 2021
Ran Clang-Tidy (LLVM 11.1.0) `readability-container-size-empty`, as motivated at https://clang.llvm.org/extra/clang-tidy/checks/readability-container-size-empty.html :

"The emptiness of a container should be checked using the empty() method instead of the size() method. It is not guaranteed that size() is a constant-time function, and it is generally more efficient and also shows clearer intent to use empty(). Furthermore some containers may implement the empty() method but not implement the size() method. Using empty() whenever possible makes it easier to switch to another container in the future."

Got extra motivated by having my very first microsoft/STL commit on this topic: microsoft/STL@b95ba0e "Avoid calling size() in empty() member functions" (merged from pull request microsoft/STL#1836)

Follows ITK pull request InsightSoftwareConsortium/ITK#414 commit InsightSoftwareConsortium/ITK@c82a5f2 "PERF: readability container size empty", Hans Johnson, January 2019.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Must go faster
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants