1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
22 #include "benchmark/benchmark.h"
24 #include "arrow/util/cpu_info.h"
28 using internal::CpuInfo
;
30 static CpuInfo
* cpu_info
= CpuInfo::GetInstance();
32 static const int64_t kL1Size
= cpu_info
->CacheSize(CpuInfo::L1_CACHE
);
33 static const int64_t kL2Size
= cpu_info
->CacheSize(CpuInfo::L2_CACHE
);
34 static const int64_t kL3Size
= cpu_info
->CacheSize(CpuInfo::L3_CACHE
);
35 static const int64_t kCantFitInL3Size
= kL3Size
* 4;
36 static const std::vector
<int64_t> kMemorySizes
= {kL1Size
, kL2Size
, kL3Size
,
39 template <typename Func
>
40 struct BenchmarkArgsType
;
42 // Pattern matching that extracts the vector element type of Benchmark::Args()
43 template <typename Values
>
44 struct BenchmarkArgsType
<benchmark::internal::Benchmark
* (
45 benchmark::internal::Benchmark::*)(const std::vector
<Values
>&)> {
49 // Benchmark changed its parameter type between releases from
50 // int to int64_t. As it doesn't have version macros, we need
51 // to apply C++ template magic.
53 typename BenchmarkArgsType
<decltype(&benchmark::internal::Benchmark::Args
)>::type
;
55 struct GenericItemsArgs
{
56 // number of items processed per iteration
59 // proportion of nulls in generated arrays
60 double null_proportion
;
62 explicit GenericItemsArgs(benchmark::State
& state
)
63 : size(state
.range(0)), state_(state
) {
64 if (state
.range(1) == 0) {
65 this->null_proportion
= 0.0;
67 this->null_proportion
= std::min(1., 1. / static_cast<double>(state
.range(1)));
72 state_
.counters
["size"] = static_cast<double>(size
);
73 state_
.counters
["null_percent"] = null_proportion
* 100;
74 state_
.SetItemsProcessed(state_
.iterations() * size
);
78 benchmark::State
& state_
;
81 void BenchmarkSetArgsWithSizes(benchmark::internal::Benchmark
* bench
,
82 const std::vector
<int64_t>& sizes
= kMemorySizes
) {
83 bench
->Unit(benchmark::kMicrosecond
);
85 // 0 is treated as "no nulls"
86 for (const auto size
: sizes
) {
87 for (const auto inverse_null_proportion
:
88 std::vector
<ArgsType
>({10000, 100, 10, 2, 1, 0})) {
89 bench
->Args({static_cast<ArgsType
>(size
), inverse_null_proportion
});
94 void BenchmarkSetArgs(benchmark::internal::Benchmark
* bench
) {
95 BenchmarkSetArgsWithSizes(bench
, kMemorySizes
);
98 void RegressionSetArgs(benchmark::internal::Benchmark
* bench
) {
99 // Regression do not need to account for cache hierarchy, thus optimize for
101 BenchmarkSetArgsWithSizes(bench
, {kL1Size
});
104 // RAII struct to handle some of the boilerplate in regression benchmarks
105 struct RegressionArgs
{
106 // size of memory tested (per iteration) in bytes
109 // proportion of nulls in generated arrays
110 double null_proportion
;
112 // If size_is_bytes is true, then it's a number of bytes, otherwise it's the
113 // number of items processed (for reporting)
114 explicit RegressionArgs(benchmark::State
& state
, bool size_is_bytes
= true)
115 : size(state
.range(0)), state_(state
), size_is_bytes_(size_is_bytes
) {
116 if (state
.range(1) == 0) {
117 this->null_proportion
= 0.0;
119 this->null_proportion
= std::min(1., 1. / static_cast<double>(state
.range(1)));
124 state_
.counters
["size"] = static_cast<double>(size
);
125 state_
.counters
["null_percent"] = null_proportion
* 100;
126 if (size_is_bytes_
) {
127 state_
.SetBytesProcessed(state_
.iterations() * size
);
129 state_
.SetItemsProcessed(state_
.iterations() * size
);
134 benchmark::State
& state_
;