Skip to content

Reimplement cudf::merge for nested types without using comparators - #14250

Merged
rapids-bot[bot] merged 22 commits into
NVIDIA:branch-23.12from
divyegala:merge-new-algo
Oct 28, 2023
Merged

Reimplement cudf::merge for nested types without using comparators#14250
rapids-bot[bot] merged 22 commits into
NVIDIA:branch-23.12from
divyegala:merge-new-algo

Conversation

@divyegala

@divyegala divyegala commented Oct 4, 2023

Copy link
Copy Markdown
Contributor

Description

Part of #11844

This PR also uses new experimental comparators for non-nested types by introducing a new device constructor for cudf::experimental::row::lexicographic::device_row_comparator. In the case of non-nested types, preprocessing can be skipped so comparators can be created on the fly. This solution helps us avoid creating 3 comparator types because thrust::merge can call the operator with indices from either side of the table.

Furthermore, the PR reworks cudf/detail/merge.cuh by removing any CUDA headers/components to expose a true detail API of the form cudf/detail/merge.hpp.

Benchmark comparison for non-nested types

Compilation time increases from ~6 mins to ~7 mins.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@divyegala divyegala added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change labels Oct 4, 2023
@github-actions github-actions Bot added the libcudf Affects libcudf (C++/CUDA) code. label Oct 4, 2023
@divyegala

divyegala commented Oct 4, 2023

Copy link
Copy Markdown
Contributor Author
Benchmark                                          Time             CPU      Time Old      Time New       CPU Old       CPU New
-------------------------------------------------------------------------------------------------------------------------------
Merge/pow2tables/2/manual_time                  +0.0034         +0.0051             0             0             0             0
Merge/pow2tables/4/manual_time                  +0.0150         +0.0136             1             1             1             1
Merge/pow2tables/8/manual_time                  +0.0045         +0.0042             2             2             2             2
Merge/pow2tables/16/manual_time                 +0.0108         +0.0108             4             4             4             4
Merge/pow2tables/32/manual_time                 +0.0128         +0.0127             9            10            10            10
Merge/pow2tables/64/manual_time                 +0.0123         +0.0123            22            23            22            23
Merge/pow2tables/128/manual_time                +0.0147         +0.0147            52            53            52            53
OVERALL_GEOMEAN                                 +0.0105         +0.0105             0             0             0             0

@copy-pr-bot

copy-pr-bot Bot commented Oct 16, 2023

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@divyegala divyegala changed the title Reimplement cudf::merge without using comparators Reimplement cudf::merge for nested types without using comparators Oct 16, 2023
@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@bdice bdice left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is great. I have a couple early suggestions on the draft.

Comment thread cpp/src/merge/merge.cu
Comment thread cpp/src/merge/merge.cu Outdated
@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@github-actions github-actions Bot added the CMake CMake build issue label Oct 20, 2023
@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@divyegala
divyegala marked this pull request as ready for review October 20, 2023 17:34
@divyegala
divyegala requested a review from a team as a code owner October 20, 2023 17:34

@bdice bdice left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Awesome work. I have a few comments.

Comment thread cpp/benchmarks/sort/rank_lists.cpp
Comment thread cpp/benchmarks/sort/rank_structs.cpp
Comment thread cpp/include/cudf/merge.hpp Outdated
Comment thread cpp/src/merge/merge.cu Outdated
Comment thread cpp/src/merge/merge.cu Outdated
@divyegala
divyegala requested a review from bdice October 26, 2023 00:18
@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@bdice bdice left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving. I had one comment about whether a comment is really a TODO or not, but otherwise LGTM.

Comment thread cpp/src/merge/merge.cu Outdated
@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

1 similar comment
@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@mythrocks mythrocks left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is looking very good. I have a couple of trivial nitpicks.

I'm not done. I've just hit the meat of the change. I'll resume the review shortly.

Comment thread cpp/include/cudf/merge.hpp
* `null_order::BEFORE` for all columns.
* @param comparator Physical element relational comparison functor.
*/
template <bool nested_disable = not has_nested_columns, CUDF_ENABLE_IF(nested_disable)>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Interesting phrasing. I'll remember this for when I need it.

Is nested_disable used elsewhere?
If not, would CUDF_ENABLE_IF(not has_nested_columns) be less readable?

@divyegala divyegala Oct 27, 2023

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I can change the variable name if you'd like, but I cannot use the class-template has_nested_columns directly here.

Let me explain why, and my apologies if you already knew this but I misunderstood what you are suggesting.

If I did:

template <CUDF_ENABLE_IF(not has_nested_columns)>

then we'd not be able to trigger SFINAE. This is because has_nested_columns is a class-template. So, when you write device_comparator<true> d_comp, the substitution for the enable-if on the constructor will trigger a failure as enable_if::type will be ill-formed.

As a result of which, we want to defer the SFINAE at the member function level so that it behaves the way it is intended to: as an overload.

Comment thread cpp/include/cudf/table/experimental/row_operators.cuh
Comment thread cpp/src/merge/merge.cu Outdated
Comment thread cpp/src/merge/merge.cu Outdated
Comment thread cpp/src/merge/merge.cu
{
size_type const left_size = left_table.num_rows();
size_type const right_size = right_table.num_rows();
size_type const total_size = left_size + right_size;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Another impertinent question: Do we need to protect against the case where the total_size overflows?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@mythrocks mythrocks left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. A couple of minor questions.
Edit: Thanks, that was an interesting read. I've learnt a thing or two from this change.

@divyegala

Copy link
Copy Markdown
Contributor Author

/ok to test

@divyegala

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit 2bc454a into NVIDIA:branch-23.12 Oct 28, 2023
Comment thread cpp/src/merge/merge.cu
Comment on lines +641 to +647
CUDF_EXPECTS(std::accumulate(tables_to_merge.cbegin(),
tables_to_merge.cend(),
cudf::size_type{0},
[](auto const& running_sum, auto const& tbl) {
return running_sum + tbl.num_rows();
}) <= std::numeric_limits<cudf::size_type>::max(),
"Total number of merged rows exceeds row limit");

@bdice bdice Oct 30, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@divyegala (cc: @mythrocks) I don't think this actually protects against overflow. By the definition of overflow (if it were even defined behavior for signed types, which it's not...), the sum will always be less than the max limit of size_type when it rolls over. You need to use a larger type and accumulate in std::size_t precision. Can you file a follow-up PR with this change?

Suggested change
CUDF_EXPECTS(std::accumulate(tables_to_merge.cbegin(),
tables_to_merge.cend(),
cudf::size_type{0},
[](auto const& running_sum, auto const& tbl) {
return running_sum + tbl.num_rows();
}) <= std::numeric_limits<cudf::size_type>::max(),
"Total number of merged rows exceeds row limit");
CUDF_EXPECTS(std::accumulate(tables_to_merge.cbegin(),
tables_to_merge.cend(),
size_t{0},
[](auto const& running_sum, auto const& tbl) {
return running_sum + static_cast<size_t>(tbl.num_rows());
}) <= static_cast<size_t>(std::numeric_limits<cudf::size_type>::max()),
"Total number of merged rows exceeds row limit");

Examples of this pattern:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing that out @bdice! I'll raise a PR

rapids-bot Bot pushed a commit that referenced this pull request Oct 31, 2023
#14250 added a check to ensure `cudf::merge` throws when the total number of merged rows exceed `cudf::size_type` limit, however @bdice pointed out that the check was not correct because the accumulation was still occurring in `cudf::size_type`. This PR computes the accumulation in `std::size_t`.

Authors:
  - Divye Gala (https://github.com/divyegala)

Approvers:
  - Bradley Dice (https://github.com/bdice)
  - MithunR (https://github.com/mythrocks)
  - Nghia Truong (https://github.com/ttnghia)

URL: #14345
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CMake CMake build issue improvement Improvement / enhancement to an existing function libcudf Affects libcudf (C++/CUDA) code. non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants