This code is simply to test the banacer sub routine. This sub takes a hash containing some sort of process_id as the key, and a process run time (i used seconds), and a number of split processes. This is used to balance programs which run multiple smaller processes into logical groupings.
Another use for this might be balancing large files (names as keys, sizes as values) into a number of directories/partitions.
#!/usr/bin/perl
use strict;
use vars qw(%PROCESS_TIMES);
## process_id => run_time_in_sec
%PROCESS_TIMES = (
117 => '335',
118 => '389',
119 => '005',
120 => '201',
130 => '622',
131 => '090',
132 => '110',
133 => '245',
134 => '010',
135 => '075',
136 => '104',
);
######################## Tester Code #####################
my @AoA = &balancer(\%PROCESS_TIMES,4);
## Verify if worked :
my $a = 0;
my $perc_tot = 0;
my $trt = &bucket_run_time([values %PROCESS_TIMES]);
foreach my $queue (@AoA) {
my @foo = ();
foreach my $pid (@$queue) {
push(@foo,$PROCESS_TIMES{$pid});
}
my $brt = &bucket_run_time(\@foo);
printf("Balanced Run Time %d : %d (%3.2f %%)\n",$a,$brt,($brt/$trt
+*100));
$a++;
$perc_tot += ($brt/$trt*100);
}
print " That is $perc_tot %\n";
exit(0);
################### end tester code #########################
# @AoA = balancer(\%hash,$X);
# Given a hash ref with process id's as keys, and
# run time in second as value, balance into X groups
# of balanced run time. Returns an array with X
# elemnts, which are the array references.
sub balancer {
my ($href,$buckets) = @_;
my @output_AoA = ();
if (! defined($href) || ! defined($buckets) || $buckets < 1) {
return undef;
}
my $total_run_time = &bucket_run_time([values %{$href}]);
my $bucket_target = $total_run_time/$buckets;
my %rt_hash = &rev_hash(%{$href});
BUCKET: for (my $i = 0;$i < $buckets;$i++) {
my $current_run_time = 0;
RUNTIME: foreach my $run_time (reverse(sort(keys(%rt_hash))))
+{
# largets to smallest, take first to fit
## Handle runtime > bucket size
if ($run_time > $bucket_target) {
push(@{$output_AoA[$i]},pop(@{$rt_hash{$run_time}}));
if (scalar @{$rt_hash{$run_time}} == 0) {
# no more with that run time, remove
delete $rt_hash{$run_time};
}
next BUCKET;
}
if ( ($current_run_time+$run_time) < $bucket_target) {
# add it
$current_run_time += $run_time;
push(@{$output_AoA[$i]},pop(@{$rt_hash{$run_time}}));
if (scalar @{$rt_hash{$run_time}} == 0) {
# no more with that run time, remove
delete $rt_hash{$run_time};
}
} else {
# bucket full
}
}
}
return(@output_AoA);
}
## used by balancer
sub rev_hash {
my (%input) = @_;
my %output = ();
foreach my $k (keys %input) {
push(@{$output{$input{$k}}},$k);
}
return(%output);
}
## used for tester code
sub bucket_run_time {
my ($aref) = @_;
my $tot = 0;
for (@{$aref}) {
$tot+=$_;
}
return($tot);
}