# HG changeset patch
# User Shan Kang <shan.kang@intel.com>
# Date 1612266737 -28800
#      Tue Feb 02 19:52:17 2021 +0800
# Node ID df3a18e894881c6cf9b37ddbe0689e8782273d02
# Parent  fdfd874293f66d6960ac43849ba7007a81d5d4f7
Improve pow operations' performance for non complex data type

* libinterp/corefcn/xpow.cc (elem_xpow): Optimized pow operation
  though VML library for non complex data types
* Makefile.am: Add VML_CFLAGS to compiler flags.
* configure.ac: Enable VML library by default and disable it through
  --disable-vml

diff -r fdfd874293f6 -r df3a18e89488 Makefile.am
--- a/Makefile.am	Mon Jan 04 14:52:06 2021 +0100
+++ b/Makefile.am	Tue Feb 02 19:52:17 2021 +0800
@@ -50,7 +50,7 @@ AM_FFLAGS = ${FPICFLAG} @FFLAGS@ ${CFLAG
 
 # C compiler flags.
 
-AM_CFLAGS = ${CPICFLAG} ${XTRA_CFLAGS} ${WARN_CFLAGS} ${CFLAG_VISIBILITY}
+AM_CFLAGS = ${CPICFLAG} ${XTRA_CFLAGS} ${WARN_CFLAGS} ${CFLAG_VISIBILITY} $(VML_CFLAGS)
 
 # ifeq (${INCLUDE_DEPS},no)
 #   omit_deps = true;
@@ -58,7 +58,7 @@ AM_CFLAGS = ${CPICFLAG} ${XTRA_CFLAGS} $
 
 # C++ compiler flags.
 
-AM_CXXFLAGS = ${CXXPICFLAG} ${XTRA_CXXFLAGS} ${WARN_CXXFLAGS} ${CFLAG_VISIBILITY}
+AM_CXXFLAGS = ${CXXPICFLAG} ${XTRA_CXXFLAGS} ${WARN_CXXFLAGS} ${CFLAG_VISIBILITY} $(VML_CFLAGS)
 
 FFTW_XCPPFLAGS = @FFTW_XCPPFLAGS@
 FFTW_XLDFLAGS = @FFTW_XLDFLAGS@
diff -r fdfd874293f6 -r df3a18e89488 configure.ac
--- a/configure.ac	Mon Jan 04 14:52:06 2021 +0100
+++ b/configure.ac	Tue Feb 02 19:52:17 2021 +0800
@@ -498,6 +498,44 @@ else
   ENABLE_64=no
 fi
 
+AC_ARG_ENABLE(vml,
+  [AS_HELP_STRING([--disable-vml],
+    [don't use VML library to speed up some vector math functions])],
+  [case $enableval in
+     yes) enable_vml=yes ;;
+     no) enable_vml=no ;;
+     *) AC_MSG_ERROR([bad value $enableval for --enable-vml]) ;;
+   esac],
+   [case $host_os in
+    linux*)
+      enable_vml=yes
+    ;;
+    *)
+      enable_vml=no
+    ;;
+  esac])
+
+if test "x$enable_vml" = "xyes"; then
+    AC_CHECK_LIB([mvec], _ZGVeN8vv_pow, [], [enable_vml=no])
+fi
+
+AS_IF([test "x$enable_vml" = "xyes"],
+   [AS_IF([ test -e ${ac_abs_confdir}/VML/vml_math.h ],[CKL_CFLAGS="-I${ac_abs_confdir}/VML -DUSE_VML=1"],[AS_IF([test $(git clone https://github.com/intel/VML.git;echo $?) = 0],[VML_CFLAGS="-I${ac_abs_confdir}/VML -DUSE_VML=1"],[VML_CFLAGS=;AC_MSG_ERROR([Failed to clone VML code])])])],
+   [VML_CFLAGS=])
+
+if test "x$VML_CFLAGS" != "x"; then
+  ## Check ifunc supports or not
+  AC_CACHE_CHECK([for __attribute__((ifunc))], [have_func_attribute_ifunc], [
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([int my_foo( void ) { return 0; }
+                    static int (*resolve_foo(void))(void) { return my_foo; }
+                    int foo( void ) __attribute__((ifunc("resolve_foo")));], [])],
+    [have_func_attribute_ifunc="yes"], [have_func_attribute_ifunc="no"])])
+  AS_IF([test "x$have_func_attribute_ifunc" != "xyes"],
+	[VML_CFLAGS=$VML_CFLAGS -DNO_IFUNC_SUPPORT=1])
+fi
+
+AC_SUBST(VML_CFLAGS)
+
 AC_ARG_ENABLE(64,
   [AS_HELP_STRING([--disable-64],
     [don't use 64-bit integers for array dimensions and indexing])],
diff -r fdfd874293f6 -r df3a18e89488 libinterp/corefcn/xpow.cc
--- a/libinterp/corefcn/xpow.cc	Mon Jan 04 14:52:06 2021 +0100
+++ b/libinterp/corefcn/xpow.cc	Tue Feb 02 19:52:17 2021 +0800
@@ -27,6 +27,13 @@
 #  include "config.h"
 #endif
 
+#if defined (USE_VML)
+#if defined (NO_IFUNC_SUPPORT)
+#define GCC_IFUN_UNAVAILABLE 1
+#endif
+#  include "vml_math.h"
+#endif
+
 #include <cassert>
 
 #include <limits>
@@ -56,6 +63,14 @@
 
 #include "bsxfun.h"
 
+#if defined (USE_VML)
+void *
+octave_quit_wrapper (void *input)
+{
+  octave_quit ();
+  return NULL;
+}
+#endif
 
 static void
 err_failed_diagonalization (void)
@@ -1136,12 +1151,16 @@ elem_xpow (double a, const NDArray& b)
   else
     {
       NDArray result (b.dims ());
+#if defined (USE_VML)
+      vml_vpow_sv_hook (a, b.fortran_vec (), result.fortran_vec (), b.numel (),
+      octave_quit_wrapper, NULL, NULL, NULL);
+#else
       for (octave_idx_type i = 0; i < b.numel (); i++)
         {
           octave_quit ();
           result(i) = std::pow (a, b(i));
         }
-
+#endif
       retval = result;
     }
 
@@ -1187,12 +1206,16 @@ elem_xpow (const NDArray& a, double b)
       else
         {
           NDArray result (a.dims ());
+#if defined (USE_VML)
+      vml_vpow_vs_hook (a.fortran_vec (), b, result.fortran_vec (), a.numel (),
+      octave_quit_wrapper, NULL, NULL, NULL);
+#else
           for (octave_idx_type i = 0; i < a.numel (); i++)
             {
               octave_quit ();
               result(i) = std::pow (a(i), b);
             }
-
+#endif
           retval = result;
         }
     }
@@ -1289,12 +1312,16 @@ done:
     {
       NDArray result (a_dims);
 
+#if defined (USE_VML)
+      vml_vpow_hook (a.fortran_vec (), b.fortran_vec (), result.fortran_vec (), len,
+      octave_quit_wrapper, NULL, NULL, NULL);
+#else
       for (octave_idx_type i = 0; i < len; i++)
         {
           octave_quit ();
           result(i) = std::pow (a(i), b(i));
         }
-
+#endif
       retval = result;
     }
 
@@ -2443,12 +2470,16 @@ elem_xpow (float a, const FloatNDArray& 
   else
     {
       FloatNDArray result (b.dims ());
+#if defined (USE_VML)
+      vml_vpowf_sv_hook (a, b.fortran_vec (), result.fortran_vec (), b.numel (),
+      octave_quit_wrapper, NULL, NULL, NULL);
+#else
       for (octave_idx_type i = 0; i < b.numel (); i++)
         {
           octave_quit ();
           result(i) = std::pow (a, b(i));
         }
-
+#endif
       retval = result;
     }
 
@@ -2496,12 +2527,16 @@ elem_xpow (const FloatNDArray& a, float 
       else
         {
           FloatNDArray result (a.dims ());
+#if defined (USE_VML)
+      vml_vpowf_vs_hook (a.fortran_vec (), b, result.fortran_vec (), a.numel (),
+      octave_quit_wrapper, NULL, NULL, NULL);
+#else
           for (octave_idx_type i = 0; i < a.numel (); i++)
             {
               octave_quit ();
               result(i) = std::pow (a(i), b);
             }
-
+#endif
           retval = result;
         }
     }
@@ -2597,16 +2632,18 @@ done:
   else
     {
       FloatNDArray result (a_dims);
-
+#if defined (USE_VML)
+      vml_vpowf_hook (a.fortran_vec (), b.fortran_vec (), result.fortran_vec (), len,
+      octave_quit_wrapper, NULL, NULL, NULL);
+#else
       for (octave_idx_type i = 0; i < len; i++)
         {
           octave_quit ();
           result(i) = std::pow (a(i), b(i));
         }
-
+#endif
       retval = result;
     }
-
   return retval;
 }
 
