File Coverage

blib/lib/Promises/Deferred/EV.pm
Criterion Covered Total %
statement 29 33 87.8
branch 5 8 62.5
condition 2 3 66.6
subroutine 6 8 75.0
pod n/a
total 42 52 80.7


line stmt bran cond sub pod time code
1             package Promises::Deferred::EV;
2             our $AUTHORITY = 'cpan:YANICK';
3             # ABSTRACT: An implementation of Promises in Perl
4             $Promises::Deferred::EV::VERSION = '1.05';
5 2     2   1441 use strict;
  2         6  
  2         87  
6 2     2   12 use warnings;
  2         3  
  2         152  
7              
8 2     2   33 use EV;
  2         5  
  2         65  
9              
10 2     2   31 use parent 'Promises::Deferred';
  2         6  
  2         17  
11              
12             # Before the pipe-based approach used below, there was an EV::timer-based
13             # approach for _notify_backend. The current code is much more performant:
14              
15             # Original code (on a laptop on battery power):
16             # Backend: Promises::Deferred::EV
17             # Benchmark: running one, two for at least 10 CPU seconds...
18             # Benchmark: running one, two for at least 10 CPU seconds...
19             # one: 67 wallclock secs @ 1755.16/s (n=17692)
20             # two: 53 wallclock secs @ 770.03/s (n=7785)
21              
22             # New approach:
23             # Backend: Promises::Deferred::EV
24             # Benchmark: running one, two for at least 10 CPU seconds...
25             # one: 10 wallclock secs @ 10949.19/s (n=115076)
26             # two: 10 wallclock secs @ 3964.58/s (n=41747)
27              
28              
29             my ($socket_pid, $socket_send, $socket_recv, $socket_io,
30             $read_buf, @io_callbacks);
31              
32             sub _do_callbacks {
33 7     7   1396 my @cbs = @io_callbacks;
34 7         16 @io_callbacks = ();
35 7         44 sysread $socket_recv, $read_buf, 16;
36 7         19 for my $cb_grp (@cbs) {
37 7         21 my ($result, $cbs) = @$cb_grp;
38 7         16 my @r = @$result;
39 7         44 $_->(@r) for @$cbs;
40             }
41             }
42              
43             sub _notify_backend {
44 8 100 66 8   65 if (! $socket_pid || $socket_pid != $$) {
45 2         79 $socket_pid = $$;
46 2 50       12 close($socket_send) if defined $socket_send;
47 2 50       7 close($socket_recv) if defined $socket_recv;
48 2         101 pipe($socket_recv, $socket_send);
49 2         36 $socket_io = EV::io($socket_recv, EV::READ, \&_do_callbacks);
50 2         81 $socket_io->keepalive(0);
51             }
52              
53             # skip signalling when there are callbacks already waiting
54 8 50       30 if (not @io_callbacks) {
55 8         106 syswrite $socket_send, ' ';
56             }
57 8         37 push @io_callbacks, [ $_[2], $_[1] ];
58             }
59              
60             sub _timeout {
61 0     0     my ( $self, $timeout, $callback ) = @_;
62              
63 0           my $id = EV::timer $timeout, 0, $callback;
64              
65 0     0     return sub { undef $id };
  0            
66             }
67              
68             1;
69              
70             __END__