From a820647b099a266e4a578dbef67e50107b162f80 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Thu, 14 Mar 2024 23:01:27 +0900 Subject: perf: optimize memory allocation by FFI --- README.md | 2 +- benchmarks/20240314-2330.log | 4 + prof.sh | 4 +- src/Execution/MemInst.php | 436 ++++++++++++++++++++++++++++------------ test.sh | 2 +- traces/20240314-2332.stderr.log | 86 ++++++++ 6 files changed, 398 insertions(+), 136 deletions(-) create mode 100644 benchmarks/20240314-2330.log create mode 100644 traces/20240314-2332.stderr.log diff --git a/README.md b/README.md index d606a55..8f68eab 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This is a WebAssembly runtime written in pure PHP. The PHP runtime can be compiled to WebAssembly binary. This Wasm runtime can execute it. Currently, "Hello, World!" program works on the PHP runtime on the Wasm runtime. ``` -$ php -d zend.assertions=-1 -d memory_limit=256M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php +$ php -d zend.assertions=-1 -d memory_limit=512M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php ``` diff --git a/benchmarks/20240314-2330.log b/benchmarks/20240314-2330.log new file mode 100644 index 0000000..1292d74 --- /dev/null +++ b/benchmarks/20240314-2330.log @@ -0,0 +1,4 @@ +Benchmark 1: make run + Time (mean ± σ): 2.852 s ± 0.025 s [User: 2.765 s, System: 0.087 s] + Range (min … max): 2.821 s … 2.886 s 10 runs + diff --git a/prof.sh b/prof.sh index 9fd164a..ef9d280 100644 --- a/prof.sh +++ b/prof.sh @@ -1,5 +1,5 @@ timestamp="$(date '+%Y%m%d-%H%M')" -# php -d 'error_reporting=E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED' vendor/bin/reli inspector:trace -o traces/"$timestamp".log -- php -d memory_limit=256M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php 2> traces/"$timestamp".stderr.log +# php -d 'error_reporting=E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED' vendor/bin/reli inspector:trace -o traces/"$timestamp".log -- php -d memory_limit=512M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php 2> traces/"$timestamp".stderr.log # vendor/bin/reli converter:flamegraph < traces/"$timestamp".log > traces/"$timestamp".svg -php -d zend.assertions=-1 -d memory_limit=256M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php 2> traces/"$timestamp".stderr.log +php -d zend.assertions=-1 -d memory_limit=512M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php 2> traces/"$timestamp".stderr.log diff --git a/src/Execution/MemInst.php b/src/Execution/MemInst.php index 53414d7..21dd353 100644 --- a/src/Execution/MemInst.php +++ b/src/Execution/MemInst.php @@ -4,31 +4,165 @@ declare(strict_types=1); namespace Nsfisis\Waddiwasi\Execution; +use FFI; +use FFI\CData; use Nsfisis\Waddiwasi\Structure\Types\MemType; use function assert; -use function chr; use function count; -use function ord; -use function strlen; final class MemInst { - private string $data; - private const PAGE_SIZE = 64 * 1024; + private CData $dataU8; + private CData $dataS8; + + private CData $dataU16_0; + private CData $dataU16_1; + private CData $dataS16_0; + private CData $dataS16_1; + + private CData $dataU32_0; + private CData $dataU32_1; + private CData $dataU32_2; + private CData $dataU32_3; + private CData $dataS32_0; + private CData $dataS32_1; + private CData $dataS32_2; + private CData $dataS32_3; + + private CData $dataS64_0; + private CData $dataS64_1; + private CData $dataS64_2; + private CData $dataS64_3; + private CData $dataS64_4; + private CData $dataS64_5; + private CData $dataS64_6; + private CData $dataS64_7; + + private CData $dataF32_0; + private CData $dataF32_1; + private CData $dataF32_2; + private CData $dataF32_3; + + private CData $dataF64_0; + private CData $dataF64_1; + private CData $dataF64_2; + private CData $dataF64_3; + private CData $dataF64_4; + private CData $dataF64_5; + private CData $dataF64_6; + private CData $dataF64_7; + + private readonly int $dataSize; + + private readonly FFI $ffi; + public function __construct( public readonly MemType $type, ) { + $this->ffi = FFI::cdef(); + $minSize = $type->limits->min; // @todo hack $minSize *= 8; - $this->data = str_repeat("\0", $minSize * self::PAGE_SIZE); + $this->dataSize = $minSize * self::PAGE_SIZE; + + // @phpstan-ignore-next-line + $this->dataU8 = $this->ffi->new("uint8_t[$this->dataSize+8]"); + // @phpstan-ignore-next-line + $this->dataS8 = $this->ffi->cast("int8_t[$this->dataSize]", $this->dataU8); + + // @phpstan-ignore-next-line + $castInt = fn ($n, $signed, $offset) => $this->ffi->cast( + sprintf("%sint%d_t[$this->dataSize/%d]", $signed ? "" : "u", $n, $n / 8), + // @phpstan-ignore-next-line + $this->ffi->cast("uint8_t[$this->dataSize+8]", $this->dataU8 + $offset), + ); + + // @phpstan-ignore-next-line + $castFloat = fn ($n, $offset) => $this->ffi->cast( + sprintf("%s[$this->dataSize/%d]", $n === 32 ? "float" : "double", $n / 8), + // @phpstan-ignore-next-line + $this->ffi->cast("uint8_t[$this->dataSize+8]", $this->dataU8 + $offset), + ); + + // @phpstan-ignore-next-line + $this->dataU16_0 = $castInt(16, false, 0); + // @phpstan-ignore-next-line + $this->dataU16_1 = $castInt(16, false, 1); + // @phpstan-ignore-next-line + $this->dataS16_0 = $castInt(16, true, 0); + // @phpstan-ignore-next-line + $this->dataS16_1 = $castInt(16, true, 1); + + // @phpstan-ignore-next-line + $this->dataU32_0 = $castInt(32, false, 0); + // @phpstan-ignore-next-line + $this->dataU32_1 = $castInt(32, false, 1); + // @phpstan-ignore-next-line + $this->dataU32_2 = $castInt(32, false, 2); + // @phpstan-ignore-next-line + $this->dataU32_3 = $castInt(32, false, 3); + // @phpstan-ignore-next-line + $this->dataS32_0 = $castInt(32, true, 0); + // @phpstan-ignore-next-line + $this->dataS32_1 = $castInt(32, true, 1); + // @phpstan-ignore-next-line + $this->dataS32_2 = $castInt(32, true, 2); + // @phpstan-ignore-next-line + $this->dataS32_3 = $castInt(32, true, 3); + + // @phpstan-ignore-next-line + $this->dataS64_0 = $castInt(64, true, 0); + // @phpstan-ignore-next-line + $this->dataS64_1 = $castInt(64, true, 1); + // @phpstan-ignore-next-line + $this->dataS64_2 = $castInt(64, true, 2); + // @phpstan-ignore-next-line + $this->dataS64_3 = $castInt(64, true, 3); + // @phpstan-ignore-next-line + $this->dataS64_4 = $castInt(64, true, 4); + // @phpstan-ignore-next-line + $this->dataS64_5 = $castInt(64, true, 5); + // @phpstan-ignore-next-line + $this->dataS64_6 = $castInt(64, true, 6); + // @phpstan-ignore-next-line + $this->dataS64_7 = $castInt(64, true, 7); + + // @phpstan-ignore-next-line + $this->dataF32_0 = $castFloat(32, 0); + // @phpstan-ignore-next-line + $this->dataF32_1 = $castFloat(32, 1); + // @phpstan-ignore-next-line + $this->dataF32_2 = $castFloat(32, 2); + // @phpstan-ignore-next-line + $this->dataF32_3 = $castFloat(32, 3); + + // @phpstan-ignore-next-line + $this->dataF64_0 = $castFloat(64, 0); + // @phpstan-ignore-next-line + $this->dataF64_1 = $castFloat(64, 1); + // @phpstan-ignore-next-line + $this->dataF64_2 = $castFloat(64, 2); + // @phpstan-ignore-next-line + $this->dataF64_3 = $castFloat(64, 3); + // @phpstan-ignore-next-line + $this->dataF64_4 = $castFloat(64, 4); + // @phpstan-ignore-next-line + $this->dataF64_5 = $castFloat(64, 5); + // @phpstan-ignore-next-line + $this->dataF64_6 = $castFloat(64, 6); + // @phpstan-ignore-next-line + $this->dataF64_7 = $castFloat(64, 7); + + // @phpstan-ignore-next-line + FFI::memset($this->dataU8, 0, $this->dataSize); } public function size(): int { - return strlen($this->data); + return $this->dataSize; } /** @@ -51,13 +185,12 @@ final class MemInst */ public function loadI32_s8(int $ptr): ?int { - if ($this->size() < $ptr) { + if ($this->size() <= $ptr + 1) { return null; } - $result = unpack('c', $this->data, $ptr); - assert($result !== false); - $c = $result[1]; - assert(-0x80 <= $c && $c <= 0x7F); + // @phpstan-ignore-next-line + $c = $this->dataS8[$ptr]; + assert(-0x80 <= $c && $c <= 0x7F, "$c"); return $c; } @@ -66,13 +199,12 @@ final class MemInst */ public function loadI32_u8(int $ptr): ?int { - if ($this->size() < $ptr) { + if ($this->size() <= $ptr + 1) { return null; } - $result = unpack('C', $this->data, $ptr); - assert($result !== false); - $c = $result[1]; - assert(0x00 <= $c && $c <= 0xFF); + // @phpstan-ignore-next-line + $c = $this->dataU8[$ptr]; + assert(0 <= $c && $c <= 0xFF, "$c"); return $c; } @@ -81,13 +213,13 @@ final class MemInst */ public function loadI32_s16(int $ptr): ?int { - $buf = $this->sliceNBytes($ptr, 2); - if ($buf === null) { + if ($this->size() <= $ptr + 2) { return null; } - $result = unpack('s', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + $c = $this->dataS16($ptr)[$ptr >> 1]; + assert(-0x8000 <= $c && $c <= 0x7FFF, "$c"); + return $c; } /** @@ -95,13 +227,13 @@ final class MemInst */ public function loadI32_u16(int $ptr): ?int { - $buf = $this->sliceNBytes($ptr, 2); - if ($buf === null) { + if ($this->size() <= $ptr + 2) { return null; } - $result = unpack('S', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + $c = $this->dataU16($ptr)[$ptr >> 1]; + assert(0 <= $c && $c <= 0xFFFF, "$c"); + return $c; } /** @@ -109,13 +241,13 @@ final class MemInst */ public function loadI32_s32(int $ptr): ?int { - $buf = $this->sliceNBytes($ptr, 4); - if ($buf === null) { + if ($this->size() <= $ptr + 4) { return null; } - $result = unpack('l', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + $c = $this->dataS32($ptr)[$ptr >> 2]; + assert(-0x80000000 <= $c && $c <= 0x7FFFFFFF, "$c"); + return $c; } /** @@ -123,13 +255,12 @@ final class MemInst */ public function loadI64_s8(int $ptr): ?int { - if ($this->size() < $ptr) { + if ($this->size() <= $ptr + 1) { return null; } - $result = unpack('c', $this->data, $ptr); - assert($result !== false); - $c = $result[1]; - assert(-0x80 <= $c && $c <= 0x7F); + // @phpstan-ignore-next-line + $c = $this->dataS8[$ptr]; + assert(-0x80 <= $c && $c <= 0x7F, "$c"); return $c; } @@ -138,13 +269,12 @@ final class MemInst */ public function loadI64_u8(int $ptr): ?int { - if ($this->size() < $ptr) { + if ($this->size() <= $ptr + 1) { return null; } - $result = unpack('C', $this->data, $ptr); - assert($result !== false); - $c = $result[1]; - assert(0x00 <= $c && $c <= 0xFF); + // @phpstan-ignore-next-line + $c = $this->dataU8[$ptr]; + assert(0 <= $c && $c <= 0xFF, "$c"); return $c; } @@ -153,13 +283,13 @@ final class MemInst */ public function loadI64_s16(int $ptr): ?int { - $buf = $this->sliceNBytes($ptr, 2); - if ($buf === null) { + if ($this->size() <= $ptr + 2) { return null; } - $result = unpack('s', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + $c = $this->dataS16($ptr)[$ptr >> 1]; + assert(-0x8000 <= $c && $c <= 0x7FFF, "$c"); + return $c; } /** @@ -167,13 +297,13 @@ final class MemInst */ public function loadI64_u16(int $ptr): ?int { - $buf = $this->sliceNBytes($ptr, 2); - if ($buf === null) { + if ($this->size() <= $ptr + 2) { return null; } - $result = unpack('S', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + $c = $this->dataU16($ptr)[$ptr >> 1]; + assert(0 <= $c && $c <= 0xFFFF, "$c"); + return $c; } /** @@ -181,13 +311,13 @@ final class MemInst */ public function loadI64_s32(int $ptr): ?int { - $buf = $this->sliceNBytes($ptr, 4); - if ($buf === null) { + if ($this->size() <= $ptr + 4) { return null; } - $result = unpack('l', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + $c = $this->dataS32($ptr)[$ptr >> 2]; + assert(-0x80000000 <= $c && $c <= 0x7FFFFFFF, "$c"); + return $c; } /** @@ -195,13 +325,13 @@ final class MemInst */ public function loadI64_u32(int $ptr): ?int { - $buf = $this->sliceNBytes($ptr, 4); - if ($buf === null) { + if ($this->size() <= $ptr + 4) { return null; } - $result = unpack('L', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + $c = $this->dataU32($ptr)[$ptr >> 2]; + assert(0 <= $c && $c <= 0xFFFFFFFF, "$c"); + return $c; } /** @@ -209,13 +339,13 @@ final class MemInst */ public function loadI64_s64(int $ptr): ?int { - $buf = $this->sliceNBytes($ptr, 8); - if ($buf === null) { + if ($this->size() <= $ptr + 8) { return null; } - $result = unpack('q', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + $c = $this->dataS64($ptr)[$ptr >> 3]; + assert(-0x8000000000000000 <= $c && $c <= 0x7FFFFFFFFFFFFFFF, "$c"); + return $c; } /** @@ -223,13 +353,11 @@ final class MemInst */ public function loadF32(int $ptr): ?float { - $buf = $this->sliceNBytes($ptr, 4); - if ($buf === null) { + if ($this->size() <= $ptr + 4) { return null; } - $result = unpack('f', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + return $this->dataF32($ptr)[$ptr >> 2]; } /** @@ -237,13 +365,11 @@ final class MemInst */ public function loadF64(int $ptr): ?float { - $buf = $this->sliceNBytes($ptr, 8); - if ($buf === null) { + if ($this->size() <= $ptr + 8) { return null; } - $result = unpack('d', $buf); - assert($result !== false); - return $result[1]; + // @phpstan-ignore-next-line + return $this->dataF64($ptr)[$ptr >> 3]; } /** @@ -251,14 +377,11 @@ final class MemInst */ public function loadByte(int $ptr): ?int { - if ($this->size() < $ptr) { + if ($this->size() <= $ptr + 1) { return null; } - $result = unpack('C', $this->data, $ptr); - assert($result !== false); - $c = $result[1]; - assert(0x00 <= $c && $c <= 0xFF); - return $c; + // @phpstan-ignore-next-line + return $this->dataU8[$ptr]; } /** @@ -266,11 +389,11 @@ final class MemInst */ public function storeByte(int $ptr, int $c): bool { - assert(0x00 <= $c && $c <= 0xFF); - if ($this->size() < $ptr) { + if ($this->size() <= $ptr + 1) { return false; } - $this->data[$ptr] = chr($c); + // @phpstan-ignore-next-line + $this->dataU8[$ptr] = $c; return true; } @@ -280,13 +403,11 @@ final class MemInst */ public function storeI32_s8(int $ptr, int $c): bool { - if ($this->size() < $ptr + 1) { + if ($this->size() <= $ptr + 1) { return false; } - $buf = pack('s', $c); - for ($i = 0; $i < 1; $i++) { - $this->storeByte($ptr + $i, ord($buf[$i])); - } + // @phpstan-ignore-next-line + $this->dataS8[$ptr] = $c; return true; } @@ -296,13 +417,11 @@ final class MemInst */ public function storeI32_s16(int $ptr, int $c): bool { - if ($this->size() < $ptr + 2) { + if ($this->size() <= $ptr + 2) { return false; } - $buf = pack('s', $c); - for ($i = 0; $i < 2; $i++) { - $this->storeByte($ptr + $i, ord($buf[$i])); - } + // @phpstan-ignore-next-line + $this->dataS16($ptr)[$ptr >> 1] = $c; return true; } @@ -312,13 +431,11 @@ final class MemInst */ public function storeI32_s32(int $ptr, int $c): bool { - if ($this->size() < $ptr + 4) { + if ($this->size() <= $ptr + 4) { return false; } - $buf = pack('l', $c); - for ($i = 0; $i < 4; $i++) { - $this->storeByte($ptr + $i, ord($buf[$i])); - } + // @phpstan-ignore-next-line + $this->dataS32($ptr)[$ptr >> 2] = $c; return true; } @@ -328,7 +445,12 @@ final class MemInst */ public function storeI64_s8(int $ptr, int $c): bool { - return $this->storeByte($ptr, $c); + if ($this->size() <= $ptr + 1) { + return false; + } + // @phpstan-ignore-next-line + $this->dataS8[$ptr] = $c; + return true; } /** @@ -337,13 +459,11 @@ final class MemInst */ public function storeI64_s16(int $ptr, int $c): bool { - if ($this->size() < $ptr + 2) { + if ($this->size() <= $ptr + 2) { return false; } - $buf = pack('s', $c); - for ($i = 0; $i < 2; $i++) { - $this->storeByte($ptr + $i, ord($buf[$i])); - } + // @phpstan-ignore-next-line + $this->dataS16($ptr)[$ptr >> 1] = $c; return true; } @@ -353,13 +473,11 @@ final class MemInst */ public function storeI64_s32(int $ptr, int $c): bool { - if ($this->size() < $ptr + 4) { + if ($this->size() <= $ptr + 4) { return false; } - $buf = pack('l', $c); - for ($i = 0; $i < 4; $i++) { - $this->storeByte($ptr + $i, ord($buf[$i])); - } + // @phpstan-ignore-next-line + $this->dataS32($ptr)[$ptr >> 2] = $c; return true; } @@ -369,13 +487,11 @@ final class MemInst */ public function storeI64_s64(int $ptr, int $c): bool { - if ($this->size() < $ptr + 8) { + if ($this->size() <= $ptr + 8) { return false; } - $buf = pack('q', $c); - for ($i = 0; $i < 8; $i++) { - $this->storeByte($ptr + $i, ord($buf[$i])); - } + // @phpstan-ignore-next-line + $this->dataS64($ptr)[$ptr >> 3] = $c; return true; } @@ -385,13 +501,11 @@ final class MemInst */ public function storeF32(int $ptr, float $c): bool { - if ($this->size() < $ptr + 4) { + if ($this->size() <= $ptr + 4) { return false; } - $buf = pack('f', $c); - for ($i = 0; $i < 4; $i++) { - $this->storeByte($ptr + $i, ord($buf[$i])); - } + // @phpstan-ignore-next-line + $this->dataF32($ptr)[$ptr >> 2] = $c; return true; } @@ -401,21 +515,79 @@ final class MemInst */ public function storeF64(int $ptr, float $c): bool { - if ($this->size() < $ptr + 8) { + if ($this->size() <= $ptr + 8) { return false; } - $buf = pack('d', $c); - for ($i = 0; $i < 8; $i++) { - $this->storeByte($ptr + $i, ord($buf[$i])); - } + // @phpstan-ignore-next-line + $this->dataF64($ptr)[$ptr >> 3] = $c; return true; } - private function sliceNBytes(int $ptr, int $len): ?string + private function dataU16(int $ptr): CData { - if ($this->size() < $ptr + $len) { - return null; - } - return substr($this->data, $ptr, $len); + return ($ptr & 1) !== 0 ? $this->dataU16_1 : $this->dataU16_0; + } + + private function dataS16(int $ptr): CData + { + return ($ptr & 1) !== 0 ? $this->dataS16_1 : $this->dataS16_0; + } + + private function dataU32(int $ptr): CData + { + return match ($ptr & 3) { + 0 => $this->dataU32_0, + 1 => $this->dataU32_1, + 2 => $this->dataU32_2, + 3 => $this->dataU32_3, + }; + } + + private function dataS32(int $ptr): CData + { + return match ($ptr & 3) { + 0 => $this->dataS32_0, + 1 => $this->dataS32_1, + 2 => $this->dataS32_2, + 3 => $this->dataS32_3, + }; + } + + private function dataS64(int $ptr): CData + { + return match ($ptr & 7) { + 0 => $this->dataS64_0, + 1 => $this->dataS64_1, + 2 => $this->dataS64_2, + 3 => $this->dataS64_3, + 4 => $this->dataS64_4, + 5 => $this->dataS64_5, + 6 => $this->dataS64_6, + 7 => $this->dataS64_7, + }; + } + + private function dataF32(int $ptr): CData + { + return match ($ptr & 3) { + 0 => $this->dataF32_0, + 1 => $this->dataF32_1, + 2 => $this->dataF32_2, + 3 => $this->dataF32_3, + }; + } + + private function dataF64(int $ptr): CData + { + return match ($ptr & 7) { + 0 => $this->dataF64_0, + 1 => $this->dataF64_1, + 2 => $this->dataF64_2, + 3 => $this->dataF64_3, + 4 => $this->dataF64_4, + 5 => $this->dataF64_5, + 6 => $this->dataF64_6, + 7 => $this->dataF64_7, + }; } } diff --git a/test.sh b/test.sh index 23552a8..1792726 100644 --- a/test.sh +++ b/test.sh @@ -1,4 +1,4 @@ -result=$(php -d zend.assertions=-1 -d memory_limit=512M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php 2>/dev/null) +result=$(php -d memory_limit=512M -d opcache.enable_cli=on -d opcache.jit=on -d opcache.jit_buffer_size=1G examples/php-on-wasm/php-wasm.php 2>/dev/null) if [[ "$result" == 'Hello, World!' ]]; then echo "Test passed" exit 0 diff --git a/traces/20240314-2332.stderr.log b/traces/20240314-2332.stderr.log new file mode 100644 index 0000000..b51ea5d --- /dev/null +++ b/traces/20240314-2332.stderr.log @@ -0,0 +1,86 @@ +Decoding... +Instantiating... +Executing... + +Exit code: 0 +Memory peak usage: 323157384 + + +i32.rem_u: 5701 1 5701.000000 +i64.rot_l: 10370 1 10370.000000 +i64.eq: 4489 2 2244.500000 +f64.gt: 5221 2 2610.500000 +f64.mul: 5541 2 2770.500000 +f64.load: 16933 2 8466.500000 +f64.add: 7524 4 1881.000000 +f64.convert_i32_s: 8306 4 2076.500000 +i64.extend_i32_s: 620298 16 38768.625000 +i64.sub: 764751 16 47796.937500 +i64.lt_u: 546810 17 32165.294118 +f64.store: 856157 24 35673.208333 +f64.const: 867055 26 33348.269231 +i32.wrap_i64: 655283 32 20477.593750 +i64.eqz: 931444 42 22177.238095 +i64.or: 743727 46 16167.978261 +i64.gt_u: 808636 46 17579.043478 +i64.shl: 1329100 47 28278.723404 +i32.le_s: 960518 49 19602.408163 +i64.xor: 951714 62 15350.225806 +i64.ne: 859975 70 12285.357143 +i32.extend8_s: 1257605 78 16123.141026 +i32.load16_s: 1179917 81 14566.876543 +memory.size: 1188311 130 9140.853846 +i32.ge_s: 1004615 134 7497.126866 +i32.ctz: 1636728 155 10559.535484 +i64.and: 864704 226 3826.123894 +i64.shr_u: 778289 239 3256.439331 +i32.extend16_s: 948276 256 3704.203125 +i32.div_u: 1543977 284 5436.538732 +i64.add: 940281 323 2911.086687 +i32.load16_u: 1242068 426 2915.652582 +i64.extend_i32_u: 1838731 592 3105.964527 +i32.gt_s: 1446665 613 2359.975530 +i64.mul: 1678097 842 1992.989311 +i32.store16: 3080481 1998 1541.782282 +i32.lt_s: 2963703 2161 1371.449792 +i32.rot_l: 3197716 2203 1451.527916 +i32.clz: 3566354 5130 695.195712 +br_table: 4148587 6061 684.472364 +i64.const: 3586867 9965 359.946513 +call_indirect: 8260356159 12643 653354.121569 +i64.load: 8942297 12927 691.753462 +drop: 5932049 15033 394.601809 +i32.xor: 13407804 18826 712.196112 +return: 5390830 19633 274.580044 +i32.le_u: 12099658 25404 476.289482 +global.get: 9850207 25951 379.569458 +select: 13782824 29114 473.408807 +i32.ge_u: 16817113 33468 502.483357 +i32.store8: 15325568 42849 357.664543 +loop: 8149939908 44110 184763.997007 +global.set: 17808131 51161 348.080198 +i32.shr_u: 19805764 51699 383.097623 +i32.load8_s: 16840481 54242 310.469396 +i32.sub: 22559546 64081 352.047346 +i32.eq: 24626271 66100 372.560832 +br: 14517941 66911 216.973906 +i32.mul: 26731971 68122 392.413185 +call: 30719408476 70579 435248.565097 +i32.or: 39125198 71541 546.891964 +i32.shl: 35726900 86408 413.467503 +i32.ne: 29138684 92660 314.468854 +i32.lt_u: 38166252 101169 377.252439 +i32.gt_u: 45741244 117828 388.203517 +i32.load8_u: 50951062 159431 319.580646 +i32.eqz: 52898379 198278 266.788948 +i32.and: 98541596 249884 394.349362 +i64.store: 96469170 306534 314.709527 +i32.store: 110435403 362806 304.392438 +local.set: 108107180 439632 245.903801 +i32.load: 170144415 564315 301.506100 +block: 65712228409 723450 90831.748440 +br_if: 151711004 732305 207.169149 +local.tee: 164164797 758661 216.387553 +i32.add: 206191783 812466 253.785122 +i32.const: 259707657 1589717 163.367226 +local.get: 541570304 3135728 172.709592 -- cgit v1.2.3-70-g09d2