EV-Etcd

 view release on metacpan or  search on metacpan

bench.pl  view on Meta::CPAN

    my $result = `etcdctl endpoint health 2>&1`;
    $etcd_running = 1 if $result =~ /is healthy/;
};
die "etcd not running\n" unless $etcd_running;

my $client = EV::Etcd->new(
    endpoints => ['127.0.0.1:2379'],
);

my $prefix = "/bench_$$";
my $iterations = $ENV{BENCH_ITER} || 1000;

print "EV::Etcd Benchmark\n";
print "==================\n\n";

# Benchmark 1: Sequential puts
{
    print "1. Sequential PUTs ($iterations iterations)...\n";
    my $completed = 0;
    my $start = time();

    for my $i (1..$iterations) {
        $client->put("$prefix/key$i", "value$i", sub {
            my ($resp, $err) = @_;
            die "PUT error: $err->{message}" if $err;
            $completed++;
            EV::break;
        });
        EV::run;
    }

    my $elapsed = time() - $start;
    printf "   Time: %.3f sec, Rate: %.0f ops/sec, Latency: %.2f ms/op\n\n",
        $elapsed, $iterations / $elapsed, ($elapsed / $iterations) * 1000;
}

# Benchmark 2: Sequential gets
{
    print "2. Sequential GETs ($iterations iterations)...\n";
    my $completed = 0;
    my $start = time();

    for my $i (1..$iterations) {
        $client->get("$prefix/key$i", sub {
            my ($resp, $err) = @_;
            die "GET error: $err->{message}" if $err;
            $completed++;
            EV::break;
        });
        EV::run;
    }

    my $elapsed = time() - $start;
    printf "   Time: %.3f sec, Rate: %.0f ops/sec, Latency: %.2f ms/op\n\n",
        $elapsed, $iterations / $elapsed, ($elapsed / $iterations) * 1000;
}

# Benchmark 3: Pipelined puts (bounded concurrency)
{
    my $concurrency = $ENV{BENCH_CONCURRENCY} || 100;
    print "3. Pipelined PUTs ($iterations iterations, concurrency=$concurrency)...\n";
    my $completed = 0;
    my $sent = 0;
    my $in_flight = 0;
    my $start = time();

    my $send_batch; $send_batch = sub {
        while ($sent < $iterations && $in_flight < $concurrency) {
            $sent++;
            $in_flight++;
            my $i = $sent;
            $client->put("$prefix/pipe$i", "value$i", sub {
                my ($resp, $err) = @_;
                die "PUT error: $err->{message}" if $err;
                $completed++;
                $in_flight--;
                if ($completed == $iterations) {
                    EV::break;
                } else {
                    $send_batch->();
                }
            });
        }
    };
    $send_batch->();
    EV::run;

    my $elapsed = time() - $start;
    printf "   Time: %.3f sec, Rate: %.0f ops/sec, Latency: %.2f ms/op\n\n",
        $elapsed, $iterations / $elapsed, ($elapsed / $iterations) * 1000;
}

# Benchmark 4: Pipelined gets (bounded concurrency)
{
    my $concurrency = $ENV{BENCH_CONCURRENCY} || 100;
    print "4. Pipelined GETs ($iterations iterations, concurrency=$concurrency)...\n";
    my $completed = 0;
    my $sent = 0;
    my $in_flight = 0;
    my $start = time();

    my $send_batch; $send_batch = sub {
        while ($sent < $iterations && $in_flight < $concurrency) {
            $sent++;
            $in_flight++;
            my $i = $sent;
            $client->get("$prefix/pipe$i", sub {
                my ($resp, $err) = @_;
                die "GET error: $err->{message}" if $err;
                $completed++;
                $in_flight--;
                if ($completed == $iterations) {
                    EV::break;
                } else {
                    $send_batch->();
                }
            });
        }
    };
    $send_batch->();
    EV::run;

    my $elapsed = time() - $start;
    printf "   Time: %.3f sec, Rate: %.0f ops/sec, Latency: %.2f ms/op\n\n",
        $elapsed, $iterations / $elapsed, ($elapsed / $iterations) * 1000;
}

# Benchmark 5: Watch latency
{
    print "5. Watch event latency (100 events)...\n";
    my $watch_key = "$prefix/watch_test";
    my @latencies;
    my $events_received = 0;
    my $puts_sent = 0;
    my $send_time;

xt/leak.t  view on Meta::CPAN


my $available = 0;
eval {
    my $c = EV::Etcd->new(endpoints => ['127.0.0.1:2379'], timeout => 2);
    $c->status(sub { $available = 1 if !$_[1]; EV::break });
    my $t = EV::timer(3, 0, sub { EV::break });
    EV::run;
};
plan skip_all => 'etcd not available on 127.0.0.1:2379' unless $available;

my $iterations = $ENV{LEAK_ITER} || 100;

# Warm up — the first iteration loads code and primes Perl's arena
for (1 .. 5) { run_cycle() }

my $handle;
my $svs_before = Devel::Leak::NoteSV($handle);
for (1 .. $iterations) { run_cycle() }
my $svs_after  = Devel::Leak::CheckSV($handle);

# Allow a small slop for arena rounding / lazy-loaded modules
my $delta = $svs_after - $svs_before;
ok($delta < 50, "$iterations new+watch+cancel+DESTROY cycles leak < 50 SVs (delta=$delta)");

done_testing();

sub run_cycle {
    my $client = EV::Etcd->new(endpoints => ['127.0.0.1:2379']);
    my $watch  = $client->watch("/leak_test_$$", sub { });
    my $done;
    $watch->cancel(sub { $done = 1; EV::break });
    my $t = EV::timer(1, 0, sub { EV::break });
    EV::run;



( run in 2.317 seconds using v1.01-cache-2.11-cpan-71847e10f99 )