bcmath-extended icon indicating copy to clipboard operation
bcmath-extended copied to clipboard

Performance

Open TheLevti opened this issue 2 years ago • 7 comments
trafficstars

Please provide the following details.

  • Operating System: Linux
  • PHP Version: 8.1.14

Performance implications

I am using BC::roundDown() on my responses to always round down specific fields to a specific decimal place. Now let's say we have in a for me realistic scenario of 16000 BC::roundDown() operations on my response. It's fine if they are all raw and not already rounded. But what if they are already? In my case the values coming cache and other sources are already rounded to 2 decimals. So why should I run BC::roundDown() again, but at the same time I can not be sure that the source always gives me formatted values?

I did 3 different solutions with 10 million values to be round:

  1. Explode a string and check if number of chars after the dot is <= required decimals
  2. Use preg_match
  3. Just run BC::roundDown as we currently do:

Simple validation with explode takes 2.6 seconds to run. Using preg_match takes 0.8 seconds to run Just do what we do now and just run BC::roundDown takes 76 seconds to run

So projected on my current project, I can drop another 10 ms at least from the response generation. And in total reduce CPU time if we can add this simple validation to the library where it makes sense.

Code used for the test

$case = 2;
$testString = '1234.123';
$start = microtime(true);
for ($i = 0; $i < 16000; ++$i) {
    switch ($case) {
        case 0:
            $elements = explode('.', $testString);
            $elementsCount = count($elements);
            if ($elementsCount === 1) {
                continue 2;
            }

            if (strlen(end($elements)) <= 2) {
                // Match
            }

            break;

        case 1:
            if (preg_match("/\d+(\.\d{1,2})?$/", $testString)) {
                // Match
            }

            break;

        case 2:
            BC::roundDown($testString, 2);

            break;
    }
}
dump(microtime(true) - $start);

TheLevti avatar Feb 09 '23 12:02 TheLevti

Besides that further optimizations are:

Do a simple string cutoff if you roundDown a positive number or roundUp a negative number.

TheLevti avatar Feb 09 '23 14:02 TheLevti

Indeed this are cool optimization, I need to test it

krowinski avatar Feb 24 '23 13:02 krowinski

The above comment is phishing and it should be removed.

peter279k avatar Feb 26 '24 06:02 peter279k

@TheLevti, after looking at the BC::roundDown method, its approach is more complicated than other cases you mention.

The approach are about the BC::roundDown method is as follows:

  • Calling the static::convertScientificNotationToString method.
  • Calling the static::parseNumber method.

After checking above of these methods, the static::parseNumber takes about 0.27 seconds. The case 0 takes about 0.00523084 seconds. and the case 1 takes about 0.002723818 seconds.

peter279k avatar Feb 26 '24 06:02 peter279k

@TheLevti, after looking at the BC::roundDown method, its approach is more complicated than other cases you mention.

The approach are about the BC::roundDown method is as follows:

  • Calling the static::convertScientificNotationToString method.
  • Calling the static::parseNumber method.

After checking above of these methods, the static::parseNumber takes about 0.27 seconds. The case 0 takes about 0.00523084 seconds. and the case 1 takes about 0.002723818 seconds.

I don't suggest to completely replace it, just for specific cases we should take shortcuts.

TheLevti avatar Feb 26 '24 21:02 TheLevti

I am not quite sure what you conclude in the last comment :)

When you do several thousand BC operations per second, it is heavily noticeable how much CPU is required. Little optimizations showed huge differences.

Unfortunately I did not have time to properly contribute to this issue code wise. But if you agree, for sure I can find some time to contribute.

TheLevti avatar Feb 26 '24 21:02 TheLevti

@TheLevti, thanks for your reply. I concluded that we might use other approaches to refactor the BC::roundDown method and let rounding number efficiency and optimization.

peter279k avatar Feb 27 '24 02:02 peter279k