Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor strings column factories #7397

Merged
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7cfdbd5
Initial attempt at using span/iterators in make_strings_columns (WIP)
harrism Feb 16, 2021
a3a1cfa
Fix zip iterator
harrism Feb 17, 2021
99eea9e
Convert chars, offsets, nulls make_strings_column to iterators
harrism Feb 17, 2021
189fdf5
use device_span version of make_strings_column in scan.cu
harrism Feb 17, 2021
01a02e2
Add another device_span version of make_strings_column
harrism Feb 17, 2021
1b8b200
Use device_span version of make_strings_column in CSV reader_impl.cu
harrism Feb 17, 2021
b33ca20
make_strings_column from std::vector uses spans internally
harrism Feb 23, 2021
f43aeb1
Clean up binops/scan spans.
harrism Feb 23, 2021
f5ecc6e
Merge branch 'branch-0.19' into fea-refactor-strings-factories
harrism Feb 23, 2021
61604d1
Remove errant std::cout
harrism Feb 23, 2021
43a3192
Make span classes part of public interface and refactor strings colum…
harrism Feb 23, 2021
bc55428
Merge branch 'branch-0.19' into fea-refactor-strings-factories
harrism Feb 23, 2021
9962b9b
Add make_device_uvector_* utilities
harrism Feb 24, 2021
75937af
Eliminate std::vector version of make_strings_column factory
harrism Feb 24, 2021
76e67a6
Add vector_factories.hpp to meta.yaml
harrism Feb 24, 2021
164a6b2
Don't put return type in doxygen @return
harrism Feb 24, 2021
1299e01
Remove unnecessary includes and add CUDF_FUNC_RANGE
harrism Feb 24, 2021
f940ee5
Convert strings extract vector to uvector
harrism Feb 24, 2021
7ec1d44
strings findall device_uvector to device_vector
harrism Feb 24, 2021
b9d6972
strings partition device_vector -> uvector
harrism Feb 25, 2021
55d2e4e
device_vector ->uvector in strings split / split_record
harrism Feb 25, 2021
ed0fd9d
device_vector -> uvector in tokenize
harrism Feb 25, 2021
5dc8e4a
Merge branch 'branch-0.19' into fea-refactor-strings-factories
harrism Mar 2, 2021
3fad943
Clean up vector_factories.hpp
harrism Mar 2, 2021
aeff8d2
Add missing const
harrism Mar 2, 2021
0cd009e
Add sync
harrism Mar 2, 2021
71db9af
Docs cleanup
harrism Mar 2, 2021
6596426
Remove unnecessary syncs in test
harrism Mar 2, 2021
4a4c8fc
Copyrights
harrism Mar 3, 2021
8ec27bf
Remove blank line
harrism Mar 3, 2021
8b132c4
Merge branch 'branch-0.19' into fea-refactor-strings-factories
harrism Mar 3, 2021
fb3c023
Fix detail::span
harrism Mar 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions conda/recipes/libcudf/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ test:
- test -f $PREFIX/include/cudf/detail/utilities/alignment.hpp
- test -f $PREFIX/include/cudf/detail/utilities/integer_utils.hpp
- test -f $PREFIX/include/cudf/detail/utilities/int_fastdiv.h
- test -f $PREFIX/include/cudf/detail/utilities/vector_factories.hpp
- test -f $PREFIX/include/cudf/dictionary/detail/concatenate.hpp
- test -f $PREFIX/include/cudf/dictionary/detail/encode.hpp
- test -f $PREFIX/include/cudf/dictionary/detail/merge.hpp
Expand Down
7 changes: 6 additions & 1 deletion cpp/benchmarks/common/generate_benchmark_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <rmm/cuda_stream_view.hpp>
#include <rmm/device_buffer.hpp>
#include <rmm/device_vector.hpp>

#include <future>
#include <memory>
Expand Down Expand Up @@ -411,7 +412,11 @@ std::unique_ptr<cudf::column> create_random_column<cudf::string_view>(data_profi
row += std::max(run_len - 1, 0);
}
}
return cudf::make_strings_column(out_col.chars, out_col.offsets, out_col.null_mask);

rmm::device_vector<char> d_chars(out_col.chars);
rmm::device_vector<cudf::size_type> d_offsets(out_col.offsets);
rmm::device_vector<cudf::bitmask_type> d_null_mask(out_col.null_mask);
return cudf::make_strings_column(d_chars, d_offsets, d_null_mask);
}

template <>
Expand Down
1 change: 0 additions & 1 deletion cpp/benchmarks/copying/shift_benchmark.cu
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

#include <benchmark/benchmark.h>

#include <thrust/device_vector.h>
#include <thrust/execution_policy.h>
#include <thrust/functional.h>
#include <thrust/sequence.h>
Expand Down
185 changes: 64 additions & 121 deletions cpp/include/cudf/column/column_factories.hpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cpp/include/cudf/detail/utilities/trie.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#include <cuda_runtime.h>
#include <thrust/host_vector.h>

using cudf::detail::device_span;
using cudf::device_span;

static constexpr char trie_terminating_character = '\n';

Expand Down
237 changes: 237 additions & 0 deletions cpp/include/cudf/detail/utilities/vector_factories.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
/*
*
harrism marked this conversation as resolved.
Show resolved Hide resolved
* 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 <cudf/utilities/span.hpp>

#include <rmm/cuda_stream_view.hpp>
#include <rmm/device_uvector.hpp>
#include <rmm/mr/device/device_memory_resource.hpp>

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 A device_uvector containing the copied data
*/
template <typename T>
rmm::device_uvector<T> make_device_uvector_async(
host_span<T const> 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<T> 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 A device_uvector containing the copied data
*/
template <typename Container,
std::enable_if_t<
std::is_convertible<Container,
host_span<typename Container::value_type const>>::value>* = nullptr>
rmm::device_uvector<typename Container::value_type> make_device_uvector_async(
Container const& c,
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
return make_device_uvector_async(host_span<typename Container::value_type const>{c}, stream, mr);
}

/**
* @brief Asynchronously construct a `device_uvector` containing a deep copy of data from a
* `device_span`
*
* @note This function does not synchronize `stream`.
*
* @tparam T The type of the data to copy
* @param source_data The device_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 A device_uvector containing the copied data
*/
template <typename T>
rmm::device_uvector<T> make_device_uvector_async(
device_span<T const> 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<T> 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 device
* 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 device 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 A device_uvector containing the copied data
*/
template <
typename Container,
std::enable_if_t<
std::is_convertible<Container, device_span<typename Container::value_type const>>::value>* =
nullptr>
rmm::device_uvector<typename Container::value_type> make_device_uvector_async(
Container const& c,
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
return make_device_uvector_async(
device_span<typename Container::value_type const>{c}, stream, mr);
}

/**
* @brief Synchronously construct a `device_uvector` containing a deep copy of data from a
* `host_span`
*
* @note This function synchronizes `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 A device_uvector containing the copied data
*/
template <typename T>
rmm::device_uvector<T> make_device_uvector_sync(
host_span<T const> source_data,
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
auto ret = make_device_uvector_async(source_data, stream, mr);
stream.synchronize();
return ret;
}

/**
* @brief Synchronously construct a `device_uvector` containing a deep copy of data from a host
* container
*
* @note This function synchronizes `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 A device_uvector containing the copied data
*/
template <typename Container,
std::enable_if_t<
std::is_convertible<Container,
host_span<typename Container::value_type const>>::value>* = nullptr>
rmm::device_uvector<typename Container::value_type> make_device_uvector_sync(
Container const& c,
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
return make_device_uvector_sync(host_span<typename Container::value_type const>{c}, stream, mr);
}

/**
* @brief Synchronously construct a `device_uvector` containing a deep copy of data from a
* `device_span`
*
* @note This function synchronizes `stream`.
*
* @tparam T The type of the data to copy
* @param source_data The device_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 A device_uvector containing the copied data
*/
template <typename T>
rmm::device_uvector<T> make_device_uvector_sync(
device_span<T const> source_data,
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
auto ret = make_device_uvector_async(source_data, stream, mr);
stream.synchronize();
return ret;
}

/**
* @brief Synchronously construct a `device_uvector` containing a deep copy of data from a device
* container
*
* @note This function synchronizes `stream`.
*
* @tparam Container The type of the container to copy from
* @tparam T The type of the data to copy
* @param c The input device 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 A device_uvector containing the copied data
*/
template <
typename Container,
std::enable_if_t<
std::is_convertible<Container, device_span<typename Container::value_type const>>::value>* =
nullptr>
rmm::device_uvector<typename Container::value_type> make_device_uvector_sync(
Container const& c,
rmm::cuda_stream_view stream = rmm::cuda_stream_default,
rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource())
{
return make_device_uvector_sync(device_span<typename Container::value_type const>{c}, stream, mr);
}

} // namespace detail

} // namespace cudf
70 changes: 57 additions & 13 deletions cpp/include/cudf/strings/detail/strings_column_factories.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <cudf/strings/detail/utilities.hpp>
#include <cudf/utilities/error.hpp>

#include <rmm/thrust_rmm_allocator.h>
#include <rmm/cuda_stream_view.hpp>
#include <rmm/exec_policy.hpp>

Expand All @@ -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 <typename IndexPairIterator>
std::unique_ptr<column> make_strings_column(IndexPairIterator begin,
IndexPairIterator end,
Expand All @@ -56,33 +57,32 @@ std::unique_ptr<column> 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<int32_t>(item.second) : 0);
};
auto offsets_transformer_itr = thrust::make_transform_iterator(
thrust::make_counting_iterator<size_type>(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<int32_t>();

// 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<char>();
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<size_type>(0),
thrust::make_zip_iterator(
thrust::make_tuple(begin, offsets_column->view().template begin<int32_t>())),
strings_count,
copy_chars);

Expand All @@ -95,6 +95,50 @@ std::unique_ptr<column> make_strings_column(IndexPairIterator begin,
mr);
}

// Create a strings-type column from iterators to chars, offsets, and bitmask.
template <typename CharIterator, typename OffsetIterator>
std::unique_ptr<column> 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<int32_t>(),
[] __device__(auto offset) { return static_cast<int32_t>(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<char>());

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
Loading