Skip to content

Commit ef38782

Browse files
authored
Merge pull request #50 from sirius-db/type_decimal
Support basic usage of decimal type.
2 parents 4e9e91a + 2240aea commit ef38782

13 files changed

Lines changed: 371 additions & 19 deletions

src/cuda/expression_executor/gpu_dispatch_materialize.cu

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,36 @@ struct MaterializeNumeric
4141
}
4242
};
4343

44+
//----------Decimals----------//
45+
template <typename T>
46+
struct MaterializeDecimal
47+
{
48+
static std::unique_ptr<cudf::column> Do(const T* input_data,
49+
const uint64_t* row_ids,
50+
uint64_t row_id_count,
51+
const cudf::data_type& cudf_type,
52+
rmm::device_async_resource_ref mr,
53+
rmm::cuda_stream_view stream = rmm::cuda_stream_default)
54+
{
55+
// Define the thrust execution policy
56+
rmm::mr::thrust_allocator<uint8_t> thrust_allocator(stream, mr);
57+
auto exec = thrust::cuda::par(thrust_allocator).on(stream);
58+
59+
// Allocate output buffer
60+
rmm::device_uvector<T> output_data(row_id_count, stream, mr);
61+
62+
// Gather the input data
63+
thrust::gather(exec, row_ids, row_ids + row_id_count, input_data, output_data.begin());
64+
65+
// Construct and return a cudf::column
66+
return std::make_unique<cudf::column>(cudf_type,
67+
static_cast<cudf::size_type>(row_id_count),
68+
output_data.release(),
69+
rmm::device_buffer(0, stream, mr),
70+
0);
71+
}
72+
};
73+
4474
//----------Strings----------//
4575
struct MaterializeString
4676
{
@@ -214,6 +244,34 @@ std::unique_ptr<cudf::column> GpuDispatcher::DispatchMaterialize(const GPUColumn
214244
input->row_id_count,
215245
mr,
216246
stream);
247+
case GPUColumnTypeId::DECIMAL: {
248+
switch (input->data_wrapper.getColumnTypeSize()) {
249+
case sizeof(int32_t): {
250+
// cudf decimal type uses negative scale, same for below
251+
cudf::data_type cudf_type(cudf::type_id::DECIMAL32,
252+
-input->data_wrapper.type.GetDecimalTypeInfo()->scale_);
253+
return MaterializeDecimal<int32_t>::Do(reinterpret_cast<const int32_t*>(input_data),
254+
input->row_ids,
255+
input->row_id_count,
256+
cudf_type,
257+
mr,
258+
stream);
259+
}
260+
case sizeof(int64_t): {
261+
cudf::data_type cudf_type(cudf::type_id::DECIMAL64,
262+
-input->data_wrapper.type.GetDecimalTypeInfo()->scale_);
263+
return MaterializeDecimal<int64_t>::Do(reinterpret_cast<const int64_t*>(input_data),
264+
input->row_ids,
265+
input->row_id_count,
266+
cudf_type,
267+
mr,
268+
stream);
269+
}
270+
default:
271+
throw NotImplementedException("Unsupported sirius DECIMAL column type size in `Dispatch[Materialize]`: %zu",
272+
input->data_wrapper.getColumnTypeSize());
273+
}
274+
}
217275
default:
218276
throw InternalException("Unsupported sirius column type in `Dispatch[Materialize]`: %d",
219277
static_cast<int>(input->data_wrapper.type.id()));

src/cuda/operator/arbitrary_expression.cu

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ __global__ void table_scan_expression(uint8_t **col, uint64_t** offset, uint8_t
131131
for (int expr = 0; expr < num_expr; expr++) {
132132
if (threadIdx.x + ITEM * B < num_tile_items) {
133133

134-
if (data_type[expr] == INT32 || data_type[expr] == DATE) {
134+
if (data_type[expr] == INT32 || data_type[expr] == DATE || data_type[expr] == DECIMAL32) {
135135
uint64_t item_idx = tile_offset + threadIdx.x + ITEM * B;
136136
int item = (reinterpret_cast<int*>(col[expr]))[item_idx];
137137

@@ -141,15 +141,15 @@ __global__ void table_scan_expression(uint8_t **col, uint64_t** offset, uint8_t
141141

142142
selection_flags[ITEM] = device_comparison<int>(item, constant, compare_mode[expr]);
143143

144-
} else if (data_type[expr] == INT64) {
144+
} else if (data_type[expr] == INT64 || data_type[expr] == DECIMAL64) {
145145
uint64_t item_idx = tile_offset + threadIdx.x + ITEM * B;
146-
uint64_t item = (reinterpret_cast<uint64_t*>(col[expr]))[item_idx];
146+
int64_t item = (reinterpret_cast<int64_t*>(col[expr]))[item_idx];
147147

148148
uint64_t start_constant_offset = constant_offset[expr];
149-
uint64_t constant;
150-
memcpy(&constant, constant_compare + start_constant_offset, sizeof(uint64_t));
149+
int64_t constant;
150+
memcpy(&constant, constant_compare + start_constant_offset, sizeof(int64_t));
151151

152-
selection_flags[ITEM] = device_comparison<uint64_t>(item, constant, compare_mode[expr]);
152+
selection_flags[ITEM] = device_comparison<int64_t>(item, constant, compare_mode[expr]);
153153

154154
} else if (data_type[expr] == FLOAT32) {
155155
uint64_t item_idx = tile_offset + threadIdx.x + ITEM * B;

src/cuda/operator/materialize.cu

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ template
6060
__global__ void materialize_expression<double, BLOCK_THREADS, ITEMS_PER_THREAD>(const double *a, double* result, uint64_t *row_ids, uint64_t N);
6161
template
6262
__global__ void materialize_expression<uint8_t, BLOCK_THREADS, ITEMS_PER_THREAD>(const uint8_t *a, uint8_t* result, uint64_t *row_ids, uint64_t N);
63+
template
64+
__global__ void materialize_expression<int64_t, BLOCK_THREADS, ITEMS_PER_THREAD>(const int64_t *a, int64_t* result, uint64_t *row_ids, uint64_t N);
6365

6466
template <typename T>
6567
void materializeExpression(T *a, T*& result, uint64_t *row_ids, uint64_t result_len, uint64_t input_len) {
@@ -189,5 +191,7 @@ template
189191
void materializeExpression<double>(double *a, double*& result, uint64_t *row_ids, uint64_t result_len, uint64_t input_size);
190192
template
191193
void materializeExpression<uint8_t>(uint8_t *a, uint8_t*& result, uint64_t *row_ids, uint64_t result_len, uint64_t input_size);
194+
template
195+
void materializeExpression<int64_t>(int64_t *a, int64_t*& result, uint64_t *row_ids, uint64_t result_len, uint64_t input_size);
192196

193197
} // namespace duckdb

src/expression_executor/gpu_expression_executor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ void GpuExpressionExecutor::Execute(const GPUIntermediateRelation& input_relatio
198198
if (result->type().id() != cudf_return_type.id())
199199
{
200200
result =
201-
cudf::cast(result->view(), cudf_return_type, cudf::get_default_stream(), resource_ref);
201+
cudf::cast(result->view(), cudf_return_type, execution_stream, resource_ref);
202202
}
203203

204204
// Transfer to output relation (zero copy)

src/expression_executor/specializations/gpu_execute_function.cpp

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ struct NumericBinaryFunctionDispatcher
149149
: executor(exec)
150150
{}
151151

152-
// Left scalar binary operator
152+
// Left scalar binary operator for numeric types
153153
template <typename T>
154154
std::unique_ptr<cudf::column> DoLeftScalarBinaryOp(const T& left_value,
155155
const cudf::column_view& right,
@@ -165,7 +165,24 @@ struct NumericBinaryFunctionDispatcher
165165
executor.resource_ref);
166166
}
167167

168-
// Right scalar binary operator
168+
// Left scalar binary operator for decimal types
169+
template <typename T>
170+
std::unique_ptr<cudf::column> DoLeftScalarBinaryOp(typename T::rep left_value,
171+
numeric::scale_type scale,
172+
const cudf::column_view& right,
173+
const cudf::data_type& return_type)
174+
{
175+
auto left_decimal_scalar = cudf::fixed_point_scalar<T>(
176+
left_value, scale, true, executor.execution_stream, executor.resource_ref);
177+
return cudf::binary_operation(left_decimal_scalar,
178+
right,
179+
BinOp,
180+
return_type,
181+
executor.execution_stream,
182+
executor.resource_ref);
183+
}
184+
185+
// Right scalar binary operator for numeric types
169186
template <typename T>
170187
std::unique_ptr<cudf::column> DoRightScalarBinaryOp(const cudf::column_view& left,
171188
const T& right_value,
@@ -181,6 +198,23 @@ struct NumericBinaryFunctionDispatcher
181198
executor.resource_ref);
182199
}
183200

201+
// Right scalar binary operator for decimal types
202+
template <typename T>
203+
std::unique_ptr<cudf::column> DoRightScalarBinaryOp(const cudf::column_view& left,
204+
typename T::rep right_value,
205+
numeric::scale_type scale,
206+
const cudf::data_type& return_type)
207+
{
208+
auto right_decimal_scalar = cudf::fixed_point_scalar<T>(
209+
right_value, scale, true, executor.execution_stream, executor.resource_ref);
210+
return cudf::binary_operation(left,
211+
right_decimal_scalar,
212+
BinOp,
213+
return_type,
214+
executor.execution_stream,
215+
executor.resource_ref);
216+
}
217+
184218
// Dispatch operator
185219
std::unique_ptr<cudf::column> operator()(const BoundFunctionExpression& expr,
186220
GpuExpressionState* state)
@@ -205,6 +239,17 @@ struct NumericBinaryFunctionDispatcher
205239
return DoLeftScalarBinaryOp(left_value.GetValue<float_t>(), right->view(), return_type);
206240
case cudf::type_id::FLOAT64:
207241
return DoLeftScalarBinaryOp(left_value.GetValue<double_t>(), right->view(), return_type);
242+
case cudf::type_id::DECIMAL32:
243+
// cudf decimal type uses negative scale, same for below
244+
return DoLeftScalarBinaryOp<numeric::decimal32>(
245+
left_value.GetValueUnsafe<int32_t>(),
246+
numeric::scale_type{-duckdb::DecimalType::GetScale(left_value.type())},
247+
right->view(), return_type);
248+
case cudf::type_id::DECIMAL64:
249+
return DoLeftScalarBinaryOp<numeric::decimal64>(
250+
left_value.GetValueUnsafe<int64_t>(),
251+
numeric::scale_type{-duckdb::DecimalType::GetScale(left_value.type())},
252+
right->view(), return_type);
208253
case cudf::type_id::BOOL8:
209254
throw NotImplementedException("Execute[Function]: Boolean types not supported for "
210255
"numeric binary operations!");
@@ -229,6 +274,17 @@ struct NumericBinaryFunctionDispatcher
229274
return DoRightScalarBinaryOp(left->view(), right_value.GetValue<float_t>(), return_type);
230275
case cudf::type_id::FLOAT64:
231276
return DoRightScalarBinaryOp(left->view(), right_value.GetValue<double_t>(), return_type);
277+
case cudf::type_id::DECIMAL32:
278+
// cudf decimal type uses negative scale, same for below
279+
return DoRightScalarBinaryOp<numeric::decimal32>(
280+
left->view(), right_value.GetValueUnsafe<int32_t>(),
281+
numeric::scale_type{-duckdb::DecimalType::GetScale(right_value.type())},
282+
return_type);
283+
case cudf::type_id::DECIMAL64:
284+
return DoRightScalarBinaryOp<numeric::decimal64>(
285+
left->view(), right_value.GetValueUnsafe<int64_t>(),
286+
numeric::scale_type{-duckdb::DecimalType::GetScale(right_value.type())},
287+
return_type);
232288
case cudf::type_id::BOOL8:
233289
throw NotImplementedException("Execute[Function]: Boolean types not supported for "
234290
"numeric binary operations!");

src/gpu_buffer_manager.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ GPUBufferManager::customCudaMalloc<int>(size_t size, int gpu, bool caching);
1818
template uint64_t*
1919
GPUBufferManager::customCudaMalloc<uint64_t>(size_t size, int gpu, bool caching);
2020

21+
template int64_t*
22+
GPUBufferManager::customCudaMalloc<int64_t>(size_t size, int gpu, bool caching);
23+
2124
template uint8_t*
2225
GPUBufferManager::customCudaMalloc<uint8_t>(size_t size, int gpu, bool caching);
2326

src/gpu_columns.cpp

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
#include "gpu_columns.hpp"
22
#include "gpu_buffer_manager.hpp"
33
#include "log/logging.hpp"
4+
#include "duckdb/common/types/decimal.hpp"
45

56
namespace duckdb {
67

8+
size_t GPUDecimalTypeInfo::GetDecimalTypeSize() const {
9+
if (width_ <= Decimal::MAX_WIDTH_INT16) {
10+
return sizeof(int16_t);
11+
} else if (width_ <= Decimal::MAX_WIDTH_INT32) {
12+
return sizeof(int32_t);
13+
} else if (width_ <= Decimal::MAX_WIDTH_INT64) {
14+
return sizeof(int64_t);
15+
} else if (width_ <= Decimal::MAX_WIDTH_INT128) {
16+
return sizeof(__int128_t);
17+
} else {
18+
throw InternalException("Decimal has a width of %d which is bigger than the maximum supported width of %d",
19+
width_, DecimalType::MaxWidth());
20+
}
21+
}
22+
723
DataWrapper::DataWrapper(GPUColumnType _type, uint8_t* _data, size_t _size) : data(_data), size(_size) {
824
type = _type;
925
num_bytes = size * getColumnTypeSize();
@@ -14,7 +30,7 @@ DataWrapper::DataWrapper(GPUColumnType _type, uint8_t* _data, uint64_t* _offset,
1430
data(_data), size(_size), type(_type), offset(_offset), num_bytes(_num_bytes), is_string_data(_is_string_data) {};
1531

1632
size_t
17-
DataWrapper::getColumnTypeSize() {
33+
DataWrapper::getColumnTypeSize() const {
1834
switch (type.id()) {
1935
case GPUColumnTypeId::INT32:
2036
case GPUColumnTypeId::DATE:
@@ -31,6 +47,13 @@ DataWrapper::getColumnTypeSize() {
3147
return sizeof(uint8_t);
3248
case GPUColumnTypeId::VARCHAR:
3349
return 128;
50+
case GPUColumnTypeId::DECIMAL: {
51+
GPUDecimalTypeInfo* decimal_type_info = type.GetDecimalTypeInfo();
52+
if (decimal_type_info == nullptr) {
53+
throw InternalException("`decimal_type_info` not set for DECIMAL type in `getColumnTypeSize`");
54+
}
55+
return decimal_type_info->GetDecimalTypeSize();
56+
}
3457
default:
3558
throw duckdb::InternalException("Unsupported sirius column type in `getColumnTypeSize()`: %d",
3659
static_cast<int>(type.id()));
@@ -114,6 +137,23 @@ GPUColumn::convertToCudfColumn() {
114137
std::move(children)
115138
);
116139
return str_col;
140+
} else if (data_wrapper.type.id() == GPUColumnTypeId::DECIMAL) {
141+
cudf::data_type cudf_type;
142+
switch (data_wrapper.getColumnTypeSize()) {
143+
case sizeof(int32_t): {
144+
// cudf decimal type uses negative scale, same for below
145+
cudf_type = cudf::data_type(cudf::type_id::DECIMAL32, -data_wrapper.type.GetDecimalTypeInfo()->scale_);
146+
break;
147+
}
148+
case sizeof(int64_t): {
149+
cudf_type = cudf::data_type(cudf::type_id::DECIMAL64, -data_wrapper.type.GetDecimalTypeInfo()->scale_);
150+
break;
151+
}
152+
default:
153+
throw duckdb::InternalException("Unsupported sirius DECIMAL column type size in `convertToCudfColumn()`: %zu",
154+
data_wrapper.getColumnTypeSize());
155+
}
156+
return cudf::column_view(cudf_type, size, reinterpret_cast<void*>(data_wrapper.data), nullptr, 0);
117157
}
118158
throw duckdb::InternalException("Unsupported sirius column type in `convertToCudfColumn()`: %d", data_wrapper.type.id());
119159
}
@@ -179,6 +219,27 @@ GPUColumn::setFromCudfColumn(cudf::column& cudf_column, bool _is_unique, int32_t
179219
data_wrapper.type = GPUColumnType(GPUColumnTypeId::BOOLEAN);
180220
data_wrapper.num_bytes = col_size * data_wrapper.getColumnTypeSize();
181221
data_wrapper.offset = nullptr;
222+
} else if (col_type == cudf::data_type(cudf::type_id::TIMESTAMP_DAYS)) {
223+
data_wrapper.is_string_data = false;
224+
data_wrapper.type = GPUColumnType(GPUColumnTypeId::DATE);
225+
data_wrapper.num_bytes = col_size * data_wrapper.getColumnTypeSize();
226+
data_wrapper.offset = nullptr;
227+
} else if (col_type.id() == cudf::type_id::DECIMAL32) {
228+
data_wrapper.is_string_data = false;
229+
data_wrapper.type = GPUColumnType(GPUColumnTypeId::DECIMAL);
230+
// cudf decimal type uses negative scale, same for below
231+
data_wrapper.type.SetDecimalTypeInfo(Decimal::MAX_WIDTH_INT32, -col_type.scale());
232+
data_wrapper.num_bytes = col_size * data_wrapper.getColumnTypeSize();
233+
data_wrapper.offset = nullptr;
234+
} else if (col_type.id() == cudf::type_id::DECIMAL64) {
235+
data_wrapper.is_string_data = false;
236+
data_wrapper.type = GPUColumnType(GPUColumnTypeId::DECIMAL);
237+
data_wrapper.type.SetDecimalTypeInfo(Decimal::MAX_WIDTH_INT64, -col_type.scale());
238+
data_wrapper.num_bytes = col_size * data_wrapper.getColumnTypeSize();
239+
data_wrapper.offset = nullptr;
240+
} else {
241+
throw NotImplementedException("Unsupported cudf data type in `setFromCudfColumn`: %d",
242+
static_cast<int>(col_type.id()));
182243
}
183244

184245
if (_row_ids != nullptr) {
@@ -224,6 +285,24 @@ GPUColumn::setFromCudfScalar(cudf::scalar& cudf_scalar, GPUBufferManager* gpuBuf
224285
callCudaMemcpyDeviceToDevice<uint8_t>(data_wrapper.data, reinterpret_cast<uint8_t*>(typed_scalar.data()), sizeof(uint8_t), 0);
225286
data_wrapper.type = GPUColumnType(GPUColumnTypeId::BOOLEAN);
226287
data_wrapper.num_bytes = sizeof(uint8_t);
288+
} else if (scalar_type.id() == cudf::type_id::DECIMAL32){
289+
auto& typed_scalar = static_cast<cudf::fixed_point_scalar<numeric::decimal32>&>(cudf_scalar);
290+
data_wrapper.data = gpuBufferManager->customCudaMalloc<uint8_t>(sizeof(int32_t), 0, 0);
291+
callCudaMemcpyDeviceToDevice<uint8_t>(data_wrapper.data, reinterpret_cast<uint8_t*>(typed_scalar.data()), sizeof(int32_t), 0);
292+
data_wrapper.type = GPUColumnType(GPUColumnTypeId::DECIMAL);
293+
// cudf decimal type uses negative scale, same for below
294+
data_wrapper.type.SetDecimalTypeInfo(Decimal::MAX_WIDTH_INT32, -typed_scalar.type().scale());
295+
data_wrapper.num_bytes = sizeof(int32_t);
296+
} else if (scalar_type.id() == cudf::type_id::DECIMAL64){
297+
auto& typed_scalar = static_cast<cudf::fixed_point_scalar<numeric::decimal64>&>(cudf_scalar);
298+
data_wrapper.data = gpuBufferManager->customCudaMalloc<uint8_t>(sizeof(int64_t), 0, 0);
299+
callCudaMemcpyDeviceToDevice<uint8_t>(data_wrapper.data, reinterpret_cast<uint8_t*>(typed_scalar.data()), sizeof(int64_t), 0);
300+
data_wrapper.type = GPUColumnType(GPUColumnTypeId::DECIMAL);
301+
data_wrapper.type.SetDecimalTypeInfo(Decimal::MAX_WIDTH_INT64, -typed_scalar.type().scale());
302+
data_wrapper.num_bytes = sizeof(int64_t);
303+
} else {
304+
throw NotImplementedException("Unsupported cudf data type in `setFromCudfScalar`: %d",
305+
static_cast<int>(scalar_type.id()));
227306
}
228307

229308
data_wrapper.size = 1;

0 commit comments

Comments
 (0)