Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow to pass a negative limit #140

Merged
merged 8 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/CpuCoreCounter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Fidry\CpuCoreCounter\Finder\FinderRegistry;
use InvalidArgumentException;
use function implode;
use function max;
use function sprintf;
use function sys_getloadavg;
use const PHP_EOL;
Expand Down Expand Up @@ -47,9 +48,12 @@ public function __construct(?array $finders = null)
* to reserve some CPUs for other processes. If the main
* process is going to be busy still, you may want to set
* this value to 1.
* @param positive-int|null $countLimit The maximum number of CPUs to return. If not provided, it
* @param non-zero-int|null $countLimit The maximum number of CPUs to return. If not provided, it
* may look for a limit in the environment variables, e.g.
* KUBERNETES_CPU_LIMIT.
* KUBERNETES_CPU_LIMIT. If negative, the limit will be
* the total number of cores found minus the absolute value.
* For instance if the system has 10 cores and countLimit=-2,
* then the effective limit considered will be 8.
* @param float|null $loadLimit Element of [0., 1.]. Percentage representing the
* amount of cores that should be used among the available
* resources. For instance, if set to 0.7, it will use 70%
Expand Down Expand Up @@ -93,9 +97,13 @@ public function getAvailableForParallelisation(
);
}

$correctedCountLimit = null === $countLimit
? self::getKubernetesLimit()
: $countLimit;
if (null === $countLimit) {
$correctedCountLimit = self::getKubernetesLimit();
} else {
$correctedCountLimit = $countLimit > 0
? $countLimit
: max(1, $totalCoreCount + $countLimit);
}

if (null !== $correctedCountLimit && $availableCores > $correctedCountLimit) {
$availableCores = $correctedCountLimit;
Expand Down Expand Up @@ -218,12 +226,9 @@ public static function getKubernetesLimit(): ?int

private static function checkCountLimit(?int $countLimit): void
{
if (null !== $countLimit && 0 >= $countLimit) {
if (0 === $countLimit) {
throw new InvalidArgumentException(
sprintf(
'The count limit must be a positive integer. Got "%s".',
$countLimit
)
'The count limit must be a non zero integer. Got "0".'
);
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/ParallelisationResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ final class ParallelisationResult
public $passedReservedCpus;

/**
* @var positive-int|null
* @var non-zero-int|null
*/
public $passedCountLimit;

Expand All @@ -39,7 +39,7 @@ final class ParallelisationResult
public $passedSystemLoadAverage;

/**
* @var positive-int|null
* @var non-zero-int|null
*/
public $correctedCountLimit;

Expand All @@ -60,8 +60,8 @@ final class ParallelisationResult

/**
* @param positive-int|0 $passedReservedCpus
* @param positive-int|null $passedCountLimit
* @param positive-int|null $correctedCountLimit
* @param non-zero-int|null $passedCountLimit
* @param non-zero-int|null $correctedCountLimit
* @param positive-int $totalCoresCount
* @param positive-int $availableCpus
*/
Expand Down
14 changes: 7 additions & 7 deletions tests/AvailableCpuCoresScenario.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ final class AvailableCpuCoresScenario
public $environmentVariables;
/** @var positive-int|0 */
public $reservedCpus;
/** @var positive-int */
/** @var non-zero-int|null */
public $countLimit;
/** @var float|null */
public $loadLimitPerCore;
public $loadLimit;
/** @var float|null */
public $systemLoadAverage;
/** @var positive-int */
Expand All @@ -41,23 +41,23 @@ final class AvailableCpuCoresScenario
* @param list<CpuCoreFinder> $finders
* @param array<string, string|int|null> $environmentVariables
* @param positive-int|0 $reservedCpus
* @param positive-int $limit
* @param non-zero-int|null $countLimit
* @param positive-int $expected
*/
public function __construct(
array $finders,
array $environmentVariables,
int $reservedCpus,
?int $limit,
?int $countLimit,
?float $loadLimit,
?float $systemLoadAverage,
int $expected
) {
$this->finders = $finders;
$this->environmentVariables = $environmentVariables;
$this->reservedCpus = $reservedCpus;
$this->countLimit = $limit;
$this->loadLimitPerCore = $loadLimit;
$this->countLimit = $countLimit;
$this->loadLimit = $loadLimit;
$this->systemLoadAverage = $systemLoadAverage;
$this->expected = $expected;
}
Expand All @@ -66,7 +66,7 @@ public function __construct(
* @param positive-int|null $coresCountFound
* @param array<string, string|int|null> $environmentVariables
* @param positive-int|0|null $reservedCpus
* @param positive-int|null $countLimit
* @param non-zero-int|null $countLimit
* @param positive-int $expected
*
* @return array{self}
Expand Down
47 changes: 41 additions & 6 deletions tests/CpuCoreCounterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public function test_it_can_get_the_number_of_available_cpu_cores_for_parallelis
$actual = $counter->getAvailableForParallelisation(
$scenario->reservedCpus,
$scenario->countLimit,
$scenario->loadLimitPerCore,
$scenario->loadLimit,
$scenario->systemLoadAverage
);

Expand Down Expand Up @@ -279,6 +279,36 @@ public static function availableCpuCoreProvider(): iterable
3
);

yield 'CPU count found, negative limit passed' => AvailableCpuCoresScenario::create(
5,
[],
0,
-2,
null,
null,
3
);

yield 'CPU count found, negative limit beyond available resources' => AvailableCpuCoresScenario::create(
5,
[],
0,
-10,
null,
null,
1
);

yield 'CPU count found, with reserved CPU, negative limit passed' => AvailableCpuCoresScenario::create(
5,
[],
1,
-2,
null,
null,
3
);

yield 'CPU count found, multiple CPUs reserved' => AvailableCpuCoresScenario::create(
5,
[],
Expand Down Expand Up @@ -361,9 +391,9 @@ public static function availableCpuCoreProvider(): iterable
}

/**
* @dataProvider limitProvider
* @dataProvider countLimitProvider
*/
public function test_it_does_not_accept_invalid_limit(
public function test_it_does_not_accept_invalid_count_limit(
int $countLimit,
?string $expectedExceptionMessage
): void {
Expand All @@ -383,16 +413,21 @@ public function test_it_does_not_accept_invalid_limit(
}
}

public static function limitProvider(): iterable
public static function countLimitProvider(): iterable
{
yield 'below limit' => [
-2,
'The count limit must be a positive integer. Got "-2".',
null,
];

yield 'within the limit (lower)' => [
-1,
null,
];

yield 'invalid limit' => [
0,
'The count limit must be a positive integer. Got "0".',
'The count limit must be a non zero integer. Got "0".',
];

yield 'within the limit (upper)' => [
Expand Down