Browse Source

[PHP] Add Swoole and Swow as event-driven stress tests for Workerman. (#9382)

* Add Swoole and Swow as event-driven stress tests for Workerman.

* Text and json requests using Select event-driven
walkor 9 months ago
parent
commit
a65d01af3c

+ 15 - 0
frameworks/PHP/workerman/Date.php

@@ -0,0 +1,15 @@
+<?php
+
+use Workerman\Timer;
+
+class Date
+{
+    public $date = null;
+    public function __construct()
+    {
+        $this->date = gmdate('D, d M Y H:i:s').' GMT';
+        Timer::add(1, function() {
+            $this->date = gmdate('D, d M Y H:i:s').' GMT';
+        });
+    }
+}

+ 82 - 0
frameworks/PHP/workerman/Mysql.php

@@ -0,0 +1,82 @@
+<?php
+
+class Mysql
+{
+
+    protected PDO $pdo;
+    protected PDOStatement $world;
+    protected PDOStatement $fortune;
+    protected PDOStatement $update;
+
+    public function __construct()
+    {
+        $this->pdo = new PDO(
+            'mysql:host=tfb-database;dbname=hello_world',
+            'benchmarkdbuser',
+            'benchmarkdbpass',
+            [
+                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+                PDO::ATTR_EMULATE_PREPARES => false
+            ]
+        );
+        $this->world = $this->pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+        $this->fortune = $this->pdo->prepare('SELECT id,message FROM Fortune');
+        $this->update = $this->pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?');
+    }
+
+    function db(): array
+    {
+        $this->world->execute([mt_rand(1, 10000)]);
+        return $this->world->fetch();
+    }
+
+    function query($request): array
+    {
+        $query_count = 1;
+        $q = (int)$request->get('q');
+        if ($q > 1) {
+            $query_count = min($q, 500);
+        }
+        $arr = [];
+        while ($query_count--) {
+            $this->world->execute([mt_rand(1, 10000)]);
+            $arr[] = $this->world->fetch();
+        }
+        return $arr;
+    }
+
+    function update($request): array
+    {
+        $query_count = 1;
+        $q = (int)$request->get('q');
+        if ($q > 1) {
+            $query_count = min($q, 500);
+        }
+        $arr = [];
+        while ($query_count--) {
+            $id = mt_rand(1, 10000);
+            $this->world->execute([$id]);
+            $item = $this->world->fetch();
+            $this->update->execute(
+                [$item['randomNumber'] = mt_rand(1, 10000), $id]
+            );
+            $arr[] = $item;
+        }
+        return $arr;
+    }
+
+    function fortune(): string
+    {
+        $this->fortune->execute();
+        $arr = $this->fortune->fetchAll(PDO::FETCH_KEY_PAIR);
+        $arr[0] = 'Additional fortune added at request time.';
+        asort($arr);
+        $html = '';
+        foreach ($arr as $id => $message) {
+            $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
+            $html .= "<tr><td>$id</td><td>$message</td></tr>";
+        }
+        return "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>$html</table></body></html>";
+    }
+
+}

+ 91 - 0
frameworks/PHP/workerman/MysqlSwoole.php

@@ -0,0 +1,91 @@
+<?php
+
+use Swoole\Database\PDOConfig;
+use Swoole\Database\PDOPool;
+class MysqlSwoole
+{
+
+    protected Pool|PDOPool $pool;
+
+    public function __construct($size)
+    {
+        $config = (new PDOConfig())
+            ->withDriver('mysql')
+            ->withHost('tfb-database')
+            ->withPort(3306)
+            ->withDbName('hello_world')
+            ->withUsername('benchmarkdbuser')
+            ->withPassword('benchmarkdbpass');
+        $this->pool = new PDOPool($config, $size);
+    }
+
+    function db(): array
+    {
+        $pdo = $this->pool->get();
+        $stmt = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+        $stmt->execute([mt_rand(1, 10000)]);
+        $result = $stmt->fetch(PDO::FETCH_ASSOC);
+        $this->pool->put($pdo);
+        return $result;
+    }
+
+    function query($request): array
+    {
+        $query_count = 1;
+        $q = (int)$request->get('q');
+        if ($q > 1) {
+            $query_count = min($q, 500);
+        }
+        $pdo = $this->pool->get();
+        $stmt = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+        $arr = [];
+        while ($query_count--) {
+            $stmt->execute([mt_rand(1, 10000)]);
+            $arr[] = $stmt->fetch(PDO::FETCH_ASSOC);
+        }
+        $this->pool->put($pdo);
+        return $arr;
+    }
+
+    function update($request): array
+    {
+        $query_count = 1;
+        $q = (int)$request->get('q');
+        if ($q > 1) {
+            $query_count = min($q, 500);
+        }
+        $arr = [];
+        $pdo = $this->pool->get();
+        $world = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+        $update = $pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?');
+        while ($query_count--) {
+            $id = mt_rand(1, 10000);
+            $world->execute([$id]);
+            $item = $world->fetch(PDO::FETCH_ASSOC);
+            $update->execute(
+                [$item['randomNumber'] = mt_rand(1, 10000), $id]
+            );
+            $arr[] = $item;
+        }
+        $this->pool->put($pdo);
+        return $arr;
+    }
+
+    function fortune(): string
+    {
+        $pdo = $this->pool->get();
+        $stmt = $pdo->prepare('SELECT id,message FROM Fortune');
+        $stmt->execute();
+        $arr = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
+        $this->pool->put($pdo);
+        $arr[0] = 'Additional fortune added at request time.';
+        asort($arr);
+        $html = '';
+        foreach ($arr as $id => $message) {
+            $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
+            $html .= "<tr><td>$id</td><td>$message</td></tr>";
+        }
+        return "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>$html</table></body></html>";
+    }
+
+}

+ 12 - 0
frameworks/PHP/workerman/MysqlSwow.php

@@ -0,0 +1,12 @@
+<?php
+
+use Swoole\Database\PDOPool;
+class MysqlSwow extends MysqlSwoole
+{
+
+    public function __construct($size)
+    {
+        $this->pool = new Pool("mysql:host=tfb-database;dbname=hello_world", 'benchmarkdbuser', 'benchmarkdbpass', $size);
+    }
+
+}

+ 65 - 0
frameworks/PHP/workerman/Pgsql.php

@@ -0,0 +1,65 @@
+<?php
+
+class Pgsql extends Mysql
+{
+    protected PDO $pdo;
+    protected PDOStatement $world;
+    protected PDOStatement $fortune;
+    protected PDOStatement $update;
+    protected PDOStatement $random;
+    protected array $updates = [];
+
+    public function __construct()
+    {
+        $this->pdo = new PDO(
+            'pgsql:host=tfb-database;dbname=hello_world',
+            'benchmarkdbuser',
+            'benchmarkdbpass',
+            [
+                PDO::ATTR_DEFAULT_FETCH_MODE  => PDO::FETCH_ASSOC,
+                PDO::ATTR_ERRMODE             => PDO::ERRMODE_EXCEPTION,
+                PDO::ATTR_EMULATE_PREPARES    => false
+            ]
+        );
+        $this->world = $this->random = $this->pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+        $this->fortune = $this->pdo->prepare('SELECT id,message FROM Fortune');
+        $this->update = $this->pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?');
+    }
+
+    function update($request): array
+    {
+        $query_count = 1;
+        $q = (int)$request->get('q');
+        if ($q > 1) {
+            $query_count = min($q, 500);
+        }
+        $worlds = [];
+        while ($query_count--) {
+            $this->random->execute([\mt_rand(1, 10000)]);
+            $world = $this->random->fetch();
+            $world['randomNumber'] = \mt_rand(1, 10000);
+            $worlds[] = $world;
+        }
+        $rows = count($worlds);
+
+        if (!isset($this->updates[$rows])) {
+            $sql = 'UPDATE world SET randomNumber = CASE id'
+                . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows)
+                . 'END WHERE id IN ('
+                . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)';
+
+            $this->updates[$rows] = $this->pdo->prepare($sql);
+        }
+
+        $val = [];
+        $keys = [];
+        foreach ($worlds as $world) {
+            $val[] = $keys[] = $world['id'];
+            $val[] = $world['randomNumber'];
+        }
+
+        $this->updates[$rows]->execute([...$val, ...$keys]);
+        return $worlds;
+    }
+
+}

+ 61 - 0
frameworks/PHP/workerman/PgsqlSwoole.php

@@ -0,0 +1,61 @@
+<?php
+
+use Swoole\Database\PDOConfig;
+use Swoole\Database\PDOPool;
+class PgsqlSwoole extends MysqlSwoole
+{
+
+    protected Pool|PDOPool $pool;
+
+    public function __construct($size)
+    {
+        $config = (new PDOConfig())
+            ->withDriver('pgsql')
+            ->withHost('tfb-database')
+            ->withPort(5432)
+            ->withDbName('hello_world')
+            ->withUsername('benchmarkdbuser')
+            ->withPassword('benchmarkdbpass');
+
+        $this->pool = new PDOPool($config, $size);
+    }
+
+
+    function update($request): array
+    {
+        $query_count = 1;
+        $q = (int)$request->get('q');
+        if ($q > 1) {
+            $query_count = min($q, 500);
+        }
+        $worlds = [];
+        $pdo = $this->pool->get();
+        $random = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
+        while ($query_count--) {
+            $random->execute([mt_rand(1, 10000)]);
+            $world = $random->fetch(PDO::FETCH_ASSOC);
+            $world['randomNumber'] = mt_rand(1, 10000);
+            $worlds[] = $world;
+        }
+        $rows = count($worlds);
+
+        $sql = 'UPDATE world SET randomNumber = CASE id'
+            . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows)
+            . 'END WHERE id IN ('
+            . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)';
+
+        $update = $pdo->prepare($sql);
+
+        $val = [];
+        $keys = [];
+        foreach ($worlds as $world) {
+            $val[] = $keys[] = $world['id'];
+            $val[] = $world['randomNumber'];
+        }
+
+        $update->execute([...$val, ...$keys]);
+        $this->pool->put($pdo);
+        return $worlds;
+    }
+
+}

+ 12 - 0
frameworks/PHP/workerman/PgsqlSwow.php

@@ -0,0 +1,12 @@
+<?php
+
+use Swoole\Database\PDOPool;
+class PgsqlSwow extends MysqlSwow
+{
+
+    public function __construct($size)
+    {
+        $this->pool = new Pool("pgsql:host=tfb-database;dbname=hello_world", 'benchmarkdbuser', 'benchmarkdbpass', $size);
+    }
+
+}

+ 29 - 0
frameworks/PHP/workerman/Pool.php

@@ -0,0 +1,29 @@
+<?php
+
+use Swow\Channel;
+
+class Pool
+{
+
+    protected static Channel $channel;
+
+    public function __construct($dsn, $username, $password, $size)
+    {
+        static::$channel = new Channel($size);
+        for ($i = 0; $i < $size; $i++) {
+            static::$channel->push(new PDO($dsn, $username, $password,[
+                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
+            ]));
+        }
+    }
+
+    public function get(): PDO
+    {
+        return static::$channel->pop();
+    }
+
+    public function put(PDO $pdo)
+    {
+        return static::$channel->push($pdo);
+    }
+}

+ 0 - 122
frameworks/PHP/workerman/app-pg.php

@@ -1,122 +0,0 @@
-<?php
-use Workerman\Protocols\Http\Response;
-use Workerman\Protocols\Http\Request;
-
-include 'dbraw.php';
-
-
-function router(Request $request)
-{
-    return match($request->path()) {
-        '/plaintext' => text(),
-        '/json'      => json(), 
-        '/db'        => db(),
-        '/fortunes'  => fortune(),
-        '/query'     => query($request),
-        '/update'    => updateraw($request),
-        // '/info'      => info(),
-        default      => new Response(404, [], 'Error 404'),
-    };
-}
-
-function text()
-{
-    return new Response(200, [
-        'Content-Type' => 'text/plain',
-        'Date'         => Header::$date
-    ], 'Hello, World!');
-}
-
-function json()
-{
-    return new Response(200, [
-        'Content-Type' => 'application/json',
-        'Date'         => Header::$date
-    ], json_encode(['message' => 'Hello, World!']));
-}
-
-function db()
-{
-    DbRaw::$random->execute([mt_rand(1, 10000)]);
-
-    return new Response(200, [
-        'Content-Type' => 'application/json',
-        'Date'         => Header::$date
-    ], json_encode(DbRaw::$random->fetch()));
-}
-
-function query($request)
-{
-    $random = DbRaw::$random;
-
-    $query_count = 1;
-    $q = (int) $request->get('q');
-    if ($q > 1) {
-        $query_count = min($q, 500);
-    }
-
-    while ($query_count--) {
-        $random->execute([mt_rand(1, 10000)]);
-        $arr[] = $random->fetch();
-    }
-
-    return new Response(200, [
-        'Content-Type' => 'application/json',
-        'Date'         => Header::$date
-    ], json_encode($arr));
-}
-
-function updateraw($request)
-{
-    $random = DbRaw::$random;
-
-    $query_count = 1;
-    $q = (int) $request->get('q');
-    if ($q > 1) {
-        $query_count = min($q, 500);
-    }
-
-    while ($query_count--) {
-
-        $random->execute([mt_rand(1, 10000)]);
-        $row = $random->fetch();
-        $row['randomNumber'] = mt_rand(1, 10000);
-
-        $worlds[] = $row;
-    }
-
-    DbRaw::update($worlds);
-
-    return new Response(200, [
-        'Content-Type' => 'application/json',
-        'Date'         => Header::$date
-    ], json_encode($worlds));
-}
-
-function fortune()
-{
-    DbRaw::$fortune->execute();
-
-    $arr    = DbRaw::$fortune->fetchAll(PDO::FETCH_KEY_PAIR);
-    $arr[0] = 'Additional fortune added at request time.';
-    asort($arr);
-
-    $html = '';
-    foreach ($arr as $id => $message) {
-        $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
-        $html .= "<tr><td>$id</td><td>$message</td></tr>";
-    }
-
-    return new Response(200, [
-        'Date'         => Header::$date
-    ], "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>$html</table></body></html>"
-    );
-}
-
-/* function info()
-{
-    ob_start();
-    phpinfo();
-    return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean());
-}
- */

+ 0 - 145
frameworks/PHP/workerman/app.php

@@ -1,145 +0,0 @@
-<?php
-use Workerman\Protocols\Http\Response;
-use Workerman\Protocols\Http\Request;
-
-function init()
-{
-    global $world, $fortune, $update;
-    $pdo = new PDO(
-        'mysql:host=tfb-database;dbname=hello_world',
-        'benchmarkdbuser',
-        'benchmarkdbpass',
-        [
-            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
-            PDO::ATTR_EMULATE_PREPARES    => false
-        ]
-    );
-    $world   = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?');
-    $fortune = $pdo->prepare('SELECT id,message FROM Fortune');
-    $update  = $pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?');
-}
-
-function router(Request $request)
-{
-    return match($request->path()) {
-        '/plaintext' => text(),
-        '/json'      => json(), 
-        '/db'        => db(),
-        '/fortunes'  => fortune(),
-        '/query'     => query($request),
-        '/update'    => updateraw($request),
-        // '/info'      => info(),
-        default      => new Response(404, [], 'Error 404'),
-    };
-}
-
-function text()
-{
-    return new Response(200, [
-        'Content-Type' => 'text/plain',
-        'Date'         => Header::$date
-    ], 'Hello, World!');
-}
-
-function json()
-{
-    return new Response(200, [
-        'Content-Type' => 'application/json',
-        'Date'         => Header::$date
-    ], json_encode(['message' => 'Hello, World!']));
-}
-
-function db()
-{
-    global $world;
-
-    $world->execute([mt_rand(1, 10000)]);
-
-    return new Response(200, [
-        'Content-Type' => 'application/json',
-        'Date'         => Header::$date
-    ], json_encode($world->fetch()));
-}
-
-function query($request)
-{
-    global $world;
-
-    $query_count = 1;
-    $q = (int) $request->get('q');
-    if ($q > 1) {
-        $query_count = min($q, 500);
-    }
-
-    while ($query_count--) {
-        $world->execute([mt_rand(1, 10000)]);
-        $arr[] = $world->fetch();
-    }
-
-    return new Response(200, [
-        'Content-Type' => 'application/json',
-        'Date'         => Header::$date
-    ], json_encode($arr));
-}
-
-function updateraw($request)
-{
-    global $world, $update;
-
-    $query_count = 1;
-    $q = (int) $request->get('q');
-    if ($q > 1) {
-        $query_count = min($q, 500);
-    }
-
-    while ($query_count--) {
-        $id = mt_rand(1, 10000);
-        $world->execute([$id]);
-        $item = $world->fetch();
-        $update->execute(
-            [$item['randomNumber'] = mt_rand(1, 10000), $id]
-        );
-
-        $arr[] = $item;
-    }
-
-    // $pdo->beginTransaction();
-    // foreach($arr as $world) {
-    //     $update->execute([$world['randomNumber'], $world['id']]);
-    // }
-    // $pdo->commit();
-    return new Response(200, [
-        'Content-Type' => 'application/json',
-        'Date'         => Header::$date
-    ], json_encode($arr));
-}
-
-function fortune()
-{
-    global $fortune;
-
-    $fortune->execute();
-
-    $arr    = $fortune->fetchAll(PDO::FETCH_KEY_PAIR);
-    $arr[0] = 'Additional fortune added at request time.';
-    asort($arr);
-
-    $html = '';
-    foreach ($arr as $id => $message) {
-        $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
-        $html .= "<tr><td>$id</td><td>$message</td></tr>";
-    }
-
-    return new Response(200, [
-        'Date'         => Header::$date
-    ], "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>$html</table></body></html>"
-    );
-}
-
-/* function info()
-{
-    ob_start();
-    phpinfo();
-    return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean());
-}
- */

+ 88 - 0
frameworks/PHP/workerman/benchmark_config.json

@@ -107,6 +107,94 @@
       "display_name": "workerman [pgsql]",
       "notes": "",
       "versus": "php"
+    },
+    "pgsql-swow": {
+      "dockerfile": "workerman-pgsql-swow-jit.dockerfile",
+      "db_url": "/db",
+      "query_url": "/query?q=",
+      "update_url": "/update?q=",
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgres",
+      "framework": "workerman",
+      "language": "PHP",
+      "flavor": "PHP8",
+      "orm": "Raw",
+      "platform": "workerman",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "workerman [jit, pgsql, swow, async]",
+      "notes": "",
+      "versus": "php"
+    },
+    "mysql-swow": {
+      "dockerfile": "workerman-mysql-swow-jit.dockerfile",
+      "db_url": "/db",
+      "query_url": "/query?q=",
+      "update_url": "/update?q=",
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "workerman",
+      "language": "PHP",
+      "flavor": "PHP8",
+      "orm": "Raw",
+      "platform": "workerman",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "workerman [jit, mysql, swow, async]",
+      "notes": "",
+      "versus": "php"
+    },
+    "pgsql-swoole": {
+      "dockerfile": "workerman-pgsql-swoole-jit.dockerfile",
+      "db_url": "/db",
+      "query_url": "/query?q=",
+      "update_url": "/update?q=",
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgres",
+      "framework": "workerman",
+      "language": "PHP",
+      "flavor": "PHP8",
+      "orm": "Raw",
+      "platform": "workerman",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "workerman [jit, pgsql, swoole, async]",
+      "notes": "",
+      "versus": "php"
+    },
+    "mysql-swoole": {
+      "dockerfile": "workerman-mysql-swoole-jit.dockerfile",
+      "db_url": "/db",
+      "query_url": "/query?q=",
+      "update_url": "/update?q=",
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "workerman",
+      "language": "PHP",
+      "flavor": "PHP8",
+      "orm": "Raw",
+      "platform": "workerman",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "workerman [jit, mysql, swoole, async]",
+      "notes": "",
+      "versus": "php"
     }
   }]
 }

+ 5 - 0
frameworks/PHP/workerman/composer.json

@@ -1,5 +1,10 @@
 {
 	"require": {
 		"workerman/workerman": "dev-master"
+	},
+	"autoload": {
+		"psr-4": {
+			"": "./"
+		}
 	}
 }

+ 60 - 0
frameworks/PHP/workerman/config.toml

@@ -82,4 +82,64 @@ os = "Linux"
 orm = "Raw"
 platform = "workerman"
 webserver = "None"
+versus = "php"
+
+[pgsql-swow]
+urls.db = "/db"
+urls.query = "/query?q="
+urls.update = "/update?q="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Platform"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "workerman"
+webserver = "None"
+versus = "php"
+
+[mysql-swow]
+urls.db = "/db"
+urls.query = "/query?q="
+urls.update = "/update?q="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Platform"
+database = "MySQL"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "workerman"
+webserver = "None"
+versus = "php"
+
+[pgsql-swoole]
+urls.db = "/db"
+urls.query = "/query?q="
+urls.update = "/update?q="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Platform"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "workerman"
+webserver = "None"
+versus = "php"
+
+[mysql-swoole]
+urls.db = "/db"
+urls.query = "/query?q="
+urls.update = "/update?q="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Platform"
+database = "MySQL"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "workerman"
+webserver = "None"
 versus = "php"

+ 0 - 88
frameworks/PHP/workerman/dbraw.php

@@ -1,88 +0,0 @@
-<?php
-
-class DbRaw
-{
-    private static PDO $instance;
-    public static PDOStatement $db;
-    public static PDOStatement $fortune;
-    public static PDOStatement $random;
-    /**
-     * @var []PDOStatement
-     */
-    private static $update;
-
-    public static function init()
-    {
-        $pdo = new PDO(
-            'pgsql:host=tfb-database;dbname=hello_world',
-            'benchmarkdbuser',
-            'benchmarkdbpass',
-            [
-                PDO::ATTR_DEFAULT_FETCH_MODE  => PDO::FETCH_ASSOC,
-                PDO::ATTR_ERRMODE             => PDO::ERRMODE_EXCEPTION,
-                PDO::ATTR_EMULATE_PREPARES    => false
-            ]
-        );
-
-        self::$fortune   = $pdo->prepare('SELECT id,message FROM Fortune');
-        self::$random    = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id = ?');
-        self::$instance  = $pdo;
-    }
-
-    /**
-     * Postgres bulk update
-     *
-     * @param array $worlds
-     * @return void
-     */
-    public static function update(array $worlds)
-    {
-        $rows = count($worlds);
-
-        if (!isset(self::$update[$rows])) {
-            $sql = 'UPDATE world SET randomNumber = CASE id'
-                . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows)
-                . 'END WHERE id IN ('
-                . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)';
-
-            self::$update[$rows] = self::$instance->prepare($sql);
-        }
-
-        $val = [];
-        $keys = [];
-        foreach ($worlds as $world) {
-            $val[] = $keys[] = $world['id'];
-            $val[] = $world['randomNumber'];
-        }
-
-        self::$update[$rows]->execute([...$val, ...$keys]);
-    }
-
-    /**
-     * Alternative bulk update in Postgres
-     *
-     * @param array $worlds
-     * @return void
-     */
-    public static function update2(array $worlds)
-    {
-        $rows = count($worlds);
-
-        if (!isset(self::$update[$rows])) {
-            $sql = 'UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES '
-                . implode(', ', array_fill(0, $rows, '(?::INTEGER, ?::INTEGER)')) .
-                ' ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id';
-
-            self::$update[$rows] = self::$instance->prepare($sql);
-        }
-
-        $val = [];
-        foreach ($worlds as $world) {
-            $val[] = $world['id'];
-            $val[] = $world['randomNumber'];
-            //$update->bindParam(++$i, $world['id'], PDO::PARAM_INT);
-        }
-
-        self::$update[$rows]->execute($val);
-    }
-}

+ 71 - 26
frameworks/PHP/workerman/server.php

@@ -2,37 +2,82 @@
 require_once __DIR__.'/vendor/autoload.php';
 
 use Workerman\Worker;
-use Workerman\Timer;
+use Workerman\Events\Swow;
+use Workerman\Events\Swoole;
+use Workerman\Events\Select;
+use Workerman\Protocols\Http\Response;
 
 $test_type = getenv('TEST_TYPE') ?: 'default';
-if ($test_type === 'pgsql') {
-    require_once __DIR__.'/app-pg.php';
-} else {
-    require_once __DIR__.'/app.php';
-}
-$process_count = (int) shell_exec('nproc') * ($test_type === 'default' ? 1 : 4);
+$process = getenv('PROCESS_MULTIPLIER') ?: 1;
+$pool_size = getenv('POOL_SIZE') ?: 2;
+$process_count = (int) shell_exec('nproc') * $process;
 
-$http_worker                = new Worker('http://0.0.0.0:8080');
-$http_worker->reusePort = true;
-$http_worker->count         = $process_count;
-$http_worker->onWorkerStart = static function () use ($test_type) {
-    Header::$date = gmdate('D, d M Y H:i:s').' GMT';
-    Timer::add(1, function() {
-        Header::$date = gmdate('D, d M Y H:i:s').' GMT';
-    });
-    if ($test_type === 'pgsql') {
-        DbRaw::init();
-    } else {
-        init();
-    }
+$db = $date = null;
+$http_worker = new Worker('http://0.0.0.0:8080');
+//$http_worker->reusePort = true;
+$http_worker->count = $process_count;
+$http_worker->onWorkerStart = static function () use ($test_type, $pool_size, &$db, &$date) {
+    $db = match ($test_type) {
+        'pgsql' => new Pgsql(),
+        'mysql' => new Mysql(),
+        'pgsql-swow' => new PgsqlSwow($pool_size),
+        'mysql-swow' => new MysqlSwow($pool_size),
+        'pgsql-swoole' => new PgsqlSwoole($pool_size),
+        'mysql-swoole' => new MysqlSwoole($pool_size),
+        'default' => new Mysql(),
+    };
+    $date = new Date();
 };
+if ($test_type === 'default') {
+    Worker::$eventLoopClass = Select::class;
+} elseif (in_array($test_type, ['pgsql-swow', 'mysql-swow'])) {
+    Worker::$eventLoopClass = Swow::class;
+} elseif (in_array($test_type, ['pgsql-swoole', 'mysql-swoole'])) {
+    Worker::$eventLoopClass = Swoole::class;
+}
 
-$http_worker->onMessage = static function ($connection, $request) {
-    $connection->send(router($request));
+$http_worker->onMessage = static function ($connection, $request) use (&$db, &$date) {
+    switch ($request->path()) {
+        case '/plaintext':
+            $connection->headers = [
+                'Content-Type' => 'text/plain',
+                'Date' => $date->date
+            ];
+            return $connection->send('Hello, World!');
+        case '/json':
+            $connection->headers = [
+                'Content-Type' => 'application/json',
+                'Date' => $date->date
+            ];
+            return $connection->send(json_encode(['message' => 'Hello, World!']));
+        case '/db':
+            $connection->headers = [
+                'Content-Type' => 'application/json',
+                'Date' => $date->date
+            ];
+            return $connection->send(json_encode($db->db()));
+        case '/fortunes':
+            $connection->headers = [
+                'Date' => $date->date
+            ];
+            return $connection->send($db->fortune());
+        case '/query':
+            $connection->headers = [
+                'Content-Type' => 'application/json',
+                'Date' => $date->date
+            ];
+            return $connection->send(json_encode($db->query($request)));
+        case '/update':
+            $connection->headers = [
+                'Content-Type' => 'application/json',
+                'Date' => $date->date
+            ];
+            return $connection->send(json_encode($db->update($request)));
+    }
+    return $connection->send(new Response(404, [
+        'Content-Type' => 'text/plain',
+        'Date' => $date->date
+    ], '404 Not Found'));
 };
 
 Worker::runAll();
-
-class Header {
-    public static $date = null;
-}

+ 1 - 0
frameworks/PHP/workerman/workerman-jit.dockerfile

@@ -1,6 +1,7 @@
 FROM ubuntu:24.04
 
 ENV TEST_TYPE default
+ENV PROCESS_MULTIPLIER 1
 
 ARG DEBIAN_FRONTEND=noninteractive
 

+ 1 - 0
frameworks/PHP/workerman/workerman-mysql-jit.dockerfile

@@ -1,6 +1,7 @@
 FROM ubuntu:24.04
 
 ENV TEST_TYPE mysql
+ENV PROCESS_MULTIPLIER 4
 
 ARG DEBIAN_FRONTEND=noninteractive
 

+ 34 - 0
frameworks/PHP/workerman/workerman-mysql-swoole-jit.dockerfile

@@ -0,0 +1,34 @@
+FROM ubuntu:24.04
+
+ENV TEST_TYPE mysql-swoole
+ENV SWOOLE_VERSION 5.1.5
+ENV PROCESS_MULTIPLIER 1
+ENV POOL_SIZE 4
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt update -yqq > /dev/null \
+    && apt install -yqq software-properties-common > /dev/null \
+    && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \
+    && apt update -yqq > /dev/null \
+    && apt install libbrotli-dev php8.3-cli php8.3-pdo-mysql php8.3-dev php8.3-mbstring git -y > /dev/null \
+    && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \
+    && cd /tmp/swoole-src-${SWOOLE_VERSION} \
+    && phpize > /dev/null \
+    && ./configure > /dev/null \
+    && make -j "$(nproc)" > /dev/null \
+    && make install > /dev/null \
+    && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \
+    && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini
+
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
+
+WORKDIR /workerman
+COPY --link . .
+
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet
+COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini
+
+EXPOSE 8080
+
+CMD php /workerman/server.php start

+ 33 - 0
frameworks/PHP/workerman/workerman-mysql-swow-jit.dockerfile

@@ -0,0 +1,33 @@
+FROM ubuntu:24.04
+
+ENV TEST_TYPE mysql-swow
+ENV PROCESS_MULTIPLIER 1
+ENV POOL_SIZE 4
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null
+RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
+    apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null
+
+RUN apt-get install -yqq php8.3-cli php8.3-mysql php8.3-xml > /dev/null
+
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
+
+RUN apt-get install -y php-pear php8.3-dev git > /dev/null
+
+
+WORKDIR /workerman
+COPY --link . .
+
+
+RUN composer require swow/swow > /dev/null
+RUN ./vendor/bin/swow-builder --install > /dev/null
+RUN echo extension=swow.so >  /etc/php/8.3/cli/conf.d/20-swow.ini
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet
+COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini
+
+EXPOSE 8080
+
+
+CMD php /workerman/server.php start

+ 1 - 0
frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile

@@ -1,6 +1,7 @@
 FROM ubuntu:24.04
 
 ENV TEST_TYPE pgsql
+ENV PROCESS_MULTIPLIER 4
 
 ARG DEBIAN_FRONTEND=noninteractive
 

+ 34 - 0
frameworks/PHP/workerman/workerman-pgsql-swoole-jit.dockerfile

@@ -0,0 +1,34 @@
+FROM ubuntu:24.04
+
+ENV TEST_TYPE pgsql-swoole
+ENV SWOOLE_VERSION 5.1.5
+ENV PROCESS_MULTIPLIER 2
+ENV POOL_SIZE 16
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt update -yqq > /dev/null \
+    && apt install -yqq software-properties-common > /dev/null \
+    && LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null \
+    && apt update -yqq > /dev/null \
+    && apt install libbrotli-dev php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev php8.3-mbstring git -y > /dev/null \
+    && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \
+    && cd /tmp/swoole-src-${SWOOLE_VERSION} \
+    && phpize > /dev/null \
+    && ./configure --enable-swoole-pgsql > /dev/null \
+    && make -j "$(nproc)" > /dev/null \
+    && make install > /dev/null \
+    && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \
+    && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini
+
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
+
+WORKDIR /workerman
+COPY --link . .
+
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet
+COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini
+
+EXPOSE 8080
+
+CMD php /workerman/server.php start

+ 33 - 0
frameworks/PHP/workerman/workerman-pgsql-swow-jit.dockerfile

@@ -0,0 +1,33 @@
+FROM ubuntu:24.04
+
+ENV TEST_TYPE pgsql-swow
+ENV PROCESS_MULTIPLIER 2
+ENV POOL_SIZE 16
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /dev/null
+RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \
+    apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null
+
+RUN apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null
+
+COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer
+
+RUN apt-get install -y php-pear php8.3-dev git > /dev/null
+
+
+WORKDIR /workerman
+COPY --link . .
+
+
+RUN composer require swow/swow > /dev/null
+RUN ./vendor/bin/swow-builder --install > /dev/null
+RUN echo extension=swow.so >  /etc/php/8.3/cli/conf.d/20-swow.ini
+RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet
+COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini
+
+EXPOSE 8080
+
+
+CMD php /workerman/server.php start

+ 1 - 0
frameworks/PHP/workerman/workerman-pgsql.dockerfile

@@ -1,6 +1,7 @@
 FROM ubuntu:24.04
 
 ENV TEST_TYPE pgsql
+ENV PROCESS_MULTIPLIER 4
 
 ARG DEBIAN_FRONTEND=noninteractive
 

+ 1 - 0
frameworks/PHP/workerman/workerman.dockerfile

@@ -1,6 +1,7 @@
 FROM ubuntu:24.04
 
 ENV TEST_TYPE default
+ENV PROCESS_MULTIPLIER 1
 
 ARG DEBIAN_FRONTEND=noninteractive