Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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