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
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
10 //
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
16 // under the License.
17 
18 #include "benchmark/benchmark.h"
19 
20 #include "arrow/sparse_tensor.h"
21 #include "arrow/testing/gtest_util.h"
22 
23 #include <random>
24 
25 namespace arrow {
26 
27 enum ContiguousType { ROW_MAJOR, COLUMN_MAJOR, STRIDED };
28 
29 template <ContiguousType contiguous_type, typename ValueType, typename IndexType>
30 class TensorConversionFixture : public benchmark::Fixture {
31  protected:
32   using c_value_type = typename ValueType::c_type;
33   using c_index_type = typename IndexType::c_type;
34 
35   std::shared_ptr<DataType> value_type_ = TypeTraits<ValueType>::type_singleton();
36   std::shared_ptr<DataType> index_type_ = TypeTraits<IndexType>::type_singleton();
37 
38   std::vector<c_value_type> values_;
39   std::shared_ptr<Tensor> tensor_;
40 
41  public:
SetUp(const::benchmark::State & state)42   void SetUp(const ::benchmark::State& state) {
43     std::vector<int64_t> shape = {30, 8, 20, 9};
44     auto n = std::accumulate(shape.begin(), shape.end(), int64_t(1),
45                              [](int64_t acc, int64_t i) { return acc * i; });
46     auto m = n / 100;
47 
48     switch (contiguous_type) {
49       case STRIDED:
50         values_.resize(2 * n);
51         for (int64_t i = 0; i < 100; ++i) {
52           values_[2 * i * m] = static_cast<c_value_type>(i);
53         }
54         break;
55       default:
56         values_.resize(n);
57         for (int64_t i = 0; i < 100; ++i) {
58           values_[i * m] = static_cast<c_value_type>(i);
59         }
60         break;
61     }
62 
63     std::vector<int64_t> strides;
64     int64_t total = sizeof(c_value_type);
65     switch (contiguous_type) {
66       case ROW_MAJOR:
67         break;
68       case COLUMN_MAJOR: {
69         for (auto i : shape) {
70           strides.push_back(total);
71           total *= i;
72         }
73         break;
74       }
75       case STRIDED: {
76         total *= 2;
77         for (auto i : shape) {
78           strides.push_back(total);
79           total *= i;
80         }
81         break;
82       }
83     }
84     ABORT_NOT_OK(
85         Tensor::Make(value_type_, Buffer::Wrap(values_), shape, strides).Value(&tensor_));
86   }
87 
SetUpRowMajor()88   void SetUpRowMajor() {}
89 };
90 
91 template <ContiguousType contiguous_type, typename ValueType, typename IndexType>
92 class MatrixConversionFixture : public benchmark::Fixture {
93  protected:
94   using c_value_type = typename ValueType::c_type;
95   using c_index_type = typename IndexType::c_type;
96 
97   std::shared_ptr<DataType> value_type_ = TypeTraits<ValueType>::type_singleton();
98   std::shared_ptr<DataType> index_type_ = TypeTraits<IndexType>::type_singleton();
99 
100   std::vector<c_value_type> values_;
101   std::shared_ptr<Tensor> tensor_;
102 
103  public:
SetUp(const::benchmark::State & state)104   void SetUp(const ::benchmark::State& state) {
105     std::vector<int64_t> shape = {88, 113};
106     auto n = std::accumulate(shape.begin(), shape.end(), int64_t(1),
107                              [](int64_t acc, int64_t i) { return acc * i; });
108     auto m = n / 100;
109 
110     switch (contiguous_type) {
111       case STRIDED:
112         values_.resize(2 * n);
113         for (int64_t i = 0; i < 100; ++i) {
114           values_[2 * i * m] = static_cast<c_value_type>(i);
115         }
116         break;
117       default:
118         values_.resize(n);
119         for (int64_t i = 0; i < 100; ++i) {
120           values_[i * m] = static_cast<c_value_type>(i);
121         }
122         break;
123     }
124 
125     std::vector<int64_t> strides;
126     int64_t total = sizeof(c_value_type);
127     switch (contiguous_type) {
128       case ROW_MAJOR:
129         break;
130       case COLUMN_MAJOR: {
131         for (auto i : shape) {
132           strides.push_back(total);
133           total *= i;
134         }
135         break;
136       }
137       case STRIDED: {
138         total *= 2;
139         for (auto i : shape) {
140           strides.push_back(total);
141           total *= i;
142         }
143         break;
144       }
145     }
146     ABORT_NOT_OK(Tensor::Make(value_type_, Buffer::Wrap(values_), shape).Value(&tensor_));
147   }
148 };
149 
150 #define DEFINE_TYPED_TENSOR_CONVERSION_FIXTURE(value_type_name)                \
151   template <typename IndexType>                                                \
152   using value_type_name##RowMajorTensorConversionFixture =                     \
153       TensorConversionFixture<ROW_MAJOR, value_type_name##Type, IndexType>;    \
154   template <typename IndexType>                                                \
155   using value_type_name##ColumnMajorTensorConversionFixture =                  \
156       TensorConversionFixture<COLUMN_MAJOR, value_type_name##Type, IndexType>; \
157   template <typename IndexType>                                                \
158   using value_type_name##StridedTensorConversionFixture =                      \
159       TensorConversionFixture<STRIDED, value_type_name##Type, IndexType>
160 
161 DEFINE_TYPED_TENSOR_CONVERSION_FIXTURE(Int8);
162 DEFINE_TYPED_TENSOR_CONVERSION_FIXTURE(Float);
163 DEFINE_TYPED_TENSOR_CONVERSION_FIXTURE(Double);
164 
165 #define DEFINE_TYPED_MATRIX_CONVERSION_FIXTURE(value_type_name)                \
166   template <typename IndexType>                                                \
167   using value_type_name##RowMajorMatrixConversionFixture =                     \
168       MatrixConversionFixture<ROW_MAJOR, value_type_name##Type, IndexType>;    \
169   template <typename IndexType>                                                \
170   using value_type_name##ColumnMajorMatrixConversionFixture =                  \
171       MatrixConversionFixture<COLUMN_MAJOR, value_type_name##Type, IndexType>; \
172   template <typename IndexType>                                                \
173   using value_type_name##StridedMatrixConversionFixture =                      \
174       MatrixConversionFixture<STRIDED, value_type_name##Type, IndexType>
175 
176 DEFINE_TYPED_MATRIX_CONVERSION_FIXTURE(Int8);
177 DEFINE_TYPED_MATRIX_CONVERSION_FIXTURE(Float);
178 DEFINE_TYPED_MATRIX_CONVERSION_FIXTURE(Double);
179 
180 #define BENCHMARK_CONVERT_TENSOR_(Contiguous, kind, format, value_type_name,     \
181                                   index_type_name)                               \
182   BENCHMARK_TEMPLATE_F(value_type_name##Contiguous##kind##ConversionFixture,     \
183                        ConvertToSparse##format##kind##index_type_name,           \
184                        index_type_name##Type)                                    \
185   (benchmark::State & state) { /* NOLINT non-const reference */                  \
186     std::shared_ptr<Sparse##format##kind> sparse_tensor;                         \
187     for (auto _ : state) {                                                       \
188       ABORT_NOT_OK(Sparse##format##kind::Make(*this->tensor_, this->index_type_) \
189                        .Value(&sparse_tensor));                                  \
190     }                                                                            \
191     benchmark::DoNotOptimize(sparse_tensor);                                     \
192     state.SetItemsProcessed(state.iterations() * this->tensor_->size());         \
193     state.SetBytesProcessed(state.iterations() * this->tensor_->data()->size()); \
194   }
195 
196 #define BENCHMARK_CONVERT_TENSOR(kind, format, value_type_name, index_type_name)       \
197   BENCHMARK_CONVERT_TENSOR_(RowMajor, kind, format, value_type_name, index_type_name); \
198   BENCHMARK_CONVERT_TENSOR_(ColumnMajor, kind, format, value_type_name,                \
199                             index_type_name);                                          \
200   BENCHMARK_CONVERT_TENSOR_(Strided, kind, format, value_type_name, index_type_name)
201 
202 BENCHMARK_CONVERT_TENSOR(Tensor, COO, Int8, Int32);
203 BENCHMARK_CONVERT_TENSOR(Tensor, COO, Int8, Int64);
204 BENCHMARK_CONVERT_TENSOR(Tensor, COO, Float, Int32);
205 BENCHMARK_CONVERT_TENSOR(Tensor, COO, Float, Int64);
206 BENCHMARK_CONVERT_TENSOR(Tensor, COO, Double, Int32);
207 BENCHMARK_CONVERT_TENSOR(Tensor, COO, Double, Int64);
208 
209 BENCHMARK_CONVERT_TENSOR(Matrix, CSR, Int8, Int8);
210 BENCHMARK_CONVERT_TENSOR(Matrix, CSR, Int8, Int16);
211 BENCHMARK_CONVERT_TENSOR(Matrix, CSR, Float, Int32);
212 BENCHMARK_CONVERT_TENSOR(Matrix, CSR, Float, Int64);
213 BENCHMARK_CONVERT_TENSOR(Matrix, CSR, Double, Int32);
214 BENCHMARK_CONVERT_TENSOR(Matrix, CSR, Double, Int64);
215 
216 BENCHMARK_CONVERT_TENSOR(Matrix, CSC, Int8, Int32);
217 BENCHMARK_CONVERT_TENSOR(Matrix, CSC, Int8, Int64);
218 BENCHMARK_CONVERT_TENSOR(Matrix, CSC, Float, Int32);
219 BENCHMARK_CONVERT_TENSOR(Matrix, CSC, Float, Int64);
220 BENCHMARK_CONVERT_TENSOR(Matrix, CSC, Double, Int32);
221 BENCHMARK_CONVERT_TENSOR(Matrix, CSC, Double, Int64);
222 
223 BENCHMARK_CONVERT_TENSOR(Tensor, CSF, Int8, Int32);
224 BENCHMARK_CONVERT_TENSOR(Tensor, CSF, Int8, Int64);
225 BENCHMARK_CONVERT_TENSOR(Tensor, CSF, Float, Int32);
226 BENCHMARK_CONVERT_TENSOR(Tensor, CSF, Float, Int64);
227 BENCHMARK_CONVERT_TENSOR(Tensor, CSF, Double, Int32);
228 BENCHMARK_CONVERT_TENSOR(Tensor, CSF, Double, Int64);
229 
230 }  // namespace arrow
231