diff options
author | Wilco Dijkstra <wdijkstr@arm.com> | 2016-12-21 15:16:29 +0000 |
---|---|---|
committer | Wilco Dijkstra <wdijkstr@arm.com> | 2016-12-21 15:16:29 +0000 |
commit | 5625f666cead9f3c71e00696df2907120aef1f31 (patch) | |
tree | 38d3bbb125573116a83930aa30d6d89d93f9a14e /string/bits | |
parent | d08ab9ced75e0d88827e0bb58183612afb7fe1fd (diff) | |
download | glibc-5625f666cead9f3c71e00696df2907120aef1f31.tar.gz glibc-5625f666cead9f3c71e00696df2907120aef1f31.tar.xz glibc-5625f666cead9f3c71e00696df2907120aef1f31.zip |
This patch cleans up the strsep implementation and improves performance.
Currently strsep calls strpbrk is is now a veneer to strcspn. Calling strcspn directly is faster. Since it handles a delimiter string of size 1 as a special case, this is not needed in strsep itself. Although this means there is a slightly higher overhead if the delimiter size is 1, all other cases are slightly faster. The overall performance gain is 5-10% on AArch64. The string/bits/string2.h header contains optimizations for constant delimiters of size 1-3. Benchmarking these showed similar performance for size 1 (since in all cases strchr/strchrnul is used), while size 2 and 3 can give up to 2x speedup for small input strings. However if these cases are common it seems much better to add this optimization to strcspn. So move these header optimizations to string-inlines.c. Improve the strsep benchmark so that it actually benchmarks something. The current version contains a delimiter character at every position in the input string, so there is very little work to do, and the extremely inefficent simple_strsep implementation appears fastest in every case. The new version has either no match in the input for the fail case and a match halfway in the input for the success case. The input is then restored so that each iteration does exactly the same amount of work. Reduce the number of testcases since simple_strsep takes a lot of time now. * benchtests/bench-strsep.c (oldstrsep): Add old implementation. (do_one_test) Restore original string so iteration works. * string/string-inlines.c (do_test): Create better input strings. (test_main) Reduce number of testruns. * string/string-inlines.c (__old_strsep_1c): New function. (__old_strsep_2c): Likewise. (__old_strsep_3c): Likewise. * string/strsep.c (__strsep): Remove case of small delim string. Call strcspn directly rather than strpbrk. * string/bits/string2.h (__strsep): Remove define. (__strsep_1c): Remove. (__strsep_2c): Remove. (__strsep_3c): Remove. (strsep): Remove. * sysdeps/unix/sysv/linux/internal_statvfs.c (__statvfs_getflags): Rename to __strsep.
Diffstat (limited to 'string/bits')
-rw-r--r-- | string/bits/string2.h | 90 |
1 files changed, 0 insertions, 90 deletions
diff --git a/string/bits/string2.h b/string/bits/string2.h index e39d4f1a85..c1366172fa 100644 --- a/string/bits/string2.h +++ b/string/bits/string2.h @@ -180,96 +180,6 @@ extern void *__rawmemchr (const void *__s, int __c); #endif -#if !defined _HAVE_STRING_ARCH_strsep || defined _FORCE_INLINES -# ifndef _HAVE_STRING_ARCH_strsep - -extern char *__strsep_g (char **__stringp, const char *__delim); -# define __strsep(s, reject) \ - __extension__ \ - ({ char __r0, __r1, __r2; \ - (__builtin_constant_p (reject) && __string2_1bptr_p (reject) \ - && (__r0 = ((const char *) (reject))[0], \ - ((const char *) (reject))[0] != '\0') \ - ? ((__r1 = ((const char *) (reject))[1], \ - ((const char *) (reject))[1] == '\0') \ - ? __strsep_1c (s, __r0) \ - : ((__r2 = ((const char *) (reject))[2], __r2 == '\0') \ - ? __strsep_2c (s, __r0, __r1) \ - : (((const char *) (reject))[3] == '\0' \ - ? __strsep_3c (s, __r0, __r1, __r2) \ - : __strsep_g (s, reject)))) \ - : __strsep_g (s, reject)); }) -# endif - -__STRING_INLINE char *__strsep_1c (char **__s, char __reject); -__STRING_INLINE char * -__strsep_1c (char **__s, char __reject) -{ - char *__retval = *__s; - if (__retval != NULL && (*__s = strchr (__retval, __reject)) != NULL) - *(*__s)++ = '\0'; - return __retval; -} - -__STRING_INLINE char *__strsep_2c (char **__s, char __reject1, char __reject2); -__STRING_INLINE char * -__strsep_2c (char **__s, char __reject1, char __reject2) -{ - char *__retval = *__s; - if (__retval != NULL) - { - char *__cp = __retval; - while (1) - { - if (*__cp == '\0') - { - __cp = NULL; - break; - } - if (*__cp == __reject1 || *__cp == __reject2) - { - *__cp++ = '\0'; - break; - } - ++__cp; - } - *__s = __cp; - } - return __retval; -} - -__STRING_INLINE char *__strsep_3c (char **__s, char __reject1, char __reject2, - char __reject3); -__STRING_INLINE char * -__strsep_3c (char **__s, char __reject1, char __reject2, char __reject3) -{ - char *__retval = *__s; - if (__retval != NULL) - { - char *__cp = __retval; - while (1) - { - if (*__cp == '\0') - { - __cp = NULL; - break; - } - if (*__cp == __reject1 || *__cp == __reject2 || *__cp == __reject3) - { - *__cp++ = '\0'; - break; - } - ++__cp; - } - *__s = __cp; - } - return __retval; -} -# ifdef __USE_MISC -# define strsep(s, reject) __strsep (s, reject) -# endif -#endif - /* We need the memory allocation functions for inline strdup(). Referring to stdlib.h (even minimally) is not allowed in any of the tight standards compliant modes. */ |