Skip to content

Commit

Permalink
Remove probe-time null equality parameters in cudf::hash_join (#10260)
Browse files Browse the repository at this point in the history
Closes #9155

This PR removes the probe-time `cudf::null_equality` parameter in `cudf::hash_join` to avoid potential mismatching bugs between building and probing a hash join object.

Authors:
  - Yunsong Wang (https://github.com/PointKernel)
  - Jason Lowe (https://github.com/jlowe)

Approvers:
  - Conor Hoekstra (https://github.com/codereport)
  - Robert (Bobby) Evans (https://github.com/revans2)

URL: #10260
  • Loading branch information
PointKernel authored Feb 10, 2022
1 parent 6d162b4 commit 2741e6b
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 203 deletions.
8 changes: 4 additions & 4 deletions cpp/benchmarks/join/join.cu
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION.
* Copyright (c) 2019-2022, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -49,7 +49,7 @@ void nvbench_inner_join(nvbench::state& state,
cudf::null_equality compare_nulls,
rmm::cuda_stream_view stream) {
cudf::hash_join hj_obj(left_input.select(left_on), compare_nulls, stream);
return hj_obj.inner_join(right_input.select(right_on), compare_nulls, std::nullopt, stream);
return hj_obj.inner_join(right_input.select(right_on), std::nullopt, stream);
};

BM_join<key_type, payload_type, Nullable>(state, join);
Expand All @@ -71,7 +71,7 @@ void nvbench_left_join(nvbench::state& state,
cudf::null_equality compare_nulls,
rmm::cuda_stream_view stream) {
cudf::hash_join hj_obj(left_input.select(left_on), compare_nulls, stream);
return hj_obj.left_join(right_input.select(right_on), compare_nulls, std::nullopt, stream);
return hj_obj.left_join(right_input.select(right_on), std::nullopt, stream);
};

BM_join<key_type, payload_type, Nullable>(state, join);
Expand All @@ -93,7 +93,7 @@ void nvbench_full_join(nvbench::state& state,
cudf::null_equality compare_nulls,
rmm::cuda_stream_view stream) {
cudf::hash_join hj_obj(left_input.select(left_on), compare_nulls, stream);
return hj_obj.full_join(right_input.select(right_on), compare_nulls, std::nullopt, stream);
return hj_obj.full_join(right_input.select(right_on), std::nullopt, stream);
};

BM_join<key_type, payload_type, Nullable>(state, join);
Expand Down
20 changes: 3 additions & 17 deletions cpp/include/cudf/join.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION.
* Copyright (c) 2019-2022, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -530,7 +530,6 @@ class hash_join {
* provided `output_size` is smaller than the actual output size.
*
* @param probe The probe table, from which the tuples are probed.
* @param compare_nulls Controls whether null join-key values should match or not.
* @param output_size Optional value which allows users to specify the exact output size.
* @param stream CUDA stream used for device memory operations and kernel launches
* @param mr Device memory resource used to allocate the returned table and columns' device
Expand All @@ -543,7 +542,6 @@ class hash_join {
std::pair<std::unique_ptr<rmm::device_uvector<size_type>>,
std::unique_ptr<rmm::device_uvector<size_type>>>
inner_join(cudf::table_view const& probe,
null_equality compare_nulls = null_equality::EQUAL,
std::optional<std::size_t> output_size = {},
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()) const;
Expand All @@ -554,7 +552,6 @@ class hash_join {
* provided `output_size` is smaller than the actual output size.
*
* @param probe The probe table, from which the tuples are probed.
* @param compare_nulls Controls whether null join-key values should match or not.
* @param output_size Optional value which allows users to specify the exact output size.
* @param stream CUDA stream used for device memory operations and kernel launches
* @param mr Device memory resource used to allocate the returned table and columns' device
Expand All @@ -567,7 +564,6 @@ class hash_join {
std::pair<std::unique_ptr<rmm::device_uvector<size_type>>,
std::unique_ptr<rmm::device_uvector<size_type>>>
left_join(cudf::table_view const& probe,
null_equality compare_nulls = null_equality::EQUAL,
std::optional<std::size_t> output_size = {},
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()) const;
Expand All @@ -578,7 +574,6 @@ class hash_join {
* provided `output_size` is smaller than the actual output size.
*
* @param probe The probe table, from which the tuples are probed.
* @param compare_nulls Controls whether null join-key values should match or not.
* @param output_size Optional value which allows users to specify the exact output size.
* @param stream CUDA stream used for device memory operations and kernel launches
* @param mr Device memory resource used to allocate the returned table and columns' device
Expand All @@ -591,7 +586,6 @@ class hash_join {
std::pair<std::unique_ptr<rmm::device_uvector<size_type>>,
std::unique_ptr<rmm::device_uvector<size_type>>>
full_join(cudf::table_view const& probe,
null_equality compare_nulls = null_equality::EQUAL,
std::optional<std::size_t> output_size = {},
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()) const;
Expand All @@ -601,39 +595,32 @@ class hash_join {
* probe table.
*
* @param probe The probe table, from which the tuples are probed.
* @param compare_nulls Controls whether null join-key values should match or not.
* @param stream CUDA stream used for device memory operations and kernel launches
*
* @return The exact number of output when performing an inner join between two tables with
* `build` and `probe` as the the join keys .
*/
[[nodiscard]] std::size_t inner_join_size(
cudf::table_view const& probe,
null_equality compare_nulls = null_equality::EQUAL,
rmm::cuda_stream_view stream = rmm::cuda_stream_default) const;
cudf::table_view const& probe, rmm::cuda_stream_view stream = rmm::cuda_stream_default) const;

/**
* Returns the exact number of matches (rows) when performing a left join with the specified probe
* table.
*
* @param probe The probe table, from which the tuples are probed.
* @param compare_nulls Controls whether null join-key values should match or not.
* @param stream CUDA stream used for device memory operations and kernel launches
*
* @return The exact number of output when performing a left join between two tables with `build`
* and `probe` as the the join keys .
*/
[[nodiscard]] std::size_t left_join_size(
cudf::table_view const& probe,
null_equality compare_nulls = null_equality::EQUAL,
rmm::cuda_stream_view stream = rmm::cuda_stream_default) const;
cudf::table_view const& probe, rmm::cuda_stream_view stream = rmm::cuda_stream_default) const;

/**
* Returns the exact number of matches (rows) when performing a full join with the specified probe
* table.
*
* @param probe The probe table, from which the tuples are probed.
* @param compare_nulls Controls whether null join-key values should match or not.
* @param stream CUDA stream used for device memory operations and kernel launches
* @param mr Device memory resource used to allocate the intermediate table and columns' device
* memory.
Expand All @@ -643,7 +630,6 @@ class hash_join {
*/
std::size_t full_join_size(
cudf::table_view const& probe,
null_equality compare_nulls = null_equality::EQUAL,
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()) const;

Expand Down
76 changes: 33 additions & 43 deletions cpp/src/join/hash_join.cu
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021, NVIDIA CORPORATION.
* Copyright (c) 2020-2022, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -140,8 +140,8 @@ probe_join_hash_table(cudf::table_device_view build_table,
std::size_t get_full_join_size(cudf::table_device_view build_table,
cudf::table_device_view probe_table,
multimap_type const& hash_table,
bool has_nulls,
null_equality compare_nulls,
bool const has_nulls,
null_equality const compare_nulls,
rmm::cuda_stream_view stream,
rmm::mr::device_memory_resource* mr)
{
Expand Down Expand Up @@ -235,6 +235,7 @@ hash_join::hash_join_impl::hash_join_impl(cudf::table_view const& build,
null_equality compare_nulls,
rmm::cuda_stream_view stream)
: _is_empty{build.num_rows() == 0},
_nulls_equal{compare_nulls},
_hash_table{compute_hash_table_size(build.num_rows()),
std::numeric_limits<hash_value_type>::max(),
cudf::detail::JoinNoneValue,
Expand All @@ -253,50 +254,43 @@ hash_join::hash_join_impl::hash_join_impl(cudf::table_view const& build,

if (_is_empty) { return; }

build_join_hash_table(_build, _hash_table, compare_nulls, stream);
cudf::detail::build_join_hash_table(_build, _hash_table, _nulls_equal, stream);
}

std::pair<std::unique_ptr<rmm::device_uvector<size_type>>,
std::unique_ptr<rmm::device_uvector<size_type>>>
hash_join::hash_join_impl::inner_join(cudf::table_view const& probe,
null_equality compare_nulls,
std::optional<std::size_t> output_size,
rmm::cuda_stream_view stream,
rmm::mr::device_memory_resource* mr) const
{
CUDF_FUNC_RANGE();
return compute_hash_join<cudf::detail::join_kind::INNER_JOIN>(
probe, compare_nulls, output_size, stream, mr);
return compute_hash_join<cudf::detail::join_kind::INNER_JOIN>(probe, output_size, stream, mr);
}

std::pair<std::unique_ptr<rmm::device_uvector<size_type>>,
std::unique_ptr<rmm::device_uvector<size_type>>>
hash_join::hash_join_impl::left_join(cudf::table_view const& probe,
null_equality compare_nulls,
std::optional<std::size_t> output_size,
rmm::cuda_stream_view stream,
rmm::mr::device_memory_resource* mr) const
{
CUDF_FUNC_RANGE();
return compute_hash_join<cudf::detail::join_kind::LEFT_JOIN>(
probe, compare_nulls, output_size, stream, mr);
return compute_hash_join<cudf::detail::join_kind::LEFT_JOIN>(probe, output_size, stream, mr);
}

std::pair<std::unique_ptr<rmm::device_uvector<size_type>>,
std::unique_ptr<rmm::device_uvector<size_type>>>
hash_join::hash_join_impl::full_join(cudf::table_view const& probe,
null_equality compare_nulls,
std::optional<std::size_t> output_size,
rmm::cuda_stream_view stream,
rmm::mr::device_memory_resource* mr) const
{
CUDF_FUNC_RANGE();
return compute_hash_join<cudf::detail::join_kind::FULL_JOIN>(
probe, compare_nulls, output_size, stream, mr);
return compute_hash_join<cudf::detail::join_kind::FULL_JOIN>(probe, output_size, stream, mr);
}

std::size_t hash_join::hash_join_impl::inner_join_size(cudf::table_view const& probe,
null_equality compare_nulls,
rmm::cuda_stream_view stream) const
{
CUDF_FUNC_RANGE();
Expand All @@ -316,12 +310,11 @@ std::size_t hash_join::hash_join_impl::inner_join_size(cudf::table_view const& p
*flattened_probe_table_ptr,
_hash_table,
cudf::has_nulls(flattened_probe_table) | cudf::has_nulls(_build),
compare_nulls,
_nulls_equal,
stream);
}

std::size_t hash_join::hash_join_impl::left_join_size(cudf::table_view const& probe,
null_equality compare_nulls,
rmm::cuda_stream_view stream) const
{
CUDF_FUNC_RANGE();
Expand All @@ -341,12 +334,11 @@ std::size_t hash_join::hash_join_impl::left_join_size(cudf::table_view const& pr
*flattened_probe_table_ptr,
_hash_table,
cudf::has_nulls(flattened_probe_table) | cudf::has_nulls(_build),
compare_nulls,
_nulls_equal,
stream);
}

std::size_t hash_join::hash_join_impl::full_join_size(cudf::table_view const& probe,
null_equality compare_nulls,
rmm::cuda_stream_view stream,
rmm::mr::device_memory_resource* mr) const
{
Expand All @@ -362,20 +354,20 @@ std::size_t hash_join::hash_join_impl::full_join_size(cudf::table_view const& pr
auto build_table_ptr = cudf::table_device_view::create(_build, stream);
auto flattened_probe_table_ptr = cudf::table_device_view::create(flattened_probe_table, stream);

return get_full_join_size(*build_table_ptr,
*flattened_probe_table_ptr,
_hash_table,
cudf::has_nulls(flattened_probe_table) | cudf::has_nulls(_build),
compare_nulls,
stream,
mr);
return cudf::detail::get_full_join_size(
*build_table_ptr,
*flattened_probe_table_ptr,
_hash_table,
cudf::has_nulls(flattened_probe_table) | cudf::has_nulls(_build),
_nulls_equal,
stream,
mr);
}

template <cudf::detail::join_kind JoinKind>
std::pair<std::unique_ptr<rmm::device_uvector<size_type>>,
std::unique_ptr<rmm::device_uvector<size_type>>>
hash_join::hash_join_impl::compute_hash_join(cudf::table_view const& probe,
null_equality compare_nulls,
std::optional<std::size_t> output_size,
rmm::cuda_stream_view stream,
rmm::mr::device_memory_resource* mr) const
Expand Down Expand Up @@ -403,42 +395,40 @@ hash_join::hash_join_impl::compute_hash_join(cudf::table_view const& probe,
[](const auto& b, const auto& p) { return b.type() == p.type(); }),
"Mismatch in joining column data types");

return probe_join_indices<JoinKind>(
flattened_probe_table, compare_nulls, output_size, stream, mr);
return probe_join_indices<JoinKind>(flattened_probe_table, output_size, stream, mr);
}

template <cudf::detail::join_kind JoinKind>
std::pair<std::unique_ptr<rmm::device_uvector<size_type>>,
std::unique_ptr<rmm::device_uvector<size_type>>>
hash_join::hash_join_impl::probe_join_indices(cudf::table_view const& probe,
null_equality compare_nulls,
hash_join::hash_join_impl::probe_join_indices(cudf::table_view const& probe_table,
std::optional<std::size_t> output_size,
rmm::cuda_stream_view stream,
rmm::mr::device_memory_resource* mr) const
{
// Trivial left join case - exit early
if (_is_empty and JoinKind != cudf::detail::join_kind::INNER_JOIN) {
return get_trivial_left_join_indices(probe, stream, mr);
return get_trivial_left_join_indices(probe_table, stream, mr);
}

CUDF_EXPECTS(!_is_empty, "Hash table of hash join is null.");

auto build_table_ptr = cudf::table_device_view::create(_build, stream);
auto probe_table_ptr = cudf::table_device_view::create(probe, stream);

auto join_indices =
cudf::detail::probe_join_hash_table<JoinKind>(*build_table_ptr,
*probe_table_ptr,
_hash_table,
cudf::has_nulls(probe) | cudf::has_nulls(_build),
compare_nulls,
output_size,
stream,
mr);
auto probe_table_ptr = cudf::table_device_view::create(probe_table, stream);

auto join_indices = cudf::detail::probe_join_hash_table<JoinKind>(
*build_table_ptr,
*probe_table_ptr,
_hash_table,
cudf::has_nulls(probe_table) | cudf::has_nulls(_build),
_nulls_equal,
output_size,
stream,
mr);

if constexpr (JoinKind == cudf::detail::join_kind::FULL_JOIN) {
auto complement_indices = detail::get_left_join_indices_complement(
join_indices.second, probe.num_rows(), _build.num_rows(), stream, mr);
join_indices.second, probe_table.num_rows(), _build.num_rows(), stream, mr);
join_indices = detail::concatenate_vector_pairs(join_indices, complement_indices, stream);
}
return join_indices;
Expand Down
Loading

0 comments on commit 2741e6b

Please sign in to comment.