Skip to content
Merged
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
11 changes: 11 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@ composer ic:bench:quick
composer ic:bench:chart
```

The default PHPForge commands intentionally exclude release stress workloads.
Run those explicitly, with their declared single-revolution settings:

```bash
vendor/bin/phpbench run benchmarks/stress/ReleaseStress.php --bootstrap=vendor/autoload.php
```

The 10,000-job file-queue subject is a limit-finding workload and can take
several minutes. It must not be combined with the quick suite's global
revolution and iteration overrides.

Performance claims must include reproducible before-and-after results from comparable environments. Avoid conclusions based on a single unstable run.

Add or update benchmark coverage when existing benchmarks do not represent the changed execution path.
Expand Down
82 changes: 31 additions & 51 deletions benchmarks/ReleaseWorkloadsBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,12 @@ public function tearDown(): void

public function benchChunkAssembly100(): void
{
$this->benchmarkChunkAssembly(100);
}

public function benchChunkAssembly1000ReverseArrival(): void
{
$this->benchmarkChunkAssembly(1_000, true);
$this->runChunkAssembly(100);
}

public function benchQueue100(): void
{
$this->benchmarkQueue(100);
}

public function benchQueue1000(): void
{
$this->benchmarkQueue(1_000);
}

public function benchQueue10000(): void
{
$this->benchmarkQueue(10_000);
$this->runQueueWorkload(100);
}

public function benchReader128KiB(): void
Expand All @@ -83,35 +68,51 @@ public function benchReader8KiB(): void

public function benchSyncChecksum1000Files(): void
{
$this->benchmarkSync(SyncComparison::CHECKSUM);
$this->runSyncWorkload(SyncComparison::CHECKSUM);
}

public function benchSyncSize1000Files(): void
{
$this->benchmarkSync(SyncComparison::SIZE);
$this->runSyncWorkload(SyncComparison::SIZE);
}

public function benchSyncSizeAndModifiedTime1000Files(): void
{
$this->benchmarkSync(SyncComparison::SIZE_AND_MODIFIED_TIME);
$this->runSyncWorkload(SyncComparison::SIZE_AND_MODIFIED_TIME);
}

public function benchTransactionHundredUpdates(): void
public function benchTransactionOneUpdate(): void
{
$this->benchmarkTransaction(100);
$this->runTransactionWorkload(1);
}

public function benchTransactionOneUpdate(): void
public function benchTransactionTenUpdates(): void
{
$this->benchmarkTransaction(1);
$this->runTransactionWorkload(10);
}

public function benchTransactionTenUpdates(): void
private function consumeReader(int $chunkSize): void
{
$this->createLargeFile();
foreach ((new SafeFileReader($this->largeFile))->chunks($chunkSize) as $chunk) {
strlen($chunk);
}

$download = new DownloadProcessor();
$download->setChunkSize($chunkSize);
$output = fopen('php://temp', 'w+b');
if (is_resource($output)) {
$download->streamDownload($this->largeFile, $output);
fclose($output);
}
}

private function createLargeFile(): void
{
$this->benchmarkTransaction(10);
FlysystemHelper::write($this->largeFile, str_repeat('0123456789abcdef', 512 * 1024));
}

private function benchmarkChunkAssembly(int $chunks, bool $reverse = false): void
private function runChunkAssembly(int $chunks, bool $reverse = false): void
{
$uploadDirectory = PathHelper::join($this->baseDirectory, 'uploads-' . $chunks);
$temporaryDirectory = PathHelper::join($this->baseDirectory, 'chunks-' . $chunks);
Expand All @@ -134,7 +135,7 @@ private function benchmarkChunkAssembly(int $chunks, bool $reverse = false): voi
$uploader->finalizeChunkUpload("bench_{$chunks}");
}

private function benchmarkQueue(int $jobs): void
private function runQueueWorkload(int $jobs): void
{
$queue = new FileJobQueue(PathHelper::join($this->baseDirectory, "queue-{$jobs}.json"), maxJobs: $jobs);
for ($index = 0; $index < $jobs; $index++) {
Expand All @@ -143,7 +144,7 @@ private function benchmarkQueue(int $jobs): void
$queue->process(static function (): void {});
}

private function benchmarkSync(SyncComparison $comparison): void
private function runSyncWorkload(SyncComparison $comparison): void
{
FlysystemHelper::createDirectory($this->sourceDirectory);
for ($index = 0; $index < 1_000; $index++) {
Expand All @@ -156,7 +157,7 @@ private function benchmarkSync(SyncComparison $comparison): void
(new DirectoryOperations($this->sourceDirectory))->syncTo($target, true, null, $comparison);
}

private function benchmarkTransaction(int $updates): void
private function runTransactionWorkload(int $updates): void
{
$this->createLargeFile();
$path = PathHelper::join($this->baseDirectory, "transaction-{$updates}.bin");
Expand All @@ -167,25 +168,4 @@ private function benchmarkTransaction(int $updates): void
}
});
}

private function consumeReader(int $chunkSize): void
{
$this->createLargeFile();
foreach ((new SafeFileReader($this->largeFile))->chunks($chunkSize) as $chunk) {
strlen($chunk);
}

$download = new DownloadProcessor();
$download->setChunkSize($chunkSize);
$output = fopen('php://temp', 'w+b');
if (is_resource($output)) {
$download->streamDownload($this->largeFile, $output);
fclose($output);
}
}

private function createLargeFile(): void
{
FlysystemHelper::write($this->largeFile, str_repeat('0123456789abcdef', 512 * 1024));
}
}
88 changes: 88 additions & 0 deletions benchmarks/stress/ReleaseStress.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

namespace Infocyph\Pathwise\Benchmarks\Stress;

use Infocyph\Pathwise\FileManager\FileOperations;
use Infocyph\Pathwise\Queue\FileJobQueue;
use Infocyph\Pathwise\StreamHandler\UploadProcessor;
use Infocyph\Pathwise\Utils\FlysystemHelper;
use Infocyph\Pathwise\Utils\PathHelper;
use PhpBench\Attributes as Bench;

/**
* Explicit stress workloads excluded from PHPForge's default *Bench.php scan.
*
* Run with:
* vendor/bin/phpbench run benchmarks/stress/ReleaseStress.php --bootstrap=vendor/autoload.php
*/
#[Bench\Iterations(1)]
#[Bench\Revs(1)]
#[Bench\BeforeMethods(['setUp'])]
#[Bench\AfterMethods(['tearDown'])]
final class ReleaseStress
{
private string $baseDirectory;

public function setUp(): void
{
$this->baseDirectory = PathHelper::join(sys_get_temp_dir(), 'pathwise_release_stress_' . uniqid('', true));
}

public function tearDown(): void
{
if (FlysystemHelper::directoryExists($this->baseDirectory)) {
FlysystemHelper::deleteDirectory($this->baseDirectory);
}
}

public function benchChunkAssembly1000ReverseArrival(): void
{
$uploadDirectory = PathHelper::join($this->baseDirectory, 'uploads');
$temporaryDirectory = PathHelper::join($this->baseDirectory, 'chunks');
$uploader = new UploadProcessor();
$uploader->setDirectorySettings($uploadDirectory, false, $temporaryDirectory);
for ($index = 999; $index >= 0; $index--) {
$part = PathHelper::join($this->baseDirectory, "part-{$index}.tmp");
FlysystemHelper::write($part, 'x');
$uploader->processChunkUpload([
'error' => UPLOAD_ERR_OK,
'size' => 1,
'tmp_name' => $part,
'name' => basename($part),
], 'stress_1000', $index, 1_000, 'assembled.txt');
}
$uploader->finalizeChunkUpload('stress_1000');
}

public function benchQueue1000(): void
{
$this->runQueueWorkload(1_000);
}

public function benchQueue10000(): void
{
$this->runQueueWorkload(10_000);
}

public function benchTransactionHundredUpdates(): void
{
$path = PathHelper::join($this->baseDirectory, 'transaction-100.bin');
FlysystemHelper::write($path, str_repeat('0123456789abcdef', 512 * 1024));
(new FileOperations($path))->transaction(static function (FileOperations $operations): void {
for ($index = 0; $index < 100; $index++) {
$operations->update(str_repeat((string) ($index % 10), 8 * 1024 * 1024));
}
});
}

private function runQueueWorkload(int $jobs): void
{
$queue = new FileJobQueue(PathHelper::join($this->baseDirectory, "queue-{$jobs}.json"), maxJobs: $jobs);
for ($index = 0; $index < $jobs; $index++) {
$queue->enqueue('benchmark', ['index' => $index]);
}
$queue->process(static function (): void {});
}
}
Loading