Skip to content

Commit ea9b2cb

Browse files
authored
Merge branch 'main' into ref/cudf/all_characters_of_type
2 parents fb5dc8f + bc7710a commit ea9b2cb

File tree

17 files changed

+253
-177
lines changed

17 files changed

+253
-177
lines changed

cpp/benchmarks/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
find_package(Threads REQUIRED)
99

10-
add_library(cudf_datagen STATIC common/generate_input.cu)
10+
add_library(cudf_datagen STATIC common/generate_input.cu common/generate_nested_types.cpp)
1111
target_compile_features(cudf_datagen PUBLIC cxx_std_20 cuda_std_20)
1212

1313
target_compile_options(
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "generate_nested_types.hpp"
7+
8+
#include "generate_input.hpp"
9+
10+
#include <cudf_test/column_wrapper.hpp>
11+
12+
#include <algorithm>
13+
#include <random>
14+
#include <vector>
15+
16+
std::unique_ptr<cudf::table> create_lists_data(nvbench::state& state,
17+
cudf::size_type const num_columns,
18+
cudf::size_type const min_val,
19+
cudf::size_type const max_val)
20+
{
21+
size_t const size_bytes(state.get_int64("size_bytes"));
22+
cudf::size_type const depth{static_cast<cudf::size_type>(state.get_int64("depth"))};
23+
auto const null_frequency{state.get_float64("null_frequency")};
24+
25+
data_profile table_profile;
26+
table_profile.set_distribution_params(
27+
cudf::type_id::LIST, distribution_id::UNIFORM, min_val, max_val);
28+
table_profile.set_list_depth(depth);
29+
table_profile.set_null_probability(null_frequency);
30+
return create_random_table(std::vector<cudf::type_id>(num_columns, cudf::type_id::LIST),
31+
table_size_bytes{size_bytes},
32+
table_profile);
33+
}
34+
35+
std::unique_ptr<cudf::table> create_structs_data(nvbench::state& state,
36+
cudf::size_type const n_cols)
37+
{
38+
using Type = int;
39+
using column_wrapper = cudf::test::fixed_width_column_wrapper<Type>;
40+
std::default_random_engine generator;
41+
std::uniform_int_distribution<int> distribution(0, 100);
42+
43+
cudf::size_type const n_rows{static_cast<cudf::size_type>(state.get_int64("NumRows"))};
44+
cudf::size_type const depth{static_cast<cudf::size_type>(state.get_int64("Depth"))};
45+
bool const nulls{static_cast<bool>(state.get_int64("Nulls"))};
46+
47+
// Create columns with values in the range [0,100)
48+
std::vector<column_wrapper> columns;
49+
columns.reserve(n_cols);
50+
std::generate_n(std::back_inserter(columns), n_cols, [&]() {
51+
auto const elements = cudf::detail::make_counting_transform_iterator(
52+
0, [&](auto row) { return distribution(generator); });
53+
if (!nulls) return column_wrapper(elements, elements + n_rows);
54+
auto valids =
55+
cudf::detail::make_counting_transform_iterator(0, [](auto i) { return i % 10 != 0; });
56+
return column_wrapper(elements, elements + n_rows, valids);
57+
});
58+
59+
std::vector<std::unique_ptr<cudf::column>> cols;
60+
std::transform(columns.begin(), columns.end(), std::back_inserter(cols), [](column_wrapper& col) {
61+
return col.release();
62+
});
63+
64+
std::vector<std::unique_ptr<cudf::column>> child_cols = std::move(cols);
65+
// Nest the child columns in a struct, then nest that struct column inside another
66+
// struct column up to the desired depth
67+
for (int i = 0; i < depth; i++) {
68+
std::vector<bool> struct_validity;
69+
std::uniform_int_distribution<int> bool_distribution(0, 100 * (i + 1));
70+
std::generate_n(
71+
std::back_inserter(struct_validity), n_rows, [&]() { return bool_distribution(generator); });
72+
cudf::test::structs_column_wrapper struct_col(std::move(child_cols), struct_validity);
73+
child_cols = std::vector<std::unique_ptr<cudf::column>>{};
74+
child_cols.push_back(struct_col.release());
75+
}
76+
77+
// Create table view
78+
return std::make_unique<cudf::table>(std::move(child_cols));
79+
}
Lines changed: 9 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,19 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2023, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

66
#pragma once
77

8-
#include "generate_input.hpp"
8+
#include <cudf/table/table.hpp>
9+
#include <cudf/types.hpp>
910

10-
#include <cudf_test/column_wrapper.hpp>
11-
12-
// This error appears in GCC 11.3 and may be a compiler bug or nvbench bug.
13-
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1411
#include <nvbench/nvbench.cuh>
15-
#pragma GCC diagnostic pop
16-
17-
#include <random>
18-
19-
inline std::unique_ptr<cudf::table> create_lists_data(nvbench::state& state,
20-
cudf::size_type const num_columns = 1,
21-
cudf::size_type const min_val = 0,
22-
cudf::size_type const max_val = 5)
23-
{
24-
size_t const size_bytes(state.get_int64("size_bytes"));
25-
cudf::size_type const depth{static_cast<cudf::size_type>(state.get_int64("depth"))};
26-
auto const null_frequency{state.get_float64("null_frequency")};
27-
28-
data_profile table_profile;
29-
table_profile.set_distribution_params(
30-
cudf::type_id::LIST, distribution_id::UNIFORM, min_val, max_val);
31-
table_profile.set_list_depth(depth);
32-
table_profile.set_null_probability(null_frequency);
33-
return create_random_table(std::vector<cudf::type_id>(num_columns, cudf::type_id::LIST),
34-
table_size_bytes{size_bytes},
35-
table_profile);
36-
}
37-
38-
inline std::unique_ptr<cudf::table> create_structs_data(nvbench::state& state,
39-
cudf::size_type const n_cols = 1)
40-
{
41-
using Type = int;
42-
using column_wrapper = cudf::test::fixed_width_column_wrapper<Type>;
43-
std::default_random_engine generator;
44-
std::uniform_int_distribution<int> distribution(0, 100);
45-
46-
cudf::size_type const n_rows{static_cast<cudf::size_type>(state.get_int64("NumRows"))};
47-
cudf::size_type const depth{static_cast<cudf::size_type>(state.get_int64("Depth"))};
48-
bool const nulls{static_cast<bool>(state.get_int64("Nulls"))};
49-
50-
// Create columns with values in the range [0,100)
51-
std::vector<column_wrapper> columns;
52-
columns.reserve(n_cols);
53-
std::generate_n(std::back_inserter(columns), n_cols, [&]() {
54-
auto const elements = cudf::detail::make_counting_transform_iterator(
55-
0, [&](auto row) { return distribution(generator); });
56-
if (!nulls) return column_wrapper(elements, elements + n_rows);
57-
auto valids =
58-
cudf::detail::make_counting_transform_iterator(0, [](auto i) { return i % 10 != 0; });
59-
return column_wrapper(elements, elements + n_rows, valids);
60-
});
61-
62-
std::vector<std::unique_ptr<cudf::column>> cols;
63-
std::transform(columns.begin(), columns.end(), std::back_inserter(cols), [](column_wrapper& col) {
64-
return col.release();
65-
});
6612

67-
std::vector<std::unique_ptr<cudf::column>> child_cols = std::move(cols);
68-
// Nest the child columns in a struct, then nest that struct column inside another
69-
// struct column up to the desired depth
70-
for (int i = 0; i < depth; i++) {
71-
std::vector<bool> struct_validity;
72-
std::uniform_int_distribution<int> bool_distribution(0, 100 * (i + 1));
73-
std::generate_n(
74-
std::back_inserter(struct_validity), n_rows, [&]() { return bool_distribution(generator); });
75-
cudf::test::structs_column_wrapper struct_col(std::move(child_cols), struct_validity);
76-
child_cols = std::vector<std::unique_ptr<cudf::column>>{};
77-
child_cols.push_back(struct_col.release());
78-
}
13+
std::unique_ptr<cudf::table> create_lists_data(nvbench::state& state,
14+
cudf::size_type const num_columns = 1,
15+
cudf::size_type const min_val = 0,
16+
cudf::size_type const max_val = 5);
7917

80-
// Create table view
81-
return std::make_unique<cudf::table>(std::move(child_cols));
82-
}
18+
std::unique_ptr<cudf::table> create_structs_data(nvbench::state& state,
19+
cudf::size_type const n_cols = 1);

cpp/benchmarks/sort/sort_lists.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2022-2025, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

66
#include <benchmarks/common/generate_nested_types.hpp>
77

8-
#include <cudf/detail/sorting.hpp>
8+
#include <cudf/lists/lists_column_view.hpp>
9+
#include <cudf/sorting.hpp>
910
#include <cudf/utilities/memory_resource.hpp>
1011

1112
#include <nvbench/nvbench.cuh>
@@ -22,8 +23,7 @@ void sort_multiple_lists(nvbench::state& state)
2223

2324
state.set_cuda_stream(nvbench::make_cuda_stream_view(stream.value()));
2425
state.exec(nvbench::exec_tag::sync, [&](nvbench::launch& launch) {
25-
cudf::detail::sorted_order(
26-
*input_table, {}, {}, stream, cudf::get_current_device_resource_ref());
26+
cudf::sorted_order(*input_table, {}, {}, stream, cudf::get_current_device_resource_ref());
2727
});
2828
}
2929

@@ -66,8 +66,7 @@ void sort_lists_of_structs(nvbench::state& state)
6666
state.set_cuda_stream(nvbench::make_cuda_stream_view(stream.value()));
6767
state.exec(nvbench::exec_tag::sync, [&](nvbench::launch& launch) {
6868
rmm::cuda_stream_view stream_view{launch.get_stream()};
69-
cudf::detail::sorted_order(
70-
input_table, {}, {}, stream, cudf::get_current_device_resource_ref());
69+
cudf::sorted_order(input_table, {}, {}, stream, cudf::get_current_device_resource_ref());
7170
});
7271
}
7372

@@ -85,7 +84,7 @@ void nvbench_sort_lists(nvbench::state& state)
8584

8685
NVBENCH_BENCH(nvbench_sort_lists)
8786
.set_name("sort_list")
88-
.add_int64_power_of_two_axis("size_bytes", {10, 18, 24, 28})
87+
.add_int64_power_of_two_axis("size_bytes", {18, 24, 28})
8988
.add_int64_axis("depth", {1, 4})
9089
.add_int64_axis("num_columns", {1})
9190
.add_int64_axis("lists_of_structs", {0, 1})

cpp/benchmarks/sort/sort_structs.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

66
#include <benchmarks/common/generate_nested_types.hpp>
77

8-
#include <cudf/detail/sorting.hpp>
8+
#include <cudf/sorting.hpp>
99
#include <cudf/utilities/memory_resource.hpp>
1010

1111
#include <nvbench/nvbench.cuh>
@@ -16,8 +16,7 @@ void nvbench_sort_struct(nvbench::state& state)
1616

1717
state.exec(nvbench::exec_tag::sync, [&](nvbench::launch& launch) {
1818
rmm::cuda_stream_view stream_view{launch.get_stream()};
19-
cudf::detail::sorted_order(
20-
*input, {}, {}, stream_view, cudf::get_current_device_resource_ref());
19+
cudf::sorted_order(*input, {}, {}, stream_view, cudf::get_current_device_resource_ref());
2120
});
2221
}
2322

python/cudf/cudf/core/column/categorical.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ class CategoricalColumn(column.ColumnBase):
7979
plc.TypeId.UINT64,
8080
}
8181

82+
@staticmethod
83+
def _validate_dtype_to_plc_column(
84+
plc_column: plc.Column, dtype: DtypeObj
85+
) -> None:
86+
"""Validate that the dtype matches the equivalent type of the plc_column"""
87+
return None
88+
8289
@classmethod
8390
def _validate_args( # type: ignore[override]
8491
cls, plc_column: plc.Column, dtype: CategoricalDtype
@@ -343,6 +350,15 @@ def _cast_self_and_other_for_where(
343350

344351
return self.codes, other
345352

353+
def where(
354+
self, cond: ColumnBase, other: ScalarLike | ColumnBase, inplace: bool
355+
) -> ColumnBase:
356+
casted_col, casted_other = self._cast_self_and_other_for_where(
357+
other, inplace
358+
)
359+
result = casted_col.copy_if_else(casted_other, cond) # type: ignore[arg-type]
360+
return column.ColumnBase.create(result.plc_column, self.dtype)
361+
346362
def _encode(self, value: ScalarLike) -> ScalarLike:
347363
return self.categories.find_first_value(value)
348364

python/cudf/cudf/core/column/column.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,17 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
330330
"ColumnBase and its subclasses must be instantiated via from_pylibcudf."
331331
)
332332

333+
@staticmethod
334+
def _validate_dtype_to_plc_column(
335+
plc_column: plc.Column, dtype: DtypeObj
336+
) -> None:
337+
"""Validate that the dtype matches the equivalent type of the plc_column"""
338+
if dtype_to_pylibcudf_type(dtype) != plc_column.type():
339+
# TODO: Override ListColumn, StructColumn, IntervalColumn to also validate children
340+
raise ValueError(
341+
f"dtype {dtype} does not match the type of the plc_column {plc_column.type().id()}"
342+
)
343+
333344
@classmethod
334345
def _validate_args(
335346
cls, plc_column: plc.Column, dtype: DtypeObj
@@ -342,6 +353,7 @@ def _validate_args(
342353
raise ValueError(
343354
f"plc_column must be a pylibcudf.Column with a TypeId in {cls._VALID_PLC_TYPES}"
344355
)
356+
cls._validate_dtype_to_plc_column(plc_column, dtype)
345357
return plc_column, dtype
346358

347359
@property
@@ -1147,9 +1159,9 @@ def from_arrow(cls, array: pa.Array | pa.ChunkedArray) -> ColumnBase:
11471159
)
11481160
)
11491161
else:
1150-
result = cls.from_pylibcudf(plc.Column.from_arrow(array))
1151-
return result._with_type_metadata(
1152-
cudf_dtype_from_pa_type(array.type)
1162+
return cls.create(
1163+
plc.Column.from_arrow(array),
1164+
cudf_dtype_from_pa_type(array.type),
11531165
)
11541166

11551167
def _get_mask_as_column(self) -> ColumnBase:
@@ -2606,24 +2618,23 @@ def _reduce(
26062618
aggregation.make_aggregation(op, kwargs).plc_obj,
26072619
dtype_to_pylibcudf_type(col_dtype),
26082620
)
2621+
# Hook for subclasses (e.g., DecimalBaseColumn adjusts precision)
2622+
col_dtype = col._adjust_reduce_result_dtype(
2623+
op, col_dtype, plc_scalar
2624+
)
26092625
result_col = ColumnBase.create(
26102626
plc.Column.from_scalar(plc_scalar, 1), col_dtype
26112627
)
2612-
# Hook for subclasses (e.g., DecimalBaseColumn adjusts precision)
2613-
result_col = col._adjust_reduce_result(
2614-
result_col, op, col_dtype, plc_scalar
2615-
)
26162628
return result_col.element_indexing(0)
26172629

2618-
def _adjust_reduce_result(
2630+
def _adjust_reduce_result_dtype(
26192631
self,
2620-
result_col: ColumnBase,
26212632
op: str,
26222633
col_dtype: DtypeObj,
26232634
plc_scalar: plc.Scalar,
2624-
) -> ColumnBase:
2635+
) -> DtypeObj:
26252636
"""Hook for subclasses to adjust reduction result."""
2626-
return result_col
2637+
return col_dtype
26272638

26282639
def minmax(self) -> tuple[ScalarLike, ScalarLike]:
26292640
with self.access(mode="read", scope="internal"):
@@ -2788,7 +2799,7 @@ def where(
27882799
other, inplace
27892800
)
27902801
result = casted_col.copy_if_else(casted_other, cond) # type: ignore[arg-type]
2791-
return ColumnBase.create(result.plc_column, self.dtype)
2802+
return ColumnBase.create(result.plc_column, casted_col.dtype)
27922803

27932804

27942805
def column_empty(

0 commit comments

Comments
 (0)