This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Add math-inline benchmark


On Wed, Jun 17, 2015 at 04:28:27PM +0100, Wilco Dijkstra wrote:
> Hi,
> 
> Due to popular demand, here is a new benchmark that tests isinf, isnan, 
> isnormal, isfinite and fpclassify. It uses 2 arrays with 1024 doubles, 
> one with 99% finite FP numbers (10% zeroes, 10% negative) and 1% inf/NaN,
> the other with 50% inf, and 50% Nan.
> 
> Results shows that using the GCC built-ins in math.h will give huge speedups
> due to avoiding explict calls, PLT indirection to execute a function with
> 3-4 instructions. The GCC builtins have similar performance as the existing 
> math_private inlines for __isnan, __finite and __isinf_ns.
> 
> OK for commit?
> 
> ChangeLog:
> 2015-06-17  Wilco Dijkstra  <wdijkstr@arm.com>
> 
> 	* benchtests/Makefile: Add bench-math-inlines.c.
> 	* benchtests/bench-math-inlines.c: New benchmark.
> 
> ---
>  benchtests/Makefile             |  14 +--
>  benchtests/bench-math-inlines.c | 203 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 211 insertions(+), 6 deletions(-)
>  create mode 100644 benchtests/bench-math-inlines.c
> 
> diff --git a/benchtests/Makefile b/benchtests/Makefile
> index 8e615e5..3c20180 100644
> --- a/benchtests/Makefile
> +++ b/benchtests/Makefile
> @@ -30,12 +30,13 @@ bench-pthread := pthread_once
>  bench := $(bench-math) $(bench-pthread)
>  
>  # String function benchmarks.
> -string-bench := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \
> -		mempcpy memset rawmemchr stpcpy stpncpy strcasecmp strcasestr \
> -		strcat strchr strchrnul strcmp strcpy strcspn strlen \
> -		strncasecmp strncat strncmp strncpy strnlen strpbrk strrchr \
> -		strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok \
> -		strcoll
> +string-bench := bcopy bzero math-inlines memccpy memchr memcmp memcpy memmem \
> +		memmove mempcpy memset rawmemchr stpcpy stpncpy strcasecmp \
> +		strcasestr strcat strchr strchrnul strcmp strcpy strcspn \
> +		strlen strncasecmp strncat strncmp strncpy strnlen strpbrk \
> +		strrchr strspn strstr strcpy_chk stpcpy_chk memrchr strsep \
> +		strtok strcoll
> +

Putting mathinline test cases in string-bench is wrong.  Make a new
benchset-math or something similar.

>  string-bench-all := $(string-bench)
>  
>  # We have to generate locales
> @@ -58,6 +59,7 @@ CFLAGS-bench-ffsll.c += -fno-builtin
>  bench-malloc := malloc-thread
>  
>  $(addprefix $(objpfx)bench-,$(bench-math)): $(libm)
> +$(addprefix $(objpfx)bench-,math-inlines): $(libm)

This doesn't need an addprefix, but if you make a benchset-math, then
you can use this format for benchset-math.

>  $(addprefix $(objpfx)bench-,$(bench-pthread)): $(shared-thread-library)
>  $(objpfx)bench-malloc-thread: $(shared-thread-library)
>  
> diff --git a/benchtests/bench-math-inlines.c b/benchtests/bench-math-inlines.c
> new file mode 100644
> index 0000000..c21a3d3
> --- /dev/null
> +++ b/benchtests/bench-math-inlines.c
> @@ -0,0 +1,203 @@
> +/* Measure math inline functions.

We've agreed to print outputs in JSON.  Please see other newer
benchtests to see how you can do that.  The string benchtests need to
be ported to the JSON output format.

> +   Copyright (C) 2015 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#define SIZE 1024
> +#define TEST_MAIN
> +#define TEST_NAME "math-inlines"
> +#include "bench-string.h"
> +
> +#include <stdlib.h>
> +#include <math.h>
> +#include <stdint.h>
> +
> +#define BOOLTEST(func)					  \
> +int							  \
> +func ## _t (volatile double *p, size_t n, size_t iters)   \
> +{							  \
> +  int i, j;						  \
> +  int res = 0;						  \
> +  for (j = 0; j < iters; j++)				  \
> +    for (i = 0; i < n; i++)				  \
> +      if (func (p[i] * 2.0)) res++;			  \
> +  return res;						  \
> +}
> +
> +#define VALUETEST(func)					  \
> +int							  \
> +func ## _t (volatile double *p, size_t n, size_t iters)	  \
> +{							  \
> +  int i, j;						  \
> +  int res = 0;						  \
> +  for (j = 0; j < iters; j++)				  \
> +    for (i = 0; i < n; i++)				  \
> +      res += func (p[i] * 2.0);				  \
> +  return res;						  \
> +}
> +
> +typedef union
> +{
> +  double value;
> +  uint64_t word;
> +} ieee_double_shape_type;
> +
> +#define EXTRACT_WORDS64(i,d)                              \
> +do {                                                      \
> +  ieee_double_shape_type gh_u;                            \
> +  gh_u.value = (d);                                       \
> +  (i) = gh_u.word;                                        \
> +} while (0)
> +
> +/* Explicit inlines similar to math_private.h versions.  */
> +
> +extern __always_inline int
> +__isnan_inl (double d)
> +{
> +  uint64_t di;
> +  EXTRACT_WORDS64 (di, d);
> +  return (di & 0x7fffffffffffffffull) > 0x7ff0000000000000ull;
> +}
> +
> +extern __always_inline int
> +__isinf_inl (double x)
> +{
> +  uint64_t ix;
> +  EXTRACT_WORDS64 (ix,x);
> +  if ((ix << 1) != 0xffe0000000000000ull)
> +    return 0;
> +  return (int)(ix >> 32);
> +}
> +
> +extern __always_inline int
> +__finite_inl (double d)
> +{
> +  uint64_t di;
> +  EXTRACT_WORDS64 (di, d);
> +  return (di & 0x7fffffffffffffffull) < 0x7ff0000000000000ull;
> +}
> +
> +/* Explicit inline similar to existing math.h implementation.  */
> +
> +#define __isnormal_inl(X) (__fpclassify (X) == FP_NORMAL)
> +#define __isnormal_inl2(X) (fpclassify (X) == FP_NORMAL)
> +
> +/* Test fpclassify with use of only 2 of the 5 results.  */
> +
> +extern __always_inline int
> +__fpclassify_test1 (double d)
> +{
> +  int cl = fpclassify (d);
> +  return cl == FP_NAN || cl == FP_INFINITE;
> +}
> +
> +extern __always_inline int
> +__fpclassify_test2 (double d)
> +{
> +  return isnan (d) || isinf (d);
> +}
> +
> +/* Create test functions for each possibility.  */
> +
> +BOOLTEST (__isnan)
> +BOOLTEST (isnan)
> +BOOLTEST (__isnan_inl)
> +
> +BOOLTEST (__isinf)
> +BOOLTEST (isinf)
> +BOOLTEST (__isinf_inl)
> +
> +BOOLTEST (__finite)
> +BOOLTEST (isfinite)
> +BOOLTEST (__finite_inl)
> +
> +BOOLTEST (isnormal)
> +BOOLTEST (__isnormal_inl)
> +BOOLTEST (__isnormal_inl2)
> +
> +VALUETEST (fpclassify)
> +VALUETEST (__fpclassify)
> +BOOLTEST (__fpclassify_test1)
> +BOOLTEST (__fpclassify_test2)
> +
> +IMPL (isnan_t, 0)
> +IMPL (__isnan_t, 1)
> +IMPL (__isnan_inl_t, 2)
> +IMPL (isinf_t, 3)
> +IMPL (__isinf_t, 4)
> +IMPL (__isinf_inl_t, 5)
> +IMPL (isfinite_t, 6)
> +IMPL (__finite_t, 7)
> +IMPL (__finite_inl_t, 8)
> +IMPL (isnormal_t, 9)
> +IMPL (__isnormal_inl_t, 10)
> +IMPL (__isnormal_inl2_t, 11)
> +IMPL (fpclassify_t, 12)
> +IMPL (__fpclassify_t, 13)
> +IMPL (__fpclassify_test1_t, 14)
> +IMPL (__fpclassify_test2_t, 15)
> +
> +typedef int (*proto_t) (volatile double *p, size_t n, size_t iters);
> +
> +static void
> +do_one_test (impl_t *impl, volatile double *arr, size_t len)
> +{
> +  size_t iters = INNER_LOOP_ITERS * 10;
> +  timing_t start, stop, cur;
> +
> +  TIMING_NOW (start);
> +  CALL (impl, arr, len, iters);
> +  TIMING_NOW (stop);
> +  TIMING_DIFF (cur, start, stop);
> +
> +  TIMING_PRINT_MEAN ((double) cur, (double) iters);
> +}
> +
> +static volatile double arr1[SIZE];
> +static volatile double arr2[SIZE];
> +
> +int
> +test_main (void)
> +{
> +  size_t i;
> +
> +  test_init ();
> +
> +  /* Create 2 test arrays, one with 10% zeroes, 10% negative values,
> +     79% positive values and 1% infinity/NaN.  The other contains
> +     50% inf, 50% NaN.  */
> +
> +  for (i = 0; i < SIZE; i++)
> +    {
> +      int x = rand () & 255;
> +      arr1[i] = (x < 25) ? 0.0 : ((x < 50) ? -1 : 100);
> +      if (x == 255) arr1[i] = __builtin_inf ();
> +      if (x == 254) arr1[i] = __builtin_nan ("0");
> +      arr2[i] = (x < 128) ? __builtin_inf () : __builtin_nan ("0");
> +    }
> +
> +  FOR_EACH_IMPL (impl, 0)
> +    {
> +      printf ("%20s: ", impl->name);
> +      do_one_test (impl, arr1, SIZE);
> +      do_one_test (impl, arr2, SIZE);
> +      putchar ('\n');
> +    }
> +
> +  return ret;
> +}
> +
> +#include "../test-skeleton.c"
> -- 
> 1.9.1
> 
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]