Skip to content
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
14 changes: 7 additions & 7 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,16 @@ For **001-SimpleWeb**, `bin/compile.php` is timed **without** compile-time `-q`;

For **003-MiniWebApp**, VM/JIT/native columns run `public/index.php` with `PATH_INFO=/home` (and related CGI env) from the example `public/` directory ([#491](https://github.com/PurHur/php-compiler/issues/491), runtime [#539](https://github.com/PurHur/php-compiler/issues/539)). AOT columns time `phpc build --project` and `.phpc/bin/app` with the same CGI overlay when LLVM is ready and execute returns HTML ([#716](https://github.com/PurHur/php-compiler/issues/716); execute [#764](https://github.com/PurHur/php-compiler/issues/764) closed). The row is omitted when `phpc lint --all examples/003-MiniWebApp` fails unless `BENCH_MINIWEBAPP=1`.

For **005-SessionsWeb**, the benchmark row is omitted until `phpc lint --all examples/005-SessionsWeb` passes unless `BENCH_SESSIONSWEB=1` ([#1889](https://github.com/PurHur/php-compiler/issues/1889)). AOT columns stay `n/a` until two-request session execute is green ([#1891](https://github.com/PurHur/php-compiler/issues/1891)).
For **005-SessionsWeb**, the benchmark row is omitted until `phpc lint --all examples/005-SessionsWeb` passes unless `BENCH_SESSIONSWEB=1` ([#1889](https://github.com/PurHur/php-compiler/issues/1889)). AOT columns time `phpc build --project` and a two-request session flash on `.phpc/bin/app` when LLVM is ready ([#1891](https://github.com/PurHur/php-compiler/issues/1891), [#1973](https://github.com/PurHur/php-compiler/issues/1973)); use `BENCH_SESSIONSWEB_AOT=1 ./script/rebuild-examples.php` to force AOT columns on harness regen.

<!-- benchmark table start -->

| Example Name | Native PHP | bin/vm.php | bin/jit.php | bin/compile.php | ./compiled |
|----------------------|-----------------|-----------------|-----------------|-----------------|-----------------|
| 000-HelloWorld | 0.00760 | 0.04387 | 0.17749 | 1.33163 | 0.00109 |
| 001-SimpleWeb | 0.00764 | 0.04682 | 0.18321 | 1.34592 | 0.00109 |
| 002-StaticWeb | 0.00770 | 0.04771 | 0.17846 | 1.35182 | 0.00111 |
| 003-MiniWebApp | 0.00838 | 0.08591 | 0.45166 | 1.75921 | 0.00098 |
| 004-ApiJson | 0.00837 | 0.04503 | 0.17964 | 1.36437 | 0.00128 |
| 005-SessionsWeb | 0.00855 | 0.04840 | 0.19095 | n/a | n/a |
| 000-HelloWorld | 0.00792 | 0.04623 | 0.20762 | 1.87538 | 0.00156 |
| 001-SimpleWeb | 0.00895 | 0.04740 | 0.18640 | 1.35069 | 0.00118 |
| 002-StaticWeb | 0.00980 | 0.05066 | 0.18906 | 1.36219 | 0.00123 |
| 003-MiniWebApp | 0.00771 | 0.09690 | 0.52931 | 1.83640 | 0.00106 |
| 004-ApiJson | 0.00850 | 0.04705 | 0.19092 | 2.98758 | 0.00116 |
| 005-SessionsWeb | 0.01742 | 0.05082 | 0.19587 | 1.43149 | 0.00277 |
<!-- benchmark table end -->
196 changes: 188 additions & 8 deletions script/check-rebuild-examples-005-row.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
* Benchmark row policy matches script/rebuild-examples.php (issue #1889):
* - Include when BENCH_SESSIONSWEB=1 or phpc lint --all examples/005-SessionsWeb passes
* - Omit when lint fails unless BENCH_SESSIONSWEB=1
* - AOT columns: n/a when LLVM/execute probe fails; real timings when probe passes (#1891, #1973)
*
* Usage:
* php script/check-rebuild-examples-005-row.php
*/

require_once __DIR__.'/../test/support/CgiCookieJar.php';
require_once __DIR__.'/../test/support/SessionsWebCgiEnv.php';

$root = dirname(__DIR__);
$readme = $root.'/examples/README.md';
$exampleDir = $root.'/examples/005-SessionsWeb';
Expand Down Expand Up @@ -49,8 +53,8 @@

if ($hasRow) {
$rowLine = extract_sessions_web_benchmark_line($body);
if (null !== $rowLine && !benchmark_row_aot_columns_honest($rowLine)) {
$errors[] = 'examples/README.md: 005-SessionsWeb benchmark row must keep bin/compile.php and ./compiled as n/a until AOT execute is green (#1891)';
if (null !== $rowLine && !benchmark_row_aot_columns_honest($rowLine, $root)) {
$errors[] = 'examples/README.md: 005-SessionsWeb benchmark AOT columns out of sync (run: BENCH_SESSIONSWEB=1 BENCH_SESSIONSWEB_AOT=1 ./script/rebuild-examples.php; #1973)';
}
}

Expand Down Expand Up @@ -127,19 +131,195 @@ function extract_sessions_web_benchmark_line(string $readmeBody): ?string
return trim($line[0]);
}

function benchmark_row_aot_columns_honest(string $rowLine): bool
function benchmark_row_aot_columns_honest(string $rowLine, string $repoRoot): bool
{
if ('1' === getenv('BENCH_SESSIONSWEB_AOT')) {
return true;
}

$parts = array_map('trim', explode('|', $rowLine));
$parts = array_values(array_filter($parts, static fn (string $p): bool => '' !== $p));
if (count($parts) < 6) {
return true;
}
$compileCol = $parts[4] ?? '';
$compiledCol = $parts[5] ?? '';
$compileNa = (bool) preg_match('/n\/a/i', $compileCol);
$compiledNa = (bool) preg_match('/n\/a/i', $compiledCol);

if (!llvm_ready_for_check($repoRoot)) {
return true;
}

if ('1' === getenv('BENCH_SESSIONSWEB_AOT')) {
return !$compileNa && !$compiledNa;
}

if (sessions_web_aot_execute_probe($repoRoot)) {
return !$compileNa && !$compiledNa;
}

return $compileNa && $compiledNa;
}

function llvm_ready_for_check(string $repoRoot): bool
{
$candidates = [];
$fromEnv = getenv('PHP_COMPILER_LLVM_PATH');
if (false !== $fromEnv && '' !== $fromEnv) {
$candidates[] = $fromEnv;
}
$candidates[] = $repoRoot.'/.llvm';
$candidates[] = '/opt/llvm9';
foreach ($candidates as $dir) {
if (is_file($dir.'/libLLVM-9.so.1')) {
return true;
}
}

return false;
}

function sessions_web_aot_execute_probe(string $repoRoot): bool
{
if ('0' === getenv('SESSIONS_WEB_AOT_PROBE')) {
return false;
}
if (!llvm_ready_for_check($repoRoot)) {
return false;
}
$phpc = $repoRoot.'/phpc';
$project = $repoRoot.'/examples/005-SessionsWeb';
$binary = $project.'/.phpc/bin/app';
if (!is_executable($phpc) || !is_file($project.'/example.php')) {
return false;
}

$sessionDir = sys_get_temp_dir().'/phpc_check_sessionsweb_'.uniqid('', true);
if (!@mkdir($sessionDir, 0700, true) && !is_dir($sessionDir)) {
return false;
}

$env = [];
foreach ($_ENV as $key => $value) {
if (is_string($value)) {
$env[$key] = $value;
}
}
$llvmDir = null;
foreach ([getenv('PHP_COMPILER_LLVM_PATH') ?: '', $repoRoot.'/.llvm', '/opt/llvm9'] as $dir) {
if ('' !== $dir && is_file($dir.'/libLLVM-9.so.1')) {
$llvmDir = realpath($dir) ?: $dir;
break;
}
}
if (null !== $llvmDir) {
$env['PHP_COMPILER_LLVM_PATH'] = $llvmDir;
$ld = $env['LD_LIBRARY_PATH'] ?? '';
$env['LD_LIBRARY_PATH'] = '' === $ld ? $llvmDir : $llvmDir.':'.$ld;
}
$env['PHP_COMPILER_SESSION_DIR'] = $sessionDir;

if (!is_executable($binary)) {
$build = proc_open(
[$phpc, 'build', '--project', $project],
[0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
$pipes,
$repoRoot,
$env
);
if (!is_resource($build)) {
check_sessions_web_cleanup($sessionDir);

return false;
}
fclose($pipes[0]);
stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
if (0 !== proc_close($build)) {
check_sessions_web_cleanup($sessionDir);

return false;
}
}

if (!is_executable($binary)) {
check_sessions_web_cleanup($sessionDir);

return preg_match('/n\/a/i', $compileCol) && preg_match('/n\/a/i', $compiledCol);
return false;
}

$ok = check_sessions_web_flash_probe($repoRoot, $binary, $env);
check_sessions_web_cleanup($sessionDir);

return $ok;
}

/**
* @param array<string, string> $baseEnv
*/
function check_sessions_web_flash_probe(string $repoRoot, string $binary, array $baseEnv): bool
{
$jar = new PHPCompiler\CgiCookieJar();
$empty = check_run_binary($repoRoot, $binary, array_merge($baseEnv, PHPCompiler\SessionsWebCgiEnv::getEmpty()));
if (null === $empty) {
return false;
}
$jar->absorbFromCgiOutput($empty);
if (!$jar->hasCookie('PHPSESSID')) {
return false;
}
$cookie = $jar->httpCookieHeader();
if (null === check_run_binary(
$repoRoot,
$binary,
array_merge($baseEnv, PHPCompiler\SessionsWebCgiEnv::postFlash('Saved'), ['HTTP_COOKIE' => $cookie])
)) {
return false;
}
$flash = check_run_binary(
$repoRoot,
$binary,
array_merge($baseEnv, PHPCompiler\SessionsWebCgiEnv::getEmpty(), ['HTTP_COOKIE' => $jar->httpCookieHeader()])
);
if (null === $flash) {
return false;
}

return str_contains($flash, 'Flash: Saved');
}

/**
* @param array<string, string> $env
*/
function check_run_binary(string $repoRoot, string $binary, array $env): ?string
{
$proc = proc_open(
[$binary],
[0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
$pipes,
$repoRoot,
$env
);
if (!is_resource($proc)) {
return null;
}
fclose($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
if (0 !== proc_close($proc)) {
return null;
}

return false !== $stdout ? $stdout : '';
}

function check_sessions_web_cleanup(string $sessionDir): void
{
if (!is_dir($sessionDir)) {
return;
}
foreach (glob($sessionDir.'/sess_*') ?: [] as $file) {
@unlink($file);
}
@rmdir($sessionDir);
}
Loading