You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
stripos with large haystack has bad performance #7847
I'd rather treat this as feature request; we probably don't want to replace the current implementation of stripos() in stable releases (given that it works this way since "forever"), and the recent changes to https://wiki.php.net/rfc/strtolower-ascii may have already improved the performance, and at least should make it easier to avoid using zend_string_tolower(). Furthermore, I somewhat doubt that the given test script is representative for real world applications, where case-insensitive searches for long ASCII strings appear to be rather rare (and especially the case where we only have to match the first character of needle to recognize that we do not have to compare the rest of needle, and can procede to the next character of haystack).
That said, consider the following drastically simplified but naive patch for master:
strpos: 1032 / second
stripos: 157 / second
preg_match: 1472 / second
This is even slightly slower than the unpatched variant, so the zend_string_tolower() and php_memnstr() approach doesn't appear that bad, especially given that preg_match() even rivals the performance of strpos().
The new algorithm seems to be faster in all cases. Even in the worst case (compared to the old implementation) it is faster, likely because there is no allocation happening. The larger the haystack the more dramatic the difference. There is some variance when executing the benchmark but the difference in the benchmark is way above the margin of error.
Reacted by Christoph M. Becker, KapitanOczywisty, Eugene Leonovich and Kamil Tekiela
@kamil-tekiela It avoids copying of both the haystack and needle so two allocations less essentially. But I haven't measured it. It will likely be insignificant unless the string is very very large as the memory is freed before the function returns.
Activity
iluuu1994 commentedon Dec 28, 2021
Not sure if this qualifies as a bug but there's definitely room for improvement.
cmb69 commentedon Dec 28, 2021
I'd rather treat this as feature request; we probably don't want to replace the current implementation of
stripos()in stable releases (given that it works this way since "forever"), and the recent changes to https://wiki.php.net/rfc/strtolower-ascii may have already improved the performance, and at least should make it easier to avoid usingzend_string_tolower(). Furthermore, I somewhat doubt that the given test script is representative for real world applications, where case-insensitive searches for long ASCII strings appear to be rather rare (and especially the case where we only have to match the first character ofneedleto recognize that we do not have to compare the rest ofneedle, and can procede to the next character of haystack).That said, consider the following drastically simplified but naive patch for master:
The given test script outputs here:
This is even slightly slower than the unpatched variant, so the
zend_string_tolower()andphp_memnstr()approach doesn't appear that bad, especially given thatpreg_match()even rivals the performance ofstrpos().iluuu1994 commentedon Dec 31, 2021
The new algorithm seems to be faster in all cases. Even in the worst case (compared to the old implementation) it is faster, likely because there is no allocation happening. The larger the haystack the more dramatic the difference. There is some variance when executing the benchmark but the difference in the benchmark is way above the margin of error.
kamil-tekiela commentedon Dec 31, 2021
Is there any impact on the memory usage?
iluuu1994 commentedon Dec 31, 2021
@kamil-tekiela It avoids copying of both the haystack and needle so two allocations less essentially. But I haven't measured it. It will likely be insignificant unless the string is very very large as the memory is freed before the function returns.
[-]stripos has very bad performance[/-][+]stripos with large haystack has bad performance[/+]Optimize stripos/stristr