Skip to content

Commit

Permalink
Allow the user to register which finders to use to the CPUCoreCounter (
Browse files Browse the repository at this point in the history
…#20)

For BC and convenience, the `CPUCoreCounter` can still be created without any finder which will use the default registered ones.

This feature will allow users to blacklist some finders, for example for Psalm which does not want to use the `WindowsWmicFinder`:

```php
$finders = array_filter(
    CpuCoreCounter::getDefaultFinders(),
    static fn (CpuCoreFinder $finder) => !($finder instanceof WindowsWmicFinder)
);

$cores = (new CpuCoreCounter($finders))->getCount();
```

Another bonus is that it helps out a lot for testing!
  • Loading branch information
theofidry authored Dec 4, 2022
1 parent 854f92d commit 6b9a0cc
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 29 deletions.
49 changes: 35 additions & 14 deletions src/CpuCoreCounter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,29 @@

final class CpuCoreCounter
{
/**
* @var list<CpuCoreFinder>
*/
private array $finders;

private int $count;

/**
* @param list<CpuCoreFinder> $finders
*/
public function __construct(?array $finders = null)
{
$this->finders = $finders ?? self::getDefaultFinders();
}

/**
* @return positive-int
*/
public function getCount(): int
{
// Memoize result
if (!isset($this->count)) {
$this->count = self::findCount();
$this->count = $this->findCount();
}

return $this->count;
Expand All @@ -36,31 +49,39 @@ public function getCount(): int
/**
* @return positive-int
*/
private static function findCount(): int
private function findCount(): int
{
if (!function_exists('proc_open')) {
return 1;
}

foreach ($this->finders as $finder) {
$cores = $finder->find();

if (null !== $cores) {
return $cores;
}
}

return 2;
}

/**
* @return list<CpuCoreFinder>
*/
public static function getDefaultFinders(): array
{
/** @var list<class-string<CpuCoreFinder>> $finders */
$finders = [
CpuInfoFinder::class,
new CpuInfoFinder(),
];

if (DIRECTORY_SEPARATOR === '\\') {
$finders[] = WindowsWmicFinder::class;
$finders[] = new WindowsWmicFinder();
}

$finders[] = HwFinder::class;

foreach ($finders as $finder) {
$cores = $finder::find();
$finders[] = new HwFinder();

if (null !== $cores) {
return $cores;
}
}

return 2;
return $finders;
}
}
2 changes: 1 addition & 1 deletion src/CpuCoreFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ interface CpuCoreFinder
/**
* @return positive-int|null
*/
public static function find(): ?int;
public function find(): ?int;
}
4 changes: 0 additions & 4 deletions src/CpuInfoFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ final class CpuInfoFinder
{
private const CPU_INFO_PATH = '/proc/cpuinfo';

private function __construct()
{
}

/**
* @return positive-int|null
*/
Expand Down
6 changes: 1 addition & 5 deletions src/HwFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,10 @@
*/
final class HwFinder implements CpuCoreFinder
{
private function __construct()
{
}

/**
* @return positive-int|null
*/
public static function find(): ?int
public function find(): ?int
{
$process = popen('sysctl -n hw.ncpu', 'rb');

Expand Down
6 changes: 1 addition & 5 deletions src/WindowsWmicFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,10 @@
*/
final class WindowsWmicFinder implements CpuCoreFinder
{
private function __construct()
{
}

/**
* @return positive-int|null
*/
public static function find(): ?int
public function find(): ?int
{
// Windows
$process = popen('wmic cpu get NumberOfLogicalProcessors', 'rb');
Expand Down
57 changes: 57 additions & 0 deletions tests/CpuCoreCounterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,61 @@ public function test_it_can_get_the_number_of_cpu_cores(): void

self::assertGreaterThan(1, $counter->getCount());
}

/**
* @dataProvider cpuCoreFinderProvider
*
* @param list<CpuCoreCounter> $finders
*/
public function test_it_can_get_the_number_of_cpu_cores_based_on_the_registered_finders(
array $finders,
int $expected
): void {
$counter = new CpuCoreCounter($finders);

$actual = $counter->getCount();

self::assertSame($expected, $actual);
}

public static function cpuCoreFinderProvider(): iterable
{
yield 'no finder' => [
[],
2,
];

yield 'single finder finds a value' => [
[
new DummyCpuCoreFinder(3),
],
3,
];

yield 'single finder does not find a value' => [
[
new DummyCpuCoreFinder(null),
],
2,
];

yield 'multiple finders find a value' => [
[
new DummyCpuCoreFinder(3),
new DummyCpuCoreFinder(7),
new DummyCpuCoreFinder(11),
],
3,
];

yield 'multiple finders find a value with some not finding any' => [
[
new DummyCpuCoreFinder(null),
new DummyCpuCoreFinder(7),
new DummyCpuCoreFinder(null),
new DummyCpuCoreFinder(11),
],
7,
];
}
}
31 changes: 31 additions & 0 deletions tests/DummyCpuCoreFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/*
* This file is part of the Fidry CPUCounter Config package.
*
* (c) Théo FIDRY <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Fidry\CpuCounter\Test;

use Fidry\CpuCounter\CpuCoreFinder;

final class DummyCpuCoreFinder implements CpuCoreFinder
{
private ?int $count;

public function __construct(?int $count)
{
$this->count = $count;
}

public function find(): ?int
{
return $this->count;
}
}

0 comments on commit 6b9a0cc

Please sign in to comment.