| Filename | /home/ss5/perl5/perlbrew/perls/perl-5.22.0/lib/site_perl/5.22.0/BenchmarkAnything/Storage/Frontend/Lib.pm |
| Statements | Executed 2062 statements in 10.3ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 9.88ms | 58.9ms | BenchmarkAnything::Storage::Frontend::Lib::connect |
| 1 | 1 | 1 | 9.64ms | 53.0s | BenchmarkAnything::Storage::Frontend::Lib::process_raw_result_queue |
| 1 | 1 | 1 | 699µs | 996µs | BenchmarkAnything::Storage::Frontend::Lib::BEGIN@10 |
| 1 | 1 | 1 | 420µs | 329ms | BenchmarkAnything::Storage::Frontend::Lib::BEGIN@280 |
| 1 | 1 | 1 | 254µs | 97.0ms | BenchmarkAnything::Storage::Frontend::Lib::new |
| 1 | 1 | 1 | 19µs | 26µs | BenchmarkAnything::Storage::Frontend::Lib::disconnect |
| 1 | 1 | 1 | 15µs | 15µs | main::BEGIN@1.22 |
| 1 | 1 | 1 | 12µs | 34.3ms | BenchmarkAnything::Storage::Frontend::Lib::gc |
| 1 | 1 | 1 | 9µs | 26µs | BenchmarkAnything::Storage::Frontend::Lib::BEGIN@27 |
| 1 | 1 | 1 | 8µs | 16µs | BenchmarkAnything::Storage::Frontend::Lib::BEGIN@275 |
| 1 | 1 | 1 | 7µs | 16µs | BenchmarkAnything::Storage::Frontend::Lib::BEGIN@189 |
| 1 | 1 | 1 | 6µs | 9µs | main::BEGIN@2 |
| 1 | 1 | 1 | 6µs | 12µs | BenchmarkAnything::Storage::Frontend::Lib::BEGIN@36 |
| 1 | 1 | 1 | 6µs | 11µs | BenchmarkAnything::Storage::Frontend::Lib::BEGIN@51 |
| 1 | 1 | 1 | 6µs | 11µs | BenchmarkAnything::Storage::Frontend::Lib::BEGIN@66 |
| 1 | 1 | 1 | 5µs | 15µs | main::BEGIN@3 |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_are_you_sure |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_default_additional_keys |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_format_flat |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_format_flat_inner_array |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_format_flat_inner_hash |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_format_flat_inner_scalar |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_format_flat_outer |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_get_additional_key_id |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_get_base_url |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_get_benchmark_operators |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_get_user_agent |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::_output_format |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::add |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::createdb |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::getpoint |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::init_search_engine |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::init_workdir |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::listkeys |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::listnames |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::search |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::stats |
| 0 | 0 | 0 | 0s | 0s | BenchmarkAnything::Storage::Frontend::Lib::sync_search_engine |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | 2 | 31µs | 1 | 15µs | # spent 15µs within main::BEGIN@1.22 which was called:
# once (15µs+0s) by main::_connect at line 1 # spent 15µs making 1 call to main::BEGIN@1.22 |
| 2 | 2 | 15µs | 2 | 12µs | # spent 9µs (6+3) within main::BEGIN@2 which was called:
# once (6µs+3µs) by main::_connect at line 2 # spent 9µs making 1 call to main::BEGIN@2
# spent 3µs making 1 call to strict::import |
| 3 | 2 | 36µs | 2 | 25µs | # spent 15µs (5+10) within main::BEGIN@3 which was called:
# once (5µs+10µs) by main::_connect at line 3 # spent 15µs making 1 call to main::BEGIN@3
# spent 10µs making 1 call to warnings::import |
| 4 | package BenchmarkAnything::Storage::Frontend::Lib; | ||||
| 5 | # git description: v0.021-0-g0676cfd | ||||
| 6 | |||||
| 7 | 1 | 400ns | our $AUTHORITY = 'cpan:SCHWIGON'; | ||
| 8 | # ABSTRACT: Basic functions to access a BenchmarkAnything store | ||||
| 9 | 1 | 400ns | $BenchmarkAnything::Storage::Frontend::Lib::VERSION = '0.022'; | ||
| 10 | 2 | 135µs | 2 | 1.05ms | # spent 996µs (699+297) within BenchmarkAnything::Storage::Frontend::Lib::BEGIN@10 which was called:
# once (699µs+297µs) by main::_connect at line 10 # spent 996µs making 1 call to BenchmarkAnything::Storage::Frontend::Lib::BEGIN@10
# spent 56µs making 1 call to Exporter::import |
| 11 | |||||
| 12 | |||||
| 13 | sub new | ||||
| 14 | # spent 97.0ms (254µs+96.8) within BenchmarkAnything::Storage::Frontend::Lib::new which was called:
# once (254µs+96.8ms) by main::_connect at line 167 of /home/ss5/perl5/perlbrew/perls/perl-5.22.0/bin/benchmarkanything-storage | ||||
| 15 | 1 | 500ns | my $class = shift; | ||
| 16 | 1 | 4µs | my $self = bless { @_ }, $class; | ||
| 17 | 1 | 59µs | require BenchmarkAnything::Config; | ||
| 18 | 1 | 6µs | 1 | 37.9ms | $self->{config} = BenchmarkAnything::Config->new(cfgfile => $self->{cfgfile}) unless $self->{noconfig}; # spent 37.9ms making 1 call to BenchmarkAnything::Config::new |
| 19 | 1 | 3µs | 1 | 58.9ms | $self->connect unless $self->{noconnect}; # spent 58.9ms making 1 call to BenchmarkAnything::Storage::Frontend::Lib::connect |
| 20 | 1 | 4µs | return $self; | ||
| 21 | } | ||||
| 22 | |||||
| 23 | sub _format_flat_inner_scalar | ||||
| 24 | { | ||||
| 25 | my ($self, $result, $opt) = @_; | ||||
| 26 | |||||
| 27 | 2 | 41µs | 2 | 42µs | # spent 26µs (9+16) within BenchmarkAnything::Storage::Frontend::Lib::BEGIN@27 which was called:
# once (9µs+16µs) by main::_connect at line 27 # spent 26µs making 1 call to BenchmarkAnything::Storage::Frontend::Lib::BEGIN@27
# spent 16µs making 1 call to warnings::unimport |
| 28 | |||||
| 29 | return "$result"; | ||||
| 30 | } | ||||
| 31 | |||||
| 32 | sub _format_flat_inner_array | ||||
| 33 | { | ||||
| 34 | my ($self, $result, $opt) = @_; | ||||
| 35 | |||||
| 36 | 2 | 65µs | 2 | 18µs | # spent 12µs (6+6) within BenchmarkAnything::Storage::Frontend::Lib::BEGIN@36 which was called:
# once (6µs+6µs) by main::_connect at line 36 # spent 12µs making 1 call to BenchmarkAnything::Storage::Frontend::Lib::BEGIN@36
# spent 6µs making 1 call to warnings::unimport |
| 37 | |||||
| 38 | return | ||||
| 39 | join($opt->{separator}, | ||||
| 40 | map { | ||||
| 41 | # only SCALARS allowed (where reftype returns undef) | ||||
| 42 | die "benchmarkanything: unsupported innermost nesting (".reftype($_).") for 'flat' output.\n" if defined reftype($_); | ||||
| 43 | "".$_ | ||||
| 44 | } @$result); | ||||
| 45 | } | ||||
| 46 | |||||
| 47 | sub _format_flat_inner_hash | ||||
| 48 | { | ||||
| 49 | my ($self, $result, $opt) = @_; | ||||
| 50 | |||||
| 51 | 2 | 76µs | 2 | 17µs | # spent 11µs (6+6) within BenchmarkAnything::Storage::Frontend::Lib::BEGIN@51 which was called:
# once (6µs+6µs) by main::_connect at line 51 # spent 11µs making 1 call to BenchmarkAnything::Storage::Frontend::Lib::BEGIN@51
# spent 6µs making 1 call to warnings::unimport |
| 52 | |||||
| 53 | return | ||||
| 54 | join($opt->{separator}, | ||||
| 55 | map { my $v = $result->{$_}; | ||||
| 56 | # only SCALARS allowed (where reftype returns undef) | ||||
| 57 | die "benchmarkanything: unsupported innermost nesting (".reftype($v).") for 'flat' output.\n" if defined reftype($v); | ||||
| 58 | "$_=".$v | ||||
| 59 | } keys %$result); | ||||
| 60 | } | ||||
| 61 | |||||
| 62 | sub _format_flat_outer | ||||
| 63 | { | ||||
| 64 | my ($self, $result, $opt) = @_; | ||||
| 65 | |||||
| 66 | 2 | 443µs | 2 | 17µs | # spent 11µs (6+6) within BenchmarkAnything::Storage::Frontend::Lib::BEGIN@66 which was called:
# once (6µs+6µs) by main::_connect at line 66 # spent 11µs making 1 call to BenchmarkAnything::Storage::Frontend::Lib::BEGIN@66
# spent 6µs making 1 call to warnings::unimport |
| 67 | |||||
| 68 | my $output = ""; | ||||
| 69 | die "benchmarkanything: can not flatten data structure (undef) - try other output format.\n" unless defined $result; | ||||
| 70 | |||||
| 71 | my $A = ""; my $B = ""; if ($opt->{fb}) { $A = "["; $B = "]" } | ||||
| 72 | my $fi = $opt->{fi}; | ||||
| 73 | |||||
| 74 | if (!defined reftype $result) { # SCALAR | ||||
| 75 | $output .= $result."\n"; # stringify | ||||
| 76 | } | ||||
| 77 | elsif (reftype $result eq 'ARRAY') { | ||||
| 78 | for (my $i=0; $i<@$result; $i++) { | ||||
| 79 | my $entry = $result->[$i]; | ||||
| 80 | my $prefix = $fi ? "$i:" : ""; | ||||
| 81 | if (!defined reftype $entry) { # SCALAR | ||||
| 82 | $output .= $prefix.$A.$self->_format_flat_inner_scalar($entry, $opt)."$B\n"; | ||||
| 83 | } | ||||
| 84 | elsif (reftype $entry eq 'ARRAY') { | ||||
| 85 | $output .= $prefix.$A.$self->_format_flat_inner_array($entry, $opt)."$B\n"; | ||||
| 86 | } | ||||
| 87 | elsif (reftype $entry eq 'HASH') { | ||||
| 88 | $output .= $prefix.$A.$self->_format_flat_inner_hash($entry, $opt)."$B\n"; | ||||
| 89 | } | ||||
| 90 | else { | ||||
| 91 | die "benchmarkanything: can not flatten data structure (".reftype($entry).").\n"; | ||||
| 92 | } | ||||
| 93 | } | ||||
| 94 | } | ||||
| 95 | elsif (reftype $result eq 'HASH') { | ||||
| 96 | my @keys = keys %$result; | ||||
| 97 | foreach my $key (@keys) { | ||||
| 98 | my $entry = $result->{$key}; | ||||
| 99 | if (!defined reftype $entry) { # SCALAR | ||||
| 100 | $output .= "$key:".$self->_format_flat_inner_scalar($entry, $opt)."\n"; | ||||
| 101 | } | ||||
| 102 | elsif (reftype $entry eq 'ARRAY') { | ||||
| 103 | $output .= "$key:".$self->_format_flat_inner_array($entry, $opt)."\n"; | ||||
| 104 | } | ||||
| 105 | elsif (reftype $entry eq 'HASH') { | ||||
| 106 | $output .= "$key:".$self->_format_flat_inner_hash($entry, $opt)."\n"; | ||||
| 107 | } | ||||
| 108 | else { | ||||
| 109 | die "benchmarkanything: can not flatten data structure (".reftype($entry).").\n"; | ||||
| 110 | } | ||||
| 111 | } | ||||
| 112 | } | ||||
| 113 | else { | ||||
| 114 | die "benchmarkanything: can not flatten data structure (".reftype($result).") - try other output format.\n"; | ||||
| 115 | } | ||||
| 116 | |||||
| 117 | return $output; | ||||
| 118 | } | ||||
| 119 | |||||
| 120 | sub _format_flat | ||||
| 121 | { | ||||
| 122 | my ($self, $result, $opt) = @_; | ||||
| 123 | |||||
| 124 | # ensure array container | ||||
| 125 | # for consistent output in 'getpoint' and 'search' | ||||
| 126 | my $resultlist = reftype($result) eq 'ARRAY' ? $result : [$result]; | ||||
| 127 | |||||
| 128 | my $output = ""; | ||||
| 129 | $opt->{separator} = ";" unless defined $opt->{separator}; | ||||
| 130 | $output .= $self->_format_flat_outer($resultlist, $opt); | ||||
| 131 | return $output; | ||||
| 132 | } | ||||
| 133 | |||||
| 134 | |||||
| 135 | sub _output_format | ||||
| 136 | { | ||||
| 137 | my ($self, $data, $opt) = @_; | ||||
| 138 | |||||
| 139 | my $output = ""; | ||||
| 140 | my $outtype = $opt->{outtype} || 'json'; | ||||
| 141 | |||||
| 142 | if ($outtype eq "yaml") | ||||
| 143 | { | ||||
| 144 | require YAML::Any; | ||||
| 145 | $output .= YAML::Any::Dump($data); | ||||
| 146 | } | ||||
| 147 | elsif ($outtype eq "json") | ||||
| 148 | { | ||||
| 149 | eval "use JSON -convert_blessed_universally"; | ||||
| 150 | my $json = JSON->new->allow_nonref->pretty->allow_blessed->convert_blessed; | ||||
| 151 | $output .= $json->encode($data); | ||||
| 152 | } | ||||
| 153 | elsif ($outtype eq "ini") { | ||||
| 154 | require Config::INI::Serializer; | ||||
| 155 | my $ini = Config::INI::Serializer->new; | ||||
| 156 | $output .= $ini->serialize($data); | ||||
| 157 | } | ||||
| 158 | elsif ($outtype eq "dumper") | ||||
| 159 | { | ||||
| 160 | require Data::Dumper; | ||||
| 161 | $output .= Data::Dumper::Dumper($data); | ||||
| 162 | } | ||||
| 163 | elsif ($outtype eq "xml") | ||||
| 164 | { | ||||
| 165 | require XML::Simple; | ||||
| 166 | my $xs = new XML::Simple; | ||||
| 167 | $output .= $xs->XMLout($data, AttrIndent => 1, KeepRoot => 1); | ||||
| 168 | } | ||||
| 169 | elsif ($outtype eq "flat") { | ||||
| 170 | $output .= $self->_format_flat( $data, $opt ); | ||||
| 171 | } | ||||
| 172 | else | ||||
| 173 | { | ||||
| 174 | die "benchmarkanything-storage: unrecognized output format: $outtype."; | ||||
| 175 | } | ||||
| 176 | return $output; | ||||
| 177 | } | ||||
| 178 | |||||
| 179 | |||||
| 180 | sub connect | ||||
| 181 | # spent 58.9ms (9.88+49.0) within BenchmarkAnything::Storage::Frontend::Lib::connect which was called:
# once (9.88ms+49.0ms) by BenchmarkAnything::Storage::Frontend::Lib::new at line 19 | ||||
| 182 | 1 | 500ns | my ($self) = @_; | ||
| 183 | |||||
| 184 | 1 | 800ns | my $backend = $self->{config}{benchmarkanything}{backend}; | ||
| 185 | 1 | 3µs | if ($backend eq 'local') | ||
| 186 | { | ||||
| 187 | 1 | 60µs | require DBI; | ||
| 188 | 1 | 90µs | require BenchmarkAnything::Storage::Backend::SQL; | ||
| 189 | 2 | 331µs | 2 | 24µs | # spent 16µs (7+8) within BenchmarkAnything::Storage::Frontend::Lib::BEGIN@189 which was called:
# once (7µs+8µs) by main::_connect at line 189 # spent 16µs making 1 call to BenchmarkAnything::Storage::Frontend::Lib::BEGIN@189
# spent 8µs making 1 call to warnings::unimport |
| 190 | |||||
| 191 | # connect | ||||
| 192 | 1 | 1µs | print "Connect db...\n" if $self->{debug}; | ||
| 193 | 1 | 2µs | my $dsn = $self->{config}{benchmarkanything}{storage}{backend}{sql}{dsn}; | ||
| 194 | 1 | 1µs | my $user = $self->{config}{benchmarkanything}{storage}{backend}{sql}{user}; | ||
| 195 | 1 | 600ns | my $password = $self->{config}{benchmarkanything}{storage}{backend}{sql}{password}; | ||
| 196 | 1 | 3µs | 1 | 8.29ms | my $dbh = DBI->connect($dsn, $user, $password, {'RaiseError' => 1}) # spent 8.29ms making 1 call to DBI::connect |
| 197 | or die "benchmarkanything: can not connect: ".$DBI::errstr; | ||||
| 198 | |||||
| 199 | # external search engine | ||||
| 200 | 1 | 2µs | my $searchengine = $self->{config}{benchmarkanything}{searchengine} || {}; | ||
| 201 | |||||
| 202 | # remember | ||||
| 203 | 1 | 1µs | $self->{dbh} = $dbh; | ||
| 204 | $self->{backend} = BenchmarkAnything::Storage::Backend::SQL->new({dbh => $dbh, | ||||
| 205 | dbh_config => $self->{config}{benchmarkanything}{storage}{backend}{sql}, | ||||
| 206 | debug => $self->{debug}, | ||||
| 207 | force => $self->{force}, | ||||
| 208 | verbose => $self->{verbose}, | ||||
| 209 | 1 | 10µs | 1 | 39.7ms | (keys %$searchengine ? (searchengine => $searchengine) : ()), # spent 39.7ms making 1 call to BenchmarkAnything::Storage::Backend::SQL::new |
| 210 | }); | ||||
| 211 | } | ||||
| 212 | elsif ($backend eq 'http') | ||||
| 213 | { | ||||
| 214 | my $ua = $self->_get_user_agent; | ||||
| 215 | my $url = $self->_get_base_url."/api/v1/hello"; | ||||
| 216 | die "benchmarkanything: can't connect to result storage ($url)\n" if (!$ua->get($url)->res->code or $ua->get($url)->res->code != 200); | ||||
| 217 | } | ||||
| 218 | |||||
| 219 | 1 | 3µs | return $self; | ||
| 220 | } | ||||
| 221 | |||||
| 222 | |||||
| 223 | sub disconnect | ||||
| 224 | # spent 26µs (19+7) within BenchmarkAnything::Storage::Frontend::Lib::disconnect which was called:
# once (19µs+7µs) by main::_disconnect at line 178 of /home/ss5/perl5/perlbrew/perls/perl-5.22.0/bin/benchmarkanything-storage | ||||
| 225 | 1 | 500ns | my ($self) = @_; | ||
| 226 | |||||
| 227 | 1 | 3µs | my $backend = $self->{config}{benchmarkanything}{backend}; | ||
| 228 | 1 | 1µs | if ($backend eq 'local') | ||
| 229 | { | ||||
| 230 | 1 | 1µs | if ($self->{dbh}) { | ||
| 231 | 1 | 17µs | 1 | 7µs | $self->{dbh}->commit unless $self->{dbh}{AutoCommit}; # spent 7µs making 1 call to DBI::common::FETCH |
| 232 | 1 | 1µs | undef $self->{dbh}; # setting dbh to undef does better cleanup than disconnect(); | ||
| 233 | } | ||||
| 234 | } | ||||
| 235 | 1 | 4µs | return $self; | ||
| 236 | } | ||||
| 237 | |||||
| 238 | |||||
| 239 | sub _are_you_sure | ||||
| 240 | { | ||||
| 241 | my ($self) = @_; | ||||
| 242 | |||||
| 243 | # DSN | ||||
| 244 | my $dsn = $self->{config}{benchmarkanything}{storage}{backend}{sql}{dsn}; | ||||
| 245 | |||||
| 246 | # option --really | ||||
| 247 | if ($self->{really}) | ||||
| 248 | { | ||||
| 249 | if ($self->{really} eq $dsn) | ||||
| 250 | { | ||||
| 251 | return 1; | ||||
| 252 | } | ||||
| 253 | else | ||||
| 254 | { | ||||
| 255 | print STDERR "DSN does not match - asking interactive.\n"; | ||||
| 256 | } | ||||
| 257 | } | ||||
| 258 | |||||
| 259 | # ask on stdin | ||||
| 260 | print "REALLY DROP AND RE-CREATE DATABASE TABLES [$dsn] (y/N): "; | ||||
| 261 | read STDIN, my $answer, 1; | ||||
| 262 | return 1 if $answer && $answer =~ /^y(es)?$/i; | ||||
| 263 | |||||
| 264 | # default: NO | ||||
| 265 | return 0; | ||||
| 266 | } | ||||
| 267 | |||||
| 268 | |||||
| 269 | sub createdb | ||||
| 270 | { | ||||
| 271 | my ($self) = @_; | ||||
| 272 | |||||
| 273 | if ($self->_are_you_sure) | ||||
| 274 | { | ||||
| 275 | 2 | 30µs | 2 | 24µs | # spent 16µs (8+8) within BenchmarkAnything::Storage::Frontend::Lib::BEGIN@275 which was called:
# once (8µs+8µs) by main::_connect at line 275 # spent 16µs making 1 call to BenchmarkAnything::Storage::Frontend::Lib::BEGIN@275
# spent 8µs making 1 call to warnings::unimport |
| 276 | |||||
| 277 | require DBI; | ||||
| 278 | require File::Slurper; | ||||
| 279 | require File::ShareDir; | ||||
| 280 | 2 | 1.19ms | 1 | 329ms | # spent 329ms (420µs+328) within BenchmarkAnything::Storage::Frontend::Lib::BEGIN@280 which was called:
# once (420µs+328ms) by main::_connect at line 280 # spent 329ms making 1 call to BenchmarkAnything::Storage::Frontend::Lib::BEGIN@280 |
| 281 | |||||
| 282 | my $batch = DBIx::MultiStatementDo->new(dbh => $self->{dbh}); | ||||
| 283 | |||||
| 284 | # get schema SQL according to driver | ||||
| 285 | my $dsn = $self->{config}{benchmarkanything}{storage}{backend}{sql}{dsn}; | ||||
| 286 | my ($scheme, $driver, $attr_string, $attr_hash, $driver_dsn) = DBI->parse_dsn($dsn) | ||||
| 287 | or die "benchmarkanything: can not parse DBI DSN '$dsn'"; | ||||
| 288 | my ($dbname) = $driver_dsn =~ m/database=(\w+)/g; | ||||
| 289 | my $sql_file = File::ShareDir::dist_file('BenchmarkAnything-Storage-Backend-SQL', "create-schema.$driver"); | ||||
| 290 | my $sql = File::Slurper::read_text($sql_file); | ||||
| 291 | $sql =~ s/^use `testrundb`;/use `$dbname`;/m if $dbname; # replace BenchmarkAnything::Storage::Backend::SQL's default | ||||
| 292 | |||||
| 293 | # execute schema SQL | ||||
| 294 | my @results = $batch->do($sql); | ||||
| 295 | if (not @results) | ||||
| 296 | { | ||||
| 297 | die "benchmarkanything: error while creating BenchmarkAnything DB: ".$batch->dbh->errstr; | ||||
| 298 | } | ||||
| 299 | |||||
| 300 | } | ||||
| 301 | |||||
| 302 | return; | ||||
| 303 | } | ||||
| 304 | |||||
| 305 | |||||
| 306 | sub _default_additional_keys | ||||
| 307 | { | ||||
| 308 | my ($self) = @_; | ||||
| 309 | |||||
| 310 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 311 | if ($backend eq 'local') | ||||
| 312 | { | ||||
| 313 | return { $self->{backend}->default_columns }; | ||||
| 314 | } | ||||
| 315 | else | ||||
| 316 | { | ||||
| 317 | # Hardcoded from BenchmarkAnything::Storage::Backend::SQL::Query::common, | ||||
| 318 | # as it is a backend-special and internal thing anyway. | ||||
| 319 | return { | ||||
| 320 | 'NAME' => 'b.bench', | ||||
| 321 | 'UNIT' => 'bu.bench_unit', | ||||
| 322 | 'VALUE' => 'bv.bench_value', | ||||
| 323 | 'VALUE_ID' => 'bv.bench_value_id', | ||||
| 324 | 'CREATED' => 'bv.created_at', | ||||
| 325 | }; | ||||
| 326 | } | ||||
| 327 | } | ||||
| 328 | |||||
| - - | |||||
| 331 | sub _get_benchmark_operators | ||||
| 332 | { | ||||
| 333 | my ($self) = @_; | ||||
| 334 | |||||
| 335 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 336 | if ($backend eq 'local') | ||||
| 337 | { | ||||
| 338 | return [ $self->{backend}->benchmark_operators ]; | ||||
| 339 | } | ||||
| 340 | else | ||||
| 341 | { | ||||
| 342 | # Hardcoded from BenchmarkAnything::Storage::Backend::SQL::Query::common, | ||||
| 343 | # as it is a backend-special and internal thing anyway. | ||||
| 344 | return [ '=', '!=', 'like', 'not like', '<', '>', '<=', '>=' ]; | ||||
| 345 | } | ||||
| 346 | } | ||||
| 347 | |||||
| - - | |||||
| 350 | sub _get_additional_key_id | ||||
| 351 | { | ||||
| 352 | my ($self, $key_name) = @_; | ||||
| 353 | |||||
| 354 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 355 | if ($backend eq 'local') | ||||
| 356 | { | ||||
| 357 | return $self->{backend}->_get_additional_key_id($key_name); | ||||
| 358 | } | ||||
| 359 | else | ||||
| 360 | { | ||||
| 361 | die "benchmarkanything: no backend '$backend' allowed here, available backends are: 'local'.\n"; | ||||
| 362 | } | ||||
| 363 | } | ||||
| 364 | |||||
| - - | |||||
| 367 | sub init_workdir | ||||
| 368 | { | ||||
| 369 | my ($self) = @_; | ||||
| 370 | |||||
| 371 | require File::Basename; | ||||
| 372 | require File::ShareDir; | ||||
| 373 | require File::HomeDir; | ||||
| 374 | require File::Slurper; | ||||
| 375 | |||||
| 376 | my $home_ba = File::HomeDir->my_home."/.benchmarkanything"; | ||||
| 377 | my $command = File::Basename::basename($0); | ||||
| 378 | |||||
| 379 | if (-d $home_ba) | ||||
| 380 | { | ||||
| 381 | print "Workdir '$home_ba' already exists - skipping.\n" if $self->{verbose}; | ||||
| 382 | } | ||||
| 383 | else | ||||
| 384 | { | ||||
| 385 | require File::Path; | ||||
| 386 | File::Path::make_path($home_ba); | ||||
| 387 | } | ||||
| 388 | |||||
| 389 | foreach my $basename (qw(client.cfg server.cfg default.cfg README)) | ||||
| 390 | { | ||||
| 391 | my $source_file = File::ShareDir::dist_file('BenchmarkAnything-Storage-Frontend-Lib', "config/$basename"); | ||||
| 392 | my $dest_file = "$home_ba/$basename"; | ||||
| 393 | |||||
| 394 | if (! -e $dest_file) | ||||
| 395 | { | ||||
| 396 | my $content = File::Slurper::read_text($source_file); | ||||
| 397 | |||||
| 398 | # poor man's templating | ||||
| 399 | $content =~ s{\[%\s*CLIENTCFG\s*%\]}{$home_ba/client.cfg}g; | ||||
| 400 | $content =~ s{\[%\s*SERVERCFG\s*%\]}{$home_ba/server.cfg}g; | ||||
| 401 | $content =~ s{\[%\s*LOCALCFG\s*%\]}{$home_ba/default.cfg}g; | ||||
| 402 | $content =~ s{\[%\s*CFG\s*%\]}{$dest_file}g; | ||||
| 403 | $content =~ s{\[%\s*HOME\s*%\]}{$home_ba}g; | ||||
| 404 | |||||
| 405 | print "Create configfile: $dest_file...\n" if $self->{verbose}; | ||||
| 406 | open my $CFGFILE, ">", $dest_file or die "Could not create $dest_file.\n"; | ||||
| 407 | print $CFGFILE $content; | ||||
| 408 | close $CFGFILE; | ||||
| 409 | } | ||||
| 410 | else | ||||
| 411 | { | ||||
| 412 | print "Config '$dest_file' already exists - skipping.\n" if $self->{verbose}; | ||||
| 413 | } | ||||
| 414 | } | ||||
| 415 | |||||
| 416 | my $dbfile = "$home_ba/benchmarkanything.sqlite"; | ||||
| 417 | my $we_created_db = 0; | ||||
| 418 | if (! -e $dbfile) | ||||
| 419 | { | ||||
| 420 | print "Create storage: $dbfile...\n" if $self->{verbose}; | ||||
| 421 | __PACKAGE__->new(cfgfile => "$home_ba/default.cfg", | ||||
| 422 | really => "dbi:SQLite:$dbfile", | ||||
| 423 | )->createdb; | ||||
| 424 | $we_created_db = 1; | ||||
| 425 | } | ||||
| 426 | else | ||||
| 427 | { | ||||
| 428 | print "Storage '$dbfile' already exists - skipping.\n" if $self->{verbose}; | ||||
| 429 | } | ||||
| 430 | |||||
| 431 | if ($self->{verbose}) | ||||
| 432 | { | ||||
| 433 | print "\n"; | ||||
| 434 | print "By default it will use this config: $home_ba/default.cfg\n"; | ||||
| 435 | print "If you want another one, set it in your ~/.bash_profile:\n"; | ||||
| 436 | print " export BENCHMARKANYTHING_CONFIGFILE=$home_ba/client.cfg\n"; | ||||
| 437 | |||||
| 438 | unless ($we_created_db) | ||||
| 439 | { | ||||
| 440 | print "\n"; | ||||
| 441 | print "Initialize a new database (it asks for confirmation) with:\n"; | ||||
| 442 | print " $command createdb\n"; | ||||
| 443 | print "\nReady.\n"; | ||||
| 444 | } | ||||
| 445 | else | ||||
| 446 | { | ||||
| 447 | print "\n"; | ||||
| 448 | print "Create sample values like this:\n"; | ||||
| 449 | print qq( echo '{"BenchmarkAnythingData":[{"NAME":"benchmarkanything.hello.world", "VALUE":17.2}]}' | $command add\n); | ||||
| 450 | print "\n"; | ||||
| 451 | print "List metric names:\n"; | ||||
| 452 | print qq( $command listnames\n); | ||||
| 453 | print "\n"; | ||||
| 454 | print "Query sample values:\n"; | ||||
| 455 | print qq( echo '{"select":["NAME","VALUE"],"where":[["=","NAME","benchmarkanything.hello.world"]]}' | $command search\n); | ||||
| 456 | print "\n"; | ||||
| 457 | } | ||||
| 458 | } | ||||
| 459 | |||||
| 460 | return; | ||||
| 461 | } | ||||
| 462 | |||||
| 463 | |||||
| 464 | sub add | ||||
| 465 | { | ||||
| 466 | my ($self, $data) = @_; | ||||
| 467 | |||||
| 468 | # --- validate --- | ||||
| 469 | if (not $data) | ||||
| 470 | { | ||||
| 471 | die "benchmarkanything: no input data provided.\n"; | ||||
| 472 | } | ||||
| 473 | |||||
| 474 | if (not $self->{skipvalidation}) { | ||||
| 475 | require BenchmarkAnything::Schema; | ||||
| 476 | print "Verify schema...\n" if $self->{verbose}; | ||||
| 477 | if (not my $result = BenchmarkAnything::Schema::valid_json_schema($data)) | ||||
| 478 | { | ||||
| 479 | die "benchmarkanything: add: invalid input: ".join("; ", $result->errors)."\n"; | ||||
| 480 | } | ||||
| 481 | } | ||||
| 482 | |||||
| 483 | # --- add to storage --- | ||||
| 484 | |||||
| 485 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 486 | if ($backend eq 'local') | ||||
| 487 | { | ||||
| 488 | my $success; | ||||
| 489 | if ($self->{queuemode}) | ||||
| 490 | { | ||||
| 491 | # only queue for later processing | ||||
| 492 | print "Enqueue data [backend:local]...\n" if $self->{verbose} or $self->{debug}; | ||||
| 493 | $success = $self->{backend}->enqueue_multi_benchmark($data->{BenchmarkAnythingData}); | ||||
| 494 | } | ||||
| 495 | else | ||||
| 496 | { | ||||
| 497 | print "Add data [backend:local]...\n" if $self->{verbose} or $self->{debug}; | ||||
| 498 | # preserve order, otherwise add_multi_benchmark() would reorder to optimize insert | ||||
| 499 | foreach my $chunk (@{$data->{BenchmarkAnythingData}}) | ||||
| 500 | { | ||||
| 501 | print "." if $self->{debug}; | ||||
| 502 | $success = $self->{backend}->add_multi_benchmark([$chunk]); | ||||
| 503 | } | ||||
| 504 | } | ||||
| 505 | if (not $success) | ||||
| 506 | { | ||||
| 507 | die "benchmarkanything: error while adding data: ".$@; | ||||
| 508 | } | ||||
| 509 | print "Done.\n" if $self->{verbose} or $self->{debug}; | ||||
| 510 | } | ||||
| 511 | elsif ($backend eq 'http') | ||||
| 512 | { | ||||
| 513 | require BenchmarkAnything::Reporter; | ||||
| 514 | $self->{config} = BenchmarkAnything::Reporter->new(config => $self->{config}, | ||||
| 515 | verbose => $self->{verbose}, | ||||
| 516 | debug => $self->{debug}, | ||||
| 517 | ); | ||||
| 518 | } | ||||
| 519 | else | ||||
| 520 | { | ||||
| 521 | die "benchmarkanything: no backend '$backend', available backends are: 'http', 'local'.\n"; | ||||
| 522 | } | ||||
| 523 | |||||
| 524 | return $self; | ||||
| 525 | } | ||||
| 526 | |||||
| 527 | sub _get_user_agent | ||||
| 528 | { | ||||
| 529 | require Mojo::UserAgent; | ||||
| 530 | return Mojo::UserAgent->new; | ||||
| 531 | } | ||||
| 532 | |||||
| 533 | sub _get_base_url | ||||
| 534 | { | ||||
| 535 | shift->{config}{benchmarkanything}{backends}{http}{base_url}; | ||||
| 536 | } | ||||
| 537 | |||||
| 538 | |||||
| 539 | sub search | ||||
| 540 | { | ||||
| 541 | my ($self, $query, $value_id) = @_; | ||||
| 542 | |||||
| 543 | # --- validate --- | ||||
| 544 | if (not $query and not $value_id) | ||||
| 545 | { | ||||
| 546 | die "benchmarkanything: no query or value_id provided.\n"; | ||||
| 547 | } | ||||
| 548 | |||||
| 549 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 550 | if ($backend eq 'local') | ||||
| 551 | { | ||||
| 552 | # single values | ||||
| 553 | return $self->{backend}->get_single_benchmark_point($value_id) if $value_id; | ||||
| 554 | return $self->{backend}->search_array($query); | ||||
| 555 | } | ||||
| 556 | elsif ($backend eq 'http') | ||||
| 557 | { | ||||
| 558 | my $ua = $self->_get_user_agent; | ||||
| 559 | my $url = $self->_get_base_url."/api/v1/search"; | ||||
| 560 | my $res; | ||||
| 561 | if ($value_id) { | ||||
| 562 | $url .= "/$value_id"; | ||||
| 563 | $res = $ua->get($url)->res; | ||||
| 564 | } else { | ||||
| 565 | $res = $ua->post($url => json => $query)->res; | ||||
| 566 | } | ||||
| 567 | |||||
| 568 | die "benchmarkanything: ".$res->error->{message}." ($url)\n" if $res->error; | ||||
| 569 | |||||
| 570 | return $res->json; | ||||
| 571 | } | ||||
| 572 | else | ||||
| 573 | { | ||||
| 574 | die "benchmarkanything: no backend '$backend', available backends are: 'http', 'local'.\n"; | ||||
| 575 | } | ||||
| 576 | } | ||||
| 577 | |||||
| 578 | |||||
| 579 | sub listnames | ||||
| 580 | { | ||||
| 581 | my ($self, $pattern) = @_; | ||||
| 582 | |||||
| 583 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 584 | if ($backend eq 'local') | ||||
| 585 | { | ||||
| 586 | return $self->{backend}->list_benchmark_names(defined($pattern) ? ($pattern) : ()); | ||||
| 587 | } | ||||
| 588 | elsif ($backend eq 'http') | ||||
| 589 | { | ||||
| 590 | my $ua = $self->_get_user_agent; | ||||
| 591 | my $url = $self->_get_base_url."/api/v1/listnames"; | ||||
| 592 | |||||
| 593 | my $res = $ua->get($url)->res; | ||||
| 594 | die "benchmarkanything: ".$res->error->{message}." ($url)\n" if $res->error; | ||||
| 595 | |||||
| 596 | my $result = $res->json; | ||||
| 597 | |||||
| 598 | # output | ||||
| 599 | return $result; | ||||
| 600 | } | ||||
| 601 | else | ||||
| 602 | { | ||||
| 603 | die "benchmarkanything: no backend '$backend', available backends are: 'http', 'local'.\n"; | ||||
| 604 | } | ||||
| 605 | } | ||||
| 606 | |||||
| 607 | |||||
| 608 | sub listkeys | ||||
| 609 | { | ||||
| 610 | my ($self, $pattern) = @_; | ||||
| 611 | |||||
| 612 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 613 | if ($backend eq 'local') | ||||
| 614 | { | ||||
| 615 | return $self->{backend}->list_additional_keys(defined($pattern) ? ($pattern) : ()); | ||||
| 616 | } | ||||
| 617 | elsif ($backend eq 'http') | ||||
| 618 | { | ||||
| 619 | my $ua = $self->_get_user_agent; | ||||
| 620 | my $url = $self->_get_base_url."/api/v1/listkeys"; | ||||
| 621 | |||||
| 622 | my $res = $ua->get($url)->res; | ||||
| 623 | die "benchmarkanything: ".$res->error->{message}." ($url)\n" if $res->error; | ||||
| 624 | |||||
| 625 | my $result = $res->json; | ||||
| 626 | |||||
| 627 | # output | ||||
| 628 | return $result; | ||||
| 629 | } | ||||
| 630 | else | ||||
| 631 | { | ||||
| 632 | die "benchmarkanything: no backend '$backend', available backends are: 'http', 'local'.\n"; | ||||
| 633 | } | ||||
| 634 | } | ||||
| 635 | |||||
| 636 | |||||
| 637 | sub stats | ||||
| 638 | { | ||||
| 639 | my ($self) = @_; | ||||
| 640 | |||||
| 641 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 642 | if ($backend eq 'local') | ||||
| 643 | { | ||||
| 644 | return $self->{backend}->get_stats; | ||||
| 645 | } | ||||
| 646 | elsif ($backend eq 'http') | ||||
| 647 | { | ||||
| 648 | my $ua = $self->_get_user_agent; | ||||
| 649 | my $url = $self->_get_base_url."/api/v1/stats"; | ||||
| 650 | |||||
| 651 | my $res = $ua->get($url)->res; | ||||
| 652 | die "benchmarkanything: ".$res->error->{message}." ($url)\n" if $res->error; | ||||
| 653 | |||||
| 654 | my $result = $res->json; | ||||
| 655 | |||||
| 656 | # output | ||||
| 657 | return $result; | ||||
| 658 | } | ||||
| 659 | else | ||||
| 660 | { | ||||
| 661 | die "benchmarkanything: no backend '$backend', available backends are: 'http', 'local'.\n"; | ||||
| 662 | } | ||||
| 663 | } | ||||
| 664 | |||||
| 665 | |||||
| 666 | sub gc | ||||
| 667 | # spent 34.3ms (12µs+34.3) within BenchmarkAnything::Storage::Frontend::Lib::gc which was called:
# once (12µs+34.3ms) by main::_gc at line 433 of /home/ss5/perl5/perlbrew/perls/perl-5.22.0/bin/benchmarkanything-storage | ||||
| 668 | 1 | 400ns | my ($self) = @_; | ||
| 669 | |||||
| 670 | 1 | 3µs | my $backend = $self->{config}{benchmarkanything}{backend}; | ||
| 671 | 1 | 8µs | 1 | 34.3ms | if ($backend eq 'local') # spent 34.3ms making 1 call to BenchmarkAnything::Storage::Backend::SQL::gc |
| 672 | { | ||||
| 673 | $self->{backend}->gc; | ||||
| 674 | } | ||||
| 675 | } | ||||
| 676 | |||||
| 677 | |||||
| 678 | sub process_raw_result_queue | ||||
| 679 | # spent 53.0s (9.64ms+53.0) within BenchmarkAnything::Storage::Frontend::Lib::process_raw_result_queue which was called:
# once (9.64ms+53.0s) by main::_processqueue at line 406 of /home/ss5/perl5/perlbrew/perls/perl-5.22.0/bin/benchmarkanything-storage | ||||
| 680 | 1 | 400ns | my ($self, $count) = @_; | ||
| 681 | |||||
| 682 | 1 | 300ns | $count ||= 10; | ||
| 683 | |||||
| 684 | 1 | 2µs | my $backend = $self->{config}{benchmarkanything}{backend}; | ||
| 685 | 1 | 1µs | if ($backend eq 'local') | ||
| 686 | { | ||||
| 687 | 1 | 100ns | my $dequeued_raw_bench_bundle_id; | ||
| 688 | 1 | 1.62ms | do { | ||
| 689 | 1000 | 5.10ms | 1000 | 53.0s | $dequeued_raw_bench_bundle_id = $self->{backend}->process_queued_multi_benchmark; # spent 53.0s making 1000 calls to BenchmarkAnything::Storage::Backend::SQL::process_queued_multi_benchmark, avg 53.0ms/call |
| 690 | 1000 | 869µs | $count--; | ||
| 691 | } until ($count < 1 or not defined($dequeued_raw_bench_bundle_id)); | ||||
| 692 | } | ||||
| 693 | else | ||||
| 694 | { | ||||
| 695 | die "benchmarkanything: only backend 'local' allowed in 'process_raw_result_queue'.\n"; | ||||
| 696 | } | ||||
| 697 | 1 | 6µs | return; | ||
| 698 | } | ||||
| 699 | |||||
| 700 | |||||
| 701 | sub init_search_engine | ||||
| 702 | { | ||||
| 703 | my ($self, $force) = @_; | ||||
| 704 | |||||
| 705 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 706 | if ($backend eq 'local') | ||||
| 707 | { | ||||
| 708 | $self->{backend}->init_search_engine($force); | ||||
| 709 | } | ||||
| 710 | else | ||||
| 711 | { | ||||
| 712 | die "benchmarkanything: only backend 'local' allowed in 'init_search_engine'.\n"; | ||||
| 713 | } | ||||
| 714 | return; | ||||
| 715 | } | ||||
| 716 | |||||
| 717 | |||||
| 718 | sub sync_search_engine | ||||
| 719 | { | ||||
| 720 | my ($self, $force, $start, $count) = @_; | ||||
| 721 | |||||
| 722 | my $backend = $self->{config}{benchmarkanything}{backend}; | ||||
| 723 | if ($backend eq 'local') | ||||
| 724 | { | ||||
| 725 | $self->{backend}->sync_search_engine($force, $start, $count); | ||||
| 726 | } | ||||
| 727 | else | ||||
| 728 | { | ||||
| 729 | die "benchmarkanything: only backend 'local' allowed in 'sync_search_engine'.\n"; | ||||
| 730 | } | ||||
| 731 | return; | ||||
| 732 | } | ||||
| 733 | |||||
| - - | |||||
| 736 | sub getpoint | ||||
| 737 | { | ||||
| 738 | my ($self, $value_id) = @_; | ||||
| 739 | |||||
| 740 | return $self->search(undef, $value_id); | ||||
| 741 | die "benchmarkanything: please provide a benchmark value_id'\n" unless $value_id; | ||||
| 742 | } | ||||
| 743 | |||||
| 744 | 1 | 3µs | 1; | ||
| 745 | |||||
| 746 | __END__ |