ClickHouse-Encoder
view release on metacpan or search on metacpan
bench/complex_insert_benchmark.pl view on Meta::CPAN
system("clickhouse-client --port $PORT --query 'create table bench_complex (
id UInt32,
name String,
tags Array(String),
coords Tuple(Float64, Float64),
optional Nullable(UInt64)
) engine = Null'");
# Benchmark function
sub bench_insert {
my ($format, $data, $iterations) = @_;
my @times;
for my $i (1 .. $iterations) {
my $t0 = time();
open my $fh, '|-', "clickhouse-client --port $PORT --query 'insert into bench_complex format $format' 2>/dev/null"
or die "Cannot run clickhouse-client: $!";
binmode $fh;
print $fh $data;
close $fh;
my $elapsed = time() - $t0;
push @times, $elapsed;
}
bench/insert_benchmark.pl view on Meta::CPAN
# Create test table
print "\nSetting up test table...\n";
system("clickhouse-client --port $PORT --query 'drop table if exists bench_native'");
system("clickhouse-client --port $PORT --query 'drop table if exists bench_csv'");
system("clickhouse-client --port $PORT --query 'create table bench_native (id UInt32, bignum UInt64, value Float64, name String) engine = Null'");
system("clickhouse-client --port $PORT --query 'create table bench_csv (id UInt32, bignum UInt64, value Float64, name String) engine = Null'");
# Benchmark function
sub bench_insert {
my ($table, $format, $data, $iterations) = @_;
my @times;
for my $i (1 .. $iterations) {
my $t0 = time();
open my $fh, '|-', "clickhouse-client --port $PORT --query 'insert into $table format $format' 2>/dev/null"
or die "Cannot run clickhouse-client: $!";
binmode $fh;
print $fh $data;
close $fh;
my $elapsed = time() - $t0;
push @times, $elapsed;
}
bench/wide_table_benchmark.pl view on Meta::CPAN
print "\n", "=" x 70, "\n";
print "INSERT Benchmark\n";
print "=" x 70, "\n\n";
print "Setting up test table...\n";
system("clickhouse-client --port $PORT --query 'drop table if exists bench_wide'");
system("clickhouse-client --port $PORT --query 'create table bench_wide (\n $col_defs\n) engine = Null'");
# Benchmark function
sub bench_insert {
my ($format, $data, $iterations) = @_;
my @times;
for my $i (1 .. $iterations) {
my $t0 = time();
open my $fh, '|-', "clickhouse-client --port $PORT --query 'insert into bench_wide format $format' 2>/dev/null"
or die "Cannot run clickhouse-client: $!";
binmode $fh;
print $fh $data;
close $fh;
my $elapsed = time() - $t0;
push @times, $elapsed;
printf " Run %d: %.3f sec\n", $i, $elapsed;
}
return @times;
}
# Warmup
print "Warming up...\n";
bench_insert('Native', $native_data, 1);
bench_insert('TabSeparated', $csv_data, 1);
# Benchmark
print "\nBenchmarking Native format ($ITERATIONS iterations)...\n";
my @native_times = bench_insert('Native', $native_data, $ITERATIONS);
print "\nBenchmarking TabSeparated format ($ITERATIONS iterations)...\n";
my @csv_times = bench_insert('TabSeparated', $csv_data, $ITERATIONS);
# Calculate statistics
sub stats {
my @times = @_;
my $sum = 0;
$sum += $_ for @times;
my $avg = $sum / @times;
my $min = (sort { $a <=> $b } @times)[0];
return ($avg, $min);
xt/fuzz-decoder.t view on Meta::CPAN
2 * 1024 * 1024 * 1024,
2 * 1024 * 1024 * 1024);
1;
};
plan skip_all => 'BSD::Resource not available; skipping unbounded fuzz'
unless $cap_ok;
srand($ENV{FUZZ_DECODER_SEED} // 19937);
# 150 is the empirical safe ceiling under RLIMIT_AS=2 GiB with the
# default seed: enough iterations to exercise each seed shape several
# times without the cumulative Perl arena footprint plus a worst-case
# bounded allocation tripping the cap. Bump FUZZ_DECODER_ITERS in CI
# when adding more aggressive fuzz patterns.
my $iters = $ENV{FUZZ_DECODER_ITERS} // 150;
# Build a known-good seed block for each interesting type, then
# mutate. Both fully-random and surgically-perturbed inputs exercise
# different decoder paths.
my @seeds;
xt/fuzz-decoder.t view on Meta::CPAN
}
else {
# Append trailing garbage.
$bytes .= join '', map chr(int rand 256), 1..int(rand 32);
}
}
next unless _looks_safe($bytes);
# Wrap in a fresh sub call so the decoder's return value and any
# mortal SVs created during decode are reclaimed before the next
# iteration. Without this, mortals can pile up across hundreds
# of iterations until the test process's heap is exhausted.
eval { _try_decode($bytes); 1 };
# "Out of memory" / "Killed" from RLIMIT_AS aborts the test process
# and never returns to this branch - but catching the symbolic text
# in $@ surfaces a real allocation gap if the eval somehow recovered
# without the process dying.
if ($@ && $@ =~ /Segmentation|stack overflow|Out of memory|Killed/i) {
$crashed++;
diag "CRASH at iter $i: $@";
} else {
$survived++;
}
}
sub _try_decode {
ClickHouse::Encoder->decode_block($_[0]);
return;
}
is($crashed, 0, "$iters fuzz iterations: 0 crashes ($survived survived)");
done_testing();
( run in 0.929 second using v1.01-cache-2.11-cpan-96521ef73a4 )