PHP Classes

File: bench/run.php

Recommend this page to a friend!
  Packages of Roni   Easy-Excel   bench/run.php   Download  
File: bench/run.php
Role: Example script
Content type: text/plain
Description: Example script
Class: Easy-Excel
Export and read XLSX files with a PHP Go extension
Author: By
Last change:
Date: 7 days ago
Size: 4,371 bytes
 

Contents

Class file image Download
<?php

declare(strict_types=1);

/*
 * Benchmark runner. One library + workload per process so peak memory is
 * honest. Emits a CSV line:
 *
 * lib,workload,rows,wall_seconds,peak_mem_bytes,peak_rss_bytes,file_bytes
 *
 * peak_mem_bytes is the Zend allocator's peak; peak_rss_bytes is the whole
 * process's VmHWM, which also counts memory PHP can't see (the easy-excel
 * Go/cgo heap, excelize buffers). Includes interpreter startup ? identical
 * per lane, so cross-library comparison stays fair.
 *
 * Usage:
 * php run.php <lib> <workload> [rows]
 * lib: easy-excel | easy-excel-native | phpspreadsheet | openspout | fast-excel-writer | rap2hpoutre
 * workload: write | read
 *
 * `write` produces rows x 10 mixed columns (string/int/float/date string).
 * `read` consumes the file produced by a prior `write` of the same lib
 * (or bench.xlsx if present), counting cells.
 * `write-styled` is `write` plus a styled header, two column number formats,
 * column widths, freeze pane and auto-filter ? the typical report
 * (phpspreadsheet and easy-excel only; both run the identical code through
 * the PhpSpreadsheet API surface).
 */

require __DIR__ . '/vendor/autoload.php';

$lib = $argv[1] ?? null;
$workload = $argv[2] ?? 'write';
$rows = (int) ($argv[3] ?? 100_000);
$file = \sys_get_temp_dir() . "/bench-$lib.xlsx";

$adapters = require __DIR__ . '/adapters.php';
if (!isset(
$adapters[$lib])) {
    \
fwrite(STDERR, 'usage: php run.php <' . \implode('|', \array_keys($adapters)) . "> <write|read> [rows]\n");
    exit(
2);
}
if (!isset(
$adapters[$lib][$workload])) {
    \
fwrite(STDERR, "$lib does not support workload $workload\n");
    exit(
2);
}

/** @return iterable<list<mixed>> deterministic mixed-type rows, generated lazily */
function benchRows(int $count): iterable
{
    for (
$i = 1; $i <= $count; ++$i) {
        yield [
           
"customer-$i",
           
'SKU-' . ($i % 1000),
           
$i,
            \
round($i * 1.37, 2),
           
$i % 2 === 0 ? 'paid' : 'open',
           
'2026-' . \str_pad((string) (($i % 12) + 1), 2, '0', STR_PAD_LEFT) . '-15',
           
$i * 3,
            \
round($i / 7, 4),
           
'note text for row ' . $i,
           
$i % 5,
        ];
    }
}

/**
 * Identical styled-report workload across PhpSpreadsheet-compatible APIs;
 * $spreadsheet/$writer come from either library.
 */
function benchStyledWrite(object $spreadsheet, string $writerClass, string $file, int $rows): void
{
   
$ws = $spreadsheet->getActiveSheet();
   
$last = $rows + 1;
   
$ws->getStyle('A1:J1')->applyFromArray([
       
'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']],
       
'fill' => ['fillType' => 'solid', 'startColor' => ['rgb' => '4472C4']],
       
'borders' => ['allBorders' => ['borderStyle' => 'thin']],
       
'alignment' => ['horizontal' => 'center'],
    ]);
   
$ws->getStyle("D2:D$last")->getNumberFormat()->setFormatCode('#,##0.00');
   
$ws->getStyle("H2:H$last")->getNumberFormat()->setFormatCode('0.0000');
   
$ws->getColumnDimension('A')->setWidth(24);
   
$ws->getColumnDimension('I')->setWidth(32);
   
$ws->getRowDimension(1)->setRowHeight(22);
   
$ws->freezePane('A2');

   
$ws->fromArray([['Customer', 'SKU', 'Qty', 'Price', 'Status', 'Date', 'Total', 'Ratio', 'Note', 'Bucket']]);
   
$chunk = [];
   
$at = 2;
    foreach (
benchRows($rows) as $row) {
       
$chunk[] = $row;
        if (\
count($chunk) === 2048) {
           
$ws->fromArray($chunk, null, 'A' . $at, true);
           
$at += 2048;
           
$chunk = [];
        }
    }
    if (
$chunk) {
       
$ws->fromArray($chunk, null, 'A' . $at, true);
    }
   
$ws->setAutoFilter("A1:J$last");
    (new
$writerClass($spreadsheet))->save($file);
   
$spreadsheet->disconnectWorksheets();
}

/** Whole-process peak RSS in bytes (VmHWM high-water mark; Linux only, 0 elsewhere). */
function peakRss(): int
{
    \
preg_match('/^VmHWM:\s+(\d+)\s+kB/m', (string) @\file_get_contents('/proc/self/status'), $m);

    return (int) (
$m[1] ?? 0) * 1024;
}

\
gc_collect_cycles();
$t0 = \hrtime(true);
$result = $adapters[$lib][$workload]($file, $rows);
$wall = (\hrtime(true) - $t0) / 1e9;
$peak = \memory_get_peak_usage(true);
$size = \is_file($file) ? \filesize($file) : 0;

\
printf("%s,%s,%d,%.3f,%d,%d,%d\n", $lib, $workload, $workload === 'read' ? (int) $result : $rows, $wall, $peak, peakRss(), $size);