File Coverage

blib/lib/Schedule/Load/Hosts/Host.pm
Criterion Covered Total %
statement 123 154 79.8
branch 46 92 50.0
condition 17 52 32.6
subroutine 31 36 86.1
pod 17 26 65.3
total 234 360 65.0


line stmt bran cond sub pod time code
1             # Schedule::Load::Hosts::Host.pm -- Loading information about a host
2             # See copyright, etc in below POD section.
3             ######################################################################
4              
5             package Schedule::Load::Hosts::Host;
6             require 5.004;
7             require Exporter;
8             require AutoLoader;
9             @ISA = qw(Exporter AutoLoader);
10              
11 1     1   6 use Schedule::Load qw(_min _max);
  1         2  
  1         52  
12 1     1   557 use Schedule::Load::Hosts::Proc;
  1         2  
  1         40  
13 1     1   407 use Schedule::Load::Safe;
  1         3  
  1         36  
14              
15 1     1   6 use Carp;
  1         2  
  1         64  
16 1     1   5 use strict;
  1         2  
  1         36  
17 1     1   6 use vars qw($VERSION $AUTOLOAD $Debug $Safer);
  1         2  
  1         1952  
18              
19             ######################################################################
20             #### Configuration Section
21              
22             # Other configurable settings.
23             $VERSION = '3.064';
24              
25             ######################################################################
26             #### Globals
27              
28             $Debug = $Schedule::Load::Debug;
29             $Safer = Schedule::Load::Safe->new();
30              
31             ######################################################################
32             #### Special status
33              
34             sub fields {
35 2 50 33 2 1 3 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->hosts)';
  2         15  
36 2         3 my @keys = keys %{$self->{const}};
  2         25  
37 2         6 push @keys, keys %{$self->{stored}};
  2         8  
38 2         4 push @keys, keys %{$self->{dynamic}};
  2         13  
39 2         6 return (grep {$_ ne "procs"} @keys);
  64         131  
40             }
41              
42             sub exists {
43 2 50 33 2 1 3 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->get(field))';
  2         20  
44 2         3 my $field = shift;
45 2   33     64 return (exists ($self->{dynamic}{$field})
46             || exists ($self->{stored}{$field})
47             || exists ($self->{const}{$field}));
48             }
49              
50             sub get {
51 2 50 33 2 1 4 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->get(field))';
  2         52  
52 2         3 my $field = shift;
53             # Always look at dynamic info first, there might be a override of a const
54 2 50       21 if (exists ($self->{dynamic}{$field})) {
    50          
    50          
55 0         0 return $self->{dynamic}{$field};
56             } elsif (exists ($self->{stored}{$field})) {
57 0         0 return $self->{stored}{$field};
58             } elsif (exists ($self->{const}{$field})) {
59 2         15 return $self->{const}{$field};
60             } else {
61 0         0 croak __PACKAGE__.'->get($field): Unknown field';
62             }
63             }
64              
65             sub get_undef {
66 24 50 33 24 0 34 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->get(field))';
  24         121  
67 24         56 my $field = shift;
68             # Always look at dynamic info first, there might be a override of a const
69 24 50       118 if (exists ($self->{dynamic}{$field})) {
    50          
    100          
70 0         0 return $self->{dynamic}{$field};
71             } elsif (exists ($self->{stored}{$field})) {
72 0         0 return $self->{stored}{$field};
73             } elsif (exists ($self->{const}{$field})) {
74 12         201 return $self->{const}{$field};
75             } else {
76 12         57 return undef;
77             }
78             }
79              
80             ######################################################################
81             #### Matching
82              
83             sub host_match {
84 14 50 33 14 0 23 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->host_match(classesref))';
  14         77  
85             # Params can be either a hash reference (for chooser)
86             # or a list of parameters (simple user functions)
87 14         32 my $paramref = $_[0];
88 14 50       34 if (!ref $paramref) {
89 14         41 $paramref = {#classes=>[],
90             #match_cb=> undef,
91             #allow_reserved=>1,
92             @_,
93             };
94             }
95             # For use of Hosts::hosts_match
96 14   33     227 return ((!defined $paramref->{classes} || $self->classes_match($paramref->{classes}))
97             && (!defined $paramref->{match_cb} || $self->eval_match ($paramref->{match_cb}))
98             && (!defined $paramref->{allow_reserved} || $paramref->{allow_reserved}
99             || !$self->reserved)
100             );
101             }
102              
103             sub host_match_chooser {
104 0     0 0 0 my $self = $_[0];
105             # Similar to host_match, but for internal use by the chooser - performance critical
106 0         0 my $paramref = $_[1];
107 0         0 my $scratchref = $_[2];
108             # For use of Hosts::hosts_match
109 0   0     0 return (( !defined $paramref->{classes} || !defined $paramref->{classes}[0]
110             || _classes_match_chooser($self, $paramref->{classes})
111             )
112             && (!defined $paramref->{match_cb}
113             #Slow, so inlined: || $self->eval_match ($paramref->{match_cb}, $scratchref)
114             || _eval_generic_cb($self, $paramref->{match_cb}, $scratchref)
115             )
116             && (!defined $paramref->{allow_reserved} || $paramref->{allow_reserved}
117             || !$self->reserved)
118             );
119             }
120              
121             sub classes_match {
122 6 50 33 6 1 13 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->classes_match(classesref))';
  6         44  
123 6         10 my $classesref = shift;
124 6 50 33     40 return 1 if !defined $classesref || !defined $classesref->[0]; # Null reference means match everything
125 6 50       18 (ref($classesref)) or croak 'usage: '.__PACKAGE__.'->classes_match(field, classesref))';
126 6         8 foreach (@{$classesref}) {
  6         14  
127 6 50       16 return 1 if get_undef($self, $_);
128             }
129 0         0 return 0;
130             }
131              
132             sub _classes_match_chooser {
133 0     0   0 my $self = $_[0];
134 0         0 my $classesref = $_[1];
135 0         0 foreach (@{$classesref}) {
  0         0  
136 0 0       0 return 1 if get_undef($self, $_);
137             }
138 0         0 return 0;
139             }
140              
141             sub eval_match {
142 4 50 33 4 1 120 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->eval_match(subroutine)';
  4         29  
143 4         6 my $subref = shift;
144             # @_ are optional arguments
145             # See inlined version in host_match_chooser
146 4 50       8 return 1 if !defined $subref; # Null reference means match everything
147 4         10 return $self->_eval_generic_cb($subref,@_);
148             }
149              
150             sub _eval_generic_cb {
151 4     4   7 my $self = shift;
152 4         4 my $subref = shift;
153             # @_ are optional arguments
154             # Call &$subref($self) in safe container
155 4         34 return $Safer->eval_cb($subref,$self,@_);
156             }
157              
158             ######################################################################
159             #### Special accessors
160              
161             sub cpus_slash {
162 2     2 1 5 my $self = shift;
163 2 50       27 if ($self->cpus != $self->physical_cpus) {
164 0         0 return $self->physical_cpus."/".$self->cpus;
165             } else {
166 2         126 return $self->cpus;
167             }
168             }
169              
170             sub top_processes {
171 2 50 33 2 1 3 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->key(key))';
  2         19  
172 2         3 my @keys = (values %{$self->{dynamic}{proc}});
  2         8  
173 2         4 grep {bless $_, 'Schedule::Load::Hosts::Proc'} @keys;
  1         19  
174             #print "TOP PROC @keys\n";
175 2 50       13 return (wantarray ? @keys : \@keys);
176             }
177              
178             sub holds {
179 0     0 1 0 my $self = shift;
180 0 0       0 return if !$self->{dynamic}{holds};
181 0         0 return (sort {$a->compare_pri_time($b)} (@{$self->{dynamic}{holds}}));
  0         0  
  0         0  
182             }
183              
184             sub free_cpus {
185 8     8 0 15 my $self = shift;
186             # How many more jobs host can take before we should turn off new jobs
187 8         151 my $free = ($self->cpus - $self->adj_load);
188 8 50       22 $free = 0 if ($free < 0);
189 8         25 $free = int ($free + .7);
190 8         25 return $free;
191             }
192              
193             sub rating_cb {
194 4 50 33 4 0 5 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->key(key))';
  4         29  
195             # How fast can we process a single job?
196             # 0 indicates can't load this host
197             # closer to 0 are the best ratings (as 'bad' is open-ended)
198 4 50 33     11 if ($self->get_undef('load_limit')
199             && $self->load_limit <= $self->adj_load) {
200             # Illegal to load this host more
201 0         0 return 0;
202             }
203              
204 4         6 my $rate = 1e9;
205             # Multiply badness by cpu loading
206             # Scale it to be between .8 and 1.0, else a large number of inactive jobs would
207             # result in a very good rating, which would make that machine always be picked.
208 4         82 $rate *= ((($self->total_pctcpu+1)/100) * 0.2 + 0.8);
209             # Multiply that by number of jobs
210 4         80 $rate *= ($self->adj_load+1);
211             # Discount by cpus & frequency
212 4         72 $rate /= $self->cpus;
213 4         78 $rate /= $self->max_clock * 0.4; # 1 free cpu at 300Mhz beat 50% of a 600 Mhz cpu
214 4   50     10 $rate *= ($self->get_undef('rating_mult') || 1.0);
215              
216             #printf "%f * (%d+%d+1) / %f / %f = %f\n", ($self->total_pctcpu+1), $self->report_load, $self->adj_load, $self->cpus, $self->max_clock, $rate if $Debug;
217 4 50       12 return 0 if $rate<=0;
218 4         9 $rate = log($rate); # Make a more readable number
219 4   50     9 $rate += ($self->get_undef('rating_adder') || 0);
220 4         50 return $rate;
221             }
222              
223             sub rating {
224 4 50 33 4 0 7 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->rating(subroutine)';
  4         29  
225 4         5 my $subref = shift;
226 4 50       18 return $self->rating_cb() if !defined $subref; # Null reference means default callback
227 0         0 return $self->_eval_generic_cb($subref);
228             }
229              
230             sub rating_chooser {
231             # Similar to rating, but for internal use by the chooser - performance critical
232 0     0 0 0 my $self = $_[0];
233 0         0 my $subref = $_[1];
234 0         0 my $scratchref = $_[2];
235 0 0       0 return $self->rating_cb() if !defined $subref; # Null reference means default callback
236 0         0 return $self->_eval_generic_cb($subref, $scratchref);
237             }
238              
239             sub rating_text {
240 2 50 33 2 0 5 my $self = shift; ($self && ref($self)) or croak 'usage: '.__PACKAGE__.'->rating(subroutine)';
  2         23  
241 2 50       44 return "inf" if $self->reserved;
242 2 50       6 return "inf" if !$self->rating;
243 2 50       4 return "slow" if $self->get_undef('slreportd_unresponsive');
244 2         6 return sprintf("%4.2f", $self->rating);
245             }
246              
247             ######################################################################
248             #### Accessors
249              
250             sub AUTOLOAD {
251 10     10   14 my $self = shift;
252 10 50       26 my $type = ref($self) or croak "$self is not an ".__PACKAGE__." object";
253              
254 10         50 (my $field = $AUTOLOAD) =~ s/.*://; # Remove package
255              
256 10 100       53 if (exists ($self->{dynamic}{$field})) {
    100          
    50          
257             # Dynamic variables stay dynamic
258 2     15 1 69 eval "sub $field { return \$_[0]->{dynamic}{$field}; }";
  15     5 1 183  
  5         63  
259 2         61 return $self->{dynamic}{$field};
260             } elsif (exists ($self->{stored}{$field})) {
261             # Stored variables can move to/from const variables
262 1 50   15 1 80 eval "sub $field { return (exists \$_[0]->{stored}{$field} "
  15         139  
263             ."? \$_[0]->{stored}{$field} : \$_[0]->{const}{$field}); }";
264 1         12 return $self->{stored}{$field};
265             } elsif (exists ($self->{const}{$field})) {
266 7 50   1 1 602 eval "sub $field { return (exists \$_[0]->{stored}{$field} "
  1 50   25 1 24  
  25 50   142 1 295  
  142 50   5 1 1348  
  5 50   1 0 40  
  1 50   1 1 7  
  1 50   2 1 7  
  2         20  
267             ."? \$_[0]->{stored}{$field} : \$_[0]->{const}{$field}); }";
268 7         121 return $self->{const}{$field};
269             } else {
270 0         0 croak "$type->$field: Unknown ".__PACKAGE__." field $field";
271             }
272             }
273              
274 0     0     sub DESTROY {}
275              
276             ######################################################################
277             ######################################################################
278             #### Package return
279             1;
280              
281             ######################################################################
282             __END__