mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
* zend_compile: Rename `string_placeholder_count` to `placeholder_count` in `zend_compile_func_sprintf()`
This is intended to make the diff of a follow-up commit smaller.
* zend_compile: Add support for `%d` to `sprintf()` optimization
This extends the existing `sprintf()` optimization by support for the `%d`
placeholder, which effectively equivalent to an `(int)` cast followed by a
`(string)` cast.
For a synthetic test using:
<?php
$a = 'foo';
$b = 42;
for ($i = 0; $i < 100_000_000; $i++) {
sprintf("%s-%d", $a, $b);
}
This optimization yields a 1.3× performance improvement:
$ hyperfine 'sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php' \
'/tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php'
Benchmark 1: sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
Time (mean ± σ): 3.296 s ± 0.094 s [User: 3.287 s, System: 0.005 s]
Range (min … max): 3.213 s … 3.527 s 10 runs
Benchmark 2: /tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
Time (mean ± σ): 4.300 s ± 0.025 s [User: 4.290 s, System: 0.007 s]
Range (min … max): 4.266 s … 4.334 s 10 runs
Summary
sapi/cli/php -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php ran
1.30 ± 0.04 times faster than /tmp/unoptimized -d zend_extension=php-src/modules/opcache.so -d opcache.enable_cli=1 test.php
* Fix sprintf_rope_optimization_003.phpt test expecation for 32-bit integers
* zend_compile: Indent switch-case labels in zend_compile_func_sprintf()
* Add GMP test to sprintf() rope optimization
* Add `%s` test case to sprintf() GMP test
135 lines
2.9 KiB
PHP
135 lines
2.9 KiB
PHP
--TEST--
|
|
Test sprintf() function : Rope Optimization for '%d'.
|
|
--FILE--
|
|
<?php
|
|
function func($num) {
|
|
return $num + 1;
|
|
}
|
|
function sideeffect() {
|
|
echo "Called!\n";
|
|
return "foo";
|
|
}
|
|
class Foo {
|
|
public function __construct() {
|
|
echo "Called\n";
|
|
}
|
|
}
|
|
|
|
$a = 42;
|
|
$b = -1337;
|
|
$c = 3.14;
|
|
$d = new stdClass();
|
|
|
|
try {
|
|
var_dump(sprintf("%d", $a));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d/%d", $a, $b));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d/%d/%d", $a, $b, $c));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d/%d/%d/%d", $a, $b, $c, $d));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d/", func(0)));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("/%d", func(0)));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("/%d/", func(0)));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d/%d/%d/%d", $a, $b, func(0), $a));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d/%d/%d/%d", __FILE__, __LINE__, 1, M_PI));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d/%d/%d", new Foo(), new Foo(), new Foo(), ));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf('%d/%d/%d', [], [], []));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
if (PHP_INT_SIZE == 8) {
|
|
var_dump(sprintf('%d/%d/%d', PHP_INT_MAX, 0, PHP_INT_MIN));
|
|
var_dump("2147483647/0/-2147483648");
|
|
} else {
|
|
var_dump("9223372036854775807/0/-9223372036854775808");
|
|
var_dump(sprintf('%d/%d/%d', PHP_INT_MAX, 0, PHP_INT_MIN));
|
|
}
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf('%d/%d/%d', true, false, true));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d/%d", true, 'foo'));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
try {
|
|
var_dump(sprintf("%d", 'foo'));
|
|
} catch (\Throwable $e) {echo $e, PHP_EOL; } echo PHP_EOL;
|
|
|
|
echo "Done";
|
|
?>
|
|
--EXPECTF--
|
|
string(2) "42"
|
|
|
|
string(8) "42/-1337"
|
|
|
|
string(10) "42/-1337/3"
|
|
|
|
|
|
Warning: Object of class stdClass could not be converted to int in %s on line 33
|
|
string(12) "42/-1337/3/1"
|
|
|
|
string(2) "1/"
|
|
|
|
string(2) "/1"
|
|
|
|
string(3) "/1/"
|
|
|
|
string(13) "42/-1337/1/42"
|
|
|
|
string(8) "0/53/1/3"
|
|
|
|
Called
|
|
Called
|
|
Called
|
|
|
|
Warning: Object of class Foo could not be converted to int in %s on line 57
|
|
|
|
Warning: Object of class Foo could not be converted to int in %s on line 57
|
|
|
|
Warning: Object of class Foo could not be converted to int in %s on line 57
|
|
string(5) "1/1/1"
|
|
|
|
string(5) "0/0/0"
|
|
|
|
string(42) "9223372036854775807/0/-9223372036854775808"
|
|
string(24) "2147483647/0/-2147483648"
|
|
|
|
string(5) "1/0/1"
|
|
|
|
string(3) "1/0"
|
|
|
|
string(1) "0"
|
|
|
|
Done
|