1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
|
use lib qw(blib/lib blib/arch);
use Sys::CpuAffinity;
use Test::More tests => 2;
use Math::BigInt;
use strict qw(vars subs);
use warnings;
$| = 1;
sub TWO () { goto &Sys::CpuAffinity::TWO }
#
# Exercise all of the methods in the toolbox to
# count processors on the system, get cpu affinity,
# and set cpu affinity.
#
# Generally each tool is targeted to work on a
# single system. Since most of the tools are
# targeted at a different system than yours,
# most of these tools will fail on your system.
#
# Among the tools that are targeted to your
# system, some of them will depend on certain
# Perl modules or certain external programs
# being available, so those tools might also
# fail on your system.
#
# Hopefully, we'll find at least one tool for
# each task (count cpus, get affinity, set
# affinity) that will work for you, which is
# all we need.
#
my $pid = $$;
$Sys::CpuAffinity::IS_TEST = 1;
#########################################################
#
# get inventory of all Sys::CpuAffinity techniques
# from the Sys::CpuAffinity source code.
#
# XXX - could also inspect %Sys::CpuAffinity:: symbol table.
#
#########################################################
{
my (@SET, @GET, @NCPUS);
open my $source, '<', $INC{"Sys/CpuAffinity.pm"}
or die "failed to load Sys::CpuAffinity source. $!\n";
while (<$source>) {
next unless /^sub _/;
next if /XXX/; # method still under development
if (/^sub _setAffinity_with_(\S+)/) {
push @SET, $1;
} elsif (/^sub _getAffinity_with_(\S+)/) {
push @GET, $1;
} elsif (/^sub _getNumCpus_from_(\S+)/) {
push @NCPUS, $1;
}
}
close $source;
sub inventory::getAffinity {
# put "DEBUG" methods at the end of the list
sort { $a=~/DEBUG/i <=> $b=~/DEBUG/i || lc $a cmp lc $b } @GET
}
sub inventory::setAffinity {
sort { $a=~/DEBUG/i <=> $b=~/DEBUG/i || lc $a cmp lc $b } @SET
}
sub inventory::getNumCpus { sort { lc $a cmp lc $b } @NCPUS }
}
select STDERR;
print "\n\n";
EXERCISE_COUNT_NCPUS();
my $n = Sys::CpuAffinity::getNumCpus();
if ($n <= 1) {
SKIP: {
if ($n == 1) {
skip "affinity exercise. Only one processor on this system", 2;
} else {
skip "affinity exercise. Can't detect number of processors", 2;
}
}
exit 0;
}
EXERCISE_GET_AFFINITY();
EXERCISE_SET_AFFINITY();
sleep 1;
ok(1);
# call all of the getAffinity_with_XXX methods
# method is successful if
# at least one method returns > 0
# all methods that return > 0 return the same value
sub EXERCISE_GET_AFFINITY {
my $ok = 0;
print "===============================================\n";
print "Current affinity = \n";
my $success = 0;
for my $s (inventory::getAffinity()) {
my $sub = 'Sys::CpuAffinity::_getAffinity_with_' . $s;
printf " %-30s ==> ", $s;
if ($sub =~ /DEBUG/i && $success) {
print "skip\n";
next;
}
my $z = eval { $sub->($pid) };
printf "%s\n", $z || 0;
$success += ($z||0) > 0;
if ($z && $z > 0) {
if ($ok == 0) {
$ok = $z;
} elsif ($ok != $z) {
$ok = -1;
}
}
}
if ($success == 0) {
recommend($^O, 'getAffinity');
}
print "\n\n";
SKIP: {
if ($ok == 0 && $^O =~ /darwin|MacOS|openbsd/i) {
skip "getAffinity/setAffinity not expected to be supported on $^O", 1;
}
ok($ok > 0, "at least one _getAffinity_XXX method works and "
. "all other methods are consistent");
}
}
#
# call all of the _getNumCpus_from_XXX functions.
# Passes if
# at least one methods returns > 0
# all methods that return > 0 return the same value
#
sub EXERCISE_COUNT_NCPUS {
local $Sys::CpuAffinity::DEBUG = $ENV{DEBUG} || 0;
if ($^O =~ /openbsd/i || $^O =~ /darwin/i) {
$Sys::CpuAffinity::DEBUG = 1;
}
print "=================================================\n";
print "Num processors =\n";
my $ok = 0;
for my $technique (inventory::getNumCpus()) {
my $s = 'Sys::CpuAffinity::_getNumCpus_from_' . $technique;
printf " %-30s ", $technique;
my $ncpus = eval { $s->() } || 0;
printf "- %s -\n", $ncpus;
if ($ncpus > 0) {
if ($ok eq 0) {
$ok = $ncpus;
} elsif ($ok ne $ncpus) {
$ok = -1;
}
}
}
print "\n\n";
# ok($ok > 0, "at least one _getNumCpus_XXX method works and "
# . "all other methods are consistent");
}
#
# call each of the _setAffinity_with_XXX methods.
# passes if at least one method works
#
sub EXERCISE_SET_AFFINITY {
print "==================================================\n";
my $np = Sys::CpuAffinity::getNumCpus();
if ($np <= 1) {
SKIP: {
# skip "skip set affinity test on single-processor sys", 1;
1;
}
return 0;
}
my $ok = 0;
my ($TARGET,$LAST_TARGET) = (0,0);
my @mask = ();
my $_2_np_1 = TWO ** $np - 1;
my $nc = $np > 10 ? 10 : $np;
while (@mask < 100) {
$TARGET = 0;
for my $i (0 .. @mask) {
my $c = int(rand() * $np);
$TARGET ^= TWO ** $c;
}
redo if $TARGET == 0;
redo if $TARGET == $LAST_TARGET && $np > 1;
$LAST_TARGET = $TARGET;
push @mask, $TARGET;
}
# print "@mask\n";
my $success = 0;
print "Set affinity =\n";
for my $technique (inventory::setAffinity()) {
my $rr = Sys::CpuAffinity::getAffinity($pid) || 0;
if ($rr == 0) {
printf " %-30s => %s ==> FAIL\n", $technique,
"no affinity";
next;
}
my $mask;
do {
$mask = shift @mask;
} while $mask == $rr;
my $s = "Sys::CpuAffinity::_setAffinity_with_$technique";
if ($s =~ /DEBUG/i && $success) {
printf " %-30s => skip\n", $technique;
next;
}
eval { $s->($pid,$mask) };
printf " %-30s => %3s ==> ", $technique, $mask;
my $r = Sys::CpuAffinity::getAffinity($pid);
my $result = $r==$rr ? "FAIL" : " ok ";
if ($r != $rr) {
$success++;
}
printf "%3s [%s]\n", $r, $result;
}
if ($success == 0) {
recommend($^O, 'setAffinity');
}
print "\n\n";
# ok($success != 0, "at least one _setAffinity_XXX method works");
}
sub recommend {
use Config;
my ($sys, $function) = @_;
print "\n\n==========================================\n\n";
print "The function 'Sys::CpuAffinity::$function' does\n";
print "not seem to work on this system.\n\n";
my @recommendations;
if ($Config{"cc"}) {
@recommendations = ("install a C compiler (preferrably $Config{cc})");
} else {
@recommendations = ("install a C compiler");
}
if ($sys eq 'cygwin') {
push @recommendations, "install the Win32 module";
push @recommendations, "install the Win32::API module";
push @recommendations, "install the Win32::Process module";
} elsif ($sys eq 'MSWin32') {
push @recommendations, "install the Win32 module";
push @recommendations, "install the Win32::API module";
push @recommendations, "install the Win32::Process module";
} elsif ($sys =~ /openbsd/i) {
@recommendations = ();
print "OpenBSD does not provide (as far as I can tell)\n";
print "a way to manipulate the CPU affinities of processes.\n";
print "\n\n==========================================\n\n\n";
return;
} elsif ($sys =~ /netbsd/i) {
if ($> != 0) {
push @recommendations, "run as super-user";
push @recommendations,
"\t(the available methods for manipulating CPU affinities "
. "on NetBSD only work for super-user)";
}
} elsif ($sys =~ /freebsd/i) {
push @recommendations, "install the BSD::Process::Affinity module";
push @recommendations, "make sure the cpuset program is in the PATH";
} elsif ($sys =~ /solaris/i) {
push @recommendations, "make sure the pbind program is in the PATH";
} elsif ($sys =~ /irix/i) {
# still need to learn to use the cpuset_XXX functions
} elsif ($sys =~ /darwin/i || $sys =~ /MacOS/i) {
@recommendations = ();
print "The Mac OS does not provide (as far as I can tell)\n";
print "a way to manipulate the CPU affinities of processes.\n";
print "\n\n==========================================\n\n\n";
return;
} elsif ($sys =~ /aix/i) {
push @recommendations,
"make sure the bindprocessor program is in the PATH";
} else {
push @recommendations,
"don't know what else to recommend for system $sys";
}
if (@recommendations > 0) {
print "To make this module work, you may want to install:\n\n";
foreach (@recommendations) {
print "\t$_\n";
}
print "\n\n";
print "If these recommendations do not help, drop a note\n";
print "to mob\@cpan.org with details about your\n";
print "system configuration.\n";
}
print "\n\n==========================================\n\n\n";
}
|