bench: Add JSON parsing benchmarks + nicer formatting

This shows I got some optimizing to do. I was expecting integer parsing
to be slower, though, but it looks like it can compete with JSON::XS's
specialized small-int parsing code anyway.
This commit is contained in:
Yorhel 2025-01-31 10:30:27 +01:00
parent 7cdc02e399
commit ca8d1b72be
2 changed files with 263 additions and 158 deletions

View file

@ -50,123 +50,216 @@ SIMD parts are only used for parsing.
API object from L<JSON::XS> documentation. API object from L<JSON::XS> documentation.
JSON::PP 5342/s Encode Canonical Decode
Cpanel::JSON::XS 110660/s JSON::PP 5397/s 4973/s 1290/s
JSON::SIMD 128161/s Cpanel::JSON::XS 112845/s 102903/s 101843/s
JSON::XS 130434/s JSON::SIMD 125127/s 116569/s 117446/s
FU::Util 129117/s JSON::XS 128792/s 118616/s 117257/s
FU::Util 126324/s 106597/s 62633/s
Object (small)
Encode Canonical Decode
JSON::PP 905/s 827/s 206/s
Cpanel::JSON::XS 42755/s 27849/s 18920/s
JSON::SIMD 48487/s 30266/s 22527/s
JSON::XS 48980/s 30558/s 24065/s
FU::Util 43172/s 24882/s 6818/s
Object (large)
Encode Canonical Decode
JSON::PP 916/s 744/s 105/s
Cpanel::JSON::XS 29889/s 11629/s 16264/s
JSON::SIMD 33950/s 12050/s 22649/s
JSON::XS 34534/s 12399/s 23418/s
FU::Util 37298/s 12001/s 5413/s
Object (large, mixed unicode)
Encode Canonical Decode
JSON::PP 845/s 699/s 86/s
Cpanel::JSON::XS 20563/s 1402/s 7590/s
JSON::SIMD 24996/s 1401/s 15959/s
JSON::XS 26915/s 1454/s 8848/s
FU::Util 24280/s 10461/s 5998/s
Small integers Small integers
JSON::PP 117/s Encode Decode
Cpanel::JSON::XS 7370/s JSON::PP 113/s 29/s
JSON::SIMD 8191/s Cpanel::JSON::XS 7235/s 6008/s
JSON::XS 8143/s JSON::SIMD 8058/s 4335/s
FU::Util 9188/s JSON::XS 8036/s 5998/s
FU::Util 8344/s 5656/s
Large integers Large integers
JSON::PP 2208/s Encode Decode
Cpanel::JSON::XS 29299/s JSON::PP 2174/s 330/s
JSON::SIMD 37344/s Cpanel::JSON::XS 31337/s 48514/s
JSON::XS 35873/s JSON::SIMD 36876/s 52446/s
FU::Util 114084/s JSON::XS 36665/s 48689/s
FU::Util 115559/s 62931/s
ASCII strings ASCII strings
JSON::PP 2798/s Encode Decode
Cpanel::JSON::XS 116754/s JSON::PP 2922/s 341/s
JSON::SIMD 134130/s Cpanel::JSON::XS 117604/s 43652/s
JSON::XS 133137/s JSON::SIMD 136214/s 50865/s
FU::Util 166142/s JSON::XS 136486/s 40599/s
FU::Util 168713/s 32742/s
Unicode strings Unicode strings
JSON::PP 5067/s Encode Decode
Cpanel::JSON::XS 95453/s JSON::PP 5144/s 254/s
JSON::SIMD 107955/s Cpanel::JSON::XS 92871/s 66032/s
JSON::XS 105367/s JSON::SIMD 106664/s 100555/s
FU::Util 103071/s JSON::XS 104716/s 60538/s
FU::Util 108032/s 36331/s
String escaping (few) String escaping (few)
JSON::PP 4275/s Encode Decode
Cpanel::JSON::XS 138030/s JSON::PP 4258/s 350/s
JSON::SIMD 157735/s Cpanel::JSON::XS 133222/s 104174/s
JSON::XS 159066/s JSON::SIMD 155205/s 148939/s
FU::Util 171426/s JSON::XS 123154/s 92594/s
FU::Util 206172/s 76491/s
String escaping (many) String escaping (many)
JSON::PP 2231/s Encode Decode
Cpanel::JSON::XS 140657/s JSON::PP 2230/s 360/s
JSON::SIMD 154850/s Cpanel::JSON::XS 139049/s 99260/s
JSON::XS 154280/s JSON::SIMD 152317/s 113037/s
FU::Util 132514/s JSON::XS 153421/s 107918/s
FU::Util 132774/s 64880/s
Canonical hash key ordering (small)
JSON::PP 835/s
Cpanel::JSON::XS 28155/s
JSON::SIMD 30066/s
JSON::XS 32151/s
FU::Util 27079/s
Canonical hash key ordering (large)
JSON::PP 756/s
Cpanel::JSON::XS 10710/s
JSON::SIMD 12640/s
JSON::XS 12858/s
FU::Util 12819/s
=cut =cut
# Cached data used by bench.PL. # Cached data used by bench.PL. Same as the formatted tables above but easier to parse.
jsonfmt/api Cpanel::JSON::XS Cpanel::JSON::XS 4.38 110660 json/api Canonical Cpanel::JSON::XS 102903
jsonfmt/api FU::Util FU 0.1 129117 json/api Canonical FU::Util 106597
jsonfmt/api JSON::PP JSON::PP 4.16 5342 json/api Canonical JSON::PP 4973
jsonfmt/api JSON::SIMD JSON::SIMD 1.06 128161 json/api Canonical JSON::SIMD 116569
jsonfmt/api JSON::XS JSON::XS 4.03 130434 json/api Canonical JSON::XS 118616
jsonfmt/canonl Cpanel::JSON::XS Cpanel::JSON::XS 4.38 10710 json/api Decode Cpanel::JSON::XS 101843
jsonfmt/canonl FU::Util FU 0.1 12819 json/api Decode FU::Util 62633
jsonfmt/canonl JSON::PP JSON::PP 4.16 756 json/api Decode JSON::PP 1290
jsonfmt/canonl JSON::SIMD JSON::SIMD 1.06 12640 json/api Decode JSON::SIMD 117446
jsonfmt/canonl JSON::XS JSON::XS 4.03 12858 json/api Decode JSON::XS 117257
jsonfmt/canons Cpanel::JSON::XS Cpanel::JSON::XS 4.38 28155 json/api Encode Cpanel::JSON::XS 112845
jsonfmt/canons FU::Util FU 0.1 27079 json/api Encode FU::Util 126324
jsonfmt/canons JSON::PP JSON::PP 4.16 835 json/api Encode JSON::PP 5397
jsonfmt/canons JSON::SIMD JSON::SIMD 1.06 30066 json/api Encode JSON::SIMD 125127
jsonfmt/canons JSON::XS JSON::XS 4.03 32151 json/api Encode JSON::XS 128792
jsonfmt/intl Cpanel::JSON::XS Cpanel::JSON::XS 4.38 29299 json/intl Decode Cpanel::JSON::XS 48514
jsonfmt/intl FU::Util FU 0.1 114084 json/intl Decode FU::Util 62931
jsonfmt/intl JSON::PP JSON::PP 4.16 2208 json/intl Decode JSON::PP 330
jsonfmt/intl JSON::SIMD JSON::SIMD 1.06 37344 json/intl Decode JSON::SIMD 52446
jsonfmt/intl JSON::XS JSON::XS 4.03 35873 json/intl Decode JSON::XS 48689
jsonfmt/ints Cpanel::JSON::XS Cpanel::JSON::XS 4.38 7370 json/intl Encode Cpanel::JSON::XS 31337
jsonfmt/ints FU::Util FU 0.1 9188 json/intl Encode FU::Util 115559
jsonfmt/ints JSON::PP JSON::PP 4.16 117 json/intl Encode JSON::PP 2174
jsonfmt/ints JSON::SIMD JSON::SIMD 1.06 8191 json/intl Encode JSON::SIMD 36876
jsonfmt/ints JSON::XS JSON::XS 4.03 8143 json/intl Encode JSON::XS 36665
jsonfmt/strel Cpanel::JSON::XS Cpanel::JSON::XS 4.38 140657 json/ints Decode Cpanel::JSON::XS 6008
jsonfmt/strel FU::Util FU 0.1 132514 json/ints Decode FU::Util 5656
jsonfmt/strel JSON::PP JSON::PP 4.16 2231 json/ints Decode JSON::PP 29
jsonfmt/strel JSON::SIMD JSON::SIMD 1.06 154850 json/ints Decode JSON::SIMD 4335
jsonfmt/strel JSON::XS JSON::XS 4.03 154280 json/ints Decode JSON::XS 5998
jsonfmt/stres Cpanel::JSON::XS Cpanel::JSON::XS 4.38 138030 json/ints Encode Cpanel::JSON::XS 7235
jsonfmt/stres FU::Util FU 0.1 171426 json/ints Encode FU::Util 8344
jsonfmt/stres JSON::PP JSON::PP 4.16 4275 json/ints Encode JSON::PP 113
jsonfmt/stres JSON::SIMD JSON::SIMD 1.06 157735 json/ints Encode JSON::SIMD 8058
jsonfmt/stres JSON::XS JSON::XS 4.03 159066 json/ints Encode JSON::XS 8036
jsonfmt/strs Cpanel::JSON::XS Cpanel::JSON::XS 4.38 116754 json/objl Canonical Cpanel::JSON::XS 11629
jsonfmt/strs FU::Util FU 0.1 166142 json/objl Canonical FU::Util 12001
jsonfmt/strs JSON::PP JSON::PP 4.16 2798 json/objl Canonical JSON::PP 744
jsonfmt/strs JSON::SIMD JSON::SIMD 1.06 134130 json/objl Canonical JSON::SIMD 12050
jsonfmt/strs JSON::XS JSON::XS 4.03 133137 json/objl Canonical JSON::XS 12399
jsonfmt/stru Cpanel::JSON::XS Cpanel::JSON::XS 4.38 95453 json/objl Decode Cpanel::JSON::XS 16264
jsonfmt/stru FU::Util FU 0.1 103071 json/objl Decode FU::Util 5413
jsonfmt/stru JSON::PP JSON::PP 4.16 5067 json/objl Decode JSON::PP 105
jsonfmt/stru JSON::SIMD JSON::SIMD 1.06 107955 json/objl Decode JSON::SIMD 22649
jsonfmt/stru JSON::XS JSON::XS 4.03 105367 json/objl Decode JSON::XS 23418
json/objl Encode Cpanel::JSON::XS 29889
json/objl Encode FU::Util 37298
json/objl Encode JSON::PP 916
json/objl Encode JSON::SIMD 33950
json/objl Encode JSON::XS 34534
json/objs Canonical Cpanel::JSON::XS 27849
json/objs Canonical FU::Util 24882
json/objs Canonical JSON::PP 827
json/objs Canonical JSON::SIMD 30266
json/objs Canonical JSON::XS 30558
json/objs Decode Cpanel::JSON::XS 18920
json/objs Decode FU::Util 6818
json/objs Decode JSON::PP 206
json/objs Decode JSON::SIMD 22527
json/objs Decode JSON::XS 24065
json/objs Encode Cpanel::JSON::XS 42755
json/objs Encode FU::Util 43172
json/objs Encode JSON::PP 905
json/objs Encode JSON::SIMD 48487
json/objs Encode JSON::XS 48980
json/obju Canonical Cpanel::JSON::XS 1402
json/obju Canonical FU::Util 10461
json/obju Canonical JSON::PP 699
json/obju Canonical JSON::SIMD 1401
json/obju Canonical JSON::XS 1454
json/obju Decode Cpanel::JSON::XS 7590
json/obju Decode FU::Util 5998
json/obju Decode JSON::PP 86
json/obju Decode JSON::SIMD 15959
json/obju Decode JSON::XS 8848
json/obju Encode Cpanel::JSON::XS 20563
json/obju Encode FU::Util 24280
json/obju Encode JSON::PP 845
json/obju Encode JSON::SIMD 24996
json/obju Encode JSON::XS 26915
json/strel Decode Cpanel::JSON::XS 99260
json/strel Decode FU::Util 64880
json/strel Decode JSON::PP 360
json/strel Decode JSON::SIMD 113037
json/strel Decode JSON::XS 107918
json/strel Encode Cpanel::JSON::XS 139049
json/strel Encode FU::Util 132774
json/strel Encode JSON::PP 2230
json/strel Encode JSON::SIMD 152317
json/strel Encode JSON::XS 153421
json/stres Decode Cpanel::JSON::XS 104174
json/stres Decode FU::Util 76491
json/stres Decode JSON::PP 350
json/stres Decode JSON::SIMD 148939
json/stres Decode JSON::XS 92594
json/stres Encode Cpanel::JSON::XS 133222
json/stres Encode FU::Util 206172
json/stres Encode JSON::PP 4258
json/stres Encode JSON::SIMD 155205
json/stres Encode JSON::XS 123154
json/strs Decode Cpanel::JSON::XS 43652
json/strs Decode FU::Util 32742
json/strs Decode JSON::PP 341
json/strs Decode JSON::SIMD 50865
json/strs Decode JSON::XS 40599
json/strs Encode Cpanel::JSON::XS 117604
json/strs Encode FU::Util 168713
json/strs Encode JSON::PP 2922
json/strs Encode JSON::SIMD 136214
json/strs Encode JSON::XS 136486
json/stru Decode Cpanel::JSON::XS 66032
json/stru Decode FU::Util 36331
json/stru Decode JSON::PP 254
json/stru Decode JSON::SIMD 100555
json/stru Decode JSON::XS 60538
json/stru Encode Cpanel::JSON::XS 92871
json/stru Encode FU::Util 108032
json/stru Encode JSON::PP 5144
json/stru Encode JSON::SIMD 106664
json/stru Encode JSON::XS 104716

134
bench.PL
View file

@ -2,7 +2,7 @@
# Can be invoked as: # Can be invoked as:
# ./bench.PL # generates FU/Benchmarks.pod, running new benchmarks as necessary # ./bench.PL # generates FU/Benchmarks.pod, running new benchmarks as necessary
# ./bench.PL id func # invalidate cache for the (regex-)matching benchmark IDs and funcs and re-run them # ./bench.PL id x y # invalidate cache for the (regex-)matching benchmark IDs, x and y and re-run them
# #
# This script obviously has more dependencies than the FU distribution itself. # This script obviously has more dependencies than the FU distribution itself.
# It's supposed to be used by maintainers, not users. # It's supposed to be used by maintainers, not users.
@ -23,97 +23,109 @@ my %modules = map +($_, eval "require $_; \$${_}::VERSION"), qw/
JSON::SIMD JSON::SIMD
/; /;
my %data; # "id func modver" => { id func module modver rate exists } my %data; # "id x y" => { id x y rate exists }
{ my %oldmodules;
{ if (open my $F, '<', 'FU/Benchmarks.pod') {
my $indata; my $indata;
if (open my $F, '<', 'FU/Benchmarks.pod') { while (<$F>) {
while (<$F>) { chomp;
chomp; $oldmodules{$1} = $2 if /^=item L<([a-zA-Z0-9:]+)> ([0-9.]+)/;
$indata = 1 if /^# Cached data used by bench\.PL/; $indata = 1 if /^# Cached data used by bench\.PL/;
next if !$indata || !$_ || /^#/; next if !$indata || !$_ || /^#/;
my %d; my %d;
@d{qw/id func module modver rate/} = split /\t/; @d{qw/id x y rate/} = split /\t/;
$data{"$d{id} $d{func} $d{modver}"} = \%d; $data{"$d{id} $d{x} $d{y}"} = \%d;
}
} }
} } }
if (@ARGV) { if (@ARGV) {
my $idre = qr/$ARGV[0]/i; my $idre = qr/$ARGV[0]/i;
my $funcre = $ARGV[1] ? qr/$ARGV[1]/i : qr/.*/; my $xre = $ARGV[1] ? qr/$ARGV[1]/i : qr/.*/;
delete $_->{rate} for grep $_->{id} =~ /$idre/ && $_->{func} =~ /$funcre/, values %data; my $yre = $ARGV[2] ? qr/$ARGV[2]/i : qr/.*/;
delete $_->{rate} for grep $_->{id} =~ /$idre/ && $_->{x} =~ /$xre/ && $_->{y} =~ /$yre/, values %data;
} }
my @bench; # [ id, text, [ func_1, funcmodule_1, funcsub_n, .. ] ] my @bench; # [ id, text, [ x_1, .. ], [ [ y_1, mod_1, sub_1, .. ], .. ] ]
sub def($id, $text, @f) { sub def($id, $text, $xs, @ys) {
for my ($f, $m, $sub) (@f) { for my ($ya) (@ys) {
$m ||= $f; my($y, $m, @sub) = @$ya;
my $d = "$id $f $modules{$m}"; $m ||= $y;
$data{$d} ||= { id => $id, func => $f, module => $m, modver => $modules{$m} }; for my($i, $x) (builtin::indexed @$xs) {
$d = $data{$d}; my $d = "$id $x $y";
$d->{exists} = 1; $data{$d} ||= { id => $id, x => $x, y => $y };
if (!exists $d->{rate}) { $d = $data{$d};
my $o = timethis -1, $sub, 0, 'none'; $d->{exists} = 1;
$d->{rate} = sprintf '%.0f', $o->iters/$o->real; delete $d->{rate} if !$oldmodules{$m} || $modules{$m} ne $oldmodules{$m};
printf "%-20s%-20s%10d/s\n", $d->{id}, $d->{func}, $d->{rate}; if (!exists $d->{rate}) {
my $o = timethis -1, $sub[$i], 0, 'none';
$d->{rate} = sprintf '%.0f', $o->iters/$o->real;
printf "%-20s%-12s%-20s%10d/s\n", $id, $x, $y, $d->{rate};
}
} }
} }
push @bench, [ $id, $text, \@f ]; push @bench, [ $id, $text, $xs, \@ys ];
} }
use FU::Util 'json_format'; use FU::Util 'json_format', 'json_parse';
sub jsonfmt($name, $text, $data) { sub defjson($name, $canon, $text, $val) {
# Use similar options for fair comparisons. # Use similar options for fair comparisons.
my $cp = Cpanel::JSON::XS->new->allow_nonref->unblessed_bool->convert_blessed; my $cp = Cpanel::JSON::XS->new->allow_nonref->unblessed_bool->convert_blessed;
my $pp = JSON::PP->new->allow_nonref->core_bools->convert_blessed; my $pp = JSON::PP->new->allow_nonref->core_bools->convert_blessed;
my $xs = JSON::XS->new->allow_nonref->boolean_values([false,true])->convert_blessed; my $xs = JSON::XS->new->allow_nonref->boolean_values([false,true])->convert_blessed;
my $si = JSON::SIMD->new->allow_nonref->core_bools->convert_blessed; my $si = JSON::SIMD->new->allow_nonref->core_bools->convert_blessed;
my @opt = (); my $c_cp = Cpanel::JSON::XS->new->allow_nonref->unblessed_bool->convert_blessed->canonical;
if ($name =~ /^canon/) { my $c_pp = JSON::PP->new->allow_nonref->core_bools->convert_blessed->canonical;
$cp = $cp->canonical; my $c_xs = JSON::XS->new->allow_nonref->boolean_values([false,true])->convert_blessed->canonical;
$pp = $pp->canonical; my $c_si = JSON::SIMD->new->allow_nonref->core_bools->convert_blessed->canonical;
$xs = $xs->canonical; my $enc = json_format $val;
$si = $si->canonical; def "json/$name", $text, [ 'Encode', $canon ? 'Canonical' : (), 'Decode' ],
@opt = (canonical => 1); [ 'JSON::PP', undef, sub { $pp->encode($val) }, $canon ? sub { $c_pp->encode($val) } : (), sub { $pp->decode($enc) } ],
} [ 'Cpanel::JSON::XS', undef, sub { $cp->encode($val) }, $canon ? sub { $c_cp->encode($val) } : (), sub { $cp->decode($enc) } ],
def "jsonfmt/$name", $text, [ 'JSON::SIMD', undef, sub { $si->encode($val) }, $canon ? sub { $c_si->encode($val) } : (), sub { $si->decode($enc) } ],
'JSON::PP', undef, sub { $pp->encode($data) }, [ 'JSON::XS', undef, sub { $xs->encode($val) }, $canon ? sub { $c_xs->encode($val) } : (), sub { $xs->decode($enc) } ],
'Cpanel::JSON::XS', undef, sub { $cp->encode($data) }, [ 'FU::Util', 'FU', sub { json_format $val }, $canon ? sub { json_format $val, canonical => 1 } : (), sub { json_parse $enc } ];
'JSON::SIMD', undef, sub { $si->encode($data) },
'JSON::XS', undef, sub { $xs->encode($data) },
'FU::Util', 'FU', sub { json_format $data, @opt };
} }
# From JSON::XS POD. # From JSON::XS POD.
jsonfmt api => 'API object from L<JSON::XS> documentation.', defjson api => 1, 'API object from L<JSON::XS> documentation.',
[ map +{method => 'handleMessage', params => ['user1','we were just talking'], 'id' => undef, 'array' => [1,11,234,-5,1e5,1e7,1,0]}, 1..10 ]; [ map +{method => 'handleMessage', params => ['user1','we were just talking'], 'id' => undef, 'array' => [1,11,234,-5,1e5,1e7,1,0]}, 1..10 ];
jsonfmt ints => 'Small integers', [ -5000..5000 ]; defjson objs => 1, 'Object (small)', [ map +{ map +("string$_", 1), 'a'..'f' }, 0..100 ];
jsonfmt intl => 'Large integers', [ map { my $n=$_; map +($n+1<<$_), 10..60 } 1..10 ]; defjson objl => 1, 'Object (large)', { map +("string$_-something", 1), 'aa'..'zz' };
jsonfmt strs => 'ASCII strings', [ map +('hello, world', 'one more string', 'another string'), 1..100 ]; defjson obju => 1, 'Object (large, mixed unicode)', { map +("str\x{1234}g$_-some\x{85232}hing", 1), 'aa'..'zz' };
jsonfmt stru => 'Unicode strings', do { use utf8;
defjson ints => 0, 'Small integers', [ -5000..5000 ];
defjson intl => 0, 'Large integers', [ map { my $n=$_; map +($n+1<<$_), 10..60 } 1..10 ];
defjson strs => 0, 'ASCII strings', [ map +('hello, world', 'one more string', 'another string'), 1..100 ];
defjson stru => 0, 'Unicode strings', do { use utf8;
[ map +('グリザイアの果実 -LE FRUIT DE LA GRISAIA-', '💩', 'Я люблю нічого не робити'), 1..50 ]; [ map +('グリザイアの果実 -LE FRUIT DE LA GRISAIA-', '💩', 'Я люблю нічого не робити'), 1..50 ];
}; };
jsonfmt stres => 'String escaping (few)', [ map 'This string needs to "be escaped" a little bit', 1..100 ]; defjson stres => 0, 'String escaping (few)', [ map 'This string needs to "be escaped" a little bit', 1..100 ];
jsonfmt strel => 'String escaping (many)', [ map "This \" \\ needs \b\x01\x02\x03\x04 more", 1..100 ]; defjson strel => 0, 'String escaping (many)', [ map "This \" \\ needs \b\x01\x02\x03\x04 more", 1..100 ];
jsonfmt canons => 'Canonical hash key ordering (small)', [ map +{ map +("string$_", 1), 'a'..'f' }, 0..100 ];
jsonfmt canonl => 'Canonical hash key ordering (large)', { map +("string$_-something", 1), 'aa'..'zz' };
delete @data{ grep !$data{$_}{exists}, keys %data }; delete @data{ grep !$data{$_}{exists}, keys %data };
sub fmtbench($id, $text, $fs) { sub fmtbench($id, $text, $xs, $ys) {
my $r = "$text\n\n"; my $r = "$text\n\n";
for my ($f, $m, $sub) (@$fs) { if (@$xs > 1) {
$m ||= $f; $r .= sprintf '%18s', '';
$r .= sprintf "%18s%10d/s\n", $f, $data{"$id $f $modules{$m}"}{rate}; $r .= sprintf '%12s', $_ for @$xs;
$r .= "\n";
}
for my ($n, $yr) (builtin::indexed @$ys) {
my $x = $xs->[$n];
my ($y, $m, @ys) = @$yr;
$m ||= $y;
$r .= sprintf '%18s', $y;
$r .= sprintf '%10d/s', $data{"$id $xs->[$_] $y"}{rate} for (0..$#$xs);
$r .= "\n";
} }
"$r\n" "$r\n"
} }
@ -128,7 +140,7 @@ sub fmtbench($id, $text, $fs) {
} }
for (sort keys %data) { for (sort keys %data) {
my $b = $data{$_}; my $b = $data{$_};
print join("\t", @{$b}{qw/ id func module modver rate /})."\n"; print join("\t", @{$b}{qw/ id x y rate /})."\n";
} }
} }
@ -173,8 +185,8 @@ smaller inputs, but I don't find that overhead very interesting.
Also worth noting that JSON::SIMD formatting code is forked from JSON::XS, the Also worth noting that JSON::SIMD formatting code is forked from JSON::XS, the
SIMD parts are only used for parsing. SIMD parts are only used for parsing.
:benches ^jsonfmt :benches ^json
=cut =cut
# Cached data used by bench.PL. # Cached data used by bench.PL. Same as the formatted tables above but easier to parse.