blob: cc5874a82ca44c7033fcff4707ff232f7dc45852 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 <benchmark/benchmark.h>
#include <cstring>
#include <random>
#include <vector>
#include "util/binary_cast.hpp"
namespace doris {
// similar to reinterpret_cast but won't break strict-aliasing rules
template <typename From, typename To>
To old_binary_cast(From from) {
constexpr bool from_u64_to_db = match_v<From, uint64_t, To, double>;
constexpr bool from_i64_to_db = match_v<From, int64_t, To, double>;
constexpr bool from_db_to_i64 = match_v<From, double, To, int64_t>;
constexpr bool from_db_to_u64 = match_v<From, double, To, uint64_t>;
constexpr bool from_i64_to_vec_dt = match_v<From, __int64_t, To, doris::VecDateTimeValue>;
constexpr bool from_vec_dt_to_i64 = match_v<From, doris::VecDateTimeValue, To, __int64_t>;
constexpr bool from_i128_to_decv2 = match_v<From, __int128_t, To, DecimalV2Value>;
constexpr bool from_decv2_to_i128 = match_v<From, DecimalV2Value, To, __int128_t>;
constexpr bool from_decv2_to_i256 = match_v<From, DecimalV2Value, To, wide::Int256>;
constexpr bool from_ui32_to_date_v2 = match_v<From, uint32_t, To, DateV2Value<DateV2ValueType>>;
constexpr bool from_date_v2_to_ui32 = match_v<From, DateV2Value<DateV2ValueType>, To, uint32_t>;
constexpr bool from_ui64_to_datetime_v2 =
match_v<From, uint64_t, To, DateV2Value<DateTimeV2ValueType>>;
constexpr bool from_datetime_v2_to_ui64 =
match_v<From, DateV2Value<DateTimeV2ValueType>, To, uint64_t>;
static_assert(from_u64_to_db || from_i64_to_db || from_db_to_i64 || from_db_to_u64 ||
from_i64_to_vec_dt || from_vec_dt_to_i64 || from_i128_to_decv2 ||
from_decv2_to_i128 || from_decv2_to_i256 || from_ui32_to_date_v2 ||
from_date_v2_to_ui32 || from_ui64_to_datetime_v2 || from_datetime_v2_to_ui64);
if constexpr (from_u64_to_db) {
TypeConverter conv;
conv.u64 = from;
return conv.dbl;
} else if constexpr (from_i64_to_db) {
TypeConverter conv;
conv.i64 = from;
return conv.dbl;
} else if constexpr (from_db_to_i64) {
TypeConverter conv;
conv.dbl = from;
return conv.i64;
} else if constexpr (from_db_to_u64) {
TypeConverter conv;
conv.dbl = from;
return conv.u64;
} else if constexpr (from_i64_to_vec_dt) {
VecDateTimeInt64Union conv = {.i64 = from};
return conv.dt;
} else if constexpr (from_ui32_to_date_v2) {
DateV2UInt32Union conv = {.ui32 = from};
return conv.dt;
} else if constexpr (from_date_v2_to_ui32) {
DateV2UInt32Union conv = {.dt = from};
return conv.ui32;
} else if constexpr (from_ui64_to_datetime_v2) {
DateTimeV2UInt64Union conv = {.ui64 = from};
return conv.dt;
} else if constexpr (from_datetime_v2_to_ui64) {
DateTimeV2UInt64Union conv = {.dt = from};
return conv.ui64;
} else if constexpr (from_vec_dt_to_i64) {
VecDateTimeInt64Union conv = {.dt = from};
return conv.i64;
} else if constexpr (from_i128_to_decv2) {
DecimalInt128Union conv;
conv.i128 = from;
return conv.decimal;
} else if constexpr (from_decv2_to_i128) {
DecimalInt128Union conv;
conv.decimal = from;
return conv.i128;
} else {
throw Exception(Status::FatalError("__builtin_unreachable"));
}
}
// Generate random datetime values in uint64_t format for testing
std::vector<uint64_t> generate_datetime_v2_ui64_data(size_t count) {
std::vector<uint64_t> data;
data.reserve(count);
static std::random_device rd;
static std::mt19937_64 gen(rd());
std::uniform_int_distribution<uint64_t> dis(MIN_DATETIME_V2, MAX_DATETIME_V2);
for (size_t i = 0; i < count; ++i) {
data.push_back(dis(gen));
}
return data;
}
// Generate DateTimeV2Value objects from uint64_t data
std::vector<DateV2Value<DateTimeV2ValueType>> convert_u_int64_to_date_time_v2(
const std::vector<uint64_t>& ui64_data) {
std::vector<DateV2Value<DateTimeV2ValueType>> result;
result.reserve(ui64_data.size());
for (const auto& ui64_val : ui64_data) {
result.push_back(binary_cast<uint64_t, DateV2Value<DateTimeV2ValueType>>(ui64_val));
}
return result;
}
// Benchmark binary_cast from uint64_t to DateTimeV2Value
static void BM_BinaryCast_UI64_to_DateTimeV2(benchmark::State& state) {
state.PauseTiming();
const size_t data_size = state.range(0);
auto test_data = generate_datetime_v2_ui64_data(data_size);
state.ResumeTiming();
for (auto _ : state) {
benchmark::DoNotOptimize(test_data.data());
for (size_t i = 0; i < data_size; ++i) {
auto result = binary_cast<uint64_t, DateV2Value<DateTimeV2ValueType>>(test_data[i]);
benchmark::DoNotOptimize(result);
}
benchmark::ClobberMemory();
}
// Set the number of items processed per second
state.SetItemsProcessed(int64_t(state.iterations()) * data_size);
}
// Benchmark old_binary_cast from uint64_t to DateTimeV2Value
static void BM_OldBinaryCast_UI64_to_DateTimeV2(benchmark::State& state) {
state.PauseTiming();
const size_t data_size = state.range(0);
auto test_data = generate_datetime_v2_ui64_data(data_size);
state.ResumeTiming();
for (auto _ : state) {
benchmark::DoNotOptimize(test_data.data());
for (size_t i = 0; i < data_size; ++i) {
auto result = old_binary_cast<uint64_t, DateV2Value<DateTimeV2ValueType>>(test_data[i]);
benchmark::DoNotOptimize(result);
}
benchmark::ClobberMemory();
}
// Set the number of items processed per second
state.SetItemsProcessed(int64_t(state.iterations()) * data_size);
}
// Benchmark binary_cast from DateTimeV2Value to uint64_t
static void BM_BinaryCast_DateTimeV2_to_UI64(benchmark::State& state) {
state.PauseTiming();
const size_t data_size = state.range(0);
auto ui64_data = generate_datetime_v2_ui64_data(data_size);
auto test_data = convert_u_int64_to_date_time_v2(ui64_data);
state.ResumeTiming();
for (auto _ : state) {
benchmark::DoNotOptimize(test_data.data());
for (size_t i = 0; i < data_size; ++i) {
auto result = binary_cast<DateV2Value<DateTimeV2ValueType>, uint64_t>(test_data[i]);
benchmark::DoNotOptimize(result);
}
benchmark::ClobberMemory();
}
// Set the number of items processed per second
state.SetItemsProcessed(int64_t(state.iterations()) * data_size);
}
// Benchmark old_binary_cast from DateTimeV2Value to uint64_t
static void BM_OldBinaryCast_DateTimeV2_to_UI64(benchmark::State& state) {
state.PauseTiming();
const size_t data_size = state.range(0);
auto ui64_data = generate_datetime_v2_ui64_data(data_size);
auto test_data = convert_u_int64_to_date_time_v2(ui64_data);
state.ResumeTiming();
for (auto _ : state) {
benchmark::DoNotOptimize(test_data.data());
for (size_t i = 0; i < data_size; ++i) {
auto result = old_binary_cast<DateV2Value<DateTimeV2ValueType>, uint64_t>(test_data[i]);
benchmark::DoNotOptimize(result);
}
benchmark::ClobberMemory();
}
// Set the number of items processed per second
state.SetItemsProcessed(int64_t(state.iterations()) * data_size);
}
// Register benchmarks with only large data sizes
// Use fixed larger sizes and more iterations for more reliable comparisons
BENCHMARK(BM_BinaryCast_UI64_to_DateTimeV2)
->Arg(1000000)
->Arg(10000000)
->Iterations(100)
->MinTime(2.0) // Run each benchmark for at least 2 seconds
->Unit(benchmark::
kMicrosecond); // Use microseconds for more readable results with large datasets
BENCHMARK(BM_OldBinaryCast_UI64_to_DateTimeV2)
->Arg(1000000)
->Arg(10000000)
->Iterations(100)
->MinTime(2.0)
->Unit(benchmark::kMicrosecond);
BENCHMARK(BM_BinaryCast_DateTimeV2_to_UI64)
->Arg(1000000)
->Arg(10000000)
->Iterations(100)
->MinTime(2.0)
->Unit(benchmark::kMicrosecond);
BENCHMARK(BM_OldBinaryCast_DateTimeV2_to_UI64)
->Arg(1000000)
->Arg(10000000)
->Iterations(100)
->MinTime(2.0)
->Unit(benchmark::kMicrosecond);
} // namespace doris