This is an automated email from the ASF dual-hosted git repository.
zclll pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new b082105d22a [env](compiler)educe template instantiations in datetime
floor/ceil functions (#61515)
b082105d22a is described below
commit b082105d22ac45364d9fd0d33cc8daf7ac3f8da1
Author: Mryange <[email protected]>
AuthorDate: Wed Mar 25 10:23:32 2026 +0800
[env](compiler)educe template instantiations in datetime floor/ceil
functions (#61515)
`function_datetime_floor_ceil.cpp` has excessive template instantiation
bloat. The class `FunctionDateTimeFloorCeil<Flag, PType, ArgNum,
UseDelta>` has 4 template parameters, producing 192 instantiations.
However, all heavy computation functions (9 `vector_*` variants,
`time_round_two_args`, `floor_opt`, etc.) only depend on `Flag` and
`PType` โ they never use `ArgNum` or `UseDelta`. This means these
expensive functions are compiled 4x more than necessary.
This PR applies three optimizations:
1. **Extract `DateTimeFloorCeilCore<Flag, PType>` struct**: All heavy
computation functions are moved into a separate struct with only 2
template parameters. `FunctionDateTimeFloorCeil` becomes a thin shell
that delegates to `Core::vector_*()`. This reduces instantiations of the
heaviest code from **192 โ 48** (รท4).
2. **Extract `convert_utc_to_local_impl<DateValueType>` free function**:
This function only depends on `DateValueType`, not
`Flag`/`ArgNum`/`UseDelta`. Extracting it reduces its instantiations
from 192 โ 3.
3. **Extract `FunctionDateTimeFloorCeilBase` non-template base class**:
Three virtual overrides (`get_number_of_arguments`, `is_variadic`,
`use_default_implementation_for_nulls`) use zero template parameters.
Moving them to a non-template base eliminates 192 redundant copies.
---
.../function/function_datetime_floor_ceil.cpp | 102 ++++++++++++---------
1 file changed, 59 insertions(+), 43 deletions(-)
diff --git a/be/src/exprs/function/function_datetime_floor_ceil.cpp
b/be/src/exprs/function/function_datetime_floor_ceil.cpp
index db9abb8941f..675af47a171 100644
--- a/be/src/exprs/function/function_datetime_floor_ceil.cpp
+++ b/be/src/exprs/function/function_datetime_floor_ceil.cpp
@@ -95,12 +95,41 @@ struct YearFloor;
#define CEIL 1
#endif
+// UTC to local time conversion - only depends on DateValueType, not all
template params
+template <typename DateValueType>
+void convert_utc_to_local_impl(const DateValueType& utc_val, DateValueType&
local_val,
+ const cctz::time_zone& tz) {
+ cctz::time_point<cctz::sys_seconds> utc_tp =
+ cctz::convert(cctz::civil_second(utc_val.year(), utc_val.month(),
utc_val.day(),
+ utc_val.hour(), utc_val.minute(),
utc_val.second()),
+ cctz::utc_time_zone());
+ auto local_cs = cctz::convert(utc_tp, tz);
+ local_val.unchecked_set_time(
+ static_cast<uint16_t>(local_cs.year()),
static_cast<uint8_t>(local_cs.month()),
+ static_cast<uint8_t>(local_cs.day()),
static_cast<uint8_t>(local_cs.hour()),
+ static_cast<uint8_t>(local_cs.minute()),
static_cast<uint8_t>(local_cs.second()),
+ utc_val.microsecond());
+}
+
+// Base class: non-template overrides shared by all instantiations
+class FunctionDateTimeFloorCeilBase : public IFunction {
+public:
+ size_t get_number_of_arguments() const override { return 0; }
+ bool is_variadic() const override { return true; }
+ bool use_default_implementation_for_nulls() const override { return false;
}
+};
+
+// Forward declaration of core computation struct (only depends on Flag +
PType)
+template <typename Flag, PrimitiveType PType>
+struct DateTimeFloorCeilCore;
+
template <typename Flag, PrimitiveType PType, int ArgNum, bool UseDelta =
false>
-class FunctionDateTimeFloorCeil : public IFunction {
+class FunctionDateTimeFloorCeil : public FunctionDateTimeFloorCeilBase {
public:
using DateType = typename PrimitiveTypeTraits<PType>::DataType;
using DateValueType = typename PrimitiveTypeTraits<PType>::CppType;
using DeltaDataType = DataTypeInt32;
+ using Core = DateTimeFloorCeilCore<Flag, PType>;
// return date type = DateType
static constexpr auto name = Flag::name;
@@ -108,12 +137,6 @@ public:
String get_name() const override { return name; }
- size_t get_number_of_arguments() const override { return 0; }
-
- bool is_variadic() const override { return true; }
-
- bool use_default_implementation_for_nulls() const override { return false;
}
-
DataTypePtr get_return_type_impl(const DataTypes& arguments) const
override {
return have_nullable(arguments) ?
make_nullable(std::make_shared<DateType>())
: std::make_shared<DateType>();
@@ -178,7 +201,7 @@ public:
col_to->resize(input_rows_count);
if constexpr (ArgNum == 1) {
- vector(sources->get_data(), col_to->get_data(), result_null_map,
context);
+ Core::vector(sources->get_data(), col_to->get_data(),
result_null_map, context);
} else if constexpr (ArgNum == 2) {
const IColumn& delta_column = *argument_columns[1];
if (col_const[1]) {
@@ -191,25 +214,26 @@ public:
if (period < 1 && !period_is_null) [[unlikely]] {
throw_out_of_bound_int(Flag::name, period);
}
- vector_const_period(sources->get_data(), period,
col_to->get_data(),
- result_null_map, context);
+ Core::vector_const_period(sources->get_data(), period,
col_to->get_data(),
+ result_null_map, context);
} else {
// time_round(datetime, const(origin))
- vector_const_anchor(sources->get_data(),
(*argument_columns[1])[0].get<PType>(),
- col_to->get_data(), result_null_map,
context);
+ Core::vector_const_anchor(sources->get_data(),
+
(*argument_columns[1])[0].get<PType>(),
+ col_to->get_data(),
result_null_map, context);
}
} else {
if (const auto* delta_vec_column0 =
check_and_get_column<ColumnVector<PType>>(delta_column)) {
// time_round(datetime, origin)
- vector_vector_anchor(sources->get_data(),
delta_vec_column0->get_data(),
- col_to->get_data(), result_null_map,
context);
+ Core::vector_vector_anchor(sources->get_data(),
delta_vec_column0->get_data(),
+ col_to->get_data(),
result_null_map, context);
} else {
const auto* delta_vec_column1 =
check_and_get_column<ColumnInt32>(delta_column);
DCHECK(delta_vec_column1 != nullptr);
// time_round(datetime, period)
- vector_vector_period(sources->get_data(),
delta_vec_column1->get_data(),
- col_to->get_data(), result_null_map,
context);
+ Core::vector_vector_period(sources->get_data(),
delta_vec_column1->get_data(),
+ col_to->get_data(),
result_null_map, context);
}
}
} else { // 3 arg, time_round(datetime, period, origin)
@@ -222,8 +246,8 @@ public:
if (period < 1 && !period_is_null) [[unlikely]] {
throw_out_of_bound_int(Flag::name, period);
}
- vector_const_const(sources->get_data(), period, origin,
col_to->get_data(),
- result_null_map, context);
+ Core::vector_const_const(sources->get_data(), period, origin,
col_to->get_data(),
+ result_null_map, context);
} else if (col_const[1] && !col_const[2]) {
const auto arg2_column =
check_and_get_column<ColumnVector<PType>>(*argument_columns[2]);
@@ -234,14 +258,14 @@ public:
if (period < 1 && !period_is_null) [[unlikely]] {
throw_out_of_bound_int(Flag::name, period);
}
- vector_const_vector(sources->get_data(), period,
arg2_column->get_data(),
- col_to->get_data(), result_null_map,
context);
+ Core::vector_const_vector(sources->get_data(), period,
arg2_column->get_data(),
+ col_to->get_data(), result_null_map,
context);
} else if (!col_const[1] && col_const[2]) {
const auto* arg1_column =
check_and_get_column<ColumnInt32>(*argument_columns[1]);
// time_round(datetime, period, const(origin))
- vector_vector_const(sources->get_data(),
arg1_column->get_data(),
- (*argument_columns[2])[0].get<PType>(),
col_to->get_data(),
- result_null_map, context);
+ Core::vector_vector_const(sources->get_data(),
arg1_column->get_data(),
+
(*argument_columns[2])[0].get<PType>(),
+ col_to->get_data(), result_null_map,
context);
} else {
const auto* arg1_column =
check_and_get_column<ColumnInt32>(*argument_columns[1]);
const auto arg2_column =
@@ -249,9 +273,9 @@ public:
DCHECK(arg1_column != nullptr);
DCHECK(arg2_column != nullptr);
// time_round(datetime, period, origin)
- vector_vector_vector(sources->get_data(),
arg1_column->get_data(),
- arg2_column->get_data(),
col_to->get_data(), result_null_map,
- context);
+ Core::vector_vector_vector(sources->get_data(),
arg1_column->get_data(),
+ arg2_column->get_data(),
col_to->get_data(),
+ result_null_map, context);
}
}
@@ -265,8 +289,14 @@ public:
return Status::OK();
}
+};
+
+// Core computation struct - only depends on Flag + PType (not
ArgNum/UseDelta).
+// This reduces template instantiations from 192 to 48 for all heavy
computation functions.
+template <typename Flag, PrimitiveType PType>
+struct DateTimeFloorCeilCore {
+ using DateValueType = typename PrimitiveTypeTraits<PType>::CppType;
-private:
static void vector(const PaddedPODArray<DateValueType>& dates,
PaddedPODArray<DateValueType>& res, const NullMap&
result_null_map,
FunctionContext* context) {
@@ -532,12 +562,12 @@ private:
const cctz::time_zone& tz = context->state()->timezone_obj();
if constexpr (need_tz_conversion) {
- convert_utc_to_local(ts_arg, local_arg, tz);
+ convert_utc_to_local_impl(ts_arg, local_arg, tz);
if (ts_origin == TimestampTzValue::FIRST_DAY) {
local_origin = ts_origin;
} else {
- convert_utc_to_local(ts_origin, local_origin, tz);
+ convert_utc_to_local_impl(ts_origin, local_origin, tz);
}
}
@@ -891,20 +921,6 @@ private:
}
}
}
-
- static void convert_utc_to_local(const DateValueType& utc_val,
DateValueType& local_val,
- const cctz::time_zone& tz) {
- cctz::time_point<cctz::sys_seconds> utc_tp = cctz::convert(
- cctz::civil_second(utc_val.year(), utc_val.month(),
utc_val.day(), utc_val.hour(),
- utc_val.minute(), utc_val.second()),
- cctz::utc_time_zone());
- auto local_cs = cctz::convert(utc_tp, tz);
- local_val.unchecked_set_time(
- static_cast<uint16_t>(local_cs.year()),
static_cast<uint8_t>(local_cs.month()),
- static_cast<uint8_t>(local_cs.day()),
static_cast<uint8_t>(local_cs.hour()),
- static_cast<uint8_t>(local_cs.minute()),
static_cast<uint8_t>(local_cs.second()),
- utc_val.microsecond());
- }
};
#define TIME_ROUND_WITH_DELTA_TYPE(IMPL, NAME, UNIT, TYPE, DELTA)
\
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]