From 6ed839b5c22e8bce91b8d3c72e320dac9bb79f5d Mon Sep 17 00:00:00 2001 From: Marcel Hernandez Date: Mon, 12 Aug 2019 00:14:53 +0200 Subject: [PATCH] explicitly enable simdjson parsing with an argument to the JsonRpc server --- src/Internal/Input.php | 4 ++-- src/Server.php | 10 ++++++++-- tests/Unit/InputTest.php | 43 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/Internal/Input.php b/src/Internal/Input.php index e789bc9..b81abb9 100644 --- a/src/Internal/Input.php +++ b/src/Internal/Input.php @@ -56,9 +56,9 @@ private function __construct($data, int $error) } } - public static function fromString(string $raw): Input + public static function fromString(string $raw, bool $simdJson): Input { - if (!\extension_loaded('simdjson')) { + if (!$simdJson || !\extension_loaded('simdjson')) { return new self(\json_decode($raw), \json_last_error()); } diff --git a/src/Server.php b/src/Server.php index b476717..95a5cba 100644 --- a/src/Server.php +++ b/src/Server.php @@ -37,9 +37,15 @@ class Server */ private $batchLimit; - public function __construct(ContainerInterface $container, int $batchLimit = null) + /** + * @var bool + */ + private $simdJson; + + public function __construct(ContainerInterface $container, int $batchLimit = null, bool $simdJson = false) { $this->container = $container; + $this->simdJson = $simdJson; $this->batchLimit = $batchLimit; $this->methods = []; $this->middlewares = []; @@ -72,7 +78,7 @@ public function attach(string $serviceId): Server */ public function run(string $raw): ?string { - $input = Input::fromString($raw); + $input = Input::fromString($raw, $this->simdJson); if (!$input->parsable()) { return self::end(Error::parsing()); diff --git a/tests/Unit/InputTest.php b/tests/Unit/InputTest.php index 6158b1e..256e72c 100644 --- a/tests/Unit/InputTest.php +++ b/tests/Unit/InputTest.php @@ -14,7 +14,7 @@ final class InputTest extends TestCase */ public function testValidInputs(string $raw): void { - $sut = Input::fromString($raw); + $sut = Input::fromString($raw, false); self::assertTrue($sut->parsable()); self::assertEquals($sut->data(), \json_decode($raw)); @@ -36,7 +36,18 @@ public function validInputsProvider(): array */ public function testInputParseError(string $raw): void { - $sut = Input::fromString($raw); + $sut = Input::fromString($raw, false); + + self::assertFalse($sut->parsable()); + self::assertNull($sut->data()); + + self::assertFalse($sut->isArray()); + + if (!self::simdJsonSupport()) { + return; + } + + $sut = Input::fromString($raw, true); self::assertFalse($sut->parsable()); self::assertNull($sut->data()); @@ -49,7 +60,7 @@ public function parseErrorProvider(): array return [ [''], ['}"jsonrpc":"2.0'], - [random_bytes(6)] + [\random_bytes(6)] ]; } @@ -58,12 +69,24 @@ public function parseErrorProvider(): array */ public function testInvalidInputs(string $raw): void { - $sut = Input::fromString($raw); + $sut = Input::fromString($raw, false); + + self::assertTrue($sut->parsable()); + self::assertEquals($sut->data(), \json_decode($raw)); + + self::assertFalse($sut->isArray()); + + if (!self::simdJsonSupport()) { + return; + } + + $sut = Input::fromString($raw, true); self::assertTrue($sut->parsable()); self::assertEquals($sut->data(), \json_decode($raw)); self::assertFalse($sut->isArray()); + } public function invalidInputsProvider(): array @@ -78,4 +101,16 @@ public function invalidInputsProvider(): array 'empty array' => ['[]'] ]; } + + /** + * Return whether the PHP installation on which the tests are running has the + * simdjson extension loaded, is running on Linux and the machine has either + * the AVX2 or SSE4.2 instruction sets. + */ + private static function simdJsonSupport(): bool + { + return \extension_loaded('simdjson') + && 'Linux' === PHP_OS + && (null !== \shell_exec('grep avx2 /proc/cpuinfo') || null !== \shell_exec('grep sse4_2 /proc/cpuinfo')); + } }