Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 1 addition & 6 deletions cpp/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ endfunction()
set(CUDF_INSTALL_LIBRARY_DEPS OFF)
set(CUDF_EXCLUDE_DEPS_FROM_ALL ON)
set(CUDF_EXCLUDE_DEPS_FROM_ALL_FLAG EXCLUDE_FROM_ALL)
set(CUDF_ENABLE_ARROW_COMPUTE ON)
include(../cmake/thirdparty/get_arrow.cmake)

# ##################################################################################################
# test sources ##################################################################################
Expand Down Expand Up @@ -223,7 +221,7 @@ ConfigureTest(
QUANTILES_TEST quantiles/percentile_approx_test.cpp quantiles/quantile_test.cpp
quantiles/quantiles_test.cpp
GPUS 1
PERCENT 70 EXTRA_LIBS ${ARROW_LIBRARIES}
PERCENT 70
)

# ##################################################################################################
Expand Down Expand Up @@ -305,16 +303,13 @@ ConfigureTest(
INTEROP_TEST
interop/arrow_data_structures_test.cpp
interop/to_arrow_device_test.cpp
interop/to_arrow_test.cpp
interop/to_arrow_host_test.cpp
interop/from_arrow_test.cpp
interop/from_arrow_device_test.cpp
interop/from_arrow_host_test.cpp
interop/from_arrow_stream_test.cpp
interop/dlpack_test.cpp
EXTRA_LIBS
nanoarrow::nanoarrow
${ARROW_LIBRARIES}
)

# ##################################################################################################
Expand Down
101 changes: 101 additions & 0 deletions cpp/tests/interop/from_arrow_host_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,92 @@

#include <cuda/iterator>

#include <array>
#include <cstring>

namespace {

void release_schema(ArrowSchema* schema) { schema->release = nullptr; }

void release_array(ArrowArray* array) { array->release = nullptr; }

struct direct_arrow_c_producer {
static constexpr int64_t num_rows = 5;

std::array<int32_t, num_rows> int_values{1, 2, 5, 2, 7};
std::array<uint8_t, 1> int_validity{0b00011101};

std::array<int32_t, num_rows + 1> string_offsets{0, 3, 6, 6, 6, 9};
std::array<char, 9> string_chars{'f', 'f', 'f', 'a', 'a', 'a', 'c', 'c', 'c'};
std::array<uint8_t, 1> string_validity{0b00010111};

ArrowSchema schema{};
std::array<ArrowSchema, 2> child_schemas{};
std::array<ArrowSchema*, 2> child_schema_ptrs{};

ArrowArray array{};
std::array<ArrowArray, 2> child_arrays{};
std::array<ArrowArray*, 2> child_array_ptrs{};
std::array<void const*, 1> parent_buffers{nullptr};
std::array<void const*, 2> int_buffers{int_validity.data(), int_values.data()};
std::array<void const*, 3> string_buffers{
string_validity.data(), string_offsets.data(), string_chars.data()};

direct_arrow_c_producer()
{
child_schema_ptrs = {&child_schemas[0], &child_schemas[1]};
child_array_ptrs = {&child_arrays[0], &child_arrays[1]};

schema.format = "+s";
schema.name = "";
schema.flags = 0;
schema.n_children = child_schemas.size();
schema.children = child_schema_ptrs.data();
schema.release = release_schema;

child_schemas[0].format = "i";
child_schemas[0].name = "ints";
child_schemas[0].flags = ARROW_FLAG_NULLABLE;
child_schemas[0].release = release_schema;

child_schemas[1].format = "u";
child_schemas[1].name = "strings";
child_schemas[1].flags = ARROW_FLAG_NULLABLE;
child_schemas[1].release = release_schema;

array.length = num_rows;
array.null_count = 0;
array.n_buffers = parent_buffers.size();
array.n_children = child_arrays.size();
array.buffers = parent_buffers.data();
array.children = child_array_ptrs.data();
array.release = release_array;

child_arrays[0].length = num_rows;
child_arrays[0].null_count = 1;
child_arrays[0].n_buffers = int_buffers.size();
child_arrays[0].buffers = int_buffers.data();
child_arrays[0].release = release_array;

child_arrays[1].length = num_rows;
child_arrays[1].null_count = 1;
child_arrays[1].n_buffers = string_buffers.size();
child_arrays[1].buffers = string_buffers.data();
child_arrays[1].release = release_array;
}

ArrowDeviceArray device_array() const
{
ArrowDeviceArray out{};
std::memcpy(&out.array, &array, sizeof(ArrowArray));
out.device_type = ARROW_DEVICE_CPU;
out.device_id = -1;
return out;
}
};

} // namespace

// create a cudf::table and equivalent arrow table with host memory
std::tuple<std::unique_ptr<cudf::table>, nanoarrow::UniqueSchema, nanoarrow::UniqueArray>
get_nanoarrow_host_tables(cudf::size_type length)
Expand Down Expand Up @@ -106,6 +192,21 @@ TEST_F(FromArrowHostDeviceTest, EmptyTable)
CUDF_TEST_EXPECT_TABLES_EQUAL(expected_cudf_table, got_cudf_table->view());
}

TEST_F(FromArrowHostDeviceTest, DirectArrowCProducerTable)
{
direct_arrow_c_producer producer;
auto input = producer.device_array();

auto const expected_ints =
cudf::test::fixed_width_column_wrapper<int32_t>{{1, 2, 5, 2, 7}, {1, 0, 1, 1, 1}};
auto const expected_strings =
cudf::test::strings_column_wrapper{{"fff", "aaa", "", "xxx", "ccc"}, {1, 1, 1, 0, 1}};
auto const expected = cudf::table_view{{expected_ints, expected_strings}};

auto got_cudf_table = cudf::from_arrow_host(&producer.schema, &input);
CUDF_TEST_EXPECT_TABLES_EQUIVALENT(expected, got_cudf_table->view());
}

TEST_F(FromArrowHostDeviceTest, ZeroColumnsWithRows)
{
constexpr cudf::size_type num_rows = 5;
Expand Down
105 changes: 105 additions & 0 deletions cpp/tests/interop/to_arrow_host_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,23 @@

#include <cuda/iterator>

#include <array>
#include <cstdint>
#include <numeric>
#include <string_view>

using vector_of_columns = std::vector<std::unique_ptr<cudf::column>>;

namespace {

bool is_valid(void const* validity_buffer, cudf::size_type index)
{
auto const byte = static_cast<std::uint8_t const*>(validity_buffer)[index / 8];
return (byte & (std::uint8_t{1} << (index % 8))) != 0;
}

} // namespace

struct BaseToArrowHostFixture : public cudf::test::BaseFixture {
template <typename T>
void compare_subset(ArrowArrayView const* expected,
Expand Down Expand Up @@ -215,6 +228,98 @@ TEST_F(ToArrowHostDeviceTest, EmptyTable)
ArrowArrayViewReset(&actual);
}

TEST_F(ToArrowHostDeviceTest, DirectArrowCConsumerTable)
{
auto const expected_ints = std::array<int32_t, 5>{1, 2, 5, 2, 7};
auto const int_validity = std::array<bool, 5>{true, false, true, true, true};
auto const expected_offsets = std::array<int32_t, 6>{0, 3, 6, 6, 6, 9};
auto const string_validity = std::array<bool, 5>{true, true, true, false, true};

auto const ints = cudf::test::fixed_width_column_wrapper<int32_t>{
expected_ints.begin(), expected_ints.end(), int_validity.begin()};
auto const strings =
cudf::test::strings_column_wrapper{{"fff", "aaa", "", "", "ccc"}, string_validity.begin()};
auto const input = cudf::table_view{{ints, strings}};
auto const metadata = std::array<cudf::column_metadata, 2>{cudf::column_metadata{"ints"},
cudf::column_metadata{"strings"}};

auto schema = cudf::to_arrow_schema(input, metadata);
ASSERT_NE(nullptr, schema->release);
EXPECT_STREQ("+s", schema->format);
EXPECT_EQ(2, schema->n_children);
ASSERT_NE(nullptr, schema->children);

ASSERT_NE(nullptr, schema->children[0]);
EXPECT_STREQ("i", schema->children[0]->format);
EXPECT_STREQ("ints", schema->children[0]->name);
EXPECT_EQ(ARROW_FLAG_NULLABLE, schema->children[0]->flags);
EXPECT_EQ(0, schema->children[0]->n_children);

ASSERT_NE(nullptr, schema->children[1]);
EXPECT_STREQ("u", schema->children[1]->format);
EXPECT_STREQ("strings", schema->children[1]->name);
EXPECT_EQ(ARROW_FLAG_NULLABLE, schema->children[1]->flags);
EXPECT_EQ(0, schema->children[1]->n_children);

auto arrow = cudf::to_arrow_host(input);
EXPECT_EQ(ARROW_DEVICE_CPU, arrow->device_type);
EXPECT_EQ(-1, arrow->device_id);
EXPECT_EQ(nullptr, arrow->sync_event);

auto const* parent = &arrow->array;
ASSERT_NE(nullptr, parent->release);
EXPECT_EQ(5, parent->length);
EXPECT_EQ(0, parent->null_count);
EXPECT_EQ(0, parent->offset);
EXPECT_EQ(1, parent->n_buffers);
ASSERT_NE(nullptr, parent->buffers);
EXPECT_EQ(nullptr, parent->buffers[0]);
EXPECT_EQ(2, parent->n_children);
ASSERT_NE(nullptr, parent->children);

auto const* int_array = parent->children[0];
ASSERT_NE(nullptr, int_array);
ASSERT_NE(nullptr, int_array->release);
EXPECT_EQ(5, int_array->length);
EXPECT_EQ(1, int_array->null_count);
EXPECT_EQ(0, int_array->offset);
EXPECT_EQ(2, int_array->n_buffers);
EXPECT_EQ(0, int_array->n_children);
ASSERT_NE(nullptr, int_array->buffers);
ASSERT_NE(nullptr, int_array->buffers[0]);
ASSERT_NE(nullptr, int_array->buffers[1]);

auto const* int_values = static_cast<int32_t const*>(int_array->buffers[1]);
for (cudf::size_type row = 0; row < int_array->length; ++row) {
EXPECT_EQ(int_validity[row], is_valid(int_array->buffers[0], row));
if (int_validity[row]) { EXPECT_EQ(expected_ints[row], int_values[row]); }
}

auto const* string_array = parent->children[1];
ASSERT_NE(nullptr, string_array);
ASSERT_NE(nullptr, string_array->release);
EXPECT_EQ(5, string_array->length);
EXPECT_EQ(1, string_array->null_count);
EXPECT_EQ(0, string_array->offset);
EXPECT_EQ(3, string_array->n_buffers);
EXPECT_EQ(0, string_array->n_children);
ASSERT_NE(nullptr, string_array->buffers);
ASSERT_NE(nullptr, string_array->buffers[0]);
ASSERT_NE(nullptr, string_array->buffers[1]);
ASSERT_NE(nullptr, string_array->buffers[2]);

auto const* string_offsets = static_cast<int32_t const*>(string_array->buffers[1]);
for (cudf::size_type row = 0; row < string_array->length; ++row) {
EXPECT_EQ(string_validity[row], is_valid(string_array->buffers[0], row));
EXPECT_EQ(expected_offsets[row], string_offsets[row]);
}
EXPECT_EQ(expected_offsets.back(), string_offsets[string_array->length]);

auto const string_chars = std::string_view{static_cast<char const*>(string_array->buffers[2]),
static_cast<std::size_t>(expected_offsets.back())};
EXPECT_EQ("fffaaaccc", string_chars);
}

TEST_F(ToArrowHostDeviceTest, Nullable)
{
auto const input = cudf::test::fixed_width_column_wrapper<int32_t>({1, 2, 3, 4}, {1, 1, 1, 1});
Expand Down
Loading
Loading