← Index
NYTProf Performance Profile   « line view »
For /home/ss5/perl5/perlbrew/perls/perl-5.22.0/bin/benchmarkanything-storage
  Run on Mon Jan 29 16:55:34 2018
Reported on Mon Jan 29 16:57:07 2018

Filename/home/ss5/perl5/perlbrew/perls/perl-5.22.0/lib/site_perl/5.22.0/BenchmarkAnything/Storage/Backend/SQL.pm
StatementsExecuted 167097 statements in 656ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
100011414ms27.9sBenchmarkAnything::Storage::Backend::SQL::::add_single_benchmarkBenchmarkAnything::Storage::Backend::SQL::add_single_benchmark
100011160ms53.0sBenchmarkAnything::Storage::Backend::SQL::::process_queued_multi_benchmarkBenchmarkAnything::Storage::Backend::SQL::process_queued_multi_benchmark
10001134.7ms28.0sBenchmarkAnything::Storage::Backend::SQL::::add_multi_benchmarkBenchmarkAnything::Storage::Backend::SQL::add_multi_benchmark
10001131.0ms941msBenchmarkAnything::Storage::Backend::SQL::::get_single_benchmark_pointBenchmarkAnything::Storage::Backend::SQL::get_single_benchmark_point
1111.24ms39.7msBenchmarkAnything::Storage::Backend::SQL::::newBenchmarkAnything::Storage::Backend::SQL::new
11196µs98µsBenchmarkAnything::Storage::Backend::SQL::::BEGIN@8BenchmarkAnything::Storage::Backend::SQL::BEGIN@8
11152µs34.3msBenchmarkAnything::Storage::Backend::SQL::::gcBenchmarkAnything::Storage::Backend::SQL::gc
11111µs11µsBenchmarkAnything::Storage::Backend::SQL::::BEGIN@7BenchmarkAnything::Storage::Backend::SQL::BEGIN@7
1117µs14µsBenchmarkAnything::Storage::Backend::SQL::::BEGIN@10BenchmarkAnything::Storage::Backend::SQL::BEGIN@10
1116µs7µsBenchmarkAnything::Storage::Backend::SQL::::BEGIN@9BenchmarkAnything::Storage::Backend::SQL::BEGIN@9
0000s0sBenchmarkAnything::Storage::Backend::SQL::::__ANON__[:105]BenchmarkAnything::Storage::Backend::SQL::__ANON__[:105]
0000s0sBenchmarkAnything::Storage::Backend::SQL::::_get_additional_key_idBenchmarkAnything::Storage::Backend::SQL::_get_additional_key_id
0000s0sBenchmarkAnything::Storage::Backend::SQL::::benchmark_operatorsBenchmarkAnything::Storage::Backend::SQL::benchmark_operators
0000s0sBenchmarkAnything::Storage::Backend::SQL::::default_columnsBenchmarkAnything::Storage::Backend::SQL::default_columns
0000s0sBenchmarkAnything::Storage::Backend::SQL::::enqueue_multi_benchmarkBenchmarkAnything::Storage::Backend::SQL::enqueue_multi_benchmark
0000s0sBenchmarkAnything::Storage::Backend::SQL::::get_full_benchmark_pointsBenchmarkAnything::Storage::Backend::SQL::get_full_benchmark_points
0000s0sBenchmarkAnything::Storage::Backend::SQL::::get_statsBenchmarkAnything::Storage::Backend::SQL::get_stats
0000s0sBenchmarkAnything::Storage::Backend::SQL::::init_search_engineBenchmarkAnything::Storage::Backend::SQL::init_search_engine
0000s0sBenchmarkAnything::Storage::Backend::SQL::::list_additional_keysBenchmarkAnything::Storage::Backend::SQL::list_additional_keys
0000s0sBenchmarkAnything::Storage::Backend::SQL::::list_benchmark_namesBenchmarkAnything::Storage::Backend::SQL::list_benchmark_names
0000s0sBenchmarkAnything::Storage::Backend::SQL::::searchBenchmarkAnything::Storage::Backend::SQL::search
0000s0sBenchmarkAnything::Storage::Backend::SQL::::search_arrayBenchmarkAnything::Storage::Backend::SQL::search_array
0000s0sBenchmarkAnything::Storage::Backend::SQL::::search_hashBenchmarkAnything::Storage::Backend::SQL::search_hash
0000s0sBenchmarkAnything::Storage::Backend::SQL::::subsumeBenchmarkAnything::Storage::Backend::SQL::subsume
0000s0sBenchmarkAnything::Storage::Backend::SQL::::sync_search_engineBenchmarkAnything::Storage::Backend::SQL::sync_search_engine
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package BenchmarkAnything::Storage::Backend::SQL;
2# git description: v0.022-5-g18cf68b
3
41400nsour $AUTHORITY = 'cpan:TAPPER';
5# ABSTRACT: Autonomous SQL backend to store benchmarks
61100ns$BenchmarkAnything::Storage::Backend::SQL::VERSION = '0.023';
7228µs111µs
# spent 11µs within BenchmarkAnything::Storage::Backend::SQL::BEGIN@7 which was called: # once (11µs+0s) by BenchmarkAnything::Storage::Frontend::Lib::connect at line 7
use 5.008;
82105µs299µs
# spent 98µs (96+1) within BenchmarkAnything::Storage::Backend::SQL::BEGIN@8 which was called: # once (96µs+1µs) by BenchmarkAnything::Storage::Frontend::Lib::connect at line 8
use utf8;
# spent 98µs making 1 call to BenchmarkAnything::Storage::Backend::SQL::BEGIN@8 # spent 2µs making 1 call to utf8::import
9215µs28µs
# spent 7µs (6+1) within BenchmarkAnything::Storage::Backend::SQL::BEGIN@9 which was called: # once (6µs+1µs) by BenchmarkAnything::Storage::Frontend::Lib::connect at line 9
use strict;
# spent 7µs making 1 call to BenchmarkAnything::Storage::Backend::SQL::BEGIN@9 # spent 1µs making 1 call to strict::import
1022.39ms220µs
# spent 14µs (7+7) within BenchmarkAnything::Storage::Backend::SQL::BEGIN@10 which was called: # once (7µs+7µs) by BenchmarkAnything::Storage::Frontend::Lib::connect at line 10
use warnings;
# spent 14µs making 1 call to BenchmarkAnything::Storage::Backend::SQL::BEGIN@10 # spent 7µs making 1 call to warnings::import
11
1215µsmy $hr_default_config = {
13 select_cache => 0,
14 default_aggregation => 'min',
15 tables => {
16 unit_table => 'bench_units',
17 benchmark_table => 'benchs',
18 benchmark_value_table => 'bench_values',
19 subsume_type_table => 'bench_subsume_types',
20 benchmark_backup_value_table => 'bench_backup_values',
21 additional_type_table => 'bench_additional_types',
22 additional_value_table => 'bench_additional_values',
23 additional_relation_table => 'bench_additional_relations',
24 additional_type_relation_table => 'bench_additional_type_relations',
25 backup_additional_relation_table => 'bench_backup_additional_relations',
26 },
27};
28
291900nsmy $hr_column_ba_mapping = {
30 bench_value_id => 'VALUE_ID',
31 bench => 'NAME',
32 bench_value => 'VALUE',
33 bench_unit => 'UNIT',
34 created_at => 'CREATED',
35};
36
37my $fn_add_subsumed_point = sub {
38
39 my ( $or_self, $hr_atts ) = @_;
40
41 $or_self->{query}->start_transaction();
42
43 eval {
44
45 # insert subsumed benchmark value
46 $or_self->{query}->insert_benchmark_value(
47 $hr_atts->{rows}[0]{bench_id},
48 $hr_atts->{type_id},
49 $hr_atts->{VALUE},
50 );
51 my $i_bench_value_id = $or_self->{query}->last_insert_id(
52 $or_self->{config}{tables}{benchmark_value_table},
53 'bench_value_id',
54 );
55
56 # insert subsumed benchmark additional values
57 $or_self->{query}->copy_additional_values({
58 new_bench_value_id => $i_bench_value_id,
59 old_bench_value_id => $hr_atts->{rows}[0]{bench_value_id},
60 });
61
62 for my $hr_backup_row ( @{$hr_atts->{rows}} ) {
63
64 if ( $hr_backup_row->{bench_subsume_type_rank} == 1 ) {
65 if ( $hr_atts->{backup} ) {
66 # copy data rows to backup table
67 $or_self->{query}->copy_benchmark_backup_value({
68 new_bench_value_id => $i_bench_value_id,
69 old_bench_value_id => $hr_backup_row->{bench_value_id},
70 });
71 my $i_bench_backup_value_id = $or_self->{query}->last_insert_id(
72 $or_self->{config}{tables}{benchmark_backup_value_table},
73 'bench_backup_value_id',
74 );
75 $or_self->{query}->copy_benchmark_backup_additional_relations({
76 new_bench_value_id => $i_bench_backup_value_id,
77 old_bench_value_id => $hr_backup_row->{bench_value_id},
78 });
79 }
80 }
81 else {
82 # update bench_value_id in backup table
83 $or_self->{query}->update_benchmark_backup_value({
84 new_bench_value_id => $i_bench_value_id,
85 old_bench_value_id => $hr_backup_row->{bench_value_id},
86 });
87 }
88
89 # now lets remove the old rows
90 $or_self->{query}->delete_benchmark_additional_relations(
91 $hr_backup_row->{bench_value_id},
92 );
93 $or_self->{query}->delete_benchmark_value(
94 $hr_backup_row->{bench_value_id},
95 );
96
97 }
98
99 };
100
101 $or_self->{query}->finish_transaction( $@ );
102
103 return 1;
104
10513µs};
106
107
# spent 39.7ms (1.24+38.4) within BenchmarkAnything::Storage::Backend::SQL::new which was called: # once (1.24ms+38.4ms) by BenchmarkAnything::Storage::Frontend::Lib::connect at line 209 of BenchmarkAnything/Storage/Frontend/Lib.pm
sub new {
108
1091500ns my ( $s_self, $hr_atts ) = @_;
110
11111µs my $or_self = bless {}, $s_self;
112
1131500ns for my $s_key (qw/ dbh /) {
1141700ns if (! $hr_atts->{$s_key} ) {
115 require Carp;
116 Carp::confess("missing '$s_key' parameter");
117 return;
118 }
119 }
120
121 # get tapper benchmark configuration
12215µs $or_self->{config} = { %{$hr_default_config} };
123
1241500ns if ( $hr_atts->{config} ) {
125 require Hash::Merge;
126 $or_self->{config} = {
127 Hash::Merge
128 ->new('LEFT_PRECEDENT')
129 ->merge(
130 %{$hr_atts->{config}},
131 %{$or_self->{config}},
132 )
133 };
134 }
135
136158µs require CHI;
13711µs if ( $or_self->{config}{select_cache} ) {
138 $or_self->{cache} = CHI->new( driver => 'RawMemory', global => 1 );
139 }
140
141128µs210µs my $s_module = "BenchmarkAnything::Storage::Backend::SQL::Query::$hr_atts->{dbh}{Driver}{Name}";
# spent 10µs making 2 calls to DBI::common::FETCH, avg 5µs/call
142
1431200ns my $fn_new_sub;
1441400ns eval {
145154µs require Module::Load;
14611µs12µs Module::Load::load( $s_module );
# spent 2µs making 1 call to Module::Load::load
14718µs12µs $fn_new_sub = $s_module->can('new');
# spent 2µs making 1 call to UNIVERSAL::can
148 };
149
15012µs if ( $@ || !$fn_new_sub ) {
151 require Carp;
152 Carp::confess("database engine '$hr_atts->{dbh}{Driver}{Name}' not supported");
153 return;
154 }
155 else {
156 $or_self->{query} = $s_module->new({
157 dbh => $hr_atts->{dbh},
158 driver => $hr_atts->{dbh}{Driver}{Name},
159 debug => $hr_atts->{debug} || 0,
160 verbose=> $hr_atts->{verbose} || 0,
161 config => $or_self->{config},
162115µs311µs });
# spent 6µs making 1 call to BenchmarkAnything::Storage::Backend::SQL::Query::new # spent 5µs making 2 calls to DBI::common::FETCH, avg 2µs/call
163 }
164
16511µs $or_self->{searchengine} = $hr_atts->{searchengine} if $hr_atts->{searchengine};
1661700ns $or_self->{debug} = $hr_atts->{debug} || 0;
1671600ns $or_self->{verbose} = $hr_atts->{verbose} || 0;
1681500ns $or_self->{dbh_config} = $hr_atts->{dbh_config};
169
17015µs return $or_self;
171
172}
173
174
175
# spent 27.9s (414ms+27.5) within BenchmarkAnything::Storage::Backend::SQL::add_single_benchmark which was called 1000 times, avg 27.9ms/call: # 1000 times (414ms+27.5s) by BenchmarkAnything::Storage::Backend::SQL::add_multi_benchmark at line 505, avg 27.9ms/call
sub add_single_benchmark {
176
1771000525µs my ( $or_self, $hr_benchmark, $hr_options ) = @_;
178
17910001.01ms my $hr_config = $or_self->{config};
180
1811000415µs my $VALUE_ID; # same spelling as reserved key in BenchmarkAnything schema
182
183 # benchmark
184 my $i_benchmark_id;
18510001.92ms if ( $hr_benchmark->{NAME} ) {
186100015.3ms3000262ms if (
# spent 180ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::common::select_benchmark, avg 180µs/call # spent 57.8ms making 1000 calls to DBI::st::fetchrow_hashref, avg 58µs/call # spent 23.9ms making 1000 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:870], avg 24µs/call
187 my $hr_bench_select = $or_self->{query}
188 ->select_benchmark( $hr_benchmark->{NAME} )
189 ->fetchrow_hashref()
190 ) {
191 $i_benchmark_id = $hr_bench_select->{bench_id};
192 }
193 else {
194 my $i_unit_id;
195 if ( $hr_benchmark->{UNIT} ) {
196 if (
197 my $hr_unit_select = $or_self->{query}
198 ->select_unit( $hr_benchmark->{UNIT} )
199 ->fetchrow_hashref()
200 ) {
201 $i_unit_id = $hr_unit_select->{bench_unit_id};
202 }
203 else {
204 $or_self->{query}->insert_unit(
205 $hr_benchmark->{UNIT},
206 );
207 $i_unit_id = $or_self->{query}->last_insert_id(
208 $hr_config->{tables}{unit_table},
209 'bench_unit_id',
210 );
211 }
212 }
213 $or_self->{query}->insert_benchmark(
214 $hr_benchmark->{NAME}, $i_unit_id,
215 );
216 $i_benchmark_id = $or_self->{query}->last_insert_id(
217 $hr_config->{tables}{benchmark_table},
218 'bench_id',
219 );
220 }
221 }
222 else {
223 require Carp;
224 Carp::confess('missing element "NAME"');
225 return 0;
226 }
227
22810002.77ms if (
229 $hr_benchmark->{data}
230 && ref( $hr_benchmark->{data} ) eq 'ARRAY'
231 && @{$hr_benchmark->{data}}
232 ) {
233
234 my $i_benchmark_subsume_type_id = $or_self->{query}
235 ->select_min_subsume_type()
236 ->fetchrow_hashref()
237 ->{bench_subsume_type_id}
23810007.24ms3000195ms ;
# spent 150ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::common::select_min_subsume_type, avg 150µs/call # spent 23.7ms making 1000 calls to DBI::st::fetchrow_hashref, avg 24µs/call # spent 21.4ms making 1000 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:870], avg 21µs/call
239
2401000568µs my $i_counter = 1;
24110002.00ms for my $hr_point ( @{$hr_benchmark->{data}} ) {
242
2431000600µs if ( not exists $hr_point->{VALUE} ) {
244 require Carp;
245 if ( $hr_options->{force} ) {
246 Carp::cluck("missing parameter 'VALUE' in element $i_counter");
247 }
248 else {
249 Carp::confess("missing parameter 'VALUE' in element $i_counter");
250 }
251 }
252
253 # benchmark value
254 $or_self->{query}->insert_benchmark_value(
255 $i_benchmark_id, $i_benchmark_subsume_type_id, $hr_point->{VALUE},
25610004.00ms1000247ms );
# spent 247ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::mysql::insert_benchmark_value, avg 247µs/call
257 my $i_benchmark_value_id = $or_self->{query}->last_insert_id(
258 $hr_config->{tables}{benchmark_value_table},
25910009.48ms10007.75ms 'bench_value_id',
# spent 7.75ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::last_insert_id, avg 8µs/call
260 );
2611000625µs $VALUE_ID = $i_benchmark_value_id;
262
26310003.84ms ADDITIONAL: for my $s_key ( keys %{$hr_point} ) {
264
26556503.25ms next ADDITIONAL if $s_key eq 'VALUE';
26646502.58ms next ADDITIONAL if not defined $hr_point->{$s_key};
267
268 # additional type
2694650939µs my $i_addtype_id;
27046501.87ms if ( $or_self->{cache} ) {
271 $i_addtype_id = $or_self->{cache}->get("addtype||$s_key");
272 }
27346502.00ms if ( !$i_addtype_id ) {
274465033.4ms13950852ms if (
# spent 646ms making 4650 calls to BenchmarkAnything::Storage::Backend::SQL::Query::common::select_addtype, avg 139µs/call # spent 110ms making 4650 calls to DBI::st::fetchrow_hashref, avg 24µs/call # spent 95.4ms making 4650 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:870], avg 21µs/call
275 my $hr_addtype_select = $or_self->{query}
276 ->select_addtype( $s_key )
277 ->fetchrow_hashref()
278 ) {
279 $i_addtype_id = $hr_addtype_select->{bench_additional_type_id};
280 }
281 else {
282 $or_self->{query}->insert_addtype(
283 $s_key,
284 );
285 $i_addtype_id = $or_self->{query}->last_insert_id(
286 $hr_config->{tables}{addition_type_table},
287 'bench_additional_type_id',
288 );
289 }
29046504.34ms if ( $or_self->{cache} ) {
291 $or_self->{cache}->set( "addtype||$s_key" => $i_addtype_id );
292 }
293 }
294
295 # benchmark - additional type - relation
29646501.30ms my $b_inserted = 0;
29746503.99ms my $s_addtyperel = "$i_benchmark_id|$i_addtype_id";
29846501.21ms if ( $or_self->{cache} ) {
299 if ( $or_self->{cache}->get("addtyperel||$s_addtyperel") ) {
300 $b_inserted = 1;
301 }
302 }
30346501.98ms if (! $b_inserted ) {
304465037.5ms13950891ms if(!
# spent 676ms making 4650 calls to BenchmarkAnything::Storage::Backend::SQL::Query::common::select_addtyperelation, avg 145µs/call # spent 118ms making 4650 calls to DBI::st::fetchrow_hashref, avg 25µs/call # spent 96.5ms making 4650 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:870], avg 21µs/call
305 $or_self->{query}
306 ->select_addtyperelation( $i_benchmark_id, $i_addtype_id )
307 ->fetchrow_hashref()
308 ) {
309 $or_self->{query}
310 ->insert_addtyperelation( $i_benchmark_id, $i_addtype_id )
311 ;
312 }
31346502.67ms if ( $or_self->{cache} ) {
314 $or_self->{cache}->set("addtyperel||$s_addtyperel" => 1 );
315 }
316 }
317
318 # additional value
3194650836µs my $i_addvalue_id;
32046505.05ms my $s_addvalue_key = "$i_addtype_id|$hr_point->{$s_key}";
32146501.08ms if ( $or_self->{cache} ) {
322 $i_addvalue_id = $or_self->{cache}->get("addvalue||$s_addvalue_key");
323 }
32446501.87ms if (! $i_addvalue_id ) {
325465043.8ms13950827ms if (
# spent 651ms making 4650 calls to BenchmarkAnything::Storage::Backend::SQL::Query::common::select_addvalue, avg 140µs/call # spent 95.7ms making 4650 calls to DBI::st::fetchrow_hashref, avg 21µs/call # spent 80.4ms making 4650 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:870], avg 17µs/call
326 my $hr_addvalue_select = $or_self->{query}
327 ->select_addvalue( $i_addtype_id, $hr_point->{$s_key} )
328 ->fetchrow_hashref()
329 ) {
330 $i_addvalue_id = $hr_addvalue_select->{bench_additional_value_id};
331 }
332 else {
333 $or_self->{query}->insert_addvalue(
3342876µs284.65ms $i_addtype_id, $hr_point->{$s_key},
# spent 4.65ms making 28 calls to BenchmarkAnything::Storage::Backend::SQL::Query::mysql::insert_addvalue, avg 166µs/call
335 );
336 $i_addvalue_id = $or_self->{query}->last_insert_id(
337 $hr_config->{tables}{addition_type_table},
3382881µs28158µs 'bench_additional_value_id',
# spent 158µs making 28 calls to BenchmarkAnything::Storage::Backend::SQL::Query::last_insert_id, avg 6µs/call
339 );
340 }
34146503.87ms if ( $or_self->{cache} ) {
342 $or_self->{cache}->set( "addvalue||$s_addvalue_key" => $i_addvalue_id );
343 }
344 }
345
346 # additional value relation
347 $or_self->{query}->insert_addvaluerelation(
348465012.6ms4650941ms $i_benchmark_value_id, $i_addvalue_id,
# spent 941ms making 4650 calls to BenchmarkAnything::Storage::Backend::SQL::Query::mysql::insert_addvaluerelation, avg 202µs/call
349 );
350
351 } # ADDITIONAL
352
35310001.11ms $i_counter++;
354
355 }
356 }
357 else {
358 require Carp;
359 Carp::cluck('no benchmark data found');
360 return 0;
361 }
362
36310004.38ms10001.46ms if ( $or_self->{searchengine}{elasticsearch}{index_single_added_values_immediately} )
# spent 1.46ms making 1000 calls to Cpanel::JSON::XS::DESTROY, avg 1µs/call
364 {
36510001.93ms require BenchmarkAnything::Storage::Search::Elasticsearch;
366 my ($or_es, $s_index, $s_type) = BenchmarkAnything::Storage::Search::Elasticsearch::get_elasticsearch_client
367 (
36810005.30ms10001.87s {searchengine => $or_self->{searchengine}, ownjson => 1}
# spent 1.87s making 1000 calls to BenchmarkAnything::Storage::Search::Elasticsearch::get_elasticsearch_client, avg 1.87ms/call
369 );
370
371 # Sic, we re-read from DB to get the very same data we
372 # *really got* stored, not just what we wish it should
373 # have stored. That gives us translations like
374 # num->string, CREATED date, etc., etc.
375
37610003.40ms1000941ms my $hr_bmk = $or_self->get_single_benchmark_point($VALUE_ID);
# spent 941ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::get_single_benchmark_point, avg 941µs/call
377100077.7ms100020.8s my $ret = $or_es->index(index => $s_index,
378 type => $s_type,
379 id => $VALUE_ID,
380 body => $hr_bmk);
381 }
382
383100011.2ms return 1;
384
385}
386
387sub enqueue_multi_benchmark {
388
389 my ( $or_self, $ar_data_points, $hr_options ) = @_;
390
391 require Sereal::Encoder;
392
393 my $s_serialized = Sereal::Encoder->new->encode($ar_data_points);
394 $or_self->{query}->insert_raw_bench_bundle($s_serialized);
395
396 return 1;
397
398}
399
400# dequeues a single bundle (can contain multiple data points)
401
# spent 53.0s (160ms+52.8) within BenchmarkAnything::Storage::Backend::SQL::process_queued_multi_benchmark which was called 1000 times, avg 53.0ms/call: # 1000 times (160ms+52.8s) by BenchmarkAnything::Storage::Frontend::Lib::process_raw_result_queue at line 689 of BenchmarkAnything/Storage/Frontend/Lib.pm, avg 53.0ms/call
sub process_queued_multi_benchmark {
402
40310001.24ms my ( $or_self, $hr_options ) = @_;
404
4051000409µs my $i_id;
406 my $s_serialized;
407 my $ar_data_points;
408 my $ar_results;
409 my $or_result;
410100013.5ms20004.32ms my $driver = $or_self->{query}{dbh}{Driver}{Name};
# spent 4.32ms making 2000 calls to DBI::common::FETCH, avg 2µs/call
411
412 # ===== exclusively pick single raw entry =====
413 # Lock single row via processing=1 so that only one worker handles it!
414100067.2ms100060.5ms $or_self->{query}{dbh}->do("set transaction isolation level read committed") if $driver eq "mysql"; # avoid deadlocks due to gap locking
# spent 60.5ms making 1000 calls to DBI::db::do, avg 61µs/call
41510003.84ms2000110ms $or_self->{query}->start_transaction;
# spent 108ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::start_transaction, avg 108µs/call # spent 2.08ms making 1000 calls to DBI::common::STORE, avg 2µs/call
4161000766µs eval {
41710004.17ms1000406ms $ar_results = $or_self->{query}->select_raw_bench_bundle_for_lock;
41810007.14ms200062.7ms $or_result = $ar_results->fetchrow_hashref;
# spent 33.1ms making 1000 calls to DBI::st::fetchrow_hashref, avg 33µs/call # spent 29.6ms making 1000 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:870], avg 30µs/call
4191000644µs $i_id = $or_result->{raw_bench_bundle_id};
4201000407µs if (!$i_id) {
421 $or_self->{query}->finish_transaction( $@ );
422 $or_self->{query}{dbh}->do("set transaction isolation level repeatable read") if $driver eq "mysql"; # reset to normal gap locking
423 goto RETURN ;
424 }
42510002.96ms1000335ms $or_self->{query}->start_processing_raw_bench_bundle($i_id);
426 };
42710002.62ms100011.8s $or_self->{query}->finish_transaction( $@ );
# spent 11.8s making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::finish_transaction, avg 11.8ms/call
428100073.8ms100060.2ms $or_self->{query}{dbh}->do("set transaction isolation level repeatable read") if $driver eq "mysql"; # reset to normal gap locking
# spent 60.2ms making 1000 calls to DBI::db::do, avg 60µs/call
429
430 # ===== process that single raw entry =====
43110004.27ms2000106ms $or_self->{query}->start_transaction;
# spent 104ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::start_transaction, avg 104µs/call # spent 2.12ms making 1000 calls to DBI::common::STORE, avg 2µs/call
4321000885µs eval {
43310001.68ms require Sereal::Decoder;
434
43510005.04ms1000251ms $ar_results = $or_self->{query}->select_raw_bench_bundle_for_processing($i_id);
436100015.8ms200065.9ms $s_serialized = $ar_results->fetchrow_hashref->{raw_bench_bundle_serialized};
# spent 37.6ms making 1000 calls to DBI::st::fetchrow_hashref, avg 38µs/call # spent 28.3ms making 1000 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:870], avg 28µs/call
437100028.6ms100014.1ms $ar_data_points = Sereal::Decoder::decode_sereal($s_serialized);
# spent 14.1ms making 1000 calls to Sereal::Decoder::decode_sereal, avg 14µs/call
438
439 # preserve order, otherwise add_multi_benchmark() would reorder to optimize insert
44010006.77ms100028.0s $or_self->add_multi_benchmark([$_], $hr_options) foreach @$ar_data_points;
# spent 28.0s making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::add_multi_benchmark, avg 28.0ms/call
44110006.00ms1000673ms $or_self->{query}->update_raw_bench_bundle_set_processed($i_id);
442 };
44310003.54ms100011.0s $or_self->{query}->finish_transaction( $@ );
# spent 11.0s making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::finish_transaction, avg 11.0ms/call
444
445100011.6ms RETURN:
446 return $@ ? undef : $i_id;
447
448}
449
450# garbage collect - initially raw_bench_bundles, but also other stuff.
451
# spent 34.3ms (52µs+34.3) within BenchmarkAnything::Storage::Backend::SQL::gc which was called: # once (52µs+34.3ms) by BenchmarkAnything::Storage::Frontend::Lib::gc at line 671 of BenchmarkAnything/Storage/Frontend/Lib.pm
sub gc {
452
45311µs my ( $or_self, $hr_options ) = @_;
454
455112µs123.5ms $or_self->{query}->delete_processed_raw_bench_bundles;
45618µs if ($or_self->{searchengine}{elasticsearch}{enable_query}) {
45711µs require BenchmarkAnything::Storage::Search::Elasticsearch;
458 my ($or_es, $s_index, $s_type) = BenchmarkAnything::Storage::Search::Elasticsearch::get_elasticsearch_client
459 (
460 {searchengine => $or_self->{searchengine}}
46116µs13.75ms );
46219µs23.81ms $or_es->indices->clear_cache(index => $s_index);
463 }
464}
465
466
# spent 28.0s (34.7ms+27.9) within BenchmarkAnything::Storage::Backend::SQL::add_multi_benchmark which was called 1000 times, avg 28.0ms/call: # 1000 times (34.7ms+27.9s) by BenchmarkAnything::Storage::Backend::SQL::process_queued_multi_benchmark at line 440, avg 28.0ms/call
sub add_multi_benchmark {
467
4681000706µs my ( $or_self, $ar_data_points, $hr_options ) = @_;
469
4701000587µs my $i_counter = 1;
47110001.37ms my %h_benchmarks = ();
47210001.14ms for my $hr_data_point ( @{$ar_data_points} ) {
473
4741000989µs for my $s_param (qw/ NAME VALUE /) {
47520001.72ms if ( not exists $hr_data_point->{$s_param} ) {
476 require Carp;
477 if ( $hr_options->{force} ) {
478 Carp::cluck("missing parameter '$s_param' in element $i_counter");
479 }
480 else {
481 Carp::confess("missing parameter '$s_param' in element $i_counter");
482 }
483 }
484 }
485
48610002.78ms my ( $s_name, $s_unit ) = delete @{$hr_data_point}{qw/ NAME UNIT /};
487
48810004.58ms if (! $h_benchmarks{$s_name} ) {
489 $h_benchmarks{$s_name} = {
490 NAME => $s_name,
491 UNIT => $s_unit,
492 data => [],
493 };
494 }
495 else {
496 $h_benchmarks{$s_name}{UNIT} ||= $s_unit;
497 }
498
49910001.92ms push @{$h_benchmarks{$s_name}{data}}, $hr_data_point;
500
5011000828µs $i_counter++;
502
503 }
50410001.53ms for my $hr_benchmark ( values %h_benchmarks ) {
50510003.79ms100027.9s $or_self->add_single_benchmark( $hr_benchmark, $hr_options );
# spent 27.9s making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::add_single_benchmark, avg 27.9ms/call
506 }
507
50810005.81ms return 1;
509
510}
511
512sub search {
513
514 my ( $or_self, $hr_search ) = @_;
515
516 return $or_self->{query}->select_benchmark_values(
517 $hr_search
518 );
519
520}
521
522sub list_benchmark_names {
523
524 my ( $or_self, $s_pattern ) = @_;
525
526 my $ar_pattern = defined($s_pattern) ? [$s_pattern] : [];
527
528 my $s_key;
529 if ( $or_self->{cache} ) {
530 require JSON::XS;
531 $s_key = JSON::XS::encode_json($ar_pattern);
532 if ( my $ar_search_data = $or_self->{cache}->get("list_benchmark_names||$s_key") ) {
533 return $ar_search_data;
534 }
535 }
536
537 my $ar_result = $or_self->{query}
538 ->select_benchmark_names( @$ar_pattern )
539 ->fetchall_arrayref([0]);
540 my $ar_benchmark_names = [ map { $_->[0] } @$ar_result ];
541
542 if ( $or_self->{cache} ) {
543 $or_self->{cache}->set( "list_benchmark_names||$s_key" => $ar_benchmark_names );
544 }
545
546 return $ar_benchmark_names;
547
548}
549
550sub list_additional_keys {
551
552 my ( $or_self, $s_pattern ) = @_;
553
554 my $ar_pattern = defined($s_pattern) ? [$s_pattern] : [];
555
556 my $s_key;
557 if ( $or_self->{cache} ) {
558 require JSON::XS;
559 $s_key = JSON::XS::encode_json($ar_pattern);
560 if ( my $ar_search_data = $or_self->{cache}->get("list_additional_keys||$s_key") ) {
561 return $ar_search_data;
562 }
563 }
564
565 my $ar_result = $or_self->{query}
566 ->select_additional_keys( @$ar_pattern )
567 ->fetchall_arrayref([0]);
568 my $ar_key_names = [ map { $_->[0] } @$ar_result ];
569
570 if ( $or_self->{cache} ) {
571 $or_self->{cache}->set( "list_additional_keys||$s_key" => $ar_key_names );
572 }
573
574 return $ar_key_names;
575
576}
577
578sub get_stats {
579
580 my ( $or_self ) = @_;
581
582 my %h_searchengine_stats = ();
583 my %h_flat_searchengine_stats = ();
584 my %stats = ();
585
586 # Not strictly *stats* but useful information.
587 if ( $or_self->{searchengine}{elasticsearch}{index} )
588 {
589 require BenchmarkAnything::Storage::Search::Elasticsearch;
590 my ($or_es, $s_index, $s_type) = BenchmarkAnything::Storage::Search::Elasticsearch::get_elasticsearch_client
591 (
592 {searchengine => $or_self->{searchengine}}
593 );
594
595 $stats{count_datapoints} = (map {chomp; $_} split(qr/ +/, $or_es->cat->count))[2];
596 %h_searchengine_stats =
597 (
598 index => $or_self->{searchengine}{elasticsearch}{index} || 'UNKNOWN',
599 type => $or_self->{searchengine}{elasticsearch}{type} || 'UNKNOWN',
600 enable_query => $or_self->{searchengine}{elasticsearch}{enable_query} || 0,
601 cluster_health => $or_es->cluster->health,
602 index_single_added_values_immediately => $or_self->{searchengine}{elasticsearch}{index_single_added_values_immediately} || 0,
603 );
604 # boolean -> 0/1
605 for (values %{$h_searchengine_stats{elasticsearch}{cluster_health}}) {
606 $_ = $_ ? 1 : 0 if ref eq 'JSON::XS::Boolean';
607 }
608 $h_flat_searchengine_stats{"elasticsearch_$_"} = $h_searchengine_stats{$_}
609 for qw(index type enable_query index_single_added_values_immediately);
610 $h_flat_searchengine_stats{"elasticsearch_cluster_health_$_"} = $h_searchengine_stats{cluster_health}{$_}
611 for qw(cluster_name active_shards_percent_as_number active_primary_shards number_of_nodes status);
612 }
613
614 $stats{count_datapoints} ||= 0+$or_self->{query}->select_count_datapoints->fetch->[0];
615 $stats{count_datapointkeys} = 0+$or_self->{query}->select_count_datapointkeys->fetch->[0] if $or_self->{verbose};
616 $stats{count_metrics} = 0+$or_self->{query}->select_count_metrics->fetch->[0] if $or_self->{verbose};
617 $stats{count_keys} = 0+$or_self->{query}->select_count_keys->fetch->[0] if $or_self->{verbose};
618
619 %stats = (%stats, %h_flat_searchengine_stats);
620
621 return \%stats;
622}
623
624
# spent 941ms (31.0+910) within BenchmarkAnything::Storage::Backend::SQL::get_single_benchmark_point which was called 1000 times, avg 941µs/call: # 1000 times (31.0ms+910ms) by BenchmarkAnything::Storage::Backend::SQL::add_single_benchmark at line 376, avg 941µs/call
sub get_single_benchmark_point {
625
6261000618µs my ( $or_self, $i_bench_value_id ) = @_;
627
6281000359µs return {} unless $i_bench_value_id;
629
630 # cache?
6311000291µs my $s_key;
6321000705µs if ( $or_self->{cache} ) {
633 require JSON::XS;
634 $s_key = JSON::XS::encode_json({bench_value_id => $i_bench_value_id});
635 if ( my $hr_search_data = $or_self->{cache}->get("get_single_benchmark_point||$s_key") ) {
636 return $hr_search_data;
637 }
638 }
639
640 # fetch all additional key/value fields
641 my $ar_query_result = $or_self->{query}
642100014.5ms3000769ms ->select_complete_benchmark_point( $i_bench_value_id )
# spent 534ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::common::select_complete_benchmark_point, avg 534µs/call # spent 121ms making 1000 calls to DBI::st::fetchall_arrayref, avg 121µs/call # spent 113ms making 1000 calls to DBD::_::st::fetchall_arrayref, avg 113µs/call
643 ->fetchall_arrayref({});
644
645 # fetch essentials, like NAME, VALUE, UNIT
646 my $hr_essentials = $or_self->{query}
64710008.03ms3000276ms ->select_benchmark_point_essentials( $i_bench_value_id )
# spent 230ms making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::Query::common::select_benchmark_point_essentials, avg 230µs/call # spent 24.8ms making 1000 calls to DBI::st::fetchrow_hashref, avg 25µs/call # spent 21.8ms making 1000 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:870], avg 22µs/call
648 ->fetchrow_hashref();
649
650 # create complete BenchmarkAnything-like key/value entry
6511000334µs my $hr_result;
65210006.23ms $hr_result = { map { ($_->{bench_additional_type} => $_->{bench_additional_value} ) } @$ar_query_result };
65310001.18ms $hr_result->{NAME} = $hr_essentials->{bench};
6541000747µs $hr_result->{VALUE} = $hr_essentials->{bench_value};
6551000986µs $hr_result->{VALUE_ID} = $hr_essentials->{bench_value_id};
6561000890µs $hr_result->{CREATED} = $hr_essentials->{created_at};
6571000408µs $hr_result->{UNIT} = $hr_essentials->{bench_unit} if $hr_essentials->{bench_unit};
658
659 # cache!
6601000447µs if ( $or_self->{cache} ) {
661 $or_self->{cache}->set( "get_single_benchmark_point||$s_key" => $hr_result );
662 }
663
66410004.73ms return $hr_result;
665}
666
667sub get_full_benchmark_points {
668
669 my ( $or_self, $i_bench_value_id, $i_count ) = @_;
670
671 return [] unless $i_bench_value_id;
672
673 $i_count ||= 1;
674
675 # cache?
676 my $s_key;
677 if ( $or_self->{cache} ) {
678 require JSON::XS;
679 $s_key = JSON::XS::encode_json({bench_value_id => $i_bench_value_id});
680 if ( my $hr_search_data = $or_self->{cache}->get("get_full_benchmark_points||$s_key") ) {
681 return $hr_search_data;
682 }
683 }
684
685 # fetch essentials, like NAME, VALUE, UNIT
686 my $ar_essentials = $or_self->{query}
687 ->select_multiple_benchmark_points_essentials($i_bench_value_id, $i_count)
688 ->fetchall_arrayref({});
689 # additional key/value pairs
690 my $ar_additional_values = $or_self->{query}
691 ->select_multiple_benchmark_points_additionals($i_bench_value_id, $i_count)
692 ->fetchall_arrayref({});
693
694 # map columns into BenchmarkAnything schema
695 my $hr_bmk;
696 foreach my $k (keys %$hr_column_ba_mapping)
697 {
698 my $K = $hr_column_ba_mapping->{$k};
699 foreach my $e (@$ar_essentials) {
700 $hr_bmk->{$e->{bench_value_id}}{$K} = $e->{$k} if $k ne 'bench_unit' or defined $e->{$k};
701 }
702 }
703 foreach (@$ar_additional_values) {
704 $hr_bmk->{$_->{bench_value_id}}{$_->{bench_additional_type}} = $_->{bench_additional_value};
705 }
706 # sorted (by VALUE_ID) array of BenchmarkAnything entries
707 my @a_bmk = map { $hr_bmk->{$_} } sort keys %$hr_bmk;
708
709 # cache!
710 if ( $or_self->{cache} ) {
711 $or_self->{cache}->set( "get_full_benchmark_points||$s_key" => \@a_bmk );
712 }
713
714 return \@a_bmk;
715}
716
717sub search_array {
718
719 my ( $or_self, $hr_search ) = @_;
720
721 my $debug = $or_self->{debug} || $or_self->{searchengine}{elasticsearch}{debug};
722
723 my $s_key;
724 if ( $or_self->{cache} ) {
725 require JSON::XS;
726 $s_key = JSON::XS::encode_json($hr_search);
727 if ( my $ar_search_data = $or_self->{cache}->get("search_array||$s_key") ) {
728 return $ar_search_data;
729 }
730 }
731
732 if ( $debug )
733 {
734 require JSON::XS;
735 require Data::Dumper;
736 print STDERR ',-------------------'."\n";
737 print STDERR "benchmarkanything query:\n";
738 print STDERR "benchmarkanything-storage search -d '\n";
739 print STDERR JSON::XS->new->pretty->encode($hr_search);
740 print STDERR "'\n";
741 print STDERR '`-------------------'."\n";
742 }
743
744 if ( $or_self->{searchengine}{elasticsearch}{enable_query} )
745 {
746 # If anything goes wrong with Elasticsearch we just continue
747 # below with relational backend query.
748
749 require BenchmarkAnything::Storage::Search::Elasticsearch;
750 my $hr_es_query = BenchmarkAnything::Storage::Search::Elasticsearch::get_elasticsearch_query($hr_search);
751
752 if ($debug)
753 {
754 require JSON::XS;
755 require Data::Dumper;
756 print STDERR ',-------------------'."\n";
757 print STDERR "elasticsearch query:\n";
758 print STDERR "curl -s -XGET 'http://localhost:9200/tapper/benchmarkanything/_search?pretty' -d '\n";
759 print STDERR JSON::XS->new->pretty->encode($hr_es_query);
760 print STDERR "'\n";
761 print STDERR '`-------------------'."\n";
762 }
763
764 # If we could transform the query then we run it against Elasticsearch and return its result.
765 if (defined $hr_es_query)
766 {
767 # ===== client =====
768
769 require BenchmarkAnything::Storage::Search::Elasticsearch;
770 my ($or_es, $s_index, $s_type) = BenchmarkAnything::Storage::Search::Elasticsearch::get_elasticsearch_client
771 (
772 {searchengine => $or_self->{searchengine}, ownjson => 1}
773 );
774
775 # ===== prepare =====
776
777 # If sort fields are of type 'text' then those fields needs to
778 # get their properties being declared as "fielddata":true.
779 my $field_mapping = {};
780 my @sort_fields = map {keys %$_} @{$hr_es_query->{sort}||[]};
781 if (@sort_fields) {
782 $field_mapping = $or_es->indices->get_mapping->{$s_index}{mappings}{$s_type}{properties};
783 }
784 foreach my $sort_field (@sort_fields)
785 {
786 if ($field_mapping->{$sort_field}{type} and $field_mapping->{$sort_field}{type} eq 'text')
787 {
788 require BenchmarkAnything::Storage::Backend::SQL::Search;
789 $or_es->indices->put_mapping
790 (
791 index => $s_index,
792 type => $s_type,
793 body => { $s_type => { properties => { $sort_field => { type => 'text',
794 fielddata => BenchmarkAnything::Storage::Backend::SQL::Search::json_true(),
795 }}}}
796 );
797 }
798 }
799
800 # ===== search =====
801 my $hr_es_answer = $or_es->search(index => $s_index, type => $s_type, body => $hr_es_query);
802
803 if (
804 !$hr_es_answer->{timed_out} and
805 !$hr_es_answer->{_shards}{failed}
806 )
807 {
808 my @ar_es_result = map { $_->{_source} } @{$hr_es_answer->{hits}{hits} || []};
809 return \@ar_es_result;
810 }
811 }
812
813 # Else no-op, continue with relational backend query.
814 }
815
816 my $ar_result = $or_self
817 ->search( $hr_search )
818 ->fetchall_arrayref({})
819 ;
820
821 if ( $or_self->{cache} ) {
822 $or_self->{cache}->set( "search_array||$s_key" => $ar_result );
823 }
824
825 return $ar_result;
826
827}
828
829sub search_hash {
830
831 my ( $or_self, $hr_search ) = @_;
832
833 my $s_key;
834 if ( $or_self->{cache} ) {
835 require JSON::XS;
836 $s_key = JSON::XS::encode_json($hr_search);
837 if ( my $hr_search_data = $or_self->{cache}->get( "search_hash||$s_key" ) ) {
838 return $hr_search_data;
839 }
840 }
841
842 if (! $hr_search->{keys} ) {
843 require Carp;
844 Carp::confess(q#cannot get hash search result without 'keys'#);
845 return;
846 }
847
848 my $hr_result = $or_self
849 ->search( $hr_search )
850 ->fetchall_hashref($hr_search->{keys})
851 ;
852
853 if ( $or_self->{cache} ) {
854 $or_self->{cache}->set( "search_hash||$s_key" => $hr_result )
855 }
856
857 return $hr_result;
858
859}
860
861sub subsume {
862
863 my ( $or_self, $hr_options ) = @_;
864
865 for my $s_parameter (qw/ subsume_type /) {
866 if (! $hr_options->{$s_parameter}) {
867 require Carp;
868 Carp::confess("missing parameter '$s_parameter'");
869 return;
870 }
871 }
872
873 # check if subsume type exists
874 my $hr_subsume_type = $or_self->{query}
875 ->select_subsume_type( $hr_options->{subsume_type} )
876 ->fetchrow_hashref()
877 ;
878 if (! $hr_subsume_type ) {
879 require Carp;
880 Carp::confess("subsume type '$hr_options->{subsume_type}' not exists");
881 return;
882 }
883 if ( $hr_subsume_type->{bench_subsume_type_rank} == 1 ) {
884 require Carp;
885 Carp::confess("cannot subsume with type '$hr_options->{subsume_type}'");
886 return;
887 }
888
889 # looking for values with with a higher rank subsume type
890 if (
891 $or_self->{query}
892 ->select_check_subsumed_values({
893 date_to => $hr_options->{date_to},
894 date_from => $hr_options->{date_from},
895 subsume_type_id => $hr_subsume_type->{bench_subsume_type_id},
896 })
897 ->rows()
898 ) {
899 require Carp;
900 Carp::confess(
901 "cannot use subsume type '$hr_options->{subsume_type}' " .
902 'because a higher rank subsume type is already used for this date period'
903 );
904 return;
905 }
906
907 # look if excluded additional types really exists
908 my @a_excluded_adds;
909 if ( $hr_options->{exclude_additionals} ) {
910 for my $s_additional_type ( @{$hr_options->{exclude_additionals}} ) {
911 if (
912 my $hr_addtype = $or_self->{query}
913 ->select_addtype( $s_additional_type )
914 ->fetchrow_hashref()
915 ) {
916 push @a_excluded_adds, $hr_addtype->{bench_additional_type_id}
917 }
918 else {
919 require Carp;
920 Carp::confess( "additional type '$s_additional_type' not exists" );
921 return;
922 }
923 }
924 }
925
926 # get all data points for subsume
927 my $or_data_values = $or_self->{query}->select_data_values_for_subsume({
928 date_to => $hr_options->{date_to},
929 date_from => $hr_options->{date_from},
930 exclude_additionals => \@a_excluded_adds,
931 subsume_type_id => $hr_subsume_type->{bench_subsume_type_id},
932 });
933
934 require DateTime::Format::Strptime;
935 my $or_strp = DateTime::Format::Strptime->new( pattern => '%F %T', );
936
937 my @a_rows;
938 my $i_counter = 0;
939 my $i_sum_value = 0;
940 my $b_backup = ((not exists $hr_options->{backup}) || $hr_options->{backup}) ? 1 : 0;
941 my $s_last_key = q##;
942
943 while ( my $hr_values = $or_data_values->fetchrow_hashref() ) {
944
945 my $s_act_key = join '__',
946 $hr_values->{bench_id},
947 $or_strp->parse_datetime( $hr_values->{created_at} )->strftime( $hr_subsume_type->{datetime_strftime_pattern} ),
948 $hr_values->{additionals} || q##,
949 ;
950
951 if ( $s_last_key ne $s_act_key ) {
952
953 if ( $i_counter ) {
954 $or_self->$fn_add_subsumed_point({
955 rows => \@a_rows,
956 VALUE => $i_sum_value / $i_counter,
957 backup => $b_backup,
958 type_id => $hr_subsume_type->{bench_subsume_type_id}
959 });
960 }
961
962 @a_rows = ();
963 $i_counter = 0;
964 $i_sum_value = 0;
965 $s_last_key = $s_act_key;
966
967 }
968
969 $i_counter += 1;
970 $i_sum_value += $hr_values->{bench_value};
971
972 push @a_rows, $hr_values;
973
974 }
975
976 if ( $i_counter ) {
977 $or_self->$fn_add_subsumed_point({
978 rows => \@a_rows,
979 VALUE => $i_sum_value / $i_counter,
980 backup => $b_backup,
981 type_id => $hr_subsume_type->{bench_subsume_type_id}
982 });
983 }
984
985 return 1;
986
987}
988
989sub _get_additional_key_id {
990
991 my ( $or_self, $s_key ) = @_;
992
993 return $or_self->{query}->select_additional_key_id($s_key)->fetch->[0];
994
995}
996
997sub default_columns {
998
999 my ( $or_self ) = @_;
1000
1001 return $or_self->{query}->default_columns;
1002
1003}
1004
1005sub benchmark_operators {
1006
1007 my ( $or_self ) = @_;
1008
1009 return $or_self->{query}->benchmark_operators;
1010
1011}
1012
1013sub init_search_engine
1014{
1015 my ( $or_self, $b_force) = @_;
1016
1017 require BenchmarkAnything::Storage::Backend::SQL::Search;
1018 BenchmarkAnything::Storage::Backend::SQL::Search::init_search_engine (@_);
1019}
1020
1021sub sync_search_engine
1022{
1023 require BenchmarkAnything::Storage::Backend::SQL::Search;
1024 BenchmarkAnything::Storage::Backend::SQL::Search::sync_search_engine (@_);
1025}
1026
102714µs1;
1028
1029__END__