--- /dev/null
+// 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 <vector>
+
+#include "arrow/compute/api_scalar.h"
+#include "arrow/compute/kernels/test_util.h"
+#include "arrow/testing/gtest_util.h"
+#include "arrow/testing/random.h"
+#include "arrow/util/benchmark_util.h"
+
+namespace arrow {
+namespace compute {
+
+constexpr auto kSeed = 0x94378165;
+
+using BinaryOp = Result<Datum>(const Datum&, const Datum&, ArithmeticOptions,
+ ExecContext*);
+
+// Add explicit overflow-checked shortcuts, for easy benchmark parametering.
+static Result<Datum> AddChecked(const Datum& left, const Datum& right,
+ ArithmeticOptions options = ArithmeticOptions(),
+ ExecContext* ctx = NULLPTR) {
+ options.check_overflow = true;
+ return Add(left, right, std::move(options), ctx);
+}
+
+static Result<Datum> SubtractChecked(const Datum& left, const Datum& right,
+ ArithmeticOptions options = ArithmeticOptions(),
+ ExecContext* ctx = NULLPTR) {
+ options.check_overflow = true;
+ return Subtract(left, right, std::move(options), ctx);
+}
+
+static Result<Datum> MultiplyChecked(const Datum& left, const Datum& right,
+ ArithmeticOptions options = ArithmeticOptions(),
+ ExecContext* ctx = NULLPTR) {
+ options.check_overflow = true;
+ return Multiply(left, right, std::move(options), ctx);
+}
+
+static Result<Datum> DivideChecked(const Datum& left, const Datum& right,
+ ArithmeticOptions options = ArithmeticOptions(),
+ ExecContext* ctx = NULLPTR) {
+ options.check_overflow = true;
+ return Divide(left, right, std::move(options), ctx);
+}
+
+template <BinaryOp& Op, typename ArrowType, typename CType = typename ArrowType::c_type>
+static void ArrayScalarKernel(benchmark::State& state) {
+ RegressionArgs args(state);
+
+ const int64_t array_size = args.size / sizeof(CType);
+
+ // Choose values so as to avoid overflow on all ops and types
+ auto min = static_cast<CType>(6);
+ auto max = static_cast<CType>(min + 15);
+ Datum rhs(static_cast<CType>(6));
+
+ auto rand = random::RandomArrayGenerator(kSeed);
+ auto lhs = std::static_pointer_cast<NumericArray<ArrowType>>(
+ rand.Numeric<ArrowType>(array_size, min, max, args.null_proportion));
+
+ for (auto _ : state) {
+ ABORT_NOT_OK(Op(lhs, rhs, ArithmeticOptions(), nullptr).status());
+ }
+ state.SetItemsProcessed(state.iterations() * array_size);
+}
+
+template <BinaryOp& Op, typename ArrowType, typename CType = typename ArrowType::c_type>
+static void ArrayArrayKernel(benchmark::State& state) {
+ RegressionArgs args(state);
+
+ // Choose values so as to avoid overflow on all ops and types
+ const int64_t array_size = args.size / sizeof(CType);
+ auto rmin = static_cast<CType>(1);
+ auto rmax = static_cast<CType>(rmin + 6); // 7
+ auto lmin = static_cast<CType>(rmax + 1); // 8
+ auto lmax = static_cast<CType>(lmin + 6); // 14
+
+ auto rand = random::RandomArrayGenerator(kSeed);
+ auto lhs = std::static_pointer_cast<NumericArray<ArrowType>>(
+ rand.Numeric<ArrowType>(array_size, lmin, lmax, args.null_proportion));
+ auto rhs = std::static_pointer_cast<NumericArray<ArrowType>>(
+ rand.Numeric<ArrowType>(array_size, rmin, rmax, args.null_proportion));
+
+ for (auto _ : state) {
+ ABORT_NOT_OK(Op(lhs, rhs, ArithmeticOptions(), nullptr).status());
+ }
+ state.SetItemsProcessed(state.iterations() * array_size);
+}
+
+void SetArgs(benchmark::internal::Benchmark* bench) {
+ for (const auto inverse_null_proportion : std::vector<ArgsType>({100, 0})) {
+ bench->Args({static_cast<ArgsType>(kL2Size), inverse_null_proportion});
+ }
+}
+
+#define DECLARE_ARITHMETIC_BENCHMARKS(BENCHMARK, OP) \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, Int64Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, Int32Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, Int16Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, Int8Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, UInt64Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, UInt32Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, UInt16Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, UInt8Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, FloatType)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, DoubleType)->Apply(SetArgs)
+
+// Checked floating-point variants of arithmetic operations are identical to
+// non-checked variants, so do not bother measuring them.
+
+#define DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(BENCHMARK, OP) \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, Int64Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, Int32Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, Int16Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, Int8Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, UInt64Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, UInt32Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, UInt16Type)->Apply(SetArgs); \
+ BENCHMARK_TEMPLATE(BENCHMARK, OP, UInt8Type)->Apply(SetArgs);
+
+DECLARE_ARITHMETIC_BENCHMARKS(ArrayArrayKernel, Add);
+DECLARE_ARITHMETIC_BENCHMARKS(ArrayScalarKernel, Add);
+DECLARE_ARITHMETIC_BENCHMARKS(ArrayArrayKernel, Subtract);
+DECLARE_ARITHMETIC_BENCHMARKS(ArrayScalarKernel, Subtract);
+DECLARE_ARITHMETIC_BENCHMARKS(ArrayArrayKernel, Multiply);
+DECLARE_ARITHMETIC_BENCHMARKS(ArrayScalarKernel, Multiply);
+DECLARE_ARITHMETIC_BENCHMARKS(ArrayArrayKernel, Divide);
+DECLARE_ARITHMETIC_BENCHMARKS(ArrayScalarKernel, Divide);
+
+DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(ArrayArrayKernel, AddChecked);
+DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(ArrayScalarKernel, AddChecked);
+DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(ArrayArrayKernel, SubtractChecked);
+DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(ArrayScalarKernel, SubtractChecked);
+DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(ArrayArrayKernel, MultiplyChecked);
+DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(ArrayScalarKernel, MultiplyChecked);
+DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(ArrayArrayKernel, DivideChecked);
+DECLARE_ARITHMETIC_CHECKED_BENCHMARKS(ArrayScalarKernel, DivideChecked);
+
+} // namespace compute
+} // namespace arrow