Skip to content

Instantly share code, notes, and snippets.

@erycson
Created July 30, 2026 20:59
Show Gist options
  • Select an option

  • Save erycson/b2fbfb63af2397883166a9db7a100585 to your computer and use it in GitHub Desktop.

Select an option

Save erycson/b2fbfb63af2397883166a9db7a100585 to your computer and use it in GitHub Desktop.
Rype 01 - Resutlados
<?php
$a = [0.0, 0.0, 0.0, 0.0, 0.0];
for ($i = 0; $i < 5000000; $i++) { $a[0] += 1.0; $a[1] += 1.0; $a[2] += 1.0; $a[3] += 1.0; $a[4] += 1.0; }
echo $a[0], "\n";
<?php
// `foreach` por referência sobre array, sem alvo de chave. Gate do caminho
// rápido que não lê o valor da entrada — o braço de referência o descarta — e
// que, quando a entrada já é célula de referência, deixa de resolvê-la à toa.
$a = [1.0, 2.0, 3.0, 4.0, 5.0];
for ($i = 0; $i < 1000000; $i++) {
foreach ($a as &$v) { $v = $v + 1.0; }
unset($v);
}
echo $a[0], " ", $a[4], "\n";
<?php
// Chamada de builtin num laço: mede o overhead do seam nativo, não o corpo do
// builtin. `sqrt` e `abs` são de um argumento, por valor — o formato que a
// esmagadora maioria do catálogo tem e que o caminho rápido cobre.
$s = 0.0;
for ($i = 0; $i < 3000000; $i++) {
$s += sqrt(2.0) + abs(-1.5);
}
echo $s, "\n";
<?php
$s = 0;
for ($i = 0; $i < 5000000; $i++) {
$s += $i;
}
echo $s;
<?php
/* The Computer Language Benchmarks Game
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
contributed by anon
modified by Sergey Khripunov
*/
function energy(&$b) {
$e = 0.0;
for ($i=0,$m=sizeof($b);$i<$m;$i++) {
$b1=$b[$i];
$e += 0.5*$b1[6]*($b1[3]*$b1[3]+$b1[4]*$b1[4]+$b1[5]*$b1[5]);
for ($j=$i+1; $j<$m; $j++) {
$b2=$b[$j];
$dx=$b1[0]-$b2[0]; $dy=$b1[1]-$b2[1]; $dz=$b1[2]-$b2[2];
$e -= ($b1[6]*$b2[6])/sqrt($dx*$dx + $dy*$dy + $dz*$dz);
}
}
return $e;
}
$pi=3.141592653589793;
$solar_mass=4*$pi*$pi;
$days_per_year=365.24;
$bodies = array(array(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, $solar_mass),
array(4.84143144246472090E+00,
-1.16032004402742839E+00,
-1.03622044471123109E-01,
1.66007664274403694E-03 * $days_per_year,
7.69901118419740425E-03 * $days_per_year,
-6.90460016972063023E-05 * $days_per_year,
9.54791938424326609E-04 * $solar_mass),
array(8.34336671824457987E+00,
4.12479856412430479E+00,
-4.03523417114321381E-01,
-2.76742510726862411E-03 * $days_per_year,
4.99852801234917238E-03 * $days_per_year,
2.30417297573763929E-05 * $days_per_year,
2.85885980666130812E-04 * $solar_mass),
array(1.28943695621391310E+01,
-1.51111514016986312E+01,
-2.23307578892655734E-01,
2.96460137564761618E-03 * $days_per_year,
2.37847173959480950E-03 * $days_per_year,
-2.96589568540237556E-05 * $days_per_year,
4.36624404335156298E-05 * $solar_mass),
array(1.53796971148509165E+01,
-2.59193146099879641E+01,
1.79258772950371181E-01,
2.68067772490389322E-03 * $days_per_year,
1.62824170038242295E-03 * $days_per_year,
-9.51592254519715870E-05 * $days_per_year,
5.15138902046611451E-05 * $solar_mass));
// offset_momentum
$px=$py=$pz=0.0;
foreach ($bodies as &$e) {
$px+=$e[3]*$e[6];
$py+=$e[4]*$e[6];
$pz+=$e[5]*$e[6];
}
$bodies[0][3]=-$px/$solar_mass;
$bodies[0][4]=-$py/$solar_mass;
$bodies[0][5]=-$pz/$solar_mass;
$pairs = array();
for ($i=0,$m=count($bodies); $i<$m; $i++)
for ($j=$i+1; $j<$m; $j++)
$pairs[] = array(&$bodies[$i], &$bodies[$j]);
$n = $argv[1];
printf("%0.9f\n", energy($bodies));
$i=0;
do {
foreach ($pairs as &$p) {
$a=&$p[0]; $b=&$p[1];
$dx=$a[0]-$b[0]; $dy=$a[1]-$b[1]; $dz=$a[2]-$b[2];
$dist = sqrt($dx*$dx + $dy*$dy + $dz*$dz);
$mag = 0.01/($dist*$dist*$dist);
$mag_a = $a[6]*$mag; $mag_b = $b[6]*$mag;
$a[3]-=$dx*$mag_b; $a[4]-=$dy*$mag_b; $a[5]-=$dz*$mag_b;
$b[3]+=$dx*$mag_a; $b[4]+=$dy*$mag_a; $b[5]+=$dz*$mag_a;
}
foreach ($bodies as &$b) {
$b[0]+=0.01*$b[3]; $b[1]+=0.01*$b[4]; $b[2]+=0.01*$b[5];
}
} while(++$i<$n);
printf("%0.9f\n", energy($bodies));

Resultados crus

Tudo aqui saiu de scripts/showdown.sh (cópia em codigo/showdown.sh). Nada foi editado à mão. Cada tabela é uma execução própria do script; a máquina, a imagem e o binário foram os mesmos em todas.

Procedência

CPU        : 13th Gen Intel(R) Core(TM) i9-13900K
núcleos    : 4 (limite do container)
PHP        : 8.4.23
opcache    : 8.4.23
imagem     : debian 13.6 (php:8.4-cli + valgrind + opcache habilitado)
Rust       : rust:1-bookworm, perfil `release` (lto=thin, codegen-units=1)
voltas     : mínimo de 7 (15 no startup), braços em rodízio
data       : 2026-07-30

Portão zero. Em toda tabela abaixo, os quatro braços imprimiram bytes idênticos ao PHP 8.4 sem JIT antes de qualquer cronômetro. O script aborta sem número se algum divergir.

Convenção da razão. razão = nosso ÷ oráculo, e o oráculo é o PHP 8.4 sem JIT. Menor é melhor; 1,000× é paridade. A coluna × é a mesma conta invertida, que é como se costuma ler de fora.

Braços

braço comando
Rype /target/release/php-ng
Rype + PGO /target/pgo-use/release/php-ng
PHP 8.4 php -d opcache.enable_cli=0
PHP 8.4 + JIT php -d opcache.enable_cli=1 -d opcache.jit_buffer_size=64M -d opcache.jit=tracing

O binário de PGO foi treinado em 46 programas de benchmarks/{scalar-loop,array,call,expr-tree}/bench*.php. benchmarks/upstream/ — que é onde o nbody mora — não alimentou o perfil.


1. Startup puro (arquivo <?php vazio), mínimo de 15

motor ms razão
Rype 2,6 0,237×
Rype + PGO 2,4 0,211×
PHP 8.4 11,1 1,000×
PHP 8.4 + JIT 12,9 1,158×

Serve de constante para descontar o custo de processo das tabelas seguintes.

2. nbody_canonical.php 1000000 — o programa do Benchmarks Game

motor ms razão ×
Rype 1513,1 1,458× 0,69×
Rype + PGO 1212,9 1,169× 0,86×
PHP 8.4 1037,5 1,000× 1,00×
PHP 8.4 + JIT 527,1 0,508× 1,97×

Descontado o startup: Rype 1,471× · PGO 1,179× · JIT 0,501×. Num programa de 1,5 s o startup não explica nada.

3. scalar-loop/bench.php — laço contado, 5.000.000 de voltas

motor ms razão ×
Rype 4,1 0,142× 7,07×
Rype + PGO 3,6 0,125× 8,02×
PHP 8.4 28,8 1,000× 1,00×
PHP 8.4 + JIT 18,5 0,641× 1,56×

Aqui o startup domina o número absoluto e desfavorece o Rype na leitura crua. Descontado, a execução pura é 1,5 ms contra 17,7 ms — 0,085×, ou 11,8× mais rápido. É o único lugar deste documento em que o desconto muda a conclusão, e por isso está declarado.

4. array/bench_awrite.php — escrita de elemento, 5.000.000 × 5

motor ms razão ×
Rype 65,5 0,647× 1,55×
Rype + PGO 64,1 0,634× 1,58×
PHP 8.4 101,2 1,000× 1,00×
PHP 8.4 + JIT 34,0 0,336× 2,98×

5. array/bench_awriteref.php — escrita através de referência

motor ms razão ×
Rype 76,8 0,717× 1,39×
Rype + PGO 81,1 0,758× 1,32×
PHP 8.4 107,1 1,000× 1,00×
PHP 8.4 + JIT 39,0 0,364× 2,75×

6. array/bench_arrayref.php — ligação de referência a elemento

motor ms razão ×
Rype 37,1 0,753× 1,33×
Rype + PGO 50,5 1,026× 0,97×
PHP 8.4 49,2 1,000× 1,00×
PHP 8.4 + JIT 36,6 0,744× 1,34×

O PGO piorou este. 0,753× → 1,026×. PGO não é ganho garantido: é ajuste de layout e previsão de desvio, e o perfil que ajuda um caminho pode deslocar outro. Fica registrado porque é justamente o tipo de número que some quando só se publica a média.

7. call/bench_native.php — chamada de builtin, 3.000.000 de voltas

motor ms razão ×
Rype 84,8 1,846× 0,54×
Rype + PGO 51,1 1,111× 0,90×
PHP 8.4 45,9 1,000× 1,00×
PHP 8.4 + JIT 18,7 0,408× 2,45×

8. array/bench_foreachref.phpforeach por referência, 1.000.000 × 5

motor ms razão ×
Rype 146,0 2,027× 0,49×
Rype + PGO 98,4 1,367× 0,73×
PHP 8.4 72,0 1,000× 1,00×
PHP 8.4 + JIT 61,6 0,855× 1,17×

Quadro consolidado

Ordenado da melhor razão para a pior. É a tabela que importa, e a única que não mente por seleção.

régua Rype Rype + PGO PHP 8.4 PHP + JIT
scalar-loop/bench 0,142× 0,125× 1,000× 0,641×
startup (vazio) 0,237× 0,211× 1,000× 1,158×
bench_awrite 0,647× 0,634× 1,000× 0,336×
bench_awriteref 0,717× 0,758× 1,000× 0,364×
bench_arrayref 0,753× 1,026× 1,000× 0,744×
bench_native 1,846× 1,111× 1,000× 0,408×
bench_foreachref 2,027× 1,367× 1,000× 0,855×
nbody_canonical 1,458× 1,169× 1,000× 0,508×

O que estas medições não dizem

  • Nada sobre PHP de aplicação. Nenhum destes programas usa classe, string, exceção, closure, autoload, I/O ou banco. Uma requisição de WordPress ou Laravel não se parece com nenhuma linha aqui.
  • Nada sobre outra CPU. O container fixa PHP, glibc, rustc e flags. Não fixa hardware. A razão transfere razoavelmente; o ms absoluto não transfere.
  • Nada sobre throughput multi-thread. Um processo por vez, quatro núcleos disponíveis, nenhum deles usado em paralelo por ninguém.
  • Nada sobre memória. Não foi medida.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment