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 <stdlib.h>
19 #include "arrow/memory_pool.h"
20 #include "arrow/status.h"
21 #include "benchmark/benchmark.h"
22 #include "gandiva/decimal_type_util.h"
23 #include "gandiva/projector.h"
24 #include "gandiva/tests/test_util.h"
25 #include "gandiva/tests/timed_evaluate.h"
26 #include "gandiva/tree_expr_builder.h"
27 
28 namespace gandiva {
29 
30 using arrow::boolean;
31 using arrow::int32;
32 using arrow::int64;
33 using arrow::utf8;
34 
TimedTestAdd3(benchmark::State & state)35 static void TimedTestAdd3(benchmark::State& state) {
36   // schema for input fields
37   auto field0 = field("f0", int64());
38   auto field1 = field("f1", int64());
39   auto field2 = field("f2", int64());
40   auto schema = arrow::schema({field0, field1, field2});
41   auto pool_ = arrow::default_memory_pool();
42 
43   // output field
44   auto field_sum = field("add", int64());
45 
46   // Build expression
47   auto part_sum = TreeExprBuilder::MakeFunction(
48       "add", {TreeExprBuilder::MakeField(field1), TreeExprBuilder::MakeField(field2)},
49       int64());
50   auto sum = TreeExprBuilder::MakeFunction(
51       "add", {TreeExprBuilder::MakeField(field0), part_sum}, int64());
52 
53   auto sum_expr = TreeExprBuilder::MakeExpression(sum, field_sum);
54 
55   std::shared_ptr<Projector> projector;
56   ASSERT_OK(Projector::Make(schema, {sum_expr}, TestConfiguration(), &projector));
57 
58   Int64DataGenerator data_generator;
59   ProjectEvaluator evaluator(projector);
60 
61   Status status = TimedEvaluate<arrow::Int64Type, int64_t>(
62       schema, evaluator, data_generator, pool_, 1 * MILLION, 16 * THOUSAND, state);
63   ASSERT_OK(status);
64 }
65 
TimedTestBigNested(benchmark::State & state)66 static void TimedTestBigNested(benchmark::State& state) {
67   // schema for input fields
68   auto fielda = field("a", int32());
69   auto schema = arrow::schema({fielda});
70   auto pool_ = arrow::default_memory_pool();
71 
72   // output fields
73   auto field_result = field("res", int32());
74 
75   // build expression.
76   // if (a < 10)
77   //   10
78   // else if (a < 20)
79   //   20
80   // ..
81   // ..
82   // else if (a < 190)
83   //   190
84   // else
85   //   200
86   auto node_a = TreeExprBuilder::MakeField(fielda);
87   auto top_node = TreeExprBuilder::MakeLiteral(200);
88   for (int thresh = 190; thresh > 0; thresh -= 10) {
89     auto literal = TreeExprBuilder::MakeLiteral(thresh);
90     auto condition =
91         TreeExprBuilder::MakeFunction("less_than", {node_a, literal}, boolean());
92     auto if_node = TreeExprBuilder::MakeIf(condition, literal, top_node, int32());
93     top_node = if_node;
94   }
95   auto expr = TreeExprBuilder::MakeExpression(top_node, field_result);
96 
97   // Build a projector for the expressions.
98   std::shared_ptr<Projector> projector;
99   ASSERT_OK(Projector::Make(schema, {expr}, TestConfiguration(), &projector));
100 
101   BoundedInt32DataGenerator data_generator(250);
102   ProjectEvaluator evaluator(projector);
103 
104   Status status = TimedEvaluate<arrow::Int32Type, int32_t>(
105       schema, evaluator, data_generator, pool_, 1 * MILLION, 16 * THOUSAND, state);
106   ASSERT_TRUE(status.ok());
107 }
108 
TimedTestExtractYear(benchmark::State & state)109 static void TimedTestExtractYear(benchmark::State& state) {
110   // schema for input fields
111   auto field0 = field("f0", arrow::date64());
112   auto schema = arrow::schema({field0});
113   auto pool_ = arrow::default_memory_pool();
114 
115   // output field
116   auto field_res = field("res", int64());
117 
118   // Build expression
119   auto expr = TreeExprBuilder::MakeExpression("extractYear", {field0}, field_res);
120 
121   std::shared_ptr<Projector> projector;
122   ASSERT_OK(Projector::Make(schema, {expr}, TestConfiguration(), &projector));
123 
124   Int64DataGenerator data_generator;
125   ProjectEvaluator evaluator(projector);
126 
127   Status status = TimedEvaluate<arrow::Date64Type, int64_t>(
128       schema, evaluator, data_generator, pool_, 1 * MILLION, 16 * THOUSAND, state);
129   ASSERT_TRUE(status.ok());
130 }
131 
TimedTestFilterAdd2(benchmark::State & state)132 static void TimedTestFilterAdd2(benchmark::State& state) {
133   // schema for input fields
134   auto field0 = field("f0", int64());
135   auto field1 = field("f1", int64());
136   auto field2 = field("f2", int64());
137   auto schema = arrow::schema({field0, field1, field2});
138   auto pool_ = arrow::default_memory_pool();
139 
140   // Build expression
141   auto sum = TreeExprBuilder::MakeFunction(
142       "add", {TreeExprBuilder::MakeField(field1), TreeExprBuilder::MakeField(field0)},
143       int64());
144   auto less_than = TreeExprBuilder::MakeFunction(
145       "less_than", {sum, TreeExprBuilder::MakeField(field2)}, boolean());
146   auto condition = TreeExprBuilder::MakeCondition(less_than);
147 
148   std::shared_ptr<Filter> filter;
149   ASSERT_OK(Filter::Make(schema, condition, TestConfiguration(), &filter));
150 
151   Int64DataGenerator data_generator;
152   FilterEvaluator evaluator(filter);
153 
154   Status status = TimedEvaluate<arrow::Int64Type, int64_t>(
155       schema, evaluator, data_generator, pool_, MILLION, 16 * THOUSAND, state);
156   ASSERT_TRUE(status.ok());
157 }
158 
TimedTestFilterLike(benchmark::State & state)159 static void TimedTestFilterLike(benchmark::State& state) {
160   // schema for input fields
161   auto fielda = field("a", utf8());
162   auto schema = arrow::schema({fielda});
163   auto pool_ = arrow::default_memory_pool();
164 
165   // build expression.
166   auto node_a = TreeExprBuilder::MakeField(fielda);
167   auto pattern_node = TreeExprBuilder::MakeStringLiteral("%yellow%");
168   auto like_yellow =
169       TreeExprBuilder::MakeFunction("like", {node_a, pattern_node}, arrow::boolean());
170   auto condition = TreeExprBuilder::MakeCondition(like_yellow);
171 
172   std::shared_ptr<Filter> filter;
173   ASSERT_OK(Filter::Make(schema, condition, TestConfiguration(), &filter));
174 
175   FastUtf8DataGenerator data_generator(32);
176   FilterEvaluator evaluator(filter);
177 
178   Status status = TimedEvaluate<arrow::StringType, std::string>(
179       schema, evaluator, data_generator, pool_, 1 * MILLION, 16 * THOUSAND, state);
180   ASSERT_TRUE(status.ok());
181 }
182 
TimedTestCastFloatFromString(benchmark::State & state)183 static void TimedTestCastFloatFromString(benchmark::State& state) {
184   auto field_a = field("a", utf8());
185   auto schema = arrow::schema({field_a});
186   auto pool = arrow::default_memory_pool();
187 
188   auto field_result = field("res", arrow::float64());
189 
190   auto node_a = TreeExprBuilder::MakeField(field_a);
191   auto fn = TreeExprBuilder::MakeFunction("castFLOAT8", {node_a}, arrow::float64());
192   auto expr = TreeExprBuilder::MakeExpression(fn, field_result);
193 
194   std::shared_ptr<Projector> projector;
195   ASSERT_OK(Projector::Make(schema, {expr}, TestConfiguration(), &projector));
196 
197   Utf8FloatDataGenerator data_generator;
198   ProjectEvaluator evaluator(projector);
199 
200   Status status = TimedEvaluate<arrow::StringType, std::string>(
201       schema, evaluator, data_generator, pool, 1 * MILLION, 16 * THOUSAND, state);
202   ASSERT_TRUE(status.ok());
203 }
204 
TimedTestCastIntFromString(benchmark::State & state)205 static void TimedTestCastIntFromString(benchmark::State& state) {
206   auto field_a = field("a", utf8());
207   auto schema = arrow::schema({field_a});
208   auto pool = arrow::default_memory_pool();
209 
210   auto field_result = field("res", int32());
211 
212   auto node_a = TreeExprBuilder::MakeField(field_a);
213   auto fn = TreeExprBuilder::MakeFunction("castINT", {node_a}, int32());
214   auto expr = TreeExprBuilder::MakeExpression(fn, field_result);
215 
216   std::shared_ptr<Projector> projector;
217   ASSERT_OK(Projector::Make(schema, {expr}, TestConfiguration(), &projector));
218 
219   Utf8IntDataGenerator data_generator;
220   ProjectEvaluator evaluator(projector);
221 
222   Status status = TimedEvaluate<arrow::StringType, std::string>(
223       schema, evaluator, data_generator, pool, 1 * MILLION, 16 * THOUSAND, state);
224   ASSERT_TRUE(status.ok());
225 }
226 
TimedTestAllocs(benchmark::State & state)227 static void TimedTestAllocs(benchmark::State& state) {
228   // schema for input fields
229   auto field_a = field("a", arrow::utf8());
230   auto schema = arrow::schema({field_a});
231   auto pool_ = arrow::default_memory_pool();
232 
233   // output field
234   auto field_res = field("res", int32());
235 
236   // Build expression
237   auto node_a = TreeExprBuilder::MakeField(field_a);
238   auto upper = TreeExprBuilder::MakeFunction("upper", {node_a}, utf8());
239   auto length = TreeExprBuilder::MakeFunction("octet_length", {upper}, int32());
240   auto expr = TreeExprBuilder::MakeExpression(length, field_res);
241 
242   std::shared_ptr<Projector> projector;
243   ASSERT_OK(Projector::Make(schema, {expr}, TestConfiguration(), &projector));
244 
245   FastUtf8DataGenerator data_generator(64);
246   ProjectEvaluator evaluator(projector);
247 
248   Status status = TimedEvaluate<arrow::StringType, std::string>(
249       schema, evaluator, data_generator, pool_, 1 * MILLION, 16 * THOUSAND, state);
250   ASSERT_TRUE(status.ok());
251 }
252 // following two tests are for benchmark optimization of
253 // in expr. will be used in follow-up PRs to optimize in expr.
254 
TimedTestMultiOr(benchmark::State & state)255 static void TimedTestMultiOr(benchmark::State& state) {
256   // schema for input fields
257   auto fielda = field("a", utf8());
258   auto schema = arrow::schema({fielda});
259   auto pool_ = arrow::default_memory_pool();
260 
261   // output fields
262   auto field_result = field("res", boolean());
263 
264   // build expression.
265   // booleanOr(a = string1, a = string2, ..)
266   auto node_a = TreeExprBuilder::MakeField(fielda);
267 
268   NodeVector boolean_functions;
269   FastUtf8DataGenerator data_generator1(250);
270   for (int thresh = 1; thresh <= 32; thresh++) {
271     auto literal = TreeExprBuilder::MakeStringLiteral(data_generator1.GenerateData());
272     auto condition = TreeExprBuilder::MakeFunction("equal", {node_a, literal}, boolean());
273     boolean_functions.push_back(condition);
274   }
275 
276   auto boolean_or = TreeExprBuilder::MakeOr(boolean_functions);
277   auto expr = TreeExprBuilder::MakeExpression(boolean_or, field_result);
278 
279   // Build a projector for the expressions.
280   std::shared_ptr<Projector> projector;
281   ASSERT_OK(Projector::Make(schema, {expr}, TestConfiguration(), &projector));
282 
283   FastUtf8DataGenerator data_generator(250);
284   ProjectEvaluator evaluator(projector);
285   Status status = TimedEvaluate<arrow::StringType, std::string>(
286       schema, evaluator, data_generator, pool_, 100 * THOUSAND, 16 * THOUSAND, state);
287   ASSERT_OK(status);
288 }
289 
TimedTestInExpr(benchmark::State & state)290 static void TimedTestInExpr(benchmark::State& state) {
291   // schema for input fields
292   auto fielda = field("a", utf8());
293   auto schema = arrow::schema({fielda});
294   auto pool_ = arrow::default_memory_pool();
295 
296   // output fields
297   auto field_result = field("res", boolean());
298 
299   // build expression.
300   // a in (string1, string2, ..)
301   auto node_a = TreeExprBuilder::MakeField(fielda);
302 
303   std::unordered_set<std::string> values;
304   FastUtf8DataGenerator data_generator1(250);
305   for (int i = 1; i <= 32; i++) {
306     values.insert(data_generator1.GenerateData());
307   }
308   auto boolean_or = TreeExprBuilder::MakeInExpressionString(node_a, values);
309   auto expr = TreeExprBuilder::MakeExpression(boolean_or, field_result);
310 
311   // Build a projector for the expressions.
312   std::shared_ptr<Projector> projector;
313   ASSERT_OK(Projector::Make(schema, {expr}, TestConfiguration(), &projector));
314 
315   FastUtf8DataGenerator data_generator(250);
316   ProjectEvaluator evaluator(projector);
317 
318   Status status = TimedEvaluate<arrow::StringType, std::string>(
319       schema, evaluator, data_generator, pool_, 100 * THOUSAND, 16 * THOUSAND, state);
320 
321   ASSERT_OK(status);
322 }
323 
DoDecimalAdd3(benchmark::State & state,int32_t precision,int32_t scale,bool large=false)324 static void DoDecimalAdd3(benchmark::State& state, int32_t precision, int32_t scale,
325                           bool large = false) {
326   // schema for input fields
327   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
328   auto field0 = field("f0", decimal_type);
329   auto field1 = field("f1", decimal_type);
330   auto field2 = field("f2", decimal_type);
331   auto schema = arrow::schema({field0, field1, field2});
332 
333   Decimal128TypePtr add2_type;
334   auto status = DecimalTypeUtil::GetResultType(DecimalTypeUtil::kOpAdd,
335                                                {decimal_type, decimal_type}, &add2_type);
336 
337   Decimal128TypePtr output_type;
338   status = DecimalTypeUtil::GetResultType(DecimalTypeUtil::kOpAdd,
339                                           {add2_type, decimal_type}, &output_type);
340 
341   // output field
342   auto field_sum = field("add", output_type);
343 
344   // Build expression
345   auto part_sum = TreeExprBuilder::MakeFunction(
346       "add", {TreeExprBuilder::MakeField(field1), TreeExprBuilder::MakeField(field2)},
347       add2_type);
348   auto sum = TreeExprBuilder::MakeFunction(
349       "add", {TreeExprBuilder::MakeField(field0), part_sum}, output_type);
350 
351   auto sum_expr = TreeExprBuilder::MakeExpression(sum, field_sum);
352 
353   std::shared_ptr<Projector> projector;
354   status = Projector::Make(schema, {sum_expr}, TestConfiguration(), &projector);
355   EXPECT_TRUE(status.ok());
356 
357   Decimal128DataGenerator data_generator(large);
358   ProjectEvaluator evaluator(projector);
359 
360   status = TimedEvaluate<arrow::Decimal128Type, arrow::Decimal128>(
361       schema, evaluator, data_generator, arrow::default_memory_pool(), 1 * MILLION,
362       16 * THOUSAND, state);
363   ASSERT_OK(status);
364 }
365 
DoDecimalAdd2(benchmark::State & state,int32_t precision,int32_t scale,bool large=false)366 static void DoDecimalAdd2(benchmark::State& state, int32_t precision, int32_t scale,
367                           bool large = false) {
368   // schema for input fields
369   auto decimal_type = std::make_shared<arrow::Decimal128Type>(precision, scale);
370   auto field0 = field("f0", decimal_type);
371   auto field1 = field("f1", decimal_type);
372   auto schema = arrow::schema({field0, field1});
373 
374   Decimal128TypePtr output_type;
375   auto status = DecimalTypeUtil::GetResultType(
376       DecimalTypeUtil::kOpAdd, {decimal_type, decimal_type}, &output_type);
377 
378   // output field
379   auto field_sum = field("add", output_type);
380 
381   // Build expression
382   auto sum = TreeExprBuilder::MakeExpression("add", {field0, field1}, field_sum);
383 
384   std::shared_ptr<Projector> projector;
385   status = Projector::Make(schema, {sum}, TestConfiguration(), &projector);
386   EXPECT_TRUE(status.ok());
387 
388   Decimal128DataGenerator data_generator(large);
389   ProjectEvaluator evaluator(projector);
390 
391   status = TimedEvaluate<arrow::Decimal128Type, arrow::Decimal128>(
392       schema, evaluator, data_generator, arrow::default_memory_pool(), 1 * MILLION,
393       16 * THOUSAND, state);
394   ASSERT_OK(status);
395 }
396 
DecimalAdd2Fast(benchmark::State & state)397 static void DecimalAdd2Fast(benchmark::State& state) {
398   // use lesser precision to test the fast-path
399   DoDecimalAdd2(state, DecimalTypeUtil::kMaxPrecision - 6, 18);
400 }
401 
DecimalAdd2LeadingZeroes(benchmark::State & state)402 static void DecimalAdd2LeadingZeroes(benchmark::State& state) {
403   // use max precision to test the large-integer-path
404   DoDecimalAdd2(state, DecimalTypeUtil::kMaxPrecision, 6);
405 }
406 
DecimalAdd2LeadingZeroesWithDiv(benchmark::State & state)407 static void DecimalAdd2LeadingZeroesWithDiv(benchmark::State& state) {
408   // use max precision to test the large-integer-path
409   DoDecimalAdd2(state, DecimalTypeUtil::kMaxPrecision, 18);
410 }
411 
DecimalAdd2Large(benchmark::State & state)412 static void DecimalAdd2Large(benchmark::State& state) {
413   // use max precision to test the large-integer-path
414   DoDecimalAdd2(state, DecimalTypeUtil::kMaxPrecision, 18, true);
415 }
416 
DecimalAdd3Fast(benchmark::State & state)417 static void DecimalAdd3Fast(benchmark::State& state) {
418   // use lesser precision to test the fast-path
419   DoDecimalAdd3(state, DecimalTypeUtil::kMaxPrecision - 6, 18);
420 }
421 
DecimalAdd3LeadingZeroes(benchmark::State & state)422 static void DecimalAdd3LeadingZeroes(benchmark::State& state) {
423   // use max precision to test the large-integer-path
424   DoDecimalAdd3(state, DecimalTypeUtil::kMaxPrecision, 6);
425 }
426 
DecimalAdd3LeadingZeroesWithDiv(benchmark::State & state)427 static void DecimalAdd3LeadingZeroesWithDiv(benchmark::State& state) {
428   // use max precision to test the large-integer-path
429   DoDecimalAdd3(state, DecimalTypeUtil::kMaxPrecision, 18);
430 }
431 
DecimalAdd3Large(benchmark::State & state)432 static void DecimalAdd3Large(benchmark::State& state) {
433   // use max precision to test the large-integer-path
434   DoDecimalAdd3(state, DecimalTypeUtil::kMaxPrecision, 18, true);
435 }
436 
437 BENCHMARK(TimedTestAdd3)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
438 BENCHMARK(TimedTestBigNested)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
439 BENCHMARK(TimedTestExtractYear)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
440 BENCHMARK(TimedTestFilterAdd2)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
441 BENCHMARK(TimedTestFilterLike)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
442 BENCHMARK(TimedTestCastFloatFromString)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
443 BENCHMARK(TimedTestCastIntFromString)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
444 BENCHMARK(TimedTestAllocs)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
445 BENCHMARK(TimedTestMultiOr)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
446 BENCHMARK(TimedTestInExpr)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
447 BENCHMARK(DecimalAdd2Fast)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
448 BENCHMARK(DecimalAdd2LeadingZeroes)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
449 BENCHMARK(DecimalAdd2LeadingZeroesWithDiv)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
450 BENCHMARK(DecimalAdd2Large)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
451 BENCHMARK(DecimalAdd3Fast)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
452 BENCHMARK(DecimalAdd3LeadingZeroes)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
453 BENCHMARK(DecimalAdd3LeadingZeroesWithDiv)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
454 BENCHMARK(DecimalAdd3Large)->MinTime(1.0)->Unit(benchmark::kMicrosecond);
455 
456 }  // namespace gandiva
457