diff --git a/cpp/benchmarks/CMakeLists.txt b/cpp/benchmarks/CMakeLists.txt index 99ef9e2976f..d2c22b788cb 100644 --- a/cpp/benchmarks/CMakeLists.txt +++ b/cpp/benchmarks/CMakeLists.txt @@ -35,6 +35,30 @@ target_include_directories( "$" ) +add_library( + tpch_data_generator STATIC + common/tpch_data_generator/tpch_data_generator.cpp common/tpch_data_generator/table_helpers.cpp + common/tpch_data_generator/random_column_generator.cu +) +target_compile_features(tpch_data_generator PUBLIC cxx_std_17 cuda_std_17) + +target_compile_options( + tpch_data_generator PUBLIC "$<$:${CUDF_CXX_FLAGS}>" + "$<$:${CUDF_CUDA_FLAGS}>" +) + +target_link_libraries( + tpch_data_generator + PUBLIC cudf cudftestutil nvtx3::nvtx3-cpp + PRIVATE $ +) + +target_include_directories( + tpch_data_generator + PUBLIC "$" "$" + "$" +) + # ################################################################################################## # * compiler function ----------------------------------------------------------------------------- diff --git a/cpp/benchmarks/common/tpch_data_generator/random_column_generator.cu b/cpp/benchmarks/common/tpch_data_generator/random_column_generator.cu new file mode 100644 index 00000000000..4246bd1a83b --- /dev/null +++ b/cpp/benchmarks/common/tpch_data_generator/random_column_generator.cu @@ -0,0 +1,246 @@ +/* + * 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 "random_column_generator.hpp" + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +namespace cudf::datagen { + +namespace { + +// Functor for generating random strings +struct random_string_generator { + char* chars; + thrust::default_random_engine engine; + thrust::uniform_int_distribution char_dist; + + CUDF_HOST_DEVICE random_string_generator(char* c) : chars(c), char_dist(44, 122) {} + + __device__ void operator()(thrust::tuple str_begin_end) + { + auto begin = thrust::get<0>(str_begin_end); + auto end = thrust::get<1>(str_begin_end); + engine.discard(begin); + for (auto i = begin; i < end; ++i) { + auto ch = char_dist(engine); + if (i == end - 1 && ch >= '\x7F') ch = ' '; // last element ASCII only. + if (ch >= '\x7F') // x7F is at the top edge of ASCII + chars[i++] = '\xC4'; // these characters are assigned two bytes + chars[i] = static_cast(ch + (ch >= '\x7F')); + } + } +}; + +// Functor for generating random numbers +template +struct random_number_generator { + T lower; + T upper; + + CUDF_HOST_DEVICE random_number_generator(T lower, T upper) : lower(lower), upper(upper) {} + + __device__ T operator()(const int64_t idx) const + { + if constexpr (cudf::is_integral()) { + thrust::default_random_engine engine; + thrust::uniform_int_distribution dist(lower, upper); + engine.discard(idx); + return dist(engine); + } else { + thrust::default_random_engine engine; + thrust::uniform_real_distribution dist(lower, upper); + engine.discard(idx); + return dist(engine); + } + } +}; + +} // namespace + +std::unique_ptr generate_random_string_column(cudf::size_type lower, + cudf::size_type upper, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto offsets_begin = cudf::detail::make_counting_transform_iterator( + 0, random_number_generator(lower, upper)); + auto [offsets_column, computed_bytes] = cudf::strings::detail::make_offsets_child_column( + offsets_begin, offsets_begin + num_rows, stream, mr); + rmm::device_uvector chars(computed_bytes, stream); + + auto const offset_itr = + cudf::detail::offsetalator_factory::make_input_iterator(offsets_column->view()); + + // We generate the strings in parallel into the `chars` vector using the + // offsets vector generated above. + thrust::for_each_n(rmm::exec_policy(stream), + thrust::make_zip_iterator(offset_itr, offset_itr + 1), + num_rows, + random_string_generator(chars.data())); + + return cudf::make_strings_column( + num_rows, std::move(offsets_column), chars.release(), 0, rmm::device_buffer{}); +} + +template +std::unique_ptr generate_random_numeric_column(T lower, + T upper, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto col = cudf::make_numeric_column( + cudf::data_type{cudf::type_to_id()}, num_rows, cudf::mask_state::UNALLOCATED, stream, mr); + cudf::size_type begin = 0; + cudf::size_type end = num_rows; + thrust::transform(rmm::exec_policy(stream), + thrust::make_counting_iterator(begin), + thrust::make_counting_iterator(end), + col->mutable_view().begin(), + random_number_generator(lower, upper)); + return col; +} + +template std::unique_ptr generate_random_numeric_column( + int8_t lower, + int8_t upper, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr); + +template std::unique_ptr generate_random_numeric_column( + int16_t lower, + int16_t upper, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr); + +template std::unique_ptr generate_random_numeric_column( + cudf::size_type lower, + cudf::size_type upper, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr); + +template std::unique_ptr generate_random_numeric_column( + double lower, + double upper, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr); + +std::unique_ptr generate_primary_key_column(cudf::scalar const& start, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + return cudf::sequence(num_rows, start, stream, mr); +} + +std::unique_ptr generate_repeat_string_column(std::string const& value, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto const scalar = cudf::string_scalar(value); + return cudf::make_column_from_scalar(scalar, num_rows, stream, mr); +} + +std::unique_ptr generate_random_string_column_from_set( + cudf::host_span set, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Build a gather map of random strings to choose from + // The size of the string sets always fits within 16-bit integers + auto const indices = + generate_primary_key_column(cudf::numeric_scalar(0), set.size(), stream, mr); + auto const keys = cudf::test::strings_column_wrapper(set.begin(), set.end()).release(); + auto const gather_map = cudf::table_view({indices->view(), keys->view()}); + + // Build a column of random keys to gather from the set + auto const gather_keys = + generate_random_numeric_column(0, set.size() - 1, num_rows, stream, mr); + + // Perform the gather operation + auto const gathered_table = cudf::gather( + gather_map, gather_keys->view(), cudf::out_of_bounds_policy::DONT_CHECK, stream, mr); + auto gathered_table_columns = gathered_table->release(); + return std::move(gathered_table_columns[1]); +} + +template +std::unique_ptr generate_repeat_sequence_column(T seq_length, + bool zero_indexed, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto pkey = + generate_primary_key_column(cudf::numeric_scalar(0), num_rows, stream, mr); + auto repeat_seq_zero_indexed = cudf::binary_operation(pkey->view(), + cudf::numeric_scalar(seq_length), + cudf::binary_operator::MOD, + cudf::data_type{cudf::type_to_id()}, + stream, + mr); + if (zero_indexed) { return repeat_seq_zero_indexed; } + return cudf::binary_operation(repeat_seq_zero_indexed->view(), + cudf::numeric_scalar(1), + cudf::binary_operator::ADD, + cudf::data_type{cudf::type_to_id()}, + stream, + mr); +} + +template std::unique_ptr generate_repeat_sequence_column( + int8_t seq_length, + bool zero_indexed, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr); + +template std::unique_ptr generate_repeat_sequence_column( + cudf::size_type seq_length, + bool zero_indexed, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr); + +} // namespace cudf::datagen diff --git a/cpp/benchmarks/common/tpch_data_generator/random_column_generator.hpp b/cpp/benchmarks/common/tpch_data_generator/random_column_generator.hpp new file mode 100644 index 00000000000..3e254f49805 --- /dev/null +++ b/cpp/benchmarks/common/tpch_data_generator/random_column_generator.hpp @@ -0,0 +1,150 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include + +namespace cudf::datagen { + +/** + * @brief Generate a column of random strings + * + * @param lower The lower bound of the length of the strings + * @param upper The upper bound of the length of the strings + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_random_string_column( + cudf::size_type lower, + cudf::size_type upper, + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate a column of random numbers + * + * Example: + * + * lower = 10 + * upper = 15 + * num_rows = 10 + * result = [10, 11, 14, 14, 13, 12, 11, 11, 12, 14] + + * + * @param lower The lower bound of the random numbers + * @param upper The upper bound of the random numbers + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +template +std::unique_ptr generate_random_numeric_column( + T lower, + T upper, + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate a primary key column + * + * Example: + * + * start = 1 + * num_rows = 10 + * result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * + * @param start The starting value of the primary key + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_primary_key_column( + cudf::scalar const& start, + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate a column where all the rows have the same string value + * + * Example: + * + * value = "abc" + * num_rows = 5 + * result = ["abc", "abc", "abc", "abc", "abc"] + * + * @param value The string value to fill the column with + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_repeat_string_column( + std::string const& value, + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate a column by randomly choosing from set of strings + * + * Example: + * + * set = {"s1", "s2", "s3"} + * num_rows = 10 + * result = ["s1", "s2", "s2", "s1", "s3", "s3", "s3", "s2", "s1", "s1"] + * + * @param set The set of strings to choose from + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_random_string_column_from_set( + cudf::host_span set, + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate a column consisting of a repeating sequence of integers + * + * Example: + * + * seq_length = 3 + * zero_indexed = false + * num_rows = 10 + * result = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1] + * + * @param seq_length The length of the repeating sequence + * @param zero_indexed Whether the sequence is zero or one indexed + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +template +std::unique_ptr generate_repeat_sequence_column( + T seq_length, + bool zero_indexed, + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +} // namespace cudf::datagen diff --git a/cpp/benchmarks/common/tpch_data_generator/table_helpers.cpp b/cpp/benchmarks/common/tpch_data_generator/table_helpers.cpp new file mode 100644 index 00000000000..36bf9c49cea --- /dev/null +++ b/cpp/benchmarks/common/tpch_data_generator/table_helpers.cpp @@ -0,0 +1,386 @@ +/* + * 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 "table_helpers.hpp" + +#include "random_column_generator.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace cudf::datagen { + +/** + * @brief Add a column of days to a column of timestamp_days + * + * @param timestamp_days The column of timestamp_days + * @param days The column of days to add + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr add_calendrical_days(cudf::column_view const& timestamp_days, + cudf::column_view const& days, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto const days_duration_type = cudf::cast(days, cudf::data_type{cudf::type_id::DURATION_DAYS}); + auto const data_type = cudf::data_type{cudf::type_id::TIMESTAMP_DAYS}; + return cudf::binary_operation( + timestamp_days, days_duration_type->view(), cudf::binary_operator::ADD, data_type, stream, mr); +} + +/** + * @brief Perform a left join operation between two tables + * + * @param left_input The left table + * @param right_input The right table + * @param left_on The indices of the columns to join on in the left table + * @param right_on The indices of the columns to join on in the right table + * @param compare_nulls The null equality comparison + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned table's device memory + */ +std::unique_ptr perform_left_join(cudf::table_view const& left_input, + cudf::table_view const& right_input, + std::vector const& left_on, + std::vector const& right_on, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + constexpr auto oob_policy = cudf::out_of_bounds_policy::NULLIFY; + auto const left_selected = left_input.select(left_on); + auto const right_selected = right_input.select(right_on); + auto const [left_join_indices, right_join_indices] = + cudf::left_join(left_selected, right_selected, cudf::null_equality::EQUAL, mr); + + auto const left_indices_span = cudf::device_span{*left_join_indices}; + auto const right_indices_span = cudf::device_span{*right_join_indices}; + + auto const left_indices_col = cudf::column_view{left_indices_span}; + auto const right_indices_col = cudf::column_view{right_indices_span}; + + auto const left_result = cudf::gather(left_input, left_indices_col, oob_policy, stream, mr); + auto const right_result = cudf::gather(right_input, right_indices_col, oob_policy, stream, mr); + + auto joined_cols = left_result->release(); + auto right_cols = right_result->release(); + joined_cols.insert(joined_cols.end(), + std::make_move_iterator(right_cols.begin()), + std::make_move_iterator(right_cols.end())); + return std::make_unique(std::move(joined_cols)); +} + +/** + * @brief Generate the `p_retailprice` column of the `part` table + * + * @param p_partkey The `p_partkey` column of the `part` table + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr calculate_p_retailprice( + cudf::column_view const& p_partkey, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Expression: (90000 + ((p_partkey/10) modulo 20001) + 100 * (p_partkey modulo 1000)) / 100 + auto table = cudf::table_view({p_partkey}); + auto p_partkey_col_ref = cudf::ast::column_reference(0); + + auto scalar_10 = cudf::numeric_scalar(10); + auto scalar_100 = cudf::numeric_scalar(100); + auto scalar_1000 = cudf::numeric_scalar(1000); + auto scalar_20001 = cudf::numeric_scalar(20001); + auto scalar_90000 = cudf::numeric_scalar(90000); + + auto literal_10 = cudf::ast::literal(scalar_10); + auto literal_100 = cudf::ast::literal(scalar_100); + auto literal_1000 = cudf::ast::literal(scalar_1000); + auto literal_20001 = cudf::ast::literal(scalar_20001); + auto literal_90000 = cudf::ast::literal(scalar_90000); + + auto expr_a = cudf::ast::operation(cudf::ast::ast_operator::DIV, p_partkey_col_ref, literal_10); + auto expr_b = cudf::ast::operation(cudf::ast::ast_operator::MOD, expr_a, literal_20001); + auto expr_c = cudf::ast::operation(cudf::ast::ast_operator::MOD, p_partkey_col_ref, literal_1000); + auto expr_d = cudf::ast::operation(cudf::ast::ast_operator::MUL, expr_c, literal_100); + auto expr_e = cudf::ast::operation(cudf::ast::ast_operator::ADD, expr_b, expr_d); + auto expr_f = cudf::ast::operation(cudf::ast::ast_operator::ADD, expr_e, literal_90000); + auto final_expr = cudf::ast::operation(cudf::ast::ast_operator::TRUE_DIV, expr_f, literal_100); + + // Execute the AST expression + return cudf::compute_column(table, final_expr, stream, mr); +} + +/** + * @brief Generate the `l_suppkey` column of the `lineitem` table + * + * @param l_partkey The `l_partkey` column of the `lineitem` table + * @param scale_factor The scale factor to use + * @param num_rows The number of rows in the `lineitem` table + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr calculate_l_suppkey(cudf::column_view const& l_partkey, + cudf::size_type scale_factor, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Expression: (l_partkey + (i * (s/4 + (int)(l_partkey - 1)/s))) % s + 1 + + // Generate the `s` col + auto s_empty = cudf::make_numeric_column( + cudf::data_type{cudf::type_id::INT32}, num_rows, cudf::mask_state::UNALLOCATED, stream); + + auto s = cudf::fill(s_empty->view(), + 0, + num_rows, + cudf::numeric_scalar(scale_factor * 10'000), + stream, + mr); + + // Generate the `i` col + auto i = generate_repeat_sequence_column(4, true, num_rows, stream, mr); + + // Create a table view out of `l_partkey`, `s`, and `i` + auto table = cudf::table_view({l_partkey, s->view(), i->view()}); + + // Create the AST expression + auto scalar_1 = cudf::numeric_scalar(1); + auto scalar_4 = cudf::numeric_scalar(4); + auto literal_1 = cudf::ast::literal(scalar_1); + auto literal_4 = cudf::ast::literal(scalar_4); + + auto l_partkey_col_ref = cudf::ast::column_reference(0); + auto s_col_ref = cudf::ast::column_reference(1); + auto i_col_ref = cudf::ast::column_reference(2); + + // (int)(l_partkey - 1)/s + auto expr_a = cudf::ast::operation(cudf::ast::ast_operator::SUB, l_partkey_col_ref, literal_1); + auto expr_b = cudf::ast::operation(cudf::ast::ast_operator::DIV, expr_a, s_col_ref); + + // s/4 + auto expr_c = cudf::ast::operation(cudf::ast::ast_operator::DIV, s_col_ref, literal_4); + + // (s/4 + (int)(l_partkey - 1)/s) + auto expr_d = cudf::ast::operation(cudf::ast::ast_operator::ADD, expr_c, expr_b); + + // (i * (s/4 + (int)(l_partkey - 1)/s)) + auto expr_e = cudf::ast::operation(cudf::ast::ast_operator::MUL, i_col_ref, expr_d); + + // (l_partkey + (i * (s/4 + (int)(l_partkey - 1)/s))) + auto expr_f = cudf::ast::operation(cudf::ast::ast_operator::ADD, l_partkey_col_ref, expr_e); + + // (l_partkey + (i * (s/4 + (int)(l_partkey - 1)/s))) % s + auto expr_g = cudf::ast::operation(cudf::ast::ast_operator::MOD, expr_f, s_col_ref); + + // (l_partkey + (i * (s/4 + (int)(l_partkey - 1)/s))) % s + 1 + auto final_expr = cudf::ast::operation(cudf::ast::ast_operator::ADD, expr_g, literal_1); + + // Execute the AST expression + return cudf::compute_column(table, final_expr, stream, mr); +} + +/** + * @brief Generate the `ps_suppkey` column of the `partsupp` table + * + * @param ps_partkey The `ps_partkey` column of the `partsupp` table + * @param scale_factor The scale factor to use + * @param num_rows The number of rows in the `partsupp` table + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr calculate_ps_suppkey( + cudf::column_view const& ps_partkey, + cudf::size_type scale_factor, + cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Expression: ps_suppkey = (ps_partkey + (i * (s/4 + (int)(ps_partkey - 1)/s))) % s + 1 + + // Generate the `s` col + auto s_empty = cudf::make_numeric_column( + cudf::data_type{cudf::type_id::INT32}, num_rows, cudf::mask_state::UNALLOCATED, stream); + + auto s = cudf::fill(s_empty->view(), + 0, + num_rows, + cudf::numeric_scalar(scale_factor * 10'000), + stream, + mr); + + // Generate the `i` col + auto i = generate_repeat_sequence_column(4, true, num_rows, stream, mr); + + // Create a table view out of `p_partkey`, `s`, and `i` + auto table = cudf::table_view({ps_partkey, s->view(), i->view()}); + + // Create the AST expression + auto scalar_1 = cudf::numeric_scalar(1); + auto scalar_4 = cudf::numeric_scalar(4); + auto literal_1 = cudf::ast::literal(scalar_1); + auto literal_4 = cudf::ast::literal(scalar_4); + + auto ps_partkey_col_ref = cudf::ast::column_reference(0); + auto s_col_ref = cudf::ast::column_reference(1); + auto i_col_ref = cudf::ast::column_reference(2); + + // (int)(ps_partkey - 1)/s + auto expr_a = cudf::ast::operation(cudf::ast::ast_operator::SUB, ps_partkey_col_ref, literal_1); + auto expr_b = cudf::ast::operation(cudf::ast::ast_operator::DIV, expr_a, s_col_ref); + + // s/4 + auto expr_c = cudf::ast::operation(cudf::ast::ast_operator::DIV, s_col_ref, literal_4); + + // (s/4 + (int)(ps_partkey - 1)/s) + auto expr_d = cudf::ast::operation(cudf::ast::ast_operator::ADD, expr_c, expr_b); + + // (i * (s/4 + (int)(ps_partkey - 1)/s)) + auto expr_e = cudf::ast::operation(cudf::ast::ast_operator::MUL, i_col_ref, expr_d); + + // (ps_partkey + (i * (s/4 + (int)(ps_partkey - 1)/s))) + auto expr_f = cudf::ast::operation(cudf::ast::ast_operator::ADD, ps_partkey_col_ref, expr_e); + + // (ps_partkey + (i * (s/4 + (int)(ps_partkey - 1)/s))) % s + auto expr_g = cudf::ast::operation(cudf::ast::ast_operator::MOD, expr_f, s_col_ref); + + // (ps_partkey + (i * (s/4 + (int)(ps_partkey - 1)/s))) % s + 1 + auto final_expr = cudf::ast::operation(cudf::ast::ast_operator::ADD, expr_g, literal_1); + + // Execute the AST expression + return cudf::compute_column(table, final_expr, stream, mr); +} + +/** + * @brief Calculate the cardinality of the `lineitem` table + * + * @param o_rep_freqs The frequency of each `o_orderkey` value in the `lineitem` table + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] cudf::size_type calculate_l_cardinality(cudf::column_view const& o_rep_freqs, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto const sum_agg = cudf::make_sum_aggregation(); + auto const l_num_rows_scalar = + cudf::reduce(o_rep_freqs, *sum_agg, cudf::data_type{cudf::type_id::INT32}, stream, mr); + return reinterpret_cast*>(l_num_rows_scalar.get()) + ->value(stream); +} + +/** + * @brief Calculate the charge column for the `lineitem` table + * + * @param extendedprice The `l_extendedprice` column + * @param tax The `l_tax` column + * @param discount The `l_discount` column + * @param stream The CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr calculate_charge(cudf::column_view const& extendedprice, + cudf::column_view const& tax, + cudf::column_view const& discount, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto const one = cudf::numeric_scalar(1); + auto const one_minus_discount = cudf::binary_operation( + one, discount, cudf::binary_operator::SUB, cudf::data_type{cudf::type_id::FLOAT64}, stream, mr); + auto disc_price = cudf::binary_operation(extendedprice, + one_minus_discount->view(), + cudf::binary_operator::MUL, + cudf::data_type{cudf::type_id::FLOAT64}, + stream, + mr); + auto const one_plus_tax = + cudf::binary_operation(one, tax, cudf::binary_operator::ADD, tax.type(), stream, mr); + return cudf::binary_operation(disc_price->view(), + one_plus_tax->view(), + cudf::binary_operator::MUL, + cudf::data_type{cudf::type_id::FLOAT64}, + stream, + mr); +} + +/** + * @brief Generate a column of random addresses according to TPC-H specification clause 4.2.2.7 + * + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr generate_address_column( + cudf::size_type num_rows, rmm::cuda_stream_view stream, rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + return generate_random_string_column(10, 40, num_rows, stream, mr); +} + +/** + * @brief Generate a phone number column according to TPC-H specification clause 4.2.2.9 + * + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr generate_phone_column(cudf::size_type num_rows, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto const part_a = cudf::strings::from_integers( + generate_random_numeric_column(10, 34, num_rows, stream, mr)->view()); + auto const part_b = cudf::strings::from_integers( + generate_random_numeric_column(100, 999, num_rows, stream, mr)->view()); + auto const part_c = cudf::strings::from_integers( + generate_random_numeric_column(100, 999, num_rows, stream, mr)->view()); + auto const part_d = cudf::strings::from_integers( + generate_random_numeric_column(1000, 9999, num_rows, stream, mr)->view()); + auto const phone_parts_table = + cudf::table_view({part_a->view(), part_b->view(), part_c->view(), part_d->view()}); + return cudf::strings::concatenate(phone_parts_table, + cudf::string_scalar("-"), + cudf::string_scalar("", false), + cudf::strings::separator_on_nulls::NO, + stream, + mr); +} + +} // namespace cudf::datagen diff --git a/cpp/benchmarks/common/tpch_data_generator/table_helpers.hpp b/cpp/benchmarks/common/tpch_data_generator/table_helpers.hpp new file mode 100644 index 00000000000..11091689469 --- /dev/null +++ b/cpp/benchmarks/common/tpch_data_generator/table_helpers.hpp @@ -0,0 +1,155 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace cudf::datagen { + +/** + * @brief Add a column of days to a column of timestamp_days + * + * @param timestamp_days The column of timestamp_days + * @param days The column of days to add + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr add_calendrical_days( + cudf::column_view const& timestamp_days, + cudf::column_view const& days, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Perform a left join operation between two tables + * + * @param left_input The left table + * @param right_input The right table + * @param left_on The indices of the columns to join on in the left table + * @param right_on The indices of the columns to join on in the right table + * @param compare_nulls The null equality comparison + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned table's device memory + */ +std::unique_ptr perform_left_join( + cudf::table_view const& left_input, + cudf::table_view const& right_input, + std::vector const& left_on, + std::vector const& right_on, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate the `p_retailprice` column of the `part` table + * + * @param p_partkey The `p_partkey` column of the `part` table + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr calculate_p_retailprice( + cudf::column_view const& p_partkey, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate the `l_suppkey` column of the `lineitem` table + * + * @param l_partkey The `l_partkey` column of the `lineitem` table + * @param scale_factor The scale factor to use + * @param num_rows The number of rows in the `lineitem` table + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr calculate_l_suppkey( + cudf::column_view const& l_partkey, + cudf::size_type scale_factor, + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate the `ps_suppkey` column of the `partsupp` table + * + * @param ps_partkey The `ps_partkey` column of the `partsupp` table + * @param scale_factor The scale factor to use + * @param num_rows The number of rows in the `partsupp` table + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr calculate_ps_suppkey( + cudf::column_view const& ps_partkey, + cudf::size_type scale_factor, + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); +/** + * @brief Calculate the cardinality of the `lineitem` table + * + * @param o_rep_freqs The frequency of each `o_orderkey` value in the `lineitem` table + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] cudf::size_type calculate_l_cardinality( + cudf::column_view const& o_rep_freqs, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); +/** + * @brief Calculate the charge column for the `lineitem` table + * + * @param extendedprice The `l_extendedprice` column + * @param tax The `l_tax` column + * @param discount The `l_discount` column + * @param stream The CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr calculate_charge( + cudf::column_view const& extendedprice, + cudf::column_view const& tax, + cudf::column_view const& discount, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate a column of random addresses according to TPC-H specification clause 4.2.2.7 + * + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr generate_address_column( + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate a phone number column according to TPC-H specification clause 4.2.2.9 + * + * @param num_rows The number of rows in the column + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +[[nodiscard]] std::unique_ptr generate_phone_column( + cudf::size_type num_rows, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +} // namespace cudf::datagen diff --git a/cpp/benchmarks/common/tpch_data_generator/tpch_data_generator.cpp b/cpp/benchmarks/common/tpch_data_generator/tpch_data_generator.cpp new file mode 100644 index 00000000000..9001c50c5a5 --- /dev/null +++ b/cpp/benchmarks/common/tpch_data_generator/tpch_data_generator.cpp @@ -0,0 +1,987 @@ +/* + * 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 "tpch_data_generator.hpp" + +#include "random_column_generator.hpp" +#include "table_helpers.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace cudf::datagen { + +namespace { +constexpr std::array nations{ + "ALGERIA", "ARGENTINA", "BRAZIL", "CANADA", "EGYPT", "ETHIOPIA", "FRANCE", + "GERMANY", "INDIA", "INDONESIA", "IRAN", "IRAQ", "JAPAN", "JORDAN", + "KENYA", "MOROCCO", "MOZAMBIQUE", "PERU", "CHINA", "ROMANIA", "SAUDI ARABIA", + "VIETNAM", "RUSSIA", "UNITED KINGDOM", "UNITED STATES"}; + +constexpr std::array years{"1992", "1993", "1994", "1995", "1996", "1997", "1998"}; +constexpr std::array months{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"}; +constexpr std::array days{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", + "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", + "23", "24", "25", "26", "27", "28", "29", "30", "31"}; + +constexpr std::array vocab_p_name{ + "almond", "antique", "aquamarine", "azure", "beige", "bisque", "black", + "blanched", "blue", "blush", "brown", "burlywood", "burnished", "chartreuse", + "chiffon", "chocolate", "coral", "cornflower", "cornsilk", "cream", "cyan", + "dark", "deep", "dim", "dodger", "drab", "firebrick", "floral", + "forest", "frosted", "gainsboro", "ghost", "goldenrod", "green", "grey", + "honeydew", "hot", "indian", "ivory", "khaki", "lace", "lavender", + "lawn", "lemon", "light", "lime", "linen", "magenta", "maroon", + "medium", "metallic", "midnight", "mint", "misty", "moccasin", "navajo", + "navy", "olive", "orange", "orchid", "pale", "papaya", "peach", + "peru", "pink", "plum", "powder", "puff", "purple", "red", + "rose", "rosy", "royal", "saddle", "salmon", "sandy", "seashell", + "sienna", "sky", "slate", "smoke", "snow", "spring", "steel", + "tan", "thistle", "tomato", "turquoise", "violet", "wheat", "white", + "yellow"}; + +constexpr std::array vocab_modes{"REG AIR", "AIR", "RAIL", "SHIP", "TRUCK", "MAIL", "FOB"}; + +constexpr std::array vocab_instructions{ + "DELIVER IN PERSON", "COLLECT COD", "NONE", "TAKE BACK RETURN"}; + +constexpr std::array vocab_priorities{"1-URGENT", "2-HIGH", "3-MEDIUM", "4-NOT SPECIFIED", "5-LOW"}; + +constexpr std::array vocab_segments{ + "AUTOMOBILE", "BUILDING", "FURNITURE", "MACHINERY", "HOUSEHOLD"}; + +constexpr std::array vocab_types{ + "STANDARD ANODIZED TIN", "STANDARD ANODIZED NICKEL", "STANDARD ANODIZED BRASS", + "STANDARD ANODIZED STEEL", "STANDARD ANODIZED COPPER", "STANDARD BURNISHED TIN", + "STANDARD BURNISHED NICKEL", "STANDARD BURNISHED BRASS", "STANDARD BURNISHED STEEL", + "STANDARD BURNISHED COPPER", "STANDARD PLATED TIN", "STANDARD PLATED NICKEL", + "STANDARD PLATED BRASS", "STANDARD PLATED STEEL", "STANDARD PLATED COPPER", + "STANDARD POLISHED TIN", "STANDARD POLISHED NICKEL", "STANDARD POLISHED BRASS", + "STANDARD POLISHED STEEL", "STANDARD POLISHED COPPER", "STANDARD BRUSHED TIN", + "STANDARD BRUSHED NICKEL", "STANDARD BRUSHED BRASS", "STANDARD BRUSHED STEEL", + "STANDARD BRUSHED COPPER", "SMALL ANODIZED TIN", "SMALL ANODIZED NICKEL", + "SMALL ANODIZED BRASS", "SMALL ANODIZED STEEL", "SMALL ANODIZED COPPER", + "SMALL BURNISHED TIN", "SMALL BURNISHED NICKEL", "SMALL BURNISHED BRASS", + "SMALL BURNISHED STEEL", "SMALL BURNISHED COPPER", "SMALL PLATED TIN", + "SMALL PLATED NICKEL", "SMALL PLATED BRASS", "SMALL PLATED STEEL", + "SMALL PLATED COPPER", "SMALL POLISHED TIN", "SMALL POLISHED NICKEL", + "SMALL POLISHED BRASS", "SMALL POLISHED STEEL", "SMALL POLISHED COPPER", + "SMALL BRUSHED TIN", "SMALL BRUSHED NICKEL", "SMALL BRUSHED BRASS", + "SMALL BRUSHED STEEL", "SMALL BRUSHED COPPER", "MEDIUM ANODIZED TIN", + "MEDIUM ANODIZED NICKEL", "MEDIUM ANODIZED BRASS", "MEDIUM ANODIZED STEEL", + "MEDIUM ANODIZED COPPER", "MEDIUM BURNISHED TIN", "MEDIUM BURNISHED NICKEL", + "MEDIUM BURNISHED BRASS", "MEDIUM BURNISHED STEEL", "MEDIUM BURNISHED COPPER", + "MEDIUM PLATED TIN", "MEDIUM PLATED NICKEL", "MEDIUM PLATED BRASS", + "MEDIUM PLATED STEEL", "MEDIUM PLATED COPPER", "MEDIUM POLISHED TIN", + "MEDIUM POLISHED NICKEL", "MEDIUM POLISHED BRASS", "MEDIUM POLISHED STEEL", + "MEDIUM POLISHED COPPER", "MEDIUM BRUSHED TIN", "MEDIUM BRUSHED NICKEL", + "MEDIUM BRUSHED BRASS", "MEDIUM BRUSHED STEEL", "MEDIUM BRUSHED COPPER", + "LARGE ANODIZED TIN", "LARGE ANODIZED NICKEL", "LARGE ANODIZED BRASS", + "LARGE ANODIZED STEEL", "LARGE ANODIZED COPPER", "LARGE BURNISHED TIN", + "LARGE BURNISHED NICKEL", "LARGE BURNISHED BRASS", "LARGE BURNISHED STEEL", + "LARGE BURNISHED COPPER", "LARGE PLATED TIN", "LARGE PLATED NICKEL", + "LARGE PLATED BRASS", "LARGE PLATED STEEL", "LARGE PLATED COPPER", + "LARGE POLISHED TIN", "LARGE POLISHED NICKEL", "LARGE POLISHED BRASS", + "LARGE POLISHED STEEL", "LARGE POLISHED COPPER", "LARGE BRUSHED TIN", + "LARGE BRUSHED NICKEL", "LARGE BRUSHED BRASS", "LARGE BRUSHED STEEL", + "LARGE BRUSHED COPPER", "ECONOMY ANODIZED TIN", "ECONOMY ANODIZED NICKEL", + "ECONOMY ANODIZED BRASS", "ECONOMY ANODIZED STEEL", "ECONOMY ANODIZED COPPER", + "ECONOMY BURNISHED TIN", "ECONOMY BURNISHED NICKEL", "ECONOMY BURNISHED BRASS", + "ECONOMY BURNISHED STEEL", "ECONOMY BURNISHED COPPER", "ECONOMY PLATED TIN", + "ECONOMY PLATED NICKEL", "ECONOMY PLATED BRASS", "ECONOMY PLATED STEEL", + "ECONOMY PLATED COPPER", "ECONOMY POLISHED TIN", "ECONOMY POLISHED NICKEL", + "ECONOMY POLISHED BRASS", "ECONOMY POLISHED STEEL", "ECONOMY POLISHED COPPER", + "ECONOMY BRUSHED TIN", "ECONOMY BRUSHED NICKEL", "ECONOMY BRUSHED BRASS", + "ECONOMY BRUSHED STEEL", "ECONOMY BRUSHED COPPER", "PROMO ANODIZED TIN", + "PROMO ANODIZED NICKEL", "PROMO ANODIZED BRASS", "PROMO ANODIZED STEEL", + "PROMO ANODIZED COPPER", "PROMO BURNISHED TIN", "PROMO BURNISHED NICKEL", + "PROMO BURNISHED BRASS", "PROMO BURNISHED STEEL", "PROMO BURNISHED COPPER", + "PROMO PLATED TIN", "PROMO PLATED NICKEL", "PROMO PLATED BRASS", + "PROMO PLATED STEEL", "PROMO PLATED COPPER", "PROMO POLISHED TIN", + "PROMO POLISHED NICKEL", "PROMO POLISHED BRASS", "PROMO POLISHED STEEL", + "PROMO POLISHED COPPER", "PROMO BRUSHED TIN", "PROMO BRUSHED NICKEL", + "PROMO BRUSHED BRASS", "PROMO BRUSHED STEEL", "PROMO BRUSHED COPPER"}; + +constexpr std::array vocab_containers{ + "SM CASE", "SM BOX", "SM BAG", "SM JAR", "SM PKG", "SM PACK", "SM CAN", + "SM DRUM", "LG CASE", "LG BOX", "LG BAG", "LG JAR", "LG PKG", "LG PACK", + "LG CAN", "LG DRUM", "MED CASE", "MED BOX", "MED BAG", "MED JAR", "MED PKG", + "MED PACK", "MED CAN", "MED DRUM", "JUMBO CASE", "JUMBO BOX", "JUMBO BAG", "JUMBO JAR", + "JUMBO PKG", "JUMBO PACK", "JUMBO CAN", "JUMBO DRUM", "WRAP CASE", "WRAP BOX", "WRAP BAG", + "WRAP JAR", "WRAP PKG", "WRAP PACK", "WRAP CAN", "WRAP DRUM"}; + +} // namespace + +/** + * @brief Generate a table out of the independent columns of the `orders` table + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_orders_independent(double scale_factor, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + cudf::size_type const o_num_rows = scale_factor * 1'500'000; + + // Generate the `o_orderkey` column + auto o_orderkey = [&]() { + auto const o_orderkey_candidates = generate_primary_key_column( + cudf::numeric_scalar(1), 4 * o_num_rows, stream, mr); + auto const o_orderkey_unsorted = cudf::sample(cudf::table_view({o_orderkey_candidates->view()}), + o_num_rows, + cudf::sample_with_replacement::FALSE, + 0, + stream, + mr); + auto const sort_result = + cudf::sort_by_key(o_orderkey_unsorted->view(), + cudf::table_view({o_orderkey_unsorted->view().column(0)}), + {}, + {}, + stream, + mr); + return std::move(sort_result->release()[0]); + }(); + + // Generate the `o_custkey` column + auto o_custkey = [&]() { + auto const col = generate_random_numeric_column( + 1, scale_factor * 49'000, o_num_rows, stream, mr); + auto const col_mul_3 = cudf::binary_operation(col->view(), + cudf::numeric_scalar(3), + cudf::binary_operator::MUL, + cudf::data_type{cudf::type_id::INT32}, + stream, + mr); + return cudf::binary_operation(col_mul_3->view(), + cudf::numeric_scalar(1), + cudf::binary_operator::ADD, + cudf::data_type{cudf::type_id::INT32}, + stream, + mr); + }(); + + // Generate the `o_orderdate` column + auto o_orderdate_ts = [&]() { + auto const o_orderdate_year = generate_random_string_column_from_set( + cudf::host_span(years.data(), years.size()), o_num_rows, stream, mr); + auto const o_orderdate_month = generate_random_string_column_from_set( + cudf::host_span(months.data(), months.size()), o_num_rows, stream, mr); + auto const o_orderdate_day = generate_random_string_column_from_set( + cudf::host_span(days.data(), days.size()), o_num_rows, stream, mr); + auto const o_orderdate_str = cudf::strings::concatenate( + cudf::table_view( + {o_orderdate_year->view(), o_orderdate_month->view(), o_orderdate_day->view()}), + cudf::string_scalar("-"), + cudf::string_scalar("", false), + cudf::strings::separator_on_nulls::NO, + stream, + mr); + + return cudf::strings::to_timestamps(o_orderdate_str->view(), + cudf::data_type{cudf::type_id::TIMESTAMP_DAYS}, + std::string("%Y-%m-%d"), + stream, + mr); + }(); + + // Generate the `o_orderpriority` column + auto o_orderpriority = generate_random_string_column_from_set( + cudf::host_span(vocab_priorities.data(), vocab_priorities.size()), + o_num_rows, + stream, + mr); + + // Generate the `o_clerk` column + auto o_clerk = [&]() { + auto const clerk_repeat = generate_repeat_string_column("Clerk#", o_num_rows, stream, mr); + auto const random_c = generate_random_numeric_column( + 1, scale_factor * 1'000, o_num_rows, stream, mr); + auto const random_c_str = cudf::strings::from_integers(random_c->view(), stream, mr); + auto const random_c_str_padded = cudf::strings::zfill(random_c_str->view(), 9, stream, mr); + return cudf::strings::concatenate( + cudf::table_view({clerk_repeat->view(), random_c_str_padded->view()}), + cudf::string_scalar(""), + cudf::string_scalar("", false), + cudf::strings::separator_on_nulls::NO, + stream, + mr); + }(); + + // Generate the `o_shippriority` column + auto o_shippriority = [&]() { + auto const empty = cudf::make_numeric_column( + cudf::data_type{cudf::type_id::INT8}, o_num_rows, cudf::mask_state::UNALLOCATED, stream); + return cudf::fill(empty->view(), 0, o_num_rows, cudf::numeric_scalar(0), stream, mr); + }(); + + // Generate the `o_comment` column + // NOTE: This column is not compliant with clause 4.2.2.10 of the TPC-H specification + auto o_comment = generate_random_string_column(19, 78, o_num_rows, stream, mr); + + // Generate the `orders_independent` table + std::vector> columns; + columns.push_back(std::move(o_orderkey)); + columns.push_back(std::move(o_custkey)); + columns.push_back(std::move(o_orderdate_ts)); + columns.push_back(std::move(o_orderpriority)); + columns.push_back(std::move(o_clerk)); + columns.push_back(std::move(o_shippriority)); + columns.push_back(std::move(o_comment)); + return std::make_unique(std::move(columns)); +} + +/** + * @brief Generate the `lineitem` table partially + * + * @param orders_independent Table with the independent columns of the `orders` table + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_lineitem_partial(cudf::table_view const& orders_independent, + double scale_factor, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto const o_num_rows = orders_independent.num_rows(); + // Generate the `lineitem` table. For each row in the `orders` table, + // we have a random number (between 1 and 7) of rows in the `lineitem` table + + // For each `o_orderkey`, generate a random number (between 1 and 7), + // which will be the number of rows in the `lineitem` table that will + // have the same `l_orderkey` + auto const o_rep_freqs = generate_random_numeric_column(1, 7, o_num_rows, stream, mr); + + // Sum up the `o_rep_freqs` to get the number of rows in the + // `lineitem` table. This is required to generate the independent columns + // in the `lineitem` table + auto const l_num_rows = calculate_l_cardinality(o_rep_freqs->view(), stream, mr); + + // We create a table out of `o_orderkey` and `o_orderdate_ts` by repeating + // the rows of `orders` according to the frequencies in `o_rep_freqs` + auto const o_orderkey = orders_independent.column(0); + auto const o_orderdate_ts = orders_independent.column(2); + auto const l_base = + cudf::repeat(cudf::table_view({o_orderkey, o_orderdate_ts}), o_rep_freqs->view(), stream, mr); + auto l_base_columns = l_base->release(); + + // Generate the `l_orderkey` column + auto l_orderkey = std::move(l_base_columns[0]); + + // Generate the `l_partkey` column + auto l_partkey = generate_random_numeric_column( + 1, scale_factor * 200'000, l_num_rows, stream, mr); + + // Generate the `l_suppkey` column + auto l_suppkey = calculate_l_suppkey(l_partkey->view(), scale_factor, l_num_rows, stream, mr); + + // Generate the `l_linenumber` column + auto l_linenumber = generate_repeat_sequence_column(7, false, l_num_rows, stream, mr); + + // Generate the `l_quantity` column + auto l_quantity = generate_random_numeric_column(1, 50, l_num_rows, stream, mr); + + // Generate the `l_discount` column + auto l_discount = [&]() { + auto const col = generate_random_numeric_column(0.00, 0.10, l_num_rows, stream, mr); + return cudf::round(col->view(), 2); + }(); + + // Generate the `l_tax` column + auto l_tax = [&]() { + auto const col = generate_random_numeric_column(0.00, 0.08, l_num_rows, stream, mr); + return cudf::round(col->view(), 2); + }(); + + // Get the orderdate column from the `l_base` table + auto const ol_orderdate_ts = std::move(l_base_columns[1]); + + // Generate the `l_shipdate` column + auto l_shipdate_ts = [&]() { + auto const l_shipdate_rand_add_days = + generate_random_numeric_column(1, 121, l_num_rows, stream, mr); + return add_calendrical_days( + ol_orderdate_ts->view(), l_shipdate_rand_add_days->view(), stream, mr); + }(); + + // Generate the `l_commitdate` column + auto l_commitdate_ts = [&]() { + auto const l_commitdate_rand_add_days = + generate_random_numeric_column(30, 90, l_num_rows, stream, mr); + return add_calendrical_days( + ol_orderdate_ts->view(), l_commitdate_rand_add_days->view(), stream, mr); + }(); + + // Generate the `l_receiptdate` column + auto l_receiptdate_ts = [&]() { + auto const l_receiptdate_rand_add_days = + generate_random_numeric_column(1, 30, l_num_rows, stream, mr); + return add_calendrical_days( + l_shipdate_ts->view(), l_receiptdate_rand_add_days->view(), stream, mr); + }(); + + // Define the current date as per clause 4.2.2.12 of the TPC-H specification + constexpr cudf::size_type current_date_days_since_epoch = 9'298; + auto current_date = + cudf::timestamp_scalar(current_date_days_since_epoch, true); + auto current_date_literal = cudf::ast::literal(current_date); + + // Generate the `l_returnflag` column + // if `l_receiptdate` <= current_date then "R" or "A" else "N" + auto l_returnflag = [&]() { + auto const col_ref = cudf::ast::column_reference(0); + auto const pred = + cudf::ast::operation(cudf::ast::ast_operator::LESS_EQUAL, col_ref, current_date_literal); + auto const binary_mask = + cudf::compute_column(cudf::table_view({l_receiptdate_ts->view()}), pred, stream, mr); + + auto const multiplier = + generate_repeat_sequence_column(2, false, l_num_rows, stream, mr); + auto const ternary_mask = cudf::binary_operation(binary_mask->view(), + multiplier->view(), + cudf::binary_operator::MUL, + cudf::data_type{cudf::type_id::INT8}, + stream, + mr); + auto const indices = cudf::test::fixed_width_column_wrapper({0, 1, 2}).release(); + auto const keys = cudf::test::strings_column_wrapper({"N", "A", "R"}).release(); + auto const gather_map = cudf::table_view({indices->view(), keys->view()}); + auto const gathered_table = cudf::gather( + gather_map, ternary_mask->view(), cudf::out_of_bounds_policy::DONT_CHECK, stream, mr); + return std::move(gathered_table->release()[1]); + }(); + + // Generate the `l_linestatus` column + // if `l_shipdate` > current_date then "F" else "O" + auto [l_linestatus, l_linestatus_mask] = [&]() { + auto const col_ref = cudf::ast::column_reference(0); + auto const pred = + cudf::ast::operation(cudf::ast::ast_operator::GREATER, col_ref, current_date_literal); + auto mask = cudf::compute_column(cudf::table_view({l_shipdate_ts->view()}), pred, stream, mr); + auto mask_index_type = cudf::cast(mask->view(), cudf::data_type{cudf::type_id::INT8}); + auto const indices = cudf::test::fixed_width_column_wrapper({0, 1}).release(); + auto const keys = cudf::test::strings_column_wrapper({"O", "F"}).release(); + auto const gather_map = cudf::table_view({indices->view(), keys->view()}); + auto const gathered_table = cudf::gather( + gather_map, mask_index_type->view(), cudf::out_of_bounds_policy::DONT_CHECK, stream, mr); + return std::make_tuple(std::move(gathered_table->release()[1]), std::move(mask_index_type)); + }(); + + // Generate the `l_shipinstruct` column + auto l_shipinstruct = generate_random_string_column_from_set( + cudf::host_span(vocab_instructions.data(), vocab_instructions.size()), + l_num_rows, + stream, + mr); + + // Generate the `l_shipmode` column + auto l_shipmode = generate_random_string_column_from_set( + cudf::host_span(vocab_modes.data(), vocab_modes.size()), + l_num_rows, + stream, + mr); + + // Generate the `l_comment` column + // NOTE: This column is not compliant with + // clause 4.2.2.10 of the TPC-H specification + auto l_comment = generate_random_string_column(10, 43, l_num_rows, stream, mr); + + // Generate the `lineitem_partial` table + std::vector> columns; + columns.push_back(std::move(l_linestatus_mask)); + columns.push_back(std::move(l_orderkey)); + columns.push_back(std::move(l_partkey)); + columns.push_back(std::move(l_suppkey)); + columns.push_back(std::move(l_linenumber)); + columns.push_back(std::move(l_quantity)); + columns.push_back(std::move(l_discount)); + columns.push_back(std::move(l_tax)); + columns.push_back(std::move(l_shipdate_ts)); + columns.push_back(std::move(l_commitdate_ts)); + columns.push_back(std::move(l_receiptdate_ts)); + columns.push_back(std::move(l_returnflag)); + columns.push_back(std::move(l_linestatus)); + columns.push_back(std::move(l_shipinstruct)); + columns.push_back(std::move(l_shipmode)); + columns.push_back(std::move(l_comment)); + return std::make_unique(std::move(columns)); +} + +std::unique_ptr generate_orders_dependent(cudf::table_view const& lineitem, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + auto const l_linestatus_mask = lineitem.column(0); + auto const l_orderkey = lineitem.column(1); + auto const l_discount = lineitem.column(6); + auto const l_tax = lineitem.column(7); + auto const l_extendedprice = lineitem.column(16); + + std::vector> orders_dependent_columns; + + // Generate the `o_totalprice` column + // We calculate the `charge` column, which is a function of `l_extendedprice`, + // `l_tax`, and `l_discount` and then group by `l_orderkey` and sum the `charge` + auto const l_charge = calculate_charge(l_extendedprice, l_tax, l_discount, stream, mr); + auto o_totalprice = [&]() { + auto const keys = cudf::table_view({l_orderkey}); + cudf::groupby::groupby gb(keys); + std::vector requests; + requests.push_back(cudf::groupby::aggregation_request()); + requests[0].aggregations.push_back(cudf::make_sum_aggregation()); + requests[0].values = l_charge->view(); + auto agg_result = gb.aggregate(requests); + return cudf::round(agg_result.second[0].results[0]->view(), 2); + }(); + orders_dependent_columns.push_back(std::move(o_totalprice)); + + // Generate the `o_orderstatus` column + auto o_orderstatus = [&]() { + auto const keys = cudf::table_view({l_orderkey}); + cudf::groupby::groupby gb(keys); + std::vector requests; + + // Perform a `count` aggregation on `l_orderkey` + requests.push_back(cudf::groupby::aggregation_request()); + requests[0].aggregations.push_back(cudf::make_count_aggregation()); + requests[0].values = l_orderkey; + + // Perform a `sum` aggregation on `l_linestatus_mask` + requests.push_back(cudf::groupby::aggregation_request()); + requests[1].aggregations.push_back(cudf::make_sum_aggregation()); + requests[1].values = l_linestatus_mask; + + // Perform the aggregations + auto agg_result = gb.aggregate(requests); + + // Create a `table_view` out of the `l_orderkey`, `count`, and `sum` columns + auto const count = std::move(agg_result.second[0].results[0]); + auto const sum = cudf::cast( + agg_result.second[1].results[0]->view(), cudf::data_type{cudf::type_id::INT32}, stream, mr); + + auto const table = + cudf::table_view({agg_result.first->get_column(0).view(), count->view(), sum->view()}); + + // Now on this table, + // if `sum` == `count` then "O", + // if `sum` == 0, then "F", + // else "P" + + // So, we first evaluate an expression `sum == count` and generate a boolean mask + auto const count_ref = cudf::ast::column_reference(1); + auto const sum_ref = cudf::ast::column_reference(2); + auto const expr_a = cudf::ast::operation(cudf::ast::ast_operator::EQUAL, sum_ref, count_ref); + auto const mask_a = cudf::compute_column(table, expr_a); + auto const o_orderstatus_intermediate = + cudf::copy_if_else(cudf::string_scalar("O"), cudf::string_scalar("F"), mask_a->view()); + + // Then, we evaluate an expression `sum == 0` and generate a boolean mask + auto zero_scalar = cudf::numeric_scalar(0); + auto const zero_literal = cudf::ast::literal(zero_scalar); + auto const expr_b_left = + cudf::ast::operation(cudf::ast::ast_operator::NOT_EQUAL, sum_ref, count_ref); + auto const expr_b_right = + cudf::ast::operation(cudf::ast::ast_operator::NOT_EQUAL, sum_ref, zero_literal); + auto const expr_b = + cudf::ast::operation(cudf::ast::ast_operator::LOGICAL_AND, expr_b_left, expr_b_right); + auto const mask_b = cudf::compute_column(table, expr_b); + return cudf::copy_if_else( + cudf::string_scalar("P"), o_orderstatus_intermediate->view(), mask_b->view()); + }(); + orders_dependent_columns.push_back(std::move(o_orderstatus)); + return std::make_unique(std::move(orders_dependent_columns)); +} + +/** + * @brief Generate the `partsupp` table + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_partsupp(double scale_factor, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Define the number of rows in the `part` and `partsupp` tables + cudf::size_type const p_num_rows = scale_factor * 200'000; + cudf::size_type const ps_num_rows = scale_factor * 800'000; + + // Generate the `ps_partkey` column + auto ps_partkey = [&]() { + auto const p_partkey = + generate_primary_key_column(cudf::numeric_scalar(1), p_num_rows, stream, mr); + auto const rep_table = cudf::repeat(cudf::table_view({p_partkey->view()}), 4, stream, mr); + return std::move(rep_table->release()[0]); + }(); + + // Generate the `ps_suppkey` column + auto ps_suppkey = calculate_ps_suppkey(ps_partkey->view(), scale_factor, ps_num_rows, stream, mr); + + // Generate the `ps_availqty` column + auto ps_availqty = generate_random_numeric_column(1, 9999, ps_num_rows, stream, mr); + + // Generate the `ps_supplycost` column + auto ps_supplycost = [&]() { + auto const col = generate_random_numeric_column(1.00, 1000.00, ps_num_rows, stream, mr); + return cudf::round(col->view(), 2); + }(); + + // Generate the `ps_comment` column + // NOTE: This column is not compliant with clause 4.2.2.10 of the TPC-H specification + auto ps_comment = generate_random_string_column(49, 198, ps_num_rows, stream, mr); + + // Create the `partsupp` table + std::vector> columns; + columns.push_back(std::move(ps_partkey)); + columns.push_back(std::move(ps_suppkey)); + columns.push_back(std::move(ps_availqty)); + columns.push_back(std::move(ps_supplycost)); + columns.push_back(std::move(ps_comment)); + return std::make_unique(std::move(columns)); +} + +/** + * @brief Generate the `part` table + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_part(double scale_factor, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + cudf::size_type const num_rows = scale_factor * 200'000; + + // Generate the `p_partkey` column + auto p_partkey = + generate_primary_key_column(cudf::numeric_scalar(1), num_rows, stream, mr); + + // Generate the `p_name` column + auto p_name = [&]() { + auto const p_name_a = generate_random_string_column_from_set( + cudf::host_span(vocab_p_name.data(), vocab_p_name.size()), + num_rows, + stream, + mr); + auto const p_name_b = generate_random_string_column_from_set( + cudf::host_span(vocab_p_name.data(), vocab_p_name.size()), + num_rows, + stream, + mr); + auto const p_name_c = generate_random_string_column_from_set( + cudf::host_span(vocab_p_name.data(), vocab_p_name.size()), + num_rows, + stream, + mr); + auto const p_name_d = generate_random_string_column_from_set( + cudf::host_span(vocab_p_name.data(), vocab_p_name.size()), + num_rows, + stream, + mr); + auto const p_name_e = generate_random_string_column_from_set( + cudf::host_span(vocab_p_name.data(), vocab_p_name.size()), + num_rows, + stream, + mr); + return cudf::strings::concatenate( + cudf::table_view( + {p_name_a->view(), p_name_b->view(), p_name_c->view(), p_name_d->view(), p_name_e->view()}), + cudf::string_scalar(" "), + cudf::string_scalar("", false), + cudf::strings::separator_on_nulls::NO, + stream, + mr); + }(); + + // Generate the `p_mfgr` and `p_brand` columns + auto const random_values_m = generate_random_numeric_column(1, 5, num_rows, stream, mr); + auto const random_values_m_str = + cudf::strings::from_integers(random_values_m->view(), stream, mr); + + auto const random_values_n = generate_random_numeric_column(1, 5, num_rows, stream, mr); + auto const random_values_n_str = + cudf::strings::from_integers(random_values_n->view(), stream, mr); + + auto p_mfgr = [&]() { + auto const mfgr_repeat = generate_repeat_string_column("Manufacturer#", num_rows, stream, mr); + return cudf::strings::concatenate( + cudf::table_view({mfgr_repeat->view(), random_values_m_str->view()}), + cudf::string_scalar(""), + cudf::string_scalar("", false), + cudf::strings::separator_on_nulls::NO, + stream, + mr); + }(); + + auto p_brand = [&]() { + auto const brand_repeat = generate_repeat_string_column("Brand#", num_rows, stream, mr); + return cudf::strings::concatenate( + cudf::table_view( + {brand_repeat->view(), random_values_m_str->view(), random_values_n_str->view()}), + cudf::string_scalar(""), + cudf::string_scalar("", false), + cudf::strings::separator_on_nulls::NO, + stream, + mr); + }(); + + // Generate the `p_type` column + auto p_type = generate_random_string_column_from_set( + cudf::host_span(vocab_types.data(), vocab_types.size()), + num_rows, + stream, + mr); + + // Generate the `p_size` column + auto p_size = generate_random_numeric_column(1, 50, num_rows, stream, mr); + + // Generate the `p_container` column + auto p_container = generate_random_string_column_from_set( + cudf::host_span(vocab_containers.data(), vocab_containers.size()), + num_rows, + stream, + mr); + + // Generate the `p_retailprice` column + auto p_retailprice = calculate_p_retailprice(p_partkey->view(), stream, mr); + + // Generate the `p_comment` column + // NOTE: This column is not compliant with clause 4.2.2.10 of the TPC-H specification + auto p_comment = generate_random_string_column(5, 22, num_rows, stream, mr); + + // Create the `part` table + std::vector> columns; + columns.push_back(std::move(p_partkey)); + columns.push_back(std::move(p_name)); + columns.push_back(std::move(p_mfgr)); + columns.push_back(std::move(p_brand)); + columns.push_back(std::move(p_type)); + columns.push_back(std::move(p_size)); + columns.push_back(std::move(p_container)); + columns.push_back(std::move(p_retailprice)); + columns.push_back(std::move(p_comment)); + return std::make_unique(std::move(columns)); +} + +/** + * @brief Generate the `orders`, `lineitem`, and `part` tables + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::tuple, std::unique_ptr, std::unique_ptr> +generate_orders_lineitem_part(double scale_factor, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Generate a table with the independent columns of the `orders` table + auto orders_independent = generate_orders_independent(scale_factor, stream, mr); + + // Generate the `lineitem` table partially + auto lineitem_partial = + generate_lineitem_partial(orders_independent->view(), scale_factor, stream, mr); + + // Generate the `part` table + auto part = generate_part(scale_factor, stream, mr); + + // Join the `part` and partial `lineitem` tables, then calculate the `l_extendedprice` column, + // add the column to the `lineitem` table, and write the `lineitem` table to a parquet file + + auto l_extendedprice = [&]() { + auto const left = cudf::table_view( + {lineitem_partial->get_column(2).view(), lineitem_partial->get_column(5).view()}); + auto const right = cudf::table_view({part->get_column(0).view(), part->get_column(7).view()}); + auto const joined_table = perform_left_join(left, right, {0}, {0}, stream, mr); + auto joined_table_columns = joined_table->release(); + auto const l_quantity = std::move(joined_table_columns[1]); + auto const l_quantity_fp = + cudf::cast(l_quantity->view(), cudf::data_type{cudf::type_id::FLOAT64}); + auto const p_retailprice = std::move(joined_table_columns[3]); + auto const col = cudf::binary_operation(l_quantity_fp->view(), + p_retailprice->view(), + cudf::binary_operator::MUL, + cudf::data_type{cudf::type_id::FLOAT64}, + stream, + mr); + return cudf::round(col->view(), 2); + }(); + + auto lineitem_partial_columns = lineitem_partial->release(); + lineitem_partial_columns.push_back(std::move(l_extendedprice)); + auto lineitem_temp = std::make_unique(std::move(lineitem_partial_columns)); + + // Generate the dependent columns of the `orders` table + // and merge them with the independent columns + auto orders_dependent = generate_orders_dependent(lineitem_temp->view(), stream, mr); + + auto orders_independent_columns = orders_independent->release(); + auto orders_dependent_columns = orders_dependent->release(); + orders_independent_columns.insert(orders_independent_columns.end(), + std::make_move_iterator(orders_dependent_columns.begin()), + std::make_move_iterator(orders_dependent_columns.end())); + + // Create the `orders` table + auto orders = std::make_unique(std::move(orders_independent_columns)); + + // Create the `lineitem` table + auto lineitem_temp_columns = lineitem_temp->release(); + lineitem_temp_columns.erase(lineitem_temp_columns.begin()); + auto lineitem = std::make_unique(std::move(lineitem_temp_columns)); + + return std::make_tuple(std::move(orders), std::move(lineitem), std::move(part)); +} + +/** + * @brief Generate the `supplier` table + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_supplier(double scale_factor, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Calculate the number of rows based on the scale factor + cudf::size_type const num_rows = scale_factor * 10'000; + + // Generate the `s_suppkey` column + auto s_suppkey = + generate_primary_key_column(cudf::numeric_scalar(1), num_rows, stream, mr); + + // Generate the `s_name` column + auto s_name = [&]() { + auto const supplier_repeat = generate_repeat_string_column("Supplier#", num_rows, stream, mr); + auto const s_suppkey_str = cudf::strings::from_integers(s_suppkey->view(), stream, mr); + auto const s_suppkey_str_padded = cudf::strings::zfill(s_suppkey_str->view(), 9, stream, mr); + return cudf::strings::concatenate( + cudf::table_view({supplier_repeat->view(), s_suppkey_str_padded->view()}), + cudf::string_scalar(""), + cudf::string_scalar("", false), + cudf::strings::separator_on_nulls::NO, + stream, + mr); + }(); + + // Generate the `s_address` column + auto s_address = generate_address_column(num_rows, stream, mr); + + // Generate the `s_nationkey` column + auto s_nationkey = generate_random_numeric_column(0, 24, num_rows, stream, mr); + + // Generate the `s_phone` column + auto s_phone = generate_phone_column(num_rows, stream, mr); + + // Generate the `s_acctbal` column + auto s_acctbal = [&]() { + auto const col = generate_random_numeric_column(-999.99, 9999.99, num_rows, stream, mr); + return cudf::round(col->view(), 2); + }(); + + // Generate the `s_comment` column + // NOTE: This column is not compliant with clause 4.2.2.10 of the TPC-H specification + auto s_comment = generate_random_string_column(25, 100, num_rows, stream, mr); + + // Create the `supplier` table + std::vector> columns; + columns.push_back(std::move(s_suppkey)); + columns.push_back(std::move(s_name)); + columns.push_back(std::move(s_address)); + columns.push_back(std::move(s_nationkey)); + columns.push_back(std::move(s_phone)); + columns.push_back(std::move(s_acctbal)); + columns.push_back(std::move(s_comment)); + return std::make_unique(std::move(columns)); +} + +/** + * @brief Generate the `customer` table + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_customer(double scale_factor, + rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Calculate the number of rows based on the scale factor + cudf::size_type const num_rows = scale_factor * 150'000; + + // Generate the `c_custkey` column + auto c_custkey = + generate_primary_key_column(cudf::numeric_scalar(1), num_rows, stream, mr); + + // Generate the `c_name` column + auto c_name = [&]() { + auto const customer_repeat = generate_repeat_string_column("Customer#", num_rows, stream, mr); + auto const c_custkey_str = cudf::strings::from_integers(c_custkey->view(), stream, mr); + auto const c_custkey_str_padded = cudf::strings::zfill(c_custkey_str->view(), 9, stream, mr); + return cudf::strings::concatenate( + cudf::table_view({customer_repeat->view(), c_custkey_str_padded->view()}), + cudf::string_scalar(""), + cudf::string_scalar("", false), + cudf::strings::separator_on_nulls::NO, + stream, + mr); + }(); + + // Generate the `c_address` column + auto c_address = generate_address_column(num_rows, stream, mr); + + // Generate the `c_nationkey` column + auto c_nationkey = generate_random_numeric_column(0, 24, num_rows, stream, mr); + + // Generate the `c_phone` column + auto c_phone = generate_phone_column(num_rows, stream, mr); + + // Generate the `c_acctbal` column + auto c_acctbal = [&]() { + auto const col = generate_random_numeric_column(-999.99, 9999.99, num_rows, stream, mr); + return cudf::round(col->view(), 2); + }(); + + // Generate the `c_mktsegment` column + auto c_mktsegment = generate_random_string_column_from_set( + cudf::host_span(vocab_segments.data(), vocab_segments.size()), + num_rows, + stream, + mr); + + // Generate the `c_comment` column + // NOTE: This column is not compliant with clause 4.2.2.10 of the TPC-H specification + auto c_comment = generate_random_string_column(29, 116, num_rows, stream, mr); + + // Create the `customer` table + std::vector> columns; + columns.push_back(std::move(c_custkey)); + columns.push_back(std::move(c_name)); + columns.push_back(std::move(c_address)); + columns.push_back(std::move(c_nationkey)); + columns.push_back(std::move(c_phone)); + columns.push_back(std::move(c_acctbal)); + columns.push_back(std::move(c_mktsegment)); + columns.push_back(std::move(c_comment)); + return std::make_unique(std::move(columns)); +} + +/** + * @brief Generate the `nation` table + * + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_nation(rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Define the number of rows + constexpr cudf::size_type num_rows = 25; + + // Generate the `n_nationkey` column + auto n_nationkey = + generate_primary_key_column(cudf::numeric_scalar(0), num_rows, stream, mr); + + // Generate the `n_name` column + auto n_name = cudf::test::strings_column_wrapper(nations.begin(), nations.end()).release(); + + // Generate the `n_regionkey` column + std::vector region_keys{0, 1, 1, 1, 4, 0, 3, 3, 2, 2, 4, 4, 2, + 4, 0, 0, 0, 1, 2, 3, 4, 2, 3, 3, 1}; + auto n_regionkey = + cudf::test::fixed_width_column_wrapper(region_keys.begin(), region_keys.end()) + .release(); + + // Generate the `n_comment` column + // NOTE: This column is not compliant with clause 4.2.2.10 of the TPC-H specification + auto n_comment = generate_random_string_column(31, 114, num_rows, stream, mr); + + // Create the `nation` table + std::vector> columns; + columns.push_back(std::move(n_nationkey)); + columns.push_back(std::move(n_name)); + columns.push_back(std::move(n_regionkey)); + columns.push_back(std::move(n_comment)); + return std::make_unique(std::move(columns)); +} + +/** + * @brief Generate the `region` table + * + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_region(rmm::cuda_stream_view stream, + rmm::device_async_resource_ref mr) +{ + CUDF_FUNC_RANGE(); + // Define the number of rows + constexpr cudf::size_type num_rows = 5; + + // Generate the `r_regionkey` column + auto r_regionkey = + generate_primary_key_column(cudf::numeric_scalar(0), num_rows, stream, mr); + + // Generate the `r_name` column + auto r_name = + cudf::test::strings_column_wrapper({"AFRICA", "AMERICA", "ASIA", "EUROPE", "MIDDLE EAST"}) + .release(); + + // Generate the `r_comment` column + // NOTE: This column is not compliant with clause 4.2.2.10 of the TPC-H specification + auto r_comment = generate_random_string_column(31, 115, num_rows, stream, mr); + + // Create the `region` table + std::vector> columns; + columns.push_back(std::move(r_regionkey)); + columns.push_back(std::move(r_name)); + columns.push_back(std::move(r_comment)); + return std::make_unique(std::move(columns)); +} + +} // namespace cudf::datagen diff --git a/cpp/benchmarks/common/tpch_data_generator/tpch_data_generator.hpp b/cpp/benchmarks/common/tpch_data_generator/tpch_data_generator.hpp new file mode 100644 index 00000000000..a6286dd8dba --- /dev/null +++ b/cpp/benchmarks/common/tpch_data_generator/tpch_data_generator.hpp @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace CUDF_EXPORT cudf { +namespace datagen { + +/** + * @brief Generate the `orders`, `lineitem`, and `part` tables + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::tuple, std::unique_ptr, std::unique_ptr> +generate_orders_lineitem_part( + double scale_factor, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate the `partsupp` table + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_partsupp( + double scale_factor, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate the `supplier` table + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_supplier( + double scale_factor, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate the `customer` table + * + * @param scale_factor The scale factor to generate + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_customer( + double scale_factor, + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate the `nation` table + * + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_nation( + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +/** + * @brief Generate the `region` table + * + * @param stream CUDA stream used for device memory operations and kernel launches + * @param mr Device memory resource used to allocate the returned column's device memory + */ +std::unique_ptr generate_region( + rmm::cuda_stream_view stream = cudf::get_default_stream(), + rmm::device_async_resource_ref mr = rmm::mr::get_current_device_resource()); + +} // namespace datagen +} // namespace CUDF_EXPORT cudf