Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Very slow performance of Fibonacci extension vs PHP script #2151

Closed
maorcatmyheritage opened this issue Feb 18, 2021 · 7 comments
Closed

Very slow performance of Fibonacci extension vs PHP script #2151

maorcatmyheritage opened this issue Feb 18, 2021 · 7 comments

Comments

@maorcatmyheritage
Copy link

Hi,

We are considering using Zephir for optimzing the performance of some CPU intenstive methods in our project.
The first step was to compile a very simple extension with a single class for calculating the Fibonacci number and compare it with similar PHP implementation.

The results we got were extermely bad and I wonder what are we doing wrong here.

Here is the result we got:

php test.php 15 10000
Looping 10000 times...
PHP Script: Result = 610; 0.57610678672791 sec
PHP Extension: Result = 610; Time = 5.3556461334229 sec

In this example above you can see the the Zephir extension is 10x slower than PHP.

For testing, we created a docker image that is based on the following docker image: https://github.com/bahadirbirsoz/docker-php and adds a compiled extension (utils.so) to php.ini:

FROM bahadirbirsoz/phalcon-phpunit
COPY ./utils.so /usr/local/lib/php/extensions/no-debug-non-zts-20190902/
COPY ./utils.ini /usr/local/etc/php/conf.d/10-utils.ini

For testing, we executed the attached fibonacci.zep script and tested with test.php as shown above.

Can you please tell us what we could be doing wrong?

Thanks,
Maor

@Jeckerson
Copy link
Member

Hello, not all type of code will have big boost of performance, for several reasons: you write bad code or you write code that already fast in PHP (ex: regular expressions).

If you want examples of code, check this - #2149

@maorcatmyheritage
Copy link
Author

Thanks @Jeckerson. I totally understand that not every piece of code will be faster as an extension. However, I didn't not expect that it will 10 times slower.
What do you mean by "bad code"? Do you see anything wrong in my Zephir implementation? (fibonacci.zep)

@Jeckerson
Copy link
Member

Jeckerson commented Feb 18, 2021

@maorcatmyheritage Check this implementations of fibonacci

https://github.com/zephir-lang/zephir/blob/development/stub/fibonnaci.zep

Also, normally, recursion is slower then iterational.

Example of bad code approach: #2119 (comment)

@maorcatmyheritage
Copy link
Author

I see. Thanks. I'll give it a try and update with the results.

@maorcatmyheritage
Copy link
Author

maorcatmyheritage commented Feb 22, 2021

So I tried the fibInt() example from here: https://github.com/zephir-lang/zephir/blob/development/stub/fibonnaci.zep

PHP Script: Result = 13; 1.4744379520416
PHP Extension: Result = 13; Time = 0.28731203079224

As you expected, the Zephir example is 5x faster than the PHP script version.
Are there any guidelines or tips for what will be faster as an extension compared to PHP?

@AlexNDRmac
Copy link
Member

If you really want to create the fastest extension as possible - you should write your own pure C implementation fo all your functions.

I created an extension with empty implementations and added my own pure C implementation for Fibonacci with recursion.

// ./utils/fibonacci.zep
namespace Utils;

class Fibonacci
{
    public function fibonacci(int n)
    {
        return n;
    }
}
int fibonacci(int n) {
    if ( n == 0 ) {
        return 0;
    }

    if ( n == 1 || n == -1 ) {
        return 1;
    }

    if ( n < 0 ) {
        return fibonacci(n+2) - fibonacci(n+1);
    }

    return fibonacci(n-1) + fibonacci(n-2);
}

How it looks into fibonacci.zep.c after Zephir generate and my small code modification:

// Insert C implementation here:
int fibonacci(int n) {
    ...
}

PHP_METHOD(Utils_Fibonacci, fibonacci) {

	zval *n_param = NULL;
	zend_long n;
	zval *this_ptr = getThis();


	zephir_fetch_params_without_memory_grow(1, 0, &n_param);

	n = zephir_get_intval(n_param);

        // Here I call my fibonacci function 
	RETURN_LONG(fibonacci(n));
}

Then I compiled extension with Clang by hand: cd ./ext && phpize && ./configure && make

Result - Zephir + pure C implementation (even with recursion) - 200x faster

$ php -d extension=./ext/modules/utils.so test.php 15 10000

Looping 10000 times...
PHP Script: Result = 610; 9.8018710613251
PHP Extension: Result = 610; Time = 0.049493789672852

And for 42 Fibonacci number :) - Extension is 230x faster (php ~7.12 minutes vs extension ~ 1.84 sec)

$ php -d extension=./ext/modules/utils.so test.php 42 1

Looping 1 times...
PHP Script: Result = 267914296; 427.64250397682
PHP Extension: Result = 267914296; Time = 1.8432431221008

@maorcatmyheritage
Copy link
Author

Thanks @AlexNDRmac. That was an extermely useful information. I didn't realize that the generated code might have such a big overhead. In my test the extension is now 30x faster but it is still much better than before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants