File Coverage

blib/lib/AnyEvent/Monitor/CPU.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package AnyEvent::Monitor::CPU;
2             our $VERSION = '0.3';
3              
4              
5              
6 1     1   937 use common::sense;
  1         2  
  1         9  
7 1     1   503 use AnyEvent;
  0            
  0            
8             use Proc::CPUUsage;
9             use Carp qw( croak );
10             use parent qw( Exporter );
11              
12             @AnyEvent::Monitor::CPU::EXPORT_OK = ('monitor_cpu');
13              
14             ## Shortcut, optional import
15             sub monitor_cpu { return __PACKAGE__->new(@_) }
16              
17              
18             sub new {
19             my $class = shift;
20             my %args = @_ == 1 ? %{$_[0]} : @_;
21              
22             my $self = bless {
23             cb => delete $args{cb},
24              
25             interval => delete $args{interval} || .25,
26              
27             high => delete $args{high} || .95,
28             low => delete $args{low} || .80,
29             high_samples => delete $args{high_samples} || 2,
30             low_samples => delete $args{low_samples} || 2,
31             cur_high_samples => 0,
32             cur_low_samples => 0,
33              
34             cpu => Proc::CPUUsage->new,
35             usage => undef,
36             state => 1,
37             }, $class;
38              
39             croak("Required parameter 'cb' not found, ") unless $self->{cb};
40             croak("Parameter 'cb' must be a coderef, ") unless ref $self->{cb} eq 'CODE';
41              
42             $self->start;
43              
44             return $self;
45             }
46              
47             sub start {
48             my $self = shift;
49              
50             $self->{timer} = AnyEvent->timer(
51             after => $self->{interval},
52             interval => $self->{interval},
53             cb => sub { $self->_check_cpu },
54             );
55              
56             $self->{usage} = $self->{cpu}->usage;
57             $self->reset_stats;
58              
59             return;
60             }
61              
62             sub stop { delete $_[0]->{timer} }
63             sub is_running { $_[0]->{timer} }
64              
65             sub usage { return $_[0]->{usage} }
66             sub is_low { return $_[0]->{state} == 1 }
67             sub is_high { return $_[0]->{state} == 0 }
68              
69             sub reset_stats {
70             my ($self) = @_;
71            
72             $self->{usage_sum} = 0;
73             $self->{usage_count} = 0;
74             }
75              
76             sub stats {
77             my ($self) = @_;
78             my %stats;
79            
80             my ($count, $sum);
81             if ($count = $self->{usage_count}) {
82             $sum = $self->{usage_sum};
83             $stats{usage_avg} = $sum/$count;
84             }
85             $stats{usage_count} = $count;
86             $stats{usage_sum} = $sum;
87             $stats{usage} = $self->{usage};
88              
89             return \%stats;
90             }
91              
92             sub _check_cpu {
93             my $self = $_[0];
94             my $chs = $self->{current_high_samples};
95             my $cls = $self->{current_low_samples};
96              
97             my $usage = $self->{usage} = $self->{cpu}->usage;
98             if ($usage > $self->{high}) { $chs++; $cls = 0 }
99             elsif ($usage < $self->{low}) { $cls++; $chs = 0 }
100             else {
101             $chs-- if $chs;
102             $cls-- if $cls;
103             }
104             $self->{usage_sum} += $usage;
105             $self->{usage_count}++;
106              
107             my $hs = $self->{high_samples};
108             my $ls = $self->{low_samples};
109             my $state = $self->{state};
110             my $trigger = 0;
111             if ($chs >= $hs) {
112             $chs = $hs;
113             if ($state) {
114             $state = 0;
115             $trigger = 1;
116             }
117             }
118             elsif ($cls >= $ls) {
119             $cls = $ls;
120             if (!$state) {
121             $state = 1;
122             $trigger = 1;
123             }
124             }
125              
126             $self->{state} = $state;
127             $self->{current_high_samples} = $chs;
128             $self->{current_low_samples} = $cls;
129              
130             $self->{cb}->($self, $state) if $trigger;
131             }
132              
133              
134             1;
135              
136             __END__