Skip to content

Commit 3272a14

Browse files
committed
Parallelize new_oom subprocesses
1 parent 61a190c commit 3272a14

1 file changed

Lines changed: 94 additions & 6 deletions

File tree

Zend/tests/new_oom.phpt

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
Test OOM on new of each class
2+
Test OOM on new of each instantiable class
33
--SKIPIF--
44
<?php
55
if (getenv("USE_ZEND_ALLOC") === "0") die("skip requires zmm");
@@ -8,14 +8,102 @@ if (getenv("SKIP_SLOW_TESTS")) die('skip slow test');
88
--FILE--
99
<?php
1010

11+
function getOomProcessCount(): int
12+
{
13+
$processCount = PHP_OS_FAMILY === 'Windows'
14+
? getenv('NUMBER_OF_PROCESSORS')
15+
: shell_exec('getconf _NPROCESSORS_ONLN 2>/dev/null');
16+
if (!is_string($processCount)) {
17+
return 1;
18+
}
19+
20+
$processCount = filter_var(trim($processCount), FILTER_VALIDATE_INT, [
21+
'options' => ['min_range' => 1],
22+
]);
23+
24+
return $processCount === false ? 1 : min($processCount, 4);
25+
}
26+
27+
function startOomTest(string $php, string $file, string $class): ?array
28+
{
29+
$output = tmpfile();
30+
if ($output === false) {
31+
echo "Class $class failed\nUnable to create output file\n";
32+
return null;
33+
}
34+
35+
$process = proc_open(
36+
[$php, '--no-php-ini', $file, $class],
37+
[
38+
0 => ['null'],
39+
1 => $output,
40+
2 => ['redirect', 1],
41+
],
42+
$pipes,
43+
);
44+
if (!is_resource($process)) {
45+
fclose($output);
46+
echo "Class $class failed\nUnable to start process\n";
47+
return null;
48+
}
49+
50+
return [
51+
'class' => $class,
52+
'output' => $output,
53+
'process' => $process,
54+
];
55+
}
56+
57+
function finishOomTest(array $test): bool
58+
{
59+
$status = proc_get_status($test['process']);
60+
if ($status['running']) {
61+
return false;
62+
}
63+
64+
proc_close($test['process']);
65+
rewind($test['output']);
66+
$output = stream_get_contents($test['output']);
67+
fclose($test['output']);
68+
69+
if ($status['signaled']) {
70+
echo "Class {$test['class']} failed\n";
71+
echo "Process terminated by signal {$status['termsig']}\n";
72+
} elseif ($output && preg_match('(^\nFatal error: Allowed memory size of [0-9]+ bytes exhausted[^\r\n]* \(tried to allocate [0-9]+ bytes\) in [^\r\n]+ on line [0-9]+\nStack trace:\n(#[0-9]+ [^\r\n]+\n)+$)', $output) !== 1) {
73+
echo "Class {$test['class']} failed\n";
74+
echo $output, "\n";
75+
}
76+
77+
return true;
78+
}
79+
1180
$file = __DIR__ . '/new_oom.inc';
1281
$php = PHP_BINARY;
82+
$classes = array_filter(
83+
get_declared_classes(),
84+
static fn(string $class): bool => (new ReflectionClass($class))->isInstantiable(),
85+
);
86+
$tests = [];
87+
$processCount = getOomProcessCount();
1388

14-
foreach (get_declared_classes() as $class) {
15-
$output = shell_exec("$php --no-php-ini $file $class 2>&1");
16-
if ($output && preg_match('(^\nFatal error: Allowed memory size of [0-9]+ bytes exhausted[^\r\n]* \(tried to allocate [0-9]+ bytes\) in [^\r\n]+ on line [0-9]+\nStack trace:\n(#[0-9]+ [^\r\n]+\n)+$)', $output) !== 1) {
17-
echo "Class $class failed\n";
18-
echo $output, "\n";
89+
while ($classes || $tests) {
90+
while ($classes && count($tests) < $processCount) {
91+
$class = array_shift($classes);
92+
$test = startOomTest($php, $file, $class);
93+
if ($test !== null) {
94+
$tests[] = $test;
95+
}
96+
}
97+
98+
$testFinished = false;
99+
foreach ($tests as $index => $test) {
100+
if (finishOomTest($test)) {
101+
unset($tests[$index]);
102+
$testFinished = true;
103+
}
104+
}
105+
if (!$testFinished) {
106+
usleep(1000);
19107
}
20108
}
21109

0 commit comments

Comments
 (0)