Selkie.git | xt/bench/ | run.raku
#!/usr/bin/env raku
use v6.d;
use lib 'lib';
use Selkie::Store;
use Selkie::Widget;
use Selkie::Widget::ViewportedCardList;
use Selkie::Layout::VBox;
use Selkie::Sizing;
class BenchWidget does Selkie::Widget {
method render() { self.clear-dirty }
}
sub json-escape(Str:D $s --> Str) {
$s.trans(['\\', '"', "\n", "\r", "\t"] => ['\\\\', '\"', '\n', '\r', '\t']);
}
sub emit-json(%results --> Nil) {
say '{';
say ' "schema": 1,';
say ' "project": "Selkie",';
say ' "generated_at": "' ~ json-escape(DateTime.now.Str) ~ '",';
say ' "benchmarks": {';
my @names = %results.keys.sort;
for @names.kv -> $i, $name {
my %r = %results{$name};
say ' "' ~ json-escape($name) ~ '": {'
~ '"iterations": ' ~ %r<iterations>
~ ', "seconds": ' ~ %r<seconds>.fmt('%.9f')
~ ', "ops_per_second": ' ~ %r<ops_per_second>.fmt('%.3f')
~ ' }' ~ ($i == @names.end ?? '' !! ',');
}
say ' }';
say '}';
}
sub timed(Str:D $name, Int:D $iterations, &body, %results --> Nil) {
body(); # warm once so module-level laziness is not charged
my $start = now;
body() for ^$iterations;
my $seconds = (now - $start).Num max 0.000000001e0;
%results{$name} = %(
:$iterations,
:$seconds,
ops_per_second => $iterations / $seconds,
);
}
sub make-vcl(Int:D $n --> Selkie::Widget::ViewportedCardList) {
my $list = Selkie::Widget::ViewportedCardList.new(follow-bottom => True);
$list.resize(24, 100);
for ^$n -> $i {
my UInt $h = (3 + ($i % 11)).UInt;
my $widget = BenchWidget.new;
my $root = Selkie::Layout::VBox.new(sizing => Sizing.fixed($h));
$list.add-item($widget, :$root, height => $h);
}
$list;
}
my %results;
{
my $store = Selkie::Store.new;
my $w = BenchWidget.new;
$store.register-handler('inc', -> $st, % {
(db => { counter => ($st.get-in('counter') // 0) + 1 },);
});
for ^500 -> $i {
$store.subscribe-path-callback("counter-$i", ['counter'], -> $ {}, $w,
:identity-check-only);
}
timed 'store.dispatch_tick.500_path_subscribers', 1000, {
$store.dispatch('inc');
$store.tick;
}, %results;
}
{
my $list = make-vcl(1000);
my $max = $list.content-height - $list.viewport-height;
my $i = 0;
timed 'vcl.scroll_to.1000_variable_height_items', 5000, {
$list.scroll-to(($i * 17) % $max);
$i++;
}, %results;
}
{
my $list = make-vcl(1000);
my $i = 0;
timed 'vcl.select_index.1000_variable_height_items', 5000, {
$list.select-index(($i * 13) % $list.count);
$i++;
}, %results;
}
{
my $list = make-vcl(1000);
my $i = 0;
timed 'vcl.set_item_height.1000_variable_height_items', 5000, {
my $idx = ($i * 19) % $list.count;
$list.set-item-height($idx, 3 + (($i + $idx) % 11));
$i++;
}, %results;
}
emit-json(%results);