Skip to content
Open
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
3 changes: 3 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ PHP 8.7 UPGRADE NOTES
target does not keep is now released at that assignment instead of after
the last one.

- Opcache:
. Improved performance of file cache checksum verification on AArch64.

- Standard:
. Improved performance of strcspn() and strpbrk() when searching longer strings
with a single-byte character mask.
Expand Down
66 changes: 66 additions & 0 deletions ext/opcache/tests/file_cache_checksum.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
--TEST--
File cache checksum is the Adler-32 of the cached script
--SKIPIF--
<?php
if (PHP_INT_SIZE != 8) die('skip 64-bit only');
@mkdir(__DIR__ . '/file_cache_checksum_cache', 0777, true);
?>
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.jit=disable
opcache.file_cache="{PWD}/file_cache_checksum_cache"
opcache.file_cache_only=1
opcache.file_update_protection=0
--EXTENSIONS--
opcache
--FILE--
<?php

/* Spans several Adler-32 blocks of 5552 bytes, with every byte value and a
* long run of 0xff, the worst case for the sums. */
$bytes = str_repeat(implode('', array_map('chr', range(0, 255))), 64) . str_repeat("\xff", 20011);
$file = __DIR__ . '/file_cache_checksum.inc';
file_put_contents($file, "<?php\nreturn '" . addcslashes($bytes, "\\'") . "';\n");
var_dump(opcache_compile_file($file));

$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(__DIR__ . '/file_cache_checksum_cache', RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $fileinfo) {
if (str_ends_with($fileinfo->getFilename(), 'file_cache_checksum.inc.bin')) {
$bin = file_get_contents($fileinfo->getPathname());
}
}

/* The header is zend_file_cache_metainfo (zend_file_cache.c): 80 bytes, with
* mem_size and str_size at offset 40 and the checksum of the rest at 72. */
['mem' => $mem, 'str' => $str] = unpack('Qmem/Qstr', $bin, 40);
var_dump(strlen($bin) === 80 + $mem + $str && $mem + $str > 3 * 5552);
var_dump(sprintf('%08x', unpack('L', $bin, 72)[1]) === hash('adler32', substr($bin, 80)));

?>
--CLEAN--
<?php
function removeDirRecursive($dir) {
if (!is_dir($dir)) return;
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $fileinfo) {
if ($fileinfo->isDir()) {
@rmdir($fileinfo->getRealPath());
} else {
@unlink($fileinfo->getRealPath());
}
}
@rmdir($dir);
}
removeDirRecursive(__DIR__ . '/file_cache_checksum_cache');
@unlink(__DIR__ . '/file_cache_checksum.inc');
?>
--EXPECT--
bool(true)
bool(true)
bool(true)
29 changes: 28 additions & 1 deletion ext/opcache/zend_accelerator_util_funcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,34 @@ static zend_always_inline void adler32_do16_loop(unsigned char *buf, const unsig
unsigned int s1 = *s1_out;
unsigned int s2 = *s2_out;

#ifdef XSSE2
#if defined(__aarch64__) || defined(_M_ARM64)
/* zend_simd.h maps the SSE2 loop below to NEON too, but its _mm_madd_epi16()
* and _mm_sad_epu8() are slow there, so use NEON directly.
* For each 16-byte block: s2 += 16 * s1 + sum((16 - i) * buf[i]), then
* s1 += sum(buf[i]). The weighted products fit in 16 bits
* (255 * 16 + 255 * 8), and all 32-bit sums wrap like the scalar code's, so
* the result is identical for any input. */
static const uint8_t weights[16] = {16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
const uint8x8_t weights_lo = vld1_u8(weights);
const uint8x8_t weights_hi = vld1_u8(weights + 8);
const unsigned int blocks = (unsigned int) ((end - buf) / 16);
uint32x4_t weighted_sum = vdupq_n_u32(0);
uint32x4_t byte_sum = vdupq_n_u32(0);
uint32x4_t byte_sum_at_block_start = vdupq_n_u32(0);

do {
const uint8x16_t read = vld1q_u8(buf);
byte_sum_at_block_start = vaddq_u32(byte_sum_at_block_start, byte_sum);
uint16x8_t products = vmull_u8(vget_low_u8(read), weights_lo);
products = vmlal_u8(products, vget_high_u8(read), weights_hi);
weighted_sum = vpadalq_u16(weighted_sum, products);
byte_sum = vpadalq_u16(byte_sum, vpaddlq_u8(read));
buf += 16;
} while (buf != end);

s2 += 16 * (blocks * s1 + vaddvq_u32(byte_sum_at_block_start)) + vaddvq_u32(weighted_sum);
s1 += vaddvq_u32(byte_sum);
#elif defined(XSSE2)
const __m128i zero = _mm_setzero_si128();

__m128i accumulate_s2 = zero;
Expand Down
Loading