Skip to content

Commit 09a384c

Browse files
Merge branch 'main' into mlir/pr11-strings-nonstring-ops
2 parents 9d468fe + c868e01 commit 09a384c

37 files changed

Lines changed: 519 additions & 352 deletions

‎.github/workflows/issue-release-scheduled.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77

88
jobs:
99
sync-release-fields:
10+
if: github.repository == 'NVIDIA/cudf'
1011
runs-on: ubuntu-latest
1112
permissions:
1213
issues: write

‎cpp/benchmarks/common/generate_input.hpp‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,11 @@ std::unique_ptr<cudf::column> create_string_column(cudf::size_type num_rows,
605605
int32_t hit_rate);
606606

607607
/**
608-
* @brief Generates an string column filled with ASCII characters only
608+
* @brief Generates a string column filled with ASCII characters only
609+
*
610+
* Only the string length distribution and null probability of the profile are used.
611+
* The cardinality and average run length settings are ignored, so every row is
612+
* generated independently.
609613
*
610614
* @param profile Data profile for the output column
611615
* @param num_rows Number of rows in the output column

‎cpp/benchmarks/io/parquet/experimental/hybrid_scan/dict_page_filter.cpp‎

Lines changed: 99 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,39 @@
1313
#include <cudf/io/parquet.hpp>
1414
#include <cudf/io/parquet_io_utils.hpp>
1515
#include <cudf/io/text/byte_range_info.hpp>
16+
#include <cudf/scalar/scalar.hpp>
1617
#include <cudf/utilities/default_stream.hpp>
18+
#include <cudf/utilities/traits.hpp>
19+
#include <cudf/utilities/type_dispatcher.hpp>
20+
#include <cudf/wrappers/durations.hpp>
1721

1822
#include <nvbench/nvbench.cuh>
1923

24+
#include <algorithm>
25+
#include <limits>
2026
#include <numeric>
2127

28+
namespace {
29+
2230
constexpr cudf::size_type num_cols = 8;
2331

24-
void BM_filter_string_row_groups_with_dicts_common(nvbench::state& state,
25-
data_profile const& table_profile,
26-
cudf::ast::operation const& filter_expr,
27-
double average_str_length,
28-
cudf::size_type cardinality)
32+
void filter_row_groups_with_dicts_common(nvbench::state& state,
33+
cudf::type_id dtype,
34+
data_profile const& table_profile,
35+
cudf::ast::literal const& literal)
2936
{
3037
auto const num_row_groups = static_cast<cudf::size_type>(state.get_int64("num_row_groups"));
38+
auto const cardinality = static_cast<cudf::size_type>(state.get_int64("cardinality"));
39+
auto const is_inline_eval = static_cast<bool>(state.get_int64("is_inline"));
3140
auto constexpr rows_per_row_group = 5'000; //< Chosen such that it is not ignored by the writer
3241
auto const num_rows = num_row_groups * rows_per_row_group;
3342

3443
std::vector<char> parquet_buffer;
3544

3645
// Write table to parquet
3746
{
38-
auto const table = create_random_table(
39-
cycle_dtypes({cudf::type_id::STRING}, num_cols), row_count{num_rows}, table_profile);
47+
auto const table =
48+
create_random_table(cycle_dtypes({dtype}, num_cols), row_count{num_rows}, table_profile);
4049

4150
cudf::io::parquet_writer_options write_opts =
4251
cudf::io::parquet_writer_options::builder(cudf::io::sink_info(&parquet_buffer), table->view())
@@ -47,6 +56,17 @@ void BM_filter_string_row_groups_with_dicts_common(nvbench::state& state,
4756
cudf::io::write_parquet(write_opts);
4857
}
4958

59+
auto col_ref = cudf::ast::column_name_reference("_col0");
60+
auto expr1 = cudf::ast::operation(cudf::ast::ast_operator::EQUAL, col_ref, literal);
61+
auto expr2 = cudf::ast::operation(cudf::ast::ast_operator::NOT_EQUAL, col_ref, literal);
62+
auto expr3 = cudf::ast::operation(cudf::ast::ast_operator::EQUAL, col_ref, literal);
63+
64+
auto filter_expr_few_literals =
65+
cudf::ast::operation(cudf::ast::ast_operator::LOGICAL_AND, expr1, expr2);
66+
auto filter_expr_many_literals =
67+
cudf::ast::operation(cudf::ast::ast_operator::LOGICAL_OR, filter_expr_few_literals, expr3);
68+
auto const& filter_expr = is_inline_eval ? filter_expr_few_literals : filter_expr_many_literals;
69+
5070
auto const stream = cudf::get_default_stream();
5171
auto const read_opts = cudf::io::parquet_reader_options::builder().filter(filter_expr).build();
5272

@@ -76,6 +96,13 @@ void BM_filter_string_row_groups_with_dicts_common(nvbench::state& state,
7696
auto input_row_group_indices = reader->all_row_groups(read_opts);
7797
auto dict_page_byte_ranges = std::vector<cudf::io::text::byte_range_info>{};
7898

99+
// Upper bound on the dictionary entries. Real dictionaries are smaller because the generator
100+
// repeats each value it draws for a run of rows, and may draw the same value again
101+
auto const num_dict_entries =
102+
static_cast<std::size_t>(std::min(cardinality, rows_per_row_group) * num_row_groups);
103+
104+
state.add_element_count(num_dict_entries, "num_dict_entries");
105+
79106
auto mem_stats_logger = cudf::memory_stats_logger();
80107

81108
state.exec(
@@ -106,12 +133,8 @@ void BM_filter_string_row_groups_with_dicts_common(nvbench::state& state,
106133
timer.stop();
107134
});
108135

109-
auto const time = state.get_summary("nv/cold/time/gpu/mean").get_float64("value");
110136
state.add_buffer_size(
111137
mem_stats_logger.peak_memory_usage(), "peak_memory_usage", "peak_memory_usage");
112-
state.add_element_count(
113-
static_cast<double>(cardinality * num_row_groups * average_str_length) / time,
114-
"strings_per_second");
115138
auto const total_dict_data_size =
116139
std::accumulate(dict_page_byte_ranges.begin(),
117140
dict_page_byte_ranges.end(),
@@ -120,44 +143,86 @@ void BM_filter_string_row_groups_with_dicts_common(nvbench::state& state,
120143
state.add_buffer_size(total_dict_data_size, "total_dict_data_size", "total_dict_data_size");
121144
}
122145

123-
void BM_filter_string_rowgroups_with_dicts(nvbench::state& state)
146+
} // namespace
147+
148+
void BM_hybrid_scan_dict_page_pruning_string(nvbench::state& state)
124149
{
125-
auto const min_length = static_cast<cudf::size_type>(state.get_int64("min_length"));
126-
auto const max_length = static_cast<cudf::size_type>(state.get_int64("max_length"));
127-
auto const cardinality = static_cast<cudf::size_type>(state.get_int64("cardinality"));
128-
auto const is_inline_eval = static_cast<bool>(state.get_int64("is_inline"));
150+
auto const min_length = static_cast<cudf::size_type>(state.get_int64("min_length"));
151+
auto const max_length = static_cast<cudf::size_type>(state.get_int64("max_length"));
152+
auto const cardinality = static_cast<cudf::size_type>(state.get_int64("cardinality"));
129153

130154
auto table_profile =
131155
data_profile_builder()
132156
.distribution(cudf::type_id::STRING, distribution_id::NORMAL, min_length, max_length)
133157
.cardinality(cardinality);
134158

135-
auto col_ref = cudf::ast::column_name_reference("_col0");
136-
auto scalar = cudf::string_scalar("000010000");
137-
auto literal = cudf::ast::literal(scalar);
138-
auto expr1 = cudf::ast::operation(cudf::ast::ast_operator::EQUAL, col_ref, literal);
139-
auto expr2 = cudf::ast::operation(cudf::ast::ast_operator::NOT_EQUAL, col_ref, literal);
140-
auto expr3 = cudf::ast::operation(cudf::ast::ast_operator::EQUAL, col_ref, literal);
159+
auto filter_value = cudf::string_scalar("000010000");
160+
filter_row_groups_with_dicts_common(
161+
state, cudf::type_id::STRING, table_profile, cudf::ast::literal(filter_value));
162+
}
141163

142-
auto filter_expr_few_literals =
143-
cudf::ast::operation(cudf::ast::ast_operator::LOGICAL_AND, expr1, expr2);
164+
template <cudf::type_id DType>
165+
void BM_hybrid_scan_dict_page_pruning_fixed_width(nvbench::state& state,
166+
nvbench::type_list<nvbench::enum_type<DType>>)
167+
{
168+
using T = cudf::id_to_type<DType>;
169+
static_assert(cudf::is_numeric<T>() or cudf::is_chrono<T>(),
170+
"Filter literals are only generated for numeric and chrono types");
171+
172+
auto const cardinality = static_cast<cudf::size_type>(state.get_int64("cardinality"));
173+
174+
// Timestamps span 1970 to 2020 as the generator overflows past 2262
175+
// Durations span 24 days to fit
176+
auto constexpr max_value = [] {
177+
if constexpr (cudf::is_timestamp<T>()) {
178+
return cuda::std::chrono::duration_cast<typename T::duration>(cudf::duration_D{50 * 365})
179+
.count();
180+
} else if constexpr (cudf::is_duration<T>()) {
181+
return cuda::std::chrono::duration_cast<T>(cudf::duration_D{24}).count();
182+
} else {
183+
return std::numeric_limits<T>::max();
184+
}
185+
}();
144186

145-
auto filter_expr_many_literals =
146-
cudf::ast::operation(cudf::ast::ast_operator::LOGICAL_OR, filter_expr_few_literals, expr3);
187+
auto table_profile =
188+
data_profile_builder()
189+
.distribution(DType, distribution_id::UNIFORM, decltype(max_value){0}, max_value)
190+
.cardinality(cardinality);
147191

148-
return BM_filter_string_row_groups_with_dicts_common(
149-
state,
150-
table_profile,
151-
is_inline_eval ? filter_expr_few_literals : filter_expr_many_literals,
152-
(static_cast<double>(min_length) + static_cast<double>(max_length)) / 2,
153-
cardinality);
192+
// The literal lies inside the value range, so min/max statistics cannot prune any row group
193+
auto filter_value = [&] {
194+
if constexpr (cudf::is_timestamp<T>()) {
195+
return cudf::timestamp_scalar<T>(T{typename T::duration{max_value / 2}});
196+
} else if constexpr (cudf::is_duration<T>()) {
197+
return cudf::duration_scalar<T>(T{max_value / 2});
198+
} else {
199+
return cudf::numeric_scalar<T>(static_cast<T>(max_value / 2));
200+
}
201+
}();
202+
filter_row_groups_with_dicts_common(
203+
state, DType, table_profile, cudf::ast::literal(filter_value));
154204
}
155205

156-
NVBENCH_BENCH(BM_filter_string_rowgroups_with_dicts)
157-
.set_name("hybrid_scan_filter_string_rowgroups_with_dicts")
206+
NVBENCH_BENCH(BM_hybrid_scan_dict_page_pruning_string)
207+
.set_name("hybrid_scan_dict_page_pruning_string")
158208
.set_min_samples(4)
159209
.add_int64_axis("num_row_groups", {32, 64, 128})
160210
.add_int64_axis("min_length", {4})
161211
.add_int64_axis("max_length", {64, 128})
162212
.add_int64_axis("cardinality", {1'000, 10'000})
163213
.add_int64_axis("is_inline", {true, false});
214+
215+
using dict_fixed_width_dtypes = nvbench::enum_type_list<cudf::type_id::INT8,
216+
cudf::type_id::FLOAT32,
217+
cudf::type_id::FLOAT64,
218+
cudf::type_id::DURATION_MILLISECONDS,
219+
cudf::type_id::TIMESTAMP_MICROSECONDS>;
220+
221+
NVBENCH_BENCH_TYPES(BM_hybrid_scan_dict_page_pruning_fixed_width,
222+
NVBENCH_TYPE_AXES(dict_fixed_width_dtypes))
223+
.set_name("hybrid_scan_dict_page_pruning_fixed_width")
224+
.set_type_axes_names({"dtype"})
225+
.set_min_samples(4)
226+
.add_int64_axis("num_row_groups", {32, 64, 128})
227+
.add_int64_axis("cardinality", {1'000, 10'000})
228+
.add_int64_axis("is_inline", {true, false});

‎cpp/benchmarks/io/parquet/experimental/hybrid_scan/hybrid_scan_composer.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ std::unique_ptr<hybrid_scan_reader> setup_reader(cudf::io::datasource& datasourc
4747

4848
std::vector<cudf::size_type> apply_row_group_filters(
4949
cudf::io::datasource& datasource,
50-
hybrid_scan_reader const& reader,
50+
hybrid_scan_reader& reader,
5151
cudf::host_span<cudf::size_type> input_row_group_indices,
5252
std::unordered_set<hybrid_scan_filter_type> const& filters,
5353
cudf::io::parquet_reader_options const& options,
@@ -126,7 +126,7 @@ std::vector<cudf::size_type> apply_row_group_filters(
126126

127127
std::unique_ptr<cudf::table> single_step_materialize(
128128
cudf::io::datasource& datasource,
129-
hybrid_scan_reader const& reader,
129+
hybrid_scan_reader& reader,
130130
cudf::host_span<cudf::size_type> current_row_group_indices,
131131
cudf::io::parquet_reader_options const& options,
132132
cuda::stream_ref stream,
@@ -162,7 +162,7 @@ std::unique_ptr<cudf::table> hybrid_scan(cudf::io::parquet_reader_options const&
162162

163163
// Setup reader and page index
164164
auto reader = setup_reader(datasource_ref, options);
165-
auto const reader_ref = std::cref(*reader);
165+
auto const reader_ref = std::ref(*reader);
166166

167167
// Start with all row groups
168168
auto row_group_indices = reader->all_row_groups(options);

‎cpp/benchmarks/io/parquet/experimental/hybrid_scan/page_stats_row_mask.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ void BM_page_stats_row_mask(nvbench::state& state)
287287

288288
auto const filter = make_filter_expression(expr_depth, dtypes);
289289
auto const options = cudf::io::parquet_reader_options::builder().filter(filter.root()).build();
290-
auto const reader = cudf::io::parquet::experimental::hybrid_scan_multifile{footer_spans, options};
290+
auto reader = cudf::io::parquet::experimental::hybrid_scan_multifile{footer_spans, options};
291291

292292
// Setup page indexes for page-statistics filtering
293293
{

‎cpp/benchmarks/string/case.cpp‎

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,11 @@ void bench_case(nvbench::state& state)
2121

2222
data_profile const profile = data_profile_builder().distribution(
2323
cudf::type_id::STRING, distribution_id::NORMAL, min_width, max_width);
24-
auto const column = create_random_column(cudf::type_id::STRING, row_count{num_rows}, profile);
25-
26-
auto col_view = column->view();
27-
auto col_size = column->alloc_size();
28-
29-
cudf::column::contents ascii_contents;
30-
if (encoding == "ascii") {
31-
data_profile ascii_profile = data_profile_builder().no_validity().distribution(
32-
cudf::type_id::INT8, distribution_id::UNIFORM, 32, 126); // nice ASCII range
33-
auto input = cudf::strings_column_view(col_view);
34-
auto ascii_column = create_random_column(
35-
cudf::type_id::INT8,
36-
row_count{static_cast<cudf::size_type>(input.chars_size(cudf::get_default_stream()))},
37-
ascii_profile);
38-
auto ascii_data = ascii_column->view();
39-
40-
col_view = cudf::column_view(col_view.type(),
41-
col_view.size(),
42-
ascii_data.data<char>(),
43-
col_view.null_mask(),
44-
col_view.null_count(),
45-
0,
46-
{input.offsets()});
47-
col_size = ascii_column->alloc_size();
48-
ascii_contents = ascii_column->release();
49-
}
50-
auto input = cudf::strings_column_view(col_view);
24+
auto const column = encoding == "ascii"
25+
? create_ascii_string_column(profile, num_rows)
26+
: create_random_column(cudf::type_id::STRING, row_count{num_rows}, profile);
27+
auto const input = cudf::strings_column_view(column->view());
28+
auto const col_size = column->alloc_size();
5129

5230
state.set_cuda_stream(nvbench::make_cuda_stream_view(cudf::get_default_stream().get()));
5331

‎cpp/benchmarks/text/edit_distance.cpp‎

Lines changed: 8 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,10 @@
66
#include <benchmarks/common/generate_input.hpp>
77
#include <benchmarks/common/memory_stats.hpp>
88

9-
#include <cudf/aggregation.hpp>
10-
#include <cudf/copying.hpp>
11-
#include <cudf/reduction.hpp>
129
#include <cudf/strings/strings_column_view.hpp>
1310

1411
#include <nvtext/edit_distance.hpp>
1512

16-
#include <rmm/device_buffer.hpp>
17-
1813
#include <nvbench/nvbench.cuh>
1914

2015
static void bench_edit_distance_utf8(nvbench::state& state)
@@ -28,7 +23,7 @@ static void bench_edit_distance_utf8(nvbench::state& state)
2823
auto const strings_table = create_random_table(
2924
{cudf::type_id::STRING, cudf::type_id::STRING}, row_count{num_rows}, strings_profile);
3025
auto input1 = strings_table->get_column(0);
31-
auto input2 = strings_table->get_column(0);
26+
auto input2 = strings_table->get_column(1);
3227
auto sv1 = cudf::strings_column_view(input1.view());
3328
auto sv2 = cudf::strings_column_view(input2.view());
3429

@@ -51,59 +46,16 @@ static void bench_edit_distance_ascii(nvbench::state& state)
5146
auto const min_width = static_cast<cudf::size_type>(state.get_int64("min_width"));
5247
auto const max_width = static_cast<cudf::size_type>(state.get_int64("max_width"));
5348

54-
auto const max_size = static_cast<int64_t>(num_rows) * static_cast<int64_t>(max_width);
55-
auto const offsets_type = max_size >= std::numeric_limits<cudf::size_type>::max()
56-
? cudf::type_id::INT64
57-
: cudf::type_id::INT32;
58-
59-
data_profile profile = data_profile_builder().no_validity().cardinality(0).distribution(
60-
offsets_type, distribution_id::NORMAL, min_width, max_width);
61-
data_profile ascii_profile = data_profile_builder().no_validity().cardinality(0).distribution(
62-
cudf::type_id::INT8, distribution_id::UNIFORM, 32, 126); // nice ASCII range
63-
64-
auto offsets = create_random_column(offsets_type, row_count{num_rows + 1}, profile);
65-
offsets = cudf::scan(offsets->view(),
66-
*cudf::make_sum_aggregation<cudf::scan_aggregation>(),
67-
cudf::scan_type::EXCLUSIVE);
68-
auto chars_size = offsets_type == cudf::type_id::INT64
69-
? dynamic_cast<cudf::numeric_scalar<int64_t>*>(
70-
cudf::get_element(offsets->view(), num_rows).get())
71-
->value()
72-
: static_cast<int64_t>(dynamic_cast<cudf::numeric_scalar<int32_t>*>(
73-
cudf::get_element(offsets->view(), num_rows).get())
74-
->value());
75-
if (chars_size > std::numeric_limits<int32_t>::max()) {
76-
// to be fixed with create_ascii_string_column utility in PR 20354
77-
state.skip("chars size too large for this benchmark");
78-
return;
79-
}
80-
81-
auto ascii_data1 = create_random_column(
82-
cudf::type_id::INT8, row_count{static_cast<cudf::size_type>(chars_size)}, ascii_profile);
83-
auto ascii_data2 = create_random_column(
84-
cudf::type_id::INT8, row_count{static_cast<cudf::size_type>(chars_size)}, ascii_profile);
85-
86-
auto input1 = cudf::column_view(cudf::data_type{cudf::type_id::STRING},
87-
num_rows,
88-
ascii_data1->view().data<char>(),
89-
nullptr,
90-
0,
91-
0,
92-
{offsets->view()});
93-
auto input2 = cudf::column_view(cudf::data_type{cudf::type_id::STRING},
94-
num_rows,
95-
ascii_data2->view().data<char>(),
96-
nullptr,
97-
0,
98-
0,
99-
{offsets->view()});
49+
data_profile const strings_profile = data_profile_builder().no_validity().distribution(
50+
cudf::type_id::STRING, distribution_id::NORMAL, min_width, max_width);
51+
auto const input1 = create_ascii_string_column(strings_profile, num_rows, 1);
52+
auto const input2 = create_ascii_string_column(strings_profile, num_rows, 2);
53+
auto sv1 = cudf::strings_column_view(input1->view());
54+
auto sv2 = cudf::strings_column_view(input2->view());
10055

10156
state.set_cuda_stream(nvbench::make_cuda_stream_view(cudf::get_default_stream().get()));
10257

103-
auto sv1 = cudf::strings_column_view(input1);
104-
auto sv2 = cudf::strings_column_view(input2);
105-
auto offsets_size = offsets->alloc_size();
106-
state.add_global_memory_reads<nvbench::int8_t>(chars_size + 2 * offsets_size);
58+
state.add_global_memory_reads<nvbench::int8_t>(input1->alloc_size() + input2->alloc_size());
10759
// output are integers (one per row)
10860
state.add_global_memory_writes<nvbench::int32_t>(num_rows);
10961

0 commit comments

Comments
 (0)