shuchkin / simplexlsxgen

Export data to Excel. PHP XLSX generator
MIT License
988 stars 201 forks source link

Hi, is good test performance add in README.md #29

Open EOM opened 3 years ago

EOM commented 3 years ago
Hi ;) Is good add test de performance in README.md Example rows time memory
50000 ?.?s ?MB
100000 ?.?s ?MB
150000 ?.?s ?MB
200000 ?.?s ?MB
250000 ?.?s ?MB

Simil to report https://github.com/mk-j/PHP_XLSXWriter

xaviermdq commented 1 year ago

I think a speed and memory usage test would not be very useful in absolute terms: it depends on PC speed, PHP version, operating system, system load, etc, etc. A more useful benchmark is to make a comparative test between the different classes under the same conditions. Or benchmarking of the same class by making internal changes to optimize speed and/or memory usage (make a certain block of code one way or another, make certain functions or variables static, or change a function to a variable when we need data convertions, or vice-versa, etc.). I did a test comparing the class you mentioned, mk-j (which, by the way, has low activity: there are many pull requests and issues pending), and simplexlsxgen. But first a brief explanation. The way the two classes work are slightly different:

1 : the entire sheet is an array where each element represents a row and each element, in turn, is another array whose elements represent the columns 2 : row is an array where each element represents a column

PHP_XLSXWriter format 1, use format 2 with each element of the data passed. From this, it follows that a proper comparison of classes is achieved using format 1 of PHP_XLSWriter. To get the data generation out of the measurement, I first generate the data, get time/memory state, create object, load data, get state again, call the file generator method, and get state again. From the tests carried out, it is concluded that:

The code used for benchmarking is:

<?php
ini_set('memory_limit', '512M');
set_time_limit(240);
require_once 'simplexlsxgen.php';
require_once 'xlsxwriter.php';

//Init
$testrepetition = 4;
$testrows = [50000, 100000, 150000, 200000];
$testsuite = [];
for ($i = 0; $i < count($testrows); $i++) $testsuite[$testrows[$i]] = [
    'data' => [], 'shuchkin' => [], 'mkj' => []
];

//Data generation
foreach ($testsuite as $rows => &$d) {
    $d['data'] = [];
    for ($i=0; $i<$rows; $i++) $d['data'][] = [$i, $i + 1, $i + 2, $i + 3];
}
unset($d);

function Test($class, &$data, $out = true) {
    $rows = count($data);
    $cols = count($data[0]);
    $filename = __FUNCTION__ . " {$rows}.xlsx";
    @unlink($filename);
    if ($out) echo "<pre><b>Testing with a {$rows}&times;{$cols} sheet...</b>\r\n";
    switch ($class) {
    case 'Shuchkin':
        $time1 = microtime(true);
        $mem1 = memory_get_usage();
        $xlsx = new SimpleXLSXGen2();
        $xlsx->addSheet($data, 'Test Sheet');
        $time2 = microtime(true);
        $mem2 = memory_get_usage();
        $xlsx->saveAs($filename);
        $time3 = microtime(true);
        $mem3 = memory_get_usage();
        break;
    case 'MKJ':
        $time1 = microtime(true);
        $mem1 = memory_get_usage();
        $xlsx = new XLSXWriter();
        $xlsx->writeSheet($data);
        $time2 = microtime(true);
        $mem2 = memory_get_usage();
        $xlsx->writeToFile($filename);
        $time3 = microtime(true);
        $mem3 = memory_get_usage();
        break;
    }
    if ($out) echo "
<table>
<thead><tr><th></th><th>Creation</th><th>Saving</th><th>Total</th></tr></thead>
<tbody>
    <tr><td>Time [us]</td><td>" . sprintf("%.0f", round(($time2-$time1)*1000000)) . "</td><td>" . sprintf("%.0f", round(($time3-$time2)*1000000)) . "</td><td>" . sprintf("%6.0f", round(($time3-$time1)*1000000)) . "</td></tr>
    <tr><td>Memory [KB]</td><td>" . sprintf("%.2f", ($mem2-$mem1)/1024) . "</td><td>" . sprintf("%.2f", ($mem3-$mem2)/1024) . "</td><td>" . sprintf("%.2f", ($mem3-$mem1)/1024) . "</td></tr>
</tbody>
</table>
</pre>";
    return [round(($time3-$time1)*1000000), ($mem3-$mem1)/1024];
}
?><!DOCTYPE html>
<html>
<head>
<style>
th,td {border: 1px solid black}
th {background: #AAA}
</style>
</head>
<body>
<h1>shuchkin / simplexlsxgen</h1>
<?php
foreach ($testsuite as $rows => &$d) {
    Test('Shuchkin', $d['data']);
    $tsum = $msum = 0.0;
    for ($i = 0 ; $i < $testrepetition ; $i++) {
        $res = Test('Shuchkin', $d['data'], false);
        $tsum += $res[0];
        $msum += $res[1];
    }
    $d['shuchkin'] = [sprintf("%.3f", ($tsum/$testrepetition)/1000), sprintf("%.2f", $msum/$testrepetition)];
}
unset($d);
?>
<table>
<thead>
    <tr><th>Rows</th><th>Time [ms]</th><th>Memory [KiB]</th></tr>
</thead>
<tbody>
<?php
foreach ($testsuite as $rows => $d) {
    echo "<tr><td>{$rows}</td><td>{$d['shuchkin'][0]}</td><td>{$d['shuchkin'][1]}</td></tr>";
}
?>
</tbody>
</table>
<hr>
<h1>mk-j / PHP_XLSXWriter</h1>
<?php
foreach ($testsuite as $rows => &$d) {
    Test('MKJ', $d['data']);
    $tsum = $msum = 0.0;
    for ($i=0 ; $i<$testrepetition ; $i++) {
        $res = Test('MKJ', $d['data'], false);
        $tsum += $res[0];
        $msum += $res[1];
    }
    $d['mkj'] = [sprintf("%.3f", ($tsum/$testrepetition)/1000), sprintf("%.2f", $msum/$testrepetition)];
}
unset($d);
?>
<table>
<thead>
    <tr><th>Rows</th><th>Time [ms]</th><th>Memory [KiB]</th></tr>
</thead>
<tbody>
<?php
foreach ($testsuite as $rows => $d) {
    echo "<tr><td>{$rows}</td><td>{$d['mkj'][0]}</td><td>{$d['mkj'][1]}</td></tr>";
}
?>
</tbody>
</table>
<hr>
<h1>Conclusions</h1>
<table>
<thead>
    <tr><th>Rows</th><th>Time [ms]</th><th>Memory [KiB]</th></tr>
</thead>
<tbody>
<?php
foreach ($testsuite as $rows => $d) {
    $trel = round($d['mkj'][0] / $d['shuchkin'][0], 2);
    $trelp = round( ($trel - 1) * 100);
    $mrel = round($d['mkj'][1] / $d['shuchkin'][1], 2);
    $mrelp = round( ($mrel - 1) * 100 , 2);
    echo "<tr><td>{$rows}</td><td>mkj {$trel} times slower than shuchkin ({$trelp}%)</td><td>mkj {$mrel} times more memory usage than shuchkin ({$mrelp}%)</td></tr>";
}
?>
</tbody>
</table>
</body>
</html>