zephir
zephir copied to clipboard
Slow performance during create multidimension arrays
Hello Code generated by zephir for setting multi-dimension array is very slow.
Example zep file:
namespace Utils;
class Example
{
public function generate(int size) -> array
{
var output = [];
var i = 0;
var j = 0;
for i in range (0, size) {
let output[i] = [];
for j in range(0, size) {
let output[i][j] = 1;
}
}
return output;
}
}
Example php code used this module:
<?php
$a = new Utils\Example();
$res = $a->generate(1000);
Execution time: real 0m4,693s user 0m4,658s sys 0m0,020s
Generated c code for this function
PHP_METHOD(Utils_Example, generate) {
zend_bool _0, _4$$3;
zval *size_param = NULL, output, i, j, _3$$3, _7$$4;
zend_long size, _1, _2, _5$$3, _6$$3;
zval *this_ptr = getThis();
ZVAL_UNDEF(&output);
ZVAL_UNDEF(&i);
ZVAL_UNDEF(&j);
ZVAL_UNDEF(&_3$$3);
ZVAL_UNDEF(&_7$$4);
ZEPHIR_MM_GROW();
zephir_fetch_params(1, 1, 0, &size_param);
size = zephir_get_intval(size_param);
ZEPHIR_INIT_VAR(&output);
array_init(&output);
ZEPHIR_INIT_VAR(&i);
ZVAL_LONG(&i, 0);
ZEPHIR_INIT_VAR(&j);
ZVAL_LONG(&j, 0);
_2 = size;
_1 = 0;
_0 = 0;
if (_1 <= _2) {
while (1) {
if (_0) {
_1++;
if (!(_1 <= _2)) {
break;
}
} else {
_0 = 1;
}
ZEPHIR_INIT_NVAR(&i);
ZVAL_LONG(&i, _1);
ZEPHIR_INIT_NVAR(&_3$$3);
array_init(&_3$$3);
zephir_array_update_zval(&output, &i, &_3$$3, PH_COPY | PH_SEPARATE);
_6$$3 = size;
_5$$3 = 0;
_4$$3 = 0;
if (_5$$3 <= _6$$3) {
while (1) {
if (_4$$3) {
_5$$3++;
if (!(_5$$3 <= _6$$3)) {
break;
}
} else {
_4$$3 = 1;
}
ZEPHIR_INIT_NVAR(&j);
ZVAL_LONG(&j, _5$$3);
ZEPHIR_INIT_NVAR(&_7$$4);
ZVAL_LONG(&_7$$4, 1);
zephir_array_update_multi(&output, &_7$$4 TSRMLS_CC, SL("zz"), 2, &i, &j);
}
}
}
}
RETURN_CCTOR(&output);
}
Similar code created in php
<?php
class Example {
public function generate(int $size): array
{
$output = [];
for ($i = 0; $i <= $size; $i++) {
$output[$i] = [];
for ($j = 0; $j <= $size; $j++) {
$output[$i][$j] = 1;
}
}
return $output;
}
}
$a = new Example();
$res = $a->generate(1000);
Execution time: real 0m0,178s user 0m0,156s sys 0m0,021s
For calculating time I used linux time command. PHP version : PHP 7.2.19-0ubuntu0.19.04.1 (cli) (built: Jun 4 2019 14:44:42) ( NTS ) Zephir version : 0.12.0 (with default configuration for new projects)
I can try to use hash directly. Second, zephir_array_update_multi is retrieved only once according to the context, not every update.
My test result: PHP
$ time php ../../test2.php
real 0m0.115s
user 0m0.095s
sys 0m0.020s
zephir
$ time php ../../test.php
real 0m0.164s
user 0m0.140s
sys 0m0.024s
After optimization
time php ../../test.php
real 0m0.089s
user 0m0.049s
sys 0m0.040s
@sergeyklay Please take look if you can add reference type, and convert as follows:
public function generate(int size) -> array
{
var output = [];
var i = 0;
var j = 0;
for i in range (0, size) {
var arr;
let output[i] = [];
let arr = &output[i]; // <-- reference
for j in range(0, size) {
let arr[j] = 1;
}
}
return output;
}
to c code like this
...
zephir_array_update_zval(&output, &i, &empty_arr, PH_COPY | PH_SEPARATE);
zephir_array_fetch(&empty_arr, &output, &i, PH_NOISY|PH_READONLY, ...); // key point, use PH_READONLY, if reference type
...
zephir_array_update_zval(&empty_arr, &j, &value, PH_COPY); // key point, don't use PH_SEPARATE, if reference type
...
Great improvement!