Mercurial > pub > Impl
comparison lib/IMPL/Profiler/Memory.pm @ 407:c6e90e02dd17 ref20150831
renamed Lib->lib
| author | cin |
|---|---|
| date | Fri, 04 Sep 2015 19:40:23 +0300 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 406:f23fcb19d3c1 | 407:c6e90e02dd17 |
|---|---|
| 1 package IMPL::Profiler::Memory; | |
| 2 | |
| 3 use strict; | |
| 4 use Carp qw(longmess shortmess); | |
| 5 use Scalar::Util qw(refaddr weaken isweak); | |
| 6 | |
| 7 my %listeners; | |
| 8 my $trapped; | |
| 9 | |
| 10 BEGIN { | |
| 11 $trapped = 0; | |
| 12 } | |
| 13 | |
| 14 sub import { | |
| 15 if (not $trapped) { | |
| 16 *CORE::GLOBAL::bless = sub { | |
| 17 $_[1] |= caller unless $_[1]; | |
| 18 my $ref = CORE::bless $_[0],$_[1]; | |
| 19 | |
| 20 $_->track($ref) foreach values %listeners; | |
| 21 | |
| 22 return $ref; | |
| 23 }; | |
| 24 $trapped = 1; | |
| 25 } | |
| 26 } | |
| 27 | |
| 28 sub _ConnectListener { | |
| 29 my ($self,$listener) = @_; | |
| 30 | |
| 31 die "Invalid listener" unless ref $listener; | |
| 32 | |
| 33 $listeners{refaddr($listener)} = $listener; | |
| 34 } | |
| 35 | |
| 36 sub _RemoveListener { | |
| 37 my ($self,$listener) = @_; | |
| 38 | |
| 39 die "Invalid listener" unless ref $listener; | |
| 40 | |
| 41 delete $listeners{refaddr($listener)}; | |
| 42 } | |
| 43 | |
| 44 sub Monitor { | |
| 45 my ($self,$code) = @_; | |
| 46 | |
| 47 my $data = IMPL::Profiler::Memory::Data->new(); | |
| 48 | |
| 49 $data->Monitor($code); | |
| 50 | |
| 51 return $data; | |
| 52 } | |
| 53 | |
| 54 package IMPL::Profiler::Memory::Data; | |
| 55 use parent qw(IMPL::Object::Fields); | |
| 56 | |
| 57 use Data::Dumper(); | |
| 58 use Scalar::Util qw(refaddr weaken isweak); | |
| 59 | |
| 60 use fields qw( objects counter); | |
| 61 | |
| 62 sub CTOR { | |
| 63 my $this = shift; | |
| 64 $this->{objects} = []; | |
| 65 $this->{counter} = 0; | |
| 66 } | |
| 67 | |
| 68 sub track { | |
| 69 my $i = scalar @{$_[0]->{objects}}; | |
| 70 $_[0]->{objects}[$i] = $_[1]; | |
| 71 weaken($_[0]->{objects}[$i]); | |
| 72 $_[0]->{counter} ++; | |
| 73 } | |
| 74 | |
| 75 sub Purge { | |
| 76 my $this = shift; | |
| 77 | |
| 78 return $this->{objects} = [ grep defined($_), @{$this->{objects}}]; | |
| 79 } | |
| 80 | |
| 81 sub Dump { | |
| 82 my $this = shift; | |
| 83 return Data::Dumper->Dump([$this->{objects}]); | |
| 84 } | |
| 85 | |
| 86 sub isLeak { | |
| 87 my ($this) = @_; | |
| 88 $this->Purge(); | |
| 89 return ( scalar(@{$this->{objects}}) > 0); | |
| 90 } | |
| 91 | |
| 92 sub Monitor { | |
| 93 my ($this,$code) = @_; | |
| 94 | |
| 95 die "A reference to a subroutine is required" unless ref $code; | |
| 96 | |
| 97 IMPL::Profiler::Memory->_ConnectListener($this); | |
| 98 eval { | |
| 99 $code->(); | |
| 100 }; | |
| 101 my $err = $@; | |
| 102 IMPL::Profiler::Memory->_RemoveListener($this); | |
| 103 | |
| 104 die $err if $err; | |
| 105 | |
| 106 return; | |
| 107 } | |
| 108 | |
| 109 | |
| 110 | |
| 111 1; |
