From 7cfdbd54d1c4dec7f8e41e13153f73899aa3630e Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Tue, 16 Feb 2021 16:05:41 +1100 Subject: [PATCH 01/28] Initial attempt at using span/iterators in make_strings_columns (WIP) --- cpp/benchmarks/copying/shift_benchmark.cu | 1 - .../detail/strings_column_factories.hpp | 18 +++ cpp/include/cudf_test/column_wrapper.hpp | 1 + cpp/src/binaryop/compiled/binary_ops.cu | 14 +- cpp/src/strings/strings_column_factories.cu | 121 ++++++++++-------- cpp/tests/strings/combine_tests.cpp | 5 + cpp/tests/utilities/column_utilities.cu | 11 +- 7 files changed, 113 insertions(+), 58 deletions(-) create mode 100644 cpp/include/cudf/strings/detail/strings_column_factories.hpp diff --git a/cpp/benchmarks/copying/shift_benchmark.cu b/cpp/benchmarks/copying/shift_benchmark.cu index 291c0ef6777..7fd00a7015f 100644 --- a/cpp/benchmarks/copying/shift_benchmark.cu +++ b/cpp/benchmarks/copying/shift_benchmark.cu @@ -23,7 +23,6 @@ #include -#include #include #include #include diff --git a/cpp/include/cudf/strings/detail/strings_column_factories.hpp b/cpp/include/cudf/strings/detail/strings_column_factories.hpp new file mode 100644 index 00000000000..a3c91422c86 --- /dev/null +++ b/cpp/include/cudf/strings/detail/strings_column_factories.hpp @@ -0,0 +1,18 @@ +#include +#include +#include + +#include +#include + +namespace cudf { +namespace detail { + +std::unique_ptr make_strings_column( + const device_span& string_views, + const string_view null_placeholder, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + +} +} // namespace cudf diff --git a/cpp/include/cudf_test/column_wrapper.hpp b/cpp/include/cudf_test/column_wrapper.hpp index 55b7096f96f..e97837507b2 100644 --- a/cpp/include/cudf_test/column_wrapper.hpp +++ b/cpp/include/cudf_test/column_wrapper.hpp @@ -139,6 +139,7 @@ template ()>* = nullptr> rmm::device_buffer make_elements(InputIterator begin, InputIterator end) { + std::cout << "hello?\n"; static_assert(cudf::is_fixed_width(), "Unexpected non-fixed width type."); auto transformer = fixed_width_type_converter{}; auto transform_begin = thrust::make_transform_iterator(begin, transformer); diff --git a/cpp/src/binaryop/compiled/binary_ops.cu b/cpp/src/binaryop/compiled/binary_ops.cu index 27f8306cbd7..e910515f7ae 100644 --- a/cpp/src/binaryop/compiled/binary_ops.cu +++ b/cpp/src/binaryop/compiled/binary_ops.cu @@ -20,10 +20,12 @@ #include #include #include +#include #include +#include #include -#include +#include #include namespace cudf { @@ -373,7 +375,7 @@ struct null_considering_binop { "Output column type should match input column type"); // Shallow copy of the resultant strings - rmm::device_vector out_col_strings(col_size); + rmm::device_uvector out_col_strings(col_size, stream); // Invalid output column strings - null rows cudf::string_view const invalid_str{nullptr, 0}; @@ -397,10 +399,14 @@ struct null_considering_binop { // Populate output column populate_out_col( - lhs_dev_view, rhs_dev_view, col_size, stream, minmax_func, out_col_strings.data().get()); + lhs_dev_view, rhs_dev_view, col_size, stream, minmax_func, out_col_strings.data()); // Create an output column with the resultant strings - out = make_strings_column(out_col_strings, invalid_str, stream, mr); + out = cudf::detail::make_strings_column(cudf::detail::device_span( + out_col_strings.data(), out_col_strings.size()), + invalid_str, + stream, + mr); break; } diff --git a/cpp/src/strings/strings_column_factories.cu b/cpp/src/strings/strings_column_factories.cu index 774c6fa0da6..2322ce08560 100644 --- a/cpp/src/strings/strings_column_factories.cu +++ b/cpp/src/strings/strings_column_factories.cu @@ -20,65 +20,76 @@ #include #include #include +#include #include #include #include #include +#include "thrust/iterator/zip_iterator.h" #include +#include #include namespace cudf { -// Create a strings-type column from vector of pointer/size pairs -std::unique_ptr make_strings_column( - const rmm::device_vector>& strings, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) +namespace { +struct string_view_to_pair { + string_view null_placeholder; + string_view_to_pair(string_view n) : null_placeholder(n) {} + __device__ thrust::pair operator()(const string_view& i) + { + return (i.data() == null_placeholder.data()) + ? thrust::pair{nullptr, 0} + : thrust::pair{i.data(), i.size_bytes()}; + } +}; + +} // namespace + +namespace detail { + +template +std::unique_ptr make_strings_column(StringPairIterator begin, + StringPairIterator end, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) { + using string_pair = thrust::pair; + CUDF_FUNC_RANGE(); - size_type strings_count = strings.size(); + size_type strings_count = std::distance(begin, end); if (strings_count == 0) return strings::detail::make_empty_strings_column(stream, mr); - auto d_strings = strings.data().get(); + // auto d_strings = strings.data(); // check total size is not too large for cudf column - auto size_checker = [d_strings] __device__(size_t idx) { - auto item = d_strings[idx]; + auto size_checker = [] __device__(string_pair const& item) { return (item.first != nullptr) ? item.second : 0; }; - size_t bytes = thrust::transform_reduce(rmm::exec_policy(stream), - thrust::make_counting_iterator(0), - thrust::make_counting_iterator(strings_count), - size_checker, - 0, - thrust::plus()); + size_t bytes = thrust::transform_reduce( + rmm::exec_policy(stream), begin, end, size_checker, 0, thrust::plus()); CUDF_EXPECTS(bytes < static_cast(std::numeric_limits::max()), "total size of strings is too large for cudf column"); // build offsets column from the strings sizes - auto offsets_transformer = [d_strings] __device__(size_type idx) { - thrust::pair item = d_strings[idx]; + auto offsets_transformer = [] __device__(string_pair const& item) { return (item.first != nullptr ? static_cast(item.second) : 0); }; - auto offsets_transformer_itr = thrust::make_transform_iterator( - thrust::make_counting_iterator(0), offsets_transformer); - auto offsets_column = strings::detail::make_offsets_child_column( - offsets_transformer_itr, offsets_transformer_itr + strings_count, stream, mr); + auto offsets_begin = thrust::make_transform_iterator(begin, offsets_transformer); + auto offsets_end = thrust::make_transform_iterator(end, offsets_transformer); + auto offsets_column = + strings::detail::make_offsets_child_column(offsets_begin, offsets_end, stream, mr); auto offsets_view = offsets_column->view(); - auto d_offsets = offsets_view.data(); + auto d_offsets = offsets_view.template data(); // create null mask auto new_nulls = detail::valid_if( - thrust::make_counting_iterator(0), - thrust::make_counting_iterator(strings_count), - [d_strings] __device__(size_type idx) { return d_strings[idx].first != nullptr; }, - stream, - mr); + begin, end, [] __device__(string_pair item) { return item.first != nullptr; }, stream, mr); auto null_count = new_nulls.second; - rmm::device_buffer null_mask{0, stream, mr}; - if (null_count > 0) null_mask = std::move(new_nulls.first); + auto null_mask = + (null_count > 0) ? std::move(new_nulls.first) : rmm::device_buffer{0, stream, mr}; // build chars column auto chars_column = @@ -86,13 +97,12 @@ std::unique_ptr make_strings_column( auto chars_view = chars_column->mutable_view(); auto d_chars = chars_view.data(); thrust::for_each_n(rmm::exec_policy(stream), - thrust::make_counting_iterator(0), + thrust::make_zip_iterator(thrust::make_tuple(begin, offsets_begin)), strings_count, - [d_strings, d_offsets, d_chars] __device__(size_type idx) { - // place individual strings - auto item = d_strings[idx]; - if (item.first != nullptr) - memcpy(d_chars + d_offsets[idx], item.first, item.second); + [d_chars] __device__(auto item) { + string_pair str = thrust::get<0>(item); + size_type offset = thrust::get<1>(item); + if (str.first != nullptr) memcpy(d_chars + offset, str.first, str.second); }); return make_strings_column(strings_count, @@ -104,16 +114,26 @@ std::unique_ptr make_strings_column( mr); } -struct string_view_to_pair { - string_view null_placeholder; - string_view_to_pair(string_view n) : null_placeholder(n) {} - __device__ thrust::pair operator()(const string_view& i) - { - return (i.data() == null_placeholder.data()) - ? thrust::pair{nullptr, 0} - : thrust::pair{i.data(), i.size_bytes()}; - } -}; +std::unique_ptr make_strings_column(const device_span& string_views, + const string_view null_placeholder, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + auto it_pair = + thrust::make_transform_iterator(string_views.begin(), string_view_to_pair{null_placeholder}); + return make_strings_column(it_pair, it_pair + string_views.size(), stream, mr); +} + +} // namespace detail + +// Create a strings-type column from vector of pointer/size pairs +std::unique_ptr make_strings_column( + const rmm::device_vector>& strings, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + return detail::make_strings_column(strings.begin(), strings.end(), stream, mr); +} // Create a strings-type column from vector of string_view std::unique_ptr make_strings_column(const rmm::device_vector& string_views, @@ -121,11 +141,12 @@ std::unique_ptr make_strings_column(const rmm::device_vector> dev_strings( - it_pair, it_pair + string_views.size()); - return make_strings_column(dev_strings, stream, mr); + return detail::make_strings_column( + detail::device_span(const_cast(string_views.data().get()), + string_views.size()), + null_placeholder, + stream, + mr); } // Create a strings-type column from device vector of chars and vector of offsets. diff --git a/cpp/tests/strings/combine_tests.cpp b/cpp/tests/strings/combine_tests.cpp index cfeca2bba29..4e4843dc721 100644 --- a/cpp/tests/strings/combine_tests.cpp +++ b/cpp/tests/strings/combine_tests.cpp @@ -281,8 +281,13 @@ TEST_F(StringsConcatenateWithColSeparatorTest, SingleColumnStringMixNoReplacemen {"", "", "", "bbabc", "", "d", "éa", "", "bbb", "éééf"}, {false, false, true, true, false, true, true, false, true, true}); + CUDA_TRY(cudaDeviceSynchronize()); + auto results = cudf::strings::concatenate(cudf::table_view{{col0}}, cudf::strings_column_view(sep_col)); + + CUDA_TRY(cudaDeviceSynchronize()); + CUDF_TEST_EXPECT_COLUMNS_EQUAL(*results, exp_results, true); } diff --git a/cpp/tests/utilities/column_utilities.cu b/cpp/tests/utilities/column_utilities.cu index 4f7ac41a00f..7c0708be968 100644 --- a/cpp/tests/utilities/column_utilities.cu +++ b/cpp/tests/utilities/column_utilities.cu @@ -175,11 +175,16 @@ std::string differences_message(thrust::device_vector const& differences, buffer << depth_str << "differences:" << std::endl; auto source_table = cudf::table_view({lhs, rhs}); - auto diff_column = fixed_width_column_wrapper(differences.begin(), differences.end()); - auto diff_table = cudf::gather(source_table, diff_column); + + std::cout << "1\n"; + auto diff_column = fixed_width_column_wrapper(differences.begin(), differences.end()); + + std::cout << "2\n"; + auto diff_table = cudf::gather(source_table, diff_column); // Need to pull back the differences - auto const h_left_strings = to_strings(diff_table->get_column(0)); + auto const h_left_strings = to_strings(diff_table->get_column(0)); + auto const h_right_strings = to_strings(diff_table->get_column(1)); for (size_t i = 0; i < differences.size(); ++i) From a3a1cfacbe679938b3acdfb1184988af427fdad3 Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Wed, 17 Feb 2021 13:55:50 +1100 Subject: [PATCH 02/28] Fix zip iterator --- cpp/src/strings/strings_column_factories.cu | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cpp/src/strings/strings_column_factories.cu b/cpp/src/strings/strings_column_factories.cu index 2322ce08560..b2980c93819 100644 --- a/cpp/src/strings/strings_column_factories.cu +++ b/cpp/src/strings/strings_column_factories.cu @@ -77,12 +77,9 @@ std::unique_ptr make_strings_column(StringPairIterator begin, auto offsets_transformer = [] __device__(string_pair const& item) { return (item.first != nullptr ? static_cast(item.second) : 0); }; - auto offsets_begin = thrust::make_transform_iterator(begin, offsets_transformer); - auto offsets_end = thrust::make_transform_iterator(end, offsets_transformer); - auto offsets_column = - strings::detail::make_offsets_child_column(offsets_begin, offsets_end, stream, mr); - auto offsets_view = offsets_column->view(); - auto d_offsets = offsets_view.template data(); + auto offsets_transformer_itr = thrust::make_transform_iterator(begin, offsets_transformer); + auto offsets_column = strings::detail::make_offsets_child_column( + offsets_transformer_itr, offsets_transformer_itr + strings_count, stream, mr); // create null mask auto new_nulls = detail::valid_if( @@ -97,7 +94,8 @@ std::unique_ptr make_strings_column(StringPairIterator begin, auto chars_view = chars_column->mutable_view(); auto d_chars = chars_view.data(); thrust::for_each_n(rmm::exec_policy(stream), - thrust::make_zip_iterator(thrust::make_tuple(begin, offsets_begin)), + thrust::make_zip_iterator( + thrust::make_tuple(begin, offsets_column->view().template begin())), strings_count, [d_chars] __device__(auto item) { string_pair str = thrust::get<0>(item); From 99eea9e02856f928a5fe7e97a1f03462053515c7 Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Wed, 17 Feb 2021 16:32:16 +1100 Subject: [PATCH 03/28] Convert chars, offsets, nulls make_strings_column to iterators --- .../detail/strings_column_factories.cuh | 70 ++++++-- .../detail/strings_column_factories.hpp | 15 +- cpp/src/strings/strings_column_factories.cu | 157 +++++------------- 3 files changed, 108 insertions(+), 134 deletions(-) diff --git a/cpp/include/cudf/strings/detail/strings_column_factories.cuh b/cpp/include/cudf/strings/detail/strings_column_factories.cuh index bec7a29ca18..bea870eeb2e 100644 --- a/cpp/include/cudf/strings/detail/strings_column_factories.cuh +++ b/cpp/include/cudf/strings/detail/strings_column_factories.cuh @@ -25,6 +25,7 @@ #include #include +#include "rmm/thrust_rmm_allocator.h" #include #include @@ -33,7 +34,7 @@ namespace cudf { namespace strings { namespace detail { -// Create a strings-type column from vector of pointer/size pairs +// Create a strings-type column from iterators of pointer/size pairs template std::unique_ptr make_strings_column(IndexPairIterator begin, IndexPairIterator end, @@ -56,33 +57,32 @@ std::unique_ptr make_strings_column(IndexPairIterator begin, "total size of strings is too large for cudf column"); // build offsets column from the strings sizes - auto offsets_transformer = [begin] __device__(size_type idx) { - string_index_pair const item = begin[idx]; + auto offsets_transformer = [] __device__(string_index_pair item) { return (item.first != nullptr ? static_cast(item.second) : 0); }; - auto offsets_transformer_itr = thrust::make_transform_iterator( - thrust::make_counting_iterator(0), offsets_transformer); - auto offsets_column = strings::detail::make_offsets_child_column( + auto offsets_transformer_itr = thrust::make_transform_iterator(begin, offsets_transformer); + auto offsets_column = strings::detail::make_offsets_child_column( offsets_transformer_itr, offsets_transformer_itr + strings_count, stream, mr); - auto d_offsets = offsets_column->view().template data(); // create null mask auto validator = [] __device__(string_index_pair const item) { return item.first != nullptr; }; auto new_nulls = cudf::detail::valid_if(begin, end, validator, stream, mr); auto null_count = new_nulls.second; - rmm::device_buffer null_mask{0, stream, mr}; - if (null_count > 0) null_mask = std::move(new_nulls.first); + auto null_mask = + (null_count > 0) ? std::move(new_nulls.first) : rmm::device_buffer{0, stream, mr}; // build chars column auto chars_column = strings::detail::create_chars_child_column(strings_count, null_count, bytes, stream, mr); auto d_chars = chars_column->mutable_view().template data(); - auto copy_chars = [begin, d_offsets, d_chars] __device__(size_type idx) { - string_index_pair const item = begin[idx]; - if (item.first != nullptr) memcpy(d_chars + d_offsets[idx], item.first, item.second); + auto copy_chars = [d_chars] __device__(auto item) { + string_index_pair str = thrust::get<0>(item); + size_type offset = thrust::get<1>(item); + if (str.first != nullptr) memcpy(d_chars + offset, str.first, str.second); }; thrust::for_each_n(rmm::exec_policy(stream), - thrust::make_counting_iterator(0), + thrust::make_zip_iterator( + thrust::make_tuple(begin, offsets_column->view().template begin())), strings_count, copy_chars); @@ -95,6 +95,50 @@ std::unique_ptr make_strings_column(IndexPairIterator begin, mr); } +// Create a strings-type column from iterators to chars, offsets, and bitmask. +template +std::unique_ptr make_strings_column(CharIterator chars_begin, + CharIterator chars_end, + OffsetIterator offsets_begin, + OffsetIterator offsets_end, + size_type null_count, + rmm::device_buffer&& null_mask, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + CUDF_FUNC_RANGE(); + size_type strings_count = thrust::distance(offsets_begin, offsets_end) - 1; + size_type bytes = std::distance(chars_begin, chars_end) * sizeof(char); + if (strings_count == 0) return strings::detail::make_empty_strings_column(stream, mr); + + CUDF_EXPECTS(null_count < strings_count, "null strings column not yet supported"); + CUDF_EXPECTS(bytes >= 0, "invalid offsets data"); + + // build offsets column -- this is the number of strings + 1 + auto offsets_column = make_numeric_column( + data_type{type_id::INT32}, strings_count + 1, mask_state::UNALLOCATED, stream, mr); + auto offsets_view = offsets_column->mutable_view(); + thrust::transform(rmm::exec_policy(stream), + offsets_begin, + offsets_end, + offsets_view.data(), + [] __device__(auto offset) { return static_cast(offset); }); + + // build chars column + auto chars_column = + strings::detail::create_chars_child_column(strings_count, null_count, bytes, stream, mr); + auto chars_view = chars_column->mutable_view(); + thrust::copy(rmm::exec_policy(stream), chars_begin, chars_end, chars_view.data()); + + return make_strings_column(strings_count, + std::move(offsets_column), + std::move(chars_column), + null_count, + std::move(null_mask), + stream, + mr); +} + } // namespace detail } // namespace strings } // namespace cudf diff --git a/cpp/include/cudf/strings/detail/strings_column_factories.hpp b/cpp/include/cudf/strings/detail/strings_column_factories.hpp index a3c91422c86..126a32f26a0 100644 --- a/cpp/include/cudf/strings/detail/strings_column_factories.hpp +++ b/cpp/include/cudf/strings/detail/strings_column_factories.hpp @@ -9,10 +9,19 @@ namespace cudf { namespace detail { std::unique_ptr make_strings_column( - const device_span& string_views, - const string_view null_placeholder, + device_span const& string_views, + string_view const null_placeholder, rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); -} +std::unique_ptr make_strings_column( + device_span const& chars, + device_span const& offsets, + size_type null_count, + rmm::device_buffer&& null_mask, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + +} // namespace detail + } // namespace cudf diff --git a/cpp/src/strings/strings_column_factories.cu b/cpp/src/strings/strings_column_factories.cu index b2980c93819..1b03e9bf818 100644 --- a/cpp/src/strings/strings_column_factories.cu +++ b/cpp/src/strings/strings_column_factories.cu @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,10 +26,10 @@ #include #include #include -#include "thrust/iterator/zip_iterator.h" #include #include +#include #include namespace cudf { @@ -50,68 +50,6 @@ struct string_view_to_pair { namespace detail { -template -std::unique_ptr make_strings_column(StringPairIterator begin, - StringPairIterator end, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - using string_pair = thrust::pair; - - CUDF_FUNC_RANGE(); - size_type strings_count = std::distance(begin, end); - if (strings_count == 0) return strings::detail::make_empty_strings_column(stream, mr); - - // auto d_strings = strings.data(); - - // check total size is not too large for cudf column - auto size_checker = [] __device__(string_pair const& item) { - return (item.first != nullptr) ? item.second : 0; - }; - size_t bytes = thrust::transform_reduce( - rmm::exec_policy(stream), begin, end, size_checker, 0, thrust::plus()); - CUDF_EXPECTS(bytes < static_cast(std::numeric_limits::max()), - "total size of strings is too large for cudf column"); - - // build offsets column from the strings sizes - auto offsets_transformer = [] __device__(string_pair const& item) { - return (item.first != nullptr ? static_cast(item.second) : 0); - }; - auto offsets_transformer_itr = thrust::make_transform_iterator(begin, offsets_transformer); - auto offsets_column = strings::detail::make_offsets_child_column( - offsets_transformer_itr, offsets_transformer_itr + strings_count, stream, mr); - - // create null mask - auto new_nulls = detail::valid_if( - begin, end, [] __device__(string_pair item) { return item.first != nullptr; }, stream, mr); - auto null_count = new_nulls.second; - auto null_mask = - (null_count > 0) ? std::move(new_nulls.first) : rmm::device_buffer{0, stream, mr}; - - // build chars column - auto chars_column = - strings::detail::create_chars_child_column(strings_count, null_count, bytes, stream, mr); - auto chars_view = chars_column->mutable_view(); - auto d_chars = chars_view.data(); - thrust::for_each_n(rmm::exec_policy(stream), - thrust::make_zip_iterator( - thrust::make_tuple(begin, offsets_column->view().template begin())), - strings_count, - [d_chars] __device__(auto item) { - string_pair str = thrust::get<0>(item); - size_type offset = thrust::get<1>(item); - if (str.first != nullptr) memcpy(d_chars + offset, str.first, str.second); - }); - - return make_strings_column(strings_count, - std::move(offsets_column), - std::move(chars_column), - null_count, - std::move(null_mask), - stream, - mr); -} - std::unique_ptr make_strings_column(const device_span& string_views, const string_view null_placeholder, rmm::cuda_stream_view stream, @@ -119,7 +57,26 @@ std::unique_ptr make_strings_column(const device_span& stri { auto it_pair = thrust::make_transform_iterator(string_views.begin(), string_view_to_pair{null_placeholder}); - return make_strings_column(it_pair, it_pair + string_views.size(), stream, mr); + return cudf::strings::detail::make_strings_column( + it_pair, it_pair + string_views.size(), stream, mr); +} + +std::unique_ptr make_strings_column( + device_span const& chars, + device_span const& offsets, + size_type null_count, + rmm::device_buffer&& null_mask, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()) +{ + return cudf::strings::detail::make_strings_column(chars.begin(), + chars.end(), + offsets.begin(), + offsets.end(), + null_count, + std::move(null_mask), + stream, + mr); } } // namespace detail @@ -130,7 +87,7 @@ std::unique_ptr make_strings_column( rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { - return detail::make_strings_column(strings.begin(), strings.end(), stream, mr); + return strings::detail::make_strings_column(strings.begin(), strings.end(), stream, mr); } // Create a strings-type column from vector of string_view @@ -148,66 +105,30 @@ std::unique_ptr make_strings_column(const rmm::device_vector make_strings_column(const rmm::device_vector& strings, - const rmm::device_vector& offsets, - const rmm::device_vector& valid_mask, +std::unique_ptr make_strings_column(rmm::device_vector const& strings, + rmm::device_vector const& offsets, + rmm::device_vector const& valid_mask, size_type null_count, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { - CUDF_FUNC_RANGE(); - size_type num_strings = offsets.size() - 1; - if (num_strings == 0) return strings::detail::make_empty_strings_column(stream, mr); - - CUDF_EXPECTS(null_count < num_strings, "null strings column not yet supported"); - if (null_count > 0) { - CUDF_EXPECTS(!valid_mask.empty(), "Cannot have null elements without a null mask."); - } - - size_type bytes = offsets.back(); - CUDF_EXPECTS(bytes >= 0, "invalid offsets vector"); - - // build offsets column -- this is the number of strings + 1 - auto offsets_column = make_numeric_column( - data_type{type_id::INT32}, num_strings + 1, mask_state::UNALLOCATED, stream, mr); - auto offsets_view = offsets_column->mutable_view(); - thrust::transform(rmm::exec_policy(stream), - offsets.begin(), - offsets.end(), - offsets_view.data(), - [] __device__(auto offset) { return static_cast(offset); }); // build null bitmask - rmm::device_buffer null_mask{ - valid_mask.data().get(), - valid_mask.size() * - sizeof(bitmask_type)}; // Or this works too: sizeof(typename - // std::remove_reference_t::value_type) - // Following give the incorrect value of 8 instead of 4 because of smart references: - // sizeof(valid_mask[0]), sizeof(decltype(valid_mask.front())) - - // build chars column - auto chars_column = - strings::detail::create_chars_child_column(num_strings, null_count, bytes, stream, mr); - auto chars_view = chars_column->mutable_view(); - CUDA_TRY(cudaMemcpyAsync(chars_view.data(), - strings.data().get(), - bytes, - cudaMemcpyDeviceToDevice, - stream.value())); - - return make_strings_column(num_strings, - std::move(offsets_column), - std::move(chars_column), - null_count, - std::move(null_mask), - stream, - mr); + rmm::device_buffer null_mask{valid_mask.data().get(), valid_mask.size() * sizeof(bitmask_type)}; + + return cudf::strings::detail::make_strings_column(strings.begin(), + strings.end(), + offsets.begin(), + offsets.end(), + null_count, + std::move(null_mask), + stream, + mr); } // Create strings column from host vectors -std::unique_ptr make_strings_column(const std::vector& strings, - const std::vector& offsets, - const std::vector& null_mask, +std::unique_ptr make_strings_column(std::vector const& strings, + std::vector const& offsets, + std::vector const& null_mask, size_type null_count, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) From 189fdf5a60ea665c4ce63cfb0bf69d6e5ff28f0d Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Wed, 17 Feb 2021 16:32:49 +1100 Subject: [PATCH 04/28] use device_span version of make_strings_column in scan.cu --- cpp/src/reductions/scan.cu | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cpp/src/reductions/scan.cu b/cpp/src/reductions/scan.cu index ca9ab82c27c..2df3891d88d 100644 --- a/cpp/src/reductions/scan.cu +++ b/cpp/src/reductions/scan.cu @@ -24,11 +24,13 @@ #include #include #include +#include #include +#include #include #include -#include +#include #include namespace cudf { @@ -166,22 +168,21 @@ struct ScanDispatcher { rmm::mr::device_memory_resource* mr) { const size_type size = input_view.size(); - rmm::device_vector result(size); + rmm::device_uvector result(size, stream); auto d_input = column_device_view::create(input_view, stream); if (input_view.has_nulls()) { auto input = make_null_replacement_iterator(*d_input, Op::template identity()); - thrust::inclusive_scan( - rmm::exec_policy(stream), input, input + size, result.data().get(), Op{}); + thrust::inclusive_scan(rmm::exec_policy(stream), input, input + size, result.data(), Op{}); } else { auto input = d_input->begin(); - thrust::inclusive_scan( - rmm::exec_policy(stream), input, input + size, result.data().get(), Op{}); + thrust::inclusive_scan(rmm::exec_policy(stream), input, input + size, result.data(), Op{}); } CHECK_CUDA(stream.value()); - auto output_column = make_strings_column(result, Op::template identity(), stream, mr); + auto output_column = cudf::detail::make_strings_column( + device_span{result.data(), result.size()}, Op::template identity(), stream, mr); if (null_handling == null_policy::EXCLUDE) { output_column->set_null_mask(detail::copy_bitmask(input_view, stream, mr), input_view.null_count()); From 01a02e28db7400579c9fdd211d2b44c410bf9f8e Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Wed, 17 Feb 2021 16:46:09 +1100 Subject: [PATCH 05/28] Add another device_span version of make_strings_column --- .../cudf/strings/detail/strings_column_factories.hpp | 5 +++++ cpp/src/strings/strings_column_factories.cu | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/cpp/include/cudf/strings/detail/strings_column_factories.hpp b/cpp/include/cudf/strings/detail/strings_column_factories.hpp index 126a32f26a0..7d697c672c6 100644 --- a/cpp/include/cudf/strings/detail/strings_column_factories.hpp +++ b/cpp/include/cudf/strings/detail/strings_column_factories.hpp @@ -8,6 +8,11 @@ namespace cudf { namespace detail { +std::unique_ptr make_strings_column( + device_span> const& strings, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + std::unique_ptr make_strings_column( device_span const& string_views, string_view const null_placeholder, diff --git a/cpp/src/strings/strings_column_factories.cu b/cpp/src/strings/strings_column_factories.cu index 1b03e9bf818..9412e01bae9 100644 --- a/cpp/src/strings/strings_column_factories.cu +++ b/cpp/src/strings/strings_column_factories.cu @@ -50,6 +50,14 @@ struct string_view_to_pair { namespace detail { +std::unique_ptr make_strings_column( + const device_span>& strings, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + return cudf::strings::detail::make_strings_column(strings.begin(), strings.end(), stream, mr); +} + std::unique_ptr make_strings_column(const device_span& string_views, const string_view null_placeholder, rmm::cuda_stream_view stream, From 1b8b2009360dec905e6b238812f974f6b643ed23 Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Wed, 17 Feb 2021 16:46:26 +1100 Subject: [PATCH 06/28] Use device_span version of make_strings_column in CSV reader_impl.cu --- cpp/src/io/csv/reader_impl.cu | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpp/src/io/csv/reader_impl.cu b/cpp/src/io/csv/reader_impl.cu index 1e27ee39455..c00741435d7 100644 --- a/cpp/src/io/csv/reader_impl.cu +++ b/cpp/src/io/csv/reader_impl.cu @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -351,7 +352,10 @@ table_with_metadata reader::impl::read(rmm::cuda_stream_view stream) // during the conversion stage const std::string quotechar(1, opts.quotechar); const std::string dblquotechar(2, opts.quotechar); - std::unique_ptr col = make_strings_column(out_buffers[i]._strings, stream); + std::unique_ptr col = cudf::detail::make_strings_column( + cudf::detail::device_span>{ + out_buffers[i]._strings.data().get(), out_buffers[i]._strings.size()}, + stream); out_columns.emplace_back( cudf::strings::replace(col->view(), dblquotechar, quotechar, -1, mr_)); } else { From b33ca20721e0e30ec30ad9dac53df0c51cf4b05a Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Tue, 23 Feb 2021 12:33:47 +1100 Subject: [PATCH 07/28] make_strings_column from std::vector uses spans internally --- cpp/src/strings/strings_column_factories.cu | 32 ++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/cpp/src/strings/strings_column_factories.cu b/cpp/src/strings/strings_column_factories.cu index 9412e01bae9..fc74d82f4c3 100644 --- a/cpp/src/strings/strings_column_factories.cu +++ b/cpp/src/strings/strings_column_factories.cu @@ -105,8 +105,8 @@ std::unique_ptr make_strings_column(const rmm::device_vector(const_cast(string_views.data().get()), - string_views.size()), + detail::device_span{const_cast(string_views.data().get()), + string_views.size()}, null_placeholder, stream, mr); @@ -141,11 +141,29 @@ std::unique_ptr make_strings_column(std::vector const& strings, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { - rmm::device_vector d_strings{strings}; - rmm::device_vector d_offsets{offsets}; - rmm::device_vector d_null_mask{null_mask}; - - return make_strings_column(d_strings, d_offsets, d_null_mask, null_count, stream, mr); + rmm::device_uvector d_strings{strings.size(), stream}; + rmm::device_uvector d_offsets{offsets.size(), stream}; + rmm::device_uvector d_null_mask{null_mask.size(), stream}; + + CUDA_TRY(cudaMemcpyAsync( + d_strings.data(), strings.data(), strings.size(), cudaMemcpyDefault, stream.value())); + CUDA_TRY(cudaMemcpyAsync(d_offsets.data(), + offsets.data(), + offsets.size() * sizeof(size_type), + cudaMemcpyDefault, + stream.value())); + CUDA_TRY(cudaMemcpyAsync(d_null_mask.data(), + null_mask.data(), + null_mask.size() * sizeof(bitmask_type), + cudaMemcpyDefault, + stream.value())); + + return make_strings_column(detail::device_span{d_strings}, + detail::device_span{d_offsets}, + null_count, + d_null_mask.release(), + stream, + mr); } // From f43aeb114b68d330abd4a952f11021fa0f2fe4bb Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Tue, 23 Feb 2021 12:35:39 +1100 Subject: [PATCH 08/28] Clean up binops/scan spans. --- cpp/src/binaryop/compiled/binary_ops.cu | 7 ++----- cpp/src/reductions/scan.cu | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cpp/src/binaryop/compiled/binary_ops.cu b/cpp/src/binaryop/compiled/binary_ops.cu index e910515f7ae..b7382c5d8c0 100644 --- a/cpp/src/binaryop/compiled/binary_ops.cu +++ b/cpp/src/binaryop/compiled/binary_ops.cu @@ -402,11 +402,8 @@ struct null_considering_binop { lhs_dev_view, rhs_dev_view, col_size, stream, minmax_func, out_col_strings.data()); // Create an output column with the resultant strings - out = cudf::detail::make_strings_column(cudf::detail::device_span( - out_col_strings.data(), out_col_strings.size()), - invalid_str, - stream, - mr); + out = cudf::detail::make_strings_column( + cudf::detail::device_span{out_col_strings}, invalid_str, stream, mr); break; } diff --git a/cpp/src/reductions/scan.cu b/cpp/src/reductions/scan.cu index 2df3891d88d..429a1fe3273 100644 --- a/cpp/src/reductions/scan.cu +++ b/cpp/src/reductions/scan.cu @@ -182,7 +182,7 @@ struct ScanDispatcher { CHECK_CUDA(stream.value()); auto output_column = cudf::detail::make_strings_column( - device_span{result.data(), result.size()}, Op::template identity(), stream, mr); + device_span{result}, Op::template identity(), stream, mr); if (null_handling == null_policy::EXCLUDE) { output_column->set_null_mask(detail::copy_bitmask(input_view, stream, mr), input_view.null_count()); From 61604d141e00810ca35bc118ffdbc7d7f340ff8e Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Tue, 23 Feb 2021 12:39:10 +1100 Subject: [PATCH 09/28] Remove errant std::cout --- cpp/include/cudf_test/column_wrapper.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/include/cudf_test/column_wrapper.hpp b/cpp/include/cudf_test/column_wrapper.hpp index 8e89b77ea5d..510cab1ffe7 100644 --- a/cpp/include/cudf_test/column_wrapper.hpp +++ b/cpp/include/cudf_test/column_wrapper.hpp @@ -139,7 +139,6 @@ template ()>* = nullptr> rmm::device_buffer make_elements(InputIterator begin, InputIterator end) { - std::cout << "hello?\n"; static_assert(cudf::is_fixed_width(), "Unexpected non-fixed width type."); auto transformer = fixed_width_type_converter{}; auto transform_begin = thrust::make_transform_iterator(begin, transformer); From 43a31920a07c3c0c40c60b2c551574f23f42bcb8 Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Tue, 23 Feb 2021 17:42:03 +1100 Subject: [PATCH 10/28] Make span classes part of public interface and refactor strings column factories to use them --- cpp/include/cudf/column/column_factories.hpp | 127 ++++++++---------- cpp/include/cudf/detail/utilities/trie.cuh | 2 +- .../detail/strings_column_factories.hpp | 32 ----- cpp/include/cudf/strings/detail/utilities.hpp | 4 +- cpp/include/cudf/utilities/span.hpp | 14 +- cpp/include/cudf_test/iterator_utilities.hpp | 4 +- cpp/src/binaryop/compiled/binary_ops.cu | 4 +- cpp/src/io/avro/avro_gpu.cu | 2 +- cpp/src/io/avro/avro_gpu.h | 2 +- cpp/src/io/avro/reader_impl.cu | 2 +- cpp/src/io/avro/reader_impl.hpp | 2 +- cpp/src/io/comp/io_uncomp.h | 2 +- cpp/src/io/comp/uncomp.cpp | 2 +- cpp/src/io/csv/csv_gpu.cu | 2 +- cpp/src/io/csv/csv_gpu.h | 2 +- cpp/src/io/csv/reader_impl.cu | 10 +- cpp/src/io/csv/reader_impl.hpp | 2 +- cpp/src/io/json/json_gpu.cu | 2 +- cpp/src/io/json/json_gpu.h | 2 +- cpp/src/io/json/reader_impl.cu | 10 +- cpp/src/io/orc/timezone.cuh | 12 +- cpp/src/io/utilities/parsing_utils.cuh | 2 +- cpp/src/reductions/scan.cu | 5 +- cpp/src/strings/convert/convert_urls.cu | 2 +- cpp/src/strings/strings_column_factories.cu | 70 ++++------ cpp/src/strings/utilities.cu | 11 +- cpp/tests/utilities_tests/span_tests.cu | 4 +- 27 files changed, 131 insertions(+), 204 deletions(-) delete mode 100644 cpp/include/cudf/strings/detail/strings_column_factories.hpp diff --git a/cpp/include/cudf/column/column_factories.hpp b/cpp/include/cudf/column/column_factories.hpp index 7ccc5879f5f..bfbebc8379e 100644 --- a/cpp/include/cudf/column/column_factories.hpp +++ b/cpp/include/cudf/column/column_factories.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -330,7 +331,7 @@ std::unique_ptr make_fixed_width_column( } /** - * @brief Construct STRING type column given a device vector of pointer/size pairs. + * @brief Construct STRING type column given a device span of pointer/size pairs. * The total number of char bytes must not exceed the maximum size of size_type. * The string characters are expected to be UTF-8 encoded sequence of char * bytes. Use the strings_column_view class to perform strings operations on @@ -344,20 +345,19 @@ std::unique_ptr make_fixed_width_column( * * @throws std::bad_alloc if device memory allocation fails * - * @param[in] strings The vector of pointer/size pairs. - * Each pointer must be a device memory address or `nullptr` - * (indicating a null string). The size must be the number of bytes. + * @param[in] strings The device span of pointer/size pairs. Each pointer must be a device memory + address or `nullptr` (indicating a null string). The size must be the number of bytes. * @param[in] stream CUDA stream used for device memory operations and kernel launches. * @param[in] mr Device memory resource used for allocation of the column's `null_mask` and children * columns' device memory. */ std::unique_ptr make_strings_column( - const rmm::device_vector>& strings, + cudf::device_span> strings, rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); /** - * @brief Construct STRING type column given a device vector of string_view. + * @brief Construct STRING type column given a device span of string_view. * The total number of char bytes must not exceed the maximum size of size_type. * The string characters are expected to be UTF-8 encoded sequence of char * bytes. Use the strings_column_view class to perform strings operations on @@ -372,10 +372,8 @@ std::unique_ptr make_strings_column( * * @throws std::bad_alloc if device memory allocation fails * - * @param[in] string_views The vector of string_view. - * Each string_view must point to a device memory address or - * `null_placeholder` (indicating a null string). The size must be the number of - * bytes. + * @param[in] string_views The span of string_view. Each string_view must point to a device memory + address or `null_placeholder` (indicating a null string). The size must be the number of bytes. * @param[in] null_placeholder string_view indicating null string in given list of * string_views. * @param[in] stream CUDA stream used for device memory operations and kernel launches. @@ -383,79 +381,69 @@ std::unique_ptr make_strings_column( * columns' device memory. */ std::unique_ptr make_strings_column( - const rmm::device_vector& string_views, + cudf::device_span string_views, const string_view null_placeholder, rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); /** - * @brief Construct STRING type column given a device vector of chars - * encoded as UTF-8, a device vector of byte offsets identifying individual - * strings within the char vector, and an optional null bitmask. + * @brief Construct STRING type column given a device span of chars encoded as UTF-8, a device + * span of byte offsets identifying individual strings within the char vector, and an optional + * null bitmask. * * `offsets.front()` must always be zero. * - * The total number of char bytes must not exceed the maximum size of size_type. - * Use the strings_column_view class to perform strings operations on this type - * of column. - * This function makes a deep copy of the strings, offsets, null_mask to create - * a new column. + * The total number of char bytes must not exceed the maximum size of size_type. Use the + * strings_column_view class to perform strings operations on this type of column. + * + * This function makes a deep copy of the strings, offsets, null_mask to create a new column. * * @throws std::bad_alloc if device memory allocation fails * - * @param[in] strings The vector of chars in device memory. - * This char vector is expected to be UTF-8 encoded characters. - * @param[in] offsets The vector of byte offsets in device memory. - * The number of elements is one more than the total number - * of strings so the `offsets.back()` is the total - * number of bytes in the strings array. - * `offsets.front()` must always be 0 to point to the beginning - * of `strings`. - * @param[in] null_mask Device vector containing the null element indicator bitmask. - * Arrow format for nulls is used for interpeting this bitmask. - * @param[in] null_count The number of null string entries. If equal to - * `UNKNOWN_NULL_COUNT`, the null count will be computed dynamically on the - * first invocation of `column::null_count()` + * @param[in] strings The device span of chars in device memory. This char vector is expected to be + * UTF-8 encoded characters. + * @param[in] offsets The device span of byte offsets in device memory. The number of elements is + * one more than the total number of strings so the `offsets.back()` is the total number of bytes + * in the strings array. `offsets.front()` must always be 0 to point to the beginning of `strings`. + * @param[in] null_mask Device span containing the null element indicator bitmask. Arrow format for + * nulls is used for interpeting this bitmask. + * @param[in] null_count The number of null string entries. If equal to `UNKNOWN_NULL_COUNT`, the + * null count will be computed dynamically on the first invocation of `column::null_count()` * @param[in] stream CUDA stream used for device memory operations and kernel launches. * @param[in] mr Device memory resource used for allocation of the column's `null_mask` and children * columns' device memory. */ std::unique_ptr make_strings_column( - const rmm::device_vector& strings, - const rmm::device_vector& offsets, - const rmm::device_vector& null_mask = {}, - size_type null_count = cudf::UNKNOWN_NULL_COUNT, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + cudf::device_span strings, + cudf::device_span offsets, + cudf::device_span null_mask = {}, + size_type null_count = cudf::UNKNOWN_NULL_COUNT, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); /** - * @brief Construct STRING type column given a host vector of chars - * encoded as UTF-8, a host vector of byte offsets identifying individual - * strings within the char vector, and an optional null bitmask. + * @brief Construct STRING type column given a host vector of chars encoded as UTF-8, a host vector + * of byte offsets identifying individual strings within the char vector, and an optional null + * bitmask. * * `offsets.front()` must always be zero. * - * The total number of char bytes must not exceed the maximum size of size_type. - * Use the strings_column_view class to perform strings operations on this type - * of column. - * This function makes a deep copy of the strings, offsets, null_mask to create - * a new column. + * The total number of char bytes must not exceed the maximum size of size_type. Use the + * strings_column_view class to perform strings operations on this type of column. + * + * This function makes a deep copy of the strings, offsets, null_mask to create a new column. * * @throws std::bad_alloc if device memory allocation fails * - * @param[in] strings The contiguous array of chars in host memory. - * This char array is expected to be UTF-8 encoded characters. - * @param[in] offsets The array of byte offsets in host memory. - * The number of elements is one more than the total number - * of strings so the `offsets.back()` is the total - * number of bytes in the strings array. - * `offsets.front()` must always be 0 to point to the beginning - * of `strings`. - * @param[in] null_mask Host vector containing the null element indicator bitmask. - * Arrow format for nulls is used for interpeting this bitmask. - * @param[in] null_count The number of null string entries. If equal to - * `UNKNOWN_NULL_COUNT`, the null count will be computed dynamically on the - * first invocation of `column::null_count()` + * @param[in] strings Host vector of chars in host memory. This char array is expected to be + * UTF-8 encoded characters. + * @param[in] offsets Host vector of byte offsets in host memory. The number of elements is one + * more than the total number of strings so the `offsets.back()` is the total number of bytes in + * the strings array. `offsets.front()` must always be 0 to point to the beginning of `strings`. + * @param[in] null_mask Host vector containing the null element indicator bitmask. Arrow format for + * nulls is used for interpeting this bitmask. + * @param[in] null_count The number of null string entries. If equal to `UNKNOWN_NULL_COUNT`, the + * null count will be computed dynamically on the first invocation of `column::null_count()` * @param[in] stream CUDA stream used for device memory operations and kernel launches. * @param[in] mr Device memory resource used for allocation of the column's `null_mask` and children * columns' device memory. @@ -469,21 +457,18 @@ std::unique_ptr make_strings_column( rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); /** - * @brief Constructs a STRING type column given offsets column, chars columns, - * and null mask and null count. The columns and mask are moved into the - * resulting strings column. + * @brief Constructs a STRING type column given offsets column, chars columns, and null mask and + * null count. The columns and mask are moved into the resulting strings column. * * @param[in] num_strings The number of strings the column represents. - * @param[in] offsets_column The column of offset values for this column. - * The number of elements is one more than the total number - * of strings so the offset[last] - offset[0] is the total - * number of bytes in the strings vector. - * @param[in] chars_column The column of char bytes for all the strings for this column. - * Individual strings are identified by the offsets and the - * nullmask. + * @param[in] offsets_column The column of offset values for this column. The number of elements is + * one more than the total number of strings so the `offset[last] - offset[0]` is the total number + * of bytes in the strings vector. + * @param[in] chars_column The column of char bytes for all the strings for this column. Individual + * strings are identified by the offsets and the nullmask. * @param[in] null_count The number of null string entries. - * @param[in] null_mask The bits specifying the null strings in device memory. - * Arrow format for nulls is used for interpeting this bitmask. + * @param[in] null_mask The bits specifying the null strings in device memory. Arrow format for + * nulls is used for interpeting this bitmask. * @param[in] stream CUDA stream used for device memory operations and kernel launches. * @param[in] mr Device memory resource used for allocation of the column's `null_mask` and children * columns' device memory. diff --git a/cpp/include/cudf/detail/utilities/trie.cuh b/cpp/include/cudf/detail/utilities/trie.cuh index 77b184a4874..1881e337151 100644 --- a/cpp/include/cudf/detail/utilities/trie.cuh +++ b/cpp/include/cudf/detail/utilities/trie.cuh @@ -30,7 +30,7 @@ #include #include -using cudf::detail::device_span; +using cudf::device_span; static constexpr char trie_terminating_character = '\n'; diff --git a/cpp/include/cudf/strings/detail/strings_column_factories.hpp b/cpp/include/cudf/strings/detail/strings_column_factories.hpp deleted file mode 100644 index 7d697c672c6..00000000000 --- a/cpp/include/cudf/strings/detail/strings_column_factories.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -#include - -#include -#include - -namespace cudf { -namespace detail { - -std::unique_ptr make_strings_column( - device_span> const& strings, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); - -std::unique_ptr make_strings_column( - device_span const& string_views, - string_view const null_placeholder, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); - -std::unique_ptr make_strings_column( - device_span const& chars, - device_span const& offsets, - size_type null_count, - rmm::device_buffer&& null_mask, - rmm::cuda_stream_view stream = rmm::cuda_stream_default, - rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); - -} // namespace detail - -} // namespace cudf diff --git a/cpp/include/cudf/strings/detail/utilities.hpp b/cpp/include/cudf/strings/detail/utilities.hpp index 8844d2fb4b2..a5db4d55001 100644 --- a/cpp/include/cudf/strings/detail/utilities.hpp +++ b/cpp/include/cudf/strings/detail/utilities.hpp @@ -73,7 +73,7 @@ rmm::device_uvector create_string_vector_from_column( * @return Child offsets column */ std::unique_ptr child_offsets_from_string_vector( - cudf::detail::device_span strings, + cudf::device_span strings, rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); @@ -87,7 +87,7 @@ std::unique_ptr child_offsets_from_string_vector( * @return Child chars column */ std::unique_ptr child_chars_from_string_vector( - cudf::detail::device_span strings, + cudf::device_span strings, column_view const& offsets, rmm::cuda_stream_view stream = rmm::cuda_stream_default, rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); diff --git a/cpp/include/cudf/utilities/span.hpp b/cpp/include/cudf/utilities/span.hpp index 750eff56d4c..b9bafd975dd 100644 --- a/cpp/include/cudf/utilities/span.hpp +++ b/cpp/include/cudf/utilities/span.hpp @@ -28,10 +28,11 @@ #include namespace cudf { -namespace detail { constexpr std::size_t dynamic_extent = std::numeric_limits::max(); +namespace detail { + /** * @brief C++20 std::span with reduced feature set. */ @@ -100,6 +101,8 @@ class span_base { size_type _size; }; +} // namespace detail + // ===== host_span ================================================================================= template @@ -116,8 +119,8 @@ struct is_host_span_supported_container< // thrust::host_vector> : std::true_type { }; -template -struct host_span : public span_base> { +template +struct host_span : public cudf::detail::span_base> { using base = cudf::detail::span_base>; using base::base; @@ -155,8 +158,8 @@ struct is_device_span_supported_container< // rmm::device_uvector> : std::true_type { }; -template -struct device_span : public span_base> { +template +struct device_span : public cudf::detail::span_base> { using base = cudf::detail::span_base>; using base::base; @@ -173,5 +176,4 @@ struct device_span : public span_base> { } }; -} // namespace detail } // namespace cudf diff --git a/cpp/include/cudf_test/iterator_utilities.hpp b/cpp/include/cudf_test/iterator_utilities.hpp index 40c275a13d3..297bcbf175c 100644 --- a/cpp/include/cudf_test/iterator_utilities.hpp +++ b/cpp/include/cudf_test/iterator_utilities.hpp @@ -66,7 +66,7 @@ static auto iterator_with_null_at(Iter index_start, Iter index_end) * and yields `true` (to mark valid rows) for all other indices. E.g. * * @code - * using host_span = cudf::detail::host_span; + * using host_span = cudf::host_span; * auto iter = iterator_with_null_at(host_span{std::vector{8,9}}); * iter[6] == true; // i.e. Valid row at index 6. * iter[7] == true; // i.e. Valid row at index 7. @@ -77,7 +77,7 @@ static auto iterator_with_null_at(Iter index_start, Iter index_end) * @param indices The indices for which the validity iterator must return `false` (i.e. null) * @return auto Validity iterator */ -static auto iterator_with_null_at(cudf::detail::host_span const& indices) +static auto iterator_with_null_at(cudf::host_span const& indices) { return iterator_with_null_at(indices.begin(), indices.end()); } diff --git a/cpp/src/binaryop/compiled/binary_ops.cu b/cpp/src/binaryop/compiled/binary_ops.cu index b7382c5d8c0..4166209e40c 100644 --- a/cpp/src/binaryop/compiled/binary_ops.cu +++ b/cpp/src/binaryop/compiled/binary_ops.cu @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -402,8 +401,7 @@ struct null_considering_binop { lhs_dev_view, rhs_dev_view, col_size, stream, minmax_func, out_col_strings.data()); // Create an output column with the resultant strings - out = cudf::detail::make_strings_column( - cudf::detail::device_span{out_col_strings}, invalid_str, stream, mr); + out = cudf::make_strings_column(out_col_strings, invalid_str, stream, mr); break; } diff --git a/cpp/src/io/avro/avro_gpu.cu b/cpp/src/io/avro/avro_gpu.cu index 4eefee66531..a97ea737b1d 100644 --- a/cpp/src/io/avro/avro_gpu.cu +++ b/cpp/src/io/avro/avro_gpu.cu @@ -19,7 +19,7 @@ #include -using cudf::detail::device_span; +using cudf::device_span; namespace cudf { namespace io { diff --git a/cpp/src/io/avro/avro_gpu.h b/cpp/src/io/avro/avro_gpu.h index 5aac6f99a80..6f37a540a8c 100644 --- a/cpp/src/io/avro/avro_gpu.h +++ b/cpp/src/io/avro/avro_gpu.h @@ -59,7 +59,7 @@ struct schemadesc_s { */ void DecodeAvroColumnData(block_desc_s *blocks, schemadesc_s *schema, - cudf::detail::device_span global_dictionary, + cudf::device_span global_dictionary, const uint8_t *avro_data, uint32_t num_blocks, uint32_t schema_len, diff --git a/cpp/src/io/avro/reader_impl.cu b/cpp/src/io/avro/reader_impl.cu index b0806a9cf92..fe97ee1009b 100644 --- a/cpp/src/io/avro/reader_impl.cu +++ b/cpp/src/io/avro/reader_impl.cu @@ -32,7 +32,7 @@ #include #include -using cudf::detail::device_span; +using cudf::device_span; namespace cudf { namespace io { diff --git a/cpp/src/io/avro/reader_impl.hpp b/cpp/src/io/avro/reader_impl.hpp index 880c428b60d..aad97c44288 100644 --- a/cpp/src/io/avro/reader_impl.hpp +++ b/cpp/src/io/avro/reader_impl.hpp @@ -97,7 +97,7 @@ class reader::impl { */ void decode_data(const rmm::device_buffer &block_data, const std::vector> &dict, - cudf::detail::device_span global_dictionary, + cudf::device_span global_dictionary, size_t num_rows, std::vector> columns, std::vector &out_buffers, diff --git a/cpp/src/io/comp/io_uncomp.h b/cpp/src/io/comp/io_uncomp.h index 55f8d20dda5..302bcb93e01 100644 --- a/cpp/src/io/comp/io_uncomp.h +++ b/cpp/src/io/comp/io_uncomp.h @@ -22,7 +22,7 @@ #include -using cudf::detail::host_span; +using cudf::host_span; namespace cudf { namespace io { diff --git a/cpp/src/io/comp/uncomp.cpp b/cpp/src/io/comp/uncomp.cpp index 68441ac4db9..57c37eaa7b1 100644 --- a/cpp/src/io/comp/uncomp.cpp +++ b/cpp/src/io/comp/uncomp.cpp @@ -26,7 +26,7 @@ #include // uncompress -using cudf::detail::host_span; +using cudf::host_span; namespace cudf { namespace io { diff --git a/cpp/src/io/csv/csv_gpu.cu b/cpp/src/io/csv/csv_gpu.cu index 041d1de3404..bddd5f2a722 100644 --- a/cpp/src/io/csv/csv_gpu.cu +++ b/cpp/src/io/csv/csv_gpu.cu @@ -42,7 +42,7 @@ using namespace ::cudf::io; -using cudf::detail::device_span; +using cudf::device_span; namespace cudf { namespace io { diff --git a/cpp/src/io/csv/csv_gpu.h b/cpp/src/io/csv/csv_gpu.h index d0e0698f8e7..2947bb242d4 100644 --- a/cpp/src/io/csv/csv_gpu.h +++ b/cpp/src/io/csv/csv_gpu.h @@ -23,7 +23,7 @@ #include -using cudf::detail::device_span; +using cudf::device_span; namespace cudf { namespace io { diff --git a/cpp/src/io/csv/reader_impl.cu b/cpp/src/io/csv/reader_impl.cu index c00741435d7..87e9526ab31 100644 --- a/cpp/src/io/csv/reader_impl.cu +++ b/cpp/src/io/csv/reader_impl.cu @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -43,8 +42,8 @@ using std::string; using std::vector; -using cudf::detail::device_span; -using cudf::detail::host_span; +using cudf::device_span; +using cudf::host_span; namespace cudf { namespace io { @@ -352,10 +351,7 @@ table_with_metadata reader::impl::read(rmm::cuda_stream_view stream) // during the conversion stage const std::string quotechar(1, opts.quotechar); const std::string dblquotechar(2, opts.quotechar); - std::unique_ptr col = cudf::detail::make_strings_column( - cudf::detail::device_span>{ - out_buffers[i]._strings.data().get(), out_buffers[i]._strings.size()}, - stream); + std::unique_ptr col = cudf::make_strings_column(out_buffers[i]._strings, stream); out_columns.emplace_back( cudf::strings::replace(col->view(), dblquotechar, quotechar, -1, mr_)); } else { diff --git a/cpp/src/io/csv/reader_impl.hpp b/cpp/src/io/csv/reader_impl.hpp index 67246165be0..e207be301d9 100644 --- a/cpp/src/io/csv/reader_impl.hpp +++ b/cpp/src/io/csv/reader_impl.hpp @@ -35,7 +35,7 @@ #include #include -using cudf::detail::host_span; +using cudf::host_span; namespace cudf { namespace io { diff --git a/cpp/src/io/json/json_gpu.cu b/cpp/src/io/json/json_gpu.cu index 7448d49e117..b44600a3c37 100644 --- a/cpp/src/io/json/json_gpu.cu +++ b/cpp/src/io/json/json_gpu.cu @@ -38,7 +38,7 @@ #include #include -using cudf::detail::device_span; +using cudf::device_span; namespace cudf { namespace io { diff --git a/cpp/src/io/json/json_gpu.h b/cpp/src/io/json/json_gpu.h index cbab408d2f1..25f8ea897d3 100644 --- a/cpp/src/io/json/json_gpu.h +++ b/cpp/src/io/json/json_gpu.h @@ -29,7 +29,7 @@ #include -using cudf::detail::device_span; +using cudf::device_span; namespace cudf { namespace io { diff --git a/cpp/src/io/json/reader_impl.cu b/cpp/src/io/json/reader_impl.cu index 4ae7e063b4b..487e91df50c 100644 --- a/cpp/src/io/json/reader_impl.cu +++ b/cpp/src/io/json/reader_impl.cu @@ -41,7 +41,7 @@ #include -using cudf::detail::host_span; +using cudf::host_span; namespace cudf { namespace io { @@ -600,9 +600,11 @@ table_with_metadata reader::impl::convert_data_to_table(rmm::cuda_stream_view st stream.synchronize(); // postprocess columns - auto target = make_strings_column( - std::vector{'\\', '"', '\\', '\\', '\\', 't', '\\', 'r', '\\', 'b'}, {0, 2, 4, 6, 8, 10}); - auto repl = make_strings_column({'"', '\\', '\t', '\r', '\b'}, {0, 1, 2, 3, 4, 5}); + auto target = + make_strings_column(std::vector{'\\', '"', '\\', '\\', '\\', 't', '\\', 'r', '\\', 'b'}, + std::vector{0, 2, 4, 6, 8, 10}); + auto repl = make_strings_column(std::vector{'"', '\\', '\t', '\r', '\b'}, + std::vector{0, 1, 2, 3, 4, 5}); thrust::host_vector h_valid_counts = d_valid_counts; std::vector> out_columns; diff --git a/cpp/src/io/orc/timezone.cuh b/cpp/src/io/orc/timezone.cuh index 6bb1e787432..0b2d8ebbd70 100644 --- a/cpp/src/io/orc/timezone.cuh +++ b/cpp/src/io/orc/timezone.cuh @@ -32,8 +32,8 @@ namespace io { struct timezone_table_view { int32_t gmt_offset = 0; - cudf::detail::device_span ttimes; - cudf::detail::device_span offsets; + cudf::device_span ttimes; + cudf::device_span offsets; }; static constexpr int64_t day_seconds = 24 * 60 * 60; @@ -85,8 +85,8 @@ CUDA_HOST_DEVICE_CALLABLE int32_t get_gmt_offset_impl(int64_t const *ttimes, * * Implemented in `get_gmt_offset_impl`. */ -inline __host__ int32_t get_gmt_offset(cudf::detail::host_span ttimes, - cudf::detail::host_span offsets, +inline __host__ int32_t get_gmt_offset(cudf::host_span ttimes, + cudf::host_span offsets, int64_t ts) { CUDF_EXPECTS(ttimes.size() == offsets.size(), @@ -99,8 +99,8 @@ inline __host__ int32_t get_gmt_offset(cudf::detail::host_span tt * * Implemented in `get_gmt_offset_impl`. */ -inline __device__ int32_t get_gmt_offset(cudf::detail::device_span ttimes, - cudf::detail::device_span offsets, +inline __device__ int32_t get_gmt_offset(cudf::device_span ttimes, + cudf::device_span offsets, int64_t ts) { return get_gmt_offset_impl(ttimes.begin(), offsets.begin(), ttimes.size(), ts); diff --git a/cpp/src/io/utilities/parsing_utils.cuh b/cpp/src/io/utilities/parsing_utils.cuh index c7f405e1cc0..9574009ccc6 100644 --- a/cpp/src/io/utilities/parsing_utils.cuh +++ b/cpp/src/io/utilities/parsing_utils.cuh @@ -22,7 +22,7 @@ #include -using cudf::detail::device_span; +using cudf::device_span; namespace cudf { namespace io { diff --git a/cpp/src/reductions/scan.cu b/cpp/src/reductions/scan.cu index 429a1fe3273..0d622387cfb 100644 --- a/cpp/src/reductions/scan.cu +++ b/cpp/src/reductions/scan.cu @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -181,8 +180,8 @@ struct ScanDispatcher { } CHECK_CUDA(stream.value()); - auto output_column = cudf::detail::make_strings_column( - device_span{result}, Op::template identity(), stream, mr); + auto output_column = + cudf::make_strings_column(result, Op::template identity(), stream, mr); if (null_handling == null_policy::EXCLUDE) { output_column->set_null_mask(detail::copy_bitmask(input_view, stream, mr), input_view.null_count()); diff --git a/cpp/src/strings/convert/convert_urls.cu b/cpp/src/strings/convert/convert_urls.cu index 2b93995ec87..cdca23a3584 100644 --- a/cpp/src/strings/convert/convert_urls.cu +++ b/cpp/src/strings/convert/convert_urls.cu @@ -33,7 +33,7 @@ #include #include -using cudf::detail::device_span; +using cudf::device_span; namespace cudf { namespace strings { diff --git a/cpp/src/strings/strings_column_factories.cu b/cpp/src/strings/strings_column_factories.cu index fc74d82f4c3..e08d34f7028 100644 --- a/cpp/src/strings/strings_column_factories.cu +++ b/cpp/src/strings/strings_column_factories.cu @@ -48,30 +48,18 @@ struct string_view_to_pair { } // namespace -namespace detail { - +// Create a strings-type column from vector of pointer/size pairs std::unique_ptr make_strings_column( - const device_span>& strings, + device_span> strings, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { return cudf::strings::detail::make_strings_column(strings.begin(), strings.end(), stream, mr); } -std::unique_ptr make_strings_column(const device_span& string_views, - const string_view null_placeholder, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - auto it_pair = - thrust::make_transform_iterator(string_views.begin(), string_view_to_pair{null_placeholder}); - return cudf::strings::detail::make_strings_column( - it_pair, it_pair + string_views.size(), stream, mr); -} - std::unique_ptr make_strings_column( - device_span const& chars, - device_span const& offsets, + device_span chars, + device_span offsets, size_type null_count, rmm::device_buffer&& null_mask, rmm::cuda_stream_view stream = rmm::cuda_stream_default, @@ -87,41 +75,28 @@ std::unique_ptr make_strings_column( mr); } -} // namespace detail - -// Create a strings-type column from vector of pointer/size pairs -std::unique_ptr make_strings_column( - const rmm::device_vector>& strings, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) -{ - return strings::detail::make_strings_column(strings.begin(), strings.end(), stream, mr); -} - -// Create a strings-type column from vector of string_view -std::unique_ptr make_strings_column(const rmm::device_vector& string_views, - const string_view null_placeholder, +std::unique_ptr make_strings_column(device_span string_views, + string_view null_placeholder, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { - return detail::make_strings_column( - detail::device_span{const_cast(string_views.data().get()), - string_views.size()}, - null_placeholder, - stream, - mr); + auto it_pair = + thrust::make_transform_iterator(string_views.begin(), string_view_to_pair{null_placeholder}); + return cudf::strings::detail::make_strings_column( + it_pair, it_pair + string_views.size(), stream, mr); } // Create a strings-type column from device vector of chars and vector of offsets. -std::unique_ptr make_strings_column(rmm::device_vector const& strings, - rmm::device_vector const& offsets, - rmm::device_vector const& valid_mask, +std::unique_ptr make_strings_column(cudf::device_span strings, + cudf::device_span offsets, + cudf::device_span valid_mask, size_type null_count, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { // build null bitmask - rmm::device_buffer null_mask{valid_mask.data().get(), valid_mask.size() * sizeof(bitmask_type)}; + rmm::device_buffer null_mask{ + valid_mask.data(), valid_mask.size() * sizeof(bitmask_type), stream, mr}; return cudf::strings::detail::make_strings_column(strings.begin(), strings.end(), @@ -158,12 +133,15 @@ std::unique_ptr make_strings_column(std::vector const& strings, cudaMemcpyDefault, stream.value())); - return make_strings_column(detail::device_span{d_strings}, - detail::device_span{d_offsets}, - null_count, - d_null_mask.release(), - stream, - mr); + auto ret = make_strings_column(device_span{d_strings}, + device_span{d_offsets}, + null_count, + d_null_mask.release(), + stream, + mr); + + stream.synchronize(); + return ret; } // diff --git a/cpp/src/strings/utilities.cu b/cpp/src/strings/utilities.cu index 5b9a1374224..2af313627ad 100644 --- a/cpp/src/strings/utilities.cu +++ b/cpp/src/strings/utilities.cu @@ -80,7 +80,7 @@ rmm::device_uvector create_string_vector_from_column(cudf::strings_ * @copydoc child_offsets_from_string_vector */ std::unique_ptr child_offsets_from_string_vector( - cudf::detail::device_span strings, + cudf::device_span strings, rmm::cuda_stream_view stream, rmm::mr::device_memory_resource* mr) { @@ -90,11 +90,10 @@ std::unique_ptr child_offsets_from_string_vector( /** * @copydoc child_chars_from_string_vector */ -std::unique_ptr child_chars_from_string_vector( - cudf::detail::device_span strings, - column_view const& offsets, - rmm::cuda_stream_view stream, - rmm::mr::device_memory_resource* mr) +std::unique_ptr child_chars_from_string_vector(cudf::device_span strings, + column_view const& offsets, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) { auto const d_strings = strings.data(); auto const bytes = cudf::detail::get_value(offsets, strings.size(), stream); diff --git a/cpp/tests/utilities_tests/span_tests.cu b/cpp/tests/utilities_tests/span_tests.cu index d49a345fc61..6456e3d7294 100644 --- a/cpp/tests/utilities_tests/span_tests.cu +++ b/cpp/tests/utilities_tests/span_tests.cu @@ -27,8 +27,8 @@ #include #include -using cudf::detail::device_span; -using cudf::detail::host_span; +using cudf::device_span; +using cudf::host_span; template void expect_equivolent(host_span a, host_span b) From 9962b9b3bdd1d7b0f5b393a69aa4959350c40de0 Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Wed, 24 Feb 2021 20:33:06 +1100 Subject: [PATCH 11/28] Add make_device_uvector_* utilities --- .../detail/utilities/vector_factories.hpp | 242 ++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 cpp/include/cudf/detail/utilities/vector_factories.hpp diff --git a/cpp/include/cudf/detail/utilities/vector_factories.hpp b/cpp/include/cudf/detail/utilities/vector_factories.hpp new file mode 100644 index 00000000000..a811ed9071a --- /dev/null +++ b/cpp/include/cudf/detail/utilities/vector_factories.hpp @@ -0,0 +1,242 @@ +/* + * + * Copyright (c) 2021, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief Convenience factories for creating device vectors from host spans + * @file vector_factories.hpp + */ + +#include + +#include +#include +#include + +namespace cudf { +namespace detail { + +/** + * @brief Asynchronously construct a `device_uvector` containing a deep copy of data from a + * host_span + * + * @note This function does not synchronize `stream`. + * + * @tparam T The type of the data to copy + * @param source_data The host_span of data to deep copy + * @param stream The stream on which to allocate memory and perform the copy + * @param mr The memory resource to use for allocating the returned device_uvector + * @return rmm::device_uvector A device_uvector containing the copied data + */ +template +rmm::device_uvector make_device_uvector_async( + host_span source_data, + rmm::cuda_stream_view stream = rmm::cuda_stream_default, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()) +{ + rmm::device_uvector ret(source_data.size(), stream, mr); + CUDA_TRY(cudaMemcpyAsync(ret.data(), + source_data.data(), + source_data.size() * sizeof(T), + cudaMemcpyDefault, + stream.value())); + return ret; +} + +/** + * @brief Asynchronously construct a `device_uvector` containing a deep copy of data from a host + * container + * + * @note This function does not synchronize `stream`. + * + * @tparam Container The type of the container to copy from + * @tparam T The type of the data to copy + * @param c The input host container from which to copy + * @param stream The stream on which to allocate memory and perform the copy + * @param mr The memory resource to use for allocating the returned device_uvector + * @return rmm::device_uvector A device_uvector containing the copied data + */ +template