Skip to content

Commit e3932f6

Browse files
authored
Merge pull request #350 from thekid/feature/available-processors
Add Environment::availableProcessors()
2 parents f97492c + 024d56d commit e3932f6

3 files changed

Lines changed: 60 additions & 6 deletions

File tree

src/main/php/lang/Environment.class.php

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
<?php namespace lang;
22

3+
use Com, Closure;
4+
35
/**
46
* User environment
57
*
6-
* @test xp://net.xp_framework.unittest.core.EnvironmentTest
8+
* @test net.xp_framework.unittest.core.EnvironmentTest
79
*/
810
abstract class Environment {
911

@@ -57,16 +59,15 @@ public static function variables($filter= null) {
5759
*/
5860
public static function variable($arg, ... $default) {
5961
foreach ((array)$arg as $name) {
60-
if (false === ($env= getenv($name))) continue;
61-
return $env;
62+
if (false !== ($env= getenv($name))) return $env;
6263
}
6364

6465
if (empty($default)) {
6566
throw new IllegalArgumentException(is_array($arg)
6667
? 'None of the variables [$'.implode(', $', $arg).'] exists'
6768
: 'No such environment variable $'.$name
6869
);
69-
} else if ($default[0] instanceof \Closure) {
70+
} else if ($default[0] instanceof Closure) {
7071
return $default[0]($arg);
7172
} else {
7273
return $default[0];
@@ -111,6 +112,54 @@ public static function platform(): string {
111112
;
112113
}
113114

115+
/**
116+
* Returns the number of processors available in this environment. First checks
117+
* for the `NUMBER_OF_PROCESSORS` environment variables, then uses platform-
118+
* specific files and tools. Returns NULL if no discovery method is available.
119+
*
120+
* @see https://stackoverflow.com/q/6481005 (Linux)
121+
* @see https://stackoverflow.com/q/1715580 (Mac OS)
122+
* @see https://stackoverflow.com/q/22919076 (Windows)
123+
* @see https://stackoverflow.com/a/49152519 (Docker w/ `--cpus=<n>`)
124+
* @see https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-computersystem
125+
* @return ?int|float
126+
*/
127+
public static function availableProcessors() {
128+
if ($n= getenv('NUMBER_OF_PROCESSORS')) {
129+
return (int)$n;
130+
} else if (class_exists(Com::class)) {
131+
$c= new Com('winmgmts://./root/cimv2');
132+
foreach ($c->instancesOf('Win32_ComputerSystem') as $sys) {
133+
return $sys->NumberOfProcessors;
134+
}
135+
} else if (is_readable($f= '/sys/fs/cgroup/cpu/cpu.cfs_quota_us') && ($fd= fopen($f, 'r'))) {
136+
fscanf($fd, '%d', $n);
137+
fclose($fd);
138+
if ($n > 0) return (float)($n / 100000);
139+
// Fall through
140+
}
141+
142+
if (is_readable($f= '/proc/cpuinfo') && ($fd= fopen($f, 'r'))) {
143+
$n= 0;
144+
do {
145+
$line= fgets($fd, 1024);
146+
if (0 === strncmp($line, 'processor', 9)) $n++;
147+
} while (!feof($fd));
148+
fclose($fd);
149+
return $n;
150+
} else {
151+
$paths= explode(PATH_SEPARATOR, getenv('PATH'));
152+
foreach (['nproc' => '', 'sysctl' => ' -n hw.ncpu'] as $command => $args) {
153+
foreach ($paths as $path) {
154+
$binary= $path.DIRECTORY_SEPARATOR.$command;
155+
if (is_executable($binary)) return (int)exec($binary.$args);
156+
}
157+
}
158+
}
159+
160+
return null;
161+
}
162+
114163
/**
115164
* Returns a path for display for a given directory. Will replace current
116165
* and parent directories with `.` and `..`, the user's home directory with
@@ -167,7 +216,7 @@ public static function path(string $dir= '.', ?string $platform= null): string {
167216
* cannot be found, uses PHP's builtin functionality.
168217
*/
169218
public static function tempDir(): string {
170-
$dir= self::variable(['TEMP', 'TMP', 'TMPDIR', 'TEMPDIR'], function() { return sys_get_temp_dir(); });
219+
$dir= self::variable(['TEMP', 'TMP', 'TMPDIR', 'TEMPDIR'], fn() => sys_get_temp_dir());
171220
return rtrim($dir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
172221
}
173222

src/main/php/lang/Runtime.class.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static function __static() {
2424
public static function getInstance() {
2525
return self::$instance;
2626
}
27-
27+
2828
/**
2929
* Returns the total amount of memory available to the runtime. If there
3030
* is no limit zero will be returned.

src/test/php/lang/unittest/EnvironmentTest.class.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ public function platform() {
115115
Assert::notEquals('', Environment::platform());
116116
}
117117

118+
#[Test]
119+
public function available_processors() {
120+
Assert::notEquals(0, Environment::availableProcessors());
121+
}
122+
118123
#[Test]
119124
public function current_path() {
120125
Assert::equals('.', Environment::path());

0 commit comments

Comments
 (0)