Skip to content

Commit b90dbcf

Browse files
committed
Add parallel benchmark using AMP async framework
1 parent 4dc5cd6 commit b90dbcf

File tree

5 files changed

+58
-29
lines changed

5 files changed

+58
-29
lines changed

.github/workflows/benchmark.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,15 @@ jobs:
6464
- name: "Install dependencies with Composer"
6565
uses: "ramsey/[email protected]"
6666
with:
67-
composer-options: "--no-suggest"
67+
composer-options: "--no-suggest --working-dir=./benchmark"
6868

6969
- name: "Run phpbench"
70+
working-directory: "./benchmark"
7071
run: "vendor/bin/phpbench run --report=aggregate --report=bar_chart_time --report=env --output html"
7172

7273
- name: Upload HTML report
7374
uses: actions/upload-artifact@v3
7475
with:
7576
name: phpbench-${{ github.sha }}.html
76-
path: .phpbench/html/index.html
77+
path: ./benchmark/.phpbench/html/index.html
7778
retention-days: 3

benchmark/DriverBench/ParallelBench.php

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace MongoDB\Benchmark\DriverBench;
44

5+
use Amp\Parallel\Worker\DefaultPool;
56
use Generator;
67
use MongoDB\Benchmark\Fixtures\Data;
78
use MongoDB\Benchmark\Utils;
@@ -14,7 +15,8 @@
1415
use PhpBench\Attributes\Revs;
1516
use RuntimeException;
1617

17-
use function array_chunk;
18+
use function Amp\ParallelFunctions\parallelMap;
19+
use function Amp\Promise\wait;
1820
use function array_map;
1921
use function ceil;
2022
use function count;
@@ -68,8 +70,6 @@ public static function afterClass(): void
6870
/**
6971
* Parallel: LDJSON multi-file import
7072
* Using single thread
71-
*
72-
* @see https://github.com/mongodb/specifications/blob/ddfc8b583d49aaf8c4c19fa01255afb66b36b92e/source/benchmarking/benchmarking.rst#ldjson-multi-file-import
7373
*/
7474
#[BeforeMethods('beforeMultiFileImport')]
7575
#[Revs(1)]
@@ -85,16 +85,15 @@ public function benchMultiFileImport(): void
8585
* Parallel: LDJSON multi-file import
8686
* Using multiple forked threads
8787
*
88-
* @see https://github.com/mongodb/specifications/blob/ddfc8b583d49aaf8c4c19fa01255afb66b36b92e/source/benchmarking/benchmarking.rst#ldjson-multi-file-import
8988
* @param array{processes:int, files:string[], batchSize:int} $params
9089
*/
9190
#[BeforeMethods('beforeMultiFileImport')]
92-
#[ParamProviders(['provideProcessesParameter', 'provideMultiFileImportParameters'])]
91+
#[ParamProviders(['provideProcessesParameter'])]
9392
#[Revs(1)]
9493
public function benchMultiFileImportFork(array $params): void
9594
{
9695
$pids = [];
97-
foreach ($params['files'] as $files) {
96+
foreach (self::getFileNames() as $file) {
9897
// Wait for a child process to finish if we have reached the maximum number of processes
9998
if (count($pids) >= $params['processes']) {
10099
$pid = pcntl_waitpid(-1, $status);
@@ -107,11 +106,7 @@ public function benchMultiFileImportFork(array $params): void
107106
// If we don't reset, we will get the same manager client_zval in the child process
108107
// and share the libmongoc client.
109108
Utils::reset();
110-
$collection = Utils::getCollection();
111-
112-
foreach ($files as $file) {
113-
self::importFile($file, $collection);
114-
}
109+
self::importFile($file, Utils::getCollection());
115110

116111
// Exit the child process
117112
exit(0);
@@ -132,21 +127,31 @@ public function benchMultiFileImportFork(array $params): void
132127
}
133128
}
134129

135-
public static function provideProcessesParameter(): Generator
130+
/**
131+
* Parallel: LDJSON multi-file import
132+
* Using amphp/parallel-functions with worker pool
133+
*
134+
* @param array{processes:int, files:string[], batchSize:int} $params
135+
*/
136+
#[BeforeMethods('beforeMultiFileImport')]
137+
#[ParamProviders(['provideProcessesParameter'])]
138+
#[Revs(1)]
139+
public function benchMultiFileImportAmp(array $params): void
136140
{
137-
// Max number of forked processes
138-
for ($i = 1; $i <= 30; $i = (int) ceil($i * 1.25)) {
139-
yield $i . 'fork' => ['processes' => $i];
140-
}
141+
wait(parallelMap(
142+
self::getFileNames(),
143+
// Uses array callable instead of closure to skip complex serialization
144+
[self::class, 'importFile'],
145+
// The pool size is the number of processes
146+
new DefaultPool($params['processes']),
147+
));
141148
}
142149

143-
public static function provideMultiFileImportParameters(): Generator
150+
public static function provideProcessesParameter(): Generator
144151
{
145-
$files = self::getFileNames();
146-
147-
// Chunk of file names to be handled by each processes
148-
for ($i = 1; $i <= 10; $i += 3) {
149-
yield 'by ' . $i => ['files' => array_chunk($files, $i)];
152+
// Max number of forked processes
153+
for ($i = 1; $i <= 30; $i = (int) ceil($i * 1.25)) {
154+
yield $i . ' proc' => ['processes' => $i];
150155
}
151156
}
152157

@@ -166,8 +171,10 @@ public function afterMultiFileImport(): void
166171
unset($this->files);
167172
}
168173

169-
private static function importFile(string $file, Collection $collection): void
174+
public static function importFile(string $file, ?Collection $collection = null): void
170175
{
176+
$collection ??= Utils::getCollection();
177+
171178
// Read file contents into BSON documents
172179
$docs = array_map(
173180
static fn (string $line) => Document::fromJSON($line),
@@ -186,8 +193,7 @@ private static function getFileNames(): array
186193

187194
return array_map(
188195
static fn (int $i) => sprintf('%s/%03d.txt', $tempDir, $i),
189-
//range(0, 99),
190-
range(0, 5),
196+
range(0, 99),
191197
);
192198
}
193199
}

benchmark/composer.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "mongodb/mongodb-benchmark",
3+
"type": "project",
4+
"repositories": [
5+
{
6+
"type": "path",
7+
"url": "../"
8+
}
9+
],
10+
"require": {
11+
"php": ">=8.1",
12+
"amphp/parallel-functions": "^1.1",
13+
"mongodb/mongodb": "@dev",
14+
"phpbench/phpbench": "^1.2"
15+
},
16+
"autoload": {
17+
"psr-4": {
18+
"MongoDB\\Benchmark\\": "./"
19+
}
20+
},
21+
"scripts": {
22+
"benchmark": "phpbench run --report=aggregate"
23+
}
24+
}
File renamed without changes.

composer.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
},
2222
"require-dev": {
2323
"doctrine/coding-standard": "^11.1",
24-
"phpbench/phpbench": "^1.2",
2524
"rector/rector": "^0.16.0",
2625
"squizlabs/php_codesniffer": "^3.7",
2726
"symfony/phpunit-bridge": "^5.2",
@@ -39,7 +38,6 @@
3938
"files": [ "tests/PHPUnit/Functions.php" ]
4039
},
4140
"scripts": {
42-
"benchmark": "phpbench run --report=aggregate",
4341
"checks": [
4442
"@check:cs",
4543
"@check:psalm",

0 commit comments

Comments
 (0)