| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Test2::Plugin::MemUsage; |
|
2
|
6
|
|
|
6
|
|
1125035
|
use strict; |
|
|
6
|
|
|
|
|
19
|
|
|
|
6
|
|
|
|
|
293
|
|
|
3
|
6
|
|
|
6
|
|
44
|
use warnings; |
|
|
6
|
|
|
|
|
18
|
|
|
|
6
|
|
|
|
|
555
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.002006'; |
|
6
|
|
|
|
|
|
|
|
|
7
|
6
|
|
|
6
|
|
42
|
use Test2::API qw/test2_add_callback_exit/; |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
11111
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
my $ADDED_HOOK = 0; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub import { |
|
12
|
7
|
100
|
|
7
|
|
115
|
return if $ADDED_HOOK++; |
|
13
|
|
|
|
|
|
|
|
|
14
|
6
|
|
|
|
|
42
|
test2_add_callback_exit(\&send_mem_event); |
|
15
|
|
|
|
|
|
|
} |
|
16
|
|
|
|
|
|
|
|
|
17
|
9
|
|
|
9
|
0
|
236580
|
sub proc_file { "/proc/$$/status" } |
|
18
|
|
|
|
|
|
|
|
|
19
|
16
|
|
|
16
|
|
215
|
sub _empty_mem { (peak => ['NA', ''], size => ['NA', ''], rss => ['NA', '']) } |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub _collect_proc { |
|
22
|
13
|
|
|
13
|
|
175886
|
my $file = proc_file(); |
|
23
|
13
|
100
|
|
|
|
489
|
return unless -e $file; |
|
24
|
|
|
|
|
|
|
|
|
25
|
12
|
|
|
|
|
51
|
my $stats; |
|
26
|
|
|
|
|
|
|
{ |
|
27
|
12
|
50
|
|
|
|
20
|
open(my $fh, '<', $file) or warn("Could not open file '$file' (<): $!"), return; |
|
|
12
|
|
|
|
|
562
|
|
|
28
|
12
|
|
|
|
|
73
|
local $/; |
|
29
|
12
|
|
|
|
|
519
|
$stats = <$fh>; |
|
30
|
12
|
50
|
|
|
|
195
|
close($fh) or warn "Could not close file '$file': $!"; |
|
31
|
|
|
|
|
|
|
} |
|
32
|
|
|
|
|
|
|
|
|
33
|
12
|
100
|
|
|
|
45
|
return unless $stats; |
|
34
|
|
|
|
|
|
|
|
|
35
|
11
|
|
|
|
|
35
|
my %mem = _empty_mem(); |
|
36
|
11
|
100
|
|
|
|
143
|
$mem{peak} = [$1, $2] if $stats =~ m/VmPeak:\s+(\d+)\s+(\S+)/; |
|
37
|
11
|
100
|
|
|
|
100
|
$mem{size} = [$1, $2] if $stats =~ m/VmSize:\s+(\d+)\s+(\S+)/; |
|
38
|
11
|
100
|
|
|
|
88
|
$mem{rss} = [$1, $2] if $stats =~ m/VmRSS:\s+(\d+)\s+(\S+)/; |
|
39
|
|
|
|
|
|
|
|
|
40
|
11
|
|
|
|
|
58
|
return %mem; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
3
|
|
|
3
|
0
|
26877
|
sub ps_command { "ps -o rss= -o vsz= -p $$" } |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub _collect_ps { |
|
46
|
4
|
|
|
4
|
|
228711
|
my $cmd = ps_command(); |
|
47
|
4
|
|
|
|
|
30703
|
my $out = `$cmd 2>/dev/null`; |
|
48
|
4
|
100
|
66
|
|
|
196
|
return unless defined $out && length $out; |
|
49
|
|
|
|
|
|
|
|
|
50
|
3
|
100
|
|
|
|
143
|
my ($rss, $vsz) = $out =~ /^\s*(\d+)\s+(\d+)\s*$/m |
|
51
|
|
|
|
|
|
|
or return; |
|
52
|
|
|
|
|
|
|
|
|
53
|
2
|
|
|
|
|
47
|
my %mem = _empty_mem(); |
|
54
|
2
|
|
|
|
|
23
|
$mem{rss} = [$rss, 'kB']; |
|
55
|
2
|
|
|
|
|
25
|
$mem{size} = [$vsz, 'kB']; |
|
56
|
2
|
|
|
|
|
54
|
return %mem; |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub _collect_win32 { |
|
60
|
4
|
50
|
|
4
|
|
190114
|
return unless eval { require Win32::Process::Memory; 1 }; |
|
|
4
|
|
|
|
|
32
|
|
|
|
4
|
|
|
|
|
12
|
|
|
61
|
|
|
|
|
|
|
|
|
62
|
4
|
100
|
|
|
|
7
|
my $info = eval { Win32::Process::Memory::GetProcessMemoryInfo($$) } |
|
|
4
|
|
|
|
|
10
|
|
|
63
|
|
|
|
|
|
|
or return; |
|
64
|
|
|
|
|
|
|
|
|
65
|
2
|
|
50
|
|
|
18
|
my $rss = $info->{WorkingSetSize} || 0; |
|
66
|
2
|
|
100
|
|
|
12
|
my $peak = $info->{PeakWorkingSetSize} || 0; |
|
67
|
2
|
|
100
|
|
|
24
|
my $size = $info->{PagefileUsage} || 0; |
|
68
|
|
|
|
|
|
|
|
|
69
|
2
|
|
|
|
|
7
|
my %mem = _empty_mem(); |
|
70
|
2
|
50
|
|
|
|
12
|
$mem{rss} = [int($rss / 1024), 'kB'] if $rss; |
|
71
|
2
|
100
|
|
|
|
6
|
$mem{peak} = [int($peak / 1024), 'kB'] if $peak; |
|
72
|
2
|
100
|
|
|
|
7
|
$mem{size} = [int($size / 1024), 'kB'] if $size; |
|
73
|
2
|
|
|
|
|
11
|
return %mem; |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _collector_for_os { |
|
77
|
18
|
|
|
18
|
|
246222
|
my $os = shift; |
|
78
|
18
|
100
|
|
|
|
93
|
$os = $^O unless defined $os; |
|
79
|
18
|
100
|
100
|
|
|
143
|
return \&_collect_proc if $os eq 'linux' || $os eq 'cygwin' || $os eq 'gnukfreebsd'; |
|
|
|
|
100
|
|
|
|
|
|
80
|
10
|
100
|
100
|
|
|
106
|
return \&_collect_ps if $os eq 'darwin' || $os =~ /bsd$/ |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|| $os eq 'solaris' || $os eq 'aix' || $os eq 'hpux'; |
|
82
|
3
|
100
|
|
|
|
11
|
return \&_collect_win32 if $os eq 'MSWin32'; |
|
83
|
2
|
|
|
|
|
9
|
return undef; |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub _maxrss_kb { |
|
87
|
7
|
50
|
|
7
|
|
263468
|
return unless eval { require BSD::Resource; 1 }; |
|
|
7
|
|
|
|
|
55
|
|
|
|
7
|
|
|
|
|
28
|
|
|
88
|
7
|
100
|
|
|
|
24
|
my @ru = BSD::Resource::getrusage(BSD::Resource::RUSAGE_SELF()) or return; |
|
89
|
6
|
|
|
|
|
129
|
my $maxrss = $ru[2]; |
|
90
|
6
|
100
|
66
|
|
|
37
|
return unless defined $maxrss && $maxrss > 0; |
|
91
|
5
|
100
|
|
|
|
38
|
return $^O eq 'darwin' ? int($maxrss / 1024) : $maxrss; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub _augment_peak { |
|
95
|
10
|
|
|
10
|
|
16130
|
my %mem = @_; |
|
96
|
10
|
100
|
66
|
|
|
112
|
return %mem if !exists $mem{peak} || $mem{peak}->[0] ne 'NA'; |
|
97
|
|
|
|
|
|
|
|
|
98
|
3
|
|
|
|
|
9
|
my $kb = _maxrss_kb(); |
|
99
|
3
|
100
|
|
|
|
18
|
return %mem unless defined $kb; |
|
100
|
2
|
|
|
|
|
8
|
$mem{peak} = [$kb, 'kB']; |
|
101
|
2
|
|
|
|
|
11
|
return %mem; |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub collect_mem { |
|
105
|
8
|
|
|
8
|
|
4591
|
my $c = _collector_for_os(); |
|
106
|
8
|
100
|
|
|
|
56
|
my %mem = $c ? $c->() : (); |
|
107
|
|
|
|
|
|
|
|
|
108
|
8
|
100
|
|
|
|
51
|
unless (%mem) { |
|
109
|
2
|
|
|
|
|
9
|
my $kb = _maxrss_kb(); |
|
110
|
2
|
100
|
|
|
|
43
|
return () unless defined $kb; |
|
111
|
1
|
|
|
|
|
3
|
%mem = _empty_mem(); |
|
112
|
1
|
|
|
|
|
5
|
$mem{peak} = [$kb, 'kB']; |
|
113
|
1
|
|
|
|
|
6
|
return %mem; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
6
|
|
|
|
|
28
|
return _augment_peak(%mem); |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
sub send_mem_event { |
|
120
|
8
|
|
|
8
|
0
|
50783
|
my ($ctx, $real, $new) = @_; |
|
121
|
|
|
|
|
|
|
|
|
122
|
8
|
|
|
|
|
58
|
my %mem = collect_mem(); |
|
123
|
8
|
100
|
|
|
|
87
|
return unless %mem; |
|
124
|
7
|
100
|
|
|
|
28
|
return unless grep { $_->[0] ne 'NA' } values %mem; |
|
|
21
|
|
|
|
|
75
|
|
|
125
|
|
|
|
|
|
|
|
|
126
|
6
|
|
|
|
|
39
|
$mem{details} = "rss: $mem{rss}->[0]$mem{rss}->[1]\nsize: $mem{size}->[0]$mem{size}->[1]\npeak: $mem{peak}->[0]$mem{peak}->[1]"; |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
$ctx->send_ev2( |
|
129
|
|
|
|
|
|
|
memory => \%mem, |
|
130
|
|
|
|
|
|
|
about => {package => __PACKAGE__, details => $mem{details}}, |
|
131
|
|
|
|
|
|
|
info => [{tag => 'MEMORY', details => $mem{details}}], |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
harness_job_fields => [ |
|
134
|
|
|
|
|
|
|
map { |
|
135
|
6
|
|
|
|
|
57
|
my $k = $_; |
|
|
18
|
|
|
|
|
32
|
|
|
136
|
18
|
|
|
|
|
33
|
my ($v, $u) = @{$mem{$k}}; |
|
|
18
|
|
|
|
|
46
|
|
|
137
|
|
|
|
|
|
|
+{ |
|
138
|
18
|
50
|
|
|
|
152
|
name => "mem_$k", |
|
139
|
|
|
|
|
|
|
details => "$v$u", |
|
140
|
|
|
|
|
|
|
data => {value => ($v eq 'NA' ? undef : $v + 0), units => $u}, |
|
141
|
|
|
|
|
|
|
}; |
|
142
|
|
|
|
|
|
|
} qw/rss size peak/, |
|
143
|
|
|
|
|
|
|
], |
|
144
|
|
|
|
|
|
|
); |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
1; |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
__END__ |