-
Notifications
You must be signed in to change notification settings - Fork 908
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
Added Arrow Interop Benchmarks #17194
base: branch-24.12
Are you sure you want to change the base?
Changes from 23 commits
974bfd6
62a1794
0568c38
6b3fe24
44825ea
dd437eb
81a2046
314d548
56102d5
0740ae6
0d5062c
7f75562
eda0ff8
a015526
1e36256
1807940
1b136dc
e476ff6
4e405ff
212d914
2a6edcd
dd64271
07a0916
f59f349
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,259 @@ | ||||||||||||||||
/* | ||||||||||||||||
* Copyright (c) 2024, 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. | ||||||||||||||||
*/ | ||||||||||||||||
|
||||||||||||||||
#include <benchmarks/common/generate_input.hpp> | ||||||||||||||||
#include <benchmarks/common/table_utilities.hpp> | ||||||||||||||||
|
||||||||||||||||
#include <cudf/interop.hpp> | ||||||||||||||||
|
||||||||||||||||
#include <thrust/iterator/counting_iterator.h> | ||||||||||||||||
|
||||||||||||||||
#include <nanoarrow/nanoarrow.hpp> | ||||||||||||||||
#include <nanoarrow/nanoarrow_device.h> | ||||||||||||||||
#include <nanoarrow_utils.hpp> | ||||||||||||||||
#include <nvbench/nvbench.cuh> | ||||||||||||||||
|
||||||||||||||||
#include <algorithm> | ||||||||||||||||
#include <iterator> | ||||||||||||||||
#include <vector> | ||||||||||||||||
|
||||||||||||||||
template <cudf::type_id data_type> | ||||||||||||||||
void BM_to_arrow_device(nvbench::state& state, nvbench::type_list<nvbench::enum_type<data_type>>) | ||||||||||||||||
{ | ||||||||||||||||
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows")); | ||||||||||||||||
auto const num_columns = static_cast<cudf::size_type>(state.get_int64("num_columns")); | ||||||||||||||||
auto const num_elements = static_cast<int64_t>(num_rows) * num_columns; | ||||||||||||||||
|
||||||||||||||||
std::vector<cudf::type_id> types; | ||||||||||||||||
|
||||||||||||||||
std::fill_n(std::back_inserter(types), num_columns, data_type); | ||||||||||||||||
|
||||||||||||||||
auto const table = create_random_table(types, row_count{num_rows}); | ||||||||||||||||
int64_t const size_bytes = estimate_size(table->view()); | ||||||||||||||||
|
||||||||||||||||
state.add_element_count(num_elements, "num_elements"); | ||||||||||||||||
state.add_global_memory_reads(size_bytes); | ||||||||||||||||
state.add_global_memory_writes(size_bytes); | ||||||||||||||||
|
||||||||||||||||
state.exec(nvbench::exec_tag::sync, [&](nvbench::launch& launch) { | ||||||||||||||||
cudf::to_arrow_device(table->view(), rmm::cuda_stream_view{launch.get_stream()}); | ||||||||||||||||
}); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
template <cudf::type_id data_type> | ||||||||||||||||
void BM_to_arrow_host(nvbench::state& state, nvbench::type_list<nvbench::enum_type<data_type>>) | ||||||||||||||||
{ | ||||||||||||||||
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows")); | ||||||||||||||||
auto const num_columns = static_cast<cudf::size_type>(state.get_int64("num_columns")); | ||||||||||||||||
auto const num_elements = static_cast<int64_t>(num_rows) * num_columns; | ||||||||||||||||
|
||||||||||||||||
std::vector<cudf::type_id> types; | ||||||||||||||||
|
||||||||||||||||
std::fill_n(std::back_inserter(types), num_columns, data_type); | ||||||||||||||||
|
||||||||||||||||
auto const table = create_random_table(types, row_count{num_rows}); | ||||||||||||||||
int64_t const size_bytes = estimate_size(table->view()); | ||||||||||||||||
|
||||||||||||||||
state.add_element_count(num_elements, "num_elements"); | ||||||||||||||||
state.add_global_memory_reads(size_bytes); | ||||||||||||||||
state.add_global_memory_writes(size_bytes); | ||||||||||||||||
|
||||||||||||||||
state.exec(nvbench::exec_tag::sync, [&](nvbench::launch& launch) { | ||||||||||||||||
cudf::to_arrow_host(table->view(), rmm::cuda_stream_view{launch.get_stream()}); | ||||||||||||||||
}); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
template <cudf::type_id data_type> | ||||||||||||||||
void BM_from_arrow_device(nvbench::state& state, nvbench::type_list<nvbench::enum_type<data_type>>) | ||||||||||||||||
{ | ||||||||||||||||
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows")); | ||||||||||||||||
auto const num_columns = static_cast<cudf::size_type>(state.get_int64("num_columns")); | ||||||||||||||||
auto const num_elements = static_cast<int64_t>(num_rows) * num_columns; | ||||||||||||||||
|
||||||||||||||||
std::vector<cudf::type_id> types; | ||||||||||||||||
|
||||||||||||||||
std::fill_n(std::back_inserter(types), num_columns, data_type); | ||||||||||||||||
|
||||||||||||||||
data_profile profile; | ||||||||||||||||
profile.set_struct_depth(1); | ||||||||||||||||
profile.set_list_depth(1); | ||||||||||||||||
|
||||||||||||||||
auto const table = create_random_table(types, row_count{num_rows}, profile); | ||||||||||||||||
cudf::table_view table_view = table->view(); | ||||||||||||||||
int64_t const size_bytes = estimate_size(table_view); | ||||||||||||||||
|
||||||||||||||||
std::vector<cudf::column_metadata> table_metadata; | ||||||||||||||||
|
||||||||||||||||
std::transform(thrust::make_counting_iterator(0), | ||||||||||||||||
thrust::make_counting_iterator(num_columns), | ||||||||||||||||
std::back_inserter(table_metadata), | ||||||||||||||||
[&](auto const column) { | ||||||||||||||||
cudf::column_metadata column_metadata{""}; | ||||||||||||||||
std::vector<cudf::column_metadata> children_metadata; | ||||||||||||||||
std::fill_n(std::back_inserter(children_metadata), | ||||||||||||||||
table->get_column(column).num_children(), | ||||||||||||||||
cudf::column_metadata{""}); | ||||||||||||||||
column_metadata.children_meta = children_metadata; | ||||||||||||||||
Comment on lines
+105
to
+109
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar suggestion here to use vector constructor.
Suggested change
|
||||||||||||||||
return column_metadata; | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
cudf::unique_schema_t schema = cudf::to_arrow_schema(table_view, table_metadata); | ||||||||||||||||
cudf::unique_device_array_t input = cudf::to_arrow_device(table_view); | ||||||||||||||||
|
||||||||||||||||
state.add_element_count(num_elements, "num_elements"); | ||||||||||||||||
state.add_global_memory_reads(size_bytes); | ||||||||||||||||
state.add_global_memory_writes(size_bytes); | ||||||||||||||||
|
||||||||||||||||
state.exec(nvbench::exec_tag::sync, [&](nvbench::launch& launch) { | ||||||||||||||||
cudf::from_arrow_device_column( | ||||||||||||||||
schema.get(), input.get(), rmm::cuda_stream_view{launch.get_stream()}); | ||||||||||||||||
}); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
template <cudf::type_id data_type> | ||||||||||||||||
void BM_from_arrow_host(nvbench::state& state, nvbench::type_list<nvbench::enum_type<data_type>>) | ||||||||||||||||
{ | ||||||||||||||||
auto const num_rows = static_cast<cudf::size_type>(state.get_int64("num_rows")); | ||||||||||||||||
auto const num_columns = static_cast<cudf::size_type>(state.get_int64("num_columns")); | ||||||||||||||||
auto const num_elements = static_cast<int64_t>(num_rows) * num_columns; | ||||||||||||||||
|
||||||||||||||||
std::vector<cudf::type_id> types; | ||||||||||||||||
|
||||||||||||||||
std::fill_n(std::back_inserter(types), num_columns, data_type); | ||||||||||||||||
|
||||||||||||||||
data_profile profile; | ||||||||||||||||
profile.set_struct_depth(1); | ||||||||||||||||
profile.set_list_depth(1); | ||||||||||||||||
|
||||||||||||||||
auto const table = create_random_table(types, row_count{num_rows}, profile); | ||||||||||||||||
cudf::table_view table_view = table->view(); | ||||||||||||||||
int64_t const size_bytes = estimate_size(table_view); | ||||||||||||||||
|
||||||||||||||||
std::vector<cudf::column_metadata> table_metadata; | ||||||||||||||||
|
||||||||||||||||
std::transform(thrust::make_counting_iterator(0), | ||||||||||||||||
thrust::make_counting_iterator(num_columns), | ||||||||||||||||
std::back_inserter(table_metadata), | ||||||||||||||||
[&](auto const column) { | ||||||||||||||||
cudf::column_metadata column_metadata{""}; | ||||||||||||||||
std::vector<cudf::column_metadata> children_metadata; | ||||||||||||||||
std::fill_n(std::back_inserter(children_metadata), | ||||||||||||||||
table->get_column(column).num_children(), | ||||||||||||||||
cudf::column_metadata{""}); | ||||||||||||||||
column_metadata.children_meta = children_metadata; | ||||||||||||||||
return column_metadata; | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
cudf::unique_schema_t schema = cudf::to_arrow_schema(table_view, table_metadata); | ||||||||||||||||
cudf::unique_device_array_t input = cudf::to_arrow_host(table_view); | ||||||||||||||||
|
||||||||||||||||
state.add_element_count(num_elements, "num_elements"); | ||||||||||||||||
state.add_global_memory_reads(size_bytes); | ||||||||||||||||
state.add_global_memory_writes(size_bytes); | ||||||||||||||||
|
||||||||||||||||
state.exec(nvbench::exec_tag::sync, [&](nvbench::launch& launch) { | ||||||||||||||||
cudf::from_arrow_host_column( | ||||||||||||||||
schema.get(), input.get(), rmm::cuda_stream_view{launch.get_stream()}); | ||||||||||||||||
}); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
using data_types = nvbench::enum_type_list<cudf::type_id::INT8, | ||||||||||||||||
cudf::type_id::INT16, | ||||||||||||||||
cudf::type_id::INT32, | ||||||||||||||||
cudf::type_id::INT64, | ||||||||||||||||
cudf::type_id::UINT8, | ||||||||||||||||
cudf::type_id::UINT16, | ||||||||||||||||
cudf::type_id::UINT32, | ||||||||||||||||
cudf::type_id::UINT64, | ||||||||||||||||
cudf::type_id::FLOAT32, | ||||||||||||||||
cudf::type_id::FLOAT64, | ||||||||||||||||
cudf::type_id::BOOL8, | ||||||||||||||||
cudf::type_id::TIMESTAMP_SECONDS, | ||||||||||||||||
cudf::type_id::TIMESTAMP_MILLISECONDS, | ||||||||||||||||
cudf::type_id::TIMESTAMP_MICROSECONDS, | ||||||||||||||||
cudf::type_id::TIMESTAMP_NANOSECONDS, | ||||||||||||||||
cudf::type_id::DURATION_SECONDS, | ||||||||||||||||
cudf::type_id::DURATION_MILLISECONDS, | ||||||||||||||||
cudf::type_id::DURATION_MICROSECONDS, | ||||||||||||||||
cudf::type_id::DURATION_NANOSECONDS, | ||||||||||||||||
// cudf::type_id::DICTIONARY32, | ||||||||||||||||
lamarrr marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
cudf::type_id::STRING, | ||||||||||||||||
cudf::type_id::LIST, | ||||||||||||||||
cudf::type_id::DECIMAL32, | ||||||||||||||||
cudf::type_id::DECIMAL64, | ||||||||||||||||
cudf::type_id::DECIMAL128, | ||||||||||||||||
cudf::type_id::STRUCT>; | ||||||||||||||||
|
||||||||||||||||
static char const* stringify_type(cudf::type_id value) | ||||||||||||||||
{ | ||||||||||||||||
switch (value) { | ||||||||||||||||
case cudf::type_id::INT8: return "INT8"; | ||||||||||||||||
case cudf::type_id::INT16: return "INT16"; | ||||||||||||||||
case cudf::type_id::INT32: return "INT32"; | ||||||||||||||||
case cudf::type_id::INT64: return "INT64"; | ||||||||||||||||
case cudf::type_id::UINT8: return "UINT8"; | ||||||||||||||||
case cudf::type_id::UINT16: return "UINT16"; | ||||||||||||||||
case cudf::type_id::UINT32: return "UINT32"; | ||||||||||||||||
case cudf::type_id::UINT64: return "UINT64"; | ||||||||||||||||
case cudf::type_id::FLOAT32: return "FLOAT32"; | ||||||||||||||||
case cudf::type_id::FLOAT64: return "FLOAT64"; | ||||||||||||||||
case cudf::type_id::BOOL8: return "BOOL8"; | ||||||||||||||||
case cudf::type_id::TIMESTAMP_DAYS: return "TIMESTAMP_DAYS"; | ||||||||||||||||
case cudf::type_id::TIMESTAMP_SECONDS: return "TIMESTAMP_SECONDS"; | ||||||||||||||||
case cudf::type_id::TIMESTAMP_MILLISECONDS: return "TIMESTAMP_MILLISECONDS"; | ||||||||||||||||
case cudf::type_id::TIMESTAMP_MICROSECONDS: return "TIMESTAMP_MICROSECONDS"; | ||||||||||||||||
case cudf::type_id::TIMESTAMP_NANOSECONDS: return "TIMESTAMP_NANOSECONDS"; | ||||||||||||||||
case cudf::type_id::DURATION_DAYS: return "DURATION_DAYS"; | ||||||||||||||||
case cudf::type_id::DURATION_SECONDS: return "DURATION_SECONDS"; | ||||||||||||||||
case cudf::type_id::DURATION_MILLISECONDS: return "DURATION_MILLISECONDS"; | ||||||||||||||||
case cudf::type_id::DURATION_MICROSECONDS: return "DURATION_MICROSECONDS"; | ||||||||||||||||
case cudf::type_id::DURATION_NANOSECONDS: return "DURATION_NANOSECONDS"; | ||||||||||||||||
case cudf::type_id::DICTIONARY32: return "DICTIONARY32"; | ||||||||||||||||
case cudf::type_id::STRING: return "STRING"; | ||||||||||||||||
case cudf::type_id::LIST: return "LIST"; | ||||||||||||||||
case cudf::type_id::DECIMAL32: return "DECIMAL32"; | ||||||||||||||||
case cudf::type_id::DECIMAL64: return "DECIMAL64"; | ||||||||||||||||
case cudf::type_id::DECIMAL128: return "DECIMAL128"; | ||||||||||||||||
case cudf::type_id::STRUCT: return "STRUCT"; | ||||||||||||||||
default: return "unknown"; | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
NVBENCH_DECLARE_ENUM_TYPE_STRINGS(cudf::type_id, stringify_type, stringify_type) | ||||||||||||||||
Comment on lines
+199
to
+234
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be used by other benchmarks too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah. which header would you suggest that be moved to? same header as type_id? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that is a good idea. Many times, I had to implement this function for my debugging. Let's make a follow up PR, moving this into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we have a similar file here: https://github.com/rapidsai/cudf/blob/branch-24.12/cpp/benchmarks/io/nvbench_helpers.hpp Declaring an NVBench-specific utility in a non-cuDF namespace within There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with a new header in the benchmarks/common. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Could you elaborate on this further? How does this feature specifically benefit unit tests? Benchmarks and unit tests are treated as "external" users of libcudf, which is why they are not included within the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I didn't mean it will benefit unit tests, but meant it will benefit developers in debugging/testing. I usually debug cudf APIs by printing out the type id of the input column. For example:
However, most of the time, for fast iteration with small issues, I just printed the type id integer value, and look up the enum, trying to identify the enum type from value. For example:
(Looking at the enum class As such, having such There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see what you mean. It's a different feature request. You are referring to the fact that NVBENCH_DECLARE_ENUM_TYPE_STRINGS(cudf::type_id, cudf::test::print::stringify_type, stringify_type) I’m inclined to leave this refactoring for a separate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Opened #17376 to track this issue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for filing the issue 👍 |
||||||||||||||||
|
||||||||||||||||
NVBENCH_BENCH_TYPES(BM_to_arrow_host, NVBENCH_TYPE_AXES(data_types)) | ||||||||||||||||
.set_type_axes_names({"data_type"}) | ||||||||||||||||
.set_name("to_arrow_host") | ||||||||||||||||
.add_int64_axis("num_rows", {10'000, 100'000, 1'000'000, 10'000'000}) | ||||||||||||||||
.add_int64_axis("num_columns", {1}); | ||||||||||||||||
|
||||||||||||||||
NVBENCH_BENCH_TYPES(BM_to_arrow_device, NVBENCH_TYPE_AXES(data_types)) | ||||||||||||||||
.set_type_axes_names({"data_type"}) | ||||||||||||||||
.set_name("to_arrow_device") | ||||||||||||||||
.add_int64_axis("num_rows", {10'000, 100'000, 1'000'000, 10'000'000}) | ||||||||||||||||
.add_int64_axis("num_columns", {1}); | ||||||||||||||||
|
||||||||||||||||
NVBENCH_BENCH_TYPES(BM_from_arrow_host, NVBENCH_TYPE_AXES(data_types)) | ||||||||||||||||
.set_type_axes_names({"data_type"}) | ||||||||||||||||
.set_name("from_arrow_host") | ||||||||||||||||
.add_int64_axis("num_rows", {10'000, 100'000, 1'000'000, 10'000'000}) | ||||||||||||||||
.add_int64_axis("num_columns", {1}); | ||||||||||||||||
|
||||||||||||||||
NVBENCH_BENCH_TYPES(BM_from_arrow_device, NVBENCH_TYPE_AXES(data_types)) | ||||||||||||||||
.set_type_axes_names({"data_type"}) | ||||||||||||||||
.set_name("from_arrow_device") | ||||||||||||||||
.add_int64_axis("num_rows", {10'000, 100'000, 1'000'000, 10'000'000}) | ||||||||||||||||
.add_int64_axis("num_columns", {1}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: similar suggestion at other places too.
is this better than using
fill_n
with back_inserter?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't trust std::vector's constructors, they easily become ambiguous and do the wrong thing