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

Small vector relocation #6468

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

isidorostsa
Copy link
Contributor

@isidorostsa isidorostsa commented Apr 3, 2024

hpx::small_vector is a small buffer optimized vector. This PR introduces two enhancements:

  • Making small_vector compatible with the proposed inplace_vector. This is done with creating a static_vector typedef for small_vector that limits it to only use the direct storage mode, without introducing overhead with that limitation.

  • Utilizing P1144's relocation algorithms to insert and remove elements, as well as relocate the buffer when needed. This abstracts away much of the logic needed of those operations and also optimizes them based on P1144's relocation semantics. A small_vector is also marked as trivially relocatable when the type it is carrying is trivially relocatable itself. That is because it is always possible that the element will be stored in the object itself.

For a small_vector<std::vector<T>> the observable speedup of using trivial relocation for insertions, push_backs, and deletions is in the order of 2-3x, benchmarks and tests for this are to be added to this PR.

Copy link

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
+0.60% 50.00%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (323904c) 197388 166693 84.45%
Head commit (ead5197) 189635 (-7753) 161286 (-5407) 85.05% (+0.60%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#6468) 24 12 50.00%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

You may notice some variations in coverage metrics with the latest Coverage engine update. For more details, visit the documentation

@hkaiser
Copy link
Member

hkaiser commented Apr 3, 2024

@isidorostsa could you please take care of the inspect and clang-format issues? Also please rebase onto master.

@isidorostsa
Copy link
Contributor Author

@isidorostsa could you please take care of the inspect and clang-format issues? Also please rebase onto master.

Yes, apologies for not already doing that

@StellarBot
Copy link

Performance test report

HPX Performance

Comparison

BENCHMARKFORK_JOIN_EXECUTORPARALLEL_EXECUTORSCHEDULER_EXECUTOR
For Each(=)=(=)

Info

PropertyBeforeAfter
HPX Datetime2024-03-18T14:00:30+00:002024-04-03T22:00:22+00:00
HPX Commitd27ac2ed751c6a
Datetime2024-03-18T09:18:04.949759-05:002024-04-03T17:10:10.128467-05:00
Clusternamerostamrostam
Compiler/opt/apps/llvm/13.0.1/bin/clang++ 13.0.1/opt/apps/llvm/13.0.1/bin/clang++ 13.0.1
Hostnamemedusa08.rostam.cct.lsu.edumedusa08.rostam.cct.lsu.edu
Envfile

Comparison

BENCHMARKNO-EXECUTOR
Future Overhead - Create Thread Hierarchical - Latch(=)

Info

PropertyBeforeAfter
HPX Datetime2024-03-18T14:00:30+00:002024-04-03T22:00:22+00:00
HPX Commitd27ac2ed751c6a
Datetime2024-03-18T09:19:53.062988-05:002024-04-03T17:11:56.568678-05:00
Clusternamerostamrostam
Compiler/opt/apps/llvm/13.0.1/bin/clang++ 13.0.1/opt/apps/llvm/13.0.1/bin/clang++ 13.0.1
Hostnamemedusa08.rostam.cct.lsu.edumedusa08.rostam.cct.lsu.edu
Envfile

Comparison

BENCHMARKFORK_JOIN_EXECUTOR_DEFAULT_FORK_JOIN_POLICY_ALLOCATORPARALLEL_EXECUTOR_DEFAULT_PARALLEL_POLICY_ALLOCATORSCHEDULER_EXECUTOR_DEFAULT_SCHEDULER_EXECUTOR_ALLOCATOR
Stream Benchmark - Add(=)(=)(=)
Stream Benchmark - Scale(=)(=)-
Stream Benchmark - Triad(=)(=)(=)
Stream Benchmark - Copy(=)==

Info

PropertyBeforeAfter
HPX Datetime2024-03-18T14:00:30+00:002024-04-03T22:00:22+00:00
HPX Commitd27ac2ed751c6a
Datetime2024-03-18T09:20:13.002391-05:002024-04-03T17:12:13.340070-05:00
Clusternamerostamrostam
Compiler/opt/apps/llvm/13.0.1/bin/clang++ 13.0.1/opt/apps/llvm/13.0.1/bin/clang++ 13.0.1
Hostnamemedusa08.rostam.cct.lsu.edumedusa08.rostam.cct.lsu.edu
Envfile

Explanation of Symbols

SymbolMEANING
=No performance change (confidence interval within ±1%)
(=)Probably no performance change (confidence interval within ±2%)
(+)/(-)Very small performance improvement/degradation (≤1%)
+/-Small performance improvement/degradation (≤5%)
++/--Large performance improvement/degradation (≤10%)
+++/---Very large performance improvement/degradation (>10%)
?Probably no change, but quite large uncertainty (confidence interval with ±5%)
??Unclear result, very large uncertainty (±10%)
???Something unexpected…

Copy link

@Quuxplusone Quuxplusone left a comment

Choose a reason for hiding this comment

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

I strongly recommend that you split this into two PRs: one for refactoring around relocatability, and one for inplace_vector-emulation. They seem almost entirely orthogonal to each other.

Comment on lines +306 to +307
static_assert(!emulate_inplace_vector,
"If called in an inplace_vector, it is a bug.");

Choose a reason for hiding this comment

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

FWIW, std::inplace_vector allows you to call .reserve. It's a no-op for small capacities, and invariably throws bad_alloc (or length_error? I'm not sure even LWG knows yet) for large capacities. I don't know if you consider that an improvement or not.

if constexpr (emulate_inplace_vector)
{
// Can not have an inplace_vector with a size larger than N
if (s <= capacity())

Choose a reason for hiding this comment

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

Nit: Cannot
Major: Isn't this condition backwards? You mean if (s > capacity()).

Comment on lines +551 to +552
// We assume that the template parameters of "other" are the same
// as "this".

Choose a reason for hiding this comment

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

The comment is superfluous: the injected-class-name small_vector on line 549 literally means small_vector<T, MinInlineCapacity, emulate_inplace_vector> because that's how the language works.

Comment on lines +946 to +949
if constexpr (emulate_inplace_vector)
{
return capacity<direction::direct>();
}

Choose a reason for hiding this comment

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

This seems redundant, since is_direct() returns constexpr true in that case. Or if you're trying to avoid even instantiating capacity<direction::indirect>() in that case, then it ought to be enclosed in an else block.

template <typename T, std::size_t N, typename Alloc, bool emul>
struct is_trivially_relocatable<
hpx::detail::small_vector<T, N, Alloc, emul>>
: is_trivially_relocatable<T>

Choose a reason for hiding this comment

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

And Alloc needs to be trivially relocatable, and Alloc::pointer, and it must have the right POCMA/POCCA/POCS behavior if you care about any of that stuff. See https://github.com/Quuxplusone/llvm-project/blob/trivially-relocatable-v107/libcxx/include/__memory/allocator_traits.h#L421-L433 and https://github.com/Quuxplusone/llvm-project/blob/trivially-relocatable-v107/libcxx/include/vector#L399-L407 for my approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, that is interesting. Will correct and write tests for this. Thank you for the catch!

@isidorostsa
Copy link
Contributor Author

I strongly recommend that you split this into two PRs: one for refactoring around relocatability, and one for inplace_vector-emulation. They seem almost entirely orthogonal to each other.

You are absolutely right to point that out, I will be doing that.

@hkaiser
Copy link
Member

hkaiser commented Apr 4, 2024

I strongly recommend that you split this into two PRs: one for refactoring around relocatability, and one for inplace_vector-emulation. They seem almost entirely orthogonal to each other.

I agree to this.

Copy link

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
+0.59% 50.00%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (323904c) 197388 166693 84.45%
Head commit (433a86d) 189909 (-7479) 161498 (-5195) 85.04% (+0.59%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#6468) 72 36 50.00%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

You may notice some variations in coverage metrics with the latest Coverage engine update. For more details, visit the documentation

@hkaiser hkaiser modified the milestones: 1.10.0, 1.11.0 Apr 28, 2024
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