(root)/
glibc-2.38/
benchtests/
bench-math-inlines.c
       1  /* Measure math inline functions.
       2     Copyright (C) 2015-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #define SIZE 1024
      20  #define TEST_MAIN
      21  #define TEST_NAME "math-inlines"
      22  #define TEST_FUNCTION test_main ()
      23  #include "bench-timing.h"
      24  #include "json-lib.h"
      25  #include "bench-util.h"
      26  
      27  #include <stdlib.h>
      28  #include <math.h>
      29  #include <stdint.h>
      30  
      31  #define BOOLTEST(func)					  \
      32  static int __attribute__((noinline))			  \
      33  func ## _f (double d, int i)				  \
      34  {							  \
      35    if (func (d))						  \
      36      return (int) d + i;					  \
      37    else							  \
      38      return 5;						  \
      39  }							  \
      40  static int						  \
      41  func ## _t (volatile double *p, size_t n, size_t iters)   \
      42  {							  \
      43    int i, j;						  \
      44    int res = 0;						  \
      45    for (j = 0; j < iters; j++)				  \
      46      for (i = 0; i < n; i++)				  \
      47        if (func ## _f (p[i] * 2.0, i) != 0)		  \
      48  	res += 5;					  \
      49    return res;						  \
      50  }
      51  
      52  #define VALUETEST(func)					  \
      53  static int __attribute__((noinline))			  \
      54  func ## _f (double d)					  \
      55  {							  \
      56    return func (d);					  \
      57  }							  \
      58  static int						  \
      59  func ## _t (volatile double *p, size_t n, size_t iters)	  \
      60  {							  \
      61    int i, j;						  \
      62    int res = 0;						  \
      63    for (j = 0; j < iters; j++)				  \
      64      for (i = 0; i < n; i++)				  \
      65        res += func ## _f (p[i] * 2.0);			  \
      66    return res;						  \
      67  }
      68  
      69  typedef union
      70  {
      71    double value;
      72    uint64_t word;
      73  } ieee_double_shape_type;
      74  
      75  #define EXTRACT_WORDS64(i,d)				  \
      76  do {							  \
      77    ieee_double_shape_type gh_u;				  \
      78    gh_u.value = (d);					  \
      79    (i) = gh_u.word;					  \
      80  } while (0)
      81  
      82  /* Inlines similar to existing math_private.h versions.  */
      83  
      84  static __always_inline int
      85  __isnan_inl (double d)
      86  {
      87    uint64_t di;
      88    EXTRACT_WORDS64 (di, d);
      89    return (di & 0x7fffffffffffffffull) > 0x7ff0000000000000ull;
      90  }
      91  
      92  static __always_inline int
      93  __isinf_ns2 (double d)
      94  {
      95    uint64_t di;
      96    EXTRACT_WORDS64 (di, d);
      97    return (di & 0x7fffffffffffffffull) == 0x7ff0000000000000ull;
      98  }
      99  
     100  static __always_inline int
     101  __finite_inl (double d)
     102  {
     103    uint64_t di;
     104    EXTRACT_WORDS64 (di, d);
     105    return (di & 0x7fffffffffffffffull) < 0x7ff0000000000000ull;
     106  }
     107  
     108  #define __isnormal_inl(X) (__fpclassify (X) == FP_NORMAL)
     109  
     110  /* Inlines for the builtin functions.  */
     111  
     112  #define __isnan_builtin(X) __builtin_isnan (X)
     113  #define __isinf_ns_builtin(X) __builtin_isinf (X)
     114  #define __isinf_builtin(X) __builtin_isinf_sign (X)
     115  #define __isfinite_builtin(X) __builtin_isfinite (X)
     116  #define __isnormal_builtin(X) __builtin_isnormal (X)
     117  #define __fpclassify_builtin(X) __builtin_fpclassify (FP_NAN, FP_INFINITE,  \
     118  				  FP_NORMAL, FP_SUBNORMAL, FP_ZERO, (X))
     119  
     120  static double __attribute ((noinline))
     121  kernel_standard (double x, double y, int z)
     122  {
     123    return x * y + z;
     124  }
     125  
     126  volatile double rem1 = 2.5;
     127  
     128  static __always_inline double
     129  remainder_test1 (double x)
     130  {
     131    double y = rem1;
     132    if (((__builtin_expect (y == 0.0, 0) && !__isnan_inl (x))
     133  	|| (__builtin_expect (__isinf_ns2 (x), 0) && !__isnan_inl (y))))
     134      return kernel_standard (x, y, 10);
     135  
     136    return remainder (x, y);
     137  }
     138  
     139  static __always_inline double
     140  remainder_test2 (double x)
     141  {
     142    double y = rem1;
     143    if (((__builtin_expect (y == 0.0, 0) && !__builtin_isnan (x))
     144  	|| (__builtin_expect (__builtin_isinf (x), 0) && !__builtin_isnan (y))))
     145      return kernel_standard (x, y, 10);
     146  
     147    return remainder (x, y);
     148  }
     149  
     150  /* Create test functions for each possibility.  */
     151  
     152  BOOLTEST (__isnan)
     153  BOOLTEST (__isnan_inl)
     154  BOOLTEST (__isnan_builtin)
     155  BOOLTEST (isnan)
     156  
     157  BOOLTEST (__isinf)
     158  BOOLTEST (__isinf_builtin)
     159  BOOLTEST (__isinf_ns2)
     160  BOOLTEST (__isinf_ns_builtin)
     161  BOOLTEST (isinf)
     162  
     163  BOOLTEST (__finite)
     164  BOOLTEST (__finite_inl)
     165  BOOLTEST (__isfinite_builtin)
     166  BOOLTEST (isfinite)
     167  
     168  BOOLTEST (__isnormal_inl)
     169  BOOLTEST (__isnormal_builtin)
     170  BOOLTEST (isnormal)
     171  
     172  VALUETEST (__fpclassify)
     173  VALUETEST (__fpclassify_builtin)
     174  VALUETEST (fpclassify)
     175  
     176  VALUETEST (remainder_test1)
     177  VALUETEST (remainder_test2)
     178  
     179  typedef int (*proto_t) (volatile double *p, size_t n, size_t iters);
     180  
     181  typedef struct
     182  {
     183    const char *name;
     184    proto_t fn;
     185  } impl_t;
     186  
     187  #define IMPL(name) { #name, name ## _t }
     188  
     189  static impl_t test_list[] =
     190  {
     191    IMPL (__isnan),
     192    IMPL (__isnan_inl),
     193    IMPL (__isnan_builtin),
     194    IMPL (isnan),
     195  
     196    IMPL (__isinf),
     197    IMPL (__isinf_ns2),
     198    IMPL (__isinf_ns_builtin),
     199    IMPL (__isinf_builtin),
     200    IMPL (isinf),
     201  
     202    IMPL (__finite),
     203    IMPL (__finite_inl),
     204    IMPL (__isfinite_builtin),
     205    IMPL (isfinite),
     206  
     207    IMPL (__isnormal_inl),
     208    IMPL (__isnormal_builtin),
     209    IMPL (isnormal),
     210  
     211    IMPL (__fpclassify),
     212    IMPL (__fpclassify_builtin),
     213    IMPL (fpclassify),
     214  
     215    IMPL (remainder_test1),
     216    IMPL (remainder_test2)
     217  };
     218  
     219  static void
     220  do_one_test (json_ctx_t *json_ctx, proto_t test_fn, volatile double *arr,
     221  	     size_t len, const char *testname)
     222  {
     223    size_t iters = 2048;
     224    timing_t start, stop, cur;
     225  
     226    json_attr_object_begin (json_ctx, testname);
     227  
     228    TIMING_NOW (start);
     229    test_fn (arr, len, iters);
     230    TIMING_NOW (stop);
     231    TIMING_DIFF (cur, start, stop);
     232  
     233    json_attr_double (json_ctx, "duration", cur);
     234    json_attr_double (json_ctx, "iterations", iters);
     235    json_attr_double (json_ctx, "mean", cur / iters);
     236    json_attr_object_end (json_ctx);
     237  }
     238  
     239  static volatile double arr1[SIZE];
     240  static volatile double arr2[SIZE];
     241  
     242  int
     243  test_main (void)
     244  {
     245    json_ctx_t json_ctx;
     246    size_t i;
     247  
     248    bench_start ();
     249  
     250    json_init (&json_ctx, 2, stdout);
     251    json_attr_object_begin (&json_ctx, TEST_NAME);
     252  
     253    /* Create 2 test arrays, one with 10% zeroes, 10% negative values,
     254       79% positive values and 1% infinity/NaN.  The other contains
     255       50% inf, 50% NaN.  This relies on rand behaving correctly.  */
     256  
     257    for (i = 0; i < SIZE; i++)
     258      {
     259        int x = rand () & 255;
     260        arr1[i] = (x < 25) ? 0.0 : ((x < 50) ? -1 : 100);
     261        if (x == 255) arr1[i] = __builtin_inf ();
     262        if (x == 254) arr1[i] = __builtin_nan ("0");
     263        arr2[i] = (x < 128) ? __builtin_inf () : __builtin_nan ("0");
     264      }
     265  
     266    for (i = 0; i < sizeof (test_list) / sizeof (test_list[0]); i++)
     267      {
     268        json_attr_object_begin (&json_ctx, test_list[i].name);
     269        do_one_test (&json_ctx, test_list[i].fn, arr2, SIZE, "inf/nan");
     270        json_attr_object_end (&json_ctx);
     271      }
     272  
     273    for (i = 0; i < sizeof (test_list) / sizeof (test_list[0]); i++)
     274      {
     275        json_attr_object_begin (&json_ctx, test_list[i].name);
     276        do_one_test (&json_ctx, test_list[i].fn, arr1, SIZE, "normal");
     277        json_attr_object_end (&json_ctx);
     278      }
     279  
     280    json_attr_object_end (&json_ctx);
     281    return 0;
     282  }
     283  
     284  #include "bench-util.c"
     285  #include "../test-skeleton.c"