This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] Improve bench-memmem
On 21/03/2019 13:19, Wilco Dijkstra wrote:
> Improve bench-memmem by replacing simple_memmem with a more efficient
> implementation. Add the Two-way implementation to enable direct comparison
> with the optimized memmem. Also change the number of iterations to reduce
> the amount of output.
>
> ChangeLog:
> 2019-03-21 Wilco Dijkstra <wdijkstr@arm.com>
>
> * benchtests/bench-memmem.c (simple_memmem): Remove function.
> (basic_memmem): Add function.
> (twoway_memmem): Add function.
LGTM, thanks.
>
> --
>
> diff --git a/benchtests/bench-memmem.c b/benchtests/bench-memmem.c
> index 4936b236a33b5e22ca6c25b4729be5fee2cd6a04..b6b97f3d1f5f94a71c177cc516cba81c869d3865 100644
> --- a/benchtests/bench-memmem.c
> +++ b/benchtests/bench-memmem.c
> @@ -19,22 +19,51 @@
> #define TEST_MAIN
> #define TEST_NAME "memmem"
> #define BUF1PAGES 20
> -#define ITERATIONS 500
> +#define ITERATIONS 100
> #include "bench-string.h"
>
> typedef char *(*proto_t) (const void *, size_t, const void *, size_t);
> -void *simple_memmem (const void *, size_t, const void *, size_t);
>
> -IMPL (simple_memmem, 0)
> -IMPL (memmem, 1)
> +void *
> +basic_memmem (const void *haystack, size_t hs_len, const void *needle,
> + size_t ne_len)
> +{
> + const char *hs = haystack;
> + const char *ne = needle;
> +
> + if (ne_len == 0)
> + return (void *)hs;
> + int i;
> + int c = ne[0];
> + const char *end = hs + hs_len - ne_len;
> +
> + for ( ; hs <= end; hs++)
> + {
> + if (hs[0] != c)
> + continue;
> + for (i = ne_len - 1; i != 0; i--)
> + if (hs[i] != ne[i])
> + break;
> + if (i == 0)
> + return (void *)hs;
> + }
> +
> + return NULL;
> +}
> +
> +#define RETURN_TYPE void *
> +#define AVAILABLE(h, h_l, j, n_l) ((j) <= (h_l) - (n_l))
> +#define FASTSEARCH(S,C,N) (void*) memchr ((void *)(S), (C), (N))
> +#include "../string/str-two-way.h"
>
> void *
> -simple_memmem (const void *haystack, size_t haystack_len, const void *needle,
> - size_t needle_len)
> +twoway_memmem (const void *haystack_start, size_t haystack_len,
> + const void *needle_start, size_t needle_len)
> {
> - const char *begin;
> - const char *const last_possible
> - = (const char *) haystack + haystack_len - needle_len;
> + /* Abstract memory is considered to be an array of 'unsigned char' values,
> + not an array of 'char' values. See ISO C 99 section 6.2.6.1. */
> + const unsigned char *haystack = (const unsigned char *) haystack_start;
> + const unsigned char *needle = (const unsigned char *) needle_start;
>
> if (needle_len == 0)
> /* The first occurrence of the empty string is deemed to occur at
> @@ -46,16 +75,32 @@ simple_memmem (const void *haystack, size_t haystack_len, const void *needle,
> if (__glibc_unlikely (haystack_len < needle_len))
> return NULL;
>
> - for (begin = (const char *) haystack; begin <= last_possible; ++begin)
> - if (begin[0] == ((const char *) needle)[0]
> - && !memcmp ((const void *) &begin[1],
> - (const void *) ((const char *) needle + 1),
> - needle_len - 1))
> - return (void *) begin;
> -
> - return NULL;
> + /* Use optimizations in memchr when possible, to reduce the search
> + size of haystack using a linear algorithm with a smaller
> + coefficient. However, avoid memchr for long needles, since we
> + can often achieve sublinear performance. */
> + if (needle_len < LONG_NEEDLE_THRESHOLD)
> + {
> + haystack = memchr (haystack, *needle, haystack_len);
> + if (!haystack || __builtin_expect (needle_len == 1, 0))
> + return (void *) haystack;
> + haystack_len -= haystack - (const unsigned char *) haystack_start;
> + if (haystack_len < needle_len)
> + return NULL;
> + /* Check whether we have a match. This improves performance since we
> + avoid the initialization overhead of the two-way algorithm. */
> + if (memcmp (haystack, needle, needle_len) == 0)
> + return (void *) haystack;
> + return two_way_short_needle (haystack, haystack_len, needle, needle_len);
> + }
> + else
> + return two_way_long_needle (haystack, haystack_len, needle, needle_len);
> }
>
> +IMPL (memmem, 1)
> +IMPL (twoway_memmem, 0)
> +IMPL (basic_memmem, 0)
> +
> static void
> do_one_test (impl_t *impl, const void *haystack, size_t haystack_len,
> const void *needle, size_t needle_len, const void *expected)
>