Req #79545 [Com]: mbstring functions are about 10x slower

From: Date: Thu, 17 Jun 2021 17:42:47 +0000
Subject: Req #79545 [Com]: mbstring functions are about 10x slower
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-234463@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=79545&edit=1

 ID:                 79545
 Comment by:         dharman@php.net
 Reported by:        michael dot vorisek at emailc dot z
 Summary:            mbstring functions are about 10x slower
 Status:             Open
 Type:               Feature/Change Request
 Package:            Performance problem
 Operating System:   Linux
 PHP Version:        7.4.5
 Block user comment: N
 Private report:     N

 New Comment:

On my Windows machine PHP 8.1 times look similar to this:

strtolower is 2.51x faster than mb_strtolower for empty

strtolower is 12.28x faster than mb_strtolower for short

strtolower is 8.57x faster than mb_strtolower for short_with_uc

strtolower is 873.44x faster than mb_strtolower for long

strtolower is 858.52x faster than mb_strtolower for long_with_uc

strtolower is 14.34x faster than mb_strtolower for short_utf8

strtolower is 14.25x faster than mb_strtolower for short_utf8_with_uc

The optimizations in strtolower are huge and make a lot of difference. It would be great if mbstring
could be optimized as well.


Previous Comments:
------------------------------------------------------------------------
[2020-06-24 20:43:54] michael dot vorisek at email dot cz

> Please note there is another reason why the plain strtolower is so much faster: It
> uses SSE2 instructions to process blocks of 16 bytes at once. This accounts for a large part of the
> difference in performance.

I replaced "strtolower" with "strtoupper" in the test code above and the
difference between strtolower/strtoupper is not the decisive.

for "strtolower":
strtolower is 6.71x faster than mb_strtolower for empty
strtolower is 10.61x faster than mb_strtolower for short
strtolower is 7.22x faster than mb_strtolower for short_with_uc
strtolower is 25.73x faster than mb_strtolower for long
strtolower is 23.38x faster than mb_strtolower for long_with_uc
strtolower is 10.86x faster than mb_strtolower for short_utf8
strtolower is 11.08x faster than mb_strtolower for short_utf8_with_uc

for "strtoupper":
strtoupper is 8.19x faster than mb_strtoupper for empty
strtoupper is 7.72x faster than mb_strtoupper for short
strtoupper is 7.66x faster than mb_strtoupper for short_with_uc
strtoupper is 25.3x faster than mb_strtoupper for long
strtoupper is 26.21x faster than mb_strtoupper for long_with_uc
strtoupper is 8.01x faster than mb_strtoupper for short_utf8
strtoupper is 8.05x faster than mb_strtoupper for short_utf8_with_uc

This issue is that current mbstring functions are several times slower even with pure ASCII (7b)
input.

------------------------------------------------------------------------
[2020-06-23 15:49:47] alexinbeijing at gmail dot com

I have studied this problem a bit more and am looking at ways to speed up case conversion of
multi-byte strings.

Please note there is another reason why the plain strtolower is so much faster: It uses
SSE2 instructions to process blocks of 16 bytes at once. This accounts for a large part of the
difference in performance.

------------------------------------------------------------------------
[2020-06-09 20:40:50] alexinbeijing at gmail dot com

This is a tricky one.

It looks like there is nothing really crazy going on in mbstring which is causing this vast
disparity in performance.

mbstring bounces through a series of function calls to process *each byte* of the input string. None
of those function calls is doing a lot of work, but when you have 200,000,000 bytes to work on, the
overhead really adds up.

Getting significantly more performance out of it might require major redesign.

------------------------------------------------------------------------
[2020-04-30 11:00:56] michael dot vorisek at emailc dot z

Description:
------------
https://3v4l.org/bOdXP

Currently the performance difference between single-byte and multi-byte string function is about 5x
- 25x (yes, +400% - +2400%).

Please verify and comment.

If the performance can not be improved with mbstring, then checking if the input string does contain
only 0x00 - 0x7f chars will improve the overall/real PHP performace - check can be done very quickly
using modern/vectored CPU instructions - and if satisfied, use equivalent single-byte string
function instead of multi-byte one.

Test script:
---------------
$cnt = 100000;

$strs = [
    'empty' => '',
    'short' => 'zluty kun',
    'short_with_uc' => 'zluty Kun',
    'long' => str_repeat('this is about 10000 chars long string', 270),
    'long_with_uc' => str_repeat('this is about 10000 chars long String',
270),
    'short_utf8' => 'žlutý kůň',
    'short_utf8_with_uc' => 'Žlutý kŮň',
];

foreach ($strs as $k => $str) {
    $a1 = microtime(true);
    for($i=0; $i < $cnt; ++$i){
        $res = strtolower($str);
    }
    $t1 = microtime(true) - $a1;
    // echo 'it took ' . round($t1 * 1000, 3) . ' ms for ++$i'."\n";

    $a2 = microtime(true);
    for($i=0; $i < $cnt; $i++){
        $res = mb_strtolower($str);
    }
    $t2 = microtime(true) - $a2;
    // echo 'it took ' . round($t2 * 1000, 3) . ' ms for $i++'."\n";

    echo 'strtolower is '.round($t2/$t1, 2).'x faster than mb_strtolower for ' .
$k . "\n\n";
}


Expected result:
----------------
strtolower is 6.73x faster than mb_strtolower for empty

strtolower is 9.78x faster than mb_strtolower for short

strtolower is 7.13x faster than mb_strtolower for short_with_uc

strtolower is 24.88x faster than mb_strtolower for long

strtolower is 23.12x faster than mb_strtolower for long_with_uc

strtolower is 9.05x faster than mb_strtolower for short_utf8

strtolower is 9.93x faster than mb_strtolower for short_utf8_with_uc



Actual result:
--------------
Difference should be no larger than 1.5x at least for single-byte strings.


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=79545&edit=1


Thread (5 messages)

« previous php.bugs (#234463) next »