Skip to content

Commit

Permalink
Improve the CPU core count detection
Browse files Browse the repository at this point in the history
See theofidry/cpu-core-counter#11 for the motivations.

The code should be sensibly the same, the notable differences are:

- fixed the deprecated usage of `hw.ncpu`
- /proc/cpuinfo is check _last_
- nproc is checked first (before was not checked at all, it's considered to be more accurate and less convoluted than cpuinfo though)
- not sure about the `return 2`, but this was not too clear [here](phpstan#514 (review)) neither. I could otherwise change the fallback value to return `1` if `proc_open` doesn't exist and 2 otherwise
- add more ways to find the CPU cores count
  • Loading branch information
theofidry committed Dec 8, 2022
1 parent 66dc2ad commit 6f0998a
Show file tree
Hide file tree
Showing 34 changed files with 1,375 additions and 119 deletions.
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -10,6 +10,7 @@
"clue/ndjson-react": "^1.0",
"composer/ca-bundle": "^1.2",
"composer/xdebug-handler": "^3.0.3",
"fidry/cpu-core-counter": "^0.3.0",
"hoa/compiler": "3.17.08.08",
"hoa/exception": "^1.0",
"hoa/regex": "1.17.01.13",
Expand All @@ -24,7 +25,7 @@
"ondram/ci-detector": "^3.4.0",
"ondrejmirtes/better-reflection": "6.4.0",
"phpstan/php-8-stubs": "0.3.52",
"phpstan/phpdoc-parser": "1.14.0",
"phpstan/phpdoc-parser": "1.15.0",
"react/async": "^3",
"react/child-process": "^0.6.4",
"react/event-loop": "^1.2",
Expand Down
75 changes: 68 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions conf/bleedingEdge.neon
Expand Up @@ -24,3 +24,4 @@ parameters:
nullContextForVoidReturningFunctions: true
unescapeStrings: true
duplicateStubs: true
invarianceComposition: true
4 changes: 4 additions & 0 deletions conf/config.neon
Expand Up @@ -54,6 +54,7 @@ parameters:
nullContextForVoidReturningFunctions: false
unescapeStrings: false
duplicateStubs: false
invarianceComposition: false
fileExtensions:
- php
checkAdvancedIsset: false
Expand Down Expand Up @@ -86,6 +87,7 @@ parameters:
checkTooWideReturnTypesInProtectedAndPublicMethods: false
checkUninitializedProperties: false
checkDynamicProperties: false
deprecationRulesInstalled: false
inferPrivatePropertyTypeFromConstructor: false
reportMaybes: false
reportMaybesInMethodSignatures: false
Expand Down Expand Up @@ -271,6 +273,7 @@ parametersSchema:
nullContextForVoidReturningFunctions: bool()
unescapeStrings: bool()
duplicateStubs: bool()
invarianceComposition: bool()
])
fileExtensions: listOf(string())
checkAdvancedIsset: bool()
Expand Down Expand Up @@ -303,6 +306,7 @@ parametersSchema:
checkTooWideReturnTypesInProtectedAndPublicMethods: bool()
checkUninitializedProperties: bool()
checkDynamicProperties: bool()
deprecationRulesInstalled: bool()
inferPrivatePropertyTypeFromConstructor: bool()

tipsOfTheDay: bool()
Expand Down
18 changes: 11 additions & 7 deletions src/Analyser/MutatingScope.php
Expand Up @@ -119,7 +119,6 @@
use function array_map;
use function array_merge;
use function array_pop;
use function array_reverse;
use function array_slice;
use function count;
use function explode;
Expand Down Expand Up @@ -3731,24 +3730,29 @@ public function filterBySpecifiedTypes(SpecifiedTypes $specifiedTypes): self
} else {
$scope = $scope->removeTypeFromExpression($expr, $type);
}
$specifiedExpressions[$this->getNodeKey($expr)] = $scope->getType($expr);
$specifiedExpressions[$this->getNodeKey($expr)] = ExpressionTypeHolder::createYes($expr, $scope->getType($expr));
}

foreach ($scope->conditionalExpressions as $conditionalExprString => $conditionalExpressions) {
foreach (array_reverse($conditionalExpressions) as $conditionalExpression) {
foreach ($conditionalExpressions as $conditionalExpression) {
foreach ($conditionalExpression->getConditionExpressionTypeHolders() as $holderExprString => $conditionalTypeHolder) {
if (!array_key_exists($holderExprString, $specifiedExpressions) || !$specifiedExpressions[$holderExprString]->equals($conditionalTypeHolder->getType())) {
if (!array_key_exists($holderExprString, $specifiedExpressions) || !$specifiedExpressions[$holderExprString]->equals($conditionalTypeHolder)) {
continue 2;
}
}

if ($conditionalExpression->getTypeHolder()->getCertainty()->no()) {
unset($scope->expressionTypes[$conditionalExprString]);
} else {
$scope->expressionTypes[$conditionalExprString] = $conditionalExpression->getTypeHolder();
$specifiedExpressions[$conditionalExprString] = $conditionalExpression->getTypeHolder()->getType();
$scope->expressionTypes[$conditionalExprString] = array_key_exists($conditionalExprString, $scope->expressionTypes)
? new ExpressionTypeHolder(
$scope->expressionTypes[$conditionalExprString]->getExpr(),
TypeCombinator::intersect($scope->expressionTypes[$conditionalExprString]->getType(), $conditionalExpression->getTypeHolder()->getType()),
TrinaryLogic::maxMin($scope->expressionTypes[$conditionalExprString]->getCertainty(), $conditionalExpression->getTypeHolder()->getCertainty()),
)
: $conditionalExpression->getTypeHolder();
$specifiedExpressions[$conditionalExprString] = $conditionalExpression->getTypeHolder();
}
continue 2;
}
}

Expand Down
14 changes: 8 additions & 6 deletions src/Analyser/NodeScopeResolver.php
Expand Up @@ -818,11 +818,11 @@ private function processStmtNode(
$inForeachScope = $this->processVarAnnotation($scope, [$stmt->expr->name], $stmt);
}
$nodeCallback(new InForeachNode($stmt), $inForeachScope);
$bodyScope = $this->enterForeach($scope->filterByTruthyValue($arrayComparisonExpr), $stmt);
$bodyScope = $this->polluteScopeWithAlwaysIterableForeach ? $this->enterForeach($scope->filterByTruthyValue($arrayComparisonExpr), $stmt) : $this->enterForeach($scope, $stmt);
$count = 0;
do {
$prevScope = $bodyScope;
$bodyScope = $bodyScope->mergeWith($scope->filterByTruthyValue($arrayComparisonExpr));
$bodyScope = $bodyScope->mergeWith($this->polluteScopeWithAlwaysIterableForeach ? $scope->filterByTruthyValue($arrayComparisonExpr) : $scope);
$bodyScope = $this->enterForeach($bodyScope, $stmt);
$bodyScopeResult = $this->processStmtNodes($stmt, $stmt->stmts, $bodyScope, static function (): void {
})->filterOutLoopExitPoints();
Expand All @@ -841,7 +841,7 @@ private function processStmtNode(
$count++;
} while (!$alwaysTerminating && $count < self::LOOP_SCOPE_ITERATIONS);

$bodyScope = $bodyScope->mergeWith($scope->filterByTruthyValue($arrayComparisonExpr));
$bodyScope = $bodyScope->mergeWith($this->polluteScopeWithAlwaysIterableForeach ? $scope->filterByTruthyValue($arrayComparisonExpr) : $scope);
$bodyScope = $this->enterForeach($bodyScope, $stmt);
$finalScopeResult = $this->processStmtNodes($stmt, $stmt->stmts, $bodyScope, $nodeCallback)->filterOutLoopExitPoints();
$finalScope = $finalScopeResult->getScope();
Expand Down Expand Up @@ -3992,16 +3992,18 @@ static function (): void {
}
}

$constantArrays = $iterateeType->getConstantArrays();
if (
$stmt->getDocComment() === null
&& $iterateeType instanceof ConstantArrayType
&& $iterateeType->isConstantArray()->yes()
&& count($constantArrays) === 1
&& $stmt->valueVar instanceof Variable && is_string($stmt->valueVar->name)
&& $stmt->keyVar instanceof Variable && is_string($stmt->keyVar->name)
) {
$valueConditionalHolders = [];
$arrayDimFetchConditionalHolders = [];
foreach ($iterateeType->getKeyTypes() as $i => $keyType) {
$valueType = $iterateeType->getValueTypes()[$i];
foreach ($constantArrays[0]->getKeyTypes() as $i => $keyType) {
$valueType = $constantArrays[0]->getValueTypes()[$i];
$holder = new ConditionalExpressionHolder([
'$' . $stmt->keyVar->name => ExpressionTypeHolder::createYes(new Variable($stmt->keyVar->name), $keyType),
], new ExpressionTypeHolder($stmt->valueVar, $valueType, TrinaryLogic::createYes()));
Expand Down
2 changes: 2 additions & 0 deletions src/DependencyInjection/ContainerFactory.php
Expand Up @@ -21,6 +21,7 @@
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Reflection\ReflectionProviderStaticAccessor;
use PHPStan\Type\Accessory\AccessoryArrayListType;
use PHPStan\Type\Generic\TemplateTypeVariance;
use Symfony\Component\Finder\Finder;
use function array_diff_key;
use function array_map;
Expand Down Expand Up @@ -174,6 +175,7 @@ public static function postInitializeContainer(Container $container): void

BleedingEdgeToggle::setBleedingEdge($container->getParameter('featureToggles')['bleedingEdge']);
AccessoryArrayListType::setListTypeEnabled($container->getParameter('featureToggles')['listType']);
TemplateTypeVariance::setInvarianceCompositionEnabled($container->getParameter('featureToggles')['invarianceComposition']);
}

public function clearOldContainers(string $tempDirectory): void
Expand Down
3 changes: 2 additions & 1 deletion src/File/FuzzyRelativePathHelper.php
Expand Up @@ -70,8 +70,9 @@ public function __construct(
/** @var string[] $pathArray */
$pathArray = explode($directorySeparator, $path);
$pathTempParts = [];
$pathArraySize = count($pathArray);
foreach ($pathArray as $i => $pathPart) {
if (str_ends_with($pathPart, '.php')) {
if ($i === $pathArraySize - 1 && str_ends_with($pathPart, '.php')) {
continue;
}
if (!isset($pathToTrimArray[$i])) {
Expand Down
2 changes: 2 additions & 0 deletions src/PhpDoc/PhpDocNodeResolver.php
Expand Up @@ -264,6 +264,8 @@ public function resolveTemplateTags(PhpDocNode $phpDocNode, NameScope $nameScope
$variance = TemplateTypeVariance::createInvariant();
} elseif (in_array($tagName, ['@template-covariant', '@psalm-template-covariant', '@phpstan-template-covariant'], true)) {
$variance = TemplateTypeVariance::createCovariant();
} elseif (in_array($tagName, ['@template-contravariant', '@psalm-template-contravariant', '@phpstan-template-contravariant'], true)) {
$variance = TemplateTypeVariance::createContravariant();
} else {
continue;
}
Expand Down
51 changes: 6 additions & 45 deletions src/Process/CpuCoreCounter.php
Expand Up @@ -2,16 +2,8 @@

namespace PHPStan\Process;

use function count;
use function fgets;
use function file_get_contents;
use function function_exists;
use function is_file;
use function is_resource;
use function pclose;
use function popen;
use function preg_match_all;
use const DIRECTORY_SEPARATOR;
use Fidry\CpuCoreCounter\CpuCoreCounter as FidryCpuCoreCounter;
use Fidry\CpuCoreCounter\NumberOfCpuCoreNotFound;

class CpuCoreCounter
{
Expand All @@ -24,42 +16,11 @@ public function getNumberOfCpuCores(): int
return $this->count;
}

if (!function_exists('proc_open')) {
return $this->count = 1;
try {
return (new FidryCpuCoreCounter())->getCount();
} catch (NumberOfCpuCoreNotFound) {
return 1;
}

// from brianium/paratest
if (@is_file('/proc/cpuinfo')) {
// Linux (and potentially Windows with linux sub systems)
$cpuinfo = @file_get_contents('/proc/cpuinfo');
if ($cpuinfo !== false) {
preg_match_all('/^processor/m', $cpuinfo, $matches);
return $this->count = count($matches[0]);
}
}

if (DIRECTORY_SEPARATOR === '\\') {
// Windows
$process = @popen('wmic cpu get NumberOfLogicalProcessors', 'rb');
if (is_resource($process)) {
fgets($process);
$cores = (int) fgets($process);
pclose($process);

return $this->count = $cores;
}
}

$process = @popen('sysctl -n hw.ncpu', 'rb');
if (is_resource($process)) {
// *nix (Linux, BSD and Mac)
$cores = (int) fgets($process);
pclose($process);

return $this->count = $cores;
}

return $this->count = 2;
}

}
1 change: 1 addition & 0 deletions src/Rules/Generics/FunctionSignatureVarianceRule.php
Expand Up @@ -40,6 +40,7 @@ public function processNode(Node $node, Scope $scope): array
sprintf('in return type of function %s()', $functionName),
sprintf('in function %s()', $functionName),
false,
false,
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Generics/GenericAncestorsCheck.php
Expand Up @@ -98,7 +98,7 @@ public function check(
$messages[] = RuleErrorBuilder::message(sprintf($invalidTypeMessage, $referencedClass))->build();
}

$variance = TemplateTypeVariance::createInvariant();
$variance = TemplateTypeVariance::createStatic();
$messageContext = sprintf(
$invalidVarianceMessage,
$ancestorType->describe(VerbosityLevel::typeOnly()),
Expand Down
1 change: 1 addition & 0 deletions src/Rules/Generics/MethodSignatureVarianceRule.php
Expand Up @@ -39,6 +39,7 @@ public function processNode(Node $node, Scope $scope): array
sprintf('in return type of method %s::%s()', $method->getDeclaringClass()->getDisplayName(), $method->getName()),
sprintf('in method %s::%s()', $method->getDeclaringClass()->getDisplayName(), $method->getName()),
$method->getName() === '__construct' || $method->isStatic(),
$method->isPrivate(),
);
}

Expand Down

0 comments on commit 6f0998a

Please sign in to comment.