blib/lib/Lustre/Info.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 37 | 129 | 28.6 |
branch | 4 | 54 | 7.4 |
condition | 0 | 3 | 0.0 |
subroutine | 14 | 24 | 58.3 |
pod | 11 | 12 | 91.6 |
total | 66 | 222 | 29.7 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | # | ||||||
2 | # Lutre::Info Mainclass | ||||||
3 | # | ||||||
4 | # (C) 2010 Adrian Ulrich - |
||||||
5 | # | ||||||
6 | # This program is free software; you can redistribute it and/or | ||||||
7 | # modify it under the same terms as Perl itself. | ||||||
8 | # | ||||||
9 | |||||||
10 | package Lustre::Info; | ||||||
11 | |||||||
12 | 1 | 1 | 788 | use strict; | |||
1 | 1 | ||||||
1 | 32 | ||||||
13 | 1 | 1 | 5 | use warnings; | |||
1 | 1 | ||||||
1 | 30 | ||||||
14 | 1 | 1 | 663 | use Lustre::Info::OST; | |||
1 | 1 | ||||||
1 | 24 | ||||||
15 | 1 | 1 | 446 | use Lustre::Info::Export; | |||
1 | 2 | ||||||
1 | 24 | ||||||
16 | 1 | 1 | 608 | use Lustre::Info::MDT; | |||
1 | 3 | ||||||
1 | 31 | ||||||
17 | |||||||
18 | require Exporter; | ||||||
19 | 1 | 1 | 4 | use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); | |||
1 | 2 | ||||||
1 | 5278 | ||||||
20 | |||||||
21 | @ISA = qw(Exporter); | ||||||
22 | @EXPORT = qw(); | ||||||
23 | @EXPORT_OK = qw(); | ||||||
24 | $VERSION = '0.02'; | ||||||
25 | |||||||
26 | 1 | 1 | 7 | use constant PROCFS_LUSTRE => "/proc/fs/lustre"; | |||
1 | 188 | ||||||
1 | 603 | ||||||
27 | 1 | 1 | 6 | use constant PROCFS_OBDFILTER => "/proc/fs/lustre/obdfilter"; | |||
1 | 1 | ||||||
1 | 53 | ||||||
28 | 1 | 1 | 5 | use constant PROCFS_MDS => "/proc/fs/lustre/mds"; | |||
1 | 2 | ||||||
1 | 5382 | ||||||
29 | |||||||
30 | ########################################################################## | ||||||
31 | # Creates a new Spy Object | ||||||
32 | sub new { | ||||||
33 | 1 | 1 | 1 | 920 | my($class,%args) = @_; | ||
34 | 1 | 4 | my $self = {}; | ||||
35 | 1 | 5 | bless($self,$class); | ||||
36 | 1 | 5 | return $self; | ||||
37 | } | ||||||
38 | |||||||
39 | ########################################################################## | ||||||
40 | # Return (uncached) list of all OBD Objects | ||||||
41 | sub get_ost_list { | ||||||
42 | 1 | 1 | 1 | 452 | my($self) = @_; | ||
43 | 1 | 2 | my @list = (); | ||||
44 | 1 | 50 | 41 | opendir(OBD, PROCFS_OBDFILTER) or return \@list; | |||
45 | 0 | 0 | while(defined(my $dirent = readdir(OBD))) { | ||||
46 | 0 | 0 | 0 | next if $dirent =~ /^\./; # dotfile | |||
47 | 0 | 0 | 0 | next if ! -d join("/",PROCFS_OBDFILTER, $dirent); | |||
48 | 0 | 0 | push(@list, $dirent); | ||||
49 | } | ||||||
50 | 0 | 0 | closedir(OBD); | ||||
51 | 0 | 0 | return \@list; | ||||
52 | } | ||||||
53 | |||||||
54 | ########################################################################## | ||||||
55 | # Returns (uncached) list of all exports known to all OSTs | ||||||
56 | sub get_export_list { | ||||||
57 | 0 | 0 | 1 | 0 | my($self) = @_; | ||
58 | 0 | 0 | my $list = {}; | ||||
59 | 0 | 0 | my @osts = $self->get_ost_list; | ||||
60 | |||||||
61 | 0 | 0 | foreach my $this_ost (@{$self->get_ost_list}) { | ||||
0 | 0 | ||||||
62 | 0 | 0 | my $export_dir = PROCFS_OBDFILTER."/$this_ost/exports/"; | ||||
63 | 0 | 0 | 0 | opendir(EXP, $export_dir) or next; | |||
64 | 0 | 0 | while(defined(my $dirent = readdir(EXP))) { | ||||
65 | 0 | 0 | 0 | next if $dirent =~ /^\./; # dotfile; | |||
66 | 0 | 0 | 0 | next if ! -d $export_dir.$dirent; | |||
67 | 0 | 0 | $list->{$dirent}++; | ||||
68 | } | ||||||
69 | 0 | 0 | closedir(EXP); | ||||
70 | } | ||||||
71 | 0 | 0 | my @exports = keys(%$list); | ||||
72 | 0 | 0 | return \@exports; | ||||
73 | } | ||||||
74 | |||||||
75 | ########################################################################## | ||||||
76 | # Return (unchaced) list of all MTD Objects | ||||||
77 | sub get_mdt_list { | ||||||
78 | 0 | 0 | 1 | 0 | my @list = (); | ||
79 | 0 | 0 | 0 | opendir(OBD, PROCFS_MDS) or return \@list; | |||
80 | 0 | 0 | while(defined(my $dirent = readdir(OBD))) { | ||||
81 | 0 | 0 | 0 | next if $dirent =~ /^\./; # dotfile | |||
82 | 0 | 0 | 0 | next if ! -d join("/",PROCFS_MDS, $dirent); | |||
83 | 0 | 0 | push(@list, $dirent); | ||||
84 | } | ||||||
85 | 0 | 0 | closedir(OBD); | ||||
86 | 0 | 0 | return \@list; | ||||
87 | } | ||||||
88 | |||||||
89 | ########################################################################## | ||||||
90 | # Returns TRUE if current host is acting as an OST | ||||||
91 | sub is_ost { | ||||||
92 | 1 | 50 | 1 | 1 | 55 | return ( -d PROCFS_LUSTRE."/ost" ? 1 : 0 ); | |
93 | } | ||||||
94 | |||||||
95 | ########################################################################## | ||||||
96 | # Returns TRUE if current host is acting as an MDS | ||||||
97 | sub is_mds { | ||||||
98 | 1 | 50 | 1 | 1 | 529 | return ( -d PROCFS_LUSTRE."/mds" ? 1 : 0 ); | |
99 | } | ||||||
100 | |||||||
101 | ########################################################################## | ||||||
102 | # Returns TRUE if current host is acting as an MDT | ||||||
103 | sub is_mdt { | ||||||
104 | 1 | 50 | 1 | 1 | 506 | return ( -d PROCFS_LUSTRE."/mdt" ? 1 : 0 ); | |
105 | } | ||||||
106 | |||||||
107 | ########################################################################## | ||||||
108 | # Return object to __PACKAGE__::OST Class | ||||||
109 | sub get_ost { | ||||||
110 | 0 | 0 | 1 | my($self,$ostname) = @_; | |||
111 | 0 | return Lustre::Info::OST->new(super=>$self, ostname=>$ostname); | |||||
112 | } | ||||||
113 | |||||||
114 | ########################################################################## | ||||||
115 | # Returns object to __PACKAGE__::Export Class | ||||||
116 | sub get_export { | ||||||
117 | 0 | 0 | 1 | my($self, $expname) = @_; | |||
118 | 0 | return Lustre::Info::Export->new(super=>$self, export=>$expname); | |||||
119 | } | ||||||
120 | |||||||
121 | ########################################################################## | ||||||
122 | # Returns object to __PACKAGE__::MDT | ||||||
123 | sub get_mdt { | ||||||
124 | 0 | 0 | 1 | my($self, $mdtname) = @_; | |||
125 | 0 | return Lustre::Info::MDT->new(super=>$self, mdtname=>$mdtname); | |||||
126 | } | ||||||
127 | |||||||
128 | ########################################################################## | ||||||
129 | # Return current lustre version (undef if lustre is not loaded) | ||||||
130 | sub get_lustre_version { | ||||||
131 | 0 | 0 | 1 | my $ver = undef; | |||
132 | 0 | 0 | open(LF, PROCFS_LUSTRE."/version") or return $ver; | ||||
133 | 0 | while( |
|||||
134 | 0 | 0 | if($_ =~ /^lustre: (\d.+)$/) { $ver = $1 } | ||||
0 | |||||||
135 | } | ||||||
136 | 0 | close(LF); | |||||
137 | 0 | return $ver; | |||||
138 | } | ||||||
139 | |||||||
140 | |||||||
141 | |||||||
142 | |||||||
143 | ########################################################################## | ||||||
144 | # Try to parse a lustre statistics file created by lprocfs | ||||||
145 | sub _parse_stats_file { | ||||||
146 | 0 | 0 | my($self,$fname) = @_; | ||||
147 | |||||||
148 | 0 | my $data = {}; | |||||
149 | 0 | my $snap = 0; | |||||
150 | 0 | 0 | open(P, $fname) or return undef; | ||||
151 | 0 | while( ) { |
|||||
152 | # req_waittime 21932809 samples [usec] 3 1047811 9446315012 4121280741355958 (<-- sqcount) | ||||||
153 | 0 | 0 | if(my($name,$samples,$format,$min,$max,$count) = $_ =~ /^(\S+)\s+(\d+) samples \[(.+)\]\s+(\d+)\s+(\d+)\s+(\d+)[^\d]/) { # note: sqcount is not used | ||||
0 | |||||||
0 | |||||||
154 | 0 | $data->{$name} = { format=>$format, samples=>$samples, count=>$count }; | |||||
155 | } | ||||||
156 | elsif(my($rqname,$rqx,$rqformat) = $_ =~ /^(\S+)\s+(\d+) samples \[(.+)\]/) { | ||||||
157 | 0 | $data->{$rqname} = { format=>$rqformat, samples=>$rqx, count=>$rqx }; | |||||
158 | } | ||||||
159 | elsif($_ =~ /^snapshot_time\s+([0-9.]+) /) { | ||||||
160 | 0 | $snap = $1; | |||||
161 | } | ||||||
162 | } | ||||||
163 | 0 | close(P); | |||||
164 | 0 | return({ timestamp=>$snap, data=>$data }); | |||||
165 | } | ||||||
166 | |||||||
167 | ########################################################################## | ||||||
168 | # Try to parse the per-export 'brw' statistics file | ||||||
169 | sub _parse_brw_file { | ||||||
170 | 0 | 0 | my($self,$fname) = @_; | ||||
171 | |||||||
172 | 0 | my $ctx = ''; | |||||
173 | 0 | my $r = {}; | |||||
174 | 0 | 0 | open(P, $fname) or return undef; | ||||
175 | 0 | while( ) { |
|||||
176 | 0 | 0 | 0 | if($_ =~ /^snapshot_time:\s+([0-9.]+) /) { | |||
0 | |||||||
0 | |||||||
0 | |||||||
177 | 0 | $r->{timestamp} = $1; | |||||
178 | } | ||||||
179 | elsif($_ =~ /([^:]+?)(\s+)ios .+ ios/) { | ||||||
180 | 0 | $ctx = lc($1); | |||||
181 | 0 | $ctx =~ tr/a-z0-9/_/c; | |||||
182 | } | ||||||
183 | elsif($_ =~ /^$/) { | ||||||
184 | 0 | $ctx = ''; | |||||
185 | } | ||||||
186 | elsif($ctx && $_ =~ /^(.+):\s+(\d+)\s+\d+\s+\d+\s+\|\s*(\d+)\s+\d+/) { | ||||||
187 | 0 | $r->{data}->{$ctx}->{$1} = { read=>$2, write=>$3 }; | |||||
188 | } | ||||||
189 | } | ||||||
190 | 0 | close(P); | |||||
191 | 0 | return $r; | |||||
192 | } | ||||||
193 | |||||||
194 | |||||||
195 | ########################################################################## | ||||||
196 | # Quick'n'dirty 'generic' parser | ||||||
197 | sub _parse_generic_file { | ||||||
198 | 0 | 0 | my($self,$fname) = @_; | ||||
199 | |||||||
200 | 0 | my $r = {}; | |||||
201 | 0 | 0 | open(P, $fname) or return undef; | ||||
202 | 0 | while( ) { |
|||||
203 | 0 | 0 | if(my($k,$v) = $_ =~ /^(\S+):\s+(.+)$/) { | ||||
204 | 0 | 0 | if($v =~ /^(\d+)\/(\d+)$/) { | ||||
205 | 0 | $v = [$1,$2]; | |||||
206 | } | ||||||
207 | 0 | $r->{$k} = $v; | |||||
208 | } | ||||||
209 | } | ||||||
210 | 0 | close(P); | |||||
211 | 0 | return $r; | |||||
212 | } | ||||||
213 | |||||||
214 | ########################################################################## | ||||||
215 | # Perform an addition on multiple deep hashrefs | ||||||
216 | # This could also be implemented by using recursion but perl is somewhat | ||||||
217 | # slow wehn it comes to call sub()'s, so eval should be faster for very | ||||||
218 | # 'deep' hashes. | ||||||
219 | sub sum_up_deep { | ||||||
220 | 0 | 0 | 0 | my($self, $size, @reflist) = @_; | |||
221 | |||||||
222 | 0 | my $to_eval_h = ''; | |||||
223 | 0 | my $to_eval_m = ''; | |||||
224 | 0 | my $to_eval_b = ''; | |||||
225 | 0 | my $eval_code = undef; | |||||
226 | 0 | my $res = {}; | |||||
227 | 0 | foreach my $tnum (0..$size) { | |||||
228 | 0 | my $nnum = $tnum+1; | |||||
229 | 0 | my $xtab = ( " " x $tnum ); | |||||
230 | 0 | $to_eval_h .= "${xtab}foreach my \$l$nnum (keys(%{\$lroot$to_eval_m})) {\n"; | |||||
231 | 0 | $to_eval_b = "$xtab}\n$to_eval_b"; | |||||
232 | 0 | $to_eval_m .= "->{\$l$nnum}"; | |||||
233 | } | ||||||
234 | |||||||
235 | # Assemble perl-loop-code: | ||||||
236 | 0 | $eval_code = "$to_eval_h\t\t\$res$to_eval_m += \$lroot$to_eval_m\n".$to_eval_b; | |||||
237 | |||||||
238 | #..and execute for each given hashref | ||||||
239 | 0 | foreach my $lroot (@reflist) { | |||||
240 | 0 | eval $eval_code; | |||||
241 | 0 | 0 | return undef if $@; # error? -> most likely caused by an invalid $size setting! | ||||
242 | } | ||||||
243 | 0 | return $res; | |||||
244 | } | ||||||
245 | |||||||
246 | |||||||
247 | 1; | ||||||
248 | __END__ |