diff --git a/gtestsuite/CMakeLists.txt b/gtestsuite/CMakeLists.txt new file mode 100644 index 000000000..2e5387a82 --- /dev/null +++ b/gtestsuite/CMakeLists.txt @@ -0,0 +1,249 @@ +##Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.## + +cmake_minimum_required(VERSION 3.10.0) +set(CMAKE_CXX_COMPILER ${CXX_COMPILER}) + +project(Blis_GtestSuite) + +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.12.1 +) +#set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) +set(BUILD_GTEST ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) +include(GoogleTest) + +enable_testing() + +# Set the path to the BLIS installation. +if(NOT(BLIS_PATH)) + message(FATAL_ERROR "Need to provide a BLIS installation path during CMake invocation. Please use + $ cmake .. -DBLIS_PATH=/home/username/blis_installation") +endif() +# Set the path to BLIS include directory. +set(BLIS_INCLUDE ${BLIS_PATH}/include/blis) + +# Set OpenMP as the default option +set(ENABLE_THREADING "openmp" CACHE STRING "Setting OpenMP as the threading library") +# Set the possible values of theading libraries for cmake-gui +set_property(CACHE ENABLE_THREADING PROPERTY STRINGS "openmp" "pthreads" "no") + +# Set static BLIS as the default library we build against. +set(BLIS_LINKING_TYPE "static" CACHE STRING "Linking to a static BLIS library") +# Set the possible values of BLIS linking type for cmake-gui +set_property(CACHE BLIS_LINKING_TYPE PROPERTY STRINGS "static" "shared") + +if(BLIS_LINKING_TYPE STREQUAL "shared") + message(FATAL_ERROR "Using shared BLIS library is currently disabled.") +endif() + +option(ENABLE_VALGRIND "Run tests using valgrind" OFF) + +option(ENABLE_ASAN "Run tests using Address Sanatizer" OFF) + +# Set variable if the platform is Linux based. +if(UNIX AND NOT APPLE) + set(LINUX TRUE) +endif() + +# Throw an error if the platform is Apple. +if(APPLE) + message(FATAL_ERROR "Build system does not support Apple platform.") +endif() + +# Set the include paths. +set(INC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/inc) + +# Set compiler options and BLIS library for Linux. +if(LINUX) + # Add compiler definition. + + add_compile_options(-g -Wall -Wno-unused-function -Wfatal-errors -fPIC) + + if(ENABLE_ASAN) + add_definitions(-D__GTEST_VALGRIND_TEST__) + add_compile_options(-fsanitize=address -static-libsan) + endif() + + # Set GNU OpenMP library as the default option + set(OpenMP_LIBRARY "GNU" CACHE STRING "Using GNU OpenMP library") + # Set the possibe values of OpenMP runtimes + set_property(CACHE OpenMP_LIBRARY PROPERTY STRINGS "GNU" "Intel") + + if(ENABLE_THREADING STREQUAL "no") + if(BLIS_LINKING_TYPE STREQUAL "static") + set(Blis_LIBRARY "${BLIS_PATH}/lib/libblis.a" CACHE STRING "blis library path") + else() + set(Blis_LIBRARY "${BLIS_PATH}/lib/libblis.so" CACHE STRING "blis library path") + endif() + else() + if(BLIS_LINKING_TYPE STREQUAL "static") + set(Blis_LIBRARY "${BLIS_PATH}/lib/libblis-mt.a" CACHE STRING "blis library path") + else() + set(Blis_LIBRARY "${BLIS_PATH}/lib/libblis-mt.so" CACHE STRING "blis library path") + endif() + endif() +endif() + +# Set BLIS library for Windows. +if(WIN32) + if(ENABLE_THREADING STREQUAL "no") + if(BLIS_LINKING_TYPE STREQUAL "static") + set(Blis_LIBRARY "${BLIS_PATH}/bin/AOCL-LibBlis-Win.a" CACHE STRING "blis library path") + else() + set(Blis_LIBRARY "${BLIS_PATH}/bin/AOCL-LibBlis-Win-dll.lib" CACHE STRING "blis library path") + endif() + else() + if(BLIS_LINKING_TYPE STREQUAL "static") + set(Blis_LIBRARY "${BLIS_PATH}/bin/AOCL-LibBlis-Win-MT.a" CACHE STRING "blis library path") + else() + set(Blis_LIBRARY "${BLIS_PATH}/bin/AOCL-LibBlis-Win-MT-dll.lib" CACHE STRING "blis library path") + endif() + endif() +endif() + +# Since this is an out-of-source build we need to copy the input files in the correct destination. +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/input.general + ${CMAKE_CURRENT_SOURCE_DIR}/alphabeta.dat + ${CMAKE_CURRENT_SOURCE_DIR}/input.operations + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +add_executable(gtest_libblis + ${CMAKE_CURRENT_SOURCE_DIR}/src/gtest_suite.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/gtest_pthread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/blis_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/blis_inpfile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/blis_utils_int.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/blis_utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_process.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_addv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_amaxv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_axpbyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_axpyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_copyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_dotv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_dotxv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_normfv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_scalv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_scal2v.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_subv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_xpbyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_addm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_axpym.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_copym.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_normfm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_scalm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_scal2m.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_subm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_xpbym.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_axpy2v.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_dotaxpyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_axpyf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_dotxf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_dotxaxpyf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_gemv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_ger.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_hemv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_her.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_her2.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_symv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_syr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_syr2.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_trmv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_trsv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_gemm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_gemmt.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_hemm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_herk.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_her2k.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_symm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_syrk.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_syr2k.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_trmm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_trmm3.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ref_trsm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_randv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_randm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_addv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_amaxv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_axpbyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_axpyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_copyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_dotv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_dotxv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_normfv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_scalv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_scal2v.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_setv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_subv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_xpbyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_addm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_axpym.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_copym.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_normfm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_scalm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_scal2m.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_setm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_subm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_xpbym.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_axpy2v.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_dotaxpyv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_axpyf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_dotxf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_dotxaxpyf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_ger.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_hemv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_her.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_her2.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_symv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_syr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_syr2.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_trmv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_trsv.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemmt.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_hemm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_herk.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_her2k.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_symm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_syrk.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_syr2k.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_trmm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_trmm3.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_trsm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/lpgemm_utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemm_u8s8s32os32.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemm_u8s8s32os8.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemm_f32f32f32of32.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemm_u8s8s16os16.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemm_u8s8s16os8.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemm_bf16bf16f32of32.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/test_gemm_bf16bf16f32obf16.cpp +) + +target_include_directories(gtest_libblis PUBLIC ${INC_PATH} ${BLIS_INCLUDE}) +target_link_libraries(gtest_libblis gtest gtest_main ${Blis_LIBRARY} pthread) + +# Linking appropriate threading library. +if(ENABLE_THREADING STREQUAL "openmp") + if(LINUX) + if(OpenMP_LIBRARY STREQUAL "GNU") + target_link_libraries(gtest_libblis -fopenmp) + else() + target_link_libraries(gtest_libblis iomp5) + endif() + endif() +endif() + +add_test( + NAME gtest_libblis + COMMAND gtest_libblis +) + +#gtest_discover_tests(gtest_libblis) \ No newline at end of file diff --git a/gtestsuite/Makefile b/gtestsuite/Makefile new file mode 100644 index 000000000..11426efc4 --- /dev/null +++ b/gtestsuite/Makefile @@ -0,0 +1,211 @@ +################################################################################################ +## Compiler options +################################################################################################ +ifeq ($(AOCL),1) +CXX := clang++ #-stdlib=libc++ +else +CXX := g++ -std=c++11 +endif +CFLAGS := -c + + +# Flags passed to the C++ compiler. +CXXFLAGS += -g -Wall -Wno-unused-function -Wfatal-errors -fPIC -fnon-call-exceptions +#Enable macro __GTEST_VALGRIND_TEST__ only when valgrind tool is used +CXXFLAGS += #-D__GTEST_VALGRIND_TEST__ +#Enable below flags only when Address Sanitizer tool is used +CXXFLAGS += #-fsanitize=address -static-libsan +LIBPTHREAD := -fopenmp #-lpthread +LIBM := -lm +LDFLAGS := $(LIBM) $(LIBPTHREAD) + +BLIS_PATH := ../blis_gcc +BLIS_LIB := ${BLIS_PATH}/lib/libblis-mt.a +GTEST_LIB := ./lib/libgtest.a +INC_PATH := ./inc +LINUX_PATH := ${BLIS_PATH}/include/blis +GTEST_HEADERS := ./inc/gtest + +ifeq ($(mkl),1) +CXXFLAGS +=-D_POSIX_C_SOURCE=200112L +CXXFLAGS += -std=c++11 -DBLAS=\"mkl\" +LDFLAGS += -lrt +MKL_LIB_PATH := ${MKLROOT}/intel64 +# MKL +#MKL_LIB := -L$(MKL_LIB_PATH) \ +# -lmkl_intel_lp64 \ +# -lmkl_core \ +# -lmkl_sequential \ +# -lpthread -lm -ldl + +# Uncomment below lines & comment above lines to link with multi-threaded library. +MKL_LIB := -L$(MKL_LIB_PATH) \ + -lmkl_intel_lp64 \ + -lmkl_core \ + -lmkl_gnu_thread \ + -lpthread -lm -ldl -liomp5 +endif +LIB_PATH := $(MKL_LIB) $(BLIS_LIB) $(GTEST_LIB) +################################################################################################ +## Variables +################################################################################################ +BIN_PATH := bin +TEST_OBJ_PATH := obj +TEST_SRC_PATH := src +CPPS := $(shell ls $(TEST_SRC_PATH)/*.cpp) +TEMP := $(subst $(TEST_SRC_PATH)/, $(TEST_OBJ_PATH)/, $(CPPS)) +OBJS := $(subst .cpp, .o, $(TEMP)) +HEADERS := $(shell ls inc/*.h) +INCLUDE_PATH := -I$(INC_PATH) -I$(LINUX_PATH) -I$(GTEST_HEADERS) + + +TESTSUITE_OUT_FILE := output.testsuite +ifneq ($(mkl),1) +TEST_EXE := $(BIN_PATH)/libblis_gtest +else +TEST_EXE := $(BIN_PATH)/gtest_mkl +endif + + +TEST_OBJS := $(TEST_OBJ_PATH)/gtest_suite.o \ + $(TEST_OBJ_PATH)/gtest_pthread.o \ + $(TEST_OBJ_PATH)/blis_api.o \ + $(TEST_OBJ_PATH)/blis_inpfile.o \ + $(TEST_OBJ_PATH)/blis_utils_int.o \ + $(TEST_OBJ_PATH)/blis_utils.o \ + $(TEST_OBJ_PATH)/main.o \ + $(TEST_OBJ_PATH)/test_process.o \ + $(TEST_OBJ_PATH)/ref_addv.o \ + $(TEST_OBJ_PATH)/ref_amaxv.o \ + $(TEST_OBJ_PATH)/ref_axpbyv.o \ + $(TEST_OBJ_PATH)/ref_axpyv.o \ + $(TEST_OBJ_PATH)/ref_copyv.o \ + $(TEST_OBJ_PATH)/ref_dotv.o \ + $(TEST_OBJ_PATH)/ref_dotxv.o \ + $(TEST_OBJ_PATH)/ref_normfv.o \ + $(TEST_OBJ_PATH)/ref_scalv.o \ + $(TEST_OBJ_PATH)/ref_scal2v.o \ + $(TEST_OBJ_PATH)/ref_subv.o \ + $(TEST_OBJ_PATH)/ref_xpbyv.o \ + $(TEST_OBJ_PATH)/ref_addm.o \ + $(TEST_OBJ_PATH)/ref_axpym.o \ + $(TEST_OBJ_PATH)/ref_copym.o \ + $(TEST_OBJ_PATH)/ref_normfm.o \ + $(TEST_OBJ_PATH)/ref_scalm.o \ + $(TEST_OBJ_PATH)/ref_scal2m.o \ + $(TEST_OBJ_PATH)/ref_subm.o \ + $(TEST_OBJ_PATH)/ref_xpbym.o \ + $(TEST_OBJ_PATH)/ref_axpy2v.o \ + $(TEST_OBJ_PATH)/ref_dotaxpyv.o \ + $(TEST_OBJ_PATH)/ref_axpyf.o \ + $(TEST_OBJ_PATH)/ref_dotxf.o \ + $(TEST_OBJ_PATH)/ref_dotxaxpyf.o \ + $(TEST_OBJ_PATH)/ref_gemv.o \ + $(TEST_OBJ_PATH)/ref_ger.o \ + $(TEST_OBJ_PATH)/ref_hemv.o \ + $(TEST_OBJ_PATH)/ref_her.o \ + $(TEST_OBJ_PATH)/ref_her2.o \ + $(TEST_OBJ_PATH)/ref_symv.o \ + $(TEST_OBJ_PATH)/ref_syr.o \ + $(TEST_OBJ_PATH)/ref_syr2.o \ + $(TEST_OBJ_PATH)/ref_trmv.o \ + $(TEST_OBJ_PATH)/ref_trsv.o \ + $(TEST_OBJ_PATH)/ref_gemm.o \ + $(TEST_OBJ_PATH)/ref_gemmt.o \ + $(TEST_OBJ_PATH)/ref_hemm.o \ + $(TEST_OBJ_PATH)/ref_herk.o \ + $(TEST_OBJ_PATH)/ref_her2k.o \ + $(TEST_OBJ_PATH)/ref_symm.o \ + $(TEST_OBJ_PATH)/ref_syrk.o \ + $(TEST_OBJ_PATH)/ref_syr2k.o \ + $(TEST_OBJ_PATH)/ref_trmm.o \ + $(TEST_OBJ_PATH)/ref_trmm3.o \ + $(TEST_OBJ_PATH)/ref_trsm.o \ + $(TEST_OBJ_PATH)/test_randv.o \ + $(TEST_OBJ_PATH)/test_randm.o \ + $(TEST_OBJ_PATH)/test_addv.o \ + $(TEST_OBJ_PATH)/test_amaxv.o \ + $(TEST_OBJ_PATH)/test_axpbyv.o \ + $(TEST_OBJ_PATH)/test_axpyv.o \ + $(TEST_OBJ_PATH)/test_copyv.o \ + $(TEST_OBJ_PATH)/test_dotv.o \ + $(TEST_OBJ_PATH)/test_dotxv.o \ + $(TEST_OBJ_PATH)/test_normfv.o \ + $(TEST_OBJ_PATH)/test_scalv.o \ + $(TEST_OBJ_PATH)/test_scal2v.o \ + $(TEST_OBJ_PATH)/test_setv.o \ + $(TEST_OBJ_PATH)/test_subv.o \ + $(TEST_OBJ_PATH)/test_xpbyv.o \ + $(TEST_OBJ_PATH)/test_addm.o \ + $(TEST_OBJ_PATH)/test_axpym.o \ + $(TEST_OBJ_PATH)/test_copym.o \ + $(TEST_OBJ_PATH)/test_normfm.o \ + $(TEST_OBJ_PATH)/test_scalm.o \ + $(TEST_OBJ_PATH)/test_scal2m.o \ + $(TEST_OBJ_PATH)/test_setm.o \ + $(TEST_OBJ_PATH)/test_subm.o \ + $(TEST_OBJ_PATH)/test_xpbym.o \ + $(TEST_OBJ_PATH)/test_axpy2v.o \ + $(TEST_OBJ_PATH)/test_dotaxpyv.o \ + $(TEST_OBJ_PATH)/test_axpyf.o \ + $(TEST_OBJ_PATH)/test_dotxf.o \ + $(TEST_OBJ_PATH)/test_dotxaxpyf.o \ + $(TEST_OBJ_PATH)/test_gemv.o \ + $(TEST_OBJ_PATH)/test_ger.o \ + $(TEST_OBJ_PATH)/test_hemv.o \ + $(TEST_OBJ_PATH)/test_her.o \ + $(TEST_OBJ_PATH)/test_her2.o \ + $(TEST_OBJ_PATH)/test_symv.o \ + $(TEST_OBJ_PATH)/test_syr.o \ + $(TEST_OBJ_PATH)/test_syr2.o \ + $(TEST_OBJ_PATH)/test_trmv.o \ + $(TEST_OBJ_PATH)/test_trsv.o \ + $(TEST_OBJ_PATH)/test_gemm.o \ + $(TEST_OBJ_PATH)/test_gemmt.o \ + $(TEST_OBJ_PATH)/test_hemm.o \ + $(TEST_OBJ_PATH)/test_herk.o \ + $(TEST_OBJ_PATH)/test_her2k.o \ + $(TEST_OBJ_PATH)/test_symm.o \ + $(TEST_OBJ_PATH)/test_syrk.o \ + $(TEST_OBJ_PATH)/test_syr2k.o \ + $(TEST_OBJ_PATH)/test_trmm.o \ + $(TEST_OBJ_PATH)/test_trmm3.o \ + $(TEST_OBJ_PATH)/test_trsm.o \ + $(TEST_OBJ_PATH)/lpgemm_utils.o \ + $(TEST_OBJ_PATH)/test_gemm_u8s8s16os8.o \ + $(TEST_OBJ_PATH)/test_gemm_u8s8s32os8.o \ + $(TEST_OBJ_PATH)/test_gemm_u8s8s16os16.o \ + $(TEST_OBJ_PATH)/test_gemm_u8s8s32os32.o \ + $(TEST_OBJ_PATH)/test_gemm_f32f32f32of32.o \ + $(TEST_OBJ_PATH)/test_gemm_bf16bf16f32of32.o \ + $(TEST_OBJ_PATH)/test_gemm_bf16bf16f32obf16.o + +#all: build run + +build: $(TEST_EXE) + +$(shell mkdir -p $(TEST_OBJ_PATH) $(BIN_PATH)) + +$(TEST_EXE): $(TEST_OBJS) $(HEADERS) + @echo "------------------------------------------" + @echo "Creating the executable for the Program" + @echo "------------------------------------------" + $(CXX) $(CXXFLAGS) $(INCLUDE_PATH) $(TEST_OBJS) $(LIB_PATH) $(LDFLAGS) -o $(TEST_EXE) + +$(TEST_OBJ_PATH)/%.o: $(TEST_SRC_PATH)/%.cpp + @echo "------------------------------------------" + @echo "Compiling the file $<" + @echo "------------------------------------------" + $(CXX) $(CFLAGS) $(CXXFLAGS) $(INCLUDE_PATH) $< $(LIBPTHREAD) -o $@ + + +# -- Test run/check rules -- +run: $(TEST_EXE) +# @echo "Running $(TEST_EXE) with output redirected to '$(TESTSUITE_OUT_FILE)'" + @./$(TEST_EXE) > $(TESTSUITE_OUT_FILE) + @./$(TEST_EXE) + + +clean: + rm -rf $(TEST_OBJ_PATH)/*.o $(TEST_EXE) + rm -rf $(TEST_OBJ_PATH) $(BIN_PATH) diff --git a/gtestsuite/README.md b/gtestsuite/README.md new file mode 100644 index 000000000..f494861c9 --- /dev/null +++ b/gtestsuite/README.md @@ -0,0 +1,38 @@ +Steps to build gtestsuite executable on linux +1. Set BLIS_PATH( blis installation path ) in gtestsuite Makefile. +2. To build executable + GCC compiler : type "make" + AOCC compiler : type "make AOCL=1" + executable will be generated in bin folder. +3. Set input parameters in input.general file and select api's from input.operations file. +4. Finally run the executable + $./bin/libblis_gtest + +Steps to build gtestsuite executable and run valdrind tool +1. In gtestsuite Makefile, define the macro/enable "__GTEST_VALGRIND_TEST__(-D__GTEST_VALGRIND_TEST__)" + Note : Undefine the macro "__GTEST_VALGRIND_TEST__" when it is not built for valgrind test. +2. Generate the executable as mentioned above(Steps to build gtestsuite executable) +3. Set input parameters and select api's to test in input.general and input.operations respectively +4. Finally run the executable + $ OMP_NUM_THREADS=1 valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes -s + +Steps to build blis library and gtestsuite executable and run ASAN +1. Build blis library with the flag CFLAGS="-g -fsanitize=address" + CC=clang ./configure -a aocl_gemm --enable-threading=openmp --enable-cblas CFLAGS="-g -fsanitize=address" auto +2. And in gtestsuite Makefile, define the macro/enable "__GTEST_VALGRIND_TEST__(-D__GTEST_VALGRIND_TEST__)" + and even set/enable "CXXFLAGS += -fsanitize=address -static-libsan". +3. Generate the executable as mentioned above(Steps to build gtestsuite executable) +4. Set input parameters in input.general file and select api's from input.operations file. +5. Finally run the executable + $./bin/libblis_gtest + +Steps to build gtestsuite executable for mkl library(machine lib-daytonax-04) +1. Goto gtestsuite folder and export the following (paths depends on the machine, where intel package is placed) + export LD_LIBRARY_PATH=/home/intel2019/update_05/intel64/:$LD_LIBRARY_PATH + export MKLROOT=/home/intel2019/update_05/ + export MKL_DEBUG_CPU_TYPE=5 + export MKL_ENABLE_INSTRUCTIONS=AVX2 +2. Type "make mkl=1" or "make AOCL=1 mkl=1(for clang compiler)", executable will be generated in bin folder +3. Set input parameters in input.general file and select api's from input.operations file. +4. Finally run the executable + $./bin/gtest_mkl diff --git a/gtestsuite/alphabeta.dat b/gtestsuite/alphabeta.dat new file mode 100644 index 000000000..bcd6f3a0c --- /dev/null +++ b/gtestsuite/alphabeta.dat @@ -0,0 +1,21 @@ +# -------------------------------------------------------------------------- +# +# alphabeta.dat +# BLIS test suite +# +# This file contains alpha and beta values which are used +# in BLIS operations +# +# -------------------------------------------------------------------------- + +5 #Number of alpha and/or beta values +-1.000 0.000 #const double alpha[5] = {-1.000,0.000,1.000,0.999,2.333}; +0.000 0.000 +1.000 0.000 +0.999 0.000 +2.333 0.000 +-1.000 0.000 #const double beta[5] = {-1.000,0.000,1.000,0.999,2.333}; +0.000 0.000 +1.000 0.000 +0.999 0.000 +2.333 0.000 \ No newline at end of file diff --git a/gtestsuite/inc/blis_test.h b/gtestsuite/inc/blis_test.h new file mode 100644 index 000000000..873151023 --- /dev/null +++ b/gtestsuite/inc/blis_test.h @@ -0,0 +1,519 @@ +#ifndef BLIS_TEST_H +#define BLIS_TEST_H + +#include +#include +#include +#include +#include + +#include "blis.h" +#include "gtest/gtest.h" + +using namespace std; + +// --- System headers --------------------------------------------------------- +// For va_* functions. +#include +// For string manipulation functions. +#include +// For other string manipulation functions (e.g. isspace()). +#include + +// For POSIX stuff. +#ifndef _MSC_VER +#include +#endif + +// --- Constants and types ---------------------------------------------------- +#define PARAMETERS_FILENAME "input.general" +#define OPERATIONS_FILENAME "input.operations" +#define ALPHA_BETA_FILENAME "alphabeta.dat" +#define INPUT_COMMENT_CHAR '#' +#define OUTPUT_COMMENT_CHAR '%' + +#define BLIS_FILE_PREFIX_STR "libblis_test" +#define BLIS_FILEDATA_PREFIX_STR "blis" +#define BLAS_FILEDATA_PREFIX_STR "blas" +#define CBLAS_FILEDATA_PREFIX_STR "cblas" + +#define INPUT_BUFFER_SIZE 256 +#define MAX_FILENAME_LENGTH 1000 +#define MAX_BINARY_NAME_LENGTH 256 +#define MAX_FUNC_STRING_LENGTH 36 +#define FLOPS_PER_UNIT_PERF 1e9 + +#define MAX_NUM_MSTORAGE 4 +#define MAX_NUM_VSTORAGE 5 +#define MAX_NUM_DATATYPES 4 +#define MAX_NUM_PARAMETERS 7 +#define MAX_NUM_DIMENSIONS 3 +#define MAX_NUM_OPERANDS 5 + +#define MAX_PASS_STRING_LENGTH 32 +#define BLIS_TEST_FAIL_STRING "FAILURE" +#define BLIS_TEST_WARN_STRING "MARGINAL" +#define BLIS_TEST_PASS_STRING "PASS" +#define BLIS_TEST_OVERFLOW_STRING "OVERFLOW" +#define BLIS_TEST_UNDERFLOW_STRING "UNDERFLOW" + +#define ON_FAILURE_IGNORE_CHAR 'i' +#define ON_FAILURE_SLEEP_CHAR 's' +#define ON_FAILURE_ABORT_CHAR 'a' + +#define SECONDS_TO_SLEEP 3 + +#define DISABLE 0 +#define ENABLE 1 +#define ENABLE_ONLY 2 + +#define MAX_PARAM_VALS_PER_TYPE 4 +#define BLIS_TEST_PARAM_SIDE_CHARS "lr" +#define BLIS_TEST_PARAM_UPLO_CHARS "lu" +#define BLIS_TEST_PARAM_UPLODE_CHARS "dlu" +#define BLIS_TEST_PARAM_TRANS_CHARS "ncth" +#define BLIS_TEST_PARAM_CONJ_CHARS "nc" +#define BLIS_TEST_PARAM_DIAG_CHARS "nu" + +#define BLIS_INIT_SUCCESS 0 +#define BLIS_INIT_FAILURE -1 +#define NUM_PARAM_TYPES 6 +#define MAX_NUM_ABVALUES 5 + +/*Allocating buffers with malloc in gtestsuite */ +#define __GTESTSUITE_MALLOC_BUFFER__ + +typedef enum +{ + BLIS_TEST_PARAM_SIDE = 0, + BLIS_TEST_PARAM_UPLO = 1, + BLIS_TEST_PARAM_UPLODE = 2, + BLIS_TEST_PARAM_TRANS = 3, + BLIS_TEST_PARAM_CONJ = 4, + BLIS_TEST_PARAM_DIAG = 5, +} param_t; + +#define MAX_STORE_VALS_PER_TYPE 4 +#define BLIS_TEST_MSTORE_CHARS "crg" +#define BLIS_TEST_VSTORE_CHARS "crji" + +#define NUM_OPERAND_TYPES 2 +typedef enum +{ + BLIS_TEST_MATRIX_OPERAND = 0, + BLIS_TEST_VECTOR_OPERAND = 1 +} operand_t; + +typedef enum +{ + API_BLIS = 0, + API_CBLAS = 1, + API_BLAS = 2 +} api_t; + +typedef enum +{ + BLIS_DEFAULT = 0, + BLIS_OVERFLOW = 1, + BLIS_UNDERFLOW = 2 +} vflg_t; + +typedef enum +{ + BLIS_TEST_DIMS_MNK = 0, + BLIS_TEST_DIMS_MN = 1, + BLIS_TEST_DIMS_MK = 2, + BLIS_TEST_DIMS_M = 3, + BLIS_TEST_DIMS_MF = 4, + BLIS_TEST_DIMS_K = 5, + BLIS_TEST_NO_DIMS = 6 +} dimset_t; + +typedef enum +{ + BLIS_TEST_SEQ_UKERNEL = 0, + BLIS_TEST_SEQ_FRONT_END = 1, + BLIS_TEST_MT_FRONT_END = 2 +} iface_t; + + +typedef enum +{ + BLIS_TEST_RAND_REAL_VALUES = 0, + BLIS_TEST_RAND_NARROW_POW2 = 1 +} rand_t; + +typedef struct +{ + double failwarn; + double warnpass; +} thresh_t; + +const thresh_t thresh[BLIS_NUM_FP_TYPES] = { { 1e-04, 1e-05 }, // warn, pass for s + { 1e-04, 1e-05 }, // warn, pass for c + { 1e-13, 1e-14 }, // warn, pass for d + { 1e-13, 1e-14 } }; // warn, pass for z + +#define SIZE 4 +typedef dcomplex atom_t; + +typedef struct +{ + dim_t m; + dim_t n; + dim_t k; +} tensor_t; + +typedef struct +{ + unsigned int n_repeats; + unsigned int n_mstorage; + unsigned int n_vstorage; + char storage[ NUM_OPERAND_TYPES ][ MAX_NUM_MSTORAGE + 1 ]; + unsigned int mix_all_storage; + unsigned int alignment; + unsigned int rand_method; + unsigned int gs_spacing; + unsigned int n_datatypes; + char datatype_char[ MAX_NUM_DATATYPES + 1 ]; + num_t datatype[ MAX_NUM_DATATYPES + 1 ]; + unsigned int mixed_domain; + unsigned int mixed_precision; + unsigned int p_first; + unsigned int p_max; + unsigned int p_inc; + unsigned int ind_enable[ BLIS_NUM_IND_METHODS ]; + unsigned int n_app_threads; + char reaction_to_failure; + unsigned int output_matlab_format; + unsigned int output_files; + unsigned int error_checking_level; + unsigned int is_mixed_dt; + unsigned int n_param_combos; + unsigned int n_store_combos; + unsigned int n_dt_combos; + char** pc_str; + char** sc_str; + char** dc_str; + unsigned int indim[MAX_NUM_DATATYPES][BLIS_NAT+1]; + unsigned int indn[MAX_NUM_DATATYPES]; + num_t dt[MAX_NUM_DATATYPES]; + bool initparams; + + api_t api; + unsigned int abf; + atom_t *alpha; + atom_t *beta; + unsigned int nab; + unsigned int ldf; + unsigned int ld[3]; + unsigned int bitextf; + unsigned int dimf; + unsigned int ndim; + unsigned int nanf; + tensor_t *dim; + + unsigned int passflag; + vflg_t oruflw; + unsigned int bitrp; + + char op_t; + +} test_params_t; + +typedef struct +{ + char libblis_test_parameters_filename[ MAX_FILENAME_LENGTH + 1 ]; + char libblis_test_operations_filename[ MAX_FILENAME_LENGTH + 1 ]; + char libblis_test_alphabeta_parameter[ MAX_FILENAME_LENGTH + 1 ]; +} blis_string_t; + +typedef struct +{ + // parent test_ops_t struct + struct test_ops_s* ops; + + opid_t opid; + dimset_t dimset; + + int op_switch; + unsigned int n_dims; + + int dim_spec[ MAX_NUM_DIMENSIONS ]; + int dim_aux[ MAX_NUM_DIMENSIONS ]; + unsigned int n_params; + char params[ MAX_NUM_PARAMETERS ]; + bool test_done; +} test_op_t; + +typedef struct test_ops_s +{ + // individual override + int indiv_over; + + // section overrides + int util_over; + int l1v_over; + int l1m_over; + int l1f_over; + int l2_over; + int l3ukr_over; + int l3_over; + + // util + test_op_t randv; + test_op_t randm; + + // level-1v + test_op_t addv; + test_op_t amaxv; + test_op_t axpbyv; + test_op_t axpyv; + test_op_t copyv; + test_op_t dotv; + test_op_t dotxv; + test_op_t normfv; + test_op_t scalv; + test_op_t scal2v; + test_op_t setv; + test_op_t subv; + test_op_t xpbyv; + + // level-1m + test_op_t addm; + test_op_t axpym; + test_op_t copym; + test_op_t normfm; + test_op_t scalm; + test_op_t scal2m; + test_op_t setm; + test_op_t subm; + test_op_t xpbym; + + // level-1f + test_op_t axpy2v; + test_op_t dotaxpyv; + test_op_t axpyf; + test_op_t dotxf; + test_op_t dotxaxpyf; + + // level-2 + test_op_t gemv; + test_op_t ger; + test_op_t hemv; + test_op_t her; + test_op_t her2; + test_op_t symv; + test_op_t syr; + test_op_t syr2; + test_op_t trmv; + test_op_t trsv; + + // level-3 micro-kernels + test_op_t gemm_ukr; + test_op_t trsm_ukr; + test_op_t gemmtrsm_ukr; + + // level-3 + test_op_t gemm; + test_op_t gemmt; + test_op_t hemm; + test_op_t herk; + test_op_t her2k; + test_op_t symm; + test_op_t syrk; + test_op_t syr2k; + test_op_t trmm; + test_op_t trmm3; + test_op_t trsm; + + test_op_t gemm_u8s8s32os32; + test_op_t gemm_u8s8s32os8; + test_op_t gemm_f32f32f32of32; + test_op_t gemm_u8s8s16os16; + test_op_t gemm_u8s8s16os8; + test_op_t gemm_bf16bf16f32of32; + test_op_t gemm_bf16bf16f32obf16; + +} test_ops_t; + +typedef struct +{ + uint32_t tcnt; + uint32_t cntf; +} printres_t; + +typedef struct +{ + test_params_t* params; + test_op_t* op; + const char* str; + unsigned int nt; + unsigned int id; + iface_t iface; + unsigned int xc; + bli_pthread_barrier_t* barrier; + printres_t* pfr; +} thread_data_t; + +typedef struct +{ + char inputfile[ MAX_FILENAME_LENGTH ]; + int fileread; +} input_file_t; + +typedef struct +{ + test_params_t *params; + test_ops_t *ops; + input_file_t *pfile; + bli_pthread_t *pthread; + thread_data_t *tdata; +} input_data_t; + +void* libblis_test_randv_thread_entry( void* tdata_void ); +void* libblis_test_randm_thread_entry( void* tdata_void ); + +void* libblis_test_addv_thread_entry( void* tdata_void ); +void* libblis_test_amaxv_thread_entry( void* tdata_void ); +void* libblis_test_axpbyv_thread_entry( void* tdata_void ); +void* libblis_test_axpyv_thread_entry( void* tdata_void ); +void* libblis_test_copyv_thread_entry( void* tdata_void ); +void* libblis_test_dotv_thread_entry( void* tdata_void ); +void* libblis_test_dotxv_thread_entry( void* tdata_void ); +void* libblis_test_normfv_thread_entry( void* tdata_void ); +void* libblis_test_scal2v_thread_entry( void* tdata_void ); +void* libblis_test_scalv_thread_entry( void* tdata_void ); +void* libblis_test_setv_thread_entry( void* tdata_void ); +void* libblis_test_subv_thread_entry( void* tdata_void ); + +void* libblis_test_xpbyv_thread_entry( void* tdata_void ); +void* libblis_test_axpy2v_thread_entry( void* tdata_void ); +void* libblis_test_dotaxpyv_thread_entry( void* tdata_void ); +void* libblis_test_axpyf_thread_entry( void* tdata_void ); +void* libblis_test_dotxf_thread_entry( void* tdata_void ); +void* libblis_test_dotxaxpyf_thread_entry( void* tdata_void ); + +void* libblis_test_addm_thread_entry( void* tdata_void ); +void* libblis_test_axpym_thread_entry( void* tdata_void ); +void* libblis_test_copym_thread_entry( void* tdata_void ); +void* libblis_test_normfm_thread_entry( void* tdata_void ); +void* libblis_test_scal2m_thread_entry( void* tdata_void ); +void* libblis_test_scalm_thread_entry( void* tdata_void ); +void* libblis_test_setm_thread_entry( void* tdata_void ); +void* libblis_test_subm_thread_entry( void* tdata_void ); +void* libblis_test_xpbym_thread_entry( void* tdata_void ); + +void* libblis_test_gemv_thread_entry( void* tdata_void ); +void* libblis_test_ger_thread_entry( void* tdata_void ); +void* libblis_test_hemv_thread_entry( void* tdata_void ); +void* libblis_test_her_thread_entry( void* tdata_void ); +void* libblis_test_her2_thread_entry( void* tdata_void ); +void* libblis_test_symv_thread_entry( void* tdata_void ); +void* libblis_test_syr_thread_entry( void* tdata_void ); +void* libblis_test_syr2_thread_entry( void* tdata_void ); +void* libblis_test_trmv_thread_entry( void* tdata_void ); +void* libblis_test_trsv_thread_entry( void* tdata_void ); + +void* libblis_test_gemm_thread_entry( void* tdata_void ); +void* libblis_test_gemmt_thread_entry( void* tdata_void ); +void* libblis_test_hemm_thread_entry( void* tdata_void ); +void* libblis_test_herk_thread_entry( void* tdata_void ); +void* libblis_test_her2k_thread_entry( void* tdata_void ); +void* libblis_test_symm_thread_entry( void* tdata_void ); +void* libblis_test_syrk_thread_entry( void* tdata_void ); +void* libblis_test_syr2k_thread_entry( void* tdata_void ); +void* libblis_test_trmm_thread_entry( void* tdata_void ); +void* libblis_test_trmm3_thread_entry( void* tdata_void ); +void* libblis_test_trsm_thread_entry( void* tdata_void ); + +void* libblis_test_gemm_u8s8s32os32_thread_entry( void* tdata_void ); +void* libblis_test_gemm_f32f32f32of32_thread_entry( void* tdata_void ); +void* libblis_test_gemm_u8s8s16os8_thread_entry( void* tdata_void ); +void* libblis_test_gemm_u8s8s32os8_thread_entry( void* tdata_void ); +void* libblis_test_gemm_u8s8s16os16_thread_entry( void* tdata_void ); +void* libblis_test_gemm_bf16bf16f32of32_thread_entry( void* tdata_void ); +void* libblis_test_gemm_bf16bf16f32obf16_thread_entry( void* tdata_void ); + +/* + * The derived class for Blis Test Suite + * where all the data members and member functions are + * declared and defined + */ +class AoclBlisTestFixture : public ::testing::TestWithParam +{ + public: + void SetUp() override + { + params = GetParam().params; + ops = GetParam().ops; + pthread = GetParam().pthread; + tdata = GetParam().tdata; + pfile = GetParam().pfile; + + if(pfile->fileread != 1) + { + nt = ( unsigned int )params->n_app_threads; + barrier = + (bli_pthread_barrier_t*)bli_malloc_user( sizeof( bli_pthread_barrier_t ) ); + bli_pthread_barrier_init( barrier, NULL, nt ); + } + pfr = (printres_t*)bli_malloc_user( sizeof( printres_t ) ); + memset(pfr, 0, sizeof(printres_t)); + } + + void TearDown() override + { + if(pfile->fileread != 1) + { + bli_pthread_barrier_destroy( barrier ); + bli_free_user( barrier ); + } + bli_free_user( pfr ); + } + + bool libblis_test_preprocess_params( test_params_t* params, test_op_t* op, + iface_t iface, const char* p_types, const char* o_types); + + bool create_params(test_params_t *params); + + bool destroy_params(test_params_t *params); + + int libblis_test_read_params_inpfile( char* filename, test_params_t* params, + test_ops_t* ops, printres_t* pfr); + protected: + unsigned int nt; + input_data_t* inData; + test_params_t* params; + test_ops_t* ops; + tensor_t* dim; + bli_pthread_t* pthread; + thread_data_t* tdata; + printres_t* pfr; + input_file_t* pfile; + bli_pthread_barrier_t* barrier; +}; + +class BlisTestSuite +{ + private: + blis_string_t blis_string; + input_file_t pfile; + test_params_t params; + test_ops_t ops; + public: + ~BlisTestSuite( ); + test_params_t* getParamsStr() { return &(this->params); } + blis_string_t* getStgStr() { return &(this->blis_string); } + test_ops_t* getOpsStr() { return &(this->ops); } + input_file_t* getfileStr() { return &(this->pfile); } + + int libblis_test_init_strings(blis_string_t *test_data); + int libblis_test_inpfile( char* input_filename, input_file_t* pfile); + int libblis_test_read_params_file( char* input_filename, + test_params_t* params, char *abpf); + int libblis_test_read_ops_file( char* input_filename, test_ops_t* ops ); + void CreateGtestFilters(test_ops_t* ops, string& str); + void CreateGtestFilters_api(input_file_t* pfile, string& str); +}; +#endif // BLIS_TEST_H diff --git a/gtestsuite/inc/gtest/gtest-death-test.h b/gtestsuite/inc/gtest/gtest-death-test.h new file mode 100644 index 000000000..9b4d4d133 --- /dev/null +++ b/gtestsuite/inc/gtest/gtest-death-test.h @@ -0,0 +1,346 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +#include "gtest/internal/gtest-death-test-internal.h" + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +namespace internal { + +// Returns a Boolean value indicating whether the caller is currently +// executing in the context of the death test child process. Tools such as +// Valgrind heap checkers may need this to modify their behavior in death +// tests. IMPORTANT: This is an internal utility. Using it may break the +// implementation of death tests. User code MUST NOT use it. +GTEST_API_ bool InDeathTestChild(); + +} // namespace internal + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i; +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// The final parameter to each of these macros is a matcher applied to any data +// the sub-process wrote to stderr. For compatibility with existing tests, a +// bare string is interpreted as a regular expression matcher. +// +// On the regular expressions used in death tests: +// +// GOOGLETEST_CM0005 DO NOT DELETE +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows or Mac), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// + +// Asserts that a given `statement` causes the program to exit, with an +// integer exit status that satisfies `predicate`, and emitting error output +// that matches `matcher`. +# define ASSERT_EXIT(statement, predicate, matcher) \ + GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_FATAL_FAILURE_) + +// Like `ASSERT_EXIT`, but continues on to successive tests in the +// test suite, if any: +# define EXPECT_EXIT(statement, predicate, matcher) \ + GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given `statement` causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches `matcher`. +# define ASSERT_DEATH(statement, matcher) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher) + +// Like `ASSERT_DEATH`, but continues on to successive tests in the +// test suite, if any: +# define EXPECT_DEATH(statement, matcher) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + ExitedWithCode(const ExitedWithCode&) = default; + void operator=(const ExitedWithCode& other) = delete; + bool operator()(int exit_status) const; + private: + const int exit_code_; +}; + +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA +// Tests that an exit code describes an exit due to termination by a +// given signal. +// GOOGLETEST_CM0006 DO NOT DELETE +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +# endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +# ifdef NDEBUG + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + GTEST_EXECUTE_STATEMENT_(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + GTEST_EXECUTE_STATEMENT_(statement, regex) + +# else + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +# endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters +// on systems that support death tests. This allows one to write such a macro on +// a system that does not support death tests and be sure that it will compile +// on a death-test supporting system. It is exposed publicly so that systems +// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST +// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and +// ASSERT_DEATH_IF_SUPPORTED. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter if and only if EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) +#endif + +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ diff --git a/gtestsuite/inc/gtest/gtest-matchers.h b/gtestsuite/inc/gtest/gtest-matchers.h new file mode 100644 index 000000000..9fa34a05b --- /dev/null +++ b/gtestsuite/inc/gtest/gtest-matchers.h @@ -0,0 +1,930 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This file implements just enough of the matcher interface to allow +// EXPECT_DEATH and friends to accept a matcher argument. + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ + +#include +#include +#include +#include +#include + +#include "gtest/gtest-printers.h" +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +// MSVC warning C5046 is new as of VS2017 version 15.8. +#if defined(_MSC_VER) && _MSC_VER >= 1915 +#define GTEST_MAYBE_5046_ 5046 +#else +#define GTEST_MAYBE_5046_ +#endif + +GTEST_DISABLE_MSC_WARNINGS_PUSH_( + 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by + clients of class B */ + /* Symbol involving type with internal linkage not defined */) + +namespace testing { + +// To implement a matcher Foo for type T, define: +// 1. a class FooMatcherMatcher that implements the matcher interface: +// using is_gtest_matcher = void; +// bool MatchAndExplain(const T&, std::ostream*); +// (MatchResultListener* can also be used instead of std::ostream*) +// void DescribeTo(std::ostream*); +// void DescribeNegationTo(std::ostream*); +// +// 2. a factory function that creates a Matcher object from a +// FooMatcherMatcher. + +class MatchResultListener { + public: + // Creates a listener object with the given underlying ostream. The + // listener does not own the ostream, and does not dereference it + // in the constructor or destructor. + explicit MatchResultListener(::std::ostream* os) : stream_(os) {} + virtual ~MatchResultListener() = 0; // Makes this class abstract. + + // Streams x to the underlying ostream; does nothing if the ostream + // is NULL. + template + MatchResultListener& operator<<(const T& x) { + if (stream_ != nullptr) *stream_ << x; + return *this; + } + + // Returns the underlying ostream. + ::std::ostream* stream() { return stream_; } + + // Returns true if and only if the listener is interested in an explanation + // of the match result. A matcher's MatchAndExplain() method can use + // this information to avoid generating the explanation when no one + // intends to hear it. + bool IsInterested() const { return stream_ != nullptr; } + + private: + ::std::ostream* const stream_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener); +}; + +inline MatchResultListener::~MatchResultListener() { +} + +// An instance of a subclass of this knows how to describe itself as a +// matcher. +class GTEST_API_ MatcherDescriberInterface { + public: + virtual ~MatcherDescriberInterface() {} + + // Describes this matcher to an ostream. The function should print + // a verb phrase that describes the property a value matching this + // matcher should have. The subject of the verb phrase is the value + // being matched. For example, the DescribeTo() method of the Gt(7) + // matcher prints "is greater than 7". + virtual void DescribeTo(::std::ostream* os) const = 0; + + // Describes the negation of this matcher to an ostream. For + // example, if the description of this matcher is "is greater than + // 7", the negated description could be "is not greater than 7". + // You are not required to override this when implementing + // MatcherInterface, but it is highly advised so that your matcher + // can produce good error messages. + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "not ("; + DescribeTo(os); + *os << ")"; + } +}; + +// The implementation of a matcher. +template +class MatcherInterface : public MatcherDescriberInterface { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener' if necessary (see the next paragraph), in + // the form of a non-restrictive relative clause ("which ...", + // "whose ...", etc) that describes x. For example, the + // MatchAndExplain() method of the Pointee(...) matcher should + // generate an explanation like "which points to ...". + // + // Implementations of MatchAndExplain() should add an explanation of + // the match result *if and only if* they can provide additional + // information that's not already present (or not obvious) in the + // print-out of x and the matcher's description. Whether the match + // succeeds is not a factor in deciding whether an explanation is + // needed, as sometimes the caller needs to print a failure message + // when the match succeeds (e.g. when the matcher is used inside + // Not()). + // + // For example, a "has at least 10 elements" matcher should explain + // what the actual element count is, regardless of the match result, + // as it is useful information to the reader; on the other hand, an + // "is empty" matcher probably only needs to explain what the actual + // size is when the match fails, as it's redundant to say that the + // size is 0 when the value is already known to be empty. + // + // You should override this method when defining a new matcher. + // + // It's the responsibility of the caller (Google Test) to guarantee + // that 'listener' is not NULL. This helps to simplify a matcher's + // implementation when it doesn't care about the performance, as it + // can talk to 'listener' without checking its validity first. + // However, in order to implement dummy listeners efficiently, + // listener->stream() may be NULL. + virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; + + // Inherits these methods from MatcherDescriberInterface: + // virtual void DescribeTo(::std::ostream* os) const = 0; + // virtual void DescribeNegationTo(::std::ostream* os) const; +}; + +namespace internal { + +struct AnyEq { + template + bool operator()(const A& a, const B& b) const { return a == b; } +}; +struct AnyNe { + template + bool operator()(const A& a, const B& b) const { return a != b; } +}; +struct AnyLt { + template + bool operator()(const A& a, const B& b) const { return a < b; } +}; +struct AnyGt { + template + bool operator()(const A& a, const B& b) const { return a > b; } +}; +struct AnyLe { + template + bool operator()(const A& a, const B& b) const { return a <= b; } +}; +struct AnyGe { + template + bool operator()(const A& a, const B& b) const { return a >= b; } +}; + +// A match result listener that ignores the explanation. +class DummyMatchResultListener : public MatchResultListener { + public: + DummyMatchResultListener() : MatchResultListener(nullptr) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener); +}; + +// A match result listener that forwards the explanation to a given +// ostream. The difference between this and MatchResultListener is +// that the former is concrete. +class StreamMatchResultListener : public MatchResultListener { + public: + explicit StreamMatchResultListener(::std::ostream* os) + : MatchResultListener(os) {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener); +}; + +struct SharedPayloadBase { + std::atomic ref{1}; + void Ref() { ref.fetch_add(1, std::memory_order_relaxed); } + bool Unref() { return ref.fetch_sub(1, std::memory_order_acq_rel) == 1; } +}; + +template +struct SharedPayload : SharedPayloadBase { + explicit SharedPayload(const T& v) : value(v) {} + explicit SharedPayload(T&& v) : value(std::move(v)) {} + + static void Destroy(SharedPayloadBase* shared) { + delete static_cast(shared); + } + + T value; +}; + +// An internal class for implementing Matcher, which will derive +// from it. We put functionalities common to all Matcher +// specializations here to avoid code duplication. +template +class MatcherBase : private MatcherDescriberInterface { + public: + // Returns true if and only if the matcher matches x; also explains the + // match result to 'listener'. + bool MatchAndExplain(const T& x, MatchResultListener* listener) const { + GTEST_CHECK_(vtable_ != nullptr); + return vtable_->match_and_explain(*this, x, listener); + } + + // Returns true if and only if this matcher matches x. + bool Matches(const T& x) const { + DummyMatchResultListener dummy; + return MatchAndExplain(x, &dummy); + } + + // Describes this matcher to an ostream. + void DescribeTo(::std::ostream* os) const final { + GTEST_CHECK_(vtable_ != nullptr); + vtable_->describe(*this, os, false); + } + + // Describes the negation of this matcher to an ostream. + void DescribeNegationTo(::std::ostream* os) const final { + GTEST_CHECK_(vtable_ != nullptr); + vtable_->describe(*this, os, true); + } + + // Explains why x matches, or doesn't match, the matcher. + void ExplainMatchResultTo(const T& x, ::std::ostream* os) const { + StreamMatchResultListener listener(os); + MatchAndExplain(x, &listener); + } + + // Returns the describer for this matcher object; retains ownership + // of the describer, which is only guaranteed to be alive when + // this matcher object is alive. + const MatcherDescriberInterface* GetDescriber() const { + if (vtable_ == nullptr) return nullptr; + return vtable_->get_describer(*this); + } + + protected: + MatcherBase() : vtable_(nullptr) {} + + // Constructs a matcher from its implementation. + template + explicit MatcherBase(const MatcherInterface* impl) { + Init(impl); + } + + template ::type::is_gtest_matcher> + MatcherBase(M&& m) { // NOLINT + Init(std::forward(m)); + } + + MatcherBase(const MatcherBase& other) + : vtable_(other.vtable_), buffer_(other.buffer_) { + if (IsShared()) buffer_.shared->Ref(); + } + + MatcherBase& operator=(const MatcherBase& other) { + if (this == &other) return *this; + Destroy(); + vtable_ = other.vtable_; + buffer_ = other.buffer_; + if (IsShared()) buffer_.shared->Ref(); + return *this; + } + + MatcherBase(MatcherBase&& other) + : vtable_(other.vtable_), buffer_(other.buffer_) { + other.vtable_ = nullptr; + } + + MatcherBase& operator=(MatcherBase&& other) { + if (this == &other) return *this; + Destroy(); + vtable_ = other.vtable_; + buffer_ = other.buffer_; + other.vtable_ = nullptr; + return *this; + } + + ~MatcherBase() override { Destroy(); } + + private: + struct VTable { + bool (*match_and_explain)(const MatcherBase&, const T&, + MatchResultListener*); + void (*describe)(const MatcherBase&, std::ostream*, bool negation); + // Returns the captured object if it implements the interface, otherwise + // returns the MatcherBase itself. + const MatcherDescriberInterface* (*get_describer)(const MatcherBase&); + // Called on shared instances when the reference count reaches 0. + void (*shared_destroy)(SharedPayloadBase*); + }; + + bool IsShared() const { + return vtable_ != nullptr && vtable_->shared_destroy != nullptr; + } + + // If the implementation uses a listener, call that. + template + static auto MatchAndExplainImpl(const MatcherBase& m, const T& value, + MatchResultListener* listener) + -> decltype(P::Get(m).MatchAndExplain(value, listener->stream())) { + return P::Get(m).MatchAndExplain(value, listener->stream()); + } + + template + static auto MatchAndExplainImpl(const MatcherBase& m, const T& value, + MatchResultListener* listener) + -> decltype(P::Get(m).MatchAndExplain(value, listener)) { + return P::Get(m).MatchAndExplain(value, listener); + } + + template + static void DescribeImpl(const MatcherBase& m, std::ostream* os, + bool negation) { + if (negation) { + P::Get(m).DescribeNegationTo(os); + } else { + P::Get(m).DescribeTo(os); + } + } + + template + static const MatcherDescriberInterface* GetDescriberImpl( + const MatcherBase& m) { + // If the impl is a MatcherDescriberInterface, then return it. + // Otherwise use MatcherBase itself. + // This allows us to implement the GetDescriber() function without support + // from the impl, but some users really want to get their impl back when + // they call GetDescriber(). + // We use std::get on a tuple as a workaround of not having `if constexpr`. + return std::get<( + std::is_convertible::value + ? 1 + : 0)>(std::make_tuple(&m, &P::Get(m))); + } + + template + const VTable* GetVTable() { + static constexpr VTable kVTable = {&MatchAndExplainImpl

, + &DescribeImpl

, &GetDescriberImpl

, + P::shared_destroy}; + return &kVTable; + } + + union Buffer { + // Add some types to give Buffer some common alignment/size use cases. + void* ptr; + double d; + int64_t i; + // And add one for the out-of-line cases. + SharedPayloadBase* shared; + }; + + void Destroy() { + if (IsShared() && buffer_.shared->Unref()) { + vtable_->shared_destroy(buffer_.shared); + } + } + + template + static constexpr bool IsInlined() { + return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) && + std::is_trivially_copy_constructible::value && + std::is_trivially_destructible::value; + } + + template ()> + struct ValuePolicy { + static const M& Get(const MatcherBase& m) { + // When inlined along with Init, need to be explicit to avoid violating + // strict aliasing rules. + const M *ptr = static_cast( + static_cast(&m.buffer_)); + return *ptr; + } + static void Init(MatcherBase& m, M impl) { + ::new (static_cast(&m.buffer_)) M(impl); + } + static constexpr auto shared_destroy = nullptr; + }; + + template + struct ValuePolicy { + using Shared = SharedPayload; + static const M& Get(const MatcherBase& m) { + return static_cast(m.buffer_.shared)->value; + } + template + static void Init(MatcherBase& m, Arg&& arg) { + m.buffer_.shared = new Shared(std::forward(arg)); + } + static constexpr auto shared_destroy = &Shared::Destroy; + }; + + template + struct ValuePolicy*, B> { + using M = const MatcherInterface; + using Shared = SharedPayload>; + static const M& Get(const MatcherBase& m) { + return *static_cast(m.buffer_.shared)->value; + } + static void Init(MatcherBase& m, M* impl) { + m.buffer_.shared = new Shared(std::unique_ptr(impl)); + } + + static constexpr auto shared_destroy = &Shared::Destroy; + }; + + template + void Init(M&& m) { + using MM = typename std::decay::type; + using Policy = ValuePolicy; + vtable_ = GetVTable(); + Policy::Init(*this, std::forward(m)); + } + + const VTable* vtable_; + Buffer buffer_; +}; + +} // namespace internal + +// A Matcher is a copyable and IMMUTABLE (except by assignment) +// object that can check whether a value of type T matches. The +// implementation of Matcher is just a std::shared_ptr to const +// MatcherInterface. Don't inherit from Matcher! +template +class Matcher : public internal::MatcherBase { + public: + // Constructs a null matcher. Needed for storing Matcher objects in STL + // containers. A default-constructed matcher is not yet initialized. You + // cannot use it until a valid value has been assigned to it. + explicit Matcher() {} // NOLINT + + // Constructs a matcher from its implementation. + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template + explicit Matcher( + const MatcherInterface* impl, + typename std::enable_if::value>::type* = + nullptr) + : internal::MatcherBase(impl) {} + + template ::type::is_gtest_matcher> + Matcher(M&& m) : internal::MatcherBase(std::forward(m)) {} // NOLINT + + // Implicit constructor here allows people to write + // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes + Matcher(T value); // NOLINT +}; + +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template ::type::is_gtest_matcher> + Matcher(M&& m) // NOLINT + : internal::MatcherBase(std::forward(m)) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template ::type::is_gtest_matcher> + Matcher(M&& m) // NOLINT + : internal::MatcherBase(std::forward(m)) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT +}; + +#if GTEST_INTERNAL_HAS_STRING_VIEW +// The following two specializations allow the user to write str +// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view +// matcher is expected. +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template ::type::is_gtest_matcher> + Matcher(M&& m) // NOLINT + : internal::MatcherBase(std::forward(m)) { + } + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views or std::string_views directly. + Matcher(internal::StringView s); // NOLINT +}; + +template <> +class GTEST_API_ Matcher + : public internal::MatcherBase { + public: + Matcher() {} + + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + explicit Matcher(const MatcherInterface* impl) + : internal::MatcherBase(impl) {} + + template ::type::is_gtest_matcher> + Matcher(M&& m) // NOLINT + : internal::MatcherBase(std::forward(m)) {} + + // Allows the user to write str instead of Eq(str) sometimes, where + // str is a std::string object. + Matcher(const std::string& s); // NOLINT + + // Allows the user to write "foo" instead of Eq("foo") sometimes. + Matcher(const char* s); // NOLINT + + // Allows the user to pass absl::string_views or std::string_views directly. + Matcher(internal::StringView s); // NOLINT +}; +#endif // GTEST_INTERNAL_HAS_STRING_VIEW + +// Prints a matcher in a human-readable format. +template +std::ostream& operator<<(std::ostream& os, const Matcher& matcher) { + matcher.DescribeTo(&os); + return os; +} + +// The PolymorphicMatcher class template makes it easy to implement a +// polymorphic matcher (i.e. a matcher that can match values of more +// than one type, e.g. Eq(n) and NotNull()). +// +// To define a polymorphic matcher, a user should provide an Impl +// class that has a DescribeTo() method and a DescribeNegationTo() +// method, and define a member function (or member function template) +// +// bool MatchAndExplain(const Value& value, +// MatchResultListener* listener) const; +// +// See the definition of NotNull() for a complete example. +template +class PolymorphicMatcher { + public: + explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {} + + // Returns a mutable reference to the underlying matcher + // implementation object. + Impl& mutable_impl() { return impl_; } + + // Returns an immutable reference to the underlying matcher + // implementation object. + const Impl& impl() const { return impl_; } + + template + operator Matcher() const { + return Matcher(new MonomorphicImpl(impl_)); + } + + private: + template + class MonomorphicImpl : public MatcherInterface { + public: + explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} + + void DescribeTo(::std::ostream* os) const override { impl_.DescribeTo(os); } + + void DescribeNegationTo(::std::ostream* os) const override { + impl_.DescribeNegationTo(os); + } + + bool MatchAndExplain(T x, MatchResultListener* listener) const override { + return impl_.MatchAndExplain(x, listener); + } + + private: + const Impl impl_; + }; + + Impl impl_; +}; + +// Creates a matcher from its implementation. +// DEPRECATED: Especially in the generic code, prefer: +// Matcher(new MyMatcherImpl(...)); +// +// MakeMatcher may create a Matcher that accepts its argument by value, which +// leads to unnecessary copies & lack of support for non-copyable types. +template +inline Matcher MakeMatcher(const MatcherInterface* impl) { + return Matcher(impl); +} + +// Creates a polymorphic matcher from its implementation. This is +// easier to use than the PolymorphicMatcher constructor as it +// doesn't require you to explicitly write the template argument, e.g. +// +// MakePolymorphicMatcher(foo); +// vs +// PolymorphicMatcher(foo); +template +inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { + return PolymorphicMatcher(impl); +} + +namespace internal { +// Implements a matcher that compares a given value with a +// pre-supplied value using one of the ==, <=, <, etc, operators. The +// two values being compared don't have to have the same type. +// +// The matcher defined here is polymorphic (for example, Eq(5) can be +// used to match an int, a short, a double, etc). Therefore we use +// a template type conversion operator in the implementation. +// +// The following template definition assumes that the Rhs parameter is +// a "bare" type (i.e. neither 'const T' nor 'T&'). +template +class ComparisonBase { + public: + explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {} + + using is_gtest_matcher = void; + + template + bool MatchAndExplain(const Lhs& lhs, std::ostream*) const { + return Op()(lhs, Unwrap(rhs_)); + } + void DescribeTo(std::ostream* os) const { + *os << D::Desc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + void DescribeNegationTo(std::ostream* os) const { + *os << D::NegatedDesc() << " "; + UniversalPrint(Unwrap(rhs_), os); + } + + private: + template + static const T& Unwrap(const T& v) { + return v; + } + template + static const T& Unwrap(std::reference_wrapper v) { + return v; + } + + Rhs rhs_; +}; + +template +class EqMatcher : public ComparisonBase, Rhs, AnyEq> { + public: + explicit EqMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyEq>(rhs) { } + static const char* Desc() { return "is equal to"; } + static const char* NegatedDesc() { return "isn't equal to"; } +}; +template +class NeMatcher : public ComparisonBase, Rhs, AnyNe> { + public: + explicit NeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyNe>(rhs) { } + static const char* Desc() { return "isn't equal to"; } + static const char* NegatedDesc() { return "is equal to"; } +}; +template +class LtMatcher : public ComparisonBase, Rhs, AnyLt> { + public: + explicit LtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLt>(rhs) { } + static const char* Desc() { return "is <"; } + static const char* NegatedDesc() { return "isn't <"; } +}; +template +class GtMatcher : public ComparisonBase, Rhs, AnyGt> { + public: + explicit GtMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGt>(rhs) { } + static const char* Desc() { return "is >"; } + static const char* NegatedDesc() { return "isn't >"; } +}; +template +class LeMatcher : public ComparisonBase, Rhs, AnyLe> { + public: + explicit LeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyLe>(rhs) { } + static const char* Desc() { return "is <="; } + static const char* NegatedDesc() { return "isn't <="; } +}; +template +class GeMatcher : public ComparisonBase, Rhs, AnyGe> { + public: + explicit GeMatcher(const Rhs& rhs) + : ComparisonBase, Rhs, AnyGe>(rhs) { } + static const char* Desc() { return "is >="; } + static const char* NegatedDesc() { return "isn't >="; } +}; + +template ::value>::type> +using StringLike = T; + +// Implements polymorphic matchers MatchesRegex(regex) and +// ContainsRegex(regex), which can be used as a Matcher as long as +// T can be converted to a string. +class MatchesRegexMatcher { + public: + MatchesRegexMatcher(const RE* regex, bool full_match) + : regex_(regex), full_match_(full_match) {} + +#if GTEST_INTERNAL_HAS_STRING_VIEW + bool MatchAndExplain(const internal::StringView& s, + MatchResultListener* listener) const { + return MatchAndExplain(std::string(s), listener); + } +#endif // GTEST_INTERNAL_HAS_STRING_VIEW + + // Accepts pointer types, particularly: + // const char* + // char* + // const wchar_t* + // wchar_t* + template + bool MatchAndExplain(CharType* s, MatchResultListener* listener) const { + return s != nullptr && MatchAndExplain(std::string(s), listener); + } + + // Matches anything that can convert to std::string. + // + // This is a template, not just a plain function with const std::string&, + // because absl::string_view has some interfering non-explicit constructors. + template + bool MatchAndExplain(const MatcheeStringType& s, + MatchResultListener* /* listener */) const { + const std::string& s2(s); + return full_match_ ? RE::FullMatch(s2, *regex_) + : RE::PartialMatch(s2, *regex_); + } + + void DescribeTo(::std::ostream* os) const { + *os << (full_match_ ? "matches" : "contains") << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + void DescribeNegationTo(::std::ostream* os) const { + *os << "doesn't " << (full_match_ ? "match" : "contain") + << " regular expression "; + UniversalPrinter::Print(regex_->pattern(), os); + } + + private: + const std::shared_ptr regex_; + const bool full_match_; +}; +} // namespace internal + +// Matches a string that fully matches regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher MatchesRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true)); +} +template +PolymorphicMatcher MatchesRegex( + const internal::StringLike& regex) { + return MatchesRegex(new internal::RE(std::string(regex))); +} + +// Matches a string that contains regular expression 'regex'. +// The matcher takes ownership of 'regex'. +inline PolymorphicMatcher ContainsRegex( + const internal::RE* regex) { + return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false)); +} +template +PolymorphicMatcher ContainsRegex( + const internal::StringLike& regex) { + return ContainsRegex(new internal::RE(std::string(regex))); +} + +// Creates a polymorphic matcher that matches anything equal to x. +// Note: if the parameter of Eq() were declared as const T&, Eq("foo") +// wouldn't compile. +template +inline internal::EqMatcher Eq(T x) { return internal::EqMatcher(x); } + +// Constructs a Matcher from a 'value' of type T. The constructed +// matcher matches any value that's equal to 'value'. +template +Matcher::Matcher(T value) { *this = Eq(value); } + +// Creates a monomorphic matcher that matches anything with type Lhs +// and equal to rhs. A user may need to use this instead of Eq(...) +// in order to resolve an overloading ambiguity. +// +// TypedEq(x) is just a convenient short-hand for Matcher(Eq(x)) +// or Matcher(x), but more readable than the latter. +// +// We could define similar monomorphic matchers for other comparison +// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do +// it yet as those are used much less than Eq() in practice. A user +// can always write Matcher(Lt(5)) to be explicit about the type, +// for example. +template +inline Matcher TypedEq(const Rhs& rhs) { return Eq(rhs); } + +// Creates a polymorphic matcher that matches anything >= x. +template +inline internal::GeMatcher Ge(Rhs x) { + return internal::GeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything > x. +template +inline internal::GtMatcher Gt(Rhs x) { + return internal::GtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything <= x. +template +inline internal::LeMatcher Le(Rhs x) { + return internal::LeMatcher(x); +} + +// Creates a polymorphic matcher that matches anything < x. +template +inline internal::LtMatcher Lt(Rhs x) { + return internal::LtMatcher(x); +} + +// Creates a polymorphic matcher that matches anything != x. +template +inline internal::NeMatcher Ne(Rhs x) { + return internal::NeMatcher(x); +} +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046 + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_ diff --git a/gtestsuite/inc/gtest/gtest-message.h b/gtestsuite/inc/gtest/gtest-message.h new file mode 100644 index 000000000..becfd49fc --- /dev/null +++ b/gtestsuite/inc/gtest/gtest-message.h @@ -0,0 +1,219 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include +#include +#include + +#include "gtest/internal/gtest-port.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +// Ensures that there is at least one operator<< in the global namespace. +// See Message& operator<<(...) below for why. +void operator<<(const testing::internal::Secret&, int); + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a stringstream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that stringstream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + Message(); + + // Copy constructor. + Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new ::std::stringstream) { + *ss_ << str; + } + + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + // Some libraries overload << for STL containers. These + // overloads are defined in the global namespace instead of ::std. + // + // C++'s symbol lookup rule (i.e. Koenig lookup) says that these + // overloads are visible in either the std namespace or the global + // namespace, but not other namespaces, including the testing + // namespace which Google Test's Message class is in. + // + // To allow STL containers (and other types that has a << operator + // defined in the global namespace) to be used in Google Test + // assertions, testing::Message must access the custom << operator + // from the global namespace. With this using declaration, + // overloads of << defined in the global namespace and those + // visible via Koenig lookup are both exposed in this function. + using ::operator <<; + *ss_ << val; + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == nullptr) { + *ss_ << "(null)"; + } else { + *ss_ << pointer; + } + return *this; + } + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str); + Message& operator <<(wchar_t* wide_c_str); + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + + // Gets the text streamed to this object so far as an std::string. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + std::string GetString() const; + + private: + // We'll hold the text streamed to this object here. + const std::unique_ptr< ::std::stringstream> ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +namespace internal { + +// Converts a streamable value to an std::string. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +template +std::string StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ diff --git a/gtestsuite/inc/gtest/gtest-param-test.h b/gtestsuite/inc/gtest/gtest-param-test.h new file mode 100644 index 000000000..804e70281 --- /dev/null +++ b/gtestsuite/inc/gtest/gtest-param-test.h @@ -0,0 +1,507 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing and Mocking Framework (Google Test) +// +// GOOGLETEST_CM0001 DO NOT DELETE +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test suite +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_SUITE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more than once) the first argument to the +// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the +// actual test suite name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests +// in the given test suite, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_SUITE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-param-util.h" +#include "gtest/internal/gtest-port.h" + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test suite is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test suite FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test suite StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings)); +// +// This instantiates tests from test suite StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_SUITE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_SUITE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename std::iterator_traits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename std::iterator_traits::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test suite BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_SUITE_P(NumSequence, +// BarTest, +// Values("one", "two", "three")); +// +// This instantiates tests from test suite BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// +template +internal::ValueArray Values(T... v) { + return internal::ValueArray(std::move(v)...); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test suite FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_SUITE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// std::tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Example: +// +// This will instantiate tests in test suite AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// std::tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder Combine(const Generator&... g) { + return internal::CartesianProductHolder(g...); +} + +#define TEST_P(test_suite_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public test_suite_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \ + void TestBody() override; \ + \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + GTEST_STRINGIFY_(test_suite_name), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestPattern( \ + GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory(), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)); \ + return 0; \ + } \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() + +// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify +// generator and an optional function or functor that generates custom test name +// suffixes based on the test parameters. Such a function or functor should +// accept one argument of type testing::TestParamInfo, and +// return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +#define GTEST_EXPAND_(arg) arg +#define GTEST_GET_FIRST_(first, ...) first +#define GTEST_GET_SECOND_(first, second, ...) second + +#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ + static ::testing::internal::ParamGenerator \ + gtest_##prefix##test_suite_name##_EvalGenerator_() { \ + return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ + } \ + static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo& info) { \ + if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))); \ + auto t = std::make_tuple(__VA_ARGS__); \ + static_assert(std::tuple_size::value <= 2, \ + "Too Many Args!"); \ + } \ + return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName, \ + DUMMY_PARAM_))))(info); \ + } \ + static int gtest_##prefix##test_suite_name##_dummy_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder( \ + GTEST_STRINGIFY_(test_suite_name), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestSuiteInstantiation( \ + GTEST_STRINGIFY_(prefix), \ + >est_##prefix##test_suite_name##_EvalGenerator_, \ + >est_##prefix##test_suite_name##_EvalGenerateName_, \ + __FILE__, __LINE__) + + +// Allow Marking a Parameterized test class as not needing to be instantiated. +#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T) \ + namespace gtest_do_not_use_outside_namespace_scope {} \ + static const ::testing::internal::MarkAsIgnored gtest_allow_ignore_##T( \ + GTEST_STRINGIFY_(T)) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TEST_CASE_P \ + static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \ + ""); \ + INSTANTIATE_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/gtestsuite/inc/gtest/gtest-printers.h b/gtestsuite/inc/gtest/gtest-printers.h new file mode 100644 index 000000000..076c9de1f --- /dev/null +++ b/gtestsuite/inc/gtest/gtest-printers.h @@ -0,0 +1,1029 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Google Test - The Google C++ Testing and Mocking Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// However if T is an STL-style container then it is printed element-wise +// unless foo::PrintTo(const T&, ostream*) is defined. Note that +// operator<<() is ignored for container types. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are +// printed. +// +// We also provide some convenient wrappers: +// +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const or not) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. Tuple support must be enabled in +// // gtest-port.h. +// std::vector UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#include +#include +#include // NOLINT +#include +#include +#include +#include +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" + +namespace testing { + +// Definitions in the internal* namespaces are subject to change without notice. +// DO NOT USE THEM IN USER CODE! +namespace internal { + +template +void UniversalPrint(const T& value, ::std::ostream* os); + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +struct ContainerPrinter { + template (0)) == sizeof(IsContainer)) && + !IsRecursiveContainer::value>::type> + static void PrintValue(const T& container, std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (auto&& elem : container) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(elem, os) here as PrintTo() doesn't + // handle `elem` being a native array. + internal::UniversalPrint(elem, os); + ++count; + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; + } +}; + +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +struct FunctionPointerPrinter { + template ::value>::type> + static void PrintValue(T* p, ::std::ostream* os) { + if (p == nullptr) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. + *os << reinterpret_cast(p); + } + } +}; + +struct PointerPrinter { + template + static void PrintValue(T* p, ::std::ostream* os) { + if (p == nullptr) { + *os << "NULL"; + } else { + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } + } +}; + +namespace internal_stream_operator_without_lexical_name_lookup { + +// The presence of an operator<< here will terminate lexical scope lookup +// straight away (even though it cannot be a match because of its argument +// types). Thus, the two operator<< calls in StreamPrinter will find only ADL +// candidates. +struct LookupBlocker {}; +void operator<<(LookupBlocker, LookupBlocker); + +struct StreamPrinter { + template ::value>::type, + // Only accept types for which we can find a streaming operator via + // ADL (possibly involving implicit conversions). + typename = decltype(std::declval() + << std::declval())> + static void PrintValue(const T& value, ::std::ostream* os) { + // Call streaming operator found by ADL, possibly with implicit conversions + // of the arguments. + *os << value; + } +}; + +} // namespace internal_stream_operator_without_lexical_name_lookup + +struct ProtobufPrinter { + // We print a protobuf using its ShortDebugString() when the string + // doesn't exceed this many characters; otherwise we print it using + // DebugString() for better readability. + static const size_t kProtobufOneLinerMaxLength = 50; + + template ::value>::type> + static void PrintValue(const T& value, ::std::ostream* os) { + std::string pretty_str = value.ShortDebugString(); + if (pretty_str.length() > kProtobufOneLinerMaxLength) { + pretty_str = "\n" + value.DebugString(); + } + *os << ("<" + pretty_str + ">"); + } +}; + +struct ConvertibleToIntegerPrinter { + // Since T has no << operator or PrintTo() but can be implicitly + // converted to BiggestInt, we print it as a BiggestInt. + // + // Most likely T is an enum type (either named or unnamed), in which + // case printing it as an integer is the desired behavior. In case + // T is not an enum, printing it as an integer is the best we can do + // given that it has no user-defined printer. + static void PrintValue(internal::BiggestInt value, ::std::ostream* os) { + *os << value; + } +}; + +struct ConvertibleToStringViewPrinter { +#if GTEST_INTERNAL_HAS_STRING_VIEW + static void PrintValue(internal::StringView value, ::std::ostream* os) { + internal::UniversalPrint(value, os); + } +#endif +}; + + +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); +struct RawBytesPrinter { + // SFINAE on `sizeof` to make sure we have a complete type. + template + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo( + static_cast( + // Load bearing cast to void* to support iOS + reinterpret_cast(std::addressof(value))), + sizeof(value), os); + } +}; + +struct FallbackPrinter { + template + static void PrintValue(const T&, ::std::ostream* os) { + *os << "(incomplete type)"; + } +}; + +// Try every printer in order and return the first one that works. +template +struct FindFirstPrinter : FindFirstPrinter {}; + +template +struct FindFirstPrinter< + T, decltype(Printer::PrintValue(std::declval(), nullptr)), + Printer, Printers...> { + using type = Printer; +}; + +// Select the best printer in the following order: +// - Print containers (they have begin/end/etc). +// - Print function pointers. +// - Print object pointers. +// - Use the stream operator, if available. +// - Print protocol buffers. +// - Print types convertible to BiggestInt. +// - Print types convertible to StringView, if available. +// - Fallback to printing the raw bytes of the object. +template +void PrintWithFallback(const T& value, ::std::ostream* os) { + using Printer = typename FindFirstPrinter< + T, void, ContainerPrinter, FunctionPointerPrinter, PointerPrinter, + internal_stream_operator_without_lexical_name_lookup::StreamPrinter, + ProtobufPrinter, ConvertibleToIntegerPrinter, + ConvertibleToStringViewPrinter, RawBytesPrinter, FallbackPrinter>::type; + Printer::PrintValue(value, os); +} + +// FormatForComparison::Format(value) formats a +// value of type ToPrint that is an operand of a comparison assertion +// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in +// the comparison, and is used to help determine the best way to +// format the value. In particular, when the value is a C string +// (char pointer) and the other operand is an STL string object, we +// want to format the C string as a string, since we know it is +// compared by value with the string object. If the value is a char +// pointer but the other operand is not an STL string object, we don't +// know whether the pointer is supposed to point to a NUL-terminated +// string, and thus want to print it as a pointer to be safe. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// The default case. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint& value) { + return ::testing::PrintToString(value); + } +}; + +// Array. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint* value) { + return FormatForComparison::Format(value); + } +}; + +// By default, print C string as pointers to be safe, as we don't know +// whether they actually point to a NUL-terminated string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ + template \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(static_cast(value)); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); +#ifdef __cpp_char8_t +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char8_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char8_t); +#endif +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char16_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char16_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char32_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char32_t); + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ + +// If a C string is compared with an STL string object, we know it's meant +// to point to a NUL-terminated string, and thus can print it as a string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ + template <> \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(value); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); +#ifdef __cpp_char8_t +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char8_t, ::std::u8string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char8_t, ::std::u8string); +#endif +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char16_t, ::std::u16string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char16_t, ::std::u16string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char32_t, ::std::u32string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char32_t, ::std::u32string); + +#if GTEST_HAS_STD_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); +#endif + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char* or void*, and print it as a C string when it is compared +// against an std::string object, for example. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +std::string FormatForComparisonFailureMessage( + const T1& value, const T2& /* other_operand */) { + return FormatForComparison::Format(value); +} + +// UniversalPrinter::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template +class UniversalPrinter; + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template +void PrintTo(const T& value, ::std::ostream* os) { + internal::PrintWithFallback(value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); +GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); + +GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os); +inline void PrintTo(char16_t c, ::std::ostream* os) { + PrintTo(ImplicitCast_(c), os); +} +#ifdef __cpp_char8_t +inline void PrintTo(char8_t c, ::std::ostream* os) { + PrintTo(ImplicitCast_(c), os); +} +#endif + +// Overloads for C strings. +GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// signed/unsigned char is often used for representing binary data, so +// we print pointers to it as void* to be safe. +inline void PrintTo(const signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(const unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#ifdef __cpp_char8_t +// Overloads for u8 strings. +GTEST_API_ void PrintTo(const char8_t* s, ::std::ostream* os); +inline void PrintTo(char8_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif +// Overloads for u16 strings. +GTEST_API_ void PrintTo(const char16_t* s, ::std::ostream* os); +inline void PrintTo(char16_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +// Overloads for u32 strings. +GTEST_API_ void PrintTo(const char32_t* s, ::std::ostream* os); +inline void PrintTo(char32_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrint(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrint(a[i], os); + } +} + +// Overloads for ::std::string. +GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} + +// Overloads for ::std::u8string +#ifdef __cpp_char8_t +GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os); +inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) { + PrintU8StringTo(s, os); +} +#endif + +// Overloads for ::std::u16string +GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os); +inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) { + PrintU16StringTo(s, os); +} + +// Overloads for ::std::u32string +GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os); +inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) { + PrintU32StringTo(s, os); +} + +// Overloads for ::std::wstring. +#if GTEST_HAS_STD_WSTRING +GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_INTERNAL_HAS_STRING_VIEW +// Overload for internal::StringView. +inline void PrintTo(internal::StringView sp, ::std::ostream* os) { + PrintTo(::std::string(sp), os); +} +#endif // GTEST_INTERNAL_HAS_STRING_VIEW + +inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } + +template +void PrintTo(std::reference_wrapper ref, ::std::ostream* os) { + UniversalPrinter::Print(ref.get(), os); +} + +inline const void* VoidifyPointer(const void* p) { return p; } +inline const void* VoidifyPointer(volatile const void* p) { + return const_cast(p); +} + +template +void PrintSmartPointer(const Ptr& ptr, std::ostream* os, char) { + if (ptr == nullptr) { + *os << "(nullptr)"; + } else { + // We can't print the value. Just print the pointer.. + *os << "(" << (VoidifyPointer)(ptr.get()) << ")"; + } +} +template ::value && + !std::is_array::value>::type> +void PrintSmartPointer(const Ptr& ptr, std::ostream* os, int) { + if (ptr == nullptr) { + *os << "(nullptr)"; + } else { + *os << "(ptr = " << (VoidifyPointer)(ptr.get()) << ", value = "; + UniversalPrinter::Print(*ptr, os); + *os << ")"; + } +} + +template +void PrintTo(const std::unique_ptr& ptr, std::ostream* os) { + (PrintSmartPointer)(ptr, os, 0); +} + +template +void PrintTo(const std::shared_ptr& ptr, std::ostream* os) { + (PrintSmartPointer)(ptr, os, 0); +} + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T&, std::integral_constant, + ::std::ostream*) {} + +template +void PrintTupleTo(const T& t, std::integral_constant, + ::std::ostream* os) { + PrintTupleTo(t, std::integral_constant(), os); + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (I > 1) { + GTEST_INTENTIONAL_CONST_COND_POP_() + *os << ", "; + } + UniversalPrinter::type>::Print( + std::get(t), os); +} + +template +void PrintTo(const ::std::tuple& t, ::std::ostream* os) { + *os << "("; + PrintTupleTo(t, std::integral_constant(), os); + *os << ")"; +} + +// Overload for std::pair. +template +void PrintTo(const ::std::pair& value, ::std::ostream* os) { + *os << '('; + // We cannot use UniversalPrint(value.first, os) here, as T1 may be + // a reference type. The same for printing value.second. + UniversalPrinter::Print(value.first, os); + *os << ", "; + UniversalPrinter::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + + GTEST_DISABLE_MSC_WARNINGS_POP_() +}; + +// Remove any const-qualifiers before passing a type to UniversalPrinter. +template +class UniversalPrinter : public UniversalPrinter {}; + +#if GTEST_INTERNAL_HAS_ANY + +// Printer for std::any / absl::any + +template <> +class UniversalPrinter { + public: + static void Print(const Any& value, ::std::ostream* os) { + if (value.has_value()) { + *os << "value of type " << GetTypeName(value); + } else { + *os << "no value"; + } + } + + private: + static std::string GetTypeName(const Any& value) { +#if GTEST_HAS_RTTI + return internal::GetTypeName(value.type()); +#else + static_cast(value); // possibly unused + return ""; +#endif // GTEST_HAS_RTTI + } +}; + +#endif // GTEST_INTERNAL_HAS_ANY + +#if GTEST_INTERNAL_HAS_OPTIONAL + +// Printer for std::optional / absl::optional + +template +class UniversalPrinter> { + public: + static void Print(const Optional& value, ::std::ostream* os) { + *os << '('; + if (!value) { + *os << "nullopt"; + } else { + UniversalPrint(*value, os); + } + *os << ')'; + } +}; + +#endif // GTEST_INTERNAL_HAS_OPTIONAL + +#if GTEST_INTERNAL_HAS_VARIANT + +// Printer for std::variant / absl::variant + +template +class UniversalPrinter> { + public: + static void Print(const Variant& value, ::std::ostream* os) { + *os << '('; +#if GTEST_HAS_ABSL + absl::visit(Visitor{os, value.index()}, value); +#else + std::visit(Visitor{os, value.index()}, value); +#endif // GTEST_HAS_ABSL + *os << ')'; + } + + private: + struct Visitor { + template + void operator()(const U& u) const { + *os << "'" << GetTypeName() << "(index = " << index + << ")' with value "; + UniversalPrint(u, os); + } + ::std::ostream* os; + std::size_t index; + }; +}; + +#endif // GTEST_INTERNAL_HAS_VARIANT + +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +GTEST_API_ void UniversalPrintArray( + const char* begin, size_t len, ::std::ostream* os); + +#ifdef __cpp_char8_t +// This overload prints a (const) char8_t array compactly. +GTEST_API_ void UniversalPrintArray(const char8_t* begin, size_t len, + ::std::ostream* os); +#endif + +// This overload prints a (const) char16_t array compactly. +GTEST_API_ void UniversalPrintArray(const char16_t* begin, size_t len, + ::std::ostream* os); + +// This overload prints a (const) char32_t array compactly. +GTEST_API_ void UniversalPrintArray(const char32_t* begin, size_t len, + ::std::ostream* os); + +// This overload prints a (const) wchar_t array compactly. +GTEST_API_ void UniversalPrintArray( + const wchar_t* begin, size_t len, ::std::ostream* os); + +// Implements printing an array type T[N]. +template +class UniversalPrinter { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + UniversalPrintArray(a, N, os); + } +}; + +// Implements printing a reference type T&. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast(&value) << " "; + + // Then prints the value itself. + UniversalPrint(value, os); + } + + GTEST_DISABLE_MSC_WARNINGS_POP_() +}; + +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. + +template +class UniversalTersePrinter { + public: + static void Print(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); + } +}; +template +class UniversalTersePrinter { + public: + static void Print(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); + } +}; +template +class UniversalTersePrinter { + public: + static void Print(const T (&value)[N], ::std::ostream* os) { + UniversalPrinter::Print(value, os); + } +}; +template <> +class UniversalTersePrinter { + public: + static void Print(const char* str, ::std::ostream* os) { + if (str == nullptr) { + *os << "NULL"; + } else { + UniversalPrint(std::string(str), os); + } + } +}; +template <> +class UniversalTersePrinter : public UniversalTersePrinter { +}; + +#ifdef __cpp_char8_t +template <> +class UniversalTersePrinter { + public: + static void Print(const char8_t* str, ::std::ostream* os) { + if (str == nullptr) { + *os << "NULL"; + } else { + UniversalPrint(::std::u8string(str), os); + } + } +}; +template <> +class UniversalTersePrinter + : public UniversalTersePrinter {}; +#endif + +template <> +class UniversalTersePrinter { + public: + static void Print(const char16_t* str, ::std::ostream* os) { + if (str == nullptr) { + *os << "NULL"; + } else { + UniversalPrint(::std::u16string(str), os); + } + } +}; +template <> +class UniversalTersePrinter + : public UniversalTersePrinter {}; + +template <> +class UniversalTersePrinter { + public: + static void Print(const char32_t* str, ::std::ostream* os) { + if (str == nullptr) { + *os << "NULL"; + } else { + UniversalPrint(::std::u32string(str), os); + } + } +}; +template <> +class UniversalTersePrinter + : public UniversalTersePrinter {}; + +#if GTEST_HAS_STD_WSTRING +template <> +class UniversalTersePrinter { + public: + static void Print(const wchar_t* str, ::std::ostream* os) { + if (str == nullptr) { + *os << "NULL"; + } else { + UniversalPrint(::std::wstring(str), os); + } + } +}; +#endif + +template <> +class UniversalTersePrinter { + public: + static void Print(wchar_t* str, ::std::ostream* os) { + UniversalTersePrinter::Print(str, os); + } +}; + +template +void UniversalTersePrint(const T& value, ::std::ostream* os) { + UniversalTersePrinter::Print(value, os); +} + +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + // A workarond for the bug in VC++ 7.1 that prevents us from instantiating + // UniversalPrinter with T directly. + typedef T T1; + UniversalPrinter::Print(value, os); +} + +typedef ::std::vector< ::std::string> Strings; + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. +template +void TersePrintPrefixToStrings(const Tuple&, std::integral_constant, + Strings*) {} +template +void TersePrintPrefixToStrings(const Tuple& t, + std::integral_constant, + Strings* strings) { + TersePrintPrefixToStrings(t, std::integral_constant(), + strings); + ::std::stringstream ss; + UniversalTersePrint(std::get(t), &ss); + strings->push_back(ss.str()); +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TersePrintPrefixToStrings( + value, std::integral_constant::value>(), + &result); + return result; +} + +} // namespace internal + +template +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrinter::Print(value, &ss); + return ss.str(); +} + +} // namespace testing + +// Include any custom printer added by the local installation. +// We must include this header at the end to make sure it can use the +// declarations from this file. +#include "gtest/internal/custom/gtest-printers.h" + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ diff --git a/gtestsuite/inc/gtest/gtest-spi.h b/gtestsuite/inc/gtest/gtest-spi.h new file mode 100644 index 000000000..eacef4466 --- /dev/null +++ b/gtestsuite/inc/gtest/gtest-spi.h @@ -0,0 +1,238 @@ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +// GOOGLETEST_CM0004 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include "gtest/gtest.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + ~ScopedFakeTestPartResultReporter() override; + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + void ReportTestPartResult(const TestPartResult& result) override; + + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, const std::string& substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const std::string substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_ diff --git a/gtestsuite/inc/gtest/gtest-test-part.h b/gtestsuite/inc/gtest/gtest-test-part.h new file mode 100644 index 000000000..203fdf98c --- /dev/null +++ b/gtestsuite/inc/gtest/gtest-test-part.h @@ -0,0 +1,184 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure, // Failed and the test should be terminated. + kSkip // Skipped. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, const char* a_file_name, int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name == nullptr ? "" : a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) {} + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { + return file_name_.empty() ? nullptr : file_name_.c_str(); + } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true if and only if the test part was skipped. + bool skipped() const { return type_ == kSkip; } + + // Returns true if and only if the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true if and only if the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true if and only if the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + + // Returns true if and only if the test part failed. + bool failed() const { return fatally_failed() || nonfatally_failed(); } + + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static std::string ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // "" if the source file is unknown. + std::string file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + std::string summary_; // The test failure summary. + std::string message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class GTEST_API_ TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + ~HasNewFatalFailureHelper() override; + void ReportTestPartResult(const TestPartResult& result) override; + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ diff --git a/gtestsuite/inc/gtest/gtest-typed-test.h b/gtestsuite/inc/gtest/gtest-typed-test.h new file mode 100644 index 000000000..9fdc6be10 --- /dev/null +++ b/gtestsuite/inc/gtest/gtest-typed-test.h @@ -0,0 +1,329 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test suite, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_SUITE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_SUITE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test suite as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to the special name TypeParam to get the type + // parameter. Since we are inside a derived class template, C++ requires + // us to visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +// TYPED_TEST_SUITE takes an optional third argument which allows to specify a +// class that generates custom test name suffixes based on the type. This should +// be a class which has a static template function GetName(int index) returning +// a string for each type. The provided integer index equals the index of the +// type in the provided type list. In many cases the index can be ignored. +// +// For example: +// class MyTypeNames { +// public: +// template +// static std::string GetName(int) { +// if (std::is_same()) return "char"; +// if (std::is_same()) return "int"; +// if (std::is_same()) return "unsignedInt"; +// } +// }; +// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames); + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test suite +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_SUITE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test suite as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test suite name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_SUITE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test suite name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); +// +// Similar to the optional argument of TYPED_TEST_SUITE above, +// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to +// generate custom names. +// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames); + +#endif // 0 + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/internal/gtest-type-util.h" + +// Implements typed tests. + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test suite. +#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_ + +// Expands to the name of the typedef for the NameGenerator, responsible for +// creating the suffixes of the name. +#define GTEST_NAME_GENERATOR_(TestSuiteName) \ + gtest_type_params_##TestSuiteName##_NameGenerator + +#define TYPED_TEST_SUITE(CaseName, Types, ...) \ + typedef ::testing::internal::GenerateTypeList::type \ + GTEST_TYPE_PARAMS_(CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ + GTEST_NAME_GENERATOR_(CaseName) + +#define TYPED_TEST(CaseName, TestName) \ + static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \ + "test-name must not be empty"); \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + void TestBody() override; \ + }; \ + static bool gtest_##CaseName##_##TestName##_registered_ \ + GTEST_ATTRIBUTE_UNUSED_ = ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel, \ + GTEST_TYPE_PARAMS_( \ + CaseName)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + GTEST_STRINGIFY_(CaseName), \ + GTEST_STRINGIFY_(TestName), 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(CaseName), \ + GTEST_TYPE_PARAMS_(CaseName)>()); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)::TestBody() + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE \ + static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \ + TYPED_TEST_SUITE +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +// Implements type-parameterized tests. + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test suite are defined in. The exact +// name of the namespace is subject to change without notice. +#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test suite. +#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \ + gtest_typed_test_suite_p_state_##TestSuiteName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test suite. +#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \ + gtest_registered_test_names_##TestSuiteName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +#define TYPED_TEST_SUITE_P(SuiteName) \ + static ::testing::internal::TypedTestSuitePState \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define TYPED_TEST_CASE_P \ + static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \ + TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define TYPED_TEST_P(SuiteName, TestName) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + template \ + class TestName : public SuiteName { \ + private: \ + typedef SuiteName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + void TestBody() override; \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ + __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \ + GTEST_STRINGIFY_(TestName)); \ + } \ + template \ + void GTEST_SUITE_NAMESPACE_( \ + SuiteName)::TestName::TestBody() + +// Note: this won't work correctly if the trailing arguments are macros. +#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_( \ + SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ + GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define REGISTER_TYPED_TEST_CASE_P \ + static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \ + ""); \ + REGISTER_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ + static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \ + "test-suit-prefix must not be empty"); \ + static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestSuite< \ + SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ + ::testing::internal::GenerateTypeList::type>:: \ + Register(GTEST_STRINGIFY_(Prefix), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \ + GTEST_STRINGIFY_(SuiteName), \ + GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::GenerateTypeList::type>()) + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +#define INSTANTIATE_TYPED_TEST_CASE_P \ + static_assert( \ + ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \ + INSTANTIATE_TYPED_TEST_SUITE_P +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ diff --git a/gtestsuite/inc/gtest/gtest.h b/gtestsuite/inc/gtest/gtest.h new file mode 100644 index 000000000..7a5d057c4 --- /dev/null +++ b/gtestsuite/inc/gtest/gtest.h @@ -0,0 +1,2495 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include +#include +#include +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-string.h" +#include "gtest/gtest-death-test.h" +#include "gtest/gtest-matchers.h" +#include "gtest/gtest-message.h" +#include "gtest/gtest-param-test.h" +#include "gtest/gtest-printers.h" +#include "gtest/gtest_prod.h" +#include "gtest/gtest-test-part.h" +#include "gtest/gtest-typed-test.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { + +// Silence C4100 (unreferenced formal parameter) and 4805 +// unsafe mix of type 'const int' and type 'const bool' +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4805) +# pragma warning(disable:4100) +#endif + + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag controls whether the test runner should continue execution past +// first failure. +GTEST_DECLARE_bool_(fail_fast); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag controls whether Google Test installs a signal handler that dumps +// debugging information when fatal signals are raised. +GTEST_DECLARE_bool_(install_failure_signal_handler); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints only test failures. +GTEST_DECLARE_bool_(brief); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flags control whether Google Test prints UTF8 characters as text. +GTEST_DECLARE_bool_(print_utf8); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. For use with an external test framework. +GTEST_DECLARE_bool_(throw_on_failure); + +// When this flag is set with a "host:port" string, on supported +// platforms test results are streamed to the specified port on +// the specified host machine. +GTEST_DECLARE_string_(stream_result_to); + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DECLARE_string_(flagfile); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class StreamingListenerTest; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class UnitTestRecordPropertyTestHelper; +class WindowsDeathTest; +class FuchsiaDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const std::string& message); +std::set* GetIgnoredParameterizedTestSuites(); + +} // namespace internal + +// The friend relationship of some of these classes is cyclic. +// If we don't forward declare them the compiler might confuse the classes +// in friendship clauses with same named classes on the scope. +class Test; +class TestSuite; + +// Old API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TestCase = TestSuite; +#endif +class TestInfo; +class UnitTest; + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + +// C4800 is a level 3 warning in Visual Studio 2015 and earlier. +// This warning is not emitted in Visual Studio 2017. +// This warning is off by default starting in Visual Studio 2019 but can be +// enabled with command-line options. +#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) +#endif + + // Used in the EXPECT_TRUE/FALSE(bool_expression). + // + // T must be contextually convertible to bool. + // + // The second parameter prevents this overload from being considered if + // the argument is implicitly convertible to AssertionResult. In that case + // we want AssertionResult's copy constructor to be used. + template + explicit AssertionResult( + const T& success, + typename std::enable_if< + !std::is_convertible::value>::type* + /*enabler*/ + = nullptr) + : success_(success) {} + +#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920) + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + + // Assignment operator. + AssertionResult& operator=(AssertionResult other) { + swap(other); + return *this; + } + + // Returns true if and only if the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != nullptr ? message_->c_str() : ""; + } + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value) { + AppendMessage(Message() << value); + return *this; + } + + // Allows streaming basic output manipulators such as endl or flush into + // this object. + AssertionResult& operator<<( + ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { + AppendMessage(Message() << basic_manipulator); + return *this; + } + + private: + // Appends the contents of message to message_. + void AppendMessage(const Message& a_message) { + if (message_.get() == nullptr) message_.reset(new ::std::string); + message_->append(a_message.GetString().c_str()); + } + + // Swap the contents of this AssertionResult with other. + void swap(AssertionResult& other); + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + std::unique_ptr< ::std::string> message_; +}; + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +} // namespace testing + +// Includes the auto-generated header that implements a family of generic +// predicate assertion macros. This include comes late because it relies on +// APIs declared above. +#include "gtest/gtest_pred_impl.h" + +namespace testing { + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestSuites, and +// each TestSuite contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used in a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// void SetUp() override { ... } +// void TearDown() override { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class TestInfo; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test suite. + // + // Google Test will call Foo::SetUpTestSuite() before running the first + // test in test suite Foo. Hence a sub-class can define its own + // SetUpTestSuite() method to shadow the one defined in the super + // class. + static void SetUpTestSuite() {} + + // Tears down the stuff shared by all tests in this test suite. + // + // Google Test will call Foo::TearDownTestSuite() after running the last + // test in test suite Foo. Hence a sub-class can define its own + // TearDownTestSuite() method to shadow the one defined in the super + // class. + static void TearDownTestSuite() {} + + // Legacy API is deprecated but still available. Use SetUpTestSuite and + // TearDownTestSuite instead. +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + static void TearDownTestCase() {} + static void SetUpTestCase() {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Returns true if and only if the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true if and only if the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true if and only if the current test was skipped. + static bool IsSkipped(); + + // Returns true if and only if the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test, test suite, or for the entire + // invocation of the test program when used outside of the context of a + // test suite. Only the last value for a given key is remembered. These + // are public static so they can be called from utility functions that are + // not members of the test fixture. Calls to RecordProperty made during + // lifespan of the test (from the moment its constructor starts to the + // moment its destructor finishes) will be output in XML as attributes of + // the element. Properties recorded from fixture's + // SetUpTestSuite or TearDownTestSuite are logged as attributes of the + // corresponding element. Calls to RecordProperty made in the + // global context (before or after invocation of RUN_ALL_TESTS and from + // SetUp/TearDown method of Environment objects registered with Google + // Test) will be output as attributes of the element. + static void RecordProperty(const std::string& key, const std::string& value); + static void RecordProperty(const std::string& key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true if and only if the current test has the same fixture class + // as the first test in the current test suite. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Deletes self. We deliberately pick an unusual name for this + // internal method to avoid clashing with names used in user TESTs. + void DeleteSelf_() { delete this; } + + const std::unique_ptr gtest_flag_saver_; + + // Often a user misspells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if void Setup() is declared in the user's + // test fixture. + // + // - This method is private, so it will be another compiler error + // if the method is called from the user's test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const std::string& a_key, const std::string& a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const std::string& new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + std::string key_; + // The value supplied by the user. + std::string value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true if and only if the test passed (i.e. no test part failed). + bool Passed() const { return !Skipped() && !Failed(); } + + // Returns true if and only if the test was skipped. + bool Skipped() const; + + // Returns true if and only if the test failed. + bool Failed() const; + + // Returns true if and only if the test fatally failed. + bool HasFatalFailure() const; + + // Returns true if and only if the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Gets the time of the test case start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Returns the i-th test part result among all the results. i can range from 0 + // to total_part_count() - 1. If i is not in that range, aborts the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class TestSuite; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + friend class internal::FuchsiaDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the start time. + void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. xml_element specifies the element for which the property is being + // recorded and is used for validation. + void RecordProperty(const std::string& xml_element, + const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testsuite tags. Returns true if the property is valid. + // FIXME: Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properties_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test suite name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test suite name. + const char* test_suite_name() const { return test_suite_name_.c_str(); } + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const char* test_case_name() const { return test_suite_name(); } +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a typed + // or a type-parameterized test. + const char* type_param() const { + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; + } + + // Returns the text representation of the value parameter, or NULL if this + // is not a value-parameterized test. + const char* value_param() const { + if (value_param_.get() != nullptr) return value_param_->c_str(); + return nullptr; + } + + // Returns the file name where this test is defined. + const char* file() const { return location_.file.c_str(); } + + // Returns the line where this test is defined. + int line() const { return location_.line; } + + // Return true if this test should not be run because it's in another shard. + bool is_in_another_shard() const { return is_in_another_shard_; } + + // Returns true if this test should run, that is if the test is not + // disabled (or it is disabled but the also_run_disabled_tests flag has + // been specified) and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test suite Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const { return should_run_; } + + // Returns true if and only if this test will appear in the XML report. + bool is_reportable() const { + // The XML report includes tests matching the filter, excluding those + // run in other shards. + return matches_filter_ && !is_in_another_shard_; + } + + // Returns the result of the test. + const TestResult* result() const { return &result_; } + + private: +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestSuite; + friend class internal::UnitTestImpl; + friend class internal::StreamingListenerTest; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, internal::CodeLocation code_location, + internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const std::string& test_suite_name, const std::string& name, + const char* a_type_param, // NULL if not a type-parameterized test + const char* a_value_param, // NULL if not a value-parameterized test + internal::CodeLocation a_code_location, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count() { + return result_.increment_death_test_count(); + } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + // Skip and records the test result for this object. + void Skip(); + + static void ClearTestResult(TestInfo* test_info) { + test_info->result_.Clear(); + } + + // These fields are immutable properties of the test. + const std::string test_suite_name_; // test suite name + const std::string name_; // Test name + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const std::unique_ptr type_param_; + // Text representation of the value parameter, or NULL if this is not a + // value-parameterized test. + const std::unique_ptr value_param_; + internal::CodeLocation location_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True if and only if this test should run + bool is_disabled_; // True if and only if this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test suite, which consists of a vector of TestInfos. +// +// TestSuite is not copyable. +class GTEST_API_ TestSuite { + public: + // Creates a TestSuite with the given name. + // + // TestSuite does NOT have a default constructor. Always use this + // constructor to create a TestSuite object. + // + // Arguments: + // + // name: name of the test suite + // a_type_param: the name of the test's type parameter, or NULL if + // this is not a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test suite + // tear_down_tc: pointer to the function that tears down the test suite + TestSuite(const char* name, const char* a_type_param, + internal::SetUpTestSuiteFunc set_up_tc, + internal::TearDownTestSuiteFunc tear_down_tc); + + // Destructor of TestSuite. + virtual ~TestSuite(); + + // Gets the name of the TestSuite. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a + // type-parameterized test suite. + const char* type_param() const { + if (type_param_.get() != nullptr) return type_param_->c_str(); + return nullptr; + } + + // Returns true if any test in this test suite should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test suite. + int successful_test_count() const; + + // Gets the number of skipped tests in this test suite. + int skipped_test_count() const; + + // Gets the number of failed tests in this test suite. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests in this test suite. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Get the number of tests in this test suite that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test suite. + int total_test_count() const; + + // Returns true if and only if the test suite passed. + bool Passed() const { return !Failed(); } + + // Returns true if and only if the test suite failed. + bool Failed() const { + return failed_test_count() > 0 || ad_hoc_test_result().Failed(); + } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Gets the time of the test suite start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + // Returns the TestResult that holds test properties recorded during + // execution of SetUpTestSuite and TearDownTestSuite. + const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestSuite. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestSuite. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test suite. Will delete the TestInfo upon + // destruction of the TestSuite object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test suite. + void ClearResult(); + + // Clears the results of all tests in the given test suite. + static void ClearTestSuiteResult(TestSuite* test_suite) { + test_suite->ClearResult(); + } + + // Runs every test in this TestSuite. + void Run(); + + // Skips the execution of tests under this TestSuite + void Skip(); + + // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed + // for catching exceptions thrown from SetUpTestSuite(). + void RunSetUpTestSuite() { + if (set_up_tc_ != nullptr) { + (*set_up_tc_)(); + } + } + + // Runs TearDownTestSuite() for this TestSuite. This wrapper is + // needed for catching exceptions thrown from TearDownTestSuite(). + void RunTearDownTestSuite() { + if (tear_down_tc_ != nullptr) { + (*tear_down_tc_)(); + } + } + + // Returns true if and only if test passed. + static bool TestPassed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Passed(); + } + + // Returns true if and only if test skipped. + static bool TestSkipped(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Skipped(); + } + + // Returns true if and only if test failed. + static bool TestFailed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Failed(); + } + + // Returns true if and only if the test is disabled and will be reported in + // the XML report. + static bool TestReportableDisabled(const TestInfo* test_info) { + return test_info->is_reportable() && test_info->is_disabled_; + } + + // Returns true if and only if test is disabled. + static bool TestDisabled(const TestInfo* test_info) { + return test_info->is_disabled_; + } + + // Returns true if and only if this test will appear in the XML report. + static bool TestReportable(const TestInfo* test_info) { + return test_info->is_reportable(); + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo* test_info) { + return test_info->should_run(); + } + + // Shuffles the tests in this test suite. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test suite. + std::string name_; + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const std::unique_ptr type_param_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test suite. + internal::SetUpTestSuiteFunc set_up_tc_; + // Pointer to the function that tears down the test suite. + internal::TearDownTestSuiteFunc tear_down_tc_; + // True if and only if any test in this test suite should run. + bool should_run_; + // The start time, in milliseconds since UNIX Epoch. + TimeInMillis start_timestamp_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + // Holds test properties recorded during execution of SetUpTestSuite and + // TearDownTestSuite. + TestResult ad_hoc_test_result_; + + // We disallow copying TestSuites. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. You should subclass this to define your own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; } +}; + +#if GTEST_HAS_EXCEPTIONS + +// Exception which can be thrown from TestEventListener::OnTestPartResult. +class GTEST_API_ AssertionException + : public internal::GoogleTestFailureException { + public: + explicit AssertionException(const TestPartResult& result) + : GoogleTestFailureException(result) {} +}; + +#endif // GTEST_HAS_EXCEPTIONS + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test suite starts. + virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {} + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCEED() invocation. + // If you want to throw an exception from this function to skip to the next + // TEST, it must be AssertionException defined above, or inherited from it. + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test suite ends. + virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {} + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + void OnTestProgramStart(const UnitTest& /*unit_test*/) override {} + void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {} + void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {} +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseStart(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnTestStart(const TestInfo& /*test_info*/) override {} + void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {} + void OnTestEnd(const TestInfo& /*test_info*/) override {} + void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {} +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + void OnTestCaseEnd(const TestCase& /*test_case*/) override {} +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {} + void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {} + void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) override {} + void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestSuite; + friend class TestInfo; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestSuites. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestSuite object for the test that's currently running, + // or NULL if no test is running. + const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_); + +// Legacy API is still available but deprecated +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); +#endif + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const + GTEST_LOCK_EXCLUDED_(mutex_); + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + + // Returns the ParameterizedTestSuiteRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() + GTEST_LOCK_EXCLUDED_(mutex_); + + // Gets the number of successful test suites. + int successful_test_suite_count() const; + + // Gets the number of failed test suites. + int failed_test_suite_count() const; + + // Gets the number of all test suites. + int total_test_suite_count() const; + + // Gets the number of all test suites that contain at least one test + // that should run. + int test_suite_to_run_count() const; + + // Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + int successful_test_case_count() const; + int failed_test_case_count() const; + int total_test_case_count() const; + int test_case_to_run_count() const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of skipped tests. + int skipped_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true if and only if the unit test passed (i.e. all test suites + // passed). + bool Passed() const; + + // Returns true if and only if the unit test failed (i.e. some test suite + // failed or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + const TestSuite* GetTestSuite(int i) const; + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + const TestCase* GetTestCase(int i) const; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + // Returns the TestResult containing information on test failures and + // properties logged outside of individual test suites. + const TestResult& ad_hoc_test_result() const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const std::string& message, + const std::string& os_stack_trace) + GTEST_LOCK_EXCLUDED_(mutex_); + + // Adds a TestProperty to the current TestResult object when invoked from + // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked + // from SetUpTestSuite or TearDownTestSuite, or to the global property set + // when invoked elsewhere. If the result already contains a property with + // the same key, the value will be updated. + void RecordProperty(const std::string& key, const std::string& value); + + // Gets the i-th test suite among all the test suites. i can range from 0 to + // total_test_suite_count() - 1. If i is not in that range, returns NULL. + TestSuite* GetMutableTestSuite(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and functions are friends as they need to access private + // members of UnitTest. + friend class ScopedTrace; + friend class Test; + friend class internal::AssertHelper; + friend class internal::StreamingListenerTest; + friend class internal::UnitTestRecordPropertyTestHelper; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend std::set* internal::GetIgnoredParameterizedTestSuites(); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const std::string& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace) + GTEST_LOCK_EXCLUDED_(mutex_); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace() + GTEST_LOCK_EXCLUDED_(mutex_); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +// This overloaded version can be used on Arduino/embedded platforms where +// there is no argc/argv. +GTEST_API_ void InitGoogleTest(); + +namespace internal { + +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers +// when calling EXPECT_* in a tight loop. +template +AssertionResult CmpHelperEQFailure(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, const T2& rhs) { + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), + false); +} + +// This block of code defines operator==/!= +// to block lexical scope lookup. +// It prevents using invalid operator==/!= defined at namespace scope. +struct faketype {}; +inline bool operator==(faketype, faketype) { return true; } +inline bool operator!=(faketype, faketype) { return false; } + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, + const T2& rhs) { + if (lhs == rhs) { + return AssertionSuccess(); + } + + return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); +} + +class EqHelper { + public: + // This templatized version is for the general case. + template < + typename T1, typename T2, + // Disable this overload for cases where one argument is a pointer + // and the other is the null pointer constant. + typename std::enable_if::value || + !std::is_pointer::value>::type* = nullptr> + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, const T1& lhs, + const T2& rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); + } + + template + static AssertionResult Compare( + const char* lhs_expression, const char* rhs_expression, + // Handle cases where '0' is used as a null pointer literal. + std::nullptr_t /* lhs */, T* rhs) { + // We already know that 'lhs' is a null pointer. + return CmpHelperEQ(lhs_expression, rhs_expression, static_cast(nullptr), + rhs); + } +}; + +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers +// when calling EXPECT_OP in a tight loop. +template +AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, + const T1& val1, const T2& val2, + const char* op) { + return AssertionFailure() + << "Expected: (" << expr1 << ") " << op << " (" << expr2 + << "), actual: " << FormatForComparisonFailureMessage(val1, val2) + << " vs " << FormatForComparisonFailureMessage(val2, val1); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ + }\ +} + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, <) +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, >) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, + const char* rhs_expression, + RawType lhs_value, + RawType rhs_value) { + const FloatingPoint lhs(lhs_value), rhs(rhs_value); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + ::std::stringstream lhs_ss; + lhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << lhs_value; + + ::std::stringstream rhs_ss; + rhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << rhs_value; + + return EqFailure(lhs_expression, + rhs_expression, + StringStreamToString(&lhs_ss), + StringStreamToString(&rhs_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + std::string const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +} // namespace internal + +// The pure interface class that all value-parameterized tests inherit from. +// A value-parameterized class must inherit from both ::testing::Test and +// ::testing::WithParamInterface. In most cases that just means inheriting +// from ::testing::TestWithParam, but more complicated test hierarchies +// may need to inherit from Test and WithParamInterface at different levels. +// +// This interface has support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// ~FooTest() override { +// // Can use GetParam() here. +// } +// void SetUp() override { +// // Can use GetParam() here. +// } +// void TearDown override { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class WithParamInterface { + public: + typedef T ParamType; + virtual ~WithParamInterface() {} + + // The current parameter value. Is also available in the test fixture's + // constructor. + static const ParamType& GetParam() { + GTEST_CHECK_(parameter_ != nullptr) + << "GetParam() can only be called inside a value-parameterized test " + << "-- did you intend to write TEST_P instead of TEST_F?"; + return *parameter_; + } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of WithParamInterface and Test. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* WithParamInterface::parameter_ = nullptr; + +// Most value-parameterized classes can ignore the existence of +// WithParamInterface, and can just inherit from ::testing::TestWithParam. + +template +class TestWithParam : public Test, public WithParamInterface { +}; + +// Macros for indicating success/failure in test code. + +// Skips test in runtime. +// Skipping test aborts current function. +// Skipped tests are neither successful nor failed. +#define GTEST_SKIP() GTEST_SKIP_("") + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a nonfatal failure at the given source file location with +// a generic message. +#define ADD_FAILURE_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kNonFatalFailure) + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Like GTEST_FAIL(), but at the given source file location. +#define GTEST_FAIL_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kFatalFailure) + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +# define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +# define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define GTEST_EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define GTEST_EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define GTEST_ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define GTEST_ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Define these macros to 1 to omit the definition of the corresponding +// EXPECT or ASSERT, which clashes with some users' own code. + +#if !GTEST_DONT_DEFINE_EXPECT_TRUE +#define EXPECT_TRUE(condition) GTEST_EXPECT_TRUE(condition) +#endif + +#if !GTEST_DONT_DEFINE_EXPECT_FALSE +#define EXPECT_FALSE(condition) GTEST_EXPECT_FALSE(condition) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_TRUE +#define ASSERT_TRUE(condition) GTEST_ASSERT_TRUE(condition) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_FALSE +#define ASSERT_FALSE(condition) GTEST_ASSERT_FALSE(condition) +#endif + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2 +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to +// {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(Foo(), 5); +// EXPECT_EQ(a_pointer, NULL); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) +#define EXPECT_NE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define GTEST_ASSERT_EQ(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2) +#define GTEST_ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define GTEST_ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define GTEST_ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define GTEST_ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define GTEST_ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of +// ASSERT_XY(), which clashes with some users' own code. + +#if !GTEST_DONT_DEFINE_ASSERT_EQ +# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_NE +# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LE +# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LT +# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GE +# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GT +# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) +#endif + +// C-string Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(val1, val2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + val1, val2) + +#define EXPECT_DOUBLE_EQ(val1, val2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + val1, val2) + +#define ASSERT_FLOAT_EQ(val1, val2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + val1, val2) + +#define ASSERT_DOUBLE_EQ(val1, val2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + val1, val2) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +# define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +# define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the given source file path and line number, +// and the given message) to be included in every test failure message generated +// by code in the scope of the lifetime of an instance of this class. The effect +// is undone with the destruction of the instance. +// +// The message argument can be anything streamable to std::ostream. +// +// Example: +// testing::ScopedTrace trace("file.cc", 123, "message"); +// +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + + // Template version. Uses Message() to convert the values into strings. + // Slow, but flexible. + template + ScopedTrace(const char* file, int line, const T& message) { + PushTrace(file, line, (Message() << message).GetString()); + } + + // Optimize for some known types. + ScopedTrace(const char* file, int line, const char* message) { + PushTrace(file, line, message ? message : "(null)"); + } + + ScopedTrace(const char* file, int line, const std::string& message) { + PushTrace(file, line, message); + } + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + void PushTrace(const char* file, int line, std::string message); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +// +// Assuming that each thread maintains its own stack of traces. +// Therefore, a SCOPED_TRACE() would (correctly) only affect the +// assertions in its own thread. +#define SCOPED_TRACE(message) \ + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, (message)) + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles if and only if type1 and type2 +// are the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +constexpr bool StaticAssertTypeEq() noexcept { + static_assert(std::is_same::value, "T1 and T2 are not the same type"); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test suite, and the second +// parameter is the name of the test within the test suite. +// +// The convention is to end the test suite name with "Test". For +// example, a test suite for the Foo class can be named FooTest. +// +// Test code should appear between braces after an invocation of +// this macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \ + ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test suite name. The second parameter is the +// name of the test within the test suite. +// +// A test fixture class must be declared earlier. The user should put +// the test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// void SetUp() override { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(a_.size(), 0); +// EXPECT_EQ(b_.size(), 1); +// } +// +// GOOGLETEST_CM0011 DO NOT DELETE +#if !GTEST_DONT_DEFINE_TEST +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) +#endif // !GTEST_DONT_DEFINE_TEST + +// Returns a path to temporary directory. +// Tries to determine an appropriate directory for the platform. +GTEST_API_ std::string TempDir(); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +// Dynamically registers a test with the framework. +// +// This is an advanced API only to be used when the `TEST` macros are +// insufficient. The macros should be preferred when possible, as they avoid +// most of the complexity of calling this function. +// +// The `factory` argument is a factory callable (move-constructible) object or +// function pointer that creates a new instance of the Test object. It +// handles ownership to the caller. The signature of the callable is +// `Fixture*()`, where `Fixture` is the test fixture class for the test. All +// tests registered with the same `test_suite_name` must return the same +// fixture type. This is checked at runtime. +// +// The framework will infer the fixture class from the factory and will call +// the `SetUpTestSuite` and `TearDownTestSuite` for it. +// +// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is +// undefined. +// +// Use case example: +// +// class MyFixture : public ::testing::Test { +// public: +// // All of these optional, just like in regular macro usage. +// static void SetUpTestSuite() { ... } +// static void TearDownTestSuite() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } +// }; +// +// class MyTest : public MyFixture { +// public: +// explicit MyTest(int data) : data_(data) {} +// void TestBody() override { ... } +// +// private: +// int data_; +// }; +// +// void RegisterMyTests(const std::vector& values) { +// for (int v : values) { +// ::testing::RegisterTest( +// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, +// std::to_string(v).c_str(), +// __FILE__, __LINE__, +// // Important to use the fixture type as the return type here. +// [=]() -> MyFixture* { return new MyTest(v); }); +// } +// } +// ... +// int main(int argc, char** argv) { +// std::vector values_to_test = LoadValuesFromConfig(); +// RegisterMyTests(values_to_test); +// ... +// return RUN_ALL_TESTS(); +// } +// +template +TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, + const char* type_param, const char* value_param, + const char* file, int line, Factory factory) { + using TestT = typename std::remove_pointer::type; + + class FactoryImpl : public internal::TestFactoryBase { + public: + explicit FactoryImpl(Factory f) : factory_(std::move(f)) {} + Test* CreateTest() override { return factory_(); } + + private: + Factory factory_; + }; + + return internal::MakeAndRegisterTestInfo( + test_suite_name, test_name, type_param, value_param, + internal::CodeLocation(file, line), internal::GetTypeId(), + internal::SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + internal::SuiteApiResolver::GetTearDownCaseOrSuite(file, line), + new FactoryImpl{std::move(factory)}); +} + +} // namespace testing + +// Use this function in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). +// +// This function was formerly a macro; thus, it is in the global +// namespace and has an all-caps name. +int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; + +inline int RUN_ALL_TESTS() { + return ::testing::UnitTest::GetInstance()->Run(); +} + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_H_ diff --git a/gtestsuite/inc/gtest/gtest_pred_impl.h b/gtestsuite/inc/gtest/gtest_pred_impl.h new file mode 100644 index 000000000..5029a9bb0 --- /dev/null +++ b/gtestsuite/inc/gtest/gtest_pred_impl.h @@ -0,0 +1,359 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +#include "gtest/gtest.h" + +namespace testing { + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + return AssertionFailure() + << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 + << ", " << e5 << ") evaluates to false, where" + << "\n" + << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n" + << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n" + << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n" + << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n" + << e5 << " evaluates to " << ::testing::PrintToString(v5); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/gtestsuite/inc/gtest/gtest_prod.h b/gtestsuite/inc/gtest/gtest_prod.h new file mode 100644 index 000000000..38b9d85a5 --- /dev/null +++ b/gtestsuite/inc/gtest/gtest_prod.h @@ -0,0 +1,61 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +// Google C++ Testing and Mocking Framework definitions useful in production code. +// GOOGLETEST_CM0003 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void PrivateMethod(); +// FRIEND_TEST(MyClassTest, PrivateMethodWorks); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, PrivateMethodWorks) { +// // Can call MyClass::PrivateMethod() here. +// } +// +// Note: The test class must be in the same namespace as the class being tested. +// For example, putting MyClassTest in an anonymous namespace will not work. + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ diff --git a/gtestsuite/inc/gtest/internal/custom/README.md b/gtestsuite/inc/gtest/internal/custom/README.md new file mode 100644 index 000000000..ff391fb4e --- /dev/null +++ b/gtestsuite/inc/gtest/internal/custom/README.md @@ -0,0 +1,56 @@ +# Customization Points + +The custom directory is an injection point for custom user configurations. + +## Header `gtest.h` + +### The following macros can be defined: + +* `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of + `OsStackTraceGetterInterface`. +* `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See + `testing::TempDir` for semantics and signature. + +## Header `gtest-port.h` + +The following macros can be defined: + +### Flag related macros: + +* `GTEST_FLAG(flag_name)` +* `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its + own flagfile flag parsing. +* `GTEST_DECLARE_bool_(name)` +* `GTEST_DECLARE_int32_(name)` +* `GTEST_DECLARE_string_(name)` +* `GTEST_DEFINE_bool_(name, default_val, doc)` +* `GTEST_DEFINE_int32_(name, default_val, doc)` +* `GTEST_DEFINE_string_(name, default_val, doc)` + +### Logging: + +* `GTEST_LOG_(severity)` +* `GTEST_CHECK_(condition)` +* Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too. + +### Threading: + +* `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided. +* `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal` + are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)` + and `GTEST_DEFINE_STATIC_MUTEX_(mutex)` +* `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)` +* `GTEST_LOCK_EXCLUDED_(locks)` + +### Underlying library support features + +* `GTEST_HAS_CXXABI_H_` + +### Exporting API symbols: + +* `GTEST_API_` - Specifier for exported symbols. + +## Header `gtest-printers.h` + +* See documentation at `gtest/gtest-printers.h` for details on how to define a + custom printer. diff --git a/gtestsuite/inc/gtest/internal/custom/gtest-port.h b/gtestsuite/inc/gtest/internal/custom/gtest-port.h new file mode 100644 index 000000000..db02881c0 --- /dev/null +++ b/gtestsuite/inc/gtest/internal/custom/gtest-port.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ diff --git a/gtestsuite/inc/gtest/internal/custom/gtest-printers.h b/gtestsuite/inc/gtest/internal/custom/gtest-printers.h new file mode 100644 index 000000000..b9495d837 --- /dev/null +++ b/gtestsuite/inc/gtest/internal/custom/gtest-printers.h @@ -0,0 +1,42 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file provides an injection point for custom printers in a local +// installation of gTest. +// It will be included from gtest-printers.h and the overrides in this file +// will be visible to everyone. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ diff --git a/gtestsuite/inc/gtest/internal/custom/gtest.h b/gtestsuite/inc/gtest/internal/custom/gtest.h new file mode 100644 index 000000000..afaaf17ba --- /dev/null +++ b/gtestsuite/inc/gtest/internal/custom/gtest.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ diff --git a/gtestsuite/inc/gtest/internal/gtest-death-test-internal.h b/gtestsuite/inc/gtest/internal/gtest-death-test-internal.h new file mode 100644 index 000000000..490296dfa --- /dev/null +++ b/gtestsuite/inc/gtest/internal/gtest-death-test-internal.h @@ -0,0 +1,304 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +#include "gtest/gtest-matchers.h" +#include "gtest/internal/gtest-internal.h" + +#include +#include + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, Matcher matcher, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the three reasons that a test might be aborted. + enum AbortReason { + TEST_ENCOUNTERED_RETURN_STATEMENT, + TEST_THREW_EXCEPTION, + TEST_DID_NOT_DIE + }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const std::string& message); + + private: + // A string containing a description of the outcome of the last death test. + static std::string last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, + Matcher matcher, const char* file, + int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + bool Create(const char* statement, Matcher matcher, + const char* file, int line, DeathTest** test) override; +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads +// and interpreted as a regex (rather than an Eq matcher) for legacy +// compatibility. +inline Matcher MakeDeathTestMatcher( + ::testing::internal::RE regex) { + return ContainsRegex(regex.pattern()); +} +inline Matcher MakeDeathTestMatcher(const char* regex) { + return ContainsRegex(regex); +} +inline Matcher MakeDeathTestMatcher( + const ::std::string& regex) { + return ContainsRegex(regex); +} + +// If a Matcher is passed to EXPECT_DEATH (etc.), it's +// used directly. +inline Matcher MakeDeathTestMatcher( + Matcher matcher) { + return matcher; +} + +// Traps C++ exceptions escaping statement and reports them as test +// failures. Note that trapping SEH exceptions is not implemented here. +# if GTEST_HAS_EXCEPTIONS +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (const ::std::exception& gtest_exception) { \ + fprintf(\ + stderr, \ + "\n%s: Caught std::exception-derived exception escaping the " \ + "death test statement. Exception message: %s\n", \ + ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ + gtest_exception.what()); \ + fflush(stderr); \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } catch (...) { \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } + +# else +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) + +# endif + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create( \ + #statement, \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != nullptr) { \ + std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \ + gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \ + : fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in +// NDEBUG mode. In this case we need the statements to be executed and the macro +// must accept a streamed message even though the message is never printed. +// The regex object is not evaluated, but it is used to prevent "unused" +// warnings and to avoid an expression that doesn't compile in debug mode. +#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \ + } else \ + ::testing::Message() + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const std::string& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + const std::string& file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + std::string file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ diff --git a/gtestsuite/inc/gtest/internal/gtest-filepath.h b/gtestsuite/inc/gtest/internal/gtest-filepath.h new file mode 100644 index 000000000..0c033abc3 --- /dev/null +++ b/gtestsuite/inc/gtest/internal/gtest-filepath.h @@ -0,0 +1,211 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in gtest/internal/gtest-internal.h. +// Do not include this header file separately! + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + +#include "gtest/internal/gtest-string.h" + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const std::string& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + const std::string& string() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true if and only if the path is "". + bool IsEmpty() const { return pathname_.empty(); } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurrence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + std::string pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/gtestsuite/inc/gtest/internal/gtest-internal.h b/gtestsuite/inc/gtest/internal/gtest-internal.h new file mode 100644 index 000000000..f8cbdbd81 --- /dev/null +++ b/gtestsuite/inc/gtest/internal/gtest-internal.h @@ -0,0 +1,1560 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +#include "gtest/internal/gtest-port.h" + +#if GTEST_OS_LINUX +# include +# include +# include +# include +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest-message.h" +#include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-string.h" +#include "gtest/internal/gtest-type-util.h" + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +// Stringifies its argument. +// Work around a bug in visual studio which doesn't accept code like this: +// +// #define GTEST_STRINGIFY_(name) #name +// #define MACRO(a, b, c) ... GTEST_STRINGIFY_(a) ... +// MACRO(, x, y) +// +// Complaining about the argument to GTEST_STRINGIFY_ being empty. +// This is allowed by the spec. +#define GTEST_STRINGIFY_HELPER_(name, ...) #name +#define GTEST_STRINGIFY_(...) GTEST_STRINGIFY_HELPER_(__VA_ARGS__, ) + +namespace proto2 { +class MessageLite; +} + +namespace testing { + +// Forward declarations. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test suites. + +template +::std::string PrintToString(const T& value); + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// An IgnoredValue object can be implicitly constructed from ANY value. +class IgnoredValue { + struct Sink {}; + public: + // This constructor template allows any value to be implicitly + // converted to IgnoredValue. The object has no data member and + // doesn't try to remember anything about the argument. We + // deliberately omit the 'explicit' keyword in order to allow the + // conversion to be implicit. + // Disable the conversion if T already has a magical conversion operator. + // Otherwise we get ambiguity. + template ::value, + int>::type = 0> + IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit) +}; + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ std::string AppendUserMessage( + const std::string& gtest_msg, const Message& user_msg); + +#if GTEST_HAS_EXCEPTIONS + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ +/* an exported class was derived from a class that was not exported */) + +// This exception is thrown by (and only by) a failed Google Test +// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions +// are enabled). We derive it from std::runtime_error, which is for +// errors presumably detectable only at run time. Since +// std::runtime_error inherits from std::exception, many testing +// frameworks know how to extract and print the message inside it. +class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure); +}; + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275 + +#endif // GTEST_HAS_EXCEPTIONS + +namespace edit_distance { +// Returns the optimal edits to go from 'left' to 'right'. +// All edits cost the same, with replace having lower priority than +// add/remove. +// Simple implementation of the Wagner-Fischer algorithm. +// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm +enum EditType { kMatch, kAdd, kRemove, kReplace }; +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, const std::vector& right); + +// Same as above, but the input is represented as strings. +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right); + +// Create a diff of the input strings in Unified diff format. +GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context = 2); + +} // namespace edit_distance + +// Calculate the diff between 'left' and 'right' and return it in unified diff +// format. +// If not null, stores in 'total_line_count' the total number of lines found +// in left + right. +GTEST_API_ std::string DiffStrings(const std::string& left, + const std::string& right, + size_t* total_line_count); + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true if and only if the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const std::string& expected_value, + const std::string& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ std::string GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + static const uint32_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Returns the maximum representable finite floating-point number. + static RawType Max(); + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true if and only if this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true if and only if this number is at most kMaxUlps ULP's away + // from rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// We cannot use std::numeric_limits::max() as it clashes with the max() +// macro defined by . +template <> +inline float FloatingPoint::Max() { return FLT_MAX; } +template <> +inline double FloatingPoint::Max() { return DBL_MAX; } + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test suite, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + Test* CreateTest() override { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Types of SetUpTestSuite() and TearDownTestSuite() functions. +using SetUpTestSuiteFunc = void (*)(); +using TearDownTestSuiteFunc = void (*)(); + +struct CodeLocation { + CodeLocation(const std::string& a_file, int a_line) + : file(a_file), line(a_line) {} + + std::string file; + int line; +}; + +// Helper to identify which setup function for TestCase / TestSuite to call. +// Only one function is allowed, either TestCase or TestSute but not both. + +// Utility functions to help SuiteApiResolver +using SetUpTearDownSuiteFuncType = void (*)(); + +inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull( + SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) { + return a == def ? nullptr : a; +} + +template +// Note that SuiteApiResolver inherits from T because +// SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way +// SuiteApiResolver can access them. +struct SuiteApiResolver : T { + // testing::Test is only forward declared at this point. So we make it a + // dependend class for the compiler to be OK with it. + using Test = + typename std::conditional::type; + + static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename, + int line_num) { +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both SetUpTestSuite and SetUpTestCase, please " + "make sure there is only one present at " + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; +#else + (void)(filename); + (void)(line_num); + return &T::SetUpTestSuite; +#endif + } + + static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename, + int line_num) { +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + SetUpTearDownSuiteFuncType test_case_fp = + GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase); + SetUpTearDownSuiteFuncType test_suite_fp = + GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite); + + GTEST_CHECK_(!test_case_fp || !test_suite_fp) + << "Test can not provide both TearDownTestSuite and TearDownTestCase," + " please make sure there is only one present at" + << filename << ":" << line_num; + + return test_case_fp != nullptr ? test_case_fp : test_suite_fp; +#else + (void)(filename); + (void)(line_num); + return &T::TearDownTestSuite; +#endif + } +}; + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_suite_name: name of the test suite +// name: name of the test +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a type-parameterized test. +// code_location: code location where the test is defined +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test suite +// tear_down_tc: pointer to the function that tears down the test suite +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_suite_name, const char* name, const char* type_param, + const char* value_param, CodeLocation code_location, + TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc, + TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); + +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + +// State of the definition of a type-parameterized test suite. +class GTEST_API_ TypedTestSuitePState { + public: + TypedTestSuitePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test suite hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, + "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + registered_tests_.insert( + ::std::make_pair(test_name, CodeLocation(file, line))); + return true; + } + + bool TestExists(const std::string& test_name) const { + return registered_tests_.count(test_name) > 0; + } + + const CodeLocation& GetCodeLocation(const std::string& test_name) const { + RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); + GTEST_CHECK_(it != registered_tests_.end()); + return it->second; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames(const char* test_suite_name, + const char* file, int line, + const char* registered_tests); + + private: + typedef ::std::map RegisteredTestsMap; + + bool registered_; + RegisteredTestsMap registered_tests_; +}; + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +using TypedTestCasePState = TypedTestSuitePState; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == nullptr) { + return nullptr; + } + while (IsSpace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline std::string GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == nullptr ? str : std::string(str, comma); +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest); + +// The default argument to the template below for the case when the user does +// not provide a name generator. +struct DefaultNameGenerator { + template + static std::string GetName(int i) { + return StreamableToString(i); + } +}; + +template +struct NameGeneratorSelector { + typedef Provided type; +}; + +template +void GenerateNamesRecursively(internal::None, std::vector*, int) {} + +template +void GenerateNamesRecursively(Types, std::vector* result, int i) { + result->push_back(NameGenerator::template GetName(i)); + GenerateNamesRecursively(typename Types::Tail(), result, + i + 1); +} + +template +std::vector GenerateNames() { + std::vector result; + GenerateNamesRecursively(Types(), &result, 0); + return result; +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const CodeLocation& code_location, + const char* case_name, const char* test_names, int index, + const std::vector& type_names = + GenerateNames()) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + + "/" + type_names[static_cast(index)]) + .c_str(), + StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), + GetTypeName().c_str(), + nullptr, // No value parameter. + code_location, GetTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite( + code_location.file.c_str(), code_location.line), + SuiteApiResolver::GetTearDownCaseOrSuite( + code_location.file.c_str(), code_location.line), + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest::Register(prefix, + code_location, + case_name, + test_names, + index + 1, + type_names); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const CodeLocation&, + const char* /*case_name*/, const char* /*test_names*/, + int /*index*/, + const std::vector& = + std::vector() /*type_names*/) { + return true; + } +}; + +GTEST_API_ void RegisterTypeParameterizedTestSuite(const char* test_suite_name, + CodeLocation code_location); +GTEST_API_ void RegisterTypeParameterizedTestSuiteInstantiation( + const char* case_name); + +// TypeParameterizedTestSuite::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestSuite { + public: + static bool Register(const char* prefix, CodeLocation code_location, + const TypedTestSuitePState* state, const char* case_name, + const char* test_names, + const std::vector& type_names = + GenerateNames()) { + RegisterTypeParameterizedTestSuiteInstantiation(case_name); + std::string test_name = StripTrailingSpaces( + GetPrefixUntilComma(test_names)); + if (!state->TestExists(test_name)) { + fprintf(stderr, "Failed to get code location for test %s.%s at %s.", + case_name, test_name.c_str(), + FormatFileLocation(code_location.file.c_str(), + code_location.line).c_str()); + fflush(stderr); + posix::Abort(); + } + const CodeLocation& test_location = state->GetCodeLocation(test_name); + + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, test_location, case_name, test_names, 0, type_names); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestSuite::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestSuite { + public: + static bool Register(const char* /*prefix*/, const CodeLocation&, + const TypedTestSuitePState* /*state*/, + const char* /*case_name*/, const char* /*test_names*/, + const std::vector& = + std::vector() /*type_names*/) { + return true; + } +}; + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( + UnitTest* unit_test, int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// Helper for suppressing false warning from Clang on a const char* +// variable declared in a conditional expression always being NULL in +// the else branch. +struct GTEST_API_ ConstCharPtr { + ConstCharPtr(const char* str) : value(str) {} + operator bool() const { return true; } + const char* value; +}; + +// Helper for declaring std::string within 'if' statement +// in pre C++17 build environment. +struct TrueWithString { + TrueWithString() = default; + explicit TrueWithString(const char* str) : value(str) {} + explicit TrueWithString(const std::string& str) : value(str) {} + explicit operator bool() const { return true; } + std::string value; +}; + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const uint32_t kMaxRange = 1u << 31; + + explicit Random(uint32_t seed) : state_(seed) {} + + void Reseed(uint32_t seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + uint32_t Generate(uint32_t range); + + private: + uint32_t state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +// Turns const U&, U&, const U, and U all into U. +#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ + typename std::remove_const::type>::type + +// HasDebugStringAndShortDebugString::value is a compile-time bool constant +// that's true if and only if T has methods DebugString() and ShortDebugString() +// that return std::string. +template +class HasDebugStringAndShortDebugString { + private: + template + static auto CheckDebugString(C*) -> typename std::is_same< + std::string, decltype(std::declval().DebugString())>::type; + template + static std::false_type CheckDebugString(...); + + template + static auto CheckShortDebugString(C*) -> typename std::is_same< + std::string, decltype(std::declval().ShortDebugString())>::type; + template + static std::false_type CheckShortDebugString(...); + + using HasDebugStringType = decltype(CheckDebugString(nullptr)); + using HasShortDebugStringType = decltype(CheckShortDebugString(nullptr)); + + public: + static constexpr bool value = + HasDebugStringType::value && HasShortDebugStringType::value; +}; + +template +constexpr bool HasDebugStringAndShortDebugString::value; + +// When the compiler sees expression IsContainerTest(0), if C is an +// STL-style container class, the first overload of IsContainerTest +// will be viable (since both C::iterator* and C::const_iterator* are +// valid types and NULL can be implicitly converted to them). It will +// be picked over the second overload as 'int' is a perfect match for +// the type of argument 0. If C::iterator or C::const_iterator is not +// a valid type, the first overload is not viable, and the second +// overload will be picked. Therefore, we can determine whether C is +// a container class by checking the type of IsContainerTest(0). +// The value of the expression is insignificant. +// +// In C++11 mode we check the existence of a const_iterator and that an +// iterator is properly implemented for the container. +// +// For pre-C++11 that we look for both C::iterator and C::const_iterator. +// The reason is that C++ injects the name of a class as a member of the +// class itself (e.g. you can refer to class iterator as either +// 'iterator' or 'iterator::iterator'). If we look for C::iterator +// only, for example, we would mistakenly think that a class named +// iterator is an STL container. +// +// Also note that the simpler approach of overloading +// IsContainerTest(typename C::const_iterator*) and +// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. +typedef int IsContainer; +template ().begin()), + class = decltype(::std::declval().end()), + class = decltype(++::std::declval()), + class = decltype(*::std::declval()), + class = typename C::const_iterator> +IsContainer IsContainerTest(int /* dummy */) { + return 0; +} + +typedef char IsNotContainer; +template +IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } + +// Trait to detect whether a type T is a hash table. +// The heuristic used is that the type contains an inner type `hasher` and does +// not contain an inner type `reverse_iterator`. +// If the container is iterable in reverse, then order might actually matter. +template +struct IsHashTable { + private: + template + static char test(typename U::hasher*, typename U::reverse_iterator*); + template + static int test(typename U::hasher*, ...); + template + static char test(...); + + public: + static const bool value = sizeof(test(nullptr, nullptr)) == sizeof(int); +}; + +template +const bool IsHashTable::value; + +template (0)) == sizeof(IsContainer)> +struct IsRecursiveContainerImpl; + +template +struct IsRecursiveContainerImpl : public std::false_type {}; + +// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to +// obey the same inconsistencies as the IsContainerTest, namely check if +// something is a container is relying on only const_iterator in C++11 and +// is relying on both const_iterator and iterator otherwise +template +struct IsRecursiveContainerImpl { + using value_type = decltype(*std::declval()); + using type = + std::is_same::type>::type, + C>; +}; + +// IsRecursiveContainer is a unary compile-time predicate that +// evaluates whether C is a recursive container type. A recursive container +// type is a container type whose value_type is equal to the container type +// itself. An example for a recursive container type is +// boost::filesystem::path, whose iterator has a value_type that is equal to +// boost::filesystem::path. +template +struct IsRecursiveContainer : public IsRecursiveContainerImpl::type {}; + +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +// We use 2 different structs to allow non-copyable types to be used, as long +// as RelationToSourceReference() is passed. +struct RelationToSourceReference {}; +struct RelationToSourceCopy {}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef Element* iterator; + typedef const Element* const_iterator; + + // Constructs from a native array. References the source. + NativeArray(const Element* array, size_t count, RelationToSourceReference) { + InitRef(array, count); + } + + // Constructs from a native array. Copies the source. + NativeArray(const Element* array, size_t count, RelationToSourceCopy) { + InitCopy(array, count); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + (this->*rhs.clone_)(rhs.array_, rhs.size_); + } + + ~NativeArray() { + if (clone_ != &NativeArray::InitRef) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + static_assert(!std::is_const::value, "Type must not be const"); + static_assert(!std::is_reference::value, + "Type must not be a reference"); + + // Initializes this object with a copy of the input. + void InitCopy(const Element* array, size_t a_size) { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + size_ = a_size; + clone_ = &NativeArray::InitCopy; + } + + // Initializes this object with a reference of the input. + void InitRef(const Element* array, size_t a_size) { + array_ = array; + size_ = a_size; + clone_ = &NativeArray::InitRef; + } + + const Element* array_; + size_t size_; + void (NativeArray::*clone_)(const Element*, size_t); +}; + +// Backport of std::index_sequence. +template +struct IndexSequence { + using type = IndexSequence; +}; + +// Double the IndexSequence, and one if plus_one is true. +template +struct DoubleSequence; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; +template +struct DoubleSequence, sizeofT> { + using type = IndexSequence; +}; + +// Backport of std::make_index_sequence. +// It uses O(ln(N)) instantiation depth. +template +struct MakeIndexSequenceImpl + : DoubleSequence::type, + N / 2>::type {}; + +template <> +struct MakeIndexSequenceImpl<0> : IndexSequence<> {}; + +template +using MakeIndexSequence = typename MakeIndexSequenceImpl::type; + +template +using IndexSequenceFor = typename MakeIndexSequence::type; + +template +struct Ignore { + Ignore(...); // NOLINT +}; + +template +struct ElemFromListImpl; +template +struct ElemFromListImpl> { + // We make Ignore a template to solve a problem with MSVC. + // A non-template Ignore would work fine with `decltype(Ignore(I))...`, but + // MSVC doesn't understand how to deal with that pack expansion. + // Use `0 * I` to have a single instantiation of Ignore. + template + static R Apply(Ignore<0 * I>..., R (*)(), ...); +}; + +template +struct ElemFromList { + using type = + decltype(ElemFromListImpl::type>::Apply( + static_cast(nullptr)...)); +}; + +struct FlatTupleConstructTag {}; + +template +class FlatTuple; + +template +struct FlatTupleElemBase; + +template +struct FlatTupleElemBase, I> { + using value_type = typename ElemFromList::type; + FlatTupleElemBase() = default; + template + explicit FlatTupleElemBase(FlatTupleConstructTag, Arg&& t) + : value(std::forward(t)) {} + value_type value; +}; + +template +struct FlatTupleBase; + +template +struct FlatTupleBase, IndexSequence> + : FlatTupleElemBase, Idx>... { + using Indices = IndexSequence; + FlatTupleBase() = default; + template + explicit FlatTupleBase(FlatTupleConstructTag, Args&&... args) + : FlatTupleElemBase, Idx>(FlatTupleConstructTag{}, + std::forward(args))... {} + + template + const typename ElemFromList::type& Get() const { + return FlatTupleElemBase, I>::value; + } + + template + typename ElemFromList::type& Get() { + return FlatTupleElemBase, I>::value; + } + + template + auto Apply(F&& f) -> decltype(std::forward(f)(this->Get()...)) { + return std::forward(f)(Get()...); + } + + template + auto Apply(F&& f) const -> decltype(std::forward(f)(this->Get()...)) { + return std::forward(f)(Get()...); + } +}; + +// Analog to std::tuple but with different tradeoffs. +// This class minimizes the template instantiation depth, thus allowing more +// elements than std::tuple would. std::tuple has been seen to require an +// instantiation depth of more than 10x the number of elements in some +// implementations. +// FlatTuple and ElemFromList are not recursive and have a fixed depth +// regardless of T... +// MakeIndexSequence, on the other hand, it is recursive but with an +// instantiation depth of O(ln(N)). +template +class FlatTuple + : private FlatTupleBase, + typename MakeIndexSequence::type> { + using Indices = typename FlatTupleBase< + FlatTuple, typename MakeIndexSequence::type>::Indices; + + public: + FlatTuple() = default; + template + explicit FlatTuple(FlatTupleConstructTag tag, Args&&... args) + : FlatTuple::FlatTupleBase(tag, std::forward(args)...) {} + + using FlatTuple::FlatTupleBase::Apply; + using FlatTuple::FlatTupleBase::Get; +}; + +// Utility functions to be called with static_assert to induce deprecation +// warnings. +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TEST_SUITE_P") +constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE_P is deprecated, please use " + "TYPED_TEST_SUITE_P") +constexpr bool TypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "TYPED_TEST_CASE is deprecated, please use " + "TYPED_TEST_SUITE") +constexpr bool TypedTestCaseIsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "REGISTER_TYPED_TEST_CASE_P is deprecated, please use " + "REGISTER_TYPED_TEST_SUITE_P") +constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; } + +GTEST_INTERNAL_DEPRECATED( + "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use " + "INSTANTIATE_TYPED_TEST_SUITE_P") +constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } + +} // namespace internal +} // namespace testing + +namespace std { +// Some standard library implementations use `struct tuple_size` and some use +// `class tuple_size`. Clang warns about the mismatch. +// https://reviews.llvm.org/D55466 +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +struct tuple_size> + : std::integral_constant {}; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +} // namespace std + +#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ + ::testing::internal::AssertHelper(result_type, file, line, message) \ + = ::testing::Message() + +#define GTEST_MESSAGE_(message, result_type) \ + GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +#define GTEST_SKIP_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip) + +// Suppress MSVC warning 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +// NOTE: The "else" is important to keep this expansion to prevent a top-level +// "else" from attaching to our "if". +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { \ + statement; \ + } else /* NOLINT */ \ + static_assert(true, "") // User must have a semicolon after expansion. + +#if GTEST_HAS_EXCEPTIONS + +namespace testing { +namespace internal { + +class NeverThrown { + public: + const char* what() const noexcept { + return "this exception should never be thrown"; + } +}; + +} // namespace internal +} // namespace testing + +#if GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) ::testing::internal::GetTypeName(typeid(e)) + +#else // GTEST_HAS_RTTI + +#define GTEST_EXCEPTION_TYPE_(e) \ + std::string { "an std::exception-derived error" } + +#endif // GTEST_HAS_RTTI + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (typename std::conditional< \ + std::is_same::type>::type, \ + std::exception>::value, \ + const ::testing::internal::NeverThrown&, const std::exception&>::type \ + e) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } + +#else // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) + +#endif // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::TrueWithString gtest_msg{}) { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \ + catch (...) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = "Expected: " #statement \ + " throws an exception of type " #expected_exception \ + ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else /*NOLINT*/ \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \ + : fail(gtest_msg.value.c_str()) + +#if GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ + catch (std::exception const& e) { \ + gtest_msg.value = "it throws "; \ + gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \ + gtest_msg.value += " with description \""; \ + gtest_msg.value += e.what(); \ + gtest_msg.value += "\"."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } + +#else // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() + +#endif // GTEST_HAS_EXCEPTIONS + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::TrueWithString gtest_msg{}) { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \ + catch (...) { \ + gtest_msg.value = "it throws."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail(("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: " + gtest_msg.value).c_str()) + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail("Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't.") + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// representation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail("Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does.") + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + test_suite_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \ + static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \ + "test_suite_name must not be empty"); \ + static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \ + "test_name must not be empty"); \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public parent_class { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() = default; \ + ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + GTEST_DISALLOW_MOVE_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)); \ + \ + private: \ + void TestBody() override; \ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \ + }; \ + \ + ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name)::test_info_ = \ + ::testing::internal::MakeAndRegisterTestInfo( \ + #test_suite_name, #test_name, nullptr, nullptr, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \ + ::testing::internal::SuiteApiResolver< \ + parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \ + new ::testing::internal::TestFactoryImpl); \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/gtestsuite/inc/gtest/internal/gtest-param-util.h b/gtestsuite/inc/gtest/internal/gtest-param-util.h new file mode 100644 index 000000000..c2ef6e312 --- /dev/null +++ b/gtestsuite/inc/gtest/internal/gtest-param-util.h @@ -0,0 +1,947 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Type and function utilities for implementing parameterized tests. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-printers.h" +#include "gtest/gtest-test-part.h" + +namespace testing { +// Input to a parameterized test name generator, describing a test parameter. +// Consists of the parameter value and the integer parameter index. +template +struct TestParamInfo { + TestParamInfo(const ParamType& a_param, size_t an_index) : + param(a_param), + index(an_index) {} + ParamType param; + size_t index; +}; + +// A builtin parameterized test name generator which returns the result of +// testing::PrintToString. +struct PrintToStringParamName { + template + std::string operator()(const TestParamInfo& info) const { + return PrintToString(info.param); + } +}; + +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// Utility Functions + +// Outputs a message explaining invalid registration of different +// fixture class for the same test suite. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name, + CodeLocation code_location); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + std::unique_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + std::shared_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + ~RangeGenerator() override {} + + ParamIteratorInterface* Begin() const override { + return new Iterator(this, begin_, 0, step_); + } + ParamIteratorInterface* End() const override { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + ~Iterator() override {} + + const ParamGeneratorInterface* BaseGenerator() const override { + return base_; + } + void Advance() override { + value_ = static_cast(value_ + step_); + index_++; + } + ParamIteratorInterface* Clone() const override { + return new Iterator(*this); + } + const T* Current() const override { return &value_; } + bool Equals(const ParamIteratorInterface& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = static_cast(i + step)) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + ~ValuesInIteratorRangeGenerator() override {} + + ParamIteratorInterface* Begin() const override { + return new Iterator(this, container_.begin()); + } + ParamIteratorInterface* End() const override { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + ~Iterator() override {} + + const ParamGeneratorInterface* BaseGenerator() const override { + return base_; + } + void Advance() override { + ++iterator_; + value_.reset(); + } + ParamIteratorInterface* Clone() const override { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + const T* Current() const override { + if (value_.get() == nullptr) value_.reset(new T(*iterator_)); + return value_.get(); + } + bool Equals(const ParamIteratorInterface& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of std::unique_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable std::unique_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Default parameterized test name generator, returns a string containing the +// integer test parameter index. +template +std::string DefaultParamName(const TestParamInfo& info) { + Message name_stream; + name_stream << info.index; + return name_stream.GetString(); +} + +template +void TestNotEmpty() { + static_assert(sizeof(T) == 0, "Empty arguments are not allowed."); +} +template +void TestNotEmpty(const T&) {} + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + Test* CreateTest() override { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestSuiteInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + using ParamType = typename TestSuite::ParamType; + + TestMetaFactory() {} + + TestFactoryBase* CreateTestFactory(ParamType parameter) override { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestSuiteInfoBase is a generic interface +// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds +// a collection of pointers to the ParameterizedTestSuiteInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestSuiteInfoBase { + public: + virtual ~ParameterizedTestSuiteInfoBase() {} + + // Base part of test suite name for display purposes. + virtual const std::string& GetTestSuiteName() const = 0; + // Test suite id to verify identity. + virtual TypeId GetTestSuiteTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test suite right before running them in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestSuiteInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Report a the name of a test_suit as safe to ignore +// as the side effect of construction of this type. +struct GTEST_API_ MarkAsIgnored { + explicit MarkAsIgnored(const char* test_suite); +}; + +GTEST_API_ void InsertSyntheticTestCase(const std::string& name, + CodeLocation location, bool has_test_p); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test suite and generators +// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that +// test suite. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestSuiteInstantiation(). + using ParamType = typename TestSuite::ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + using ParamNameGeneratorFunc = std::string(const TestParamInfo&); + + explicit ParameterizedTestSuiteInfo(const char* name, + CodeLocation code_location) + : test_suite_name_(name), code_location_(code_location) {} + + // Test suite base name for display purposes. + const std::string& GetTestSuiteName() const override { + return test_suite_name_; + } + // Test suite id to verify identity. + TypeId GetTestSuiteTypeId() const override { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_suite_name is the base name of the test suite (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test suite base name and DoBar is test base name. + void AddTestPattern(const char* test_suite_name, const char* test_base_name, + TestMetaFactoryBase* meta_factory, + CodeLocation code_location) { + tests_.push_back(std::shared_ptr(new TestInfo( + test_suite_name, test_base_name, meta_factory, code_location))); + } + // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestSuiteInstantiation(const std::string& instantiation_name, + GeneratorCreationFunc* func, + ParamNameGeneratorFunc* name_func, + const char* file, int line) { + instantiations_.push_back( + InstantiationInfo(instantiation_name, func, name_func, file, line)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test suite + // right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more than once on any single + // instance of a ParameterizedTestSuiteInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more than once. + void RegisterTests() override { + bool generated_instantiations = false; + + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + std::shared_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const std::string& instantiation_name = gen_it->name; + ParamGenerator generator((*gen_it->generator)()); + ParamNameGeneratorFunc* name_func = gen_it->name_func; + const char* file = gen_it->file; + int line = gen_it->line; + + std::string test_suite_name; + if ( !instantiation_name.empty() ) + test_suite_name = instantiation_name + "/"; + test_suite_name += test_info->test_suite_base_name; + + size_t i = 0; + std::set test_param_names; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + generated_instantiations = true; + + Message test_name_stream; + + std::string param_name = name_func( + TestParamInfo(*param_it, i)); + + GTEST_CHECK_(IsValidParamName(param_name)) + << "Parameterized test name '" << param_name + << "' is invalid, in " << file + << " line " << line << std::endl; + + GTEST_CHECK_(test_param_names.count(param_name) == 0) + << "Duplicate parameterized test name '" << param_name + << "', in " << file << " line " << line << std::endl; + + test_param_names.insert(param_name); + + if (!test_info->test_base_name.empty()) { + test_name_stream << test_info->test_base_name << "/"; + } + test_name_stream << param_name; + MakeAndRegisterTestInfo( + test_suite_name.c_str(), test_name_stream.GetString().c_str(), + nullptr, // No type parameter. + PrintToString(*param_it).c_str(), test_info->code_location, + GetTestSuiteTypeId(), + SuiteApiResolver::GetSetUpCaseOrSuite(file, line), + SuiteApiResolver::GetTearDownCaseOrSuite(file, line), + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + + if (!generated_instantiations) { + // There are no generaotrs, or they all generate nothing ... + InsertSyntheticTestCase(GetTestSuiteName(), code_location_, + !tests_.empty()); + } + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory, + CodeLocation a_code_location) + : test_suite_base_name(a_test_suite_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory), + code_location(a_code_location) {} + + const std::string test_suite_base_name; + const std::string test_base_name; + const std::unique_ptr > test_meta_factory; + const CodeLocation code_location; + }; + using TestInfoContainer = ::std::vector >; + // Records data received from INSTANTIATE_TEST_SUITE_P macros: + // + struct InstantiationInfo { + InstantiationInfo(const std::string &name_in, + GeneratorCreationFunc* generator_in, + ParamNameGeneratorFunc* name_func_in, + const char* file_in, + int line_in) + : name(name_in), + generator(generator_in), + name_func(name_func_in), + file(file_in), + line(line_in) {} + + std::string name; + GeneratorCreationFunc* generator; + ParamNameGeneratorFunc* name_func; + const char* file; + int line; + }; + typedef ::std::vector InstantiationContainer; + + static bool IsValidParamName(const std::string& name) { + // Check for empty string + if (name.empty()) + return false; + + // Check for invalid characters + for (std::string::size_type index = 0; index < name.size(); ++index) { + if (!IsAlNum(name[index]) && name[index] != '_') + return false; + } + + return true; + } + + const std::string test_suite_name_; + CodeLocation code_location_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo); +}; // class ParameterizedTestSuiteInfo + +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ +template +using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo; +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestSuiteRegistry contains a map of +// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P +// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding +// ParameterizedTestSuiteInfo descriptors. +class ParameterizedTestSuiteRegistry { + public: + ParameterizedTestSuiteRegistry() {} + ~ParameterizedTestSuiteRegistry() { + for (auto& test_suite_info : test_suite_infos_) { + delete test_suite_info; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test suite. + template + ParameterizedTestSuiteInfo* GetTestSuitePatternHolder( + const char* test_suite_name, CodeLocation code_location) { + ParameterizedTestSuiteInfo* typed_test_info = nullptr; + for (auto& test_suite_info : test_suite_infos_) { + if (test_suite_info->GetTestSuiteName() == test_suite_name) { + if (test_suite_info->GetTestSuiteTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test suite setup and tear-down in this case. + ReportInvalidTestSuiteType(test_suite_name, code_location); + posix::Abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestSuiteInfo >(test_suite_info); + } + break; + } + } + if (typed_test_info == nullptr) { + typed_test_info = new ParameterizedTestSuiteInfo( + test_suite_name, code_location); + test_suite_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (auto& test_suite_info : test_suite_infos_) { + test_suite_info->RegisterTests(); + } + } +// Legacy API is deprecated but still available +#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, CodeLocation code_location) { + return GetTestSuitePatternHolder(test_case_name, code_location); + } + +#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ + + private: + using TestSuiteInfoContainer = ::std::vector; + + TestSuiteInfoContainer test_suite_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry); +}; + +// Keep track of what type-parameterized test suite are defined and +// where as well as which are intatiated. This allows susequently +// identifying suits that are defined but never used. +class TypeParameterizedTestSuiteRegistry { + public: + // Add a suite definition + void RegisterTestSuite(const char* test_suite_name, + CodeLocation code_location); + + // Add an instantiation of a suit. + void RegisterInstantiation(const char* test_suite_name); + + // For each suit repored as defined but not reported as instantiation, + // emit a test that reports that fact (configurably, as an error). + void CheckForInstantiations(); + + private: + struct TypeParameterizedTestSuiteInfo { + explicit TypeParameterizedTestSuiteInfo(CodeLocation c) + : code_location(c), instantiated(false) {} + + CodeLocation code_location; + bool instantiated; + }; + + std::map suites_; +}; + +} // namespace internal + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { +// Used in the Values() function to provide polymorphic capabilities. + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + +template +class ValueArray { + public: + explicit ValueArray(Ts... v) : v_(FlatTupleConstructTag{}, std::move(v)...) {} + + template + operator ParamGenerator() const { // NOLINT + return ValuesIn(MakeVector(MakeIndexSequence())); + } + + private: + template + std::vector MakeVector(IndexSequence) const { + return std::vector{static_cast(v_.template Get())...}; + } + + FlatTuple v_; +}; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +template +class CartesianProductGenerator + : public ParamGeneratorInterface<::std::tuple> { + public: + typedef ::std::tuple ParamType; + + CartesianProductGenerator(const std::tuple...>& g) + : generators_(g) {} + ~CartesianProductGenerator() override {} + + ParamIteratorInterface* Begin() const override { + return new Iterator(this, generators_, false); + } + ParamIteratorInterface* End() const override { + return new Iterator(this, generators_, true); + } + + private: + template + class IteratorImpl; + template + class IteratorImpl> + : public ParamIteratorInterface { + public: + IteratorImpl(const ParamGeneratorInterface* base, + const std::tuple...>& generators, bool is_end) + : base_(base), + begin_(std::get(generators).begin()...), + end_(std::get(generators).end()...), + current_(is_end ? end_ : begin_) { + ComputeCurrentValue(); + } + ~IteratorImpl() override {} + + const ParamGeneratorInterface* BaseGenerator() const override { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + void Advance() override { + assert(!AtEnd()); + // Advance the last iterator. + ++std::get(current_); + // if that reaches end, propagate that up. + AdvanceIfEnd(); + ComputeCurrentValue(); + } + ParamIteratorInterface* Clone() const override { + return new IteratorImpl(*this); + } + + const ParamType* Current() const override { return current_value_.get(); } + + bool Equals(const ParamIteratorInterface& other) const override { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const IteratorImpl* typed_other = + CheckedDowncastToActualType(&other); + + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + if (AtEnd() && typed_other->AtEnd()) return true; + + bool same = true; + bool dummy[] = { + (same = same && std::get(current_) == + std::get(typed_other->current_))...}; + (void)dummy; + return same; + } + + private: + template + void AdvanceIfEnd() { + if (std::get(current_) != std::get(end_)) return; + + bool last = ThisI == 0; + if (last) { + // We are done. Nothing else to propagate. + return; + } + + constexpr size_t NextI = ThisI - (ThisI != 0); + std::get(current_) = std::get(begin_); + ++std::get(current_); + AdvanceIfEnd(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = std::make_shared(*std::get(current_)...); + } + bool AtEnd() const { + bool at_end = false; + bool dummy[] = { + (at_end = at_end || std::get(current_) == std::get(end_))...}; + (void)dummy; + return at_end; + } + + const ParamGeneratorInterface* const base_; + std::tuple::iterator...> begin_; + std::tuple::iterator...> end_; + std::tuple::iterator...> current_; + std::shared_ptr current_value_; + }; + + using Iterator = IteratorImpl::type>; + + std::tuple...> generators_; +}; + +template +class CartesianProductHolder { + public: + CartesianProductHolder(const Gen&... g) : generators_(g...) {} + template + operator ParamGenerator<::std::tuple>() const { + return ParamGenerator<::std::tuple>( + new CartesianProductGenerator(generators_)); + } + + private: + std::tuple generators_; +}; + +} // namespace internal +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ diff --git a/gtestsuite/inc/gtest/internal/gtest-port-arch.h b/gtestsuite/inc/gtest/internal/gtest-port-arch.h new file mode 100644 index 000000000..dd845915e --- /dev/null +++ b/gtestsuite/inc/gtest/internal/gtest-port-arch.h @@ -0,0 +1,114 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the GTEST_OS_* macro. +// It is separate from gtest-port.h so that custom/gtest-port.h can include it. + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +# elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) +# define GTEST_OS_WINDOWS_MINGW 1 +# define GTEST_OS_WINDOWS 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define GTEST_OS_WINDOWS_DESKTOP 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +# define GTEST_OS_WINDOWS_PHONE 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +# define GTEST_OS_WINDOWS_RT 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) +# define GTEST_OS_WINDOWS_PHONE 1 +# define GTEST_OS_WINDOWS_TV_TITLE 1 +# else + // WINAPI_FAMILY defined but no known partition matched. + // Default to desktop. +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __OS2__ +# define GTEST_OS_OS2 1 +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +# include +# if TARGET_OS_IPHONE +# define GTEST_OS_IOS 1 +# endif +#elif defined __DragonFly__ +# define GTEST_OS_DRAGONFLY 1 +#elif defined __FreeBSD__ +# define GTEST_OS_FREEBSD 1 +#elif defined __Fuchsia__ +# define GTEST_OS_FUCHSIA 1 +#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__) +# define GTEST_OS_GNU_KFREEBSD 1 +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# if defined __ANDROID__ +# define GTEST_OS_LINUX_ANDROID 1 +# endif +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#elif defined __NetBSD__ +# define GTEST_OS_NETBSD 1 +#elif defined __OpenBSD__ +# define GTEST_OS_OPENBSD 1 +#elif defined __QNX__ +# define GTEST_OS_QNX 1 +#elif defined(__HAIKU__) +#define GTEST_OS_HAIKU 1 +#elif defined ESP8266 +#define GTEST_OS_ESP8266 1 +#elif defined ESP32 +#define GTEST_OS_ESP32 1 +#elif defined(__XTENSA__) +#define GTEST_OS_XTENSA 1 +#endif // __CYGWIN__ + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ diff --git a/gtestsuite/inc/gtest/internal/gtest-port.h b/gtestsuite/inc/gtest/internal/gtest-port.h new file mode 100644 index 000000000..0953a781c --- /dev/null +++ b/gtestsuite/inc/gtest/internal/gtest-port.h @@ -0,0 +1,2389 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Low-level types and utilities for porting Google Test to various +// platforms. All macros ending with _ and symbols defined in an +// internal namespace are subject to change without notice. Code +// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't +// end with _ are part of Google Test's public API and can be used by +// code outside Google Test. +// +// This file is fundamental to Google Test. All other Google Test source +// files are expected to #include this. Therefore, it cannot #include +// any other Google Test header. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// Environment-describing macros +// ----------------------------- +// +// Google Test can be used in many different environments. Macros in +// this section tell Google Test what kind of environment it is being +// used in, such that Google Test can provide environment-specific +// features and implementations. +// +// Google Test tries to automatically detect the properties of its +// environment, so users usually don't need to worry about these +// macros. However, the automatic detection is not perfect. +// Sometimes it's necessary for a user to define some of the following +// macros in the build script to override Google Test's decisions. +// +// If the user doesn't define a macro in the list, Google Test will +// provide a default definition. After this header is #included, all +// macros in this list will be defined to either 1 or 0. +// +// Notes to maintainers: +// - Each macro here is a user-tweakable knob; do not grow the list +// lightly. +// - Use #if to key off these macros. Don't use #ifdef or "#if +// defined(...)", which will not work as these macros are ALWAYS +// defined. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular +// expressions are/aren't available. +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_HAS_STREAM_REDIRECTION +// - Define it to 1/0 to indicate whether the +// platform supports I/O stream redirection using +// dup() and dup2(). +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. +// GTEST_DEFAULT_DEATH_TEST_STYLE +// - The default value of --gtest_death_test_style. +// The legacy default has been "fast" in the open +// source version since 2008. The recommended value +// is "threadsafe", and can be set in +// custom/gtest-port.h. + +// Platform-indicating macros +// -------------------------- +// +// Macros indicating the platform on which Google Test is being used +// (a macro is defined to 1 if compiled on the given platform; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. +// +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_DRAGONFLY - DragonFlyBSD +// GTEST_OS_FREEBSD - FreeBSD +// GTEST_OS_FUCHSIA - Fuchsia +// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD +// GTEST_OS_HAIKU - Haiku +// GTEST_OS_HPUX - HP-UX +// GTEST_OS_LINUX - Linux +// GTEST_OS_LINUX_ANDROID - Google Android +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_IOS - iOS +// GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_NETBSD - NetBSD +// GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_OS2 - OS/2 +// GTEST_OS_QNX - QNX +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_WINDOWS_PHONE - Windows Phone +// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// It is possible that none of the GTEST_OS_* macros are defined. + +// Feature-indicating macros +// ------------------------- +// +// Macros indicating which Google Test features are available (a macro +// is defined to 1 if the corresponding feature is supported; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. +// +// These macros are public so that portable tests can be written. +// Such tests typically surround code using a feature with an #if +// which controls that code. For example: +// +// #if GTEST_HAS_DEATH_TEST +// EXPECT_DEATH(DoSomethingDeadly()); +// #endif +// +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_IS_THREADSAFE - Google Test is thread-safe. +// GOOGLETEST_CM0007 DO NOT DELETE +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with +// GTEST_HAS_POSIX_RE (see above) which users can +// define themselves. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above RE\b(s) are mutually exclusive. + +// Misc public macros +// ------------------ +// +// GTEST_FLAG(flag_name) - references the variable corresponding to +// the given Google Test flag. + +// Internal utilities +// ------------------ +// +// The following macros and utilities are for Google Test's INTERNAL +// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY. +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables copy operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_DISALLOW_MOVE_ASSIGN_ - disables move operator=. +// GTEST_DISALLOW_MOVE_AND_ASSIGN_ - disables move ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is +// suppressed (constant conditional). +// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 +// is suppressed. +// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter or +// UniversalPrinter specializations. +// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter +// or +// UniversalPrinter +// specializations. +// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or +// Matcher +// specializations. +// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter or +// UniversalPrinter +// specializations. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax on UNIX-like platforms +// GOOGLETEST_CM0008 DO NOT DELETE +// or a reduced regular exception syntax on other +// platforms, including Windows. +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// TimeInMillis - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetInjectableArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an int32_t environment variable. +// StringFromGTestEnv() - parses a string environment variable. +// +// Deprecation warnings: +// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as +// deprecated; calling a marked function +// should generate a compiler warning + +#include // for isspace, etc +#include // for ptrdiff_t +#include +#include +#include + +#include +#include +#include +#include + +#ifndef _WIN32_WCE +# include +# include +#endif // !_WIN32_WCE + +#if defined __APPLE__ +# include +# include +#endif + +#include // NOLINT +#include +#include +#include // NOLINT +#include +#include // NOLINT + +#include "gtest/internal/custom/gtest-port.h" +#include "gtest/internal/gtest-port-arch.h" + +#if !defined(GTEST_DEV_EMAIL_) +# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +# define GTEST_FLAG_PREFIX_ "gtest_" +# define GTEST_FLAG_PREFIX_DASH_ "gtest-" +# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +# define GTEST_NAME_ "Google Test" +# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/" +#endif // !defined(GTEST_DEV_EMAIL_) + +#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_) +# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" +#endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_) + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +# define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Macros for disabling Microsoft Visual C++ warnings. +// +// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) +// /* code that triggers warnings C4800 and C4385 */ +// GTEST_DISABLE_MSC_WARNINGS_POP_() +#if defined(_MSC_VER) +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ + __pragma(warning(push)) \ + __pragma(warning(disable: warnings)) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() \ + __pragma(warning(pop)) +#else +// Not all compilers are MSVC +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + +// Clang on Windows does not understand MSVC's pragma warning. +// We need clang-specific way to disable function deprecation warning. +#ifdef __clang__ +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + _Pragma("clang diagnostic pop") +#else +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + +// Brings in definitions for functions used in the testing::internal::posix +// namespace (read, write, close, chdir, isatty, stat). We do not currently +// use them on Windows Mobile. +#if GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS_MOBILE +# include +# include +# endif +// In order to avoid having to include , use forward declaration +#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) +// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two +// separate (equivalent) structs, instead of using typedef +typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#else +// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. +// This assumption is verified by +// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. +typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#endif +#elif GTEST_OS_XTENSA +#include +// Xtensa toolchains define strcasecmp in the string.h header instead of +// strings.h. string.h is already included. +#else +// This assumes that non-Windows OSes provide unistd.h. For OSes where this +// is not the case, we need to include headers that provide the functions +// mentioned above. +# include +# include +#endif // GTEST_OS_WINDOWS + +#if GTEST_OS_LINUX_ANDROID +// Used to define __ANDROID_API__ matching the target NDK API level. +# include // NOLINT +#endif + +// Defines this to true if and only if Google Test can use POSIX regular +// expressions. +#ifndef GTEST_HAS_POSIX_RE +# if GTEST_OS_LINUX_ANDROID +// On Android, is only available starting with Gingerbread. +# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) +# else +#define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS && !GTEST_OS_XTENSA) +# endif +#endif + +#if GTEST_USES_PCRE +// The appropriate headers have already been included. + +#elif GTEST_HAS_POSIX_RE + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +# include // NOLINT + +# define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +// is not available on Windows. Use our own simple regex +// implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_USES_PCRE + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +# if defined(_MSC_VER) && defined(_CPPUNWIND) +// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__BORLANDC__) +// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +# ifndef _HAS_EXCEPTIONS +# define _HAS_EXCEPTIONS 1 +# endif // _HAS_EXCEPTIONS +# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__clang__) +// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang +// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files, +// there can be cleanups for ObjC exceptions which also need cleanups, even if +// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which +// checks for C++ exceptions starting at clang r206352, but which checked for +// cleanups prior to that. To reliably check for C++ exception availability with +// clang, check for +// __EXCEPTIONS && __has_feature(cxx_exceptions). +# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) +# elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__HP_aCC) +// Exception handling is in effect by default in HP aCC compiler. It has to +// be turned of by +noeh compiler option if desired. +# define GTEST_HAS_EXCEPTIONS 1 +# else +// For other compilers, we assume exceptions are disabled to be +// conservative. +# define GTEST_HAS_EXCEPTIONS 0 +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// Cygwin 1.7 and below doesn't support ::std::wstring. +// Solaris' libc++ doesn't support it either. Android has +// no support for it at least as recent as Froyo (2.2). +#define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + GTEST_OS_HAIKU || GTEST_OS_ESP32 || GTEST_OS_ESP8266 || GTEST_OS_XTENSA)) + +#endif // GTEST_HAS_STD_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +# ifdef _MSC_VER + +#ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled. +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is +// enabled. +# elif defined(__GNUC__) + +# ifdef __GXX_RTTI +// When building against STLport with the Android NDK and with +// -frtti -fno-exceptions, the build fails at link time with undefined +// references to __cxa_bad_typeid. Note sure if STL or toolchain bug, +// so disable RTTI when detected. +# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ + !defined(__EXCEPTIONS) +# define GTEST_HAS_RTTI 0 +# else +# define GTEST_HAS_RTTI 1 +# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS +# else +# define GTEST_HAS_RTTI 0 +# endif // __GXX_RTTI + +// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends +// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the +// first version with C++ support. +# elif defined(__clang__) + +# define GTEST_HAS_RTTI __has_feature(cxx_rtti) + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +# ifdef __RTTI_ALL__ +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +# else + +// For all other compilers, we assume RTTI is enabled. +# define GTEST_HAS_RTTI 1 + +# endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +# include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we make reasonable assumptions about +// which platforms have pthreads support. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \ + GTEST_OS_HAIKU) +#endif // GTEST_HAS_PTHREAD + +#if GTEST_HAS_PTHREAD +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +# include // NOLINT + +// For timespec and nanosleep, used below. +# include // NOLINT +#endif + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +# if GTEST_OS_LINUX && !defined(__ia64__) +# if GTEST_OS_LINUX_ANDROID +// On Android, clone() became available at different API levels for each 32-bit +// architecture. +# if defined(__LP64__) || \ + (defined(__arm__) && __ANDROID_API__ >= 9) || \ + (defined(__mips__) && __ANDROID_API__ >= 12) || \ + (defined(__i386__) && __ANDROID_API__ >= 17) +# define GTEST_HAS_CLONE 1 +# else +# define GTEST_HAS_CLONE 0 +# endif +# else +# define GTEST_HAS_CLONE 1 +# endif +# else +# define GTEST_HAS_CLONE 0 +# endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#ifndef GTEST_HAS_STREAM_REDIRECTION +// By default, we assume that stream redirection is supported on all +// platforms except known mobile ones. +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_XTENSA +# define GTEST_HAS_STREAM_REDIRECTION 0 +# else +# define GTEST_HAS_STREAM_REDIRECTION 1 +# endif // !GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_HAS_STREAM_REDIRECTION + +// Determines whether to support death tests. +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \ + GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \ + GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU) +# define GTEST_HAS_DEATH_TEST 1 +#endif + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, IBM Visual Age, and HP aCC support. +#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) || defined(__HP_aCC) +# define GTEST_HAS_TYPED_TEST 1 +# define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2) + +// Determines whether test results can be streamed to a socket. +#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \ + GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD +# define GTEST_CAN_STREAM_RESULTS_ 1 +#endif + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#elif defined(__clang__) +# if __has_attribute(unused) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +# endif +#endif +#ifndef GTEST_ATTRIBUTE_UNUSED_ +# define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// Use this annotation before a function that takes a printf format string. +#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) +# if defined(__MINGW_PRINTF_FORMAT) +// MinGW has two different printf implementations. Ensure the format macro +// matches the selected implementation. See +// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ + first_to_check))) +# else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +# endif +#else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) +#endif + + +// A macro to disallow copy operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type) \ + type& operator=(type const &) = delete + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ + type(type const&) = delete; \ + type& operator=(type const&) = delete + +// A macro to disallow move operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_MOVE_ASSIGN_(type) \ + type& operator=(type &&) noexcept = delete + +// A macro to disallow move constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_MOVE_AND_ASSIGN_(type) \ + type(type&&) noexcept = delete; \ + type& operator=(type&&) noexcept = delete + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +# define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && !COMPILER_ICC + +// MS C++ compiler emits warning when a conditional expression is compile time +// constant. In some contexts this warning is false positive and needs to be +// suppressed. Use the following two macros in such cases: +// +// GTEST_INTENTIONAL_CONST_COND_PUSH_() +// while (true) { +// GTEST_INTENTIONAL_CONST_COND_POP_() +// } +# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) +# define GTEST_INTENTIONAL_CONST_COND_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +# if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +# define GTEST_HAS_SEH 1 +# else +// Assume no SEH. +# define GTEST_HAS_SEH 0 +# endif + +#endif // GTEST_HAS_SEH + +#ifndef GTEST_IS_THREADSAFE + +#define GTEST_IS_THREADSAFE \ + (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \ + (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \ + GTEST_HAS_PTHREAD) + +#endif // GTEST_IS_THREADSAFE + +// GTEST_API_ qualifies all symbols that must be exported. The definitions below +// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in +// gtest/internal/custom/gtest-port.h +#ifndef GTEST_API_ + +#ifdef _MSC_VER +# if GTEST_LINKED_AS_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllimport) +# elif GTEST_CREATE_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllexport) +# endif +#elif __GNUC__ >= 4 || defined(__clang__) +# define GTEST_API_ __attribute__((visibility ("default"))) +#endif // _MSC_VER + +#endif // GTEST_API_ + +#ifndef GTEST_API_ +# define GTEST_API_ +#endif // GTEST_API_ + +#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE +# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" +#endif // GTEST_DEFAULT_DEATH_TEST_STYLE + +#ifdef __GNUC__ +// Ask the compiler to never inline a given function. +# define GTEST_NO_INLINE_ __attribute__((noinline)) +#else +# define GTEST_NO_INLINE_ +#endif + +// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. +#if !defined(GTEST_HAS_CXXABI_H_) +# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) +# define GTEST_HAS_CXXABI_H_ 1 +# else +# define GTEST_HAS_CXXABI_H_ 0 +# endif +#endif + +// A function level attribute to disable checking for use of uninitialized +// memory when built with MemorySanitizer. +#if defined(__clang__) +# if __has_feature(memory_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ + __attribute__((no_sanitize_memory)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +# endif // __has_feature(memory_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +#endif // __clang__ + +// A function level attribute to disable AddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(address_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ + __attribute__((no_sanitize_address)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +# endif // __has_feature(address_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +#endif // __clang__ + +// A function level attribute to disable HWAddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(hwaddress_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \ + __attribute__((no_sanitize("hwaddress"))) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +# endif // __has_feature(hwaddress_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ +#endif // __clang__ + +// A function level attribute to disable ThreadSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(thread_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ + __attribute__((no_sanitize_thread)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +# endif // __has_feature(thread_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +#endif // __clang__ + +namespace testing { + +class Message; + +// Legacy imports for backwards compatibility. +// New code should use std:: names directly. +using std::get; +using std::make_tuple; +using std::tuple; +using std::tuple_element; +using std::tuple_size; + +namespace internal { + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile +// time expression is true (in new code, use static_assert instead). For +// example, you could use it to verify the size of a static array: +// +// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, +// names_incorrect_size); +// +// The second argument to the macro must be a valid C++ identifier. If the +// expression is false, compiler will issue an error containing this identifier. +#define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines RE. + +#if GTEST_USES_PCRE +// if used, PCRE is injected by custom/gtest-port.h +#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true if and only if regular expression re + // matches the entire str. + // PartialMatch(str, re) returns true if and only if regular expression re + // matches a substring of str (including str itself). + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + const char* pattern_; + bool is_valid_; + +# if GTEST_USES_POSIX_RE + + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). + +# else // GTEST_USES_SIMPLE_RE + + const char* full_pattern_; // For FullMatch(); + +# endif +}; + +#endif // GTEST_USES_PCRE + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, + int line); + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#if !defined(GTEST_LOG_) + +# define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(nullptr); } + +#endif // !defined(GTEST_LOG_) + +#if !defined(GTEST_CHECK_) +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +# define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " +#endif // !defined(GTEST_CHECK_) + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// Transforms "T" into "const T&" according to standard reference collapsing +// rules (this is only needed as a backport for C++98 compilers that do not +// support reference collapsing). Specifically, it transforms: +// +// char ==> const char& +// const char ==> const char& +// char& ==> char& +// const char& ==> const char& +// +// Note that the non-const reference will not have "const" added. This is +// standard, and necessary so that "T" can always bind to "const T&". +template +struct ConstRef { typedef const T& type; }; +template +struct ConstRef { typedef T& type; }; + +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + typename ::testing::internal::ConstRef::type + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Use ImplicitCast_ as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use ImplicitCast_, the compiler checks that +// the cast is safe. Such explicit ImplicitCast_s are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using ImplicitCast_ is the same as for static_cast: +// +// ImplicitCast_(expr) +// +// ImplicitCast_ would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., implicit_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template +inline To ImplicitCast_(To x) { return x; } + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., down_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template // use like this: DownCast_(foo); +inline To DownCast_(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (false) { + GTEST_INTENTIONAL_CONST_COND_POP_() + const To to = nullptr; + ::testing::internal::ImplicitCast_(to); + } + +#if GTEST_HAS_RTTI + // RTTI: debug mode only! + GTEST_CHECK_(f == nullptr || dynamic_cast(f) != nullptr); +#endif + return static_cast(f); +} + +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); +#endif + +#if GTEST_HAS_DOWNCAST_ + return ::down_cast(base); +#elif GTEST_HAS_RTTI + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ std::string GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ std::string GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION +// Returns the size (in bytes) of a file. +GTEST_API_ size_t GetFileSize(FILE* file); + +// Reads the entire content of a file as a string. +GTEST_API_ std::string ReadEntireFile(FILE* file); + +// All command line arguments. +GTEST_API_ std::vector GetArgvs(); + +#if GTEST_HAS_DEATH_TEST + +std::vector GetInjectableArgvs(); +// Deprecated: pass the args vector by value instead. +void SetInjectableArgvs(const std::vector* new_argvs); +void SetInjectableArgvs(const std::vector& new_argvs); +void ClearInjectableArgvs(); + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. +#if GTEST_IS_THREADSAFE +# if GTEST_HAS_PTHREAD +// Sleeps for (roughly) n milliseconds. This function is only for testing +// Google Test's own constructs. Don't use it in user tests, either +// directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, nullptr); +} +# endif // GTEST_HAS_PTHREAD + +# if GTEST_HAS_NOTIFICATION_ +// Notification has already been imported into the namespace. +// Nothing to do here. + +# elif GTEST_HAS_PTHREAD +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); + } + ~Notification() { + pthread_mutex_destroy(&mutex_); + } + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { + pthread_mutex_lock(&mutex_); + notified_ = true; + pthread_mutex_unlock(&mutex_); + } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + for (;;) { + pthread_mutex_lock(&mutex_); + const bool notified = notified_; + pthread_mutex_unlock(&mutex_); + if (notified) + break; + SleepMilliseconds(10); + } + } + + private: + pthread_mutex_t mutex_; + bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +GTEST_API_ void SleepMilliseconds(int n); + +// Provides leak-safe Windows kernel handle ownership. +// Used in death tests and in threading support. +class GTEST_API_ AutoHandle { + public: + // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to + // avoid including in this header file. Including is + // undesirable because it defines a lot of symbols and macros that tend to + // conflict with client code. This assumption is verified by + // WindowsTypesTest.HANDLEIsVoidStar. + typedef void* Handle; + AutoHandle(); + explicit AutoHandle(Handle handle); + + ~AutoHandle(); + + Handle Get() const; + void Reset(); + void Reset(Handle handle); + + private: + // Returns true if and only if the handle is a valid handle object that can be + // closed. + bool IsCloseable() const; + + Handle handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class GTEST_API_ Notification { + public: + Notification(); + void Notify(); + void WaitForNotification(); + + private: + AutoHandle event_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; +# endif // GTEST_HAS_NOTIFICATION_ + +// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD +// defined, but we don't want to use MinGW's pthreads implementation, which +// has conformance problems with some versions of the POSIX standard. +# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return nullptr; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void UserThreadFunc(T); + + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() override { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr)); + finished_ = true; + } + } + + void Run() override { + if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + UserThreadFunc* const func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true if and only if we know that the thread function has + // finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; +# endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || + // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ + +# if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ +// Mutex and ThreadLocal have already been imported into the namespace. +// Nothing to do here. + +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +// Mutex implements mutex on Windows platforms. It is used in conjunction +// with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the +// // end of the current scope. +// +// A static Mutex *must* be defined or declared using one of the following +// macros: +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// (A non-static Mutex is defined/declared in the usual way). +class GTEST_API_ Mutex { + public: + enum MutexType { kStatic = 0, kDynamic = 1 }; + // We rely on kStaticMutex being 0 as it is to what the linker initializes + // type_ in static mutexes. critical_section_ will be initialized lazily + // in ThreadSafeLazyInit(). + enum StaticConstructorSelector { kStaticMutex = 0 }; + + // This constructor intentionally does nothing. It relies on type_ being + // statically initialized to 0 (effectively setting it to kStatic) and on + // ThreadSafeLazyInit() to lazily initialize the rest of the members. + explicit Mutex(StaticConstructorSelector /*dummy*/) {} + + Mutex(); + ~Mutex(); + + void Lock(); + + void Unlock(); + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld(); + + private: + // Initializes owner_thread_id_ and critical_section_ in static mutexes. + void ThreadSafeLazyInit(); + + // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503, + // we assume that 0 is an invalid value for thread IDs. + unsigned int owner_thread_id_; + + // For static mutexes, we rely on these members being initialized to zeros + // by the linker. + MutexType type_; + long critical_section_init_phase_; // NOLINT + GTEST_CRITICAL_SECTION* critical_section_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + Mutex* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Base class for ValueHolder. Allows a caller to hold and delete a value +// without knowing its type. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Provides a way for a thread to send notifications to a ThreadLocal +// regardless of its parameter type. +class ThreadLocalBase { + public: + // Creates a new ValueHolder object holding a default value passed to + // this ThreadLocal's constructor and returns it. It is the caller's + // responsibility not to call this when the ThreadLocal instance already + // has a value on the current thread. + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; + + protected: + ThreadLocalBase() {} + virtual ~ThreadLocalBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); +}; + +// Maps a thread to a set of ThreadLocals that have values instantiated on that +// thread and notifies them when the thread exits. A ThreadLocal instance is +// expected to persist until all threads it has values on have terminated. +class GTEST_API_ ThreadLocalRegistry { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance); + + // Invoked when a ThreadLocal instance is destroyed. + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance); +}; + +class GTEST_API_ ThreadWithParamBase { + public: + void Join(); + + protected: + class Runnable { + public: + virtual ~Runnable() {} + virtual void Run() = 0; + }; + + ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); + virtual ~ThreadWithParamBase(); + + private: + AutoHandle thread_; +}; + +// Helper class for testing Google Test's multi-threading constructs. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void UserThreadFunc(T); + + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) + : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { + } + virtual ~ThreadWithParam() {} + + private: + class RunnableImpl : public Runnable { + public: + RunnableImpl(UserThreadFunc* func, T param) + : func_(func), + param_(param) { + } + virtual ~RunnableImpl() {} + virtual void Run() { + func_(param_); + } + + private: + UserThreadFunc* const func_; + const T param_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); + }; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// Implements thread-local storage on Windows systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// The users of a TheadLocal instance have to make sure that all but one +// threads (including the main one) using that instance have exited before +// destroying it. Otherwise, the per-thread objects managed for them by the +// ThreadLocal instance are not guaranteed to be destroyed on all platforms. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal : public ThreadLocalBase { + public: + ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : default_factory_(new InstanceValueHolderFactory(value)) {} + + ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of T. Can be deleted via its base class without the caller + // knowing the type of T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + ValueHolder() : value_() {} + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + + T* GetOrCreateValue() const { + return static_cast( + ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); + } + + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { + return default_factory_->MakeNewHolder(); + } + + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + ValueHolder* MakeNewHolder() const override { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + ValueHolder* MakeNewHolder() const override { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + + std::unique_ptr default_factory_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# elif GTEST_HAS_PTHREAD + +// MutexBase and Mutex implement mutex on pthreads-based platforms. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + has_owner_ = true; + } + + // Releases this mutex. + void Unlock() { + // Since the lock is being released the owner_ field should no longer be + // considered valid. We don't protect writing to has_owner_ here, as it's + // the caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + has_owner_ = false; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + // has_owner_ indicates whether the owner_ field below contains a valid thread + // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All + // accesses to the owner_ field should be protected by a check of this field. + // An alternative might be to memset() owner_ to all zeros, but there's no + // guarantee that a zero'd pthread_t is necessarily invalid or even different + // from pthread_self(). + bool has_owner_; + pthread_t owner_; // The thread holding the mutex. +}; + +// Forward-declares a static mutex. +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +// The initialization list here does not explicitly initialize each field, +// instead relying on default initialization for the unspecified fields. In +// particular, the owner_ field (a pthread_t) is not explicitly initialized. +// This allows initialization to work whether pthread_t is a scalar or struct. +// The flag -Wmissing-field-initializers must not be specified for this to work. +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr)); + has_owner_ = false; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +template +class GTEST_API_ ThreadLocal { + public: + ThreadLocal() + : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : key_(CreateKey()), + default_factory_(new InstanceValueHolderFactory(value)) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + ValueHolder() : value_() {} + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != nullptr) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = default_factory_->MakeNewHolder(); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + ValueHolder* MakeNewHolder() const override { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + ValueHolder* MakeNewHolder() const override { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + std::unique_ptr default_factory_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ + +#else // GTEST_IS_THREADSAFE + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void Lock() {} + void Unlock() {} + void AssertHeld() const {} +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class GTEST_API_ ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +#endif // GTEST_IS_THREADSAFE + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_SEP_ "\\" +# define GTEST_HAS_ALT_PATH_SEP_ 1 +#else +# define GTEST_PATH_SEP_ "/" +# define GTEST_HAS_ALT_PATH_SEP_ 0 +#endif // GTEST_OS_WINDOWS + +// Utilities for char. + +// isspace(int ch) and friends accept an unsigned char or EOF. char +// may be signed, depending on the compiler (or compiler flags). +// Therefore we need to cast a char to unsigned char before calling +// isspace(), etc. + +inline bool IsAlpha(char ch) { + return isalpha(static_cast(ch)) != 0; +} +inline bool IsAlNum(char ch) { + return isalnum(static_cast(ch)) != 0; +} +inline bool IsDigit(char ch) { + return isdigit(static_cast(ch)) != 0; +} +inline bool IsLower(char ch) { + return islower(static_cast(ch)) != 0; +} +inline bool IsSpace(char ch) { + return isspace(static_cast(ch)) != 0; +} +inline bool IsUpper(char ch) { + return isupper(static_cast(ch)) != 0; +} +inline bool IsXDigit(char ch) { + return isxdigit(static_cast(ch)) != 0; +} +#ifdef __cpp_char8_t +inline bool IsXDigit(char8_t ch) { + return isxdigit(static_cast(ch)) != 0; +} +#endif +inline bool IsXDigit(char16_t ch) { + const unsigned char low_byte = static_cast(ch); + return ch == low_byte && isxdigit(low_byte) != 0; +} +inline bool IsXDigit(char32_t ch) { + const unsigned char low_byte = static_cast(ch); + return ch == low_byte && isxdigit(low_byte) != 0; +} +inline bool IsXDigit(wchar_t ch) { + const unsigned char low_byte = static_cast(ch); + return ch == low_byte && isxdigit(low_byte) != 0; +} + +inline char ToLower(char ch) { + return static_cast(tolower(static_cast(ch))); +} +inline char ToUpper(char ch) { + return static_cast(toupper(static_cast(ch))); +} + +inline std::string StripTrailingSpaces(std::string str) { + std::string::iterator it = str.end(); + while (it != str.begin() && IsSpace(*--it)) + it = str.erase(it); + return str; +} + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +# ifdef __BORLANDC__ +inline int DoIsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +# else // !__BORLANDC__ +# if GTEST_OS_WINDOWS_MOBILE +inline int DoIsATTY(int /* fd */) { return 0; } +# else +inline int DoIsATTY(int fd) { return _isatty(fd); } +# endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +# endif // __BORLANDC__ + +# if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +# else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#elif GTEST_OS_ESP8266 +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int DoIsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { + // stat function not implemented on ESP8266 + return 0; +} +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int DoIsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +inline int IsATTY(int fd) { + // DoIsATTY might change errno (for example ENOTTY in case you redirect stdout + // to a file on Linux), which is unexpected, so save the previous value, and + // restore it after the call. + int savedErrno = errno; + int isAttyValue = DoIsATTY(fd); + errno = savedErrno; + + return isAttyValue; +} + +// Functions deprecated by MSVC 8.0. + +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && \ + !GTEST_OS_WINDOWS_RT && !GTEST_OS_ESP8266 && !GTEST_OS_XTENSA +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW + struct wchar_codecvt : public std::codecvt {}; + std::wstring_convert converter; + std::wstring wide_path = converter.from_bytes(path); + std::wstring wide_mode = converter.from_bytes(mode); + return _wfopen(wide_path.c_str(), wide_mode.c_str()); +#else // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW + return fopen(path, mode); +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \ + GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_XTENSA + // We are on an embedded platform, which has no environment variables. + static_cast(name); // To prevent 'unused argument' warning. + return nullptr; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != nullptr && env[0] != '\0') ? env : nullptr; +#else + return getenv(name); +#endif +} + +GTEST_DISABLE_MSC_DEPRECATED_POP_() + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +[[noreturn]] void Abort(); +#else +[[noreturn]] inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// MSVC "deprecates" snprintf and issues warnings wherever it is used. In +// order to avoid these warnings, we need to use _snprintf or _snprintf_s on +// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate +// function in order to achieve that. We use macro definition here because +// snprintf is a variadic function. +#if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE +// MSVC 2005 and above support variadic macros. +# define GTEST_SNPRINTF_(buffer, size, format, ...) \ + _snprintf_s(buffer, size, size, format, __VA_ARGS__) +#elif defined(_MSC_VER) +// Windows CE does not define _snprintf_s +# define GTEST_SNPRINTF_ _snprintf +#else +# define GTEST_SNPRINTF_ snprintf +#endif + +// The biggest signed integer type the compiler supports. +// +// long long is guaranteed to be at least 64-bits in C++11. +using BiggestInt = long long; // NOLINT + +// The maximum number a BiggestInt can represent. +constexpr BiggestInt kMaxBiggestInt = (std::numeric_limits::max)(); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + using UInt = void; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + using Int = std::int32_t; + using UInt = std::uint32_t; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: + using Int = std::int64_t; + using UInt = std::uint64_t; +}; + +// Integer types of known sizes. +using TimeInMillis = int64_t; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#if !defined(GTEST_FLAG) +# define GTEST_FLAG(name) FLAGS_gtest_##name +#endif // !defined(GTEST_FLAG) + +#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) +# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 +#endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) + +#if !defined(GTEST_DECLARE_bool_) +# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver + +// Macros for declaring flags. +# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +# define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern std::int32_t GTEST_FLAG(name) +# define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::std::string GTEST_FLAG(name) + +// Macros for defining flags. +# define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +# define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ std::int32_t GTEST_FLAG(name) = (default_val) +# define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) + +#endif // !defined(GTEST_DECLARE_bool_) + +// Thread annotations +#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) +# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) +# define GTEST_LOCK_EXCLUDED_(locks) +#endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +GTEST_API_ bool ParseInt32(const Message& src_text, const char* str, + int32_t* value); + +// Parses a bool/int32_t/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ int32_t Int32FromGTestEnv(const char* flag, int32_t default_val); +std::string OutputFlagAlsoCheckEnvVar(); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#if !defined(GTEST_INTERNAL_DEPRECATED) + +// Internal Macro to mark an API deprecated, for googletest usage only +// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or +// GTEST_INTERNAL_DEPRECATED(message) myFunction(); Every usage of +// a deprecated entity will trigger a warning when compiled with +// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler). +// For msvc /W3 option will need to be used +// Note that for 'other' compilers this macro evaluates to nothing to prevent +// compilations errors. +#if defined(_MSC_VER) +#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message)) +#elif defined(__GNUC__) +#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message))) +#else +#define GTEST_INTERNAL_DEPRECATED(message) +#endif + +#endif // !defined(GTEST_INTERNAL_DEPRECATED) + +#if GTEST_HAS_ABSL +// Always use absl::any for UniversalPrinter<> specializations if googletest +// is built with absl support. +#define GTEST_INTERNAL_HAS_ANY 1 +#include "absl/types/any.h" +namespace testing { +namespace internal { +using Any = ::absl::any; +} // namespace internal +} // namespace testing +#else +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::any for UniversalPrinter<> +// specializations. +#define GTEST_INTERNAL_HAS_ANY 1 +#include +namespace testing { +namespace internal { +using Any = ::std::any; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::any is not +// supported. +#endif // __has_include() && __cplusplus >= 201703L +#endif // __has_include +#endif // GTEST_HAS_ABSL + +#if GTEST_HAS_ABSL +// Always use absl::optional for UniversalPrinter<> specializations if +// googletest is built with absl support. +#define GTEST_INTERNAL_HAS_OPTIONAL 1 +#include "absl/types/optional.h" +namespace testing { +namespace internal { +template +using Optional = ::absl::optional; +} // namespace internal +} // namespace testing +#else +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::optional for UniversalPrinter<> +// specializations. +#define GTEST_INTERNAL_HAS_OPTIONAL 1 +#include +namespace testing { +namespace internal { +template +using Optional = ::std::optional; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::optional is not +// supported. +#endif // __has_include() && __cplusplus >= 201703L +#endif // __has_include +#endif // GTEST_HAS_ABSL + +#if GTEST_HAS_ABSL +// Always use absl::string_view for Matcher<> specializations if googletest +// is built with absl support. +# define GTEST_INTERNAL_HAS_STRING_VIEW 1 +#include "absl/strings/string_view.h" +namespace testing { +namespace internal { +using StringView = ::absl::string_view; +} // namespace internal +} // namespace testing +#else +# ifdef __has_include +# if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::string_view for Matcher<> +// specializations. +# define GTEST_INTERNAL_HAS_STRING_VIEW 1 +#include +namespace testing { +namespace internal { +using StringView = ::std::string_view; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::string_view is not +// supported. +# endif // __has_include() && __cplusplus >= 201703L +# endif // __has_include +#endif // GTEST_HAS_ABSL + +#if GTEST_HAS_ABSL +// Always use absl::variant for UniversalPrinter<> specializations if googletest +// is built with absl support. +#define GTEST_INTERNAL_HAS_VARIANT 1 +#include "absl/types/variant.h" +namespace testing { +namespace internal { +template +using Variant = ::absl::variant; +} // namespace internal +} // namespace testing +#else +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::variant for UniversalPrinter<> +// specializations. +#define GTEST_INTERNAL_HAS_VARIANT 1 +#include +namespace testing { +namespace internal { +template +using Variant = ::std::variant; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::variant is not supported. +#endif // __has_include() && __cplusplus >= 201703L +#endif // __has_include +#endif // GTEST_HAS_ABSL + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/gtestsuite/inc/gtest/internal/gtest-string.h b/gtestsuite/inc/gtest/internal/gtest-string.h new file mode 100644 index 000000000..10f774f96 --- /dev/null +++ b/gtestsuite/inc/gtest/internal/gtest-string.h @@ -0,0 +1,175 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by gtest-internal.h. +// It should not be #included by other files. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +# include +#endif + +#include +#include +#include + +#include "gtest/internal/gtest-port.h" + +namespace testing { +namespace internal { + +// String - an abstract class holding static string utilities. +class GTEST_API_ String { + public: + // Static utility methods + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true if and only if they have the same + // content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static std::string ShowWideCString(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true if and only if they have the + // same content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true if and only if + // they have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true if and only if + // they have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Returns true if and only if the given string ends with the given suffix, + // ignoring case. Any string is considered to end with an empty suffix. + static bool EndsWithCaseInsensitive( + const std::string& str, const std::string& suffix); + + // Formats an int value as "%02d". + static std::string FormatIntWidth2(int value); // "%02d" for width == 2 + + // Formats an int value to given width with leading zeros. + static std::string FormatIntWidthN(int value, int width); + + // Formats an int value as "%X". + static std::string FormatHexInt(int value); + + // Formats an int value as "%X". + static std::string FormatHexUInt32(uint32_t value); + + // Formats a byte as "%02X". + static std::string FormatByte(unsigned char value); + + private: + String(); // Not meant to be instantiated. +}; // class String + +// Gets the content of the stringstream's buffer as an std::string. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); + +} // namespace internal +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ diff --git a/gtestsuite/inc/gtest/internal/gtest-type-util.h b/gtestsuite/inc/gtest/internal/gtest-type-util.h new file mode 100644 index 000000000..b87a2e2ca --- /dev/null +++ b/gtestsuite/inc/gtest/internal/gtest-type-util.h @@ -0,0 +1,183 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Type utilities needed for implementing typed and type-parameterized +// tests. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +#include "gtest/internal/gtest-port.h" + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# if GTEST_HAS_CXXABI_H_ +# include +# elif defined(__HP_aCC) +# include +# endif // GTEST_HASH_CXXABI_H_ + +namespace testing { +namespace internal { + +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + +#if GTEST_HAS_RTTI +// GetTypeName(const std::type_info&) returns a human-readable name of type T. +inline std::string GetTypeName(const std::type_info& type) { + const char* const name = type.name(); +#if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +#if GTEST_HAS_CXXABI_H_ + using abi::__cxa_demangle; +#endif // GTEST_HAS_CXXABI_H_ + char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); + const std::string name_str(status == 0 ? readable_name : name); + free(readable_name); + return CanonicalizeForStdLibVersioning(name_str); +#else + return name; +#endif // GTEST_HAS_CXXABI_H_ || __HP_aCC +} +#endif // GTEST_HAS_RTTI + +// GetTypeName() returns a human-readable name of type T if and only if +// RTTI is enabled, otherwise it returns a dummy type name. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +std::string GetTypeName() { +#if GTEST_HAS_RTTI + return GetTypeName(typeid(T)); +#else + return ""; +#endif // GTEST_HAS_RTTI +} + +// A unique type indicating an empty node +struct None {}; + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +template +struct Templates { + using Head = TemplateSel; + using Tail = Templates; +}; + +template +struct Templates { + using Head = TemplateSel; + using Tail = None; +}; + +// Tuple-like type lists +template +struct Types { + using Head = Head_; + using Tail = Types; +}; + +template +struct Types { + using Head = Head_; + using Tail = None; +}; + +// Helper metafunctions to tell apart a single type from types +// generated by ::testing::Types +template +struct ProxyTypeList { + using type = Types; +}; + +template +struct is_proxy_type_list : std::false_type {}; + +template +struct is_proxy_type_list> : std::true_type {}; + +// Generator which conditionally creates type lists. +// It recognizes if a requested type list should be created +// and prevents creating a new type list nested within another one. +template +struct GenerateTypeList { + private: + using proxy = typename std::conditional::value, T, + ProxyTypeList>::type; + + public: + using type = typename proxy::type; +}; + +} // namespace internal + +template +using Types = internal::ProxyTypeList; + +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ diff --git a/gtestsuite/input.general b/gtestsuite/input.general new file mode 100644 index 000000000..8265c7cca --- /dev/null +++ b/gtestsuite/input.general @@ -0,0 +1,63 @@ +# ---------------------------------------------------------------------- +# +# input.general +# BLIS GtestSuite +# +# This file contains input values that control how BLIS operations are +# tested. Comments explain the purpose of each parameter as well as +# accepted values. +# + +1 # Number of repeats per experiment (best result is reported) +rc # Matrix storage scheme(s) to test: + # 'c' = col-major storage; 'g' = general stride storage; + # 'r' = row-major storage +cj # Vector storage scheme(s) to test: + # 'c' = colvec / unit stride; 'j' = colvec / non-unit stride; + # 'r' = rowvec / unit stride; 'i' = rowvec / non-unit stride +0 # Test all combinations of storage schemes? +1 # Perform all tests with alignment? + # '0' = do NOT align buffers/ldims; '1' = align buffers/ldims +0 # Randomize vectors and matrices using: + # '0' = real values on [-1,1]; + # '1' = powers of 2 in narrow precision range +32 # General stride spacing (for cases when testing general stride) +sdcz # Datatype(s) to test: + # 's' = single real; 'c' = single complex; + # 'd' = double real; 'z' = double complex +0 # Test gemm with mixed-domain operands? +0 # Test gemm with mixed-precision operands? +10 # Problem size: first to test +100 # Problem size: maximum to test +10 # Problem size: increment between experiments + # Complex level-3 implementations to test: +0 # 3mh ('1' = enable; '0' = disable) +0 # 3m1 ('1' = enable; '0' = disable) +0 # 4mh ('1' = enable; '0' = disable) +0 # 4m1b ('1' = enable; '0' = disable) +0 # 4m1a ('1' = enable; '0' = disable) +0 # 1m ('1' = enable; '0' = disable) +1 # native ('1' = enable; '0' = disable) +1 # Simulate application-level threading: + # '1' = disable / use one testsuite thread; + # 'n' = enable and use n testsuite threads +1 # Error-checking level: + # '0' = disable error checking; '1' = full error checking +i # Reaction to test failure: + # 'i' = ignore; 's' = sleep() and continue; 'a' = abort +0 # Output results in matlab/octave format? ('1' = yes; '0' = no) +0 # Output results to stdout AND files? ('1' = yes; '0' = no) +0 # api : '0' = BLIS / '1' = CBLAS / '2' = BLAS +0 # m/n/k : '0' = Values where m=n=k / '1' = Multiple combinations of m/n/k +0 # alpha/beta : '0' = Fixed value / '1' = Multiple values with combination +0 # Integer bit-exactness testing + # '0' = 's/d/c/z' datatype testing + # '1' = Integer bit-exactness testing +0 # '0' = Print only fail cases + # '1' = Print pass and fail cases +0 # Bit-Reproducibility + # '0' = Disable + # '1' = Enable +r # lpgemm memformat reorder + # 'p' = No reorder + # 'r' = reorder diff --git a/gtestsuite/input.operations b/gtestsuite/input.operations new file mode 100644 index 000000000..d7cfe5253 --- /dev/null +++ b/gtestsuite/input.operations @@ -0,0 +1,321 @@ +# -------------------------------------------------------------------------- +# +# input.operations +# BLIS GtestSuite +# +# This file contains input values that control which BLIS operations are +# tested as well as how those test runs are parameterized. We will now +# describe how each section or line type may be edited. +# +# ENABLING/DISABLING INDIVIDUAL OPERATION TESTS +# Given that an operation's section override switch is set to 1 +# (enabled), whether or not that operation will get tested is +# determined by its local switch. For example, if the level-1v section +# override is set to 1, and there is a 1 on the line marked "addv", +# then the addv operation will be tested. Similarly, a 0 would cause +# addv to not be tested. +# +# CHANGING PROBLEM SIZE/SHAPES TESTED +# The problem sizes tested by an operation are determined by the +# dimension specifiers on the line marked "dimensions: ". +# If, for example, contains two dimension labels (e.g. +# "m n"), then the line should begin with two dimension specifiers. +# Dimension specifiers of -1 cause the corresponding dimension to be +# bound to the problem size, which is determined by values set in +# input.general. Positive values cause the corresponding dimension to +# be fixed to that value and held constant. +# +# Examples of dimension specifiers (where the dimensions are m and n): +# +# -1 -1 Dimensions m and n grow with problem size (resulting in +# square matrices). +# -1 150 Dimension m grows with problem size and n is fixed at +# 150. +# -1 -2 Dimension m grows with problem size and n grows +# proportional to half the problem size. +# +# CHANGING PARAMTER COMBINATIONS TESTED +# The parameter combinations tested by an operation are determined by +# the parameter specifier characters on the line marked "parameters: +# ". If, for example, contains two +# parameter labels (e.g. "transa conjx"), then the line should contain +# two parameter specifier characters. The '?' specifier character +# serves as a wildcard--it causes all possible values of that parameter +# to be tested. A character such as 'n' or 't' causes only that value +# to be tested. +# +# Examples of parameter specifiers (where the parameters are transa +# and conjx): +# +# ?? All combinations of the transa and conjx parameters are +# tested: nn, nc, tn, tc, cn, cc, hn, hc. +# ?n conjx is fixed to "no conjugate" but transa is allowed +# to vary: nn, tn, cn, hn. +# hc Only the case where transa is "Hermitian-transpose" and +# conjx is "conjugate" is tested. +# +# Here is a full list of the parameter types used by the various BLIS +# operations along with their possible character encodings: +# +# side: l,r left, right +# uplo: l,u lower, upper +# trans: n,t,c,h no transpose, transpose, conjugate, Hermitian- +# transpose (i.e. conjugate-transpose) +# conj: n,c no conjugate, conjugate +# diag: n,u non-unit diagonal, unit diagonal +# +# -------------------------------------------------------------------------- + +# --- Utility -------------------------------------------------------------- + +0 # randv +-1 # dimensions: m + +0 # randm +-1 -1 # dimensions: m n + + +# --- Level-1v ------------------------------------------------------------- + +0 # addv +-1 # dimensions: m +? # parameters: conjx + +0 # amaxv +-1 # dimensions: m + +0 # axpbyv +-1 # dimensions: m +? # parameters: conjx + +0 # axpyv +-1 # dimensions: m +? # parameters: conjx + +0 # copyv +-1 # dimensions: m +? # parameters: conjx + +0 # dotv +-1 # dimensions: m +?? # parameters: conjx conjy + +0 # dotxv +-1 # dimensions: m +?? # parameters: conjx conjy + +0 # normfv +-1 # dimensions: m + +0 # scalv +-1 # dimensions: m +? # parameters: conjbeta + +0 # scal2v +-1 # dimensions: m +? # parameters: conjx + +0 # setv +-1 # dimensions: m + +0 # subv +-1 # dimensions: m +? # parameters: conjx + +0 # xpbyv +-1 # dimensions: m +? # parameters: conjx + + +# --- Level-1m ------------------------------------------------------------- + +0 # addm +-1 -2 # dimensions: m n +? # parameters: transa + +0 # axpym +-1 -1 # dimensions: m n +? # parameters: transa + +0 # copym +-1 -2 # dimensions: m n +? # parameters: transa + +0 # normfm +-1 -2 # dimensions: m n + +0 # scalm +-1 -2 # dimensions: m n +? # parameters: conjbeta + +0 # scal2m +-1 -2 # dimensions: m n +? # parameters: transa + +0 # setm +-1 -2 # dimensions: m n + +0 # subm +-1 -2 # dimensions: m n +? # parameters: transa + +0 # xpbym +-1 -1 # dimensions: m n +? # parameters: transa + + +# --- Level-1f kernels ----------------------------------------------------- + +0 # axpy2v +-1 # dimensions: m +?? # parameters: conjx conjy + +0 # dotaxpyv +-1 # dimensions: m +??? # parameters: conjxt conjx conjy + +0 # axpyf +-1 # dimensions: m +?? # parameters: conja conjx + +0 # dotxf +-1 # dimensions: m +?? # parameters: conjat conjx + +0 # dotxaxpyf +-1 # dimensions: m +???? # parameters: conjat conja conjw conjx + + +# --- Level-2 -------------------------------------------------------------- + +0 # gemv +-1 -2 # dimensions: m n +?? # parameters: transa conjx + +0 # ger +-1 -2 # dimensions: m n +?? # parameters: conjx conjy + +0 # hemv +-1 # dimensions: m +??? # parameters: uploa conja conjx + +0 # her +-1 # dimensions: m +?? # parameters: uploc conjx + +0 # her2 +-1 # dimensions: m +??? # parameters: uploc conjx conjy + +0 # symv +-1 # dimensions: m +??? # parameters: uploa conja conjx + +0 # syr +-1 # dimensions: m +?? # parameters: uploc conjx + +0 # syr2 +-1 # dimensions: m +??? # parameters: uploc conjx conjy + +0 # trmv +-1 # dimensions: m +??? # parameters: uploa transa diaga + +0 # trsv +-1 # dimensions: m +??? # parameters: uploa transa diaga + + +# --- Level-3 micro-kernels ------------------------------------------------ + +0 # gemm +-1 # dimensions: k + +0 # trsm +? # parameters: uploa + +0 # gemmtrsm +-1 # dimensions: k +? # parameters: uploa + + +# --- Level-3 -------------------------------------------------------------- + +1 # gemm +-1 -1 -1 # dimensions: m n k +?? # parameters: transa transb + +0 # gemmt +-1 -1 # dimensions: m k +??? # parameters: uploc transa transb + +0 # hemm +-1 -1 # dimensions: m n +?? # parameters: side uploa + +0 # herk +-1 -1 # dimensions: m k +?? # parameters: uploc trans + +0 # her2k +-1 -1 # dimensions: m k +?? # parameters: uploc trans + +0 # symm +-1 -1 # dimensions: m n +?? # parameters: side uploa + +0 # syrk +-1 -1 # dimensions: m k +?? # parameters: uploc trans + +0 # syr2k +-1 -1 # dimensions: m k +?? # parameters: uploc trans + +0 # trmm +-1 -1 # dimensions: m n +???? # parameters: side uploa transa diaga + +0 # trmm3 +-1 -1 # dimensions: m n +????? # parameters: side uploa transa diaga transb + +0 # trsm +-1 -1 # dimensions: m n +???? # parameters: side uploa transa diaga + +# --- lpgemm -------------------------------------------------------------- + +0 # gemm_u8s8s32os32 +-1 -1 -1 # dimensions: m n k +nn # parameters: transa transb + +0 # gemm_u8s8s32os8 +-1 -1 -1 # dimensions: m n k +nn # parameters: transa transb + +0 # gemm_f32f32f32of32 +-1 -1 -1 # dimensions: m n k +nn # parameters: transa transb + +0 # gemm_u8s8s16os16 +-1 -1 -1 # dimensions: m n k +nn # parameters: transa transb + +0 # gemm_u8s8s16os8 +-1 -1 -1 # dimensions: m n k +nn # parameters: transa transb + +0 # gemm_bf16bf16f32of32 +-1 -1 -1 # dimensions: m n k +nn # parameters: transa transb + +0 # gemm_bf16bf16f32obf16 +-1 -1 -1 # dimensions: m n k +nn # parameters: transa transb + diff --git a/gtestsuite/inputfile.txt b/gtestsuite/inputfile.txt new file mode 100644 index 000000000..c3f727903 --- /dev/null +++ b/gtestsuite/inputfile.txt @@ -0,0 +1,3 @@ +dgemm_ D N N 1000 3000 2000 0.900000 0.000000 4000 5000 -1.100000 0.000000 6000 +dgemv_ D N 1 14 -1.000000 0.000000 10000 1 1.000000 0.000000 1 +sgemm_ S N N 7 1026 1026 0.900000 0.000000 1026 1026 -1.100000 0.000000 1026 \ No newline at end of file diff --git a/gtestsuite/lib/libgtest.a b/gtestsuite/lib/libgtest.a new file mode 100644 index 000000000..17e3f5c2c Binary files /dev/null and b/gtestsuite/lib/libgtest.a differ diff --git a/gtestsuite/src/blis_api.cpp b/gtestsuite/src/blis_api.cpp new file mode 100644 index 000000000..487b67aff --- /dev/null +++ b/gtestsuite/src/blis_api.cpp @@ -0,0 +1,3583 @@ +#include "blis_utils.h" +#include "blis_inpfile.h" +#include "blis_api.h" + +/*****************************Utility Operations******************************/ +void* libblis_test_randv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + unsigned int pci = 0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_randv( params, iface, params->dc_str[dci], + params->sc_str[sci], &m); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_randm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + unsigned int pci = 0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_randm( params, iface, params->dc_str[dci], + params->sc_str[sci], &mn); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} +/********************* End Of Utility Operations *****************************/ +/* */ +/*****************************Level-1V Operations******************************/ +void* libblis_test_addv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_addv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_amaxv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_amaxv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_axpbyv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_axpbyv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_axpyv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_axpyv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_copyv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_copyv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_dotv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_dotv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_dotxv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_dotxv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_normfv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_normfv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_scal2v_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_scal2v( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_scalv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_scalv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_setv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_setv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_subv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_subv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} +/********************* End Of Level-1V Operations *****************************/ +/* */ +/*****************************Level-1F Operations******************************/ +void* libblis_test_xpbyv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_xpbyv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_axpy2v_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_axpy2v( params, iface, + params->dc_str[dci], params->pc_str[pci], + params->sc_str[sci], &m, params->alpha[a], + params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_dotaxpyv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_dotaxpyv( params, iface, + params->dc_str[dci], params->pc_str[pci], + params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_axpyf_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_axpyf( params, op, iface, + params->dc_str[dci], params->pc_str[pci], + params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_dotxf_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_dotxf( params, op, iface, + params->dc_str[dci], params->pc_str[pci], + params->sc_str[sci], &m, params->alpha[a], + params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_dotxaxpyf_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_dotxaxpyf( params, op, iface, + params->dc_str[dci], params->pc_str[pci], + params->sc_str[sci], &m, params->alpha[a], + params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} +/********************* End Of Level-1F Operations *****************************/ +/* */ +/*****************************Level-1M Operations******************************/ +void* libblis_test_addm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_addm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_axpym_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_axpym( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a] ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_copym_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_copym( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_normfm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_normfm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_scal2m_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_scal2m( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_scalm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_scalm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_setm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_setm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_subm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_subm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn ); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_xpbym_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_xpbym( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} +/********************* End Of Level-1M Operations *****************************/ +/* */ +/*****************************Level-2 Operations*******************************/ +void* libblis_test_gemv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_ger_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_ger( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_hemv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_hemv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_her_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_her( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_her2_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_her2( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_symv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_symv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_syr_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_syr( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_syr2_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_syr2( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_trmv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_trmv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_trsv_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t m; + double resid = 0.0; + + if( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + m = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_trsv( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &m, params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &m, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} +/********************* End Of Level-2 Operations *****************************/ +/* */ +/*****************************Level-3 Operations******************************/ +void* libblis_test_gemm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mnk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mnk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mnk, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mnk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_gemmt_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t nk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + nk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemmt( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &nk, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &nk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_hemm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_hemm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_herk_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t nk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + nk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_herk( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &nk, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &nk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_her2k_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_her2k( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_symm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_symm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_syrk_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t nk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + nk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_syrk( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &nk, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &nk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_syr2k_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_syr2k( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_trmm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_trmm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_trmm3_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_trmm3( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_trsm_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + iface_t iface = tdata->iface; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mn; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mn = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested datatypes. + for ( unsigned int dci = 0; dci < params->n_dt_combos; ++dci ) { + unsigned int n = params->indn[dci]; + // Loop over induced methods (or just BLIS_NAT). + for( unsigned int ind = 0 ; ind < n ; ++ind) { + mt = ind_enable_get_str(params, dci, ind, op); + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_trsm( params, iface, params->dc_str[dci], + params->pc_str[pci], params->sc_str[sci], &mn, + params->alpha[a]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[dci], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, + mt, dci, pci, sci, buffer); + + displayProps(buffer, params, op, &mn, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} +/********************* End Of Level-3 Operations *****************************/ +/* */ +/*****************************LPGEMM Operations ******************************/ +void* libblis_test_gemm_u8s8s32os32_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mnk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + params->dc_str[0][0] = 's'; + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mnk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemm_u8s8s32os32( params, params->pc_str[pci], + params->sc_str[sci], &mnk, params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + 0, pci, sci, buffer); + + displayProps(buffer, params, op, &mnk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_gemm_u8s8s32os8_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mnk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + params->dc_str[0][0] = 's'; + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mnk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemm_u8s8s32os8( params, params->pc_str[pci], + params->sc_str[sci], &mnk, params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + 0, pci, sci, buffer); + + displayProps(buffer, params, op, &mnk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_gemm_f32f32f32of32_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mnk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + params->dc_str[0][0] = 's'; + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mnk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemm_f32f32f32of32( params, params->pc_str[pci], + params->sc_str[sci], &mnk, params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + 0, pci, sci, buffer); + + displayProps(buffer, params, op, &mnk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_gemm_u8s8s16os8_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mnk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + params->dc_str[0][0] = 's'; + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mnk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemm_u8s8s16os8( params, params->pc_str[pci], + params->sc_str[sci], &mnk, params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + 0, pci, sci, buffer); + + displayProps(buffer, params, op, &mnk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_gemm_u8s8s16os16_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mnk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + params->dc_str[0][0] = 's'; + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mnk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemm_u8s8s16os16( params, params->pc_str[pci], + params->sc_str[sci], &mnk, params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + 0, pci, sci, buffer); + + displayProps(buffer, params, op, &mnk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_gemm_bf16bf16f32obf16_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mnk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + params->dc_str[0][0] = 's'; + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mnk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemm_bf16bf16f32obf16( params, params->pc_str[pci], + params->sc_str[sci], &mnk, params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + 0, pci, sci, buffer); + + displayProps(buffer, params, op, &mnk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +void* libblis_test_gemm_bf16bf16f32of32_thread_entry( void* tdata_void ) { + thread_data_t* tdata = (thread_data_t*)tdata_void; + test_params_t* params = tdata->params; + test_op_t* op = tdata->op; + const char* op_str = tdata->str; + printres_t* pfr = tdata->pfr; + ind_t mt = BLIS_NAT; + char label_str[128]; + tensor_t mnk; + double resid = 0.0; + + if ( tdata->id == 0 ) { + libblis_test_build_col_labels_string( params, op, label_str ); + libblis_test_fprintf( stdout, "\n%s\n", label_str ); + } + + params->dc_str[0][0] = 's'; + tensor_t *dim = params->dim; + unsigned int ndim = params->ndim; + + // Loop over the requested problem sizes. + for(unsigned int i = 0 ; i < ndim ; i++) { + mnk = dim[i]; + // Loop over the requested storage schemes. + for ( unsigned int sci = 0; sci < params->n_store_combos; ++sci ) { + // Loop over the requested parameter combinations. + for ( unsigned int pci = 0; pci < params->n_param_combos; ++pci ) { + // Loop over the alpha values. + for ( unsigned int a = 0; a < params->nab; ++a ) { + // Loop over the beta values. + for ( unsigned int b = 0; b < params->nab; ++b ) { + if ( tdata->xc % tdata->nt != tdata->id ) { + tdata->xc++; + continue; + } + resid = libblis_test_op_gemm_bf16bf16f32of32( params, params->pc_str[pci], + params->sc_str[sci], &mnk, params->alpha[a], params->beta[b]); + + pfr->tcnt++; + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, + 0, pci, sci, buffer); + + displayProps(buffer, params, op, &mnk, resid, res_str, pfr); + + tdata->xc += 1; + } + } + } + } + } + + // Wait for all other threads so that the output stays organized. + bli_pthread_barrier_wait( tdata->barrier ); + + return 0; +} + +/*************************** End Of Operations *******************************/ +/* END OF OPERATIONS */ +/*****************************************************************************/ \ No newline at end of file diff --git a/gtestsuite/src/blis_api.h b/gtestsuite/src/blis_api.h new file mode 100644 index 000000000..f7b860f72 --- /dev/null +++ b/gtestsuite/src/blis_api.h @@ -0,0 +1,737 @@ +#ifndef BLIS_API_H +#define BLIS_API_H + +#include "blis_utils.h" +#include "blis_inpfile.h" + +char* libblis_test_get_result + ( + double resid, + const thresh_t* thresh, + char* dc_str, + test_params_t* params + ); + +void fill_string_with_n_spaces( char* str, unsigned int n_spaces ); + +void libblis_test_build_function_string + ( + char* prefix_str, + opid_t opid, + ind_t method, + char* ind_str, + const char* op_str, + unsigned int is_mixed_dt, + char* dc_str, + unsigned int n_param_combos, + char* pc_str, + char* sc_str, + char* funcname_str + ); + +void libblis_test_build_dims_string(test_op_t* op, tensor_t* dim, char* dims_str); + +static char* libblis_test_result( double resid, const thresh_t* thresh, + char* dc_str, test_params_t* params ) { + char* r_val; + return r_val = libblis_test_get_result ( resid, thresh, dc_str, params ); +} + +static void libblis_build_function_string( test_params_t* params, + opid_t opid, const char *op_str, ind_t method, unsigned int dci, + unsigned int pci, unsigned int sci, char* fucnptr ) { + + char* ind_str = NULL; + char* str = NULL; + if( params->api == API_CBLAS ) + str = (char*)CBLAS_FILEDATA_PREFIX_STR; + else if( params->api == API_BLAS ) + str = (char*)BLAS_FILEDATA_PREFIX_STR; + else + str = (char*)BLIS_FILEDATA_PREFIX_STR; + + if ( method != BLIS_NAT ) { + ind_str = bli_ind_get_impl_string( method ); + } + + // Build a string unique to the operation, datatype combo, + // parameter combo, and storage combo being tested. + libblis_test_build_function_string( str, + opid, method, ind_str, op_str, params->is_mixed_dt, + params->dc_str[dci], params->n_param_combos, params->pc_str[pci], + params->sc_str[sci], fucnptr ); +} + +static void displayProps( const char* fucnptr, test_params_t* prms, test_op_t* op, + tensor_t* dim, double& resid, char *ps, printres_t *ptr) +{ + char blank_str[32]; + char dims_str[64]; + string sas = ps ; + string sfs = BLIS_TEST_FAIL_STRING ; + string sos = BLIS_TEST_OVERFLOW_STRING; + string sus = BLIS_TEST_UNDERFLOW_STRING; + string sps = BLIS_TEST_PASS_STRING; + string sws = BLIS_TEST_WARN_STRING; + + // Compute the number of spaces we have left to fill given + // length of our operation's name. + unsigned int n_spaces = MAX_FUNC_STRING_LENGTH - strlen( fucnptr ); + fill_string_with_n_spaces( blank_str, n_spaces ); + + // Print all dimensions to a single string. + libblis_test_build_dims_string( op, dim, dims_str ); + +/* if(( prms->passflag && ( strcmp(ps, BLIS_TEST_FAIL_STRING) != 0 )) || + ( prms->oruflw && (( strcmp(ps, BLIS_TEST_OVERFLOW_STRING) != 0 ) || + ( strcmp(ps, BLIS_TEST_UNDERFLOW_STRING) != 0 ))))*/ + if( prms->passflag && (( sas == sps) || ( sas == sws)) ) + { + fprintf( stdout, + "%s%s %s %8.2le %s\n", + fucnptr, blank_str, + dims_str, resid, + ps ); + } + +/* if(( strcmp(ps, BLIS_TEST_FAIL_STRING) == 0 ) || + ( prms->oruflw && (( strcmp(ps, BLIS_TEST_OVERFLOW_STRING) == 0 ) || + ( strcmp(ps, BLIS_TEST_UNDERFLOW_STRING) == 0 ))))*/ + if(( sas == sfs) || ( prms->oruflw && (( sas == sos) || ( sas == sus)))) + { + fprintf( stdout, + "%s%s %s %8.2le %s\n", + fucnptr, blank_str, + dims_str, resid, + ps ); + + ptr->cntf++; + } +} + +double libblis_test_op_randv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_randm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_addv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_amaxv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_axpbyv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_axpyv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_copyv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_dotv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_dotxv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_normfv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_scal2v + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_scalv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_setv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_xpbyv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_subv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_axpy2v + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_dotaxpyv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_axpyf + ( + test_params_t* params, + test_op_t* op, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_dotxf + ( + test_params_t* params, + test_op_t* op, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_dotxaxpyf + ( + test_params_t* params, + test_op_t* op, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_addm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_axpym + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_copym + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_normfm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_scal2m + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_scalm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_setm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_subm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim + ); + +double libblis_test_op_xpbym + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_gemv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_ger + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_hemv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_her + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_her2 + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_symv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_syr + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_syr2 + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_trmv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_trsv + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_gemm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_gemmt + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_hemm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_herk + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_her2k + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_symm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_syrk + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_syr2k + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_trmm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_trmm3 + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_trsm + ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha + ); + +double libblis_test_op_gemm_u8s8s32os32 + ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_gemm_u8s8s32os8 + ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_gemm_f32f32f32of32 + ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_gemm_u8s8s16os8 + ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_gemm_u8s8s16os16 + ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_gemm_bf16bf16f32obf16 + ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +double libblis_test_op_gemm_bf16bf16f32of32 + ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha, + atom_t beta + ); + +#endif // BLIS_API_H + diff --git a/gtestsuite/src/blis_inpfile.cpp b/gtestsuite/src/blis_inpfile.cpp new file mode 100644 index 000000000..511370f16 --- /dev/null +++ b/gtestsuite/src/blis_inpfile.cpp @@ -0,0 +1,3651 @@ +#include "blis_utils.h" +#include "blis_api.h" +#include "blis_inpfile.h" + +int libblis_test_read_randv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %ld \n", + api_name, &dt, &m) == 3) { + + params->sc_str[0][0] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "randv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_randv( params, iface, params->dc_str[0], + params->sc_str[0], &t); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_randm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %ld %ld\n", + api_name, &dt, &m, &n) == 4) { + + params->sc_str[0][0] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "randm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_randm( params, iface, params->dc_str[0], params->sc_str[0], &t); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_addv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld\n", + api_name, &dt, &transx, &m ) == 4) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "addv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_addv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_amaxv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + + // Variables extracted from the logs which are used by bench + char stor_scheme; + inc_t incx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %ld %ld \n", api_name, &dt, &m, &incx) == 4) + { + params->sc_str[0][0] = stor_scheme; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "amaxv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_amaxv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t ); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_axpbyv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + inc_t incx, incy; + double alpha_r, alpha_i, beta_r, beta_i; + + if(sscanf(str, "%s %c %ld %lf %lf %ld %lf %lf %ld\n", + api_name, &dt, &m, &alpha_r, &alpha_i, &incx, + &beta_r, &beta_i, &incy ) == 9 ){ + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + } + + double resid = 0.0; + const char* op_str = "axpbyv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_axpbyv( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_axpyv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, conjx = 'n'; + stor_scheme = 'c'; + inc_t incx, incy; + double alpha_r, alpha_i; + + if(sscanf(str, "%s %c %ld %lf %lf %ld %ld \n", + api_name, &dt, &m, &alpha_r, &alpha_i, &incx, &incy ) == 7) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(conjx) ){ + params->pc_str[0][0] = tolower(conjx); + } else { + params->pc_str[0][0] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + + params->dim[0].m = m; + params->dim[0].n = 0; + params->dim[0].k = 0; + } + + double resid = 0.0; + const char* op_str = "axpyv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_axpyv( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_copyv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + inc_t incx, incy; + + if(sscanf(str, "%s %c %ld %ld %ld\n", + api_name, &dt, &m, &incx, &incy) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = 0; + params->dim[0].k = 0; + } + + double resid = 0.0; + const char* op_str = "copyv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_copyv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t ); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_dotv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + inc_t incx, incy; + + if(sscanf(str, "%s %c %ld %ld %ld\n", + api_name, &dt, &m, &incx, &incy) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + params->pc_str[0][0] = 'n'; + params->pc_str[0][1] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "dotv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_dotv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t ); + + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_dotxv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, conjx, conjy; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %ld\n", + api_name, &dt, &conjx, &conjy, &m) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(conjx) ){ + params->pc_str[0][0] = tolower(conjx); + } else { + params->pc_str[0][0] = conjx; + } + + if (isalpha(conjy) ){ + params->pc_str[0][1] = tolower(conjy); + } else { + params->pc_str[0][1] = conjy; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "dotxv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_dotxv( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_normfv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %ld\n", + api_name, &dt, &m) == 3) { + + params->sc_str[0][0] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "normfv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_normfv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t ); + + char* res_str = libblis_test_result (resid, thresh, + params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_scal2v_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld \n", + api_name, &dt, &transx, &m ) == 4) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "scal2v"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_scal2v( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params,op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_scalv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + double alpha_r, alpha_i; + inc_t incx; + + if(sscanf(str, "%s %c %lf %lf %ld %ld\n", + api_name, &dt, &alpha_r, &alpha_i, &m, &incx) == 6){ + + params->sc_str[0][0] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + } + + double resid = 0.0; + const char* op_str = "scalv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_scalv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_setv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %ld \n", + api_name, &dt, &m) == 3) { + + params->sc_str[0][0] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "setv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_setv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t ); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_subv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld\n", + api_name, &dt, &transx, &m ) == 4) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "subv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_subv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t ); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_xpbyv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + char transx; + + if(sscanf(str, "%s %c %c %ld\n", + api_name, &dt, &transx, &m) == 4){ + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "xpbyv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_xpbyv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_axpyf_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, conja, conjx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %ld\n", + api_name, &dt, &conja, &conjx, &m ) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(conja) ){ + params->pc_str[0][0] = tolower(conja); + } else { + params->pc_str[0][0] = conja; + } + + if (isalpha(conjx) ){ + params->pc_str[0][1] = tolower(conjx); + } else { + params->pc_str[0][1] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "axpyf"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_axpyf( params, op, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_axpy2v_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, conjx, conjy; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %ld\n", + api_name, &dt, &conjx, &conjy, &m ) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(conjx) ){ + params->pc_str[0][0] = tolower(conjx); + } else { + params->pc_str[0][0] = conjx; + } + + if (isalpha(conjy) ){ + params->pc_str[0][1] = tolower(conjy); + } else { + params->pc_str[0][1] = conjy; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "axpy2v"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_axpy2v( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_dotxf_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, conjat, conjx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %ld\n", + api_name, &dt, &conjat, &conjx, &m) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(conjat) ){ + params->pc_str[0][0] = tolower(conjat); + } else { + params->pc_str[0][0] = conjat; + } + + if (isalpha(conjx) ){ + params->pc_str[0][1] = tolower(conjx); + } else { + params->pc_str[0][1] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "dotxf"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_dotxf( params, op, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_dotaxpyv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, conjxt, conjx, conjy; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %c %ld\n", + api_name, &dt, &conjxt, &conjx, &conjy, &m) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(conjxt) ){ + params->pc_str[0][0] = tolower(conjxt); + } else { + params->pc_str[0][0] = conjxt; + } + + if (isalpha(conjx) ){ + params->pc_str[0][1] = tolower(conjx); + } else { + params->pc_str[0][1] = conjx; + } + + if (isalpha(conjy) ){ + params->pc_str[0][1] = tolower(conjy); + } else { + params->pc_str[0][1] = conjy; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "dotaxpyv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_dotaxpyv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_dotxaxpyf_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, conjat, conja, conjw, conjx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %c %c %ld\n", + api_name, &dt, &conjat, &conja, &conjw, &conjx, &m) == 7) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + params->sc_str[0][3] = stor_scheme; + + if (isalpha(conjat) ){ + params->pc_str[0][0] = tolower(conjat); + } else { + params->pc_str[0][0] = conjat; + } + + if (isalpha(conja) ){ + params->pc_str[0][1] = tolower(conja); + } else { + params->pc_str[0][1] = conja; + } + + if (isalpha(conjw) ){ + params->pc_str[0][2] = tolower(conjw); + } else { + params->pc_str[0][2] = conjw; + } + + if (isalpha(conjx) ){ + params->pc_str[0][3] = tolower(conjx); + } else { + params->pc_str[0][3] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "dotxaxpyf"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_dotxaxpyf( params, op, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_addm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld %ld\n", + api_name, &dt, &transx, &m, &n ) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "addm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_addm( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t ); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_axpym_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld %ld\n", + api_name, &dt, &transx, &m, &n ) == 5) { + + params->sc_str[0][0] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "axpym"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_axpym( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_copym_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + + if(sscanf(str, "%s %c %c %ld %ld\n", + api_name, &dt, &transx, &m, &n ) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "copym"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_copym( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_normfm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m,n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %ld %ld\n", + api_name, &dt, &m, &n) == 4) { + + params->sc_str[0][0] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "normfm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_normfm( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_scal2m_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld %ld\n", + api_name, &dt, &transx, &m, &n ) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "scal2m"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_scal2m( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_scalm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld %ld\n", + api_name, &dt, &transx, &m, &n ) == 5) { + + params->sc_str[0][0] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "scalm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_scalm( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_setm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %ld %ld\n", + api_name, &dt, &m, &n) == 4) { + + params->sc_str[0][0] = stor_scheme; + + params->pc_str[0][0] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "setm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_setm( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_subm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme, transx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld %ld\n", + api_name, &dt, &transx, &m, &n ) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "subm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_subm( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_xpbym_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m,n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + char transx; + + if(sscanf(str, "%s %c %c %ld %ld\n", + api_name, &dt, &transx, &m, &n) == 5){ + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(transx) ){ + params->pc_str[0][0] = tolower(transx); + } else { + params->pc_str[0][0] = transx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + } + + double resid = 0.0; + const char* op_str = "xpbym"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_xpbym( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + + // Variables extracted from the logs which are used by bench + char stor_scheme, transA; + double alpha_r, beta_r, alpha_i, beta_i; + inc_t lda; + inc_t incx, incy; + + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %ld %ld %lf %lf %ld %ld %lf %lf %ld\n", + api_name, &dt, &transA, &m, &n, &alpha_r, &alpha_i, &lda, + &incx, &beta_r, &beta_i, &incy) == 12) + { + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(transA) ){ + params->pc_str[0][0] = tolower(transA); + } else { + params->pc_str[0][0] = transA; + } + + if(transA == 'C' || transA == 'c') + params->pc_str[0][1] = 'c'; + else /*if(transA == 'N' || transA == 'n')*/ + params->pc_str[0][1] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + } + + double resid = 0.0; + const char* op_str = "gemv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemv( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_ger_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + double alpha_r, alpha_i; + inc_t lda; + inc_t incx, incy; + + if(sscanf(str, "%s %c %ld %ld %lf %lf %ld %ld %ld\n", + api_name, &dt, &m, &n, &alpha_r, &alpha_i, &incx, &incy, &lda) == 9) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + params->pc_str[0][0] = 'n'; + params->pc_str[0][1] = 'n'; + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + + params->ld[0] = lda; + } + + double resid = 0.0; + const char* op_str = "ger"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_ger( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_hemv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, uploa, conja, conjx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %c %ld\n", + api_name, &dt, &uploa, &conja, &conjx, &m) == 6) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(uploa) ){ + params->pc_str[0][0] = tolower(uploa); + } else { + params->pc_str[0][0] = uploa; + } + + if (isalpha(conja) ){ + params->pc_str[0][1] = tolower(conja); + } else { + params->pc_str[0][1] = conja; + } + + if (isalpha(conjx) ){ + params->pc_str[0][2] = tolower(conjx); + } else { + params->pc_str[0][2] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "hemv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_hemv( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_her_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, uploa, conjx; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %ld\n", + api_name, &dt, &uploa, &conjx, &m) == 5) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(uploa) ){ + params->pc_str[0][0] = tolower(uploa); + } else { + params->pc_str[0][0] = uploa; + } + + if (isalpha(conjx) ){ + params->pc_str[0][1] = tolower(conjx); + } else { + params->pc_str[0][1] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "her"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_her( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_her2_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme, uploa, conjx, conjy; + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %c %ld\n", + api_name, &dt, &uploa, &conjx, &conjy, &m) == 6) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(uploa) ){ + params->pc_str[0][0] = tolower(uploa); + } else { + params->pc_str[0][0] = uploa; + } + + if (isalpha(conjx) ){ + params->pc_str[0][1] = tolower(conjx); + } else { + params->pc_str[0][1] = conjx; + } + + if (isalpha(conjy) ){ + params->pc_str[0][2] = tolower(conjy); + } else { + params->pc_str[0][2] = conjy; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + } + + double resid = 0.0; + const char* op_str = "her2"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_her2( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_symv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + inc_t lda; + char uplo, conja, conjx; + double alpha_r, beta_r, alpha_i, beta_i; + + if(sscanf(str, "%s %c %c %c %c %ld %lf %lf %lu %lf %lf \n", + api_name, &dt, &uplo, &conja, &conjx, &m, &alpha_r, &alpha_i, + &lda, &beta_r, &beta_i) == 11) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(uplo) ){ + params->pc_str[0][0] = tolower(uplo); + } else { + params->pc_str[0][0] = uplo; + } + + if (isalpha(conja) ){ + params->pc_str[0][1] = tolower(conja); + } else { + params->pc_str[0][1] = conja; + } + + if (isalpha(conjx) ){ + params->pc_str[0][1] = tolower(conjx); + } else { + params->pc_str[0][1] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][2] = tolower(dt); + } else { + params->dc_str[0][2] = dt; + } + + params->dim[0].m = m; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + } + + double resid = 0.0; + const char* op_str = "symv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_symv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_syr_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + char uplo, conjx; + double alpha_r, alpha_i; + + if(sscanf(str, "%s %c %c %c %ld %lf %lf \n", + api_name, &dt, &uplo, &conjx, &m, &alpha_r, &alpha_i) == 7) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(uplo) ){ + params->pc_str[0][0] = tolower(uplo); + } else { + params->pc_str[0][0] = uplo; + } + + if (isalpha(conjx) ){ + params->pc_str[0][1] = tolower(conjx); + } else { + params->pc_str[0][1] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + } + + double resid = 0.0; + const char* op_str = "syr"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_syr( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_syr2_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + char uplo, conjx; + double alpha_r, alpha_i; + + if(sscanf(str, "%s %c %c %c %ld %lf %lf \n", + api_name, &dt, &uplo, &conjx, &m, &alpha_r, &alpha_i) == 7) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(uplo) ){ + params->pc_str[0][0] = tolower(uplo); + } else { + params->pc_str[0][0] = uplo; + } + + if (isalpha(conjx) ){ + params->pc_str[0][1] = tolower(conjx); + } else { + params->pc_str[0][1] = conjx; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + } + + double resid = 0.0; + const char* op_str = "syr2"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_syr2( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params,op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_trmv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + dim_t lda; + char uploa, transA, diaga; + inc_t incx; + + if(sscanf(str, "%s %c %c %c %c %ld %ld %ld\n", + api_name, &dt, &uploa, &transA, &diaga, &m, &lda, &incx) == 8){ + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(uploa) ){ + params->pc_str[0][0] = tolower(uploa); + } else { + params->pc_str[0][0] = uploa; + } + + if (isalpha(transA) ){ + params->pc_str[0][1] = tolower(transA); + } else { + params->pc_str[0][1] = transA; + } + + if (isalpha(diaga) ){ + params->pc_str[0][2] = tolower(diaga); + } else { + params->pc_str[0][2] = diaga; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + + params->ld[0] = lda; + } + + double resid = 0.0; + const char* op_str = "trmv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_trmv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_trsv_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + dim_t lda; + char uploa, transA, diaga; + inc_t incx; + + if(sscanf(str, "%s %c %c %c %c %ld %ld %ld\n", + api_name, &dt, &uploa, &transA, &diaga, &m, &lda, &incx) == 8){ + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(uploa) ){ + params->pc_str[0][0] = tolower(uploa); + } else { + params->pc_str[0][0] = uploa; + } + + if (isalpha(transA) ){ + params->pc_str[0][1] = tolower(transA); + } else { + params->pc_str[0][1] = transA; + } + + if (isalpha(diaga) ){ + params->pc_str[0][2] = tolower(diaga); + } else { + params->pc_str[0][2] = diaga; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + + params->ld[0] = lda; + } + + double resid = 0.0; + const char* op_str = "trsv"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_trsv( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n, k; + char dt; + + // Variables extracted from the logs which are used by bench + char stor_scheme, transA, transB; + double alpha_r, beta_r, alpha_i, beta_i; + inc_t lda, ldb, ldc; + + stor_scheme = 'c'; + + if(sscanf(str, "%s %c %c %c %ld %ld %ld %lf %lf %ld %ld %lf %lf %ld[^\n]", + api_name, &dt, &transA, &transB, &m, &n, &k, &alpha_r, &alpha_i, + &lda, &ldb, &beta_r, &beta_i, &ldc) == 14) { + + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(transA) ){ + params->pc_str[0][0] = tolower(transA); + } else { + params->pc_str[0][0] = transA; + } + + if (isalpha(transB) ){ + params->pc_str[0][1] = tolower(transB); + } else { + params->pc_str[0][1] = transB; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + params->dim[0].k = k; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "gemm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemm( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemmt_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + inc_t lda, ldb, ldc; + char transA, transB, uplo; + double alpha_r, beta_r, alpha_i, beta_i; + + if(sscanf(str,"%s %c %c %ld %ld %lu %lu %lu %c %c %lf %lf %lf %lf\n",\ + api_name, &dt, &uplo, &m, &n, &lda, &ldb, &ldc, &transA, &transB, + &alpha_r, &alpha_i, &beta_r, &beta_i) == 14) { + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if(isalpha(uplo) ){ + params->pc_str[0][0] = tolower(uplo); + } else { + params->pc_str[0][0] = uplo; + } + + if (isalpha(transA) ){ + params->pc_str[0][1] = tolower(transA); + } else { + params->pc_str[0][1] = transA; + } + + if (isalpha(transB) ){ + params->pc_str[0][2] = tolower(transB); + } else { + params->pc_str[0][2] = transB; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "gemmt"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemmt( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_hemm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + dim_t lda, ldb, ldc; + char side, uploa ; + double alpha_r, alpha_i, beta_r, beta_i; + + if(sscanf(str, "%s %c %c %c %ld %ld %lf %lf %ld %ld %lf %lf %ld\n", + api_name, &dt, &side, &uploa, &m, &n, &alpha_r, &alpha_i, + &lda, &ldb, &beta_r, &beta_i, &ldc) == 13) { + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(side) ){ + params->pc_str[0][0] = tolower(side); + } else { + params->pc_str[0][0] = side; + } + + if (isalpha(uploa) ){ + params->pc_str[0][1] = tolower(uploa); + } else { + params->pc_str[0][1] = uploa; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "hemm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_hemm( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_herk_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + inc_t lda, ldc; + char transA, uplo; + double alpha_r, beta_r, alpha_i, beta_i; + + if(sscanf(str, "%s %c %c %c %ld %ld %lf %lf %lu %lf %lf %lu\n", + api_name, &dt, &uplo, &transA, &m, &n, &alpha_r, &alpha_i, + &lda, &beta_r, &beta_i, &ldc) == 12) { + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(uplo) ){ + params->pc_str[0][0] = tolower(uplo); + } else { + params->pc_str[0][0] = uplo; + } + + if (isalpha(transA) ){ + params->pc_str[0][1] = tolower(transA); + } else { + params->pc_str[0][1] = transA; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "herk"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_herk( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_her2k_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + inc_t lda, ldc; + char transA, transB, uplo; + double alpha_r, beta_r, alpha_i, beta_i; + + if(sscanf(str, "%s %c %c %c %c %ld %ld %lf %lf %lu %lf %lf %lu\n", + api_name, &dt, &uplo, &transA, &transB, &m, &n, + &alpha_r, &alpha_i, &lda, &beta_r, &beta_i, &ldc) == 12) + { + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(uplo) ){ + params->pc_str[0][0] = tolower(uplo); + } else { + params->pc_str[0][0] = uplo; + } + + if (isalpha(transA) ){ + params->pc_str[0][1] = tolower(transA); + } else { + params->pc_str[0][1] = transA; + } + + if (isalpha(transB) ){ + params->pc_str[0][1] = tolower(transB); + } else { + params->pc_str[0][1] = transB; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "her2k"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_her2k( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_symm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + dim_t lda, ldb, ldc; + char side, uploa ; + double alpha_r, alpha_i, beta_r, beta_i; + + if(sscanf(str, "%s %c %c %c %ld %ld %lf %lf %ld %ld %lf %lf %ld\n", + api_name, &dt, &side, &uploa, &m, &n, &alpha_r, &alpha_i, + &lda, &ldb, &beta_r, &beta_i, &ldc) == 13) { + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(side) ){ + params->pc_str[0][0] = tolower(side); + } else { + params->pc_str[0][0] = side; + } + + if (isalpha(uploa) ){ + params->pc_str[0][1] = tolower(uploa); + } else { + params->pc_str[0][1] = uploa; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "symm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_symm( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_syrk_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + inc_t lda, ldc; + char transA, uplo; + double alpha_r, beta_r, alpha_i, beta_i; + + if(sscanf(str, "%s %c %c %c %ld %ld %lf %lf %lu %lf %lf %lu\n", + api_name, &dt, &uplo, &transA, &m, &n, &alpha_r, &alpha_i, + &lda, &beta_r, &beta_i, &ldc) == 12) { + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(uplo) ){ + params->pc_str[0][0] = tolower(uplo); + } else { + params->pc_str[0][0] = uplo; + } + + if (isalpha(transA) ){ + params->pc_str[0][1] = tolower(transA); + } else { + params->pc_str[0][1] = transA; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "syrk"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_syrk( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_syr2k_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + inc_t lda, ldc; + char transA, transB, uplo; + double alpha_r, beta_r, alpha_i, beta_i; + + if(sscanf(str, "%s %c %c %c %c %ld %ld %lf %lf %lu %lf %lf %lu\n", + api_name, &dt, &uplo, &transA, &transB, &m, &n, + &alpha_r, &alpha_i, &lda, &beta_r, &beta_i, &ldc) == 12) + { + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + if (isalpha(uplo) ){ + params->pc_str[0][0] = tolower(uplo); + } else { + params->pc_str[0][0] = uplo; + } + + if (isalpha(transA) ){ + params->pc_str[0][1] = tolower(transA); + } else { + params->pc_str[0][1] = transA; + } + + if (isalpha(transB) ){ + params->pc_str[0][1] = tolower(transB); + } else { + params->pc_str[0][1] = transB; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "syr2k"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_syr2k( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_trmm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + dim_t lda, ldb; + char side, uploa, transa, diaga; + double alpha_r, alpha_i; + + if(sscanf(str, "%s %c %c %c %c %c %ld %ld %ld %ld %lf %lf\n", + api_name, &dt, &side, &uploa, &transa, &diaga, &m, &n, + &lda, &ldb, &alpha_r, &alpha_i) == 12) { + + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(side) ){ + params->pc_str[0][0] = tolower(side); + } else { + params->pc_str[0][0] = side; + } + + if (isalpha(uploa) ){ + params->pc_str[0][1] = tolower(uploa); + } else { + params->pc_str[0][1] = uploa; + } + + if (isalpha(transa) ){ + params->pc_str[0][2] = tolower(transa); + } else { + params->pc_str[0][2] = transa; + } + + if (isalpha(diaga) ){ + params->pc_str[0][3] = tolower(diaga); + } else { + params->pc_str[0][3] = diaga; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + + params->ld[0] = lda; + params->ld[1] = ldb; + } + + double resid = 0.0; + const char* op_str = "trmm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_trmm( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_trmm3_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + dim_t lda, ldb, ldc; + char side, uploa, transa, transb, diaga; + double alpha_r, alpha_i, beta_r, beta_i; + + if(sscanf(str, "%s %c %c %c %c %c %c %ld %ld %lf %lf %ld %ld %lf %lf %ld\n", + api_name, &dt, &side, &uploa, &transa, &transb, &diaga, &m, &n, + &alpha_r, &alpha_i, &lda, &ldb, &beta_r, &beta_i, &ldc) == 16) + { + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(side) ){ + params->pc_str[0][0] = tolower(side); + } else { + params->pc_str[0][0] = side; + } + + if (isalpha(uploa) ){ + params->pc_str[0][1] = tolower(uploa); + } else { + params->pc_str[0][1] = uploa; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + params->beta->real = beta_r; + params->beta->imag = beta_i; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + } + + double resid = 0.0; + const char* op_str = "trmm3"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_trmm3( params, iface, params->dc_str[0], params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_trsm_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[10]; + dim_t m, n; + char dt; + char stor_scheme; + stor_scheme = 'c'; + + dim_t lda, ldb; + char side, uploa, transa, diaga; + double alpha_r, alpha_i; + + if(sscanf(str, "%s %c %c %c %c %c %ld %ld %ld %ld %lf %lf\n", + api_name, &dt, &side, &uploa, &transa, &diaga, &m, &n, + &lda, &ldb, &alpha_r, &alpha_i) == 12) { + + if( m == lda ) + stor_scheme = 'c'; + if( n == lda ) + stor_scheme = 'r'; + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + + if (isalpha(side) ){ + params->pc_str[0][0] = tolower(side); + } else { + params->pc_str[0][0] = side; + } + + if (isalpha(uploa) ){ + params->pc_str[0][1] = tolower(uploa); + } else { + params->pc_str[0][1] = uploa; + } + + if (isalpha(transa) ){ + params->pc_str[0][2] = tolower(transa); + } else { + params->pc_str[0][2] = transa; + } + + if (isalpha(diaga) ){ + params->pc_str[0][3] = tolower(diaga); + } else { + params->pc_str[0][3] = diaga; + } + + if (isalpha(dt) ){ + params->dc_str[0][0] = tolower(dt); + } else { + params->dc_str[0][0] = dt; + } + + params->dim[0].m = m; + params->dim[0].n = n; + + params->alpha->real = alpha_r; + params->alpha->imag = alpha_i; + + params->ld[0] = lda; + params->ld[1] = ldb; + } + + double resid = 0.0; + const char* op_str = "trsm"; + ind_t mt = BLIS_NAT; + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_trsm( params, iface, params->dc_str[0], + params->pc_str[0], params->sc_str[0], &t, params->alpha[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemm_u8s8s32os32_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[25]; + dim_t m, n, k; + char stor_scheme = 'c'; + + // Variables extracted from the logs which are used by bench + inc_t lda, ldb, ldc; + char op_t; + + if( sscanf( str, "%s %c %c %ld %ld %ld %ld %ld %ld\n", + api_name, &stor_scheme, &op_t, &m, &n, &k, + &lda, &ldb, &ldc ) == 9 ) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + params->pc_str[0][1] = 'n'; + params->pc_str[0][2] = 'n'; + + params->dim[0].m = m; + params->dim[0].n = n; + params->dim[0].k = k; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + + params->op_t = op_t; + + params->alpha->real = 2; + params->alpha->imag = 0; + params->beta->real = 9; + params->beta->imag = 0; + + } + + double resid = 0.0; + const char* op_str = "gemm_u8s8s32os32"; + params->dc_str[0][0] = 's'; + ind_t mt = BLIS_NAT; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemm_u8s8s32os32( params, params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemm_u8s8s32os8_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[25]; + dim_t m, n, k; + char stor_scheme = 'c'; + + // Variables extracted from the logs which are used by bench + inc_t lda, ldb, ldc; + char op_t; + + if( sscanf( str, "%s %c %c %ld %ld %ld %ld %ld %ld\n", + api_name, &stor_scheme, &op_t, &m, &n, &k, + &lda, &ldb, &ldc ) == 9 ) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + params->pc_str[0][1] = 'n'; + params->pc_str[0][2] = 'n'; + + params->dim[0].m = m; + params->dim[0].n = n; + params->dim[0].k = k; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + + params->op_t = op_t; + + params->alpha->real = 2; + params->alpha->imag = 0; + params->beta->real = 9; + params->beta->imag = 0; + + } + + double resid = 0.0; + const char* op_str = "gemm_u8s8s32os8"; + params->dc_str[0][0] = 's'; + ind_t mt = BLIS_NAT; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemm_u8s8s32os8( params, params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemm_f32f32f32of32_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[25]; + dim_t m, n, k; + char stor_scheme = 'c'; + + // Variables extracted from the logs which are used by bench + inc_t lda, ldb, ldc; + char op_t; + + if( sscanf( str, "%s %c %c %ld %ld %ld %ld %ld %ld\n", + api_name, &stor_scheme, &op_t, &m, &n, &k, + &lda, &ldb, &ldc ) == 9 ) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + params->pc_str[0][1] = 'n'; + params->pc_str[0][2] = 'n'; + + params->dim[0].m = m; + params->dim[0].n = n; + params->dim[0].k = k; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + + params->op_t = op_t; + + params->alpha->real = 2; + params->alpha->imag = 0; + params->beta->real = 9; + params->beta->imag = 0; + + } + + double resid = 0.0; + const char* op_str = "gemm_f32f32f32of32"; + params->dc_str[0][0] = 's'; + ind_t mt = BLIS_NAT; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemm_f32f32f32of32( params, params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemm_u8s8s16os16_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[25]; + dim_t m, n, k; + char stor_scheme = 'c'; + + // Variables extracted from the logs which are used by bench + inc_t lda, ldb, ldc; + char op_t; + + if( sscanf( str, "%s %c %c %ld %ld %ld %ld %ld %ld\n", + api_name, &stor_scheme, &op_t, &m, &n, &k, + &lda, &ldb, &ldc ) == 9 ) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + params->pc_str[0][1] = 'n'; + params->pc_str[0][2] = 'n'; + + params->dim[0].m = m; + params->dim[0].n = n; + params->dim[0].k = k; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + + params->op_t = op_t; + + params->alpha->real = 2; + params->alpha->imag = 0; + params->beta->real = 9; + params->beta->imag = 0; + + } + + double resid = 0.0; + const char* op_str = "gemm_u8s8s16os16"; + params->dc_str[0][0] = 's'; + ind_t mt = BLIS_NAT; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemm_u8s8s16os16( params, params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemm_u8s8s16os8_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[25]; + dim_t m, n, k; + char stor_scheme = 'c'; + + // Variables extracted from the logs which are used by bench + inc_t lda, ldb, ldc; + char op_t; + + if( sscanf( str, "%s %c %c %ld %ld %ld %ld %ld %ld\n", + api_name, &stor_scheme, &op_t, &m, &n, &k, + &lda, &ldb, &ldc ) == 9 ) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + params->pc_str[0][1] = 'n'; + params->pc_str[0][2] = 'n'; + + params->dim[0].m = m; + params->dim[0].n = n; + params->dim[0].k = k; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + + params->op_t = op_t; + + params->alpha->real = 2; + params->alpha->imag = 0; + params->beta->real = 9; + params->beta->imag = 0; + + } + + double resid = 0.0; + const char* op_str = "gemm_u8s8s16os8"; + params->dc_str[0][0] = 's'; + ind_t mt = BLIS_NAT; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemm_u8s8s16os8( params, params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemm_bf16bf16f32of32_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[25]; + dim_t m, n, k; + char stor_scheme = 'c'; + + // Variables extracted from the logs which are used by bench + inc_t lda, ldb, ldc; + char op_t; + + if( sscanf( str, "%s %c %c %ld %ld %ld %ld %ld %ld\n", + api_name, &stor_scheme, &op_t, &m, &n, &k, + &lda, &ldb, &ldc ) == 9 ) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + params->pc_str[0][1] = 'n'; + params->pc_str[0][2] = 'n'; + + params->dim[0].m = m; + params->dim[0].n = n; + params->dim[0].k = k; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + + params->op_t = op_t; + + params->alpha->real = 2; + params->alpha->imag = 0; + params->beta->real = 9; + params->beta->imag = 0; + + } + + double resid = 0.0; + const char* op_str = "gemm_bf16bf16f32of32"; + params->dc_str[0][0] = 's'; + ind_t mt = BLIS_NAT; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemm_bf16bf16f32of32( params, params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +int libblis_test_read_gemm_bf16bf16f32obf16_params( char* str, test_op_t* op, + test_params_t* params, printres_t* pfr) { + char api_name[25]; + dim_t m, n, k; + char stor_scheme = 'c'; + + // Variables extracted from the logs which are used by bench + inc_t lda, ldb, ldc; + char op_t; + + if( sscanf( str, "%s %c %c %ld %ld %ld %ld %ld %ld\n", + api_name, &stor_scheme, &op_t, &m, &n, &k, + &lda, &ldb, &ldc ) == 9 ) { + + params->sc_str[0][0] = stor_scheme; + params->sc_str[0][1] = stor_scheme; + params->sc_str[0][2] = stor_scheme; + + params->pc_str[0][1] = 'n'; + params->pc_str[0][2] = 'n'; + + params->dim[0].m = m; + params->dim[0].n = n; + params->dim[0].k = k; + + params->ld[0] = lda; + params->ld[1] = ldb; + params->ld[2] = ldc; + + params->op_t = op_t; + + params->alpha->real = 2; + params->alpha->imag = 0; + params->beta->real = 9; + params->beta->imag = 0; + + } + + double resid = 0.0; + const char* op_str = "gemm_bf16bf16f32obf16"; + params->dc_str[0][0] = 's'; + ind_t mt = BLIS_NAT; + tensor_t *dim = params->dim; + tensor_t t = dim[0]; + + resid = libblis_test_op_gemm_bf16bf16f32obf16( params, params->pc_str[0], + params->sc_str[0], &t, params->alpha[0], params->beta[0]); + + char* res_str = libblis_test_result (resid, thresh, params->dc_str[0], params ); + + char buffer[125]; + libblis_build_function_string(params, op->opid, op_str, mt, 0, 0, 0, buffer); + + displayProps(buffer, params, op, &t, resid, res_str, pfr); + + return 0; +} + +void libblis_read_api(test_ops_t* ops, opid_t opid, dimset_t dimset, + unsigned int n_params, test_op_t* op ) { + + if ( op->op_switch == ENABLE_ONLY ){ + return; + } + + // Initialize the operation type field. + op->opid = opid; + + op->op_switch = ENABLE_ONLY ; + + // Check the op_switch for the individual override value. + if ( op->op_switch == ENABLE_ONLY ) { + ops->indiv_over = TRUE; + } + + op->n_dims = libblis_test_get_n_dims_from_dimset( dimset ); + op->dimset = dimset; + + if ( op->n_dims > MAX_NUM_DIMENSIONS ) { + libblis_test_printf_error( "Detected too many dimensions (%u) in input file to store.\n", + op->n_dims ); + } + + if ( n_params > 0 ) { + op->n_params = n_params; + } + else { + op->n_params = 0; + strcpy( op->params, "" ); + } + + // Initialize the "test done" switch. + op->test_done = FALSE; + + // Initialize the parent pointer. + op->ops = ops; + + return; +} + +void libblis_read_inpops(string ss, test_params_t* params, test_ops_t* ops, + string api, printres_t* pfr){ + char str[125]; + strcpy( str, ss.c_str() ); + + /* Utility operations */ + if (api == "randv") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 0, &(ops->randv) ); + libblis_test_read_randv_params(str, &(ops->randv), params, pfr); + } else if(api == "randm") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 0, &(ops->randm) ); + libblis_test_read_randm_params(str, &(ops->randm), params, pfr); + } else + /* Level-1v */ + if( (api == "addv") || (api == "add") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->addv) ); + libblis_test_read_addv_params(str, &(ops->addv), params, pfr); + } else if( (api == "amaxv") || (api == "amax") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 0, &(ops->amaxv) ); + libblis_test_read_amaxv_params(str, &(ops->amaxv), params, pfr); + } else if( (api == "axpbyv") || (api == "axpby") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->axpbyv) ); + libblis_test_read_axpbyv_params(str, &(ops->axpbyv), params, pfr); + } else if( (api == "axpyv") || (api == "axpy") ){ + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->axpyv) ); + libblis_test_read_axpyv_params(str, &(ops->axpyv), params, pfr); + } else if((api == "copyv") || (api == "copy") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->copyv) ); + libblis_test_read_copyv_params(str, &(ops->copyv), params, pfr); + } else if( (api == "dotv") || (api == "dot")) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->dotv) ); + libblis_test_read_dotv_params(str, &(ops->dotv), params, pfr); + } else if( (api == "dotxv") || (api == "dotx") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->dotxv) ); + libblis_test_read_dotxv_params(str, &(ops->dotxv), params, pfr); + } else if( (api == "normfv") || (api == "nrm2") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 0, &(ops->normfv) ); + libblis_test_read_normfv_params(str, &(ops->normfv), params, pfr); + } else if( (api == "scalv") || (api == "scal") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->scalv) ); + libblis_test_read_scalv_params(str, &(ops->scalv), params, pfr); + } else if( (api == "scal2v") || (api == "scal2") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->scal2v) ); + libblis_test_read_scal2v_params(str, &(ops->scal2v), params, pfr); + } else if( (api == "setv") || (api == "set") ){ + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 0, &(ops->setv) ); + libblis_test_read_setv_params(str, &(ops->setv), params, pfr); + } else if( (api == "subv") || (api == "sub") ) { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->subv) ); + libblis_test_read_subv_params(str, &(ops->subv), params, pfr); + } else if( (api == "xpbyv") || (api == "xpby") ){ + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->xpbyv) ); + libblis_test_read_xpbyv_params(str, &(ops->xpbyv), params, pfr); + } else + /* Level-1m */ + if(api == "addm") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->addm) ); + libblis_test_read_addm_params(str, &(ops->addm), params, pfr); + } else if(api == "axpym") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->axpym) ); + libblis_test_read_axpym_params(str, &(ops->axpym), params, pfr); + } else if(api == "copym") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->copym) ); + libblis_test_read_copym_params(str, &(ops->copym), params, pfr); + } else if(api == "normfm") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 0, &(ops->normfm) ); + libblis_test_read_normfm_params(str, &(ops->normfm), params, pfr); + } else if(api == "scalm") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->scalm) ); + libblis_test_read_scal2m_params(str, &(ops->scalm), params, pfr); + } else if(api == "scal2m") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->scal2m) ); + libblis_test_read_scalm_params(str, &(ops->scal2m), params, pfr); + } else if(api == "setm") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 0, &(ops->setm) ); + libblis_test_read_setm_params(str, &(ops->setm), params, pfr); + } else if(api == "subm") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->subm) ); + libblis_test_read_subm_params(str, &(ops->subm), params, pfr); + } else if(api == "xpbym") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->xpbym) ); + libblis_test_read_xpbym_params(str, &(ops->xpbym), params, pfr); + } else + /* Level-1f */ + if(api == "axpy2v") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->axpy2v) ); + libblis_test_read_axpy2v_params(str, &(ops->axpy2v), params, pfr); + } else if(api == "dotaxpyv") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->dotaxpyv) ); + libblis_test_read_dotaxpyv_params(str, &(ops->dotaxpyv), params, pfr); + } else if(api == "axpyf") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MF, 2, &(ops->axpyf) ); + libblis_test_read_axpyf_params(str, &(ops->axpyf), params, pfr); + } else if(api == "dotxf") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MF, 2, &(ops->dotxf) ); + libblis_test_read_dotxf_params(str, &(ops->dotxf), params, pfr); + } else if(api == "dotxaxpyf") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MF, 4, &(ops->dotxaxpyf) ); + libblis_test_read_dotxaxpyf_params(str, &(ops->dotxaxpyf), params, pfr); + } else + /* Level-2 */ + if(api == "gemv") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 2, &(ops->gemv) ); + libblis_test_read_gemv_params(str, &(ops->gemv), params, pfr); + } else if(api == "ger") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MN, 2, &(ops->ger) ); + libblis_test_read_ger_params(str, &(ops->ger), params, pfr); + } else if(api == "hemv") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->hemv) ); + libblis_test_read_hemv_params(str, &(ops->hemv), params, pfr); + } else if(api == "her") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->her) ); + libblis_test_read_her_params(str, &(ops->her), params, pfr); + } else if(api == "her2") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->her2) ); + libblis_test_read_her2_params(str, &(ops->her2), params, pfr); + } else if(api == "symv") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->symv) ); + libblis_test_read_symv_params(str, &(ops->symv), params, pfr); + } else if(api == "syr") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->syr) ); + libblis_test_read_syr_params(str, &(ops->syr), params, pfr); + } else if(api == "syr2") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->syr2) ); + libblis_test_read_syr2_params(str, &(ops->syr2), params, pfr); + } else if(api == "trmv") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->trmv) ); + libblis_test_read_trmv_params(str, &(ops->trmv), params, pfr); + } else if(api == "trsv") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->trsv) ); + libblis_test_read_trsv_params(str, &(ops->trsv), params, pfr); + } else + /* Level-3 */ + if(api == "gemm") { + libblis_read_api( ops, BLIS_GEMM, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm) ); + libblis_test_read_gemm_params(str, &(ops->gemm), params, pfr); + } else if(api == "gemmt") { + libblis_read_api( ops, BLIS_GEMMT, BLIS_TEST_DIMS_MK, 3, &(ops->gemmt) ); + libblis_test_read_gemmt_params(str, &(ops->gemmt), params, pfr); + } else if(api == "hemm") { + libblis_read_api( ops, BLIS_HEMM, BLIS_TEST_DIMS_MN, 2, &(ops->hemm) ); + libblis_test_read_hemm_params(str, &(ops->hemm), params, pfr); + } else if(api == "herk") { + libblis_read_api( ops, BLIS_HERK, BLIS_TEST_DIMS_MK, 2, &(ops->herk) ); + libblis_test_read_herk_params(str, &(ops->herk), params, pfr); + } else if(api == "her2k") { + libblis_read_api( ops, BLIS_HER2K, BLIS_TEST_DIMS_MK, 2, &(ops->her2k) ); + libblis_test_read_her2k_params(str, &(ops->her2k), params, pfr); + } else if(api == "symm") { + libblis_read_api( ops, BLIS_SYMM, BLIS_TEST_DIMS_MN, 2, &(ops->symm) ); + libblis_test_read_symm_params(str, &(ops->symm), params, pfr); + } else if(api == "syrk") { + libblis_read_api( ops, BLIS_SYRK, BLIS_TEST_DIMS_MK, 2, &(ops->syrk) ); + libblis_test_read_syrk_params(str, &(ops->syrk), params, pfr); + } else if(api == "syr2k") { + libblis_read_api( ops, BLIS_SYR2K, BLIS_TEST_DIMS_MK, 2, &(ops->syr2k) ); + libblis_test_read_syr2k_params(str, &(ops->syr2k), params, pfr); + } else if(api == "trmm") { + libblis_read_api( ops, BLIS_TRMM, BLIS_TEST_DIMS_MN, 4, &(ops->trmm) ); + libblis_test_read_trmm_params(str, &(ops->trmm), params, pfr); + } else if(api == "trmm3") { + libblis_read_api( ops, BLIS_TRMM3, BLIS_TEST_DIMS_MN, 5, &(ops->trmm3) ); + libblis_test_read_trmm3_params(str, &(ops->trmm3), params, pfr); + } else if(api == "trsm") { + libblis_read_api( ops, BLIS_TRSM, BLIS_TEST_DIMS_MN, 4, &(ops->trsm) ); + libblis_test_read_trsm_params(str, &(ops->trsm), params, pfr); + } else + /* LPGEMM */ + if(api == "gemm_u8s8s32os32") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_u8s8s32os32) ); + libblis_test_read_gemm_u8s8s32os32_params(str, &(ops->gemm_u8s8s32os32), params, pfr); + } + else if(api == "gemm_u8s8s32os8") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_u8s8s32os8) ); + libblis_test_read_gemm_u8s8s32os8_params(str, &(ops->gemm_u8s8s32os8), params, pfr); + } + else if(api == "gemm_f32f32f32of32") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_f32f32f32of32) ); + libblis_test_read_gemm_f32f32f32of32_params(str, &(ops->gemm_f32f32f32of32), params, pfr); + } + else if(api == "gemm_u8s8s16os16") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_u8s8s16os16) ); + libblis_test_read_gemm_u8s8s16os16_params(str, &(ops->gemm_u8s8s16os16), params, pfr); + } + else if(api == "gemm_u8s8s16os8") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_u8s8s16os8) ); + libblis_test_read_gemm_u8s8s16os8_params(str, &(ops->gemm_u8s8s16os8), params, pfr); + } + else if(api == "gemm_bf16bf16f32of32") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_bf16bf16f32of32) ); + libblis_test_read_gemm_bf16bf16f32of32_params(str, &(ops->gemm_bf16bf16f32of32), params, pfr); + } + else if(api == "gemm_bf16bf16f32obf16") { + libblis_read_api( ops, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_bf16bf16f32obf16) ); + libblis_test_read_gemm_bf16bf16f32obf16_params(str, &(ops->gemm_bf16bf16f32obf16), params, pfr); + } + else { + printf("Invalid api option : "); + cout << ss << endl; + } + return; +} + +void libblis_read_inpprms(string str, test_params_t* params, test_ops_t* ops, printres_t* pfr) { + + stringstream ss; + string api, wrd; + + ss << str; + + str = ""; + ss >> wrd; + api = wrd.substr(1, (wrd.length()-2)); +// api = wrd.substr(0, wrd.length()); + + str = str + api; + + // Running loop till end of stream + while (!ss.eof()) { + + str = str + ' '; + + // Extracting word by word from stream + ss >> wrd; + + // Concatenating in the string to be returned + str = str + wrd; + } + + libblis_read_inpops(str, params, ops, api, pfr); +} diff --git a/gtestsuite/src/blis_inpfile.h b/gtestsuite/src/blis_inpfile.h new file mode 100644 index 000000000..660295a05 --- /dev/null +++ b/gtestsuite/src/blis_inpfile.h @@ -0,0 +1,490 @@ +#ifndef BLIS_INPFILE_H +#define BLIS_INPFILE_H + +#include "blis_test.h" + +void libblis_read_inpprms + ( + string str, + test_params_t* params, + test_ops_t* ops, + printres_t* pfr + ); + +void libblis_read_inpops + ( + string ss, + test_params_t* params, + test_ops_t* ops, + string api, + printres_t* pfr + ); + +void libblis_read_api + ( + test_ops_t* ops, + opid_t opid, + dimset_t dimset, + unsigned int n_params, + test_op_t* op + ); + +int libblis_test_read_randv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_randm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_addv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_amaxv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_axpbyv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_axpyv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_copyv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_dotv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_dotxv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_normfv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_scal2v_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_scalv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_setv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_xpbyv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_subv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_axpyf_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_axpy2v_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_dotxf_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_dotaxpyv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_dotxaxpyf_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_addm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_axpym_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_copym_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_normfm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_scal2m_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_scalm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_setm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_subm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_xpbym_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + + +int libblis_test_read_gemv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_ger_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_hemv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_her_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_her2_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_symv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_syr_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_syr2_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_trmv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_trsv_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemmt_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_hemm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_herk_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_her2k_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_symm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_syrk_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_syr2k_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_trmm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_trsm_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_u8s8s32os32_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_u8s8s32os8_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_f32f32f32of32_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_u8s8s32os32_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_u8s8s16os16_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_u8s8s16os8_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_bf16bf16f32of32_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +int libblis_test_read_gemm_bf16bf16f32obf16_params + ( + char* str, + test_op_t* op, + test_params_t* params, + printres_t* pfr + ); + +#endif // BLIS_INPFILE_H + diff --git a/gtestsuite/src/blis_utils.cpp b/gtestsuite/src/blis_utils.cpp new file mode 100644 index 000000000..fd61d459f --- /dev/null +++ b/gtestsuite/src/blis_utils.cpp @@ -0,0 +1,1947 @@ +#include "blis_utils.h" + +using namespace std; + +extern char libblis_test_pass_string[ MAX_PASS_STRING_LENGTH + 1 ]; +extern char libblis_test_warn_string[ MAX_PASS_STRING_LENGTH + 1 ]; +extern char libblis_test_fail_string[ MAX_PASS_STRING_LENGTH + 1 ]; +extern char libblis_test_overflow_string[ MAX_PASS_STRING_LENGTH + 1 ]; +extern char libblis_test_underflow_string[ MAX_PASS_STRING_LENGTH + 1 ]; + +void libblis_test_fprintf_c( FILE* output_stream, const char* message, ... ); +void libblis_test_printf_infoc( const char* message, ... ); + +char libblis_test_binary_name[ MAX_BINARY_NAME_LENGTH + 1 ]; + +void carryover( unsigned int* c, unsigned int* n_vals_for_param, unsigned int n_params ); +void libblis_test_ceil_pow2( obj_t* alpha ); +void libblis_test_parse_message( FILE* output_stream, const char* message, va_list args ) ; + +unsigned int libblis_test_get_n_dims_from_dimset( dimset_t dimset ) ; + +void bli_map_blis_to_netlib_trans( trans_t trans, char* blas_trans ) +{ + if ( trans == BLIS_NO_TRANSPOSE ) *blas_trans = 'N'; + else if ( trans == BLIS_TRANSPOSE ) *blas_trans = 'T'; + else if ( trans == BLIS_CONJ_NO_TRANSPOSE ) *blas_trans = 'C'; + else if ( trans == BLIS_CONJ_TRANSPOSE ) *blas_trans = 'C'; //*blas_trans = 'H' + else + { + bli_check_error_code( BLIS_INVALID_TRANS ); + } +} + +void bli_param_map_char_to_blas_trans( char trans, trans_t* blas_trans ) +{ + if ( trans == 'n' || trans == 'N' ) *blas_trans = BLIS_NO_TRANSPOSE; + else if ( trans == 't' || trans == 'T' ) *blas_trans = BLIS_TRANSPOSE; + else if ( trans == 'c' || trans == 'C' ) *blas_trans = BLIS_CONJ_TRANSPOSE; + else if ( trans == 'h' || trans == 'H' ) *blas_trans = BLIS_CONJ_NO_TRANSPOSE; + else + { + bli_check_error_code( BLIS_INVALID_TRANS ); + } +} + +void bli_param_map_char_to_herk_trans( char trans, trans_t* herk_trans ) +{ + if ( trans == 'n' || trans == 'N' ) *herk_trans = BLIS_NO_TRANSPOSE; + else if ( trans == 'c' || trans == 'C' ) *herk_trans = BLIS_TRANSPOSE; + else + { + bli_check_error_code( BLIS_INVALID_TRANS ); + } +} + +void bli_param_map_char_to_syrk_trans( char trans, trans_t* syrk_trans ) +{ + if ( trans == 'n' || trans == 'N' ) *syrk_trans = BLIS_NO_TRANSPOSE; + else if ( trans == 't' || trans == 'T' ) *syrk_trans = BLIS_TRANSPOSE; + else if ( trans == 'c' || trans == 'C' ) *syrk_trans = BLIS_TRANSPOSE; + else if ( trans == 'h' || trans == 'H' ) *syrk_trans = BLIS_NO_TRANSPOSE; + else + { + bli_check_error_code( BLIS_INVALID_TRANS ); + } +} + +void fill_string_with_n_spaces( char* str, unsigned int n_spaces ) +{ + unsigned int i; + + // Initialze to empty string in case n_spaces == 0. + sprintf( str, "%s", "" ); + + for ( i = 0; i < n_spaces; ++i ) + sprintf( &str[i], " " ); +} + +void libblis_test_build_dims_string(test_op_t* op, tensor_t* dim, char* dims_str) +{ + // For level-1f experiments with fusing factors, we grab the fusing + // factor from the op struct. We do something similar for micro-kernel + // calls. + if ( op->dimset == BLIS_TEST_DIMS_MF ) + { + sprintf( dims_str, " %5u %5u", + ( unsigned int )dim->m, + ( unsigned int ) op->dim_aux[0] ); + } + else if( op->dimset == BLIS_TEST_DIMS_K ) + { + sprintf( dims_str, " %5u %5u %5u", + ( unsigned int ) op->dim_aux[0], + ( unsigned int ) op->dim_aux[1], + ( unsigned int )dim->m ); + } + else if( op->dimset == BLIS_TEST_NO_DIMS ) + { + sprintf( dims_str, " %5u %5u", + ( unsigned int ) op->dim_aux[0], + ( unsigned int ) op->dim_aux[1] ); + } + else // For all other operations, we just use the dim_spec[] values + // and the current problem size. + { + // Initialize the string as empty. + sprintf( dims_str, "%s", "" ); + + // Print all dimensions to a single string. + //for ( i = 0; i < op->n_dims; ++i ) { + if( (op->n_dims > 0) && (dim->m > 0) ) + sprintf( &dims_str[strlen(dims_str)], " %5u", ( unsigned int ) dim->m ); + if( (op->n_dims > 0) && (dim->n > 0) ) + sprintf( &dims_str[strlen(dims_str)], " %5u", ( unsigned int ) dim->n ); + if( (op->n_dims > 0) && (dim->k > 0) ) + sprintf( &dims_str[strlen(dims_str)], " %5u", ( unsigned int ) dim->k ); + } +} + +void libblis_test_read_section_override( test_ops_t* ops, + FILE* input_stream, int* override ) +{ + char buffer[ INPUT_BUFFER_SIZE ]; + + // Read the line for the section override switch. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%d ", override ); +} + +void libblis_test_read_op_info + ( + test_ops_t* ops, + FILE* input_stream, + opid_t opid, + dimset_t dimset, + unsigned int n_params, + test_op_t* op + ) +{ + char buffer[ INPUT_BUFFER_SIZE ]; + char temp[ INPUT_BUFFER_SIZE ]; + unsigned int i, p; + + // Initialize the operation type field. + op->opid = opid; + + // Read the line for the overall operation switch. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%d ", &(op->op_switch) ); + + // Check the op_switch for the individual override value. + if ( op->op_switch == ENABLE_ONLY ) + { + ops->indiv_over = TRUE; + } + + op->n_dims = libblis_test_get_n_dims_from_dimset( dimset ); + op->dimset = dimset; + + if ( op->n_dims > MAX_NUM_DIMENSIONS ) + { + libblis_test_printf_error( "Detected too many dimensions (%u) in input file to store.\n", op->n_dims ); + } + + //printf( "n_dims = %u\n", op->n_dims ); + + // If there is at least one dimension for the current operation, read the + // dimension specifications, which encode the actual dimensions or the + // dimension ratios for each dimension. + if( op->n_dims > 0 ) { + libblis_test_read_next_line( buffer, input_stream ); + + for( i = 0, p = 0; i < op->n_dims; ++i ) + { + //printf( "buffer[p]: %s\n", &buffer[p] ); + + // Advance until we hit non-whitespace (ie: the next number). + for ( ; isspace( buffer[p] ); ++p ) ; + + //printf( "buffer[p] after: %s\n", &buffer[p] ); + + sscanf( &buffer[p], "%d", &(op->dim_spec[i]) ); + + //printf( "dim[%d] = %d\n", i, op->dim_spec[i] ); + + // Advance until we hit whitespace (ie: the space before the next number). + for ( ; !isspace( buffer[p] ); ++p ) ; + } + } + + // If there is at least one parameter for the current operation, read the + // parameter chars, which encode which parameter combinations to test. + if ( n_params > 0 ) + { + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%s ", temp ); + + op->n_params = strlen( temp ); + if ( op->n_params > MAX_NUM_PARAMETERS ) + { + libblis_test_printf_error( "Detected too many parameters (%u) in input file.\n", + op->n_params ); + } + if ( op->n_params != n_params ) + { + libblis_test_printf_error( "Number of parameters specified by caller does not match length of parameter string in input file. strlen( temp ) = %u; n_params = %u\n", op->n_params, n_params ); + } + + strcpy( op->params, temp ); + } + else + { + op->n_params = 0; + strcpy( op->params, "" ); + } + + // Initialize the "test done" switch. + op->test_done = FALSE; + + // Initialize the parent pointer. + op->ops = ops; +} + +void libblis_test_output_section_overrides( FILE* os, test_ops_t* ops ) +{ + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "--- Section overrides ---\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "Utility operations %d\n", ops->util_over ); + libblis_test_fprintf_c( os, "Level-1v operations %d\n", ops->l1v_over ); + libblis_test_fprintf_c( os, "Level-1m operations %d\n", ops->l1m_over ); + libblis_test_fprintf_c( os, "Level-1f operations %d\n", ops->l1f_over ); + libblis_test_fprintf_c( os, "Level-2 operations %d\n", ops->l2_over ); + libblis_test_fprintf_c( os, "Level-3 micro-kernels %d\n", ops->l3ukr_over ); + libblis_test_fprintf_c( os, "Level-3 operations %d\n", ops->l3_over ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf( os, "\n" ); +} + +void libblis_test_output_params_struct( FILE* os, test_params_t* params ) +{ + unsigned int i; + //char int_type_size_str[8]; + gint_t int_type_size; + ind_t im; + cntx_t* cntx; + cntx_t* cntx_c; + cntx_t* cntx_z; + + // If bli_info_get_int_type_size() returns 32 or 64, the size is forced. + // Otherwise, the size is chosen automatically. We query the result of + // that automatic choice via sizeof(gint_t). + if ( bli_info_get_int_type_size() == 32 || + bli_info_get_int_type_size() == 64 ) + int_type_size = bli_info_get_int_type_size(); + else + int_type_size = sizeof(gint_t) * 8; + + char impl_str[16]; + char jrir_str[16]; + + // Describe the threading implementation. + if ( bli_info_get_enable_openmp() ) sprintf( impl_str, "openmp" ); + else if ( bli_info_get_enable_pthreads() ) sprintf( impl_str, "pthreads" ); + else /* threading disabled */ sprintf( impl_str, "disabled" ); + + // Describe the status of jrir thread partitioning. + if ( bli_info_get_thread_part_jrir_slab() ) sprintf( jrir_str, "slab" ); + else /*bli_info_get_thread_part_jrir_rr()*/ sprintf( jrir_str, "round-robin" ); + + char nt_str[16]; + char jc_nt_str[16]; + char pc_nt_str[16]; + char ic_nt_str[16]; + char jr_nt_str[16]; + char ir_nt_str[16]; + char api[50]; + + // Query the number of ways of parallelism per loop (and overall) and + // convert these values into strings, with "unset" being used if the + // value returned was -1 (indicating the environment variable was unset). + dim_t nt = bli_thread_get_num_threads(); + dim_t jc_nt = bli_thread_get_jc_nt(); + dim_t pc_nt = bli_thread_get_pc_nt(); + dim_t ic_nt = bli_thread_get_ic_nt(); + dim_t jr_nt = bli_thread_get_jr_nt(); + dim_t ir_nt = bli_thread_get_ir_nt(); + + if ( nt == -1 ) sprintf( nt_str, "unset" ); + else sprintf( nt_str, "%d", ( int ) nt ); + if ( jc_nt == -1 ) sprintf( jc_nt_str, "unset" ); + else sprintf( jc_nt_str, "%d", ( int )jc_nt ); + if ( pc_nt == -1 ) sprintf( pc_nt_str, "unset" ); + else sprintf( pc_nt_str, "%d", ( int )pc_nt ); + if ( ic_nt == -1 ) sprintf( ic_nt_str, "unset" ); + else sprintf( ic_nt_str, "%d", ( int )ic_nt ); + if ( jr_nt == -1 ) sprintf( jr_nt_str, "unset" ); + else sprintf( jr_nt_str, "%d", ( int )jr_nt ); + if ( ir_nt == -1 ) sprintf( ir_nt_str, "unset" ); + else sprintf( ir_nt_str, "%d", ( int )ir_nt ); + + // Set up rntm_t objects for each of the four families: + // gemm, herk, trmm, trsm. + rntm_t gemm, herk, trmm_l, trmm_r, trsm_l, trsm_r; + dim_t m = 1000, n = 1000, k = 1000; + + bli_rntm_init_from_global( &gemm ); + bli_rntm_init_from_global( &herk ); + bli_rntm_init_from_global( &trmm_l ); + bli_rntm_init_from_global( &trmm_r ); + bli_rntm_init_from_global( &trsm_l ); + bli_rntm_init_from_global( &trsm_r ); + + bli_rntm_set_ways_for_op( BLIS_GEMM, BLIS_LEFT, m, n, k, &gemm ); + bli_rntm_set_ways_for_op( BLIS_HERK, BLIS_LEFT, m, n, k, &herk ); + bli_rntm_set_ways_for_op( BLIS_TRMM, BLIS_LEFT, m, n, k, &trmm_l ); + bli_rntm_set_ways_for_op( BLIS_TRMM, BLIS_RIGHT, m, n, k, &trmm_r ); + bli_rntm_set_ways_for_op( BLIS_TRSM, BLIS_LEFT, m, n, k, &trsm_l ); + bli_rntm_set_ways_for_op( BLIS_TRSM, BLIS_RIGHT, m, n, k, &trsm_r ); + + if (params->api == API_CBLAS) + sprintf( api, "cblas" ); + else if(params->api == API_BLAS) + sprintf( api, "blas" ); + else + sprintf( api, "blis" ); + + // Output some system parameters. + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "--- BLIS library info -------------------------------------\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "version string %s\n", bli_info_get_version_str() ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "--- BLIS configuration info ---\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "active sub-configuration %s\n", bli_arch_string( bli_arch_query_id() ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "BLIS integer type size (bits) %d\n", ( int )int_type_size ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "Assumed max # of SIMD regs %d\n", ( int )bli_info_get_simd_num_registers() ); + libblis_test_fprintf_c( os, "SIMD size (bytes) %d\n", ( int )bli_info_get_simd_size() ); + libblis_test_fprintf_c( os, "SIMD alignment (bytes) %d\n", ( int )bli_info_get_simd_align_size() ); + libblis_test_fprintf_c( os, "Max stack buffer size (bytes) %d\n", ( int )bli_info_get_stack_buf_max_size() ); + libblis_test_fprintf_c( os, "Page size (bytes) %d\n", ( int )bli_info_get_page_size() ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "memory pools\n" ); + libblis_test_fprintf_c( os, " enabled for packing blocks? %d\n", ( int )bli_info_get_enable_pba_pools() ); + libblis_test_fprintf_c( os, " enabled for small blocks? %d\n", ( int )bli_info_get_enable_sba_pools() ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "memory alignment (bytes) \n" ); + libblis_test_fprintf_c( os, " stack address %d\n", ( int )bli_info_get_stack_buf_align_size() ); + libblis_test_fprintf_c( os, " obj_t address %d\n", ( int )bli_info_get_heap_addr_align_size() ); + libblis_test_fprintf_c( os, " obj_t stride %d\n", ( int )bli_info_get_heap_stride_align_size() ); + libblis_test_fprintf_c( os, " pool block addr A (+offset) %d (+%d)\n", ( int )bli_info_get_pool_addr_align_size_a(), ( int )bli_info_get_pool_addr_offset_size_a() ); + libblis_test_fprintf_c( os, " pool block addr B (+offset) %d (+%d)\n", ( int )bli_info_get_pool_addr_align_size_b(), ( int )bli_info_get_pool_addr_offset_size_b() ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "BLAS/CBLAS compatibility layers \n" ); + libblis_test_fprintf_c( os, " BLAS API enabled? %d\n", ( int )bli_info_get_enable_blas() ); + libblis_test_fprintf_c( os, " CBLAS API enabled? %d\n", ( int )bli_info_get_enable_cblas() ); + libblis_test_fprintf_c( os, " integer type size (bits) %d\n", ( int )bli_info_get_blas_int_type_size() ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "libmemkind \n" ); + libblis_test_fprintf_c( os, " enabled? %d\n", ( int )bli_info_get_enable_memkind() ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "gemm sandbox \n" ); + libblis_test_fprintf_c( os, " enabled? %d\n", ( int )bli_info_get_enable_sandbox() ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "floating-point types s d c z \n" ); + libblis_test_fprintf_c( os, " sizes (bytes) %7u %7u %7u %7u\n", sizeof(float), + sizeof(double), + sizeof(scomplex), + sizeof(dcomplex) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "--- BLIS parallelization info ---\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "multithreading %s\n", impl_str ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "thread auto-factorization \n" ); + libblis_test_fprintf_c( os, " m dim thread ratio %d\n", ( int )BLIS_THREAD_RATIO_M ); + libblis_test_fprintf_c( os, " n dim thread ratio %d\n", ( int )BLIS_THREAD_RATIO_N ); + libblis_test_fprintf_c( os, " jr max threads %d\n", ( int )BLIS_THREAD_MAX_JR ); + libblis_test_fprintf_c( os, " ir max threads %d\n", ( int )BLIS_THREAD_MAX_IR ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "ways of parallelism nt jc pc ic jr ir\n" ); + libblis_test_fprintf_c( os, " environment %5s %5s %5s %5s %5s %5s\n", + nt_str, jc_nt_str, pc_nt_str, + ic_nt_str, jr_nt_str, ir_nt_str ); + libblis_test_fprintf_c( os, " gemm (m,n,k=1000) %5d %5d %5d %5d %5d\n", + ( int )bli_rntm_jc_ways( &gemm ), ( int )bli_rntm_pc_ways( &gemm ), + ( int )bli_rntm_ic_ways( &gemm ), + ( int )bli_rntm_jr_ways( &gemm ), ( int )bli_rntm_ir_ways( &gemm ) ); + libblis_test_fprintf_c( os, " herk (m,k=1000) %5d %5d %5d %5d %5d\n", + ( int )bli_rntm_jc_ways( &herk ), ( int )bli_rntm_pc_ways( &herk ), + ( int )bli_rntm_ic_ways( &herk ), + ( int )bli_rntm_jr_ways( &herk ), ( int )bli_rntm_ir_ways( &herk ) ); + libblis_test_fprintf_c( os, " trmm_l (m,n=1000) %5d %5d %5d %5d %5d\n", + ( int )bli_rntm_jc_ways( &trmm_l ), ( int )bli_rntm_pc_ways( &trmm_l ), + ( int )bli_rntm_ic_ways( &trmm_l ), + ( int )bli_rntm_jr_ways( &trmm_l ), ( int )bli_rntm_ir_ways( &trmm_l ) ); + libblis_test_fprintf_c( os, " trmm_r (m,n=1000) %5d %5d %5d %5d %5d\n", + ( int )bli_rntm_jc_ways( &trmm_r ), ( int )bli_rntm_pc_ways( &trmm_r ), + ( int )bli_rntm_ic_ways( &trmm_r ), + ( int )bli_rntm_jr_ways( &trmm_r ), ( int )bli_rntm_ir_ways( &trmm_r ) ); + libblis_test_fprintf_c( os, " trsm_l (m,n=1000) %5d %5d %5d %5d %5d\n", + ( int )bli_rntm_jc_ways( &trsm_l ), ( int )bli_rntm_pc_ways( &trsm_l ), + ( int )bli_rntm_ic_ways( &trsm_l ), + ( int )bli_rntm_jr_ways( &trsm_l ), ( int )bli_rntm_ir_ways( &trsm_l ) ); + libblis_test_fprintf_c( os, " trsm_r (m,n=1000) %5d %5d %5d %5d %5d\n", + ( int )bli_rntm_jc_ways( &trsm_r ), ( int )bli_rntm_pc_ways( &trsm_r ), + ( int )bli_rntm_ic_ways( &trsm_r ), + ( int )bli_rntm_jr_ways( &trsm_r ), ( int )bli_rntm_ir_ways( &trsm_r ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "thread partitioning \n" ); + //libblis_test_fprintf_c( os, " jc/ic loops %s\n", "slab" ); + libblis_test_fprintf_c( os, " jr/ir loops %s\n", jrir_str ); + libblis_test_fprintf_c( os, "\n" ); + + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "--- BLIS default implementations ---\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "level-3 implementations s d c z\n" ); + libblis_test_fprintf_c( os, " gemm %7s %7s %7s %7s\n", + bli_info_get_gemm_impl_string( BLIS_FLOAT ), + bli_info_get_gemm_impl_string( BLIS_DOUBLE ), + bli_info_get_gemm_impl_string( BLIS_SCOMPLEX ), + bli_info_get_gemm_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " hemm %7s %7s %7s %7s\n", + bli_info_get_hemm_impl_string( BLIS_FLOAT ), + bli_info_get_hemm_impl_string( BLIS_DOUBLE ), + bli_info_get_hemm_impl_string( BLIS_SCOMPLEX ), + bli_info_get_hemm_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " herk %7s %7s %7s %7s\n", + bli_info_get_herk_impl_string( BLIS_FLOAT ), + bli_info_get_herk_impl_string( BLIS_DOUBLE ), + bli_info_get_herk_impl_string( BLIS_SCOMPLEX ), + bli_info_get_herk_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " her2k %7s %7s %7s %7s\n", + bli_info_get_her2k_impl_string( BLIS_FLOAT ), + bli_info_get_her2k_impl_string( BLIS_DOUBLE ), + bli_info_get_her2k_impl_string( BLIS_SCOMPLEX ), + bli_info_get_her2k_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " symm %7s %7s %7s %7s\n", + bli_info_get_symm_impl_string( BLIS_FLOAT ), + bli_info_get_symm_impl_string( BLIS_DOUBLE ), + bli_info_get_symm_impl_string( BLIS_SCOMPLEX ), + bli_info_get_symm_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " syrk %7s %7s %7s %7s\n", + bli_info_get_syrk_impl_string( BLIS_FLOAT ), + bli_info_get_syrk_impl_string( BLIS_DOUBLE ), + bli_info_get_syrk_impl_string( BLIS_SCOMPLEX ), + bli_info_get_syrk_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " syr2k %7s %7s %7s %7s\n", + bli_info_get_syr2k_impl_string( BLIS_FLOAT ), + bli_info_get_syr2k_impl_string( BLIS_DOUBLE ), + bli_info_get_syr2k_impl_string( BLIS_SCOMPLEX ), + bli_info_get_syr2k_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " trmm %7s %7s %7s %7s\n", + bli_info_get_trmm_impl_string( BLIS_FLOAT ), + bli_info_get_trmm_impl_string( BLIS_DOUBLE ), + bli_info_get_trmm_impl_string( BLIS_SCOMPLEX ), + bli_info_get_trmm_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " trmm3 %7s %7s %7s %7s\n", + bli_info_get_trmm3_impl_string( BLIS_FLOAT ), + bli_info_get_trmm3_impl_string( BLIS_DOUBLE ), + bli_info_get_trmm3_impl_string( BLIS_SCOMPLEX ), + bli_info_get_trmm3_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " trsm %7s %7s %7s %7s\n", + bli_info_get_trsm_impl_string( BLIS_FLOAT ), + bli_info_get_trsm_impl_string( BLIS_DOUBLE ), + bli_info_get_trsm_impl_string( BLIS_SCOMPLEX ), + bli_info_get_trsm_impl_string( BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, "\n" ); + + //bli_ind_disable_all(); + + bli_ind_oper_enable_only( BLIS_GEMM, BLIS_NAT, BLIS_SCOMPLEX ); + bli_ind_oper_enable_only( BLIS_GEMM, BLIS_NAT, BLIS_DCOMPLEX ); + + libblis_test_fprintf_c( os, "--- BLIS native implementation info ---\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, " c z \n" ); + libblis_test_fprintf_c( os, "complex implementation %7s %7s\n", + bli_ind_oper_get_avail_impl_string( BLIS_GEMM, BLIS_SCOMPLEX ), + bli_ind_oper_get_avail_impl_string( BLIS_GEMM, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, "\n" ); + + // Query a native context. + cntx = bli_gks_query_nat_cntx(); + + libblis_test_fprintf_c( os, "level-3 blocksizes s d c z \n" ); + libblis_test_fprintf_c( os, " mc %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_MC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_MC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_MC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_MC, cntx ) ); + libblis_test_fprintf_c( os, " kc %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_KC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_KC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_KC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_KC, cntx ) ); + libblis_test_fprintf_c( os, " nc %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_NC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_NC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_NC, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_NC, cntx ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, " mc maximum %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_FLOAT, BLIS_MC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DOUBLE, BLIS_MC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_MC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_MC, cntx ) ); + libblis_test_fprintf_c( os, " kc maximum %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_FLOAT, BLIS_KC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DOUBLE, BLIS_KC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_KC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_KC, cntx ) ); + libblis_test_fprintf_c( os, " nc maximum %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_FLOAT, BLIS_NC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DOUBLE, BLIS_NC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_NC, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_NC, cntx ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, " mr %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_MR, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_MR, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_MR, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_MR, cntx ) ); + libblis_test_fprintf_c( os, " nr %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_NR, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_NR, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_NR, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_NR, cntx ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, " mr packdim %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_FLOAT, BLIS_MR, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DOUBLE, BLIS_MR, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_MR, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_MR, cntx ) ); + libblis_test_fprintf_c( os, " nr packdim %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_FLOAT, BLIS_NR, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DOUBLE, BLIS_NR, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_NR, cntx ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_NR, cntx ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "micro-kernel types s d c z\n" ); + libblis_test_fprintf_c( os, " gemm %7s %7s %7s %7s\n", + bli_info_get_gemm_ukr_impl_string( BLIS_NAT, BLIS_FLOAT ), + bli_info_get_gemm_ukr_impl_string( BLIS_NAT, BLIS_DOUBLE ), + bli_info_get_gemm_ukr_impl_string( BLIS_NAT, BLIS_SCOMPLEX ), + bli_info_get_gemm_ukr_impl_string( BLIS_NAT, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " gemmtrsm_l %7s %7s %7s %7s\n", + bli_info_get_gemmtrsm_l_ukr_impl_string( BLIS_NAT, BLIS_FLOAT ), + bli_info_get_gemmtrsm_l_ukr_impl_string( BLIS_NAT, BLIS_DOUBLE ), + bli_info_get_gemmtrsm_l_ukr_impl_string( BLIS_NAT, BLIS_SCOMPLEX ), + bli_info_get_gemmtrsm_l_ukr_impl_string( BLIS_NAT, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " gemmtrsm_u %7s %7s %7s %7s\n", + bli_info_get_gemmtrsm_u_ukr_impl_string( BLIS_NAT, BLIS_FLOAT ), + bli_info_get_gemmtrsm_u_ukr_impl_string( BLIS_NAT, BLIS_DOUBLE ), + bli_info_get_gemmtrsm_u_ukr_impl_string( BLIS_NAT, BLIS_SCOMPLEX ), + bli_info_get_gemmtrsm_u_ukr_impl_string( BLIS_NAT, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " trsm_l %7s %7s %7s %7s\n", + bli_info_get_trsm_l_ukr_impl_string( BLIS_NAT, BLIS_FLOAT ), + bli_info_get_trsm_l_ukr_impl_string( BLIS_NAT, BLIS_DOUBLE ), + bli_info_get_trsm_l_ukr_impl_string( BLIS_NAT, BLIS_SCOMPLEX ), + bli_info_get_trsm_l_ukr_impl_string( BLIS_NAT, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " trsm_u %7s %7s %7s %7s\n", + bli_info_get_trsm_u_ukr_impl_string( BLIS_NAT, BLIS_FLOAT ), + bli_info_get_trsm_u_ukr_impl_string( BLIS_NAT, BLIS_DOUBLE ), + bli_info_get_trsm_u_ukr_impl_string( BLIS_NAT, BLIS_SCOMPLEX ), + bli_info_get_trsm_u_ukr_impl_string( BLIS_NAT, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "\n" ); + + libblis_test_fprintf_c( os, "--- BLIS induced implementation info ---\n" ); + libblis_test_fprintf_c( os, "\n" ); + + for ( i = 0; i < BLIS_NAT; ++i ) + { + im = (ind_t)i; + if ( params->ind_enable[ im ] == 0 ) continue; + + bli_ind_oper_enable_only( BLIS_GEMM, im, BLIS_SCOMPLEX ); + bli_ind_oper_enable_only( BLIS_GEMM, im, BLIS_DCOMPLEX ); + + //libblis_test_fprintf_c( os, " c z \n" ); + libblis_test_fprintf_c( os, " c z \n" ); + libblis_test_fprintf_c( os, "complex implementation %7s %7s\n", + bli_ind_oper_get_avail_impl_string( BLIS_GEMM, BLIS_SCOMPLEX ), + bli_ind_oper_get_avail_impl_string( BLIS_GEMM, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, "\n" ); + + // Query a native context. + cntx_c = bli_gks_query_ind_cntx( im, BLIS_SCOMPLEX ); + cntx_z = bli_gks_query_ind_cntx( im, BLIS_DCOMPLEX ); + + libblis_test_fprintf_c( os, "level-3 blocksizes c z \n" ); + libblis_test_fprintf_c( os, " mc %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_MC, cntx_c ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_MC, cntx_z ) ); + libblis_test_fprintf_c( os, " kc %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_KC, cntx_c ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_KC, cntx_z ) ); + libblis_test_fprintf_c( os, " nc %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_NC, cntx_c ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_NC, cntx_z ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, " mc maximum %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_MC, cntx_c ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_MC, cntx_z ) ); + libblis_test_fprintf_c( os, " kc maximum %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_KC, cntx_c ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_KC, cntx_z ) ); + libblis_test_fprintf_c( os, " nc maximum %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_NC, cntx_c ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_NC, cntx_z ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, " mr %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_MR, cntx_c ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_MR, cntx_z ) ); + libblis_test_fprintf_c( os, " nr %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_NR, cntx_c ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_NR, cntx_z ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, " mr packdim %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_MR, cntx_c ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_MR, cntx_z ) ); + libblis_test_fprintf_c( os, " nr packdim %7d %7d\n", + ( int )bli_cntx_get_blksz_max_dt( BLIS_SCOMPLEX, BLIS_NR, cntx_c ), + ( int )bli_cntx_get_blksz_max_dt( BLIS_DCOMPLEX, BLIS_NR, cntx_z ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "micro-kernel types c z\n" ); + libblis_test_fprintf_c( os, " gemm %7s %7s\n", + bli_info_get_gemm_ukr_impl_string( im, BLIS_SCOMPLEX ), + bli_info_get_gemm_ukr_impl_string( im, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " gemmtrsm_l %7s %7s\n", + bli_info_get_gemmtrsm_l_ukr_impl_string( im, BLIS_SCOMPLEX ), + bli_info_get_gemmtrsm_l_ukr_impl_string( im, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " gemmtrsm_u %7s %7s\n", + bli_info_get_gemmtrsm_u_ukr_impl_string( im, BLIS_SCOMPLEX ), + bli_info_get_gemmtrsm_u_ukr_impl_string( im, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " trsm_l %7s %7s\n", + bli_info_get_trsm_l_ukr_impl_string( im, BLIS_SCOMPLEX ), + bli_info_get_trsm_l_ukr_impl_string( im, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, " trsm_u %7s %7s\n", + bli_info_get_trsm_u_ukr_impl_string( im, BLIS_SCOMPLEX ), + bli_info_get_trsm_u_ukr_impl_string( im, BLIS_DCOMPLEX ) ); + libblis_test_fprintf_c( os, "\n" ); + + } + + bli_ind_disable_all(); + + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "--- BLIS misc. other info ---\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "level-2 cache blocksizes s d c z \n" ); + libblis_test_fprintf_c( os, " m dimension %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_M2, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_M2, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_M2, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_M2, cntx ) ); + libblis_test_fprintf_c( os, " n dimension %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_N2, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_N2, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_N2, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_N2, cntx ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "level-1f fusing factors s d c z \n" ); + libblis_test_fprintf_c( os, " axpyf %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_AF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_AF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_AF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_AF, cntx ) ); + libblis_test_fprintf_c( os, " dotxf %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_DF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_DF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_DF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_DF, cntx ) ); + libblis_test_fprintf_c( os, " dotxaxpyf %7d %7d %7d %7d\n", + ( int )bli_cntx_get_blksz_def_dt( BLIS_FLOAT, BLIS_XF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DOUBLE, BLIS_XF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_SCOMPLEX, BLIS_XF, cntx ), + ( int )bli_cntx_get_blksz_def_dt( BLIS_DCOMPLEX, BLIS_XF, cntx ) ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf( os, "\n" ); + + // Output the contents of the param struct. + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "--- BLIS test suite parameters ----------------------------\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf_c( os, "num repeats per experiment %u\n", params->n_repeats ); + libblis_test_fprintf_c( os, "num matrix storage schemes %u\n", params->n_mstorage ); + libblis_test_fprintf_c( os, "storage[ matrix ] %s\n", params->storage[ BLIS_TEST_MATRIX_OPERAND ] ); + libblis_test_fprintf_c( os, "num vector storage schemes %u\n", params->n_vstorage ); + libblis_test_fprintf_c( os, "storage[ vector ] %s\n", params->storage[ BLIS_TEST_VECTOR_OPERAND ] ); + libblis_test_fprintf_c( os, "mix all storage schemes? %u\n", params->mix_all_storage ); + libblis_test_fprintf_c( os, "test with aligned memory? %u\n", params->alignment ); + libblis_test_fprintf_c( os, "randomization method %u\n", params->rand_method ); + libblis_test_fprintf_c( os, "general stride spacing %u\n", params->gs_spacing ); + libblis_test_fprintf_c( os, "num datatypes %u\n", params->n_datatypes ); + libblis_test_fprintf_c( os, "datatype[0] %d (%c)\n", params->datatype[0], + params->datatype_char[0] ); + for( i = 1; i < params->n_datatypes; ++i ) + libblis_test_fprintf_c( os, " [%d] %d (%c)\n", i, params->datatype[i], + params->datatype_char[i] ); + libblis_test_fprintf_c( os, "mix domains for gemm? %u\n", params->mixed_domain ); + libblis_test_fprintf_c( os, "mix precisions for gemm? %u\n", params->mixed_precision ); + libblis_test_fprintf_c( os, "problem size: first to test %u\n", params->p_first ); + libblis_test_fprintf_c( os, "problem size: max to test %u\n", params->p_max ); + libblis_test_fprintf_c( os, "problem size increment %u\n", params->p_inc ); + libblis_test_fprintf_c( os, "complex implementations \n" ); + libblis_test_fprintf_c( os, " 3mh? %u\n", params->ind_enable[ BLIS_3MH ] ); + libblis_test_fprintf_c( os, " 3m1? %u\n", params->ind_enable[ BLIS_3M1 ] ); + libblis_test_fprintf_c( os, " 4mh? %u\n", params->ind_enable[ BLIS_4MH ] ); + libblis_test_fprintf_c( os, " 4m1b (4mb)? %u\n", params->ind_enable[ BLIS_4M1B ] ); + libblis_test_fprintf_c( os, " 4m1a (4m1)? %u\n", params->ind_enable[ BLIS_4M1A ] ); + libblis_test_fprintf_c( os, " 1m? %u\n", params->ind_enable[ BLIS_1M ] ); + libblis_test_fprintf_c( os, " native? %u\n", params->ind_enable[ BLIS_NAT ] ); + libblis_test_fprintf_c( os, "simulated app-level threads %u\n", params->n_app_threads ); + libblis_test_fprintf_c( os, "error-checking level %u\n", params->error_checking_level ); + libblis_test_fprintf_c( os, "reaction to failure %c\n", params->reaction_to_failure ); + libblis_test_fprintf_c( os, "output in matlab format? %u\n", params->output_matlab_format ); + libblis_test_fprintf_c( os, "output to stdout AND files? %u\n", params->output_files ); + libblis_test_fprintf_c( os, "api interface %s\n", api ); + libblis_test_fprintf_c( os, "permutation and combination %s\n", (params->dimf == 1) ? "yes" : "no" ); + libblis_test_fprintf_c( os, "alpha and beta combination %s\n", (params->nab == 0) ? "single value" : "multiple values" ); + libblis_test_fprintf_c( os, "integer bitexact test %s\n", (params->bitextf == 1) ? "enabled" : "disabled" ); + libblis_test_fprintf_c( os, "print cases %s\n", (params->passflag == 1) ? "all" : "only failures" ); + libblis_test_fprintf_c( os, "bit-reproducibility %s\n", (params->bitrp == 1) ? "enabled" : "disabled" ); + libblis_test_fprintf_c( os, "lpgemm memory-format order %s\n", (params->op_t == 'p') ? "no-reorder" : "reorder" ); + libblis_test_fprintf_c( os, "-----------------------------------------------------------\n" ); + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf( os, "\n" ); + +#ifndef BLIS_ENABLE_GEMM_MD + // Notify the user if mixed domain or mixed precision was requested. + if ( params->mixed_domain || params->mixed_precision ) + { + libblis_test_printf_error( "mixed domain and/or mixed precision testing requested, but building against BLIS without mixed datatype support.\n" ); + } +#endif + + // If mixed domain or mixed precision was requested, we disable all + // induced methods except 1m and native execution. + if ( params->mixed_domain || params->mixed_precision ) + { + ind_t im; + + for ( i = BLIS_IND_FIRST; i < BLIS_IND_LAST+1; ++i ) + { + im = (ind_t)i; + if ( im != BLIS_1M && im != BLIS_NAT ) + params->ind_enable[ im ] = 0; + } + } +} + +void libblis_test_output_op_struct( FILE* os, test_op_t* op, char* op_str ) +{ + + dimset_t dimset = op->dimset; + + if ( dimset == BLIS_TEST_DIMS_MNK ) { + libblis_test_fprintf_c( os, "%s m n k %d %d %d\n", op_str, + op->dim_spec[0], op->dim_spec[1], op->dim_spec[2] ); + } + else if ( dimset == BLIS_TEST_DIMS_MN ) { + libblis_test_fprintf_c( os, "%s m n %d %d\n", op_str, + op->dim_spec[0], op->dim_spec[1] ); + } + else if ( dimset == BLIS_TEST_DIMS_MK ) { + libblis_test_fprintf_c( os, "%s m k %d %d\n", op_str, + op->dim_spec[0], op->dim_spec[1] ); + } + else if ( dimset == BLIS_TEST_DIMS_M || + dimset == BLIS_TEST_DIMS_MF ) { + libblis_test_fprintf_c( os, "%s m %d\n", op_str, + op->dim_spec[0] ); + } + else if ( dimset == BLIS_TEST_DIMS_K ) { + libblis_test_fprintf_c( os, "%s k %d\n", op_str, + op->dim_spec[0] ); + } + else if ( dimset == BLIS_TEST_NO_DIMS ) { + // Do nothing. + } + else { + libblis_test_printf_error( "Invalid dimension combination.\n" ); + } + + if ( op->n_params > 0 ) + libblis_test_fprintf_c( os, "%s operand params %s\n", op_str, op->params ); + else + libblis_test_fprintf_c( os, "%s operand params %s\n", op_str, "(none)" ); + + libblis_test_fprintf_c( os, "\n" ); + libblis_test_fprintf( os, "\n" ); +} + +param_t libblis_test_get_param_type_for_char( char p_type ) +{ + param_t r_val; + + if ( p_type == 's' ) r_val = BLIS_TEST_PARAM_SIDE; + else if ( p_type == 'u' ) r_val = BLIS_TEST_PARAM_UPLO; + else if ( p_type == 'e' ) r_val = BLIS_TEST_PARAM_UPLODE; + else if ( p_type == 'h' ) r_val = BLIS_TEST_PARAM_TRANS; + else if ( p_type == 'c' ) r_val = BLIS_TEST_PARAM_CONJ; + else if ( p_type == 'd' ) r_val = BLIS_TEST_PARAM_DIAG; + else { + r_val = BLIS_TEST_PARAM_SIDE; + libblis_test_printf_error( "Invalid parameter character.\n" ); + } + + return r_val; +} + +operand_t libblis_test_get_operand_type_for_char( char o_type ) +{ + operand_t r_val; + + if ( o_type == 'm' ) r_val = BLIS_TEST_MATRIX_OPERAND; + else if ( o_type == 'v' ) r_val = BLIS_TEST_VECTOR_OPERAND; + else { + r_val = BLIS_TEST_MATRIX_OPERAND; + libblis_test_printf_error( "Invalid operand character.\n" ); + } + return r_val; +} + +unsigned int libblis_test_get_n_dims_from_dimset( dimset_t dimset ) +{ + + unsigned int n_dims; + + if ( dimset == BLIS_TEST_DIMS_MNK ) n_dims = 3; + else if ( dimset == BLIS_TEST_DIMS_MN ) n_dims = 2; + else if ( dimset == BLIS_TEST_DIMS_MK ) n_dims = 2; + else if ( dimset == BLIS_TEST_DIMS_M ) n_dims = 1; + else if ( dimset == BLIS_TEST_DIMS_MF ) n_dims = 1; + else if ( dimset == BLIS_TEST_DIMS_K ) n_dims = 1; + else if ( dimset == BLIS_TEST_NO_DIMS ) n_dims = 0; + else { + n_dims = 0; + libblis_test_printf_error( "Invalid dimension combination.\n" ); + } + + return n_dims; +} + +unsigned int libblis_test_get_n_dims_from_string( char* dims_str ) +{ + unsigned int n_dims; + char* cp; + + cp = dims_str; + + for ( n_dims = 0; *cp != '\0'; ++n_dims ) { + while ( isspace( *cp ) ) { + ++cp; + } + + while ( isdigit( *cp ) ) { + ++cp; + } + } + + return n_dims; +} + +dim_t libblis_test_get_dim_from_prob_size( int dim_spec, unsigned int p_size ) +{ + dim_t dim; + + if ( dim_spec < 0 ) + dim = p_size / bli_abs(dim_spec); + else + dim = dim_spec; + + return dim; +} + +void libblis_test_fill_param_strings( char* p_spec_str, + char** chars_for_param, + unsigned int n_params, + unsigned int n_param_combos, + char** pc_str ) +{ + unsigned int pci, pi, i; + unsigned int* counter; + unsigned int* n_vals_for_param; + + // Allocate an array that will store the number of parameter values + // for each parameter. + n_vals_for_param = ( unsigned int* ) malloc( n_params * sizeof( unsigned int ) ); + + // Fill n_vals_for_param[i] with the number of parameter values (chars) + // in chars_for_param[i] (this is simply the string length). + for ( i = 0; i < n_params; ++i ) { + if ( p_spec_str[i] == '?' ) + n_vals_for_param[i] = strlen( chars_for_param[i] ); + else + n_vals_for_param[i] = 1; + } + + // Allocate an array with one digit per parameter. We will use + // this array to keep track of our progress as we canonically move + // though all possible parameter combinations. + counter = ( unsigned int* ) malloc( n_params * sizeof( unsigned int ) ); + + // Initialize all values in c to zero. + for ( i = 0; i < n_params; ++i ) + counter[i] = 0; + + for ( pci = 0; pci < n_param_combos; ++pci ) { + // Iterate backwards through each parameter string we create, since we + // want to form (for example, if the parameters are transa and conjx: + // (1) nn, (2) nc, (3) cn, (4) cc, (5) tn, (6) tc, (7) hn, (8) hc. + for ( i = 0, pi = n_params - 1; i < n_params; --pi, ++i ) { + // If the current parameter character, p_spec_str[pi] is fixed (ie: if + // it is not '?'), then just copy it into the parameter combination + // string. Otherwise, map the current integer value in c to the + // corresponding character in char_for_param[pi]. + if ( p_spec_str[pi] != '?' ) + pc_str[pci][pi] = p_spec_str[pi]; + else + pc_str[pci][pi] = chars_for_param[ pi ][ counter[pi] ]; + } + + // Terminate the current parameter combination string. + pc_str[pci][n_params] = '\0'; + + // Only try to increment/carryover if this is NOT the last param + // combo. + if ( pci < n_param_combos - 1 ) { + // Increment the least-most significant counter. + counter[ n_params - 1 ]++; + + // Perform "carryover" if needed. + carryover( &counter[ n_params - 1 ], &n_vals_for_param[ n_params - 1 ], n_params ); + } + } + + // Free the temporary arrays. + free( counter ); + + // Free the array holding the number of parameter values for each + // parameter. + free( n_vals_for_param ); +} + +void carryover( unsigned int* c, + unsigned int* n_vals_for_param, + unsigned int n_params ) +{ + if ( n_params == 1 ) + return; + else { + if ( *c == *n_vals_for_param ) { + *c = 0; + *(c-1) += 1; + carryover( c-1, n_vals_for_param-1, n_params-1 ); + } + } +} + +void libblis_test_vobj_randomize( test_params_t* params, bool normalize, obj_t* x ) +{ + if( params->rand_method == BLIS_TEST_RAND_REAL_VALUES ) + bli_randv( x ); + else // if ( params->rand_method == BLIS_TEST_RAND_NARROW_POW2 ) + bli_randnv( x ); + + if( normalize ) + { + num_t dt = bli_obj_dt( x ); + num_t dt_r = bli_obj_dt_proj_to_real( x ); + obj_t kappa; + obj_t kappa_r; + + bli_obj_scalar_init_detached( dt, &kappa ); + bli_obj_scalar_init_detached( dt_r, &kappa_r ); + + // Normalize vector elements. The following code ensures that we + // always invert-scale by whole power of two. + bli_normfv( x, &kappa_r ); + libblis_test_ceil_pow2( &kappa_r ); + bli_copysc( &kappa_r, &kappa ); + bli_invertsc( &kappa ); + bli_scalv( &kappa, x ); + } +} + +void libblis_test_mobj_randomize( test_params_t* params, bool normalize, obj_t* a ) +{ + if ( params->rand_method == BLIS_TEST_RAND_REAL_VALUES ) + bli_randm( a ); + else // if ( params->rand_method == BLIS_TEST_RAND_NARROW_POW2 ) + bli_randnm( a ); + + if ( normalize ) + { + num_t dt = bli_obj_dt( a ); + num_t dt_r = bli_obj_dt_proj_to_real( a ); + obj_t kappa; + obj_t kappa_r; + + bli_obj_scalar_init_detached( dt, &kappa ); + bli_obj_scalar_init_detached( dt_r, &kappa_r ); + + // Normalize matrix elements. + bli_norm1m( a, &kappa_r ); + libblis_test_ceil_pow2( &kappa_r ); + bli_copysc( &kappa_r, &kappa ); + bli_invertsc( &kappa ); + bli_scalm( &kappa, a ); + } +} + +void libblis_test_ceil_pow2( obj_t* alpha ) +{ + double alpha_r; + double alpha_i; + + bli_getsc( alpha, &alpha_r, &alpha_i ); + + alpha_r = pow( 2.0, ceil( log2( alpha_r ) ) ); + + bli_setsc( alpha_r, alpha_i, alpha ); +} + +void libblis_test_mobj_load_diag( test_params_t* params, obj_t* a ) +{ + // We assume that all elements of a were intialized on interval [-1,1]. + + // Load the diagonal by 2.0. + bli_shiftd( &BLIS_TWO, a ); +} + +void libblis_test_build_filename_string( const char* prefix_str, + char* op_str, + char* funcname_str ) +{ + sprintf( funcname_str, "%s_%s.m", prefix_str, op_str ); +} + +void libblis_test_fopen_check_stream( char* filename_str, + FILE* stream ) +{ + // Check for success. + if ( stream == NULL ) + { + libblis_test_printf_error( "Failed to open file %s. Check existence (if file is being read), permissions (if file is being overwritten), and/or storage limit.\n", + filename_str ); + } +} + +void libblis_test_fopen_ofile( char* op_str, iface_t iface, FILE** output_stream ) +{ + char filename_str[ MAX_FILENAME_LENGTH ]; + + if ( iface == BLIS_TEST_MT_FRONT_END ) + bli_check_error_code( BLIS_NOT_YET_IMPLEMENTED ); + + // Construct a filename string for the current operation. + libblis_test_build_filename_string( BLIS_FILE_PREFIX_STR, + op_str, + filename_str ); + + // Open the output file (overwriting a previous instance, if it exists) + // for writing (in binary mode). + *output_stream = fopen( filename_str, "wb" ); + + // Check the output stream and report an error if something went wrong. + libblis_test_fopen_check_stream( filename_str, *output_stream ); +} + +void libblis_test_fclose_ofile( FILE* output_stream ) +{ + fclose( output_stream ); +} + +void libblis_test_read_next_line( char* buffer, FILE* input_stream ) +{ + char temp[ INPUT_BUFFER_SIZE ]; + + // We want to read at least one line, so we use a do-while loop. + do { + // Read the next line into a temporary buffer and check success. + if ( fgets( temp, INPUT_BUFFER_SIZE-1, input_stream ) == NULL ) { + if ( feof( input_stream ) ) + libblis_test_printf_error( "Error reading input file: encountered unexpected EOF." ); + else + libblis_test_printf_error( "Error (non-EOF) reading input file." ); + } + // We continue to read lines into buffer until the line is neither + // commented nor blank. + }while ( temp[0] == INPUT_COMMENT_CHAR || temp[0] == '\n' || + temp[0] == ' ' || temp[0] == '\t' ); + + // Save the string in temp, up to first white space character, into buffer. + //sscanf( temp, "%s ", buffer ); + strcpy( buffer, temp ); + + //printf( "libblis_test_read_next_line() read: %s\n", buffer ); +} + +void libblis_test_fprintf( FILE* output_stream, const char* message, ... ) +{ + va_list args; + + // Initialize variable argument environment. + va_start( args, message ); + + // Parse the received message and print its components. + libblis_test_parse_message( output_stream, message, args ); + + // Shutdown variable argument environment and clean up stack. + va_end( args ); + + // Flush the output stream. + fflush( output_stream ); +} + +void libblis_test_fprintf_c( FILE* output_stream, const char* message, ... ) +{ + va_list args; + + fprintf( output_stream, "%c ", OUTPUT_COMMENT_CHAR ); + + // Initialize variable argument environment. + va_start( args, message ); + + // Parse the received message and print its components. + libblis_test_parse_message( output_stream, message, args ); + + // Shutdown variable argument environment and clean up stack. + va_end( args ); + + // Flush the output stream. + fflush( output_stream ); +} + +void libblis_test_printf_info( const char* message, ... ) +{ + FILE* output_stream = stdout; + va_list args; + + // Initialize variable argument environment. + va_start( args, message ); + + // Parse the received message and print its components. + libblis_test_parse_message( output_stream, message, args ); + + // Shutdown variable argument environment and clean up stack. + va_end( args ); + + // Flush the output stream. + fflush( output_stream ); +} + +void libblis_test_printf_infoc( const char* message, ... ) +{ + FILE* output_stream = stdout; + va_list args; + + fprintf( output_stream, "%c ", OUTPUT_COMMENT_CHAR ); + + // Initialize variable argument environment. + va_start( args, message ); + + // Parse the received message and print its components. + libblis_test_parse_message( output_stream, message, args ); + + // Shutdown variable argument environment and clean up stack. + va_end( args ); + + // Flush the output stream. + fflush( output_stream ); +} + +void libblis_test_printf_error( const char* message, ... ) +{ + FILE* output_stream = stderr; + va_list args; + + fprintf( output_stream, "%s: *** error ***: ", libblis_test_binary_name ); + + // Initialize variable argument environment. + va_start( args, message ); + + // Parse the received message and print its components. + libblis_test_parse_message( output_stream, message, args ); + + // Shutdown variable argument environment and clean up stack. + va_end( args ); + + // Flush the output stream. + fflush( output_stream ); + + // Exit. + exit(1); +} + +void libblis_test_parse_message( FILE* output_stream, const char* message, va_list args ) +{ + int c, cf; + char format_spec[8]; + unsigned int the_uint; + int the_int; + double the_double; + char* the_string; + char the_char; + + // Begin looping over message to insert variables wherever there are + // format specifiers. + for ( c = 0; message[c] != '\0'; ) { + if ( message[c] != '%' ) { + fprintf( output_stream, "%c", message[c] ); + c += 1; + } + else if ( message[c] == '%' && message[c+1] == '%' ) {// handle escaped '%' chars. + fprintf( output_stream, "%c", message[c] ); + c += 2; + } + else { + // Save the format string if there is one. + format_spec[0] = '%'; + for ( c += 1, cf = 1; strchr( "udefsc", message[c] ) == NULL; ++c, ++cf ) { + format_spec[cf] = message[c]; + } + + // Add the final type specifier, and null-terminate the string. + format_spec[cf] = message[c]; + format_spec[cf+1] = '\0'; + + // Switch based on type, since we can't predict what will + // va_args() will return. + switch ( message[c] ) { + case 'u': + the_uint = va_arg( args, unsigned int ); + fprintf( output_stream, format_spec, the_uint ); + break; + + case 'd': + the_int = va_arg( args, int ); + fprintf( output_stream, format_spec, the_int ); + break; + + case 'e': + the_double = va_arg( args, double ); + fprintf( output_stream, format_spec, the_double ); + break; + + case 'f': + the_double = va_arg( args, double ); + fprintf( output_stream, format_spec, the_double ); + break; + + case 's': + the_string = va_arg( args, char* ); + fprintf( output_stream, format_spec, the_string ); + break; + + case 'c': + the_char = va_arg( args, int ); + fprintf( output_stream, "%c", the_char ); + break; + } + + // Move to next character past type specifier. + c += 1; + } + } +} + +void libblis_test_check_empty_problem( obj_t* c, double* resid ) +{ + if ( bli_obj_has_zero_dim( c ) ) { + *resid = 0.0; + } +} + +bool libblis_test_op_is_done( test_op_t* op ) +{ + return op->test_done; +} + +int libblis_test_op_is_disabled( test_op_t* op ) +{ + int r_val; + + // If there was at least one individual override, then an op test is + // disabled if it is NOT equal to ENABLE_ONLY. If there were no + // individual overrides, then an op test is disabled if it is equal + // to DISABLE. + if ( op->ops->indiv_over == TRUE ) { + if ( op->op_switch != ENABLE_ONLY ) + r_val = TRUE; + else + r_val = FALSE; + } + else {// if ( op->ops->indiv_over == FALSE ) + if ( op->op_switch == DISABLE ) + r_val = TRUE; + else + r_val = FALSE; + } + return r_val; +} + +char* libblis_test_get_result(double resid, const thresh_t* thresh, + char* dc_str, test_params_t* params ) { + char* r_val; + num_t dt; + bli_param_map_char_to_blis_dt(dc_str[0], &dt ); + + if(params->bitextf == 1 ) { + r_val = libblis_test_pass_string; + double dmx = 0.0; + double dmn = 0.0; + switch( dt ) { + case BLIS_FLOAT : + case BLIS_SCOMPLEX : + { + dmx = (double)(std::numeric_limits::max)();; + dmn = (double)(std::numeric_limits::min)();; + break; + } + case BLIS_DOUBLE : + case BLIS_DCOMPLEX : + { + dmx = (std::numeric_limits::max)(); + dmn = (std::numeric_limits::min)(); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + + if( params->oruflw == BLIS_OVERFLOW ) { + if(( bli_isnan( resid ) || bli_isinf( resid ) || + ( resid > dmx )) && ( resid != 0.0 )) + { + r_val = libblis_test_overflow_string; + } + } + else if( params->oruflw == BLIS_UNDERFLOW ) { + if(( bli_isnan( resid ) || bli_isinf( resid ) || + ( resid < dmn )) && ( resid != 0.0 )) + { + r_val = libblis_test_underflow_string; + } + } + else { /* params->oruflw == BLIS_DEFAULT */ + if ( resid != 0 ) r_val = libblis_test_fail_string; + else r_val = libblis_test_pass_string; + } + } + else if ( bli_isnan( resid ) || bli_isinf( resid ) ) { + r_val = libblis_test_fail_string; + } + else { + // Check the result against the thresholds. + if ( resid > thresh[dt].failwarn ) r_val = libblis_test_fail_string; + else if ( resid > thresh[dt].warnpass ) r_val = libblis_test_warn_string; + else r_val = libblis_test_pass_string; + } + return r_val; +} + +bool libblis_test_get_string_for_result( double resid, num_t dt, + const thresh_t* thresh, char *r_val ) { + bool res; + // Before checking against the thresholds, make sure the residual is + // neither NaN nor Inf. (Note that bli_isnan() and bli_isinf() are + // both simply wrappers to the isnan() and isinf() macros defined + // defined in math.h.) + if ( bli_isnan( resid ) || bli_isinf( resid ) ) { + r_val = libblis_test_fail_string; + res = false; + } + else { + // Check the result against the thresholds. + if ( resid > thresh[dt].failwarn ) { + r_val = libblis_test_fail_string; + res = false; + } + else if ( resid > thresh[dt].warnpass ) { + r_val = libblis_test_warn_string; + res = true; + } + else { + r_val = libblis_test_pass_string; + res = true; + } + } + return res; +} + +int libblis_test_util_is_disabled( test_op_t* op ) { + if ( op->ops->util_over == DISABLE ) + return TRUE; + else + return FALSE; +} + +int libblis_test_l1v_is_disabled( test_op_t* op ) { + if ( op->ops->l1v_over == DISABLE ) + return TRUE; + else + return FALSE; +} + +int libblis_test_l1m_is_disabled( test_op_t* op ) { + if ( op->ops->l1m_over == DISABLE ) + return TRUE; + else + return FALSE; +} + +int libblis_test_l1f_is_disabled( test_op_t* op ) { + if ( op->ops->l1f_over == DISABLE ) + return TRUE; + else + return FALSE; +} + +int libblis_test_l2_is_disabled( test_op_t* op ) +{ + if( op->ops->l2_over == DISABLE ) + return TRUE; + else + return FALSE; +} + +int libblis_test_l3ukr_is_disabled( test_op_t* op ) +{ + if( op->ops->l3ukr_over == DISABLE ) + return TRUE; + else + return FALSE; +} + +int libblis_test_l3_is_disabled( test_op_t* op ) +{ + if( op->ops->l3_over == DISABLE ) + return TRUE; + else + return FALSE; +} + +// --- +int libblis_test_dt_str_has_sp_char_str( int n, char* str ) +{ + for ( int i = 0 ; i < n ; ++i ) + { + if ( str[i] == 's' || str[i] == 'c' ) + return TRUE; + } + return FALSE; +} + +int libblis_test_dt_str_has_sp_char( test_params_t* params ) +{ + return libblis_test_dt_str_has_sp_char_str( params->n_datatypes, + params->datatype_char ); +} + +// --- +int libblis_test_dt_str_has_dp_char_str( int n, char* str ) +{ + for ( int i = 0 ; i < n ; ++i ) + { + if ( str[i] == 'd' || str[i] == 'z' ) + return TRUE; + } + return FALSE; +} + +int libblis_test_dt_str_has_dp_char( test_params_t* params ) +{ + return libblis_test_dt_str_has_dp_char_str( params->n_datatypes, + params->datatype_char ); +} + +// --- +int libblis_test_dt_str_has_rd_char_str( int n, char* str ) +{ + for ( int i = 0; i < n; ++i ) + { + if ( str[i] == 's' || str[i] == 'd' ) + return TRUE; + } + return FALSE; +} + +int libblis_test_dt_str_has_rd_char( test_params_t* params ) { + return libblis_test_dt_str_has_rd_char_str( params->n_datatypes, + params->datatype_char ); +} + +// --- +int libblis_test_dt_str_has_cd_char_str( int n, char* str ) +{ + for ( int i = 0; i < n; ++i ) + { + if ( str[i] == 'c' || str[i] == 'z' ) + return TRUE; + } + return FALSE; +} + +int libblis_test_dt_str_has_cd_char( test_params_t* params ) +{ + return libblis_test_dt_str_has_cd_char_str( params->n_datatypes, + params->datatype_char ); +} + +// --- +unsigned int libblis_test_count_combos ( + unsigned int n_operands, + char* spec_str, + char** char_sets +) +{ + unsigned int n_combos = 1; + + for ( unsigned int i = 0; i < n_operands; ++i ) + { + if ( spec_str[i] == '?' ) + n_combos *= strlen( char_sets[i] ); + } + + return n_combos; +} + +char libblis_test_proj_dtchar_to_precchar( char dt_char ) +{ + char r_val = dt_char; + if ( r_val == 'c' ) + r_val = 's'; + else if( r_val == 'z' ) + r_val = 'd'; + + return r_val; +} + +//////////////////////////////////////////////////////////////////////// +#ifdef __GTESTSUITE_MALLOC_BUFFER__ +void libblis_test_alloc_buffer( obj_t* a ) +{ + dim_t n_elem = 0; + dim_t m, n; + siz_t elem_size; + siz_t buffer_size; + void* p; + inc_t rs,cs,is; + + bli_obj_free( a ); + + // Query the dimensions of the object we are allocating. + m = bli_obj_length( a ); + n = bli_obj_width( a ); + rs = bli_obj_row_stride( a ); + cs = bli_obj_col_stride( a ); + is = bli_obj_imag_stride( a ); + + // Query the size of one element. + elem_size = bli_obj_elem_size( a ); + + // Determine how much object to allocate. + if ( m == 0 || n == 0 ) + { + // For empty objects, set n_elem to zero. Row and column strides + // should remain unchanged (because alignment is not needed). + n_elem = 0; + } + else + { + // The number of elements to allocate is given by the distance from + // the element with the lowest address (usually {0, 0}) to the element + // with the highest address (usually {m-1, n-1}), plus one for the + // highest element itself. + n_elem = (m-1) * bli_abs( rs ) + (n-1) * bli_abs( cs ) + 1; + } + + // Handle the special case where imaginary stride is larger than + // normal. + if ( bli_obj_is_complex( a ) ) + { + // Notice that adding is/2 works regardless of whether the + // imaginary stride is unit, something between unit and + // 2*n_elem, or something bigger than 2*n_elem. + n_elem = bli_abs( is ) / 2 + n_elem; + } + + // Compute the size of the total buffer to be allocated, which includes + // padding if the leading dimension was increased for alignment purposes. + buffer_size = ( siz_t )n_elem * elem_size; + + // Allocate the buffer. + p = malloc( buffer_size ); + + // Set individual fields. + bli_obj_set_buffer( p, a ); + +} +#endif + +void libblis_test_obj_free( obj_t* x ) +{ +#ifdef __GTESTSUITE_MALLOC_BUFFER__ + void* p; + // Don't dereference obj if it is NULL. + if ( x != NULL ) + { + p = (void *)bli_obj_buffer( x ); + free( p ); + } +#else + bli_obj_free( x ); +#endif +} + +void libblis_test_vobj_create( test_params_t* params, num_t dt, char storage, + dim_t m, obj_t* x ) +{ + dim_t gs = params->gs_spacing; + + // Column vector (unit stride) + if ( storage == 'c' ) { + bli_obj_create( dt, m, 1, 1, m, x ); +#ifdef __GTESTSUITE_MALLOC_BUFFER__ + libblis_test_alloc_buffer( x ); +#endif + } + // Row vector (unit stride) + else if ( storage == 'r' ) { + bli_obj_create( dt, 1, m, m, 1, x ); +#ifdef __GTESTSUITE_MALLOC_BUFFER__ + libblis_test_alloc_buffer( x ); +#endif + } + // Column vector (non-unit stride) + else if ( storage == 'j' ) { + bli_obj_create( dt, m, 1, gs, gs*m, x ); +#ifdef __GTESTSUITE_MALLOC_BUFFER__ + libblis_test_alloc_buffer( x ); +#endif + } + // Row vector (non-unit stride) + else if ( storage == 'i' ) { + bli_obj_create( dt, 1, m, gs*m, gs, x ); +#ifdef __GTESTSUITE_MALLOC_BUFFER__ + libblis_test_alloc_buffer( x ); +#endif + } + else { + libblis_test_printf_error( "Invalid storage character: %c\n", storage ); + } + +} + +void libblis_test_mobj_create( test_params_t* params, num_t dt, trans_t trans, + char storage, dim_t m, dim_t n, obj_t* a ) { + + dim_t gs = params->gs_spacing; + bool alignment = params->alignment; + siz_t elem_size = bli_dt_size( dt ); + dim_t m_trans = m; + dim_t n_trans = n; + dim_t rs = 1; // Initialization avoids a compiler warning. + dim_t cs = 1; // Initialization avoids a compiler warning. + + // Apply the trans parameter to the dimensions (if needed). + bli_set_dims_with_trans( trans, m, n, &m_trans, &n_trans ); + + // Compute unaligned strides according to the storage case encoded in + // the storage char, and then align the leading dimension if alignment + // was requested. + if ( storage == 'c' ) + { + rs = 1; + cs = m_trans; + + if ( alignment ) + cs = bli_align_dim_to_size( cs, elem_size, + BLIS_HEAP_STRIDE_ALIGN_SIZE ); + } + else if ( storage == 'r' ) + { + rs = n_trans; + cs = 1; + + if ( alignment ) + rs = bli_align_dim_to_size( rs, elem_size, + BLIS_HEAP_STRIDE_ALIGN_SIZE ); + } + else if ( storage == 'g' ) + { + // We apply (arbitrarily) a column tilt, instead of a row tilt, to + // all general stride cases. + rs = gs; + cs = gs * m_trans; + + if ( alignment ) + cs = bli_align_dim_to_size( cs, elem_size, + BLIS_HEAP_STRIDE_ALIGN_SIZE ); + } + else + { + libblis_test_printf_error( "Invalid storage character: %c\n", storage ); + } + + // Create the object using the dimensions and strides computed above. + bli_obj_create( dt, m_trans, n_trans, rs, cs, a ); + +#ifdef __GTESTSUITE_MALLOC_BUFFER__ + libblis_test_alloc_buffer( a ); +#endif + +} + +double libblis_test_vector_check( test_params_t* params, obj_t* y ) +{ + double resid = 0.0; + num_t dt = bli_obj_dt( y ); + f77_int len = bli_obj_vector_dim( y ); + f77_int incy = bli_obj_vector_inc( y ); + + vflg_t flg = params->oruflw; + + switch( dt ) + { + case BLIS_FLOAT : + { + float* Y = (float*) bli_obj_buffer( y ); + resid = libblis_vector_check_real( flg, len, incy, Y ); + break; + } + case BLIS_DOUBLE : + { + double* Y = (double*) bli_obj_buffer( y ); + resid = libblis_vector_check_real( flg, len, incy, Y ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + resid = libblis_vector_check_cmplx( flg, len, incy, Y ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + resid = libblis_vector_check_cmplx( flg, len, incy, Y ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +double libblis_test_matrix_check( test_params_t* params, obj_t* c ) +{ + dim_t rsc, csc; + double resid = 0.0; + num_t dt = bli_obj_dt( c ); + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + + if( bli_obj_row_stride( c ) == 1 ) + { + rsc = 1; + csc = bli_obj_col_stride( c ); + } + else + { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + vflg_t flg = params->oruflw; + + switch( dt ) + { + case BLIS_FLOAT : + { + float* C = (float*) bli_obj_buffer( c ); + resid = libblis_matrix_check_real( flg, C, M, N, rsc, csc ); + break; + } + case BLIS_DOUBLE : + { + double* C = (double*) bli_obj_buffer( c ); + resid = libblis_matrix_check_real( flg, C, M, N, rsc, csc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* C = (scomplex*) bli_obj_buffer( c ); + resid = libblis_matrix_check_cmplx( flg, C, M, N, rsc, csc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* C = (dcomplex*) bli_obj_buffer( c ); + resid = libblis_matrix_check_cmplx( flg, C, M, N, rsc, csc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +double libblis_test_bitrp_vector( obj_t* x, obj_t* y, num_t dt ) +{ + double resid = 0.0; + f77_int len = bli_obj_vector_dim( x ); + f77_int incy = bli_obj_vector_inc( x ); + + switch( dt ) + { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y ); + resid = computediffrv( len, incy, X, Y ); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y ); + resid = computediffrv( len, incy, X, Y ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + resid = computediffiv( len, incy, X, Y ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + resid = computediffiv( len, incy, X, Y ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +double libblis_test_bitrp_matrix( obj_t* c, obj_t* r, num_t dt ) +{ + dim_t rsc, csc; + double resid = 0.0; + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + + if( bli_obj_row_stride( c ) == 1 ) + { + rsc = 1; + csc = bli_obj_col_stride( c ); + } + else + { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) + { + case BLIS_FLOAT : + { + float* C = (float*) bli_obj_buffer( c ); + float* R = (float*) bli_obj_buffer( r ); + resid = computediffrm( M, N, C, R, rsc, csc ); + break; + } + case BLIS_DOUBLE : + { + double* C = (double*) bli_obj_buffer( c ); + double* R = (double*) bli_obj_buffer( r ); + resid = computediffrm( M, N, C, R, rsc, csc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* C = (scomplex*) bli_obj_buffer( c ); + scomplex* R = (scomplex*) bli_obj_buffer( r ); + resid = computediffim( M, N, C, R, rsc, csc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* C = (dcomplex*) bli_obj_buffer( c ); + dcomplex* R = (dcomplex*) bli_obj_buffer( r ); + resid = computediffim( M, N, C, R, rsc, csc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +void conjugate_tensor( obj_t* aa, num_t dt ) +{ + dim_t rs, cs; + dim_t m = bli_obj_length( aa ); + dim_t n = bli_obj_width( aa ); + rs = bli_obj_row_stride( aa ) ; + cs = bli_obj_col_stride( aa ) ; + + switch( dt ) + { + case BLIS_FLOAT : + break; + case BLIS_DOUBLE : + break; + case BLIS_SCOMPLEX : + { + scomplex* aap = (scomplex*) bli_obj_buffer( aa ); + conjugatematrix( aap, m, n, rs, cs ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* aap = (dcomplex*) bli_obj_buffer( aa ); + conjugatematrix( aap, m, n, rs, cs ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return; +} diff --git a/gtestsuite/src/blis_utils.h b/gtestsuite/src/blis_utils.h new file mode 100644 index 000000000..0321cde42 --- /dev/null +++ b/gtestsuite/src/blis_utils.h @@ -0,0 +1,503 @@ +#ifndef BLIS_UTILS_H +#define BLIS_UTILS_H + +#include +#include + +#include "blis_test.h" + +using namespace std; + +#define abscomplex(x) (abs(x.real) + abs(x.imag)) + +#define mulr(x,y) (( x.real * y.real ) - ( x.imag * y.imag )) +#define muli(x,y) (( x.real * y.imag ) + ( x.imag * y.real )) + +#define ELD 8 +#define PAT32 0x78abcdef +#define PAT64 0x0123456789abcdef + +template +T real( T x ) +{ + T r = { 0.0, 0.0 }; + r.real = x.real; + r.imag = 0; + return r; +} + +template +T conjugate( T x ) +{ + T r = { 0.0, 0.0 }; + r.real = x.real; + r.imag = -(x.imag); + return r; +} + +template +T addc( T xx, T yy ) { + T r = { 0.0, 0.0 }; + r.real = xx.real + yy.real; + r.imag = xx.imag + yy.imag; + return r; +} + +template +T subc( T xx, T yy ) +{ + T r = { 0.0, 0.0 }; + r.real = xx.real - yy.real; + r.imag = xx.imag - yy.imag; + return r; +} + +template +T mulc( T xx, T yy ) +{ + T r = { 0.0, 0.0 }; + r.real = mulr( xx, yy ); + r.imag = muli( xx, yy ); + return r; +} + +template +T divc( T yy, T xx ) +{ + T r = { 0.0, 0.0 }; + U s = bli_fmaxabs( (xx.real),(xx.imag) ); + U xxrs = ( (xx.real)/s ); + U xxis = ( (xx.imag)/s ); + U deno = ( (xxrs * xx.real) + (xxis * xx.imag) ); + r.real = ( ((yy.real * xxrs) + (yy.imag * xxis))/deno ); + r.imag = ( ((yy.imag * xxrs) - (yy.real * xxis))/deno ); + return r; +} + +template +T divct( T yy, T xx ) +{ + T r = { 0.0, 0.0 }; + U deno = ( (xx.real * xx.real) + (xx.imag * xx.imag) ); + r.real = ( ((xx.real * yy.real) + (xx.imag * yy.imag))/deno ); + r.imag = ( ((yy.imag * xx.real) - (yy.real * xx.imag))/deno ); + return r; +} + +template +double computediffrv( dim_t len, dim_t incy, T *act, T *ref ) +{ + double resid = 0.0; + unsigned int j,jy = 0; + for( j = 0 ; j < len ; j++ ) + { + auto av = ref[jy]; + auto xc = act[jy]; + resid += xc - av; + jy = jy + incy; + } + return abs(resid); +} + +template +double computediffiv( dim_t len, dim_t incy, T *act, T *ref ) +{ + double resid = 0.0; + unsigned int j,jy = 0; + double rr,ri; + rr = ri = 0.0; + for( j = 0 ; j < len ; j++ ) + { + auto av = ref[jy]; + auto xc = act[jy]; + rr += xc.real - av.real; + ri += xc.imag - av.imag; + jy = jy + incy; + } + resid = rr + ri; + return abs(resid); +} + +template +double computediffrm( dim_t m,dim_t n, T *act, T *ref, dim_t rsc, dim_t csc ) +{ + double resid = 0.0; + unsigned int i,j; + for( i = 0 ; i < m ; i++ ) + { + for( j = 0 ; j < n ; j++ ) + { + auto av = ref[ i*rsc + j*csc ]; + auto xc = act[ i*rsc + j*csc ]; + resid += xc - av; + } + } + return abs(resid); +} + +template +double computediffim( dim_t m,dim_t n, T *act, T *ref, dim_t rsc, dim_t csc ) +{ + unsigned int i,j; + double rr,ri; + double resid = 0.0; + rr = ri = 0.0; + for( i = 0 ; i < m ; i++ ) + { + for( j = 0 ; j < n ; j++ ) + { + auto av = ref[ i*rsc + j*csc ]; + auto xc = act[ i*rsc + j*csc ]; + rr += xc.real - av.real; + ri += xc.imag - av.imag; + } + } + resid = rr + ri; + return abs(resid); +} + +template +double libblis_vector_check_real( vflg_t flg, dim_t len, dim_t incy, T *buf ) +{ + double resid = 0.0; + unsigned int j,jy=0; + T val = 0.0; + if(flg == BLIS_OVERFLOW) + { + val = (std::numeric_limits::max)(); + for( j = 0 ; j < len ; j++ ) + { + auto res = buf[jy]; + if((isnan(res)) || (fabs(res) > val)) + { + return abs(res); + } + jy = jy + incy; + } + } + else + { + val = (std::numeric_limits::min)(); + for( j = 0 ; j < len ; j++ ) { + auto res = buf[jy]; + if((isnan(res)) || (fabs(res) < val)) + { + return abs(res); + } + jy = jy + incy; + } + } + return resid; +} + +template +double libblis_vector_check_cmplx( vflg_t flg, dim_t len, dim_t incy, T *buf ) +{ + double resid = 0.0; + unsigned int j,jy=0; + U val = 0.0; + if(flg == BLIS_OVERFLOW) + { + val = (std::numeric_limits::max)(); + for( j = 0 ; j < len ; j++ ) + { + auto res = buf[jy]; + if((isnan(res.real) || (isnan(res.imag))) || + (fabs(res.real) > val) || (fabs(res.imag) > val)) + { + resid = (fabs(res.real) > fabs(res.imag)) ? res.real : res.imag; + return abs(resid); + } + jy = jy + incy; + } + } + else + { + val = (std::numeric_limits::min)(); + for( j = 0 ; j < len ; j++ ) + { + auto res = buf[jy]; + if((isnan(res.real) || (isnan(res.imag))) || + (fabs(res.real) < val) || (fabs(res.imag) < val)) + { + resid = (fabs(res.real) < fabs(res.imag)) ? res.imag : res.real; + return abs(resid); + } + jy = jy + incy; + } + } + return resid; +} + +template +double libblis_matrix_check_real( vflg_t flg, T* buf, dim_t m, dim_t n, + dim_t rsc, dim_t csc ) +{ + double resid = 0.0; + unsigned int i,j; + T val = 0.0; + if(flg == BLIS_OVERFLOW) + { + val = (std::numeric_limits::max)(); + for( i = 0 ; i < m ; i++ ) + { + for( j = 0 ; j < n ; j++ ) + { + auto res = buf[ i*rsc + j*csc ]; + if((isnan(res)) || (fabs(res) > val)) + { + return abs(res); + } + } + } + } + else + { + val = (std::numeric_limits::min)(); + for( i = 0 ; i < m ; i++ ) + { + for( j = 0 ; j < n ; j++ ) + { + auto res = buf[ i*rsc + j*csc ]; + if((isnan(res)) || (fabs(res) < val)) + { + return abs(res); + } + } + } + } + return resid; +} + +template +double libblis_matrix_check_cmplx(vflg_t flg, T* buf, dim_t m, dim_t n, + dim_t rsc, dim_t csc) +{ + double resid = 0.0; + unsigned int i,j; + U val = 0.0; + if(flg == BLIS_OVERFLOW) + { + val = (std::numeric_limits::max)(); + for( i = 0 ; i < m ; i++ ) + { + for( j = 0 ; j < n ; j++ ) + { + auto res = buf[ i*rsc + j*csc ]; + if((isnan(res.real) || (isnan(res.imag))) || + (fabs(res.real) > val) || (fabs(res.imag) > val)) + { + resid = (fabs(res.real) > fabs(res.imag)) ? res.real : res.imag; + return abs(resid); + } + } + } + } + else + { + val = (std::numeric_limits::min)(); + for( i = 0 ; i < m ; i++ ) + { + for( j = 0 ; j < n ; j++ ) + { + auto res = buf[ i*rsc + j*csc ]; + if((isnan(res.real) || (isnan(res.imag))) || + (fabs(res.real) < val) || (fabs(res.imag) < val)) + { + resid = (fabs(res.real) < fabs(res.imag)) ? res.imag : res.real; + return abs(resid); + } + } + } + } + return resid; +} + +template +void conjugatematrix(T* X, dim_t m, dim_t n, dim_t rs, dim_t cs) +{ + dim_t i,j; + for( i = 0 ; i < m ; i++ ) + { + for( j = 0 ; j < n ; j++ ) + { + X[i*rs + j*cs] = conjugate( X[i*rs + j*cs] ); + } + } + return; +} + + +template +void test_mmfill( T* dst, T* src, f77_int m, f77_int n, f77_int ld, T val ) +{ + f77_int i,j; + f77_int ldm = ld-ELD; + if( n == ldm ) + { + f77_int tmp; + tmp = n; + n = m; + m = tmp; + } + + for( j = 0 ; j < (n+ELD) ; j++ ) { + for( i = 0 ; i < (m+ELD) ; i++ ) { + dst[ i + j*ld ] = val; + } + } + + for( j = 0 ; j < n ; j++ ) { + for( i = 0 ; i < m ; i++ ) { + dst[ i + j*ld ] = src[ i + j*ldm ]; + } + } +/* + for( j = 0 ; j < n ; j++ ) { + for( i = m ; i < (m+ELD) ; i++ ) { + dst[ i + j*ld ] = val; + } + } + + for( j = n ; j < (n+ELD) ; j++ ) { + for( i = 0 ; i < (m+ELD) ; i++ ) { + dst[ i + j*ld ] = val; + } + } +*/ +} + +template +double test_mmchk( T* dst, f77_int m, f77_int n, f77_int ld, T val ) +{ + f77_int i,j; + f77_int ldm = ld-ELD; + + if( n == ldm ) + { + f77_int tmp; + tmp = n; + n = m; + m = tmp; + } + + for( j = 0 ; j < n ; j++ ) { + for( i = m ; i < (m+ELD) ; i++ ) { + if( dst[ i + j*ld ] != val ) { + cout << "Invalid Access" << endl; + return val; + } + } + } + + for( j = n ; j < (n+ELD) ; j++ ) { + for( i = 0 ; i < (m+ELD) ; i++ ) { + if( dst[ i + j*ld ] != val ) { + cout << "Invalid Access" << endl; + return val; + } + } + } + return 0; +} + +template +double test_mmchkc( T* dst, f77_int m, f77_int n, f77_int ld, U val ) +{ + f77_int i,j; + f77_int ldm = ld-ELD; + + if( n == ldm ) + { + f77_int tmp; + tmp = n; + n = m; + m = tmp; + } + + for( j = 0 ; j < n ; j++ ) { + for( i = m ; i < (m+ELD) ; i++ ) { + T tmp = dst[ i + j*ld ]; + if((tmp.real != val) ||(tmp.imag != val)) { + cout << "Invalid Access" << endl; + return val; + } + } + } + + for( j = n ; j < (n+ELD) ; j++ ) { + for( i = 0 ; i < (m+ELD) ; i++ ) { + T tmp = dst[ i + j*ld ]; + if((tmp.real != val) ||(tmp.imag != val)) { + cout << "Invalid Access" << endl; + return val; + } + } + } + return 0; +} + +void conjugate_tensor( obj_t* aa, num_t dt ); +void libblis_test_build_col_labels_string( test_params_t* params, + test_op_t* op, char* l_str ); +unsigned int libblis_test_get_n_dims_from_dimset( dimset_t dimset ) ; +void bli_param_map_char_to_blas_trans( char trans, trans_t* blas_trans ); +void bli_param_map_char_to_herk_trans( char trans, trans_t* herk_trans ); +void bli_param_map_char_to_syrk_trans( char trans, trans_t* syrk_trans ); +void libblis_test_fprintf( FILE* output_stream, const char* message, ... ); +ind_t ind_enable_get_str( test_params_t*, unsigned int d, unsigned int x, + test_op_t* op ); + +double libblis_test_vector_check( test_params_t* params, obj_t* y ); +double libblis_test_matrix_check( test_params_t* params, obj_t* y ); +double libblis_test_bitrp_vector( obj_t* c, obj_t* r, num_t dt ); +double libblis_test_bitrp_matrix( obj_t* c, obj_t* r, num_t dt ); +void libblis_test_mobj_irandomize( test_params_t* params, obj_t* x ); +void libblis_test_vobj_irandomize( test_params_t* params, obj_t* x ); +void test_fillbuffmem( obj_t* c, num_t dt ); +void test_fillbuffmem_diag( obj_t* c, num_t dt ); + +int libblis_test_dt_str_has_sp_char_str( int n, char* str ); +int libblis_test_dt_str_has_dp_char_str( int n, char* str ); +int libblis_test_dt_str_has_rd_char_str( int n, char* str ); + +void bli_map_blis_to_netlib_trans( trans_t trans, char* blas_trans ); +bool libblis_test_op_is_done( test_op_t* op ); +int libblis_test_l3_is_disabled( test_op_t* op ); +bool libblis_test_get_string_for_result( double resid, num_t dt, + const thresh_t* thresh, char *r_val ); + +void libblis_test_read_next_line( char* buffer, FILE* input_stream ); +void libblis_test_fopen_check_stream( char* filename_str, FILE* stream ); +void libblis_test_read_section_override( test_ops_t* ops, + FILE* input_stream, int* override ); +void libblis_test_read_op_info( test_ops_t* ops, FILE* input_stream, + opid_t opid, dimset_t dimset, unsigned int n_params, test_op_t* op ); +void libblis_test_output_section_overrides( FILE* os, test_ops_t* ops ); +void libblis_test_output_params_struct( FILE* os, test_params_t* params ); + +param_t libblis_test_get_param_type_for_char( char p_type ); +unsigned int libblis_test_count_combos ( unsigned int n_operands, char* spec_str, char** char_sets ); +void libblis_test_fill_param_strings( char* p_spec_str, char** chars_for_param, + unsigned int n_params, unsigned int n_param_combos, char** pc_str ); +operand_t libblis_test_get_operand_type_for_char( char o_type ) ; +int libblis_test_dt_str_has_rd_char( test_params_t* params ); +int libblis_test_dt_str_has_cd_char( test_params_t* params ); +int libblis_test_dt_str_has_sp_char( test_params_t* params ); +int libblis_test_dt_str_has_dp_char( test_params_t* params ); +char libblis_test_proj_dtchar_to_precchar( char dt_char ); + +void libblis_test_printf_error( const char* message, ... ); +void libblis_test_check_empty_problem( obj_t* c, double* resid ); +void libblis_test_mobj_create( test_params_t* params, num_t dt, trans_t trans, + char storage, dim_t m, dim_t n, obj_t* a ); +void libblis_test_vobj_create( test_params_t* params, num_t dt, + char storage, dim_t m, obj_t* x ); +void libblis_test_mobj_randomize( test_params_t* params, bool normalize, obj_t* a ); +void libblis_test_mobj_load_diag( test_params_t* params, obj_t* a ); +void libblis_test_vobj_randomize( test_params_t* params, bool normalize, obj_t* x ); + +void libblis_test_alloc_buffer( obj_t* a ); +void libblis_test_obj_free( obj_t* a ); + +#endif \ No newline at end of file diff --git a/gtestsuite/src/blis_utils_int.cpp b/gtestsuite/src/blis_utils_int.cpp new file mode 100644 index 000000000..17c479302 --- /dev/null +++ b/gtestsuite/src/blis_utils_int.cpp @@ -0,0 +1,625 @@ +#include +#include "blis_utils.h" + +//#define DEF_SRAND + +void bli_isrands( float* alpha ) +{ + /* 24*24*k < 23 bits max value to avoid + rounding off errors */ + int32_t a = ( int32_t ) (rand() % 4); + *alpha = ( float ) a ; +} + +void bli_idrands( double* alpha ) +{ + int64_t a = ( int64_t ) (rand() % 4); + *alpha = ( double ) a ; +} + +void bli_icrands( scomplex* alpha ) +{ + bli_isrands( &(alpha->real) ); + bli_isrands( &(alpha->imag) ); +} + +void bli_izrands( dcomplex* alpha ) +{ + bli_idrands( &(alpha->real) ); + bli_idrands( &(alpha->imag) ); +} + +void bli_israndv( int n, float* x, int incx ) +{ + float* chi; + int i; +#ifdef DEF_SRAND + srand(time(0)); +#endif + for ( i = 0; i < n; ++i ) { + chi = x + i*incx; + bli_isrands( chi ); + } +} + +void bli_idrandv( int n, double* x, int incx ) +{ + double* chi; + int i; +#ifdef DEF_SRAND + srand(time(0)); +#endif + for ( i = 0; i < n; ++i ) + { + chi = x + i*incx; + bli_idrands( chi ); + } +} + +void bli_icrandv( int n, scomplex* x, int incx ) +{ + scomplex* chi; + int i; +#ifdef DEF_SRAND + srand(time(0)); +#endif + for ( i = 0; i < n; ++i ) + { + chi = x + i*incx; + bli_icrands( chi ); + } +} + +void bli_izrandv( int n, dcomplex* x, int incx ) +{ + dcomplex* chi; + int i; +#ifdef DEF_SRAND + srand(time(0)); +#endif + for ( i = 0; i < n; ++i ) + { + chi = x + i*incx; + bli_izrands( chi ); + } +} + + +void bli_israndm(test_params_t* params, int m, int n, float* a, int a_rs, int a_cs ) +{ + float* a_begin, *x; + inc_t inca, lda; + inc_t n_iter; + inc_t n_elem; + int i,j; + + // Return early if possible. + if ( bli_zero_dim2( m, n ) ) return; + + // Initialize with optimal values for column-major storage. + inca = a_rs; + lda = a_cs; + n_iter = n; + n_elem = m; + + // An optimization: if A is row-major, then let's access the matrix by + // rows instead of by columns for increased spatial locality. + if ( bli_is_row_stored( a_rs, a_cs ) ) + { + bli_swap_incs( &n_iter, &n_elem ); + bli_swap_incs( &lda, &inca ); + } + + if(1) //if(params->oruflw == BLIS_DEFAULT) + { + for ( j = 0; j < n_iter; j++ ) + { + a_begin = a + j*lda; + bli_israndv( n_elem, a_begin, inca ); + } + } + else + { + float val; + val = (std::numeric_limits::max)(); + if(params->oruflw == BLIS_UNDERFLOW) + { + val = (std::numeric_limits::min)(); + } + for ( j = 0; j < n_iter; j++ ) + { + x = a + j*lda; + for ( i = 0; i < n_elem; ++i ) + { + x[i*inca] = val ; + } + } + } +} + +void bli_idrandm(test_params_t* params, int m, int n, double* a, int a_rs, int a_cs ) +{ + double* a_begin, *x; + inc_t inca, lda; + inc_t n_iter; + inc_t n_elem; + int i,j; + + // Return early if possible. + if ( bli_zero_dim2( m, n ) ) return; + + // Initialize with optimal values for column-major storage. + inca = a_rs; + lda = a_cs; + n_iter = n; + n_elem = m; + + // An optimization: if A is row-major, then let's access the matrix by + // rows instead of by columns for increased spatial locality. + if ( bli_is_row_stored( a_rs, a_cs ) ) + { + bli_swap_incs( &n_iter, &n_elem ); + bli_swap_incs( &lda, &inca ); + } + + if(1) //if(params->oruflw == BLIS_DEFAULT) + { + for ( j = 0; j < n_iter; j++ ) + { + a_begin = a + j*lda; + bli_idrandv( n_elem, a_begin, inca ); + } + } + else + { + double val; + val = (std::numeric_limits::max)(); + if(params->oruflw == BLIS_UNDERFLOW) + { + val = (std::numeric_limits::min)(); + } + for ( j = 0; j < n_iter; j++ ) { + x = a + j*lda; + for ( i = 0; i < n_elem; ++i ) { + x[i*inca] = val ; + } + } + } +} + +void bli_icrandm(test_params_t* params, int m, int n, scomplex* a, int a_rs, int a_cs ) +{ + scomplex* a_begin, *x; + inc_t inca, lda; + inc_t n_iter; + inc_t n_elem; + int i,j; + + // Return early if possible. + if ( bli_zero_dim2( m, n ) ) return; + + // Initialize with optimal values for column-major storage. + inca = a_rs; + lda = a_cs; + n_iter = n; + n_elem = m; + + // An optimization: if A is row-major, then let's access the matrix by + // rows instead of by columns for increased spatial locality. + if ( bli_is_row_stored( a_rs, a_cs ) ) + { + bli_swap_incs( &n_iter, &n_elem ); + bli_swap_incs( &lda, &inca ); + } + + if(1) //if(params->oruflw == BLIS_DEFAULT) + { + for ( j = 0; j < n_iter; j++ ) + { + a_begin = a + j*lda; + bli_icrandv( n_elem, a_begin, inca ); + } + } + else + { + float val; + val = (std::numeric_limits::max)(); + if(params->oruflw == BLIS_UNDERFLOW) + { + val = (std::numeric_limits::min)(); + } + scomplex cval = {val, val}; + for ( j = 0; j < n_iter; j++ ) + { + x = a + j*lda; + for ( i = 0; i < n_elem; ++i ) + { + x[i*inca] = cval ; + } + } + } +} + +void bli_izrandm(test_params_t* params, int m, int n, dcomplex* a, int a_rs, int a_cs ) { + dcomplex* a_begin, *x; + inc_t inca, lda; + inc_t n_iter; + inc_t n_elem; + int i,j; + + // Return early if possible. + if ( bli_zero_dim2( m, n ) ) return; + + // Initialize with optimal values for column-major storage. + inca = a_rs; + lda = a_cs; + n_iter = n; + n_elem = m; + + // An optimization: if A is row-major, then let's access the matrix by + // rows instead of by columns for increased spatial locality. + if ( bli_is_row_stored( a_rs, a_cs ) ) + { + bli_swap_incs( &n_iter, &n_elem ); + bli_swap_incs( &lda, &inca ); + } + + if(1) //if(params->oruflw == BLIS_DEFAULT) + { + for ( j = 0; j < n_iter; j++ ) + { + a_begin = a + j*lda; + bli_izrandv( n_elem, a_begin, inca ); + } + } + else + { + double val; + val = (std::numeric_limits::max)(); + if(params->oruflw == BLIS_UNDERFLOW) + { + val = (std::numeric_limits::min)(); + } + dcomplex cval = {val, val}; + for ( j = 0; j < n_iter; j++ ) + { + x = a + j*lda; + for ( i = 0; i < n_elem; ++i ) + { + x[i*inca] = cval ; + } + } + } +} + +void libblis_test_mobj_irandomize(test_params_t* params, obj_t* x ) +{ + num_t dt = bli_obj_dt( x ); + dim_t m = bli_obj_length( x ); + dim_t n = bli_obj_width( x ); + inc_t rs = bli_obj_row_stride( x ); + inc_t cs = bli_obj_col_stride( x ); + + switch( dt ) + { + case BLIS_FLOAT : + { + float *buff = ( float * ) bli_obj_buffer_at_off( x ); + bli_israndm(params, m, n, buff, rs, cs ); + break; + } + case BLIS_DOUBLE : + { + double *buff = ( double * ) bli_obj_buffer_at_off( x ); + bli_idrandm(params, m, n, buff, rs, cs ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex *buff = ( scomplex * ) bli_obj_buffer_at_off( x ); + bli_icrandm(params, m, n, buff, rs, cs ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex *buff = ( dcomplex * ) bli_obj_buffer_at_off( x ); + bli_izrandm(params, m, n, buff, rs, cs ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_test_vobj_irandomize(test_params_t* params, obj_t* x ) +{ + num_t dt = bli_obj_dt( x ); + dim_t n = bli_obj_vector_dim( x ); + inc_t inx = bli_obj_vector_inc( x ); + int i; + + switch( dt ) + { + case BLIS_FLOAT : + { + float *buff = ( float * ) bli_obj_buffer_at_off( x ); + if(1) //if(params->oruflw == BLIS_DEFAULT) + { + bli_israndv( n, buff, inx ); + } + else + { + float val; + if(params->oruflw == BLIS_OVERFLOW) + { + val = (std::numeric_limits::max)(); + } + else + { + val = (std::numeric_limits::min)(); + } + for ( i = 0; i < n; ++i ) + { + buff[i*inx] = val ; + } + } + break; + } + case BLIS_DOUBLE : + { + double *buff = ( double * ) bli_obj_buffer_at_off( x ); + if(1) //if(params->oruflw == BLIS_DEFAULT) + { + bli_idrandv( n, buff, inx ); + } + else + { + double val; + if(params->oruflw == BLIS_OVERFLOW) + { + val = (std::numeric_limits::max)(); + } + else + { + val = (std::numeric_limits::min)(); + } + for ( i = 0; i < n; ++i ) + { + buff[i*inx] = val ; + } + } + break; + } + case BLIS_SCOMPLEX : + { + scomplex *buff = ( scomplex * ) bli_obj_buffer_at_off( x );; + if(1) //if(params->oruflw == BLIS_DEFAULT) + { + bli_icrandv( n, buff, inx ); + } + else + { + float val; + if(params->oruflw == BLIS_OVERFLOW) + { + val = (std::numeric_limits::max)(); + } + else + { + val = (std::numeric_limits::min)(); + } + scomplex cval = {val, val}; + for ( i = 0; i < n; ++i ) + { + buff[i*inx] = cval ; + } + } + break; + } + case BLIS_DCOMPLEX : + { + dcomplex *buff = ( dcomplex * ) bli_obj_buffer_at_off( x ); + if(1) //if(params->oruflw == BLIS_DEFAULT) + { + bli_izrandv( n, buff, inx ); + } + else + { + double val; + if(params->oruflw == BLIS_OVERFLOW) + { + val = (std::numeric_limits::max)(); + } + else + { + val = (std::numeric_limits::min)(); + } + dcomplex cval = {val, val}; + for ( i = 0; i < n; ++i ) + { + buff[i*inx] = cval ; + } + } + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +template +void fillcbuff( dim_t rsc, dim_t csc, obj_t* c ) +{ + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + T* C = (T*) bli_obj_buffer( c ); + T Nan =(T)NAN; + + for( i = 0 ; i < M ; i++ ) + { + for( j = 0 ; j < N ; j++ ) + { + C[ i*rsc + j*csc ] = ( Nan ); + } + } + return; +} + +template +void fillicbuff ( dim_t rsc, dim_t csc, obj_t* c ) +{ + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + U* C = (U*) bli_obj_buffer( c ); + T Nan =(T)NAN; + + U tv = {0,0}; + tv.real = Nan; + tv.imag = Nan; + for( i = 0 ; i < M ; i++ ) + { + for( j = 0 ; j < N ; j++ ) + { + C[ i*rsc + j*csc ] = tv ; + } + } + return; +} + +void test_fillbuffmem(obj_t* c, num_t dt ) +{ + dim_t rsc, csc; + + if( bli_obj_row_stride( c ) == 1 ) + { + rsc = 1; + csc = bli_obj_col_stride( c ); + } + else + { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) + { + case BLIS_FLOAT : + { + fillcbuff( rsc, csc, c ); + break; + } + case BLIS_DOUBLE : + { + fillcbuff( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX : + { + fillicbuff( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX : + { + fillicbuff( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return ; +} + +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +template +void fillcbuff_diag( dim_t rsc, dim_t csc, obj_t* c ) +{ + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + T* C = (T*) bli_obj_buffer( c ); + T val = (T) 2.0; + + for( i = 0 ; i < M ; i++ ) + { + for( j = 0 ; j < N ; j++ ) + { + if(i == j) + { + C[ i*rsc + j*csc ] = ( val ); + } + } + } + return; +} + +template +void fillicbuff_diag ( dim_t rsc, dim_t csc, obj_t* c ) +{ + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + T* C = (T*) bli_obj_buffer( c ); + + T val = {2.0,2.0}; + for( i = 0 ; i < M ; i++ ) + { + for( j = 0 ; j < N ; j++ ) + { + if(i == j) + { + C[ i*rsc + j*csc ] = ( val ); + } + } + } + return; +} + +void test_fillbuffmem_diag( obj_t* c, num_t dt ) +{ + dim_t rsc, csc; + + if( bli_obj_row_stride( c ) == 1 ) + { + rsc = 1; + csc = bli_obj_col_stride( c ); + } + else + { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) + { + case BLIS_FLOAT : + { + fillcbuff_diag( rsc, csc, c ); + break; + } + case BLIS_DOUBLE : + { + fillcbuff_diag( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX : + { + fillicbuff_diag( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX : + { + fillicbuff_diag( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return ; +} +/////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gtestsuite/src/gtest_pthread.cpp b/gtestsuite/src/gtest_pthread.cpp new file mode 100644 index 000000000..4f70a9ad3 --- /dev/null +++ b/gtestsuite/src/gtest_pthread.cpp @@ -0,0 +1,62 @@ +#include "gtest_pthread.h" + +#if defined(BLIS_DISABLE_SYSTEM) + +#elif defined(_MSC_VER) // !defined(BLIS_DISABLE_SYSTEM) + +#include + +int gtest_pthread_create + ( + bli_pthread_t* thread, + const bli_pthread_attr_t* attr, + void* (*start_routine)(void*), + void* arg + ) +{ + if (attr) return EINVAL; + LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE )start_routine; + thread->handle = CreateThread(NULL, 0, func, arg, 0, NULL); + if ( !thread->handle ) return EAGAIN; + return 0; +} + +int gtest_pthread_join + ( + bli_pthread_t thread, + void** retval + ) +{ + return bli_pthread_join(thread, retval); +} + +#else // !defined(BLIS_DISABLE_SYSTEM) && !defined(_MSC_VER) + +// This branch defines a pthreads-like API, bli_pthreads_*(), and implements it +// in terms of the corresponding pthreads_*() types, macros, and function calls. +// This branch is compiled for Linux and other non-Windows environments where +// we assume that *some* implementation of pthreads is provided (although it +// may lack barriers--see below). + +// -- pthread_create(), pthread_join() -- + +int gtest_pthread_create + ( + bli_pthread_t* thread, + const bli_pthread_attr_t* attr, + void* (*start_routine)(void*), + void* arg + ) +{ + return bli_pthread_create( thread, attr, start_routine, arg ); +} + +int gtest_pthread_join + ( + bli_pthread_t thread, + void** retval + ) +{ + return bli_pthread_join( thread , retval ); +} +#endif // !defined(BLIS_DISABLE_SYSTEM) && !defined(_MSC_VER) diff --git a/gtestsuite/src/gtest_pthread.h b/gtestsuite/src/gtest_pthread.h new file mode 100644 index 000000000..0ebb8507f --- /dev/null +++ b/gtestsuite/src/gtest_pthread.h @@ -0,0 +1,29 @@ +#ifndef GTEST_PTHREAD_H +#define GTEST_PTHREAD_H + +#include "blis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int gtest_pthread_create + ( + bli_pthread_t* thread, + const bli_pthread_attr_t* attr, + void* (*start_routine)(void*), + void* arg + ); + + +int gtest_pthread_join + ( + bli_pthread_t thread, + void** retval + ); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/gtestsuite/src/gtest_suite.cpp b/gtestsuite/src/gtest_suite.cpp new file mode 100644 index 000000000..79d262eff --- /dev/null +++ b/gtestsuite/src/gtest_suite.cpp @@ -0,0 +1,2379 @@ +#include "blis_test.h" +#include "gtest_pthread.h" + +extern vector inputData; + +using namespace std; + +/*****************************Utility Operations******************************/ +TEST_P( AoclBlisTestFixture, AOCL_BLIS_RANDV ) +{ + unsigned int id = 0; + const char* op_str = "randv"; + const char* o_types = "v"; // x + const char* p_types = ""; // (no parameters) + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->randv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_randv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for randv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_RANDM ) +{ + unsigned int id = 0; + const char* op_str = "randm"; + const char* o_types = "m"; // a + const char* p_types = ""; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->randm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_randm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for randm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} +/********************* End Of Utility Operations *****************************/ + +/*****************************Level-1V Operations******************************/ +TEST_P( AoclBlisTestFixture, AOCL_BLIS_ADDV ) +{ + unsigned int id = 0; + const char* op_str = "addv"; + const char* o_types = "vv"; // x y + const char* p_types = "c"; // conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->addv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_addv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for addv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_AMAXV ) +{ + unsigned int id = 0; + const char* op_str = "amaxv"; + const char* o_types = "v"; // x + const char* p_types = ""; // (no parameters) + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->amaxv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_amaxv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for amaxv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_AXPBYV ) +{ + unsigned int id = 0; + const char* op_str = "axpbyv"; + const char* o_types = "vv"; // x y + const char* p_types = "c"; // conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->axpbyv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_axpbyv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for axpbyv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_AXPYV ) +{ + unsigned int id = 0; + const char* op_str = "axpyv"; + const char* o_types = "vv"; // x y + const char* p_types = "c"; // conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->axpyv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_axpyv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for axpyv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_COPYV ) +{ + unsigned int id = 0; + const char* op_str = "copyv"; + const char* o_types = "vv"; // x y + const char* p_types = "c"; // conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->copyv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_copyv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for copyv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_DOTV ) +{ + unsigned int id = 0; + const char* op_str = "dotv"; + const char* o_types = "vv"; // x y + const char* p_types = "cc"; // conjx conjy + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->dotv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_dotv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for dotv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); + } + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_DOTXV ) +{ + unsigned int id = 0; + const char* op_str = "dotxv"; + const char* o_types = "vv"; // x y + const char* p_types = "cc"; // conjx conjy + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->dotxv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_dotxv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for dotxv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_NORMFV ) +{ + unsigned int id = 0; + const char* op_str = "normfv"; + const char* o_types = "v"; // x + const char* p_types = ""; // (no parameters) + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->normfv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_normfv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for normfv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SCAL2V ) +{ + unsigned int id = 0; + const char* op_str = "scal2v"; + const char* o_types = "vv"; // x y + const char* p_types = "c"; // conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->scal2v); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_scal2v_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for scal2v : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); + } + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SCALV ) +{ + unsigned int id = 0; + const char* op_str = "scalv"; + const char* o_types = "v"; // x + const char* p_types = "c"; // conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->scalv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_scalv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for scalv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SETV ) +{ + unsigned int id = 0; + const char* op_str = "setv"; + const char* o_types = "v"; // x + const char* p_types = ""; // (no parameters) + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->setv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_setv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for setv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SUBV ) +{ + unsigned int id = 0; + const char* op_str = "subv"; + const char* o_types = "vv"; // x y + const char* p_types = "c"; // conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->subv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_subv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for subv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + /********************* End Of Level-1V Operations *****************************/ + + /*****************************Level-1F Operations******************************/ +TEST_P( AoclBlisTestFixture, AOCL_BLIS_XPBYV ) +{ + unsigned int id = 0; + const char* op_str = "xpbyv"; + const char* o_types = "vv"; // x y + const char* p_types = "c"; // conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->xpbyv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_xpbyv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for xpbyv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_AXPY2V ) +{ + unsigned int id = 0; + const char* op_str = "axpy2v"; + const char* o_types = "vvv"; // x y z + const char* p_types = "cc"; // conjx conjy + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->axpy2v); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_axpy2v_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for axpy2v : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_DOTAXPYV ) +{ + unsigned int id = 0; + const char* op_str = "dotaxpyv"; + const char* o_types = "vvv"; // x y z + const char* p_types = "ccc"; // conjxt conjx conjy + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->dotaxpyv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_dotaxpyv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for dotaxpyv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); + } + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_AXPYF ) +{ + unsigned int id = 0; + const char* op_str = "axpyf"; + const char* o_types = "mvv"; // A x y + const char* p_types = "cc"; // conja conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->axpyf); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_axpyf_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for axpyf : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_DOTXF ) +{ + unsigned int id = 0; + const char* op_str = "dotxf"; + const char* o_types = "mvv"; // A x y + const char* p_types = "cc"; // conjat conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->dotxf); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_dotxf_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for dotxf : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_DOTXAXPYF ) +{ + unsigned int id = 0; + const char* op_str = "dotxaxpyf"; + const char* o_types = "mvvvv"; // A w x y z + const char* p_types = "cccc"; // conjat conja conjw conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->dotxaxpyf); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_dotxaxpyf_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for dotxaxpyf : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); + } + /********************* End Of Level-1F Operations *****************************/ + + /*****************************Level-1M Operations******************************/ +TEST_P( AoclBlisTestFixture, AOCL_BLIS_ADDM ) +{ + unsigned int id = 0; + const char* op_str = "addm"; + const char* o_types = "mm"; // x y + const char* p_types = "h"; // transx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->addm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_addm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for addm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_AXPYM ) +{ + unsigned int id = 0; + const char* op_str = "axpym"; + const char* o_types = "mm"; // x y + const char* p_types = "h"; // transx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->axpym); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_axpym_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for axpym : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); + } + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_COPYM ) +{ + unsigned int id = 0; + const char* op_str = "copym"; + const char* o_types = "mm"; // x y + const char* p_types = "h"; // transx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->copym); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_copym_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for copym : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_NORMFM ) +{ + unsigned int id = 0; + const char* op_str = "normfm"; + const char* o_types = "m"; // x + const char* p_types = ""; // (no parameters) + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->normfm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_normfm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for normfm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SCAL2M ) +{ + unsigned int id = 0; + const char* op_str = "scal2m"; + const char* o_types = "mm"; // x y + const char* p_types = "h"; // transx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->scal2m); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_scal2m_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for scal2m : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SCALM ) +{ + unsigned int id = 0; + const char* op_str = "scalm"; + const char* o_types = "m"; // x + const char* p_types = "c"; // conjbeta + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->scalm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_scalm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for scalm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); + } + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SETM ) +{ + unsigned int id = 0; + const char* op_str = "setm"; + const char* o_types = "m"; // x + const char* p_types = ""; // (no parameters) + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->setm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_setm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for setm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SUBM ) +{ + unsigned int id = 0; + const char* op_str = "subm"; + const char* o_types = "mm"; // x y + const char* p_types = "h"; // transx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->subm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_subm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for subm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_XPBYM ) +{ + unsigned int id = 0; + const char* op_str = "xpbym"; + const char* o_types = "mm"; // x y + const char* p_types = "h"; // transx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->xpbym); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_xpbym_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for xpbym : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); + } + /********************* End Of Level-1M Operations *****************************/ + /* */ + /*****************************Level-2 Operations*******************************/ +TEST_P( AoclBlisTestFixture, AOCL_BLIS_GEMV ) +{ + unsigned int id = 0; + const char* op_str = "gemv"; + const char* o_types = "mvv"; // a x y + const char* p_types = "hc"; // transa conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_GER ) +{ + unsigned int id; + const char* op_str = "ger"; + const char* o_types = "vvm"; // x y a + const char* p_types = "cc"; // conjx conjy + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->ger); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_ger_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for ger : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_HEMV ) +{ + unsigned int id; + const char* op_str = "hemv"; + const char* o_types = "mvv"; // a x y + const char* p_types = "ucc"; // uploa conja conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->hemv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_hemv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for hemv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_L2HER ) +{ + unsigned int id; + const char* op_str = "her"; + const char* o_types = "vm"; // x a + const char* p_types = "uc"; // uploa conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->her); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_her_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for her : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_L2HER2 ) +{ + unsigned int id; + const char* op_str = "her2"; + const char* o_types = "vvm"; // x y a + const char* p_types = "ucc"; // uploa conjx conjy + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->her2); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_her2_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for her2 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SYMV ) +{ + unsigned int id; + const char* op_str = "symv"; + const char* o_types = "mvv"; // a x y + const char* p_types = "ucc"; // uploa conja conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->symv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_symv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for symv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_L2SYR ) +{ + unsigned int id; + const char* op_str = "syr"; + const char* o_types = "vm"; // x a + const char* p_types = "uc"; // uploa conjx + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->syr); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_syr_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for syr : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_L2SYR2 ) +{ + unsigned int id; + const char* op_str = "syr2"; + const char* o_types = "vvm"; // x y a + const char* p_types = "ucc"; // uploa conjx conjy + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->syr2); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_syr2_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for syr2 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_TRMV ) +{ + unsigned int id; + const char* op_str = "trmv"; + const char* o_types = "mv"; // a x + const char* p_types = "uhd"; // uploa transa diaga + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->trmv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_trmv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for trmv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_TRSV ) +{ + unsigned int id; + const char* op_str = "trsv"; + const char* o_types = "mv"; // a x + const char* p_types = "uhd"; // uploa transa diaga + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->trsv); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_trsv_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for trsv : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} +/********************* End Of Level-2 Operations *****************************/ +/* */ +/*****************************Level-3 Operations******************************/ +TEST_P( AoclBlisTestFixture, AOCL_BLIS_GEMM ) +{ + unsigned int id; + const char* op_str = "gemm"; + const char* o_types = "mmm"; // a b c + const char* p_types = "hh"; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_L3GEMMT ) +{ + unsigned int id; + const char* op_str = "gemmt"; + const char* o_types = "mmm"; // a b c + const char* p_types = "uhh"; // uploc transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemmt); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemmt_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemmt: %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_HEMM ) +{ + unsigned int id; + const char* op_str = "hemm"; + const char* o_types = "mmm"; // a b c + const char* p_types = "su"; // side uploa + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->hemm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_hemm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for hemm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_HERK ) +{ + unsigned int id; + const char* op_str = "herk"; + const char* o_types = "mm"; // a c + const char* p_types = "uc"; // uploc trans + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->herk); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_herk_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for herk : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_HER2K ) +{ + unsigned int id; + const char* op_str = "her2k"; + const char* o_types = "mmm"; // a b c + const char* p_types = "uc"; // uploc trans + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->her2k); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_her2k_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for her2k : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SYMM ) +{ + unsigned int id; + const char* op_str = "symm"; + const char* o_types = "mmm"; // a b c + const char* p_types = "su"; // side uploa + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->symm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_symm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for symm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SYRK ) +{ + unsigned int id; + const char* op_str = "syrk"; + const char* o_types = "mm"; // a c + const char* p_types = "uh"; // uploc trans + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->syrk); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_syrk_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for syrk : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_SYR2K ) +{ + unsigned int id; + const char* op_str = "syr2k"; + const char* o_types = "mmm"; // a b c + const char* p_types = "uh"; // uploc trans + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->syr2k); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_syr2k_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for syr2k : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_L3TRMM ) +{ + unsigned int id; + const char* op_str = "trmm"; + const char* o_types = "mm"; // a b + const char* p_types = "suhd"; // side uploa transa diaga + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->trmm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_trmm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for trmm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_TRMM3 ) +{ + unsigned int id; + const char* op_str = "trmm3"; + const char* o_types = "mmm"; // a b c + const char* p_types = "suhdh"; // side uploa transa diaga transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->trmm3); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_trmm3_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for trmm3 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_BLIS_TRSM ) +{ + unsigned int id; + const char* op_str = "trsm"; + const char* o_types = "mm"; // a b + const char* p_types = "suhd"; // side uploa transa diaga + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->trsm); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_trsm_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for trsm : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} +/********************* End Of Level-3 Operations *****************************/ +/* */ +/***************************** LPGEMM Operations *****************************/ +TEST_P( AoclBlisTestFixture, AOCL_GEMM_S32S32 ) +{ + unsigned int id; + const char* op_str = "gemm_u8s8s32os32"; + const char* o_types = "mmm"; // a b c + const char* p_types = "hh"; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemm_u8s8s32os32); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemm_u8s8s32os32_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemm_u8s8s32os32 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_GEMM_S8S32 ) +{ + unsigned int id; + const char* op_str = "gemm_u8s8s32os8"; + const char* o_types = "mmm"; // a b c + const char* p_types = "hh"; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemm_u8s8s32os8); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemm_u8s8s32os8_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemm_u8s8s32os8 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_GEMM_F32F32 ) +{ + unsigned int id; + const char* op_str = "gemm_f32f32f32of32"; + const char* o_types = "mmm"; // a b c + const char* p_types = "hh"; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemm_f32f32f32of32); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemm_f32f32f32of32_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemm_f32f32f32of32 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_GEMM_S8S16 ) +{ + unsigned int id; + const char* op_str = "gemm_u8s8s16os8"; + const char* o_types = "mmm"; // a b c + const char* p_types = "hh"; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemm_u8s8s16os8); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemm_u8s8s16os8_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemm_u8s8s16os8 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_GEMM_S16S16 ) +{ + unsigned int id; + const char* op_str = "gemm_u8s8s16os16"; + const char* o_types = "mmm"; // a b c + const char* p_types = "hh"; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemm_u8s8s16os16); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemm_u8s8s16os16_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemm_u8s8s16os16 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_GEMM_BF16BF16 ) +{ + unsigned int id; + const char* op_str = "gemm_bf16bf16f32obf16"; + const char* o_types = "mmm"; // a b c + const char* p_types = "hh"; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemm_bf16bf16f32obf16); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemm_bf16bf16f32obf16_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemm_bf16bf16f32obf16 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} + +TEST_P( AoclBlisTestFixture, AOCL_GEMM_F32BF16 ) +{ + unsigned int id; + const char* op_str = "gemm_bf16bf16f32of32"; + const char* o_types = "mmm"; // a b c + const char* p_types = "hh"; // transa transb + iface_t iface = BLIS_TEST_SEQ_FRONT_END; + test_op_t* op = &(ops->gemm_bf16bf16f32of32); + + libblis_test_preprocess_params( params, op, iface, p_types, o_types ); + + for( id = 0 ; id < nt ; id++ ) + { + tdata[id].params = params; + tdata[id].op = op; + tdata[id].str = op_str; + tdata[id].nt = nt; + tdata[id].id = id; + tdata[id].iface = iface; + tdata[id].xc = 0; + tdata[id].barrier = barrier; + tdata[id].pfr = pfr; + gtest_pthread_create( &pthread[id], NULL, + libblis_test_gemm_bf16bf16f32of32_thread_entry, + (void *)&tdata[id] ); + } + + // Thread 0 waits for additional threads to finish. + for( id = 0 ; id < nt ; id++ ) + { + gtest_pthread_join( pthread[id], NULL ); + } + + printf( "\n" ); + printf( "Total test cases for gemm_bf16bf16f32of32 : %d\n", pfr->tcnt ); + printf( "Total test cases passed : %d\n", (pfr->tcnt - pfr->cntf) ); + printf( "Total test cases failed : %d\n", pfr->cntf ); + + AoclBlisTestFixture::destroy_params( params ); +} +/********************* End Of Level-3 Operations *****************************/ +/* */ +/********************* FILE_READ from InputFile ******************************/ +TEST_P( AoclBlisTestFixture, AOCL_BLIS_READ_INPUTFILE ) +{ + AoclBlisTestFixture::create_params( params ); + + libblis_test_read_params_inpfile( pfile->inputfile, params, ops, pfr ); + + AoclBlisTestFixture::destroy_params( params ); +} +/******************************************************************************************/ +/* END OF OPERATIONS */ +/******************************************************************************************/ + + +/******************************************************************************************/ +/*** INSTANTIATE_TEST_SUITE_P ***/ +/******************************************************************************************/ +INSTANTIATE_TEST_SUITE_P( AoclBlisTests, + AoclBlisTestFixture, + ::testing::ValuesIn( inputData ) ); +/******************************************************************************************/ diff --git a/gtestsuite/src/lpgemm_utils.cpp b/gtestsuite/src/lpgemm_utils.cpp new file mode 100644 index 000000000..49af172cb --- /dev/null +++ b/gtestsuite/src/lpgemm_utils.cpp @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include +#include "lpgemm_utils.h" + +#ifdef BLIS_ENABLE_ADDONS + +bfloat16 mat_mul_accuracy_check_downscale_bf16( float temp_accum, bfloat16 out_temp_accum, + aocl_post_op* post_op, dim_t j) +{ + float_to_bf16( ( &temp_accum ), ( &out_temp_accum ) ); + return out_temp_accum; +} + +float bf16_to_float( bfloat16 bf16_val ) +{ + int32_t inter_temp = *( ( int16_t* ) &bf16_val ); + inter_temp = inter_temp << 16; + float float_value = *( float* ) ( &inter_temp ); + return float_value; +} + +float mat_mul_accuracy_check_accum_bf16 + ( + bfloat16* a, + bfloat16* b, + float* c_ref, + float temp_accum, + float alpha, + float beta, + dim_t rs_a, + dim_t rs_b, + dim_t cs_a, + dim_t cs_b, + dim_t rs_c_ref, + dim_t cs_c_ref, + dim_t i, + dim_t j, + dim_t k + ) +{ + for ( dim_t p = 0; p < k; ++p) + { + float a_float = bf16_to_float( *( a + i * rs_a + p * cs_a ) ); + float b_float = bf16_to_float( *( b + p * rs_b + j * cs_b ) ); + temp_accum += ( ( a_float ) * ( b_float ) ); + } + temp_accum = ( beta * ( * (c_ref + ( rs_c_ref * i ) + ( cs_c_ref * j ) ) ) ) + + ( alpha * temp_accum ); + return temp_accum; +} + +float mat_mul_accuracy_check_accum_bf16 + ( + bfloat16* a, + bfloat16* b, + bfloat16* c_ref, + float temp_accum, + float alpha, + float beta, + dim_t rs_a, + dim_t rs_b, + dim_t cs_a, + dim_t cs_b, + dim_t rs_c_ref, + dim_t cs_c_ref, + dim_t i, + dim_t j, + dim_t k + ) +{ + for ( dim_t p = 0; p < k; ++p) + { + float a_float = bf16_to_float( *( a + i*rs_a + p*cs_a ) ); + float b_float = bf16_to_float( *( b + p*rs_b + j*cs_b ) ); + temp_accum += ( ( a_float ) * ( b_float ) ); + } + float c_ref_float = bf16_to_float( *( c_ref + i*rs_c_ref + j*cs_c_ref ) ); + temp_accum = ( beta * ( c_ref_float ) ) + ( alpha * temp_accum ); + + return temp_accum; +} + +void lpgemm_destroy_post_ops_struct( aocl_post_op* post_ops ) +{ + if ( post_ops == NULL ) + { + return; + } + + if ( post_ops->eltwise.algo.alpha != NULL ) + { + free( post_ops->eltwise.algo.alpha ); + } + if ( post_ops->sum.scale_factor != NULL ) + { + free( post_ops->sum.scale_factor ); + } + if ( post_ops->bias.bias != NULL ) + { + free( post_ops->bias.bias ); + } + if( post_ops->seq_vector != NULL ) + { + free( post_ops->seq_vector ); + } + + free( post_ops ); +} +#endif \ No newline at end of file diff --git a/gtestsuite/src/lpgemm_utils.h b/gtestsuite/src/lpgemm_utils.h new file mode 100644 index 000000000..c90f421db --- /dev/null +++ b/gtestsuite/src/lpgemm_utils.h @@ -0,0 +1,481 @@ +#include +#include +#include +#include +#include + +#include "blis_test.h" + +#ifdef BLIS_ENABLE_ADDONS + +#define S8_MIN (-128) +#define S8_MAX (+127) + +static inline int max (int a, int b) +{ + return ( a > b ? a : b ); +} + +static inline int min (int a, int b) +{ + return ( a < b ? a : b ); +} + +template +void fill_array ( T* arr, dim_t size ) +{ + T* temp_arr = ( T* ) arr; + for ( dim_t i = 0; i < size; ++i ) + { + temp_arr[i] = ( T )( i % 10 ); + } +} + +template +void fill_array_post_ops( T* arr, dim_t size ) +{ + T* temp_arr = ( T* ) arr; + for ( dim_t i = 0; i < size; ++i ) + { + temp_arr[i] = ( T )( i % 20 ); + } +} + +static void float_to_bf16( float* float_value, bfloat16* bf16_val ) +{ + /*Set offset 2 to copy most significant 2 bytes of float + to convert float values to bf16 values*/ + memcpy( ( bf16_val ), (char *)( float_value ) + 2, sizeof ( bfloat16 ) ); +} + +static inline void convert_float_arr_to_bf16( float* array, bfloat16* array_bf16, int size ) +{ + for (int i = 0 ; i < size ; i++) + { + float_to_bf16( ( array + i ), ( array_bf16 + i ) ); + } +} + +/* Only supports bias followed by RELU and vice versa for now.*/ +template +aocl_post_op* lpgemm_create_post_ops_struct( dim_t m, dim_t n, + char* post_ops_str, bool dscale_out ) +{ + aocl_post_op* post_ops = NULL; + post_ops = ( aocl_post_op* ) malloc( sizeof( aocl_post_op ) ); + + if ( ( post_ops == NULL ) && ( dscale_out ) ) + { + return NULL; + } + + /* Only supporting 3 post ops at max for now.*/ + dim_t max_post_ops_seq_length = 3; + post_ops->seq_vector = ( AOCL_POST_OP_TYPE* ) + malloc( max_post_ops_seq_length * sizeof( AOCL_POST_OP_TYPE ) ); + + if ( post_ops->seq_vector == NULL ) + { + free( post_ops ); + return NULL; + } + + /* Parse post ops list.*/ + dim_t cur_op_index = 0; + /* Ensure the buffers that use NULL check in deinit code is properly set to NULL.*/ + post_ops->eltwise.algo.alpha = NULL; + post_ops->bias.bias = NULL; + post_ops->sum.scale_factor = NULL; + if ( post_ops_str != NULL ) + { + char* ops_tok = strtok(post_ops_str, ", " ); + bool is_param_relu = FALSE; + while ( ops_tok ) + { + if ( strcmp( ops_tok, "bias") == 0 ) + { + post_ops->seq_vector[cur_op_index] = BIAS; + } + else if ( strcmp( ops_tok, "relu") == 0 ) + { + post_ops->seq_vector[cur_op_index] = ELTWISE; + } + else if ( strcmp( ops_tok, "prelu") == 0 ) + { + post_ops->seq_vector[cur_op_index] = ELTWISE; + is_param_relu = TRUE; + } + ops_tok = strtok( NULL, ", " ); + cur_op_index++; + } + + /* Allocate bias buffer, return early if alloc fails.*/ + post_ops->bias.bias = malloc( n * sizeof( X ) ); + if ( post_ops->bias.bias == NULL ) + { + free( post_ops->seq_vector ); + free( post_ops ); + return NULL; + } + fill_array_post_ops((X*)post_ops->bias.bias, n ); + + post_ops->eltwise.is_power_of_2 = FALSE; + post_ops->eltwise.scale_factor = NULL; + post_ops->eltwise.algo.alpha = NULL; + post_ops->eltwise.algo.algo_type = RELU; + if ( is_param_relu == TRUE ) + { + post_ops->eltwise.algo.alpha = malloc( sizeof( X ) ); + *( ( X* ) post_ops->eltwise.algo.alpha ) = ( X )6; + post_ops->eltwise.algo.algo_type = PRELU; + } + post_ops->eltwise.algo.beta = NULL; + } + + if ( dscale_out ) + { + post_ops->seq_vector[cur_op_index] = SCALE; + cur_op_index++; + + post_ops->sum.is_power_of_2 = FALSE; + post_ops->sum.scale_factor = NULL; + post_ops->sum.buff = NULL; + post_ops->sum.zero_point = NULL; + if ( dscale_out ) + { + /* Allocate scale buffer, return early if alloc fails.*/ + post_ops->sum.scale_factor = malloc( n * sizeof( Z ) ); + if ( post_ops->sum.scale_factor == NULL ) + { + free ( post_ops->bias.bias ); + free( post_ops->seq_vector ); + free( post_ops ); + return NULL; + } + /* Fill scale factor.*/ + Z* temp_dscale_ptr = ( Z* )post_ops->sum.scale_factor; + for ( dim_t i = 0; i < n; ++i ) + { + temp_dscale_ptr[i] = ( ( Z )1 )/ ( ( Z )1000 ); + } + } + } + + post_ops->seq_length = cur_op_index; + + return post_ops; +} + +void lpgemm_destroy_post_ops_struct( aocl_post_op* post_ops ); + +template +B mat_mul_accuracy_check_downscale( Z temp_accum, B out_temp_accum, + aocl_post_op* post_op, dim_t j ) +{ + out_temp_accum = ( B ) min ( max ( nearbyintf( ( ST )temp_accum * + ( *( ( ST* )post_op->sum.scale_factor + j ) ) ), S8_MIN ), S8_MAX ) ; + return out_temp_accum; +} + +template +Z mat_mul_accuracy_check_accum + ( + A* a, + B* b, + X* c_ref, + Z temp_accum, + Z alpha, + Z beta, + dim_t rs_a, + dim_t rs_b, + dim_t cs_a, + dim_t cs_b, + dim_t rs_c_ref, + dim_t cs_c_ref, + dim_t i, + dim_t j, + dim_t k + ) +{ + dim_t p; + + for( p = 0 ; p < k ; ++p ) + { + temp_accum += ( *( a + ( i * rs_a ) + ( cs_a * p ) ) * + *( b + ( rs_b * p ) + ( cs_b * j ) ) ); + } + + temp_accum = ( beta * ( * (c_ref + ( rs_c_ref * i ) + ( cs_c_ref * j ) ) ) ) + + ( alpha * temp_accum ); + return temp_accum; +} + +template +double mat_mul_accuracy_check_driver + ( + dim_t m, + dim_t n, + dim_t k, + Z alpha, + A* a, + dim_t rs_a, + dim_t cs_a, + B* b, + dim_t rs_b, + dim_t cs_b, + Z beta, + X* c, + dim_t rs_c, + dim_t cs_c, + X* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_c_ref = rs_c; + dim_t cs_c_ref = cs_c; + dim_t i,j; + + for( i = 0 ; i < m ; ++i ) + { + for( j = 0 ; j < n ; ++j ) + { + Z temp_accum = 0; + X out_temp_accum = 0; + + temp_accum = mat_mul_accuracy_check_accum (a, b, c_ref, + temp_accum, alpha, beta, rs_a, rs_b, cs_a, cs_b, + rs_c_ref, cs_c_ref, i, j, k); + + if ( post_op != NULL ) + { + /* Apply bias followed by relu. */ + if ( post_op->seq_vector[0] == BIAS ) + { + if ( post_op->seq_length >= 1 ) + { + temp_accum += ( *( ( Z* )post_op->bias.bias + j ) ); + } + if ( ( post_op->seq_length > 1 ) && + ( post_op->seq_vector[1] == ELTWISE ) ) + { + if ( post_op->eltwise.algo.alpha != NULL ) /* PReLU*/ + { + temp_accum = ( temp_accum > 0 ) ? + temp_accum : + ( temp_accum * + *( ( Z* ) post_op->eltwise.algo.alpha ) ); + } + else + { + temp_accum = ( temp_accum > 0 ) ? temp_accum : 0 ; + } + } + } + else if ( post_op->seq_vector[0] == ELTWISE ) + { + if ( post_op->seq_length >= 1 ) + { + if ( post_op->eltwise.algo.alpha != NULL ) /* PReLU*/ + { + temp_accum = ( temp_accum > 0 ) ? + temp_accum : + ( temp_accum * *( ( Z* ) post_op->eltwise.algo.alpha ) ); + } + else + { + temp_accum = ( temp_accum > 0 ) ? temp_accum : 0 ; + } + } + if ( ( post_op->seq_length > 1 ) && ( post_op->seq_vector[1] == BIAS ) ) + { + temp_accum += ( *( ( Z* )post_op->bias.bias + j ) ); + } + } + } + if ( dscale_out ) + { + out_temp_accum = mat_mul_accuracy_check_downscale + ( temp_accum, out_temp_accum, post_op, j); + } + else + { + out_temp_accum = ( X )temp_accum; + } + + if( *( c + ( rs_c * i ) + ( cs_c * j ) ) != out_temp_accum ) + { + auto tmp = *( c + ( rs_c * i ) + ( cs_c * j ) ); + resid += abs( tmp - out_temp_accum ); + //return resid; + } + } + } + return resid; +} + +bfloat16 mat_mul_accuracy_check_downscale_bf16 + ( float temp_accum, bfloat16 out_temp_accum, aocl_post_op* post_op, dim_t j); + +float bf16_to_float( bfloat16 bf16_val ); + +float mat_mul_accuracy_check_accum_bf16 + ( + bfloat16* a, + bfloat16* b, + float* c_ref, + float temp_accum, + float alpha, + float beta, + dim_t rs_a, + dim_t rs_b, + dim_t cs_a, + dim_t cs_b, + dim_t rs_c_ref, + dim_t cs_c_ref, + dim_t i, + dim_t j, + dim_t k + ); + +float mat_mul_accuracy_check_accum_bf16 + ( + bfloat16* a, + bfloat16* b, + bfloat16* c_ref, + float temp_accum, + float alpha, + float beta, + dim_t rs_a, + dim_t rs_b, + dim_t cs_a, + dim_t cs_b, + dim_t rs_c_ref, + dim_t cs_c_ref, + dim_t i, + dim_t j, + dim_t k + ); + +template +double mat_mul_accuracy_check_driver_bf16 + ( + dim_t m, + dim_t n, + dim_t k, + Z alpha, + A* a, + dim_t rs_a, + dim_t cs_a, + B* b, + dim_t rs_b, + dim_t cs_b, + Z beta, + X* c, + dim_t rs_c, + dim_t cs_c, + X* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_c_ref = rs_c; + dim_t cs_c_ref = cs_c; + + for ( dim_t i = 0; i < m; ++i ) + { + for ( dim_t j = 0; j < n; ++j ) + { + Z temp_accum = 0; + X out_temp_accum = 0; + + temp_accum = mat_mul_accuracy_check_accum_bf16(a, b, c_ref, + temp_accum, alpha, beta, rs_a, rs_b, cs_a, cs_b, + rs_c_ref, cs_c_ref, i, j, k); + + if ( post_op != NULL ) + { + /* Apply bias followed by relu. */ + if ( post_op->seq_vector[0] == BIAS ) + { + if ( post_op->seq_length >= 1 ) + { + temp_accum += ( *( ( Z* )post_op->bias.bias + j ) ); + } + if ( ( post_op->seq_length > 1 ) && + ( post_op->seq_vector[1] == ELTWISE ) ) + { + if ( post_op->eltwise.algo.alpha != NULL ) /* PReLU*/ + { + temp_accum = ( temp_accum > 0 ) ? + temp_accum : + ( temp_accum * + *( ( Z* ) post_op->eltwise.algo.alpha ) ); + } + else + { + temp_accum = ( temp_accum > 0 ) ? temp_accum : 0 ; + } + } + } + else if ( post_op->seq_vector[0] == ELTWISE ) + { + if ( post_op->seq_length >= 1 ) + { + if ( post_op->eltwise.algo.alpha != NULL ) /* PReLU*/ + { + temp_accum = ( temp_accum > 0 ) ? + temp_accum : + ( temp_accum * *( ( Z* ) post_op->eltwise.algo.alpha ) ); + } + else + { + temp_accum = ( temp_accum > 0 ) ? temp_accum : 0 ; + } + } + if ( ( post_op->seq_length > 1 ) && ( post_op->seq_vector[1] == BIAS ) ) + { + temp_accum += ( *( ( Z* )post_op->bias.bias + j ) ); + } + } + } + if ( dscale_out ) + { + out_temp_accum = mat_mul_accuracy_check_downscale_bf16 + ( temp_accum, out_temp_accum, post_op, j); + } + else + { + out_temp_accum = ( X )temp_accum; + } + + if( *( c + ( rs_c * i ) + ( cs_c * j ) ) != out_temp_accum ) + { + auto tmp = *( c + ( rs_c * i ) + ( cs_c * j ) ); + resid += abs( tmp - out_temp_accum ); + //return resid; + } + } + } + return resid; +} +#endif + +template +void print_matrics(T *x , dim_t mm, dim_t nn, dim_t ld) +{ + dim_t i,j; + int32_t val; + for ( i = 0; i < mm; ++i ) { + for ( j = 0; j < nn; ++j ) { + val = (int32_t)(x[i*ld + j]); + printf("%9d", val); + } + cout << endl; + } + cout << endl; + return; +} + diff --git a/gtestsuite/src/main.cpp b/gtestsuite/src/main.cpp new file mode 100644 index 000000000..8430db35d --- /dev/null +++ b/gtestsuite/src/main.cpp @@ -0,0 +1,79 @@ +#include +#include + +#include +#include +#include +#include + +#include "blis_test.h" + +vector inputData; + +int main(int argc, char **argv) +{ + BlisTestSuite bts; + test_params_t* params = NULL; + blis_string_t* strData = NULL; + test_ops_t* ops = NULL; + input_file_t* pfile = NULL; + input_data_t inData; + string filter_data( "" ); + + params = bts.getParamsStr(); + strData = bts.getStgStr(); + ops = bts.getOpsStr(); + pfile = bts.getfileStr(); + + unsigned int n = std::thread::hardware_concurrency(); + std::cout << n << " concurrent threads are supported.\n"; + + memset( &inData, 0, sizeof( input_data_t ) ); + memset( params, 0, sizeof( test_params_t ) ); + memset( strData, 0, sizeof( blis_string_t ) ); + memset( ops, 0, sizeof( test_ops_t ) ); + memset( pfile, 0, sizeof( input_file_t ) ); + + // Initialize some strings. + bts.libblis_test_init_strings( strData ); + + if(argc <= 1) + { + // Read the global parameters file. + bts.libblis_test_read_params_file( strData->libblis_test_parameters_filename, + params, strData->libblis_test_alphabeta_parameter); + + // Read the operations parameter file. + bts.libblis_test_read_ops_file(strData->libblis_test_operations_filename, ops); + + bts.CreateGtestFilters(ops, filter_data); + } + else + { + // Read the global parameters file. + bts.libblis_test_inpfile(argv[1], pfile); + + bts.CreateGtestFilters_api(pfile, filter_data); + } + + inData.params = params; + inData.ops = ops; + inData.pfile = pfile; + if(pfile->fileread != 1) { + inData.pthread = (bli_pthread_t *)malloc( sizeof( bli_pthread_t ) * params->n_app_threads ); + inData.tdata = (thread_data_t *)malloc( sizeof( thread_data_t ) * params->n_app_threads ); + } + + inputData.push_back(inData); + + ::testing::GTEST_FLAG(filter) = filter_data.c_str(); + testing::InitGoogleTest(&argc, argv); + int retval = RUN_ALL_TESTS(); + + if(pfile->fileread != 1) { + free( inData.pthread ); + free( inData.tdata ); + } + + return retval; +} diff --git a/gtestsuite/src/ref_addm.cpp b/gtestsuite/src/ref_addm.cpp new file mode 100644 index 000000000..60ccb2148 --- /dev/null +++ b/gtestsuite/src/ref_addm.cpp @@ -0,0 +1,130 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_addm.h" + +using namespace std; + +//* ========================================================================== +//*> ADDM performs matrix operations +//*> B := B + transa(A) +//*> where B is an m x n matrix. +//* ========================================================================== + +template +void libblis_iaddm_check(dim_t M, dim_t N, T* X, dim_t rsx, dim_t csx, + T* Y, dim_t rsy, dim_t csy, T* YY) { + + dim_t i, j; + + if ((M == 0) || (N == 0)) { + return; + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = Y[i*rsy + j*csy] + X[i*rsx + j*csx]; + } + } + + return; +} + +template +void libblis_icaddm_check(dim_t M, dim_t N, T* X, dim_t rsx, dim_t csx, + conj_t conjx, T* Y, dim_t rsy, dim_t csy) { + + dim_t i, j; + + if ((M == 0) || (N == 0)) { + return; + } + + if(conjx) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = conjugate(X[i*rsx + j*csx]); + } + } + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = addc(Y[i*rsy + j*csy], X[i*rsx + j*csx]); + } + } + + return; +} + +double libblis_test_iaddm_check( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + bool transx = bli_obj_has_trans( x ); + conj_t conjx = bli_obj_conj_status( x ); + dim_t M = bli_obj_length( y ); + dim_t N = bli_obj_width( y ); + dim_t rsy = bli_obj_row_stride( y ) ; + dim_t csy = bli_obj_col_stride( y ) ; + double resid = 0.0; + dim_t rsx, csx; + + if( bli_obj_is_col_stored( x ) ) { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } else { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_iaddm_check( M, N, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_iaddm_check( M, N, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icaddm_check( M, N, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icaddm_check( M, N, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_addv.cpp b/gtestsuite/src/ref_addv.cpp new file mode 100644 index 000000000..b48044798 --- /dev/null +++ b/gtestsuite/src/ref_addv.cpp @@ -0,0 +1,117 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_addv.h" + +using namespace std; + +//* ========================================================================== +//*> ADDV performs vector operations +//*> y := y + conjx(x) +//*> where x and y are vectors of length n. +//* ========================================================================== + +template +void libblis_iaddv_check(dim_t len, T* X, dim_t incx, T* Y, dim_t incy) { + + dim_t i, ix, iy; + if (len == 0) { + return; + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = Y[iy] + X[ix]; + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +template +void libblis_icaddv_check(dim_t len, T* X, dim_t incx, T* Y, + dim_t incy, bool cfx) { + dim_t i, ix, iy; + if (len == 0) { + return; + } + + ix = 0; + if(cfx) { + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = addc(Y[iy] , X[ix]); + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +double libblis_test_iaddv_check( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + bool cfx = bli_obj_has_conj( x ); + dim_t incx = bli_obj_vector_inc( x ); + dim_t incy = bli_obj_vector_inc( y_orig ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_iaddv_check( M, X, incx, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_iaddv_check( M, X, incx, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icaddv_check( M, X, incx, Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icaddv_check( M, X, incx, Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_amaxv.cpp b/gtestsuite/src/ref_amaxv.cpp new file mode 100644 index 000000000..e112a68ec --- /dev/null +++ b/gtestsuite/src/ref_amaxv.cpp @@ -0,0 +1,105 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_amaxv.h" + +using namespace std; + +//* ========================================================================== +//*> Given a vector of length n, return the zero-based index index of +//*> the element of vector x that contains the largest absolute value +//*> (or, in the complex domain, the largest complex modulus). +//* ========================================================================== + +template +dim_t libblis_iamaxv_check(dim_t len, T* X, dim_t incx) { + + dim_t i, ix, iamax = 0; + + if (len == 0) { + return 0; + } + + ix = 0; + T smax = abs(X[ix]); + for(i = 0 ; i < len ; i++) { + if(abs(X[ix]) > smax) { + iamax = i; + smax = abs(X[ix]); + } + ix = ix + incx; + } + + return iamax; +} + +template +dim_t libblis_icamaxv_check(dim_t len, T* X, dim_t incx) { + + dim_t i, ix, iamax = 0; + if (len == 0) { + return 0; + } + + ix = 0; + U smax = abscomplex(X[ix]); + for(i = 0 ; i < len ; i++) { + if(abscomplex(X[ix]) > smax) { + iamax = i; + smax = abscomplex(X[ix]); + } + ix = ix + incx; + } + + return iamax; +} + +double libblis_test_iamaxv_check( + test_params_t* params, + obj_t* x, + obj_t* index +){ + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + double resid = 0.0; + dim_t ind = 0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + f77_int* indx = (f77_int*) bli_obj_buffer( index ); + ind = libblis_iamaxv_check( M, X, incx ); + resid = (double)(*indx - ind); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + f77_int* indx = (f77_int*) bli_obj_buffer( index ); + ind = libblis_iamaxv_check( M, X, incx ); + resid = (double)(*indx - ind); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + f77_int* indx = (f77_int*) bli_obj_buffer( index ); + ind = libblis_icamaxv_check( M, X, incx ); + resid = (double)(*indx - ind); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + f77_int* indx = (f77_int*) bli_obj_buffer( index ); + ind = libblis_icamaxv_check( M, X, incx ); + resid = (double)(*indx - ind); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} diff --git a/gtestsuite/src/ref_axpbyv.cpp b/gtestsuite/src/ref_axpbyv.cpp new file mode 100644 index 000000000..ab8dec811 --- /dev/null +++ b/gtestsuite/src/ref_axpbyv.cpp @@ -0,0 +1,202 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpbyv.h" + +using namespace std; + +//* ========================================================================== +//*> AXPBYV performs vector operations +//*> y := beta * y + alpha * conjx(x) +//*> where x and y are vectors of length n, and alpha and beta are scalars +//* ========================================================================== + +template +void libblis_iaxpbyv_check(dim_t len, T* alpha, T* X, dim_t incx, + T* beta, T* Y, dim_t incy) { + + dim_t i, ix, iy; + T ONE, ZERO; + ONE = 1.0 ; + ZERO = 0.0 ; + T Alpha = alpha[0]; + T Beta = beta[0]; + if (len == 0){ + return; + } + + //* First form y := beta*y. + if (Beta != ONE) { + iy = 0; + if (Beta == ZERO) { + for(i = 0 ; i < len ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < len ; i++) { + Y[iy] = Beta*Y[iy]; + iy = iy + incy; + } + } + } + + if (Alpha != ONE) { + ix = 0; + if (Alpha == ZERO) { + for(i = 0 ; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = Alpha*X[ix]; + ix = ix + incx; + } + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = Y[iy] + X[ix]; + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +template +void libblis_icaxpbyv_check(dim_t len, T* alpha, T* X, dim_t incx, + T* beta, T* Y, dim_t incy, bool cfx) { + dim_t i, ix, iy; + T ONE, ZERO; + ONE = {1.0 , 0.0}; + ZERO = {0.0 , 0.0}; + T Alpha = *alpha; + T Beta = *beta; + + if (len == 0) { + return; + } + + if(cfx) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + /* First form y := beta*y. */ + iy = 0; + if ((Beta.real == ZERO.real) && (Beta.imag == ZERO.imag)) { + for(i = 0; i < len ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < len ; i++) { + Y[iy] = mulc(Beta , Y[iy]); + iy = iy + incy; + } + } + + ix = 0; + if ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)) { + for(i = 0; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = mulc(Alpha , X[ix]); + ix = ix + incx; + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = addc(Y[iy] , X[ix]); + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +double libblis_test_iaxpbyv_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + bool cfx = bli_obj_has_conj( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y_orig ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_iaxpbyv_check( M, Alpha, X, incx, + Beta, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_iaxpbyv_check( M, Alpha, X, incx, + Beta, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icaxpbyv_check( M, Alpha, X, incx, + Beta, Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icaxpbyv_check( M, Alpha, X, incx, + Beta, Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} diff --git a/gtestsuite/src/ref_axpy2v.cpp b/gtestsuite/src/ref_axpy2v.cpp new file mode 100644 index 000000000..fbb973f0b --- /dev/null +++ b/gtestsuite/src/ref_axpy2v.cpp @@ -0,0 +1,231 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpy2v.h" + +using namespace std; + +//* ========================================================================== +//*> AXPY2V performs vector operations +//*> z := y + alphax * conjx(x) + alphay * conjy(y) +//*> where x, y, and z are vectors of length m. The kernel is implemented +//*> as a fused pair of calls to axpyv. +//* ========================================================================== + +template +void libblis_iaxpy2v_check(dim_t len, T* alphax, T* alphay, T* X, dim_t incx, + T* Y, dim_t incy, T* Z, dim_t incz) { + dim_t i, ix, iy, iz; + T ONE, ZERO; + ONE = 1.0 ; + ZERO = 0.0 ; + T Alphax = alphax[0]; + T Alphay = alphay[0]; + + if (len == 0){ + return; + } + + if (Alphax != ONE) { + ix = 0; + if (Alphax == ZERO) { + for(i = 0 ; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = Alphax * X[ix]; + ix = ix + incx; + } + } + } + + if (Alphay != ONE) { + iy = 0; + if (Alphay == ZERO) { + for(i = 0 ; i < len ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < len ; i++) { + Y[iy] = Alphay * Y[iy]; + iy = iy + incy; + } + } + } + + ix = 0; + iy = 0; + iz = 0; + for(i = 0 ; i < len ; i++) { + Z[iz] = Z[iz] + X[ix] + Y[iy] ; + ix = ix + incx; + iy = iy + incy; + iz = iz + incz; + } + + return; +} + +template +void libblis_icaxpy2v_check(dim_t len, T* alphax, T* alphay, T* X, dim_t incx, + bool cfx, T* Y, dim_t incy, bool cfy, T* Z, dim_t incz) { + + dim_t i, ix, iy, iz; + T ONE, ZERO; + ONE = {1.0 , 0.0}; + ZERO = {0.0 , 0.0}; + T Alphax = *alphax; + T Alphay = *alphay; + + if (len == 0) { + return; + } + + if(cfx) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(cfy) { + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = conjugate(Y[iy]); + iy = iy + incy; + } + } + + if ((Alphax.real != ONE.real) && (Alphax.imag != ONE.imag)) { + ix = 0; + if ((Alphax.real == ZERO.real) && (Alphax.imag == ZERO.imag)) { + for(i = 0; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = mulc(Alphax , X[ix]); + ix = ix + incx; + } + } + } + + if ((Alphay.real != ONE.real) && (Alphay.imag != ONE.imag)) { + iy = 0; + if ((Alphay.real == ZERO.real) && (Alphay.imag == ZERO.imag)) { + for(i = 0; i < len ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < len ; i++) { + Y[iy] = mulc(Alphay , Y[iy]); + iy = iy + incy; + } + } + } + + ix = 0; + iy = 0; + iz = 0; + for(i = 0 ; i < len ; i++) { + auto xx = X[ix]; + auto yy = Y[iy]; + auto zz = Z[iz]; + zz.real = zz.real + xx.real + yy.real ; + zz.imag = zz.imag + xx.imag + yy.imag ; + Z[iz] = zz; + ix = ix + incx; + iy = iy + incy; + iz = iz + incz; + } + + return; +} + +double libblis_test_iaxpy2v_check ( + test_params_t* params, + obj_t* alphax, + obj_t* alphay, + obj_t* x, + obj_t* y, + obj_t* z, + obj_t* z_orig +) { + num_t dt = bli_obj_dt( z ); + dim_t M = bli_obj_vector_dim( z ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + bool cfx = bli_obj_has_conj( x ); + bool cfy = bli_obj_has_conj( y ); + f77_int incz = bli_obj_vector_inc( z ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alphax = (float*) bli_obj_buffer( alphax ); + float* Alphay = (float*) bli_obj_buffer( alphay ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y ); + float* Z = (float*) bli_obj_buffer( z_orig ); + float* ZZ = (float*) bli_obj_buffer( z ); + libblis_iaxpy2v_check( M, Alphax, Alphay, X, incx, + Y, incy, Z, incz ); + resid = computediffrv(M, incz, ZZ, Z); + break; + } + case BLIS_DOUBLE : + { + double* Alphax = (double*) bli_obj_buffer( alphax ); + double* Alphay = (double*) bli_obj_buffer( alphay ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y ); + double* Z = (double*) bli_obj_buffer( z_orig ); + double* ZZ = (double*) bli_obj_buffer( z ); + libblis_iaxpy2v_check( M, Alphax, Alphay, X, incx, + Y, incy, Z, incz ); + resid = computediffrv(M, incz, ZZ, Z); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alphax = (scomplex*) bli_obj_buffer( alphax ); + scomplex* Alphay = (scomplex*) bli_obj_buffer( alphay ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + scomplex* Z = (scomplex*) bli_obj_buffer( z_orig ); + scomplex* ZZ = (scomplex*) bli_obj_buffer( z ); + libblis_icaxpy2v_check( M, Alphax, Alphay, X, incx, + cfx, Y, incy, cfy, Z, incz ); + resid = computediffiv(M, incz, ZZ, Z); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alphax = (dcomplex*) bli_obj_buffer( alphax ); + dcomplex* Alphay = (dcomplex*) bli_obj_buffer( alphay ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + dcomplex* Z = (dcomplex*) bli_obj_buffer( z_orig ); + dcomplex* ZZ = (dcomplex*) bli_obj_buffer( z ); + libblis_icaxpy2v_check( M, Alphax, Alphay, X, incx, + cfx, Y, incy, cfy, Z, incz ); + resid = computediffiv(M, incz, ZZ, Z); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_axpyf.cpp b/gtestsuite/src/ref_axpyf.cpp new file mode 100644 index 000000000..021a44b66 --- /dev/null +++ b/gtestsuite/src/ref_axpyf.cpp @@ -0,0 +1,156 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpyv.h" + +using namespace std; + +//* ========================================================================== +//*> AXPYF performs vector operations +//*> y := y + alpha * conja(A) * conjx(x) +//*> where A is an m x b matrix, and y and x are vectors. +//*> The kernel is implemented as a fused series of calls to axpyv +//*> where b is less than or equal to an implementation-dependent +//*> fusing factor specific to axpyf +//* ========================================================================== + +template +void libblis_iaxpyf_check(dim_t M, dim_t N, T* alpha, T* A, dim_t rsa, + dim_t csa, T* X, dim_t incx, T* Y, dim_t incy) { + dim_t i, j, ix, iy; + T Alpha = alpha[0]; + T temp; + if((M == 0) || (N == 0)) { + return; + } + + ix = 0; + for(j = 0 ; j < N ; j++) { + temp = Alpha * X[ix]; + iy = 0; + for(i = 0 ; i < M ; i++) { + Y[iy] = Y[iy] + temp * A[i*rsa + j*csa]; + iy = iy + incy; + } + ix = ix + incx; + } + + return; +} + +template +void libblis_icaxpyf_check(dim_t M, dim_t N, T* alpha, T* A, dim_t rsa, + dim_t csa, bool cfa, T* X, dim_t incx, bool cfx, T* Y, dim_t incy ) { + + dim_t i, j, ix, iy; + T Alpha = *alpha; + T temp; + + if((M == 0) || (N == 0)) { + return; + } + + if(cfx) { + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(cfa) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i < M ; i++) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + ix = 0; + for(j = 0 ; j < N ; j++) { + temp = mulc(Alpha , X[ix]); + iy = 0; + for(i = 0 ; i < M ; i++) { + Y[iy] = addc(Y[iy] , mulc(temp , A[i*rsa + j*csa])); + iy = iy + incy; + } + ix = ix + incx; + } + + return; +} + +double libblis_test_iaxpyf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( y ); + dim_t M = bli_obj_vector_dim( y ); + dim_t N = bli_obj_width( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + bool cfx = bli_obj_has_conj( x ); + bool cfa = bli_obj_has_conj( a ); + f77_int rsa = bli_obj_row_stride( a ) ; + f77_int csa = bli_obj_col_stride( a ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_iaxpyf_check( M, N, Alpha, A, rsa, csa, + X, incx, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_iaxpyf_check( M, N, Alpha, A, rsa, csa, + X, incx, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icaxpyf_check( M, N, Alpha, A, rsa, csa, + cfa, X, incx, cfx, Y, incy ); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icaxpyf_check( M, N, Alpha, A, rsa, csa, + cfa, X, incx, cfx, Y, incy ); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_axpym.cpp b/gtestsuite/src/ref_axpym.cpp new file mode 100644 index 000000000..83aa8bb79 --- /dev/null +++ b/gtestsuite/src/ref_axpym.cpp @@ -0,0 +1,137 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpym.h" + +using namespace std; + +//* ========================================================================== +//*> AXPYM performs matrix operations +//*> B := B + alpha * transa(A) +//*> where B is an m x n matrix. +//* ========================================================================== + +template +void libblis_iaxpym_check(dim_t M, dim_t N, T* alpha, + T* X, dim_t rsx, dim_t csx, T* Y, dim_t rsy, dim_t csy, T* YY) { + + dim_t i, j; + T Alpha = alpha[0]; + + if ((M == 0) || (N == 0)) { + return; + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = Y[i*rsy + j*csy] + ( Alpha * X[i*rsx + j*csx] ); + } + } + + return; +} + +template +void libblis_icaxpym_check(dim_t M, dim_t N, T* alpha, + T* X, dim_t rsx, dim_t csx, conj_t conjx, T* Y, dim_t rsy, dim_t csy) { + + dim_t i, j; + T Alpha = *alpha; + + if ((M == 0) || (N == 0)) { + return; + } + + if(conjx) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = conjugate(X[i*rsx + j*csx]); + } + } + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = addc(Y[i*rsy + j*csy] , mulc(Alpha , X[i*rsx + j*csx])); + } + } + + return; +} + +double libblis_test_iaxpym_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( x ); + bool transx = bli_obj_has_trans( x ); + conj_t conjx = bli_obj_conj_status( x ); + dim_t M = bli_obj_length( y ); + dim_t N = bli_obj_width( y ); + dim_t rsy = bli_obj_row_stride( y ) ; + dim_t csy = bli_obj_col_stride( y ) ; + double resid = 0.0; + dim_t rsx, csx; + + if( bli_obj_is_col_stored( x ) ) { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } else { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_iaxpym_check( M, N, Alpha, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_iaxpym_check( M, N, Alpha, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icaxpym_check( M, N, Alpha, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icaxpym_check( M, N, Alpha, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_axpyv.cpp b/gtestsuite/src/ref_axpyv.cpp new file mode 100644 index 000000000..6a63b31ff --- /dev/null +++ b/gtestsuite/src/ref_axpyv.cpp @@ -0,0 +1,160 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpyv.h" + +using namespace std; + +//* ========================================================================== +//*> AXPYV performs vector operations +//*> y := y + alpha * conjx(x) +//*> where x and y are vectors of length n, and alpha is a scalar +//* ========================================================================== + +template +void libblis_iaxpyv_check(dim_t len, T* alpha, T* X, dim_t incx, + T* Y, dim_t incy) { + + dim_t i, ix, iy; + T ONE, ZERO; + ONE = 1.0 ; + ZERO = 0.0 ; + T Alpha = alpha[0]; + + if (len == 0){ + return; + } + + if (Alpha != ONE) { + ix = 0; + if (Alpha == ZERO) { + for(i = 0 ; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = Alpha*X[ix]; + ix = ix + incx; + } + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = Y[iy] + X[ix]; + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +template +void libblis_icaxpyv_check(dim_t len, T* alpha, T* X, dim_t incx, + T* Y, dim_t incy, bool cfx) { + dim_t i, ix, iy; + T ONE, ZERO; + ONE = {1.0 , 0.0}; + ZERO = {0.0 , 0.0}; + T Alpha = *alpha; + + if(len == 0){ + return; + } + + if(cfx) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + /* First form y := beta*y. */ + if (Alpha.real != ONE.real) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = mulc(Alpha , X[ix]); + ix = ix + incx; + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = addc(Y[iy] , X[ix]); + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +double libblis_test_iaxpyv_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + bool cfx = bli_obj_has_conj( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y_orig ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_iaxpyv_check( M, Alpha, X, incx, + Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_iaxpyv_check( M, Alpha, X, incx, + Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icaxpyv_check( M, Alpha, X, incx, + Y, incy, cfx ); + + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icaxpyv_check( M, Alpha, X, incx, + Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} diff --git a/gtestsuite/src/ref_copym.cpp b/gtestsuite/src/ref_copym.cpp new file mode 100644 index 000000000..1e99e451c --- /dev/null +++ b/gtestsuite/src/ref_copym.cpp @@ -0,0 +1,130 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_copym.h" + +using namespace std; + +//* ========================================================================== +//*> COPYM performs matrix operations +//*> B := transa(A) +//*> where B is an m x n matrix. +//* ========================================================================== + +template +void libblis_icopym_check(dim_t M, dim_t N, T* X, dim_t rsx, dim_t csx, + T* Y, dim_t rsy, dim_t csy, T* YY) { + + dim_t i, j; + + if ((M == 0) || (N == 0)) { + return; + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = X[i*rsx + j*csx]; + } + } + + return; +} + +template +void libblis_iccopym_check(dim_t M, dim_t N, T* X, dim_t rsx, dim_t csx, + conj_t conjx, T* Y, dim_t rsy, dim_t csy) { + + dim_t i, j; + + if ((M == 0) || (N == 0)) { + return; + } + + if(conjx) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = conjugate(X[i*rsx + j*csx]); + } + } + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = X[i*rsx + j*csx]; + } + } + + return; +} + +double libblis_test_icopym_check( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + bool transx = bli_obj_has_trans( x ); + conj_t conjx = bli_obj_conj_status( x ); + dim_t M = bli_obj_length( y ); + dim_t N = bli_obj_width( y ); + dim_t rsy = bli_obj_row_stride( y ) ; + dim_t csy = bli_obj_col_stride( y ) ; + double resid = 0.0; + dim_t rsx, csx; + + if( bli_obj_is_col_stored( x ) ) { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } else { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_icopym_check( M, N, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_icopym_check( M, N, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_iccopym_check( M, N, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_iccopym_check( M, N, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_copyv.cpp b/gtestsuite/src/ref_copyv.cpp new file mode 100644 index 000000000..867a8280c --- /dev/null +++ b/gtestsuite/src/ref_copyv.cpp @@ -0,0 +1,114 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_copyv.h" + +using namespace std; + +//* ========================================================================== +//*> COPYV performs vector operations +//*> y := conjx(x) +//*> where x and y are vectors of length n. +//* ========================================================================== + +template +void libblis_icopyv_check(dim_t len, T* X, dim_t incx, T* Y, dim_t incy) { + + dim_t i, ix, iy; + if (len == 0) { + return; + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = X[ix]; + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +template +void libblis_iccopyv_check(dim_t len, T* X, dim_t incx, T* Y, + dim_t incy, bool cfx) { + dim_t i, ix, iy; + if (len == 0) { + return; + } + + if(cfx) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = X[ix]; + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +double libblis_test_icopyv_check( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + bool cfx = bli_obj_has_conj( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y_orig ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_icopyv_check( M, X, incx, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_icopyv_check( M, X, incx, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_iccopyv_check( M, X, incx, Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_iccopyv_check( M, X, incx, Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} diff --git a/gtestsuite/src/ref_dotaxpyv.cpp b/gtestsuite/src/ref_dotaxpyv.cpp new file mode 100644 index 000000000..6913b5369 --- /dev/null +++ b/gtestsuite/src/ref_dotaxpyv.cpp @@ -0,0 +1,228 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotaxpyv.h" + +using namespace std; + +//* ========================================================================== +//*> DOTAXPYV performs fused operations +//*> rho := conjxt(x^T) * conjy(y) +//*> y := y + alpha * conjx(x) +//*> where x, y, and z are vectors of length m and alpha and rho are scalars. +//*> The kernel is implemented as a fusion of calls to dotv and axpyv +//* ========================================================================== + +template +T libblis_idotaxpyv_check(dim_t len, T* alpha, T* XT, dim_t incxt, + T* X, dim_t incx, T* Y, dim_t incy, T* Z, dim_t incz ) { + + dim_t i, ixt, ix, iy, iz; + T ONE = 1.0 ; + T ZERO = 0.0 ; + T Alpha = alpha[0]; + T pr = 0.0; + if (len == 0) { + return pr; + } + + ixt = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + pr = pr + XT[ixt] * Y[iy]; + ixt = ixt + incxt; + iy = iy + incy; + } + + if (Alpha != ONE) { + ix = 0; + if (Alpha == ZERO) { + for(i = 0 ; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = Alpha*X[ix]; + ix = ix + incx; + } + } + } + + ix = 0; + iz = 0; + for(i = 0 ; i < len ; i++) { + Z[iz] = Z[iz] + X[ix]; + ix = ix + incx; + iz = iz + incz; + } + + return pr; +} + +template +T libblis_icdotaxpyv_check(dim_t len, T* alpha, T* XT, dim_t incxt, bool cfxt, + T* X, dim_t incx, bool cfx, T* Y, dim_t incy, bool cfy, T* Z, dim_t incz ) { + + dim_t i, ixt, ix, iy, iz; + T ONE = {1.0 , 0.0}; + T ZERO = {0.0 , 0.0}; + T Alpha = *alpha; + + T pr = {0.0, 0.0}; + if (len == 0) { + return pr; + } + + if(cfxt) { + ixt = 0; + for(i = 0 ; i < len ; i++) { + XT[ixt] = conjugate(XT[ixt]); + ixt = ixt + incxt; + } + } + + if(cfy) { + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = conjugate(Y[iy]); + iy = iy + incy; + } + } + + ixt = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + pr = addc(pr, mulc(Y[iy] , XT[ixt])); + ixt = ixt + incxt; + iy = iy + incy; + } + + if(cfx != cfxt) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if ((Alpha.real != ONE.real) && (Alpha.imag != ONE.imag)) { + ix = 0; + if ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)) { + for(i = 0 ; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = mulc(Alpha, X[ix]); + ix = ix + incx; + } + } + } + + ix = 0; + iz = 0; + for(i = 0 ; i < len ; i++) { + Z[iz] = addc(Z[iz] , X[ix]); + ix = ix + incx; + iz = iz + incz; + } + + return pr; + +} + +double libblis_test_idotaxpyv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* xt, + obj_t* x, + obj_t* y, + obj_t* rho_orig, + obj_t* z, + obj_t* z_orig +) { + num_t dt = bli_obj_dt( y ); + dim_t M = bli_obj_vector_dim( z ); + f77_int incxt = bli_obj_vector_inc( xt ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + f77_int incz = bli_obj_vector_inc( z ); + bool cfxt = bli_obj_has_conj( xt ); + bool cfx = bli_obj_has_conj( x ); + bool cfy = bli_obj_has_conj( y ); + double r1,r2,resid ; + r1 = r2 = resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x ); + float* XT = (float*) bli_obj_buffer( xt ); + float* Y = (float*) bli_obj_buffer( y ); + float* Z = (float*) bli_obj_buffer( z_orig ); + float* ZZ = (float*) bli_obj_buffer( z ); + float* av = (float*) bli_obj_buffer( rho_orig ); + float ref = libblis_idotaxpyv_check( M, Alpha, + XT, incxt, X, incx, Y, incy, Z, incz ); + r1 = computediffrv(M, incy, ZZ, Z); + r2 = (*av - ref); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x ); + double* XT = (double*) bli_obj_buffer( xt ); + double* Y = (double*) bli_obj_buffer( y ); + double* Z = (double*) bli_obj_buffer( z_orig ); + double* ZZ = (double*) bli_obj_buffer( z ); + double* av = (double*) bli_obj_buffer( rho_orig ); + double ref = libblis_idotaxpyv_check( M, Alpha, + XT, incxt, X, incx, Y, incy, Z, incz ); + r1 = computediffrv(M, incy, ZZ, Z); + r2 = (*av - ref); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* XT = (scomplex*) bli_obj_buffer( xt ); + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + scomplex* Z = (scomplex*) bli_obj_buffer( z_orig ); + scomplex* ZZ = (scomplex*) bli_obj_buffer( z ); + scomplex* av = (scomplex*) bli_obj_buffer( rho_orig ); + scomplex ref = libblis_icdotaxpyv_check( M, Alpha, + XT, incxt, cfxt, X, incx, cfx, Y, incy, cfy, Z, incz ); + r1 = computediffiv(M, incy, ZZ, Z); + r2 = ((*av).real - ref.real); + r2 +=((*av).imag - ref.imag); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* XT = (dcomplex*) bli_obj_buffer( xt ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + dcomplex* Z = (dcomplex*) bli_obj_buffer( z_orig ); + dcomplex* ZZ = (dcomplex*) bli_obj_buffer( z ); + dcomplex* av = (dcomplex*) bli_obj_buffer( rho_orig ); + dcomplex ref = libblis_icdotaxpyv_check( M, Alpha, + XT, incxt, cfxt, X, incx, cfx, Y, incy, cfy, Z, incz ); + r1 = computediffiv(M, incy, ZZ, Z); + r2 = ((*av).real - ref.real); + r2 +=((*av).imag - ref.imag); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + resid = abs(bli_fmaxabs( r1, r2 )); + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_dotv.cpp b/gtestsuite/src/ref_dotv.cpp new file mode 100644 index 000000000..8f6b8f474 --- /dev/null +++ b/gtestsuite/src/ref_dotv.cpp @@ -0,0 +1,129 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotv.h" + +using namespace std; + +//* ========================================================================== +//*> DOTV performs vector operations +//*> rho := conjx(x)^T * conjy(y) +//*> where x and y are vectors of length n, and rho is a scalar. +//* ========================================================================== + +template +T libblis_idotv_check(dim_t len, T* X, dim_t incx, T* Y, dim_t incy) { + + dim_t i, ix, iy; + T pr = 0.0; + if (len == 0) { + return pr; + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + pr = pr + X[ix] * Y[iy]; + ix = ix + incx; + iy = iy + incy; + } + + return pr; +} + +template +T libblis_icdotv_check(dim_t len, T* X, dim_t incx, T* Y, + dim_t incy, bool cfx, bool cfy) { + dim_t i, ix, iy; + T pr = {0.0, 0.0}; + if (len == 0) { + return pr; + } + + if(cfx) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(cfy) { + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = conjugate(Y[iy]); + iy = iy + incy; + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + pr = addc(pr, mulc(Y[iy] , X[ix])); + ix = ix + incx; + iy = iy + incy; + } + + return pr; +} + +double libblis_test_idotv_check( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* rho +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + bool cfx = bli_obj_has_conj( x ); + bool cfy = bli_obj_has_conj( y ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y ); + float* av = (float*) bli_obj_internal_scalar_buffer( rho ); + float ref = libblis_idotv_check( M, X, incx, Y, incy ); + resid = (*av - ref); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y ); + double* av = (double*) bli_obj_internal_scalar_buffer( rho ); + double ref = libblis_idotv_check( M, X, incx, Y, incy ); + resid = (*av - ref); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + scomplex* av = (scomplex*) bli_obj_internal_scalar_buffer( rho ); + scomplex ref = libblis_icdotv_check( M, X, incx, + Y, incy, cfx, cfy ); + resid = ((*av).real - ref.real); + resid +=((*av).imag - ref.imag); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + dcomplex* av = (dcomplex*) bli_obj_internal_scalar_buffer( rho ); + dcomplex ref = libblis_icdotv_check( M, X, incx, + Y, incy, cfx, cfy ); + resid = ((*av).real - ref.real); + resid +=((*av).imag - ref.imag); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_dotxaxpyf.cpp b/gtestsuite/src/ref_dotxaxpyf.cpp new file mode 100644 index 000000000..68abe7386 --- /dev/null +++ b/gtestsuite/src/ref_dotxaxpyf.cpp @@ -0,0 +1,245 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotxaxpyf.h" + +using namespace std; + +//* ========================================================================== +//*> DOTXAXPYF performs fused operations +//*> y := beta * y + alpha * conjat(A^T) * conjw(w) +//*> z := z + alpha * conja(A) * conjx(x) +//*> where A is an m x b matrix, w and z are vectors of length m, +//*> x and y are vectors of length b, and alpha and beta are scalars. +//*> The kernel is implemented as a fusion of calls to dotxf and axpyf. +//* ========================================================================== + +template +void libblis_idotxaxpyf_check(dim_t M, dim_t N, T* alpha, T* AT, T* A, dim_t rsa, + dim_t csa, T* W, dim_t incw, T* X, dim_t incx, T* beta, T* Y, + dim_t incy, T* Z, dim_t incz) { + + dim_t i, j, iw, ix, iy, iz; + T Alpha = alpha[0]; + T Beta = beta[0]; + T temp; + if((M == 0) || (N == 0)) { + return; + } + + //y := beta * y + alpha * conjat(A^T) * conjw(w) + iy = 0; + for(j = 0 ; j < N ; j++) { + iw = 0; + temp = 0.0; + for(i = 0 ; i < M ; i++) { + temp += W[iw] * AT[i*rsa + j*csa]; + iw = iw + incw; + } + temp = Alpha * temp; + Y[iy] = (Y[iy] * Beta) + temp; + iy = iy + incy; + } + + //z := z + alpha * conja(A) * conjx(x) + ix = 0; + for(j = 0 ; j < N ; j++) { + temp = Alpha * X[ix]; + iz = 0; + for(i = 0 ; i < M ; i++) { + Z[iz] = Z[iz] + temp * A[i*rsa + j*csa]; + iz = iz + incz; + } + ix = ix + incx; + } + + return; +} + +template +void libblis_icdotxaxpyf_check(dim_t M, dim_t N, T* alpha, T* AT, bool conjat, + T* A, dim_t rsa, dim_t csa, bool conja, T* W, dim_t incw, bool conjw, T* X, + dim_t incx, bool conjx, T* beta, T* Y, dim_t incy, T* Z, dim_t incz) { + + dim_t i, j, iw, ix, iy, iz; + //T ONE = {1.0 , 0.0}; + T ZERO = {0.0 , 0.0}; + T Alpha = *alpha; + T Beta = *beta; + T temp; + + if((M == 0) || (N == 0)) { + return; + } + + if(conjw) { + iw = 0; + for(i = 0 ; i < M ; i++) { + W[iw] = conjugate(W[iw]); + iw = iw + incw; + } + } + + if(conjat) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i < M ; i++) { + AT[i*rsa + j*csa] = conjugate(AT[i*rsa + j*csa]); + } + } + } + + //y := beta * y + alpha * conjat(A^T) * conjw(w) + iy = 0; + for(j = 0 ; j < N ; j++) { + iw = 0; + temp = ZERO; + for(i = 0 ; i < M ; i++) { + temp = addc(temp , mulc(W[iw] , AT[i*rsa + j*csa])); + iw = iw + incw; + } + temp = mulc(Alpha , temp); + Y[iy] = addc(temp , mulc(Y[iy] , Beta)); + iy = iy + incy; + } + + //z := z + alpha * conja(A) * conjx(x) + if(conjx) { + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(conja != conjat) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i < M ; i++) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + //z := z + alpha * conja(A) * conjx(x) + ix = 0; + for(j = 0 ; j < N ; j++) { + temp = mulc(Alpha , X[ix]); + iz = 0; + for(i = 0 ; i < M ; i++) { + Z[iz] = addc(Z[iz] , mulc(temp , A[i*rsa + j*csa])); + iz = iz + incz; + } + ix = ix + incx; + } + + return; +} + +double libblis_test_idotxaxpyf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* at, + obj_t* a, + obj_t* w, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* z, + obj_t* y_orig, + obj_t* z_orig +) { + num_t dt = bli_obj_dt( a ); + dim_t M = bli_obj_vector_dim( z ); + dim_t N = bli_obj_vector_dim( y ); + f77_int rsa = bli_obj_row_stride( a ) ; + f77_int csa = bli_obj_col_stride( a ) ; + f77_int incw = bli_obj_vector_inc( w ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + f77_int incz = bli_obj_vector_inc( z ); + bool conjat = bli_obj_has_conj( at ); + bool conja = bli_obj_has_conj( a ); + bool conjw = bli_obj_has_conj( w ); + bool conjx = bli_obj_has_conj( x ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* AT = (float*) bli_obj_buffer( at ); + float* A = (float*) bli_obj_buffer( a ); + float* W = (float*) bli_obj_buffer( w ); + float* X = (float*) bli_obj_buffer( x ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* Z = (float*) bli_obj_buffer( z_orig ); + float* YY = (float*) bli_obj_buffer( y ); + float* ZZ = (float*) bli_obj_buffer( z ); + libblis_idotxaxpyf_check(M, N, Alpha, AT, + A, rsa, csa, W, incw, X, incx, Beta, Y, incy, Z, incz); + resid = computediffrv(M, incz, ZZ, Z); + resid += computediffrv(N, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* AT = (double*) bli_obj_buffer( at ); + double* A = (double*) bli_obj_buffer( a ); + double* W = (double*) bli_obj_buffer( w ); + double* X = (double*) bli_obj_buffer( x ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* Z = (double*) bli_obj_buffer( z_orig ); + double* YY = (double*) bli_obj_buffer( y ); + double* ZZ = (double*) bli_obj_buffer( z ); + libblis_idotxaxpyf_check(M, N, Alpha, AT, + A, rsa, csa, W, incw, X, incx, Beta, Y, incy, Z, incz); + resid = computediffrv(M, incz, ZZ, Z); + resid += computediffrv(N, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* AT = (scomplex*) bli_obj_buffer( at ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* W = (scomplex*) bli_obj_buffer( w ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* Z = (scomplex*) bli_obj_buffer( z_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + scomplex* ZZ = (scomplex*) bli_obj_buffer( z ); + libblis_icdotxaxpyf_check(M, N, Alpha, AT, conjat, + A, rsa, csa, conja, W, incw, conjw, X, incx, conjx, Beta, + Y, incy, Z, incz); + resid = computediffiv(M, incz, ZZ, Z); + resid += computediffiv(N, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* AT = (dcomplex*) bli_obj_buffer( at ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* W = (dcomplex*) bli_obj_buffer( w ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* Z = (dcomplex*) bli_obj_buffer( z_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + dcomplex* ZZ = (dcomplex*) bli_obj_buffer( z ); + libblis_icdotxaxpyf_check(M, N, Alpha, AT, conjat, + A, rsa, csa, conja, W, incw, conjw, X, incx, conjx, Beta, + Y, incy, Z, incz); + resid = computediffiv(M, incz, ZZ, Z); + resid += computediffiv(N, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return abs(resid); +} + diff --git a/gtestsuite/src/ref_dotxf.cpp b/gtestsuite/src/ref_dotxf.cpp new file mode 100644 index 000000000..337bdea7e --- /dev/null +++ b/gtestsuite/src/ref_dotxf.cpp @@ -0,0 +1,172 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotxf.h" + +using namespace std; + +//* ========================================================================== +//*> DOTXF performs vector operations +//*> y := beta * y_orig + alpha * conjat(A^T) * conjx(x) +//*> where A is an m x b matrix, and y and x are vectors. +//*> The kernel is implemented as a fused series of calls to dotxv +//*> where b is less than or equal to an implementation-dependent fusing +//*> factor specific to dotxf +//* ========================================================================== + +template +void libblis_idotxf_check(dim_t M, dim_t N, T* alpha, T* A, dim_t rsa, + dim_t csa, T* X, dim_t incx, T* beta, T* Y, dim_t incy) { + + dim_t i, j, ix, iy; + T Alpha = alpha[0]; + T Beta = beta[0]; + T temp; + if((M == 0) || (N == 0)) { + return; + } + + iy = 0; + for(j = 0 ; j < M ; j++) { + ix = 0; + temp = 0.0; + for(i = 0 ; i < N ; i++) { + temp += X[ix] * A[i*rsa + j*csa]; + ix = ix + incx; + } + temp = Alpha * temp; + Y[iy] = (Y[iy] * Beta) + temp; + iy = iy + incy; + } + + return; +} + +template +void libblis_icdotxf_check(dim_t M, dim_t N, T* alpha, T* A, dim_t rsa, +dim_t csa, bool cfa, T* X, dim_t incx, bool cfx, T* beta, T* Y, dim_t incy ) { + + dim_t i, j, ix, iy; + //T ONE = {1.0 , 0.0}; + T ZERO = {0.0 , 0.0}; + T Alpha = *alpha; + T Beta = *beta; + T temp; + + if((M == 0) || (N == 0)) { + return; + } + + if(cfx) { + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(cfa) { + for(j = 0 ; j < M ; j++) { + for(i = 0 ; i < N ; i++) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + iy = 0; + for(j = 0 ; j < M ; j++) { + ix = 0; + temp = ZERO; + for(i = 0 ; i < N ; i++) { + temp = addc(temp , mulc(X[ix] , A[i*rsa + j*csa])); + ix = ix + incx; + } + temp = mulc(Alpha , temp); + Y[iy] = addc(temp , mulc(Y[iy] , Beta)); + iy = iy + incy; + } + + return; +} + +double libblis_test_idotxf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( y ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + bool cfx = bli_obj_has_conj( x ); + bool cfa = bli_obj_has_conj( a ); + double resid = 0.0; + + //martix transpose + dim_t N = bli_obj_vector_dim( x ); + dim_t M = bli_obj_vector_dim( y ); + f77_int rsa = bli_obj_row_stride( a ); + f77_int csa = bli_obj_col_stride( a ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* X = (float*) bli_obj_buffer( x ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_idotxf_check( M, N, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* X = (double*) bli_obj_buffer( x ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_idotxf_check( M, N, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icdotxf_check( M, N, Alpha, A, rsa, csa, + cfa, X, incx, cfx, Beta, Y, incy ); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icdotxf_check( M, N, Alpha, A, rsa, csa, + cfa, X, incx, cfx, Beta, Y, incy ); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_dotxv.cpp b/gtestsuite/src/ref_dotxv.cpp new file mode 100644 index 000000000..06a303abd --- /dev/null +++ b/gtestsuite/src/ref_dotxv.cpp @@ -0,0 +1,197 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotxv.h" + +using namespace std; + +//* ========================================================================== +//*> DOTXV performs vector operations +//*> rho := beta * rho + alpha * conjx(x)^T * conjy(y) +//*> where x and y are vectors of length n, and alpha, beta, and rho are scalars. +//* ========================================================================== + +template +void libblis_idotxv_check(dim_t len, T* alpha, T* X, dim_t incx, + T* beta, T* Y, dim_t incy, T* rhorig ) { + dim_t i, ix, iy; + T ONE, ZERO; + ONE = 1.0 ; + ZERO = 0.0 ; + T Alpha = alpha[0]; + T Beta = beta[0]; + T rho = *rhorig; + + if(len == 0) { + return; + } + + rho = rho * Beta; + + if (Alpha != ONE) { + ix = 0; + if (Alpha == ZERO) { + for(i = 0 ; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = Alpha * X[ix]; + ix = ix + incx; + } + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + rho = rho + X[ix] * Y[iy]; + ix = ix + incx; + iy = iy + incy; + } + + *rhorig = rho; + return; +} + +template +void libblis_icdotxv_check(dim_t len, T* alpha, T* X, dim_t incx, T* beta, + T* Y, dim_t incy, T* rhorig, bool cfx, bool cfy) { + dim_t i, ix, iy; + T ONE, ZERO; + ONE = {1.0 , 0.0}; + ZERO = {0.0 , 0.0}; + T Alpha = *alpha; + T Beta = *beta; + T rho = *rhorig; + + if (len == 0) { + return; + } + + rho = mulc(rho , Beta); + + if(cfx) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if((Alpha.real != ONE.real) && (Alpha.imag != ONE.imag)) { + ix = 0; + if((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)) { + for(i = 0 ; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for(i = 0 ; i < len ; i++) { + X[ix] = mulc(Alpha , X[ix]); + ix = ix + incx; + } + } + } + + if(cfy) { + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = conjugate(Y[iy]); + iy = iy + incy; + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + rho = addc(rho, mulc(Y[iy] , X[ix])); + ix = ix + incx; + iy = iy + incy; + } + + *rhorig = rho; + return; +} + +double libblis_test_idotxv_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* beta, + obj_t* rho, + obj_t* rho_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + bool cfx = bli_obj_has_conj( x ); + bool cfy = bli_obj_has_conj( y ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* Y = (float*) bli_obj_buffer( y ); + float* rhorig = (float*) bli_obj_internal_scalar_buffer( rho_orig ); + float* rhp = (float*) bli_obj_internal_scalar_buffer( rho ); + libblis_idotxv_check( M, Alpha, X, incx, + Beta, Y, incy, rhorig ); + resid = (*rhp - *rhorig); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* Y = (double*) bli_obj_buffer( y ); + double* rhorig = (double*) bli_obj_internal_scalar_buffer( rho_orig ); + double* rhp = (double*) bli_obj_internal_scalar_buffer( rho ); + libblis_idotxv_check( M, Alpha, X, incx, + Beta, Y, incy, rhorig ); + resid = (*rhp - *rhorig); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + scomplex* rhorig = (scomplex*) bli_obj_internal_scalar_buffer( rho_orig ); + scomplex* rhp = (scomplex*) bli_obj_internal_scalar_buffer( rho ); + libblis_icdotxv_check( M, Alpha, X, incx, + Beta, Y, incy, rhorig, cfx, cfy ); + resid = ((*rhp).real - (*rhorig).real); + resid += ((*rhp).imag - (*rhorig).imag); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + dcomplex* rhorig = (dcomplex*) bli_obj_internal_scalar_buffer( rho_orig ); + dcomplex* rhp = (dcomplex*) bli_obj_internal_scalar_buffer( rho ); + libblis_icdotxv_check( M, Alpha, X, incx, + Beta, Y, incy, rhorig, cfx, cfy ); + resid = ((*rhp).real - (*rhorig).real); + resid += ((*rhp).imag - (*rhorig).imag); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return abs(resid); +} + diff --git a/gtestsuite/src/ref_gemm.cpp b/gtestsuite/src/ref_gemm.cpp new file mode 100644 index 000000000..99938ae3d --- /dev/null +++ b/gtestsuite/src/ref_gemm.cpp @@ -0,0 +1,317 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_gemm.h" + +using namespace std; + +//* ========================================================================== +//*> GEMM performs one of the matrix-matrix operations +//*> C := alpha*op( A )*op( B ) + beta*C, +//*> where op( X ) is one of +//*> op( X ) = X or op( X ) = X**T or op( X ) = X**H, +//*> alpha and beta are scalars, and A, B and C are matrices, with op( A ) +//*> an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. +/* +Reference GEMM implemenation C = C*Beta + Alpha*A*B +Row major A=mxk , B=kxn and C=mxn , lda=rsa=k, csa=1, ldb=rsb=n,csb=1, ldc=rsc=n,csc=1 +Col major A=mxk , B=kxn and C=mxn , rsa=1, lda=csa=m, rsb=1,ldb=csb=k, rsc=1,ldc=csc=m +*/ +//* ========================================================================== + +template +void libblis_igemm_check(dim_t M, dim_t N, dim_t K, T *alpha, T *A, + dim_t rsa, dim_t csa, T *B, dim_t rsb, dim_t csb, T* beta, + T *C, dim_t rsc, dim_t csc){ + + T Alpha = alpha[0]; + T Beta = beta[0]; + int i,j,k; + + if(( Alpha != 0.) && ( Beta != 0. )) { + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + T sum = 0.0; + for( k = 0 ; k < K ; k++ ) { + sum += A[i*rsa + k*csa] * B[k*rsb + j*csb]; + } + sum = ((Beta * C[i*rsc + j*csc]) + (Alpha * sum)); + C[i*rsc + j*csc] = sum; + } + } + } + else if(( Alpha != 0.) && ( Beta == 0. )) { + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + T sum = 0.0; + for( k = 0 ; k < K ; k++ ) { + sum += A[i*rsa + k*csa] * B[k*rsb + j*csb]; + } + sum = (Alpha * sum); + C[i*rsc + j*csc] = sum; + } + } + } + else if(( Alpha == 0.) && ( Beta != 0. )) { + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + T sum = (Beta * C[ i*rsc + j*csc ]); + C[i*rsc + j*csc] = sum; + } + } + } + else /*if(( Alpha == 0.) && ( Beta == 0. ))*/ { + // + } + + return; +} + +template +void libblis_icgemm_check(dim_t M, dim_t N, dim_t K, T *alpha, + T *A, dim_t rsa, dim_t csa, bool conja, T *B, dim_t rsb, dim_t csb, + bool conjb, T* beta, T *C, dim_t rsc, dim_t csc){ + + T Alpha = *alpha; + T Beta = *beta; + int i,j,k; + + if(conja) { + for( i = 0 ; i < M ; i++ ) { + for( k = 0 ; k < K ; k++ ) { + A[i*rsa + k*csa] = conjugate(A[i*rsa + k*csa]); + } + } + } + if(conjb) { + for( k = 0 ; k < K ; k++ ) { + for( j = 0 ; j < N ; j++ ) { + B[k*rsb + j*csb] = conjugate(B[k*rsb + j*csb]); + } + } + } + + if((Alpha.real != 0.) && (Beta.real != 0.)) { + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + T sum = {0.0, 0.0}; + for( k = 0 ; k < K ; k++ ) { + T aa = A[i*rsa + k*csa]; + T bb = B[k*rsb + j*csb]; + sum = addc(sum , mulc(aa , bb)); + } + T xc = C[i*rsc + j*csc]; + sum = mulc(Alpha,sum); + xc = mulc(Beta,xc); + C[i*rsc + j*csc] = addc(xc , sum); + } + } + } + else if(( Alpha.real != 0.) && ( Beta.real == 0. )) { + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + T sum = {0.0, 0.0}; + for( k = 0 ; k < K ; k++ ) { + T aa = A[i*rsa + k*csa]; + T bb = B[k*rsb + j*csb]; + sum = addc(sum , mulc(aa , bb)); + } + sum = mulc(Alpha,sum); + C[i*rsc + j*csc] = sum; + } + } + } + else if(( Alpha.real == 0.) && ( Beta.real != 0. )) { + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + T sum ; + T cc = C[i*rsc + j*csc]; + sum = mulc(Beta,cc); + C[i*rsc + j*csc] = sum; + } + } + } else /*if(( Alpha == 0.) && ( Beta == 0. ))*/ { + // + } + return ; +} + +double libblis_test_igemm_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + num_t dt +){ + dim_t M = bli_obj_length( c_orig ); + dim_t N = bli_obj_width( c_orig ); + dim_t K = bli_obj_width_after_trans( a ); + dim_t rsa, csa; + dim_t rsb, csb; + dim_t rsc, csc; + bool conja = bli_obj_has_conj( a ); + bool conjb = bli_obj_has_conj( b ); + trans_t transA = bli_obj_onlytrans_status( a ); + trans_t transB = bli_obj_onlytrans_status( b ); + double resid = 0.0; + + if( bli_obj_row_stride( c ) == 1 ) { + rsa = transA ? bli_obj_col_stride( a ) : bli_obj_row_stride( a ) ; + csa = transA ? bli_obj_row_stride( a ) : bli_obj_col_stride( a ) ; + rsb = transB ? bli_obj_col_stride( b ) : bli_obj_row_stride( b ) ; + csb = transB ? bli_obj_row_stride( b ) : bli_obj_col_stride( b ) ; + rsc = 1; + csc = bli_obj_col_stride( c_orig ); + } else { + rsa = transA ? bli_obj_col_stride( a ) : bli_obj_row_stride( a ) ; + csa = transA ? bli_obj_row_stride( a ) : bli_obj_col_stride( a ) ; + rsb = transB ? bli_obj_col_stride( b ) : bli_obj_row_stride( b ) ; + csb = transB ? bli_obj_row_stride( b ) : bli_obj_col_stride( b ) ; + rsc = bli_obj_row_stride( c_orig ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* B = (float*) bli_obj_buffer( b ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* C = (float*) bli_obj_buffer( c_orig ); + float* CC = (float*) bli_obj_buffer( c ); + libblis_igemm_check(M, N, K, Alpha, A, rsa, csa, + B, rsb, csb, Beta, C, rsc, csc); + resid = computediffrm(M, N, CC, C, rsc, csc); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* B = (double*) bli_obj_buffer( b ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* C = (double*) bli_obj_buffer( c_orig ); + double* CC = (double*) bli_obj_buffer( c ); + libblis_igemm_check(M, N, K, Alpha, A, rsa, csa, + B, rsb, csb, Beta, C, rsc, csc); + resid = computediffrm(M, N, CC, C, rsc, csc); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* B = (scomplex*) bli_obj_buffer( b ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* C = (scomplex*) bli_obj_buffer( c_orig ); + scomplex* CC = (scomplex*) bli_obj_buffer( c ); + libblis_icgemm_check(M, N, K, Alpha, A, rsa, csa, + conja, B, rsb, csb, conjb, Beta, C, rsc, csc); + resid = computediffim(M, N, CC, C, rsc, csc); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* B = (dcomplex*) bli_obj_buffer( b ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* C = (dcomplex*) bli_obj_buffer( c_orig ); + dcomplex* CC = (dcomplex*) bli_obj_buffer( c ); + libblis_icgemm_check(M, N, K, Alpha, A, rsa, csa, + conja, B, rsb, csb, conjb, Beta, C, rsc, csc); + resid = computediffim(M, N, CC, C, rsc, csc); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + +template +double libblis_check_nan_real( dim_t rsc, dim_t csc, obj_t* c ) { + + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + T* C = (T*) bli_obj_buffer( c ); + double resid = 0.0; + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = C[ i*rsc + j*csc ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rsc, dim_t csc, obj_t* c ) { + + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + T* C = (T*) bli_obj_buffer( c ); + double resid = 0.0; + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = C[ i*rsc + j*csc ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_gemm(obj_t* c, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( c ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_gemmt.cpp b/gtestsuite/src/ref_gemmt.cpp new file mode 100644 index 000000000..59a194a97 --- /dev/null +++ b/gtestsuite/src/ref_gemmt.cpp @@ -0,0 +1,445 @@ +#include +#include "blis_test.h" +#include "blis_utils.h" +#include "test_gemmt.h" + +using namespace std; + +//* ========================================================================== +//*> GEMMT performs one of the matrix-matrix operations +//*> C := beta * C + alpha * transa(A) * transb(B) +//* ========================================================================== + +void libblis_gemv_check(trans_t transA , dim_t M, dim_t N, float* Alpha, + float* A, dim_t rsa, dim_t csa, bool conja, float* X, dim_t incx, bool conjx, + float* Beta, float* Y, dim_t incy) { + libblis_igemv_check(transA, M, N, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy); + return; +} + +void libblis_gemv_check(trans_t transA , dim_t M, dim_t N, double* Alpha, + double* A, dim_t rsa, dim_t csa, bool conja, double* X, dim_t incx, + bool conjx, double* Beta, double* Y, dim_t incy) { + libblis_igemv_check(transA, M, N, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy); + return; +} + +void libblis_gemv_check(trans_t transA , dim_t M, dim_t N, scomplex* Alpha, + scomplex* A, dim_t rsa, dim_t csa, bool conja, scomplex* X, dim_t incx, + bool conjx, scomplex* Beta, scomplex* Y, dim_t incy) { + libblis_icgemv_check(transA, M, N, Alpha, A, rsa, csa, + conja, X, incx, Beta, Y, incy, conjx); + return; +} +void libblis_gemv_check(trans_t transA , dim_t M, dim_t N, dcomplex* Alpha, + dcomplex* A, dim_t rsa, dim_t csa, bool conja, dcomplex* X, dim_t incx, + bool conjx, dcomplex* Beta, dcomplex* Y, dim_t incy) { + libblis_icgemv_check(transA, M, N, Alpha, A, rsa, csa, + conja, X, incx, Beta, Y, incy, conjx); + return; +} + + +void libblis_gemm_check(dim_t M, dim_t N, dim_t K, float* Alpha, float* A, + dim_t rsa, dim_t csa, bool conja, float* B, dim_t rsb, dim_t csb, bool conjb, + float* Beta, float* C, dim_t rsc, dim_t csc) { + libblis_igemm_check(M, N, K, Alpha, A, rsa, csa, B, rsb, + csb, Beta, C, rsc, csc); + return; +} + +void libblis_gemm_check(dim_t M, dim_t N, dim_t K, double* Alpha, double* A, + dim_t rsa, dim_t csa, bool conja, double* B, dim_t rsb, dim_t csb, bool conjb, + double* Beta, double* C, dim_t rsc, dim_t csc) { + libblis_igemm_check(M, N, K, Alpha, A, rsa, csa, B, rsb, + csb, Beta, C, rsc, csc); + return; +} + +void libblis_gemm_check(dim_t M, dim_t N, dim_t K, scomplex* Alpha, scomplex* A, + dim_t rsa, dim_t csa, bool conja, scomplex* B, dim_t rsb, dim_t csb, bool conjb, + scomplex* Beta, scomplex* C, dim_t rsc, dim_t csc) { + libblis_icgemm_check(M, N, K, Alpha, A, rsa, csa, conja, + B, rsb, csb, conjb, Beta, C, rsc, csc); + return; +} + +void libblis_gemm_check(dim_t M, dim_t N, dim_t K, dcomplex* Alpha, dcomplex* A, + dim_t rsa, dim_t csa, bool conja, dcomplex* B, dim_t rsb, dim_t csb, bool conjb, + dcomplex* Beta, dcomplex* C, dim_t rsc, dim_t csc) { + libblis_icgemm_check(M, N, K, Alpha, A, rsa, csa, conja, + B, rsb, csb, conjb, Beta, C, rsc, csc); + return; +} + +#define CROSSOVER_GEMMT 24 + +dim_t rec_split(dim_t n, num_t dt) { + dim_t res = 0; + + switch( dt ) { + case BLIS_FLOAT : + { + res = ((n >= 32) ? ((n + 16) / 32) * 16 : n / 2); + break; + } + case BLIS_DOUBLE : + { + res = ((n >= 16) ? ((n + 8) / 16) * 8 : n / 2); + break; + } + case BLIS_SCOMPLEX : + { + res = ((n >= 16) ? ((n + 8) / 16) * 8 : n / 2); + break; + } + case BLIS_DCOMPLEX : + { + res = ((n >= 8) ? ((n + 4) / 8) * 4 : n / 2); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return res; +} + +/** sgemmt's unblocked compute kernel */ +template +static void gemmt_rec2(uplo_t uploc, trans_t transA, trans_t transB, + dim_t n, dim_t k, T* alpha, T* A, dim_t ldA, bool conja, T* B, + dim_t ldB, bool conjb, T* beta, T* C, dim_t ldC ) { + + dim_t incB, incC; + dim_t rsa, csa; + dim_t i; + + rsa = (transA == BLIS_NO_TRANSPOSE) ? 1 : ldA ; + csa = (transA == BLIS_NO_TRANSPOSE) ? ldA : 1 ; + incB = (transB == BLIS_NO_TRANSPOSE) ? 1 : ldB ; + incC = 1; + + for (i = 0; i < n; i++) { + // A_0 + // A_i + T * A_0 = A; + T * A_i = A + ((transA == BLIS_NO_TRANSPOSE) ? i : ldA * i); + + // * B_i * + T * B_i = B + ((transB == BLIS_NO_TRANSPOSE) ? ldB * i : i); + + // * C_0i * + // * C_ii * + T * C_0i = C + ldC * i; + T * C_ii = C + ldC * i + i; + + if (uploc == BLIS_LOWER) { + int nmi = n - i; + if (transA == BLIS_NO_TRANSPOSE) + libblis_gemv_check(transA, nmi, k, alpha, A_i, rsa, csa, conja, B_i, incB, conjb, beta, C_ii, incC); + else + libblis_gemv_check(transA, k, nmi, alpha, A_i, rsa, csa, conja, B_i, incB, conjb, beta, C_ii, incC); + } else { + int ip1 = i + 1; + if (transA == BLIS_NO_TRANSPOSE) + libblis_gemv_check(transA, ip1, k, alpha, A_0, rsa, csa, conja, B_i, incB, conjb, beta, C_0i, incC); + else + libblis_gemv_check(transA, k, ip1, alpha, A_0, rsa, csa, conja, B_i, incB, conjb, beta, C_0i, incC); + } + } +} + +/** sgemmt's recursive compute kernel */ +template +static void gemmt_rec(uplo_t uploc, trans_t transA, trans_t transB, + dim_t n, dim_t k, T* alpha, T* A, dim_t ldA, bool cfA, T* B, + dim_t ldB, bool cfB, T* beta, T* C, dim_t ldC, num_t dt ) { + if (n <= max(CROSSOVER_GEMMT, 1)) { + // Unblocked + gemmt_rec2(uploc, transA, transB, n, k, alpha, A, ldA, cfA, + B, ldB, cfB, beta, C, ldC); + return; + } + + dim_t rsa, csa; + dim_t rsb, csb; + dim_t rsc, csc; + + rsa = (transA == BLIS_NO_TRANSPOSE) ? 1 : ldA ; + csa = (transA == BLIS_NO_TRANSPOSE) ? ldA : 1 ; + rsb = (transB == BLIS_NO_TRANSPOSE) ? 1 : ldB ; + csb = (transB == BLIS_NO_TRANSPOSE) ? ldB : 1 ; + rsc = 1 ; + csc = ldC; + + // Splitting + dim_t n1 = rec_split(n, dt); //SREC_SPLIT(n); + dim_t n2 = n - n1; + + // A_T + // A_B + T * A_T = A; + T * A_B = A + ((transA == BLIS_NO_TRANSPOSE) ? n1 : ldA * n1); + + // B_L B_R + T * B_L = B; + T * B_R = B + ((transB == BLIS_NO_TRANSPOSE) ? ldB * n1 : n1); + + // C_TL C_TR + // C_BL C_BR + T * C_TL = C; + T * C_TR = C + ldC * n1; + T * C_BL = C + n1; + T * C_BR = C + ldC * n1 + n1; + + // recursion(C_TL) + gemmt_rec(uploc, transA, transB, n1, k, alpha, A_T, ldA, cfA, B_L, ldB, + cfB, beta, C_TL, ldC, dt); + + if (uploc == BLIS_LOWER) + // C_BL = alpha A_B B_L + beta C_BL + libblis_gemm_check(n2, n1, k, alpha, A_B, rsa, csa, cfA, + B_L, rsb, csb, cfB, beta, C_BL, rsc, csc); + else + // C_TR = alpha A_T B_R + beta C_TR + libblis_gemm_check(n1, n2, k, alpha, A_T, rsa, csa, cfA, + B_R, rsb, csb, cfB, beta, C_TR, rsc, csc); + + // recursion(C_BR) + gemmt_rec(uploc, transA, transB, n2, k, alpha, A_B, ldA, cfA, B_R, ldB, + cfB, beta, C_BR, ldC, dt); +} + +double computediff(dim_t n,dim_t k, float *act, float *ref, dim_t rsc, dim_t csc) { + return computediffrm(n, k, act, ref, rsc, csc); +} + +double computediff(dim_t n,dim_t k, double *act, double *ref, dim_t rsc, dim_t csc) { + return computediffrm(n, k, act, ref, rsc, csc); +} + +double computediff(dim_t n,dim_t k, scomplex *act, scomplex *ref, dim_t rsc, dim_t csc) { + return computediffim(n, k, act, ref, rsc, csc); +} +double computediff(dim_t n,dim_t k, dcomplex *act, dcomplex *ref, dim_t rsc, dim_t csc) { + return computediffim(n, k, act, ref, rsc, csc); +} + +/** GEMMT computes a matrix-matrix product with general matrices but updates + * only the upper or lower triangular part of the result matrix. + * */ +template +double libblis_igemmt_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + num_t dt +){ + dim_t k = bli_obj_width_after_trans( a ); + dim_t n = bli_obj_width( c ); + uplo_t uploc = bli_obj_uplo( c ); + trans_t transA = bli_obj_onlytrans_status( a ); + trans_t transB = bli_obj_onlytrans_status( b ); + dim_t lda, ldb, ldc; + dim_t rsa, csa; + dim_t rsb, csb; + dim_t rsc, csc; + + bool crsf = bli_obj_is_row_stored( c ); + + if ( crsf ) { + rsa = transA ? bli_obj_col_stride( a ) : bli_obj_row_stride( a ) ; + csa = transA ? bli_obj_row_stride( a ) : bli_obj_col_stride( a ) ; + rsb = transB ? bli_obj_col_stride( b ) : bli_obj_row_stride( b ) ; + csb = transB ? bli_obj_row_stride( b ) : bli_obj_col_stride( b ) ; + rsc = bli_obj_row_stride( c_orig ) ; + csc = 1 ; + lda = transA ? csa : rsa ; + ldb = transB ? csb : rsb ; + ldc = rsc ; + } else { + rsa = transA ? bli_obj_col_stride( a ) : bli_obj_row_stride( a ) ; + csa = transA ? bli_obj_row_stride( a ) : bli_obj_col_stride( a ) ; + rsb = transB ? bli_obj_col_stride( b ) : bli_obj_row_stride( b ) ; + csb = transB ? bli_obj_row_stride( b ) : bli_obj_col_stride( b ) ; + rsc = 1 ; + csc = bli_obj_col_stride( c_orig ) ; ; + lda = transA ? rsa : csa ; + ldb = transB ? rsb : csb ; + ldc = csc ; + } + + T* A = (T*) bli_obj_buffer( a ); + T* B = (T*) bli_obj_buffer( b ); + T* C = (T*) bli_obj_buffer( c_orig ); + T* Alpha = (T*) bli_obj_buffer( alpha ); + T* Beta = (T*) bli_obj_buffer( beta ); + bool conja = bli_obj_has_conj( a ); + bool conjb = bli_obj_has_conj( b ); + + if(bli_obj_has_conj(a)) { + conjugate_tensor(a, dt); + transA = bli_obj_onlytrans_status( a ); + conja = false; + } + + if(bli_obj_has_conj(b)) { + conjugate_tensor(b, dt); + transB = bli_obj_onlytrans_status( b ); + conjb = false; + } + + // Recursive kernel + if( !crsf ) { + gemmt_rec(uploc, transA, transB, n, k, Alpha, A, lda, + conja, B, ldb, conjb, Beta, C, ldc, dt); + }else { + if( uploc == BLIS_UPPER) + uploc = BLIS_LOWER; + else if(uploc == BLIS_LOWER) + uploc = BLIS_UPPER; + + gemmt_rec(uploc, transB, transA, n, k, Alpha, B, ldb, + conjb, A, lda, conja, Beta, C, ldc, dt); + } + + T* CC = (T*) bli_obj_buffer( c ); + + double resid = 0.0; + resid = computediff(n, k, C, CC, rsc, csc); + + return resid; +} + +double libblis_test_igemmt_check( + test_params_t *params, + obj_t *alpha, + obj_t *a, + obj_t *b, + obj_t *beta, + obj_t *c, + obj_t *c_orig +) { + double resid = 0.0; + num_t dt = bli_obj_dt(c); + + switch( dt ) { + case BLIS_FLOAT : + { + resid = libblis_igemmt_check( params, alpha, a, b, beta, + c, c_orig, dt ); + break; + } + case BLIS_DOUBLE : + { + resid = libblis_igemmt_check( params, alpha, a, b, beta, + c, c_orig, dt ); + break; + } + case BLIS_SCOMPLEX : + { + resid = libblis_igemmt_check( params, alpha, a, b, beta, + c, c_orig, dt ); + break; + } + case BLIS_DCOMPLEX : + { + resid = libblis_igemmt_check( params, alpha, a, b, beta, + c, c_orig, dt ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + + +template +double libblis_check_nan_real( dim_t rsc, dim_t csc, obj_t* c ) { + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + double resid = 0.0; + T* C = (T*) bli_obj_buffer( c ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = C[ i*rsc + j*csc ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rsc, dim_t csc, obj_t* c ) { + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + double resid = 0.0; + U* C = (U*) bli_obj_buffer( c ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = C[ i*rsc + j*csc ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_gemmt(obj_t* c) { + dim_t rsc, csc; + double resid = 0.0; + + num_t dt = bli_obj_dt(c); + if( bli_obj_row_stride( c ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + + diff --git a/gtestsuite/src/ref_gemv.cpp b/gtestsuite/src/ref_gemv.cpp new file mode 100644 index 000000000..8ae50475b --- /dev/null +++ b/gtestsuite/src/ref_gemv.cpp @@ -0,0 +1,319 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_gemv.h" + +using namespace std; + +//* ========================================================================== +//*> GEMV performs one of the matrix-vector operations +//*> y := alpha*A*x + beta*y, or y := alpha*A**T*x + beta*y, or +//*> y := alpha*A**H*x + beta*y, +//* ========================================================================== + +template +void libblis_igemv_check(trans_t transA , dim_t M, dim_t N, T* alpha, T* A, + dim_t rsa, dim_t csa, T* X, dim_t incx, T* beta, T* Y, dim_t incy) { + T ONE, ZERO; + T temp; + dim_t i, ix, iy, j, jx, jy, kx, ky, lenx, leny; + bool NOTRANSA; + + ONE = 1.0 ; + ZERO = 0.0 ; + T Alpha = alpha[0]; + T Beta = beta[0]; + + if (((M == 0) || (N == 0)) || + ((Alpha == ZERO) && (Beta == ONE))) { + return; + } + + NOTRANSA = ((transA == BLIS_NO_TRANSPOSE) || (transA == BLIS_CONJ_NO_TRANSPOSE)); + + /* Set lenx and leny, the lengths of the vectors x and y, + and set up the start points in X and Y. */ + if (NOTRANSA) { + lenx = N; + leny = M; + } + else { + lenx = M; + leny = N; + } + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (lenx - 1) * incx; + } + + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (leny - 1) * incy; + } + + //* Start the operations. Here, the elements of A are + //* accessed sequentially with one pass through A. + //* First form y := beta*y. + if (Beta != ONE) { + iy = ky; + if (Beta == ZERO) { + for(i = 0 ; i < leny ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < leny ; i++) { + Y[iy] = Beta*Y[iy]; + iy = iy + incy; + } + } + } + + if(Alpha == ZERO) + return; + + if(NOTRANSA) { + /* Form y := alpha*A*x + y.*/ + jx = kx; + for(j = 0 ; j < N ; j++) { + temp = Alpha*X[jx]; + iy = ky; + for(i = 0 ; i < M ; i++) { + Y[iy] = Y[iy] + temp * A[i*rsa + j*csa]; + iy = iy + incy; + } + jx = jx + incx; + } + } + else { + //* Form y := alpha*A**T*x + y. + jy = ky; + for(i = 0 ; i < N ; i++) { + temp = ZERO; + ix = kx; + for(j = 0 ; j < M ; j++) { + temp = temp + A[i*rsa + j*csa] * X[ix]; + ix = ix + incx; + } + Y[jy] = Y[jy] + Alpha*temp; + jy = jy + incy; + } + } + return; +} + +template +void libblis_icgemv_check(trans_t transA , dim_t M, dim_t N, T* alpha, T* A, + dim_t rsa, dim_t csa, bool conja, T* X, dim_t incx, T* beta, T* Y, + dim_t incy, bool conjx) { + T ONE; + T ZERO; + T temp; + dim_t i, ix, iy, j, jx, jy, kx, ky, lenx, leny; + bool NOTRANSA; + + ONE = {1.0 , 0.0}; + ZERO = {0.0 , 0.0}; + T Alpha = *alpha; + T Beta = *beta; + + if (((M == 0) || (N == 0)) || + ((Alpha.real == ZERO.real) && (Beta.real == ONE.real))) { + return ; + } + + NOTRANSA = ((transA == BLIS_NO_TRANSPOSE) || (transA == BLIS_CONJ_NO_TRANSPOSE)); + + /* Set lenx and leny, the lengths of the vectors x and y, + and set up the start points in X and Y. */ + if(NOTRANSA) { + lenx = N; + leny = M; + } + else { + lenx = M; + leny = N; + } + + if (incx > 0) { + kx = 0; + } + else{ + kx = 1 - (lenx - 1) * incx; + } + + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (leny - 1)*incy; + } + + if (Alpha.real == ZERO.real) + return; + + if( conja ) { + for(i = 0; i < leny ; i++) { + for(j = 0 ; j < lenx ; j++) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + if(conjx) { + ix = kx; + for(i = 0 ; i < lenx ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + /* First form y := beta*y. */ + if (Beta.real != ONE.real) { + iy = ky; + if (Beta.real == ZERO.real) { + for(i = 0; i < leny ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < leny ; i++) { + Y[iy] = mulc(Beta , Y[iy]); + iy = iy + incy; + } + } + } + + if (NOTRANSA) { + /* Form y := alpha*A*x + y. */ + jx = kx; + for(j = 0; j < N ; j++) { + temp = mulc(Alpha , X[jx]); + iy = ky; + for(i = 0; i < M ; i++) { + Y[iy] = addc(Y[iy] , mulc(temp , A[i*rsa + j*csa])); + iy = iy + incy; + } + jx = jx + incx; + } + } + else { + /* Form y := alpha*A**T*x + y or y := alpha*A**H*x + y. */ + jy = ky; + for(i = 0 ; i < N ; i++) { + temp = ZERO; + ix = kx; + for(j = 0 ; j < M ; j++) { + temp = addc(temp , mulc(A[i*rsa + j*csa] , X[ix])); + ix = ix + incx; + } + Y[jy] = addc(Y[jy] , mulc(Alpha , temp)); + jy = jy + incy; + } + } + return; +} + +double libblis_test_igemv_check( + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + num_t dt +){ + double resid = 0.0; + f77_int rsa, csa; + trans_t transA = bli_obj_onlytrans_status( a ); + f77_int M = transA ? bli_obj_vector_dim( x ) : bli_obj_vector_dim( y_orig ); + f77_int N = transA ? bli_obj_vector_dim( y_orig ): bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y_orig ); + f77_int len = bli_obj_vector_dim( y_orig ); + bool cfx = bli_obj_has_conj( x ); + bool cfa = bli_obj_has_conj( a ); + bool sf = bli_obj_is_col_stored( a ); + + if( sf ) { + rsa = bli_obj_has_trans( a ) ? bli_obj_col_stride( a ) : bli_obj_row_stride( a ) ; + csa = bli_obj_has_trans( a ) ? bli_obj_row_stride( a ) : bli_obj_col_stride( a ) ; + } else { + rsa = bli_obj_has_trans( a ) ? bli_obj_col_stride( a ) : bli_obj_row_stride( a ) ; + csa = bli_obj_has_trans( a ) ? bli_obj_row_stride( a ) : bli_obj_col_stride( a ) ; + + if(transA == BLIS_NO_TRANSPOSE) transA = BLIS_TRANSPOSE; + else if(transA == BLIS_TRANSPOSE) transA = BLIS_NO_TRANSPOSE; + else if ( transA == BLIS_CONJ_NO_TRANSPOSE) transA = BLIS_CONJ_TRANSPOSE; + else /*if ( transa == BLIS_CONJ_TRANSPOSE )*/ transA = BLIS_CONJ_NO_TRANSPOSE; + M = M ^ N; + N = M ^ N; + M = M ^ N; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + libblis_igemv_check(transA, M, N, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy ); + float* YY = (float*) bli_obj_buffer( y ); + resid = computediffrv(len, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + libblis_igemv_check(transA, M, N, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy ); + double* YY = (double*) bli_obj_buffer( y ); + resid = computediffrv(len, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + libblis_icgemv_check(transA, M, N, Alpha, A, rsa, + csa, cfa, X, incx, Beta, Y, incy, cfx ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + resid = computediffiv(len, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + libblis_icgemv_check(transA, M, N, Alpha, A, rsa, + csa, cfa, X, incx, Beta, Y, incy, cfx ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + resid = computediffiv(len, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_ger.cpp b/gtestsuite/src/ref_ger.cpp new file mode 100644 index 000000000..1a2824dad --- /dev/null +++ b/gtestsuite/src/ref_ger.cpp @@ -0,0 +1,184 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_ger.h" + +using namespace std; + +//* ========================================================================== +//*> GER performs the rank 1 operation +//*> A := alpha*x*y**T + A, +//*> where alpha is a scalar, x is an m element vector, y is an n element +//*> vector and A is an m by n matrix. +//* ========================================================================== + +template +void libblis_iger_check(dim_t M, dim_t N, T *alpha, T *X, dim_t incx, + T* Y, dim_t incy, T* A, dim_t rsa, dim_t csa) { + T Alpha = alpha[0]; + T temp; + dim_t i, ix, j, jy, kx; + T ZERO = 0.0; + + if ((M == 0) || (N == 0) || + (Alpha == ZERO)) + return; + + if (incy > 0) { + jy = 0; + } + else { + jy = 1 - (N - 1)*incy; + } + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (M - 1)*incx; + } + + for(j = 0; j < N ; j++) { + if (Y[jy] != ZERO) { + temp = Alpha * Y[jy]; + ix = kx; + for(i = 0 ; i < M ; i++) { + A[i*rsa + j *csa] = A[i*rsa + j *csa] + temp * X[ix]; + ix = ix + incx; + } + } + jy = jy + incy; + } + return; +} + +template +void libblis_icger_check(dim_t M, dim_t N, T *alpha, T *X, dim_t incx, + bool conjx, T* Y, dim_t incy, bool conjy, T* A, dim_t rsa, dim_t csa) { + + T Alpha = alpha[0]; + T temp; + dim_t i, ix, j, jy, kx; + T ZERO = {0.0 , 0.0}; + + if ((M == 0) || (N == 0) || + ((Alpha.real == ZERO.real) &&(Alpha.imag == ZERO.imag))) + return; + + ix = 0; + if(conjx) { + for(i = 0 ; i < M ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + jy = 0; + if(conjy) { + for(j = 0; j < N ; j++) { + Y[jy] = conjugate(Y[jy]); + jy = jy + incy; + } + } + + if (incy > 0) { + jy = 0; + } + else { + jy = 1 - (N - 1)*incy; + } + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (M - 1)*incx; + } + + for(j = 0; j < N ; j++) { + if ((Y[jy].real != ZERO.real) || (Y[jy].imag != ZERO.imag)) { + temp = mulc(Alpha , Y[jy]); + ix = kx; + for(i = 0 ; i < M ; i++) { + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , mulc(temp , X[ix])); + ix = ix + incx; + } + } + jy = jy + incy; + } + return; +} + +double libblis_test_iger_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +){ + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_length( a ); + dim_t N = bli_obj_width( a ); + dim_t incx = bli_obj_vector_inc( x ); + dim_t incy = bli_obj_vector_inc( y ); + bool conjx = bli_obj_has_conj( x ); + bool conjy = bli_obj_has_conj( y ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a_orig ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y ); + float* AA = (float*) bli_obj_buffer( a ); + libblis_iger_check(M, N, Alpha, X, incx, + Y, incy, A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a_orig ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y ); + double* AA = (double*) bli_obj_buffer( a ); + libblis_iger_check(M, N, Alpha, X, incx, + Y, incy, A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a_orig ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + scomplex* AA = (scomplex*) bli_obj_buffer( a ); + libblis_icger_check(M, N, Alpha, X, incx, conjx, + Y, incy, conjy, A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a_orig ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + dcomplex* AA = (dcomplex*) bli_obj_buffer( a ); + libblis_icger_check(M, N, Alpha, X, incx, conjx, + Y, incy, conjy, A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_hemm.cpp b/gtestsuite/src/ref_hemm.cpp new file mode 100644 index 000000000..8dbf0aabb --- /dev/null +++ b/gtestsuite/src/ref_hemm.cpp @@ -0,0 +1,486 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_hemm.h" + +using namespace std; + +//* ========================================================================== +//*> HEMM performs one of the matrix-matrix operations +//*> C := alpha*A*B + beta*C, +//*> or +//*> C := alpha*B*A + beta*C, +//*> where alpha and beta are scalars, A is an hermitian matrix and B and +//*> C are m by n matrices. +//* ========================================================================== + +template +void libblis_ihemm_check(side_t side, uplo_t uplo, dim_t M, dim_t N, + T Alpha, T* A, dim_t rsa, dim_t csa, T* B, dim_t rsb, dim_t csb, T Beta, + T* C, dim_t rsc, dim_t csc ) +{ + T ONE = 1.0; + T ZERO = 0.0; + T tmp1, tmp2; + bool LSIDE, UPPER; + dim_t i, j, k; + + //* Test the input parameters. + LSIDE = (side == BLIS_LEFT); + UPPER = (uplo == BLIS_UPPER); + + if( (M == 0 || N == 0) || ( Alpha == ZERO && Beta == ONE ) ) + return; + + //* And when Alpha.eq.zero. + if( Alpha == ZERO ) + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + return; + } + + //* Start the operations. + if( LSIDE ) + { + //* Form C := Alpha*A*B + Beta*C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp1 = Alpha*B[i*rsb + j*csb]; + tmp2 = ZERO; + for( k = 0 ; k < i ; k++ ) + { + C[k*rsc + j*csc] = C[k*rsc + j*csc] + tmp1*A[k*rsa + i*csa]; + tmp2 = tmp2 + B[k*rsb + j*csb] * A[k*rsa + i*csa]; + } + if (Beta == ZERO) + { + C[i*rsc + j*csc] = tmp1*A[i*rsa + i*csa] + Alpha*tmp2; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + tmp1*A[i*rsa + i*csa] + Alpha*tmp2; + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = (M-1) ; i >= 0 ; i-- ) + { + tmp1 = Alpha*B[i*rsb + j*csb]; + tmp2 = ZERO; + for( k = (i+1) ; k < M ; k++ ) + { + C[k*rsc + j*csc] = C[k*rsc + j*csc] + tmp1*A[k*rsa + i*csa]; + tmp2 = tmp2 + B[k*rsb + j*csb]*A[k*rsa + i*csa]; + } + if (Beta == ZERO) + { + C[i*rsc + j*csc] = tmp1*A[i*rsa + i*csa] + Alpha*tmp2; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + tmp1*A[i*rsa + i*csa] + Alpha*tmp2; + } + } + } + } + } + else + { + //* Form C := Alpha*B*A + Beta*C. + for( j = 0 ; j < N ; j++ ) + { + tmp1 = Alpha*A[j*rsa + j*csa]; + if( Beta == ZERO ) + { + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = tmp1*B[i*rsb + j*csb]; + } + } + else + { + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + tmp1*B[i*rsb + j*csb]; + } + } + for( k = 0 ; k < j ; k++ ) + { + if( UPPER ) + { + tmp1 = Alpha*A[k*rsa + j*csa]; + } + else + { + tmp1 = Alpha*A[j*rsa + k*csa]; + } + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + tmp1*B[i*rsb + k*csb]; + } + } + for( k = (j+1) ; k < N ; k++ ) + { + if( UPPER ) + { + tmp1 = Alpha*A[j*rsa + k*csa]; + } + else + { + tmp1 = Alpha*A[k*rsa + j*csa]; + } + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + tmp1*B[i*rsb + k*csb]; + } + } + } + } + return; +} + +template +void libblis_ichemm_check(side_t side, uplo_t uplo, dim_t M, dim_t N, + T Alpha, T* A, dim_t rsa, dim_t csa, T* B, dim_t rsb, dim_t csb, T Beta, + T* C, dim_t rsc, dim_t csc ) +{ + T ONE = {1.0 , 0.0}; + T ZERO = {0.0 , 0.0}; + T tmp1, tmp2; + bool LSIDE, UPPER; + dim_t i, j, k; + + //* Test the input parameters. + LSIDE = (side == BLIS_LEFT); + UPPER = (uplo == BLIS_UPPER); + + if( (M == 0 || N == 0) || ( Alpha.real == ZERO.real && Beta.real == ONE.real ) ) + return; + + //* And when Alpha.eq.zero. + if( Alpha.real == ZERO.real ) + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + return; + } + + //* Start the operations. + if( LSIDE ) + { + //* Form C := Alpha*A*B + Beta*C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp1 = mulc(Alpha , B[i*rsb + j*csb]); + tmp2 = ZERO; + for( k = 0 ; k < i ; k++ ) + { + C[k*rsc + j*csc] = addc(C[k*rsc + j*csc] , mulc(tmp1 , A[k*rsa + i*csa])); + tmp2 = addc(tmp2 , mulc(B[k*rsb + j*csb] , conjugate(A[k*rsa + i*csa]))); + } + if (Beta.real == ZERO.real) + { + C[i*rsc + j*csc] = addc(mulc(tmp1 , real(A[i*rsa + i*csa])) , mulc(Alpha , tmp2)); + } + else + { + tmp2 = addc(mulc(tmp1 , real(A[i*rsa + i*csa])) , mulc(Alpha , tmp2)); + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , tmp2); + //C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]) + mulc(tmp1 , real(A[i*rsa + i*csa])) + mulc(Alpha , tmp2); + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = (M-1) ; i >= 0 ; i-- ) + { + tmp1 = mulc(Alpha , B[i*rsb + j*csb]); + tmp2 = ZERO; + for( k = (i+1) ; k < M ; k++ ) + { + C[k*rsc + j*csc] = addc(C[k*rsc + j*csc] , mulc(tmp1 , A[k*rsa + i*csc])); + tmp2 = addc(tmp2 , mulc(B[k*rsb + j*csb] , conjugate(A[k*rsa + i*csa]))); + } + if (Beta.real == ZERO.real) + { + C[i*rsc + j*csc] = addc(mulc(tmp1 , real(A[i*rsa + i*csa])) , mulc(Alpha , tmp2)); + } + else + { + tmp2 = addc(mulc(tmp1 , real(A[i*rsa + i*csa])) , mulc(Alpha , tmp2)); + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , tmp2); + //C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]) + mulc(tmp1 , real(A[i*rsa + i*csa])) + mulc(Alpha , tmp2); + } + } + } + } + } + else + { + //* Form C := Alpha*B*A + Beta*C. + for( j = 0 ; j < N ; j++ ) + { + tmp1 = mulc(Alpha , real(A[j*rsa + j*csa])); + if (Beta.real == ZERO.real) + { + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = mulc(tmp1 , B[i*rsb + j*csb]); + } + } + else + { + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , mulc(tmp1 , B[i*rsb + j*csb])); + } + } + for( k = 0 ; k < j ; k++ ) + { + if( UPPER ) + { + tmp1 = mulc(Alpha , A[k*rsa + j*csa]); + } + else + { + tmp1 = mulc(Alpha , conjugate(A[j*rsa + k*csa])); + } + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , mulc(tmp1 , B[i*rsb + k*csb])); + } + } + for( k = (j+1) ; k < N ; k++ ) + { + if( UPPER ) + { + tmp1 = mulc(Alpha , conjugate(A[j*rsa + k*csa])); + } + else + { + tmp1 = mulc(Alpha , A[k*rsa + j*csa]); + } + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , mulc(tmp1 , B[i*rsb + k*csb])); + } + } + } + } + return; +} + +double libblis_test_ihemm_check + ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ) +{ + + num_t dt = bli_obj_dt( a ); + uplo_t uploa = bli_obj_uplo( a ); + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + dim_t rsb = bli_obj_row_stride( b ) ; + dim_t csb = bli_obj_col_stride( b ) ; + dim_t rsc = bli_obj_row_stride( c ) ; + dim_t csc = bli_obj_col_stride( c ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* B = (float*) bli_obj_buffer( b ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* C = (float*) bli_obj_buffer( c_orig ); + float* CC = (float*) bli_obj_buffer( c ); + libblis_ihemm_check(side, uploa, M, N, *Alpha, A, rsa, csa, + B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, N, CC, C, rsc, csc); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* B = (double*) bli_obj_buffer( b ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* C = (double*) bli_obj_buffer( c_orig ); + double* CC = (double*) bli_obj_buffer( c ); + libblis_ihemm_check(side, uploa, M, N, *Alpha, A, rsa, csa, + B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, N, CC, C, rsc, csc); + } + break; + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* B = (scomplex*) bli_obj_buffer( b ); + scomplex* C = (scomplex*) bli_obj_buffer( c_orig ); + scomplex* CC = (scomplex*) bli_obj_buffer( c ); + libblis_ichemm_check(side, uploa, M, N, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffim(M, N, CC, C, rsc, csc); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* B = (dcomplex*) bli_obj_buffer( b ); + dcomplex* C = (dcomplex*) bli_obj_buffer( c_orig ); + dcomplex* CC = (dcomplex*) bli_obj_buffer( c ); + libblis_ichemm_check(side, uploa, M, N, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffim(M, N, CC, C, rsc, csc); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +template +double libblis_check_nan_real( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_hemm(obj_t* c, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( c ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_hemv.cpp b/gtestsuite/src/ref_hemv.cpp new file mode 100644 index 000000000..ed1e829ce --- /dev/null +++ b/gtestsuite/src/ref_hemv.cpp @@ -0,0 +1,305 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_hemv.h" + +using namespace std; + +//* ========================================================================== +//*> HEMV performs the matrix-vector operation +//*> y := alpha*A*x + beta*y +//*> where alpha and beta are scalars, x and y are n element vectors and +//*> A is an n by n hermitian matrix. +//* ========================================================================== + +template +void libblis_ihemv_check(uplo_t uploa, dim_t M, T* alpha, T* A, + dim_t rsa, dim_t csa, T* X, dim_t incx, T* beta, T* Y, dim_t incy) { + T ONE = 1.0; + T ZERO = 0.0; + T Alpha = alpha[0]; + T Beta = beta[0]; + T tmp1, tmp2; + dim_t i, ix, iy, j, jx, jy, kx, ky; + + if ((M == 0) || + ((Alpha == ZERO) && (Beta == ONE))) + return ; + + //* Set up the start points in X and Y. + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (M * incx); + } + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (M * incy); + } + + //* First form y := beta*y. + if (Beta != ONE) { + iy = ky; + if (Beta == ZERO) { + for(i = 0 ; i < M ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < M ; i++) { + Y[iy] = (Beta * Y[iy]); + iy = iy + incy; + } + } + } + + if (Alpha == ZERO) + return; + + T tmp = 0.0 ; + if(uploa == BLIS_UPPER) { + //* Form y when A is stored in upper triangle. + jx = kx; + jy = ky; + for(j = 0 ; j < M ; j++) { + tmp1 = (Alpha * X[jx]); + tmp2 = ZERO; + ix = kx; + iy = ky; + for(i = 0 ; i < j ; i++) { + tmp = A[i*rsa + j*csa]; + Y[iy] = Y[iy] + (tmp1 * tmp); + tmp2 = tmp2 + (tmp * X[ix]); + ix = ix + incx; + iy = iy + incy; + } + tmp = A[j*rsa + j*csa]; + Y[jy] = Y[jy] + (tmp1 * tmp) + (Alpha * tmp2); + jx = jx + incx; + jy = jy + incy; + } + } + else { + //* Form y when A is stored in lower triangle. + jx = kx; + jy = ky; + for(j = 0 ; j < M ; j++) { + tmp1 = (Alpha * X[jx]); + tmp = A[j*rsa + j*csa]; + tmp2 = ZERO; + Y[jy] = Y[jy] + (tmp1 * tmp); + ix = jx; + iy = jy; + for(i = (j+1) ; i < M ; i++) { + ix = ix + incx; + iy = iy + incy; + tmp = A[i*rsa + j*csa]; + Y[iy] = Y[iy] + (tmp1 * tmp); + tmp2 = tmp2 + (tmp * X[ix]); + } + Y[jy] = Y[jy] + (Alpha * tmp2); + jx = jx + incx; + jy = jy + incy; + } + } + + return; +} + +template +void libblis_ichemv_check(uplo_t uploa, dim_t M, T* alpha, T* A, dim_t rsa, +dim_t csa, bool conja, T* X, dim_t incx, bool conjx, T* beta, T* Y, dim_t incy) { + T ONE = { 1.0, 0.0 }; + T ZERO = { 0.0, 0.0 }; + T Alpha = *alpha; + T Beta = *beta; + T tmp1, tmp2; + dim_t i, ix, iy, j, jx, jy, kx, ky; + + if ((M == 0) || + ((Alpha.real == ZERO.real) && (Beta.real == ONE.real))) + return ; + + //* Set up the start points in X and Y. + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (M * incx); + } + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (M * incy); + } + + //* First form y := beta*y. + if((Beta.real != ONE.real) && (Beta.imag != ONE.imag)) { + iy = ky; + if((Beta.real != ZERO.real) && (Beta.imag != ZERO.imag)) { + for(i = 0 ; i < M ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < M ; i++) { + Y[iy] = mulc(Beta , Y[iy]); + iy = iy + incy; + } + } + } + + if((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)) + return; + + if(conjx) { + ix = 0; + for(i = 0 ; i < M ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(conja) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < M ; j++) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + T tmp = {0.0, 0.0}; + if(uploa == BLIS_UPPER) { + //* Form y when A is stored in upper triangle. + jx = kx; + jy = ky; + for(j = 0 ; j < M ; j++) { + tmp1 = mulc(Alpha , X[jx]); + tmp2 = ZERO; + ix = kx; + iy = ky; + for(i = 0 ; i < j ; i++) { + tmp = A[i*rsa + j*csa]; + Y[iy] = addc(Y[iy] , mulc(tmp1 , tmp)); + tmp2 = addc(tmp2 , mulc(conjugate(tmp) , X[ix])); + ix = ix + incx; + iy = iy + incy; + } + tmp = A[j*rsa + j*csa]; + tmp = addc(mulc(tmp1 , real(tmp)) , mulc(Alpha , tmp2)); + Y[jy] = addc(Y[jy] , tmp ); + jx = jx + incx; + jy = jy + incy; + } + } + else { + //* Form y when A is stored in lower triangle. + jx = kx; + jy = ky; + for(j = 0 ; j < M ; j++) { + tmp1 = mulc(Alpha , X[jx]); + tmp = A[j*rsa + j*csa]; + tmp2 = ZERO; + Y[jy] = addc(Y[jy] , mulc(tmp1 , real(tmp))); + ix = jx; + iy = jy; + for(i = (j+1) ; i < M ; i++) { + ix = ix + incx; + iy = iy + incy; + tmp = A[i*rsa + j*csa]; + Y[iy] = addc(Y[iy] , mulc(tmp1 , tmp)); + tmp2 = addc(tmp2 , mulc(conjugate(tmp) , X[ix])); + } + Y[jy] = addc(Y[jy] , mulc(Alpha , tmp2)); + jx = jx + incx; + jy = jy + incy; + } + } + + return; +} + +double libblis_test_ihemv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( a ); + uplo_t uploa = bli_obj_uplo( a ); + dim_t M = bli_obj_length( a ); + dim_t rsa = bli_obj_row_stride( a ); + dim_t csa = bli_obj_col_stride( a ); + bool conja = bli_obj_has_conj( a ); + dim_t incx = bli_obj_vector_inc( x ); + dim_t incy = bli_obj_vector_inc( y ); + bool conjx = bli_obj_has_conj( x ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* X = (float*) bli_obj_buffer( x ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_ihemv_check(uploa, M, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* X = (double*) bli_obj_buffer( x ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_ihemv_check(uploa, M, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_ichemv_check(uploa, M, Alpha, A, rsa, csa, + conja, X, incx, conjx, Beta, Y, incy); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_ichemv_check(uploa, M, Alpha, A, rsa, csa, + conja, X, incx, conjx, Beta, Y, incy); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_her.cpp b/gtestsuite/src/ref_her.cpp new file mode 100644 index 000000000..915f534c4 --- /dev/null +++ b/gtestsuite/src/ref_her.cpp @@ -0,0 +1,203 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_her.h" + +using namespace std; + +//* ========================================================================== +//*> HER performs the hermitian rank 1 operation +//*> A := alpha*x*x**H + A +//*> where alpha is a real scalar, x is an n element vector and A is an +//*> n by n hermitian matrix. +//* ========================================================================== + +template +void libblis_iher_check(uplo_t uploa, dim_t N, T* alpha, T* X, dim_t incx, + T* A, dim_t rsa, dim_t csa) { + T ZERO = 0.0; + T Alpha = alpha[0]; + T temp; + int i, ix, j, jx, kx; + + if((N == 0) || (Alpha == ZERO)) + return; + + /* Set the start point in X if the increment is not unity. */ + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if(uploa == BLIS_UPPER) { + /* Form A when A is stored in upper triangle. */ + jx = kx; + for(j = 0 ; j < N ; j++) { + if (X[jx] != ZERO) { + temp = Alpha * X[jx]; + ix = kx; + for(i = 0 ; i <= j ; i++) { + A[i*rsa + j*csa] = A[i*rsa + j*csa] + (X[ix] * temp); + ix = ix + incx; + } + } + jx = jx + incx; + } + } + else { + /* Form A when A is stored in lower triangle. */ + jx = kx; + for(j = 0; j < N ; j++) { + if (X[jx] != ZERO) { + temp = Alpha * X[jx]; + ix = jx; + for(i = j ; i < N ; i++) { + A[i*rsa + j*csa] = A[i*rsa + j*csa] + (X[ix] * temp); + ix = ix + incx; + } + } + jx = jx + incx; + } + } + + return; +} + +template +void libblis_icher_check(uplo_t uploa, dim_t N, T* alpha, T* X, dim_t incx, + bool conjx, T* A, dim_t rsa, dim_t csa) { + T ZERO = {0.0 , 0.0}; + T Alpha = alpha[0]; + T temp; + int i, ix, j, jx, kx; + + if ((N == 0) || ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag))) + return; + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if(conjx) { + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(uploa == BLIS_UPPER) { + /* Form A when A is stored in upper triangle. */ + jx = kx; + for(j = 0 ; j < N ; j++) { + if ((X[jx].real != ZERO.real) || (X[jx].imag != ZERO.imag)) { + temp = mulc(Alpha , conjugate(X[jx])); + ix = kx; + for(i = 0 ; i < j ; i++) { + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , mulc(X[ix] , temp)); + ix = ix + incx; + } + A[j*rsa + j*csa] = real(addc(A[j*rsa + j*csa] , mulc(X[jx] , temp))); + } + else { + A[j*rsa + j*csa] = real(A[j*rsa + j*csa]); + } + jx = jx + incx; + } + } + else { + /* Form A when A is stored in lower triangle. */ + jx = kx; + for(j = 0; j < N ; j++) { + if ((X[jx].real != ZERO.real) || (X[jx].imag != ZERO.imag)) { + temp = mulc(Alpha , conjugate(X[jx])); + A[j*rsa + j*csa] = real(addc(A[j*rsa + j*csa] , mulc(temp , X[jx]))); + ix = jx; + for( i = (j+1) ; i < N ; i++) { + ix = ix + incx; + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , mulc(X[ix] , temp)); + } + } + else { + A[j*rsa + j*csa] = real(A[j*rsa + j*csa]); + } + jx = jx + incx; + } + } + + return; +} + +double libblis_test_iher_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig +){ + + num_t dt = bli_obj_dt( x ); + uplo_t uploa = bli_obj_uplo( a ); + dim_t M = bli_obj_length( a ); + dim_t N = bli_obj_width( a ); + dim_t incx = bli_obj_vector_inc( x ); + bool conjx = bli_obj_has_conj( x ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a_orig ); + float* X = (float*) bli_obj_buffer( x ); + float* AA = (float*) bli_obj_buffer( a ); + libblis_iher_check(uploa, M, Alpha, X, incx, + A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a_orig ); + double* X = (double*) bli_obj_buffer( x ); + double* AA = (double*) bli_obj_buffer( a ); + libblis_iher_check(uploa, M, Alpha, X, incx, + A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a_orig ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* AA = (scomplex*) bli_obj_buffer( a ); + libblis_icher_check(uploa, M, Alpha, X, incx, conjx, + A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a_orig ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* AA = (dcomplex*) bli_obj_buffer( a ); + libblis_icher_check(uploa, M, Alpha, X, incx, conjx, + A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + diff --git a/gtestsuite/src/ref_her2.cpp b/gtestsuite/src/ref_her2.cpp new file mode 100644 index 000000000..bebc1dc16 --- /dev/null +++ b/gtestsuite/src/ref_her2.cpp @@ -0,0 +1,259 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_her2.h" + +using namespace std; + +//* ========================================================================== +//*> HER2 performs the hermitian rank 2 operation +//*> A := alpha*x*y**H + conjg( alpha )*y*x**H + A, +//*> where alpha is a scalar, x and y are n element vectors and A is an n +//*> by n hermitian matrix. +//* ========================================================================== + +template +void libblis_iher2_check(uplo_t uploa, dim_t N, T* alpha, T* X, dim_t incx, + T* Y, dim_t incy, T* A, dim_t rsa, dim_t csa) { + + T ZERO = 0.0; + T Alpha = alpha[0]; + T tmp1, tmp2; + int i, ix, iy, j, jx, jy, kx, ky; + + if ((N == 0) || (Alpha == ZERO)) + return; + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (N * incy); + } + jx = kx; + jy = ky; + + if(uploa == BLIS_UPPER) { + //* Form A when A is stored in the upper triangle. + for(j = 0 ; j < N ; j++) { + if ((X[jx] != ZERO) || (Y[jy] != ZERO)) { + tmp1 = Alpha * Y[jy]; + tmp2 = Alpha * X[jx]; + ix = kx; + iy = ky; + for(i = 0 ; i < j ; i++) { + A[i*rsa + j*csa] = A[i*rsa + j*csa] + X[ix]*tmp1 + Y[iy]*tmp2; + ix = ix + incx; + iy = iy + incy; + } + A[j*rsa + j*csa] = A[j*rsa + j*csa] + X[jx]*tmp1 + Y[jy]*tmp2; + } + else { + A[j*rsa + j*csa] = A[j*rsa + j*csa]; + } + jx = jx + incx; + jy = jy + incy; + } + } + else { + //* Form A when A is stored in the lower triangle. + for(j = 0 ; j < N ; j++) { + if((X[jx] != ZERO) || (Y[jy] != ZERO)) { + tmp1 = Alpha * Y[jy]; + tmp2 = Alpha * X[jx]; + A[j*rsa + j*csa] = A[j*rsa + j*csa] + X[jx]*tmp1 + Y[jy]*tmp2; + ix = jx; + iy = jy; + for(i = (j+1) ;i < N; i++) { + ix = ix + incx; + iy = iy + incy; + A[i*rsa + j*csa] = A[i*rsa + j*csa] + X[ix]*tmp1 + Y[iy]*tmp2; + } + } + else { + A[j*rsa + j*csa] = A[j*rsa + j*csa]; + } + jx = jx + incx; + jy = jy + incy; + } + } + return; +} + +template +void libblis_icher2_check(uplo_t uploa, dim_t N, T* alpha, T* X, dim_t incx, + bool conjx, T* Y, dim_t incy, bool conjy, T* A, dim_t rsa, dim_t csa) { + + T ZERO = {0.0, 0.0}; + T Alpha = *alpha; + T tmp1, tmp2; + int i, ix, iy, j, jx, jy, kx, ky; + + if((N == 0) || ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag))) + return; + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (N * incy); + } + jx = kx; + jy = ky; + + if(conjx) { + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(conjy) { + iy = 0; + for(i = 0 ; i < N ; i++) { + Y[iy] = conjugate(Y[iy]); + iy = iy + incy; + } + } + + T p1, p2, p; + if(uploa == BLIS_UPPER) { + //* Form A when A is stored in the upper triangle. + for(j = 0 ; j < N ; j++) { + tmp1 = mulc(Alpha , conjugate(Y[jy])); + tmp2 = conjugate(mulc(Alpha , X[jx])); + ix = kx; + iy = ky; + for(i = 0 ; i < j ; i++) { + p1 = mulc(X[ix] , tmp1); + p2 = mulc(Y[iy] , tmp2); + p = addc(p1 , p2); + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , p); + ix = ix + incx; + iy = iy + incy; + } + p1 = mulc(X[jx] , tmp1); + p2 = mulc(Y[jy] , tmp2); + p = addc(p1 , p2); + A[j*rsa + j*csa] = real(addc(A[j*rsa + j*csa] , p)); + jx = jx + incx; + jy = jy + incy; + } + } + else { + //* Form A when A is stored in the lower triangle. + for(j = 0; j < N ; j++) { + tmp1 = mulc(Alpha , conjugate(Y[jy])); + tmp2 = conjugate(mulc(Alpha , X[jx])); + p1 = mulc(X[jx] , tmp1); + p2 = mulc(Y[jy] , tmp2); + p = addc(p1 , p2); + A[j*rsa + j*csa] = real(addc(A[j*rsa + j*csa] , p)); + ix = jx; + iy = jy; + for(i = (j+1) ;i < N; i++) { + ix = ix + incx; + iy = iy + incy; + p1 = mulc(X[ix] , tmp1); + p2 = mulc(Y[iy] , tmp2); + p = addc(p1 , p2); + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , p); + } + jx = jx + incx; + jy = jy + incy; + } + } + return; +} + +double libblis_test_iher2_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +){ + + num_t dt = bli_obj_dt( x ); + uplo_t uploa = bli_obj_uplo( a ); + dim_t M = bli_obj_length( a ); + dim_t N = bli_obj_width( a ); + dim_t incx = bli_obj_vector_inc( x ); + dim_t incy = bli_obj_vector_inc( y ); + bool conjx = bli_obj_has_conj( x ); + bool conjy = bli_obj_has_conj( y ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a_orig ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y ); + float* AA = (float*) bli_obj_buffer( a ); + libblis_iher2_check(uploa, M, Alpha, X, incx, + Y, incy, A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a_orig ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y ); + double* AA = (double*) bli_obj_buffer( a ); + libblis_iher2_check(uploa, M, Alpha, X, incx, + Y, incy, A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a_orig ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + scomplex* AA = (scomplex*) bli_obj_buffer( a ); + libblis_icher2_check(uploa, M, Alpha, X, incx, conjx, + Y, incy, conjy, A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a_orig ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + dcomplex* AA = (dcomplex*) bli_obj_buffer( a ); + libblis_icher2_check(uploa, M, Alpha, X, incx, conjx, + Y, incy, conjy, A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + + diff --git a/gtestsuite/src/ref_her2k.cpp b/gtestsuite/src/ref_her2k.cpp new file mode 100644 index 000000000..6cc13fdc4 --- /dev/null +++ b/gtestsuite/src/ref_her2k.cpp @@ -0,0 +1,666 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_her2k.h" + +using namespace std; + +//*============================================================================ +//*> HER2K performs one of the hermitian rank 2k operations +//*> C := alpha*A*B**H + conjg( alpha )*B*A**H + beta*C, +//*> or +//*> C := alpha*A**H*B + conjg( alpha )*B**H*A + beta*C, +//*============================================================================ + +template +void libblis_iher2k_check( uplo_t uplo, trans_t trans, dim_t N, dim_t K, + T Alpha, T* A, dim_t rsa, dim_t csa, T* B, dim_t rsb, dim_t csb, T Beta, + T* C, dim_t rsc, dim_t csc ) +{ + T tmp1, tmp2; + int i, j, l; + bool UPPER, NOTRANS; + + T ONE = 1.0 ; + T ZERO = 0.0 ; + + //* Test the input parameters. + UPPER = ( uplo == BLIS_UPPER ); + NOTRANS = ( trans == BLIS_NO_TRANSPOSE ); + + if( N == 0 || (( Alpha == ZERO || K == 0 ) && Beta == ONE )) + return; + + //* And when alpha.eq.zero. + if( Alpha == ZERO ) + { + if( UPPER ) + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + } + else + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + } + return; + } + + //* Start the operations. + if( NOTRANS ) + { + //* C := alpha*A*B**T + alpha*B*A**T + C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + if( Beta == ZERO ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta != ONE ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + for( l = 0 ; l < K ; l++ ) + { + if( (A[j*rsa + l*csa] != ZERO) || (B[j*rsb + l*csb] != ZERO) ) + { + tmp1 = Alpha*B[j*rsb + l*csb]; + tmp2 = Alpha*A[j*rsa + l*csa]; + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + A[i*rsa + l*csa]*tmp1 + B[i*rsb + l*csb]*tmp2; + } + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + if( Beta == ZERO ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta != ONE ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + for( l = 0 ; l < K ; l++ ) + { + if( (A[j*rsa + l*csa] != ZERO) || (B[j*rsb + l*csb] != ZERO) ) + { + tmp1 = Alpha*B[j*rsb + l*csb]; + tmp2 = Alpha*A[j*rsa + l*csa]; + for( i = j; i < N ; i++ ) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + A[i*rsa + l*csa]*tmp1 + B[i*rsb + l*csb]*tmp2; + } + } + } + } + } + } + else + { + //* C := alpha*A**T*B + alpha*B**T*A + C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + tmp1 = ZERO; + tmp2 = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp1 = tmp1 + A[l*rsa + i*csa]*B[l*rsb + j*csb]; + tmp2 = tmp2 + B[l*rsb + i*csb]*A[l*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp1 + Alpha*tmp2; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + Alpha*tmp1 + Alpha*tmp2; + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + tmp1 = ZERO; + tmp2 = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp1 = tmp1 + A[l*rsa + i*csa]*B[l*rsb + j*csb]; + tmp2 = tmp2 + B[l*rsb + i*csb]*A[l*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp1 + Alpha*tmp2; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + Alpha*tmp1 + Alpha*tmp2; + } + } + } + } + } + return; +} + +template +void libblis_icher2k_check( uplo_t uplo, trans_t trans, dim_t N, dim_t K, + T Alpha, T* A, dim_t rsa, dim_t csa, T* B, dim_t rsb, dim_t csb, T Beta, + T* C, dim_t rsc, dim_t csc ) +{ + T tmp1, tmp2; + T tmpa, tmpb; + int i, j, l; + bool UPPER, NOTRANS; + + T ONE = { 1.0 , 0.0 }; + T ZERO = { 0.0 , 0.0 }; + + //* Test the input parameters. + UPPER = (uplo == BLIS_UPPER); + NOTRANS = (trans == BLIS_NO_TRANSPOSE); + + if( N == 0 || (( Alpha.real == ZERO.real || K == 0 ) && Beta.real == ONE.real )) + return; + + //* And when alpha.eq.zero. + if( Alpha.real == ZERO.real ) + { + if( UPPER ) + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < j ; i++) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + C[j*rsc + j*csc] = mulc(Beta , real(C[j*rsc + j*csc])); + } + } + } + else + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + C[j*rsc + j*csc] = mulc(Beta , real(C[j*rsc + j*csc])); + for( i = (j+1) ; i < N ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + } + return; + } + + //* Start the operations. + if( NOTRANS ) + { + //* Form C := alpha*A*B**H + conjg( alpha )*B*A**H + C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + if( Beta.real == ZERO.real ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta.real != ONE.real ) + { + for(i = 0 ; i < j ; i++) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + C[j*rsc + j*csc] = mulc(Beta , real(C[j*rsc + j*csc])); + } + else + { + C[j*rsc + j*csc] = real(C[j*rsc + j*csc]); + } + for( l = 0 ; l < K ; l++ ) + { + if( ((A[j*rsa + l*csa].real != ZERO.real) || (A[j*rsa + l*csa].imag != ZERO.imag)) + || ((B[j*rsb + l*csb].real != ZERO.real) || (B[j*rsb + l*csb].imag != ZERO.imag)) ) + { + tmp1 = mulc(Alpha , conjugate(B[j*rsb + l*csb])); + tmp2 = conjugate(mulc(Alpha , A[j*rsa + l*csa])); + for( i = 0 ; i < j ; i++) + { + tmpa = mulc(A[i*rsa + l*csa] , tmp1); + tmpb = mulc(B[i*rsb + l*csb] , tmp2); + tmpa = addc(tmpa , tmpb); + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , tmpa); + } + tmpa = mulc(A[j*rsa + l*csa] , tmp1); + tmpb = mulc(B[j*rsb + l*csb] , tmp2); + tmpa = addc(tmpa , tmpb); + C[j*rsc + j*csc] = addc(real(C[j*rsc + j*csc]) , real(tmpa)); + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + if( Beta.real == ZERO.real ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta.real != ONE.real ) + { + for( i = (j+1) ; i < N ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + C[j*rsc + j*csc] = mulc(Beta , real(C[j*rsc + j*csc])); + } + else + { + C[j*rsc + j*csc] = real(C[j*rsc + j*csc]); + } + for( l = 0 ; l < K ; l++ ) + { + if( ((A[j*rsa + l*csa].real != ZERO.real) || (A[j*rsa + l*csa].imag != ZERO.imag)) + || ((B[j*rsb + l*csb].real != ZERO.real) || (B[j*rsb + l*csb].imag != ZERO.imag)) ) + { + tmp1 = mulc(Alpha , conjugate(B[j*rsb + l*csb])); + tmp2 = conjugate(mulc(Alpha , A[j*rsa + l*csa])); + for( i = (j+1) ; i < N ; i++ ) + { + tmpa = mulc(A[i*rsa + l*csa] , tmp1); + tmpb = mulc(B[i*rsb + l*csb] , tmp2); + tmpa = addc(tmpa, tmpb); + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , tmpa); + } + tmpa = mulc(A[j*rsa + l*csa] , tmp1); + tmpb = mulc(B[j*rsb + l*csb] , tmp2); + tmpa = addc(tmpa, tmpb); + C[j*rsc + j*csc] = addc(real(C[j*rsc + j*csc]) , real(tmpa)); + } + } + } + } + } + else + { + //* Form C := alpha*A**H*B + conjg( alpha )*B**H*A + C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + tmp1 = ZERO; + tmp2 = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp1 = addc(tmp1 , mulc(conjugate(A[l*rsa + i*csa]) , B[l*rsb + j*csb])); + tmp2 = addc(tmp2 , mulc(conjugate(B[l*rsb + i*csb]) , A[l*rsa + j*csa])); + } + if( i == j ) + { + if( Beta.real == ZERO.real ) + { + tmpa = mulc(Alpha , tmp1); + tmpb = mulc(conjugate(Alpha) , tmp2); + C[j*rsc + j*csc] = real(addc(tmpa, tmpb)); + } + else + { + tmpa = mulc(Alpha , tmp1); + tmpb = mulc(conjugate(Alpha) , tmp2); + tmpa = addc(tmpa, tmpb); + C[j*rsc + j*csc] = addc(mulc(Beta , real(C[j*rsc + j*csc])) , real(tmpa)); + } + } + else + { + if( Beta.real == ZERO.real ) + { + C[i*rsc + j*csc] = addc(mulc(Alpha , tmp1) , mulc(conjugate(Alpha) ,tmp2)); + } + else + { + tmpa = mulc(Alpha , tmp1); + tmpb = mulc(conjugate(Alpha) , tmp2); + tmpa = addc(tmpa , tmpb); + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) ,tmpa); + } + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + tmp1 = ZERO; + tmp2 = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp1 = addc(tmp1 , mulc(conjugate(A[l*rsa + i*csa]) , B[l*rsb + j*csb])); + tmp2 = addc(tmp2 , mulc(conjugate(B[l*rsb + i*csb]) , A[l*rsa + j*csa])); + } + if( i == j ) + { + if( Beta.real == ZERO.real ) + { + C[j*rsc + j*csc] = real(addc(mulc(Alpha , tmp1) , mulc(conjugate(Alpha) , tmp2))); + } + else + { + tmpa = mulc(Alpha , tmp1); + tmpb = mulc(conjugate(Alpha) , tmp2); + tmpa = addc(tmpa, tmpb); + C[j*rsc + j*csc] = addc(mulc(Beta , real(C[j*rsc + j*csc])) , real(tmpa)); + } + } + else + { + if( Beta.real == ZERO.real ) + { + C[i*rsc + j*csc] = addc(mulc(Alpha , tmp1) , mulc(conjugate(Alpha) , tmp2)); + } + else + { + tmpa = mulc(Alpha , tmp1); + tmpb = mulc(conjugate(Alpha) , tmp2); + tmpa = addc(tmpa, tmpb); + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , tmpa); + } + } + } + } + } + } + return; +} + +double libblis_test_iher2k_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ) +{ + num_t dt = bli_obj_dt( c ); + uplo_t uploc = bli_obj_uplo( c ); + dim_t M = bli_obj_length( c ); + dim_t K = bli_obj_width_after_trans( a ); + trans_t trans = bli_obj_onlytrans_status( a ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + dim_t rsb = bli_obj_row_stride( b ) ; + dim_t csb = bli_obj_col_stride( b ) ; + dim_t rsc = bli_obj_row_stride( c ) ; + dim_t csc = bli_obj_col_stride( c ) ; + double resid = 0.0; + f77_int lda, ldb, ldc; + + if( bli_obj_is_col_stored( c ) ) { + lda = bli_obj_col_stride( a ); + ldb = bli_obj_col_stride( b ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldb = bli_obj_row_stride( b ); + ldc = bli_obj_row_stride( c ); + } + + int nrowa; + if (trans == BLIS_NO_TRANSPOSE) { + nrowa = M; + } else { + nrowa = K; + } + + if( lda < max(1, nrowa) ) { + return resid; + } + if( ldb < max(1, nrowa) ) { + return resid; + } + if( ldc < max(1, (int)M) ) { + return resid; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* B = (float*) bli_obj_buffer( b ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* C = (float*) bli_obj_buffer( c_orig ); + float* CC = (float*) bli_obj_buffer( c ); + libblis_iher2k_check(uploc, trans, M, K, *Alpha, A, + rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, M, CC, C, rsc, csc); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* B = (double*) bli_obj_buffer( b ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* C = (double*) bli_obj_buffer( c_orig ); + double* CC = (double*) bli_obj_buffer( c ); + libblis_iher2k_check(uploc, trans, M, K, *Alpha, A, + rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, M, CC, C, rsc, csc); + } + break; + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* B = (scomplex*) bli_obj_buffer( b ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* C = (scomplex*) bli_obj_buffer( c_orig ); + scomplex* CC = (scomplex*) bli_obj_buffer( c ); + Beta->imag = 0.0 ; + libblis_icher2k_check(uploc, trans, M, K, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffim(M, M, CC, C, rsc, csc); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* B = (dcomplex*) bli_obj_buffer( b ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* C = (dcomplex*) bli_obj_buffer( c_orig ); + dcomplex* CC = (dcomplex*) bli_obj_buffer( c ); + Beta->imag = 0.0 ; + libblis_icher2k_check(uploc, trans, M, K, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffim(M, M, CC, C, rsc, csc); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return abs(resid); +} + +template +double libblis_check_nan_real( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_her2k(obj_t* c, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( c ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_herk.cpp b/gtestsuite/src/ref_herk.cpp new file mode 100644 index 000000000..4c6f8c4be --- /dev/null +++ b/gtestsuite/src/ref_herk.cpp @@ -0,0 +1,648 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_herk.h" + +using namespace std; + +//* ========================================================================== +//*> HERK performs one of the hermitian rank k operations +//*> C := alpha*A*A**H + beta*C, +//*> or +//*> C := alpha*A**H*A + beta*C, +//*> where alpha and beta are real scalars, C is an n by n hermitian +//*> matrix and A is an n by k matrix in the first case and a k by n +//*> matrix in the second case. +//* ========================================================================== + +template +void libblis_iherk_check( uplo_t uplo, trans_t trans, dim_t N, dim_t K, + T Alpha, T* A, dim_t rsa, dim_t csa, T Beta, T* C, dim_t rsc, dim_t csc ) +{ + T tmp, rtmp; + dim_t i, j, l; + bool UPPER, NOTRANS; + + T ONE = 1.0; + T ZERO = 0.0; + + UPPER = (uplo == BLIS_UPPER); + NOTRANS = (trans == BLIS_NO_TRANSPOSE) || (trans == BLIS_CONJ_NO_TRANSPOSE); + + if( (N == 0) || (( Alpha == ZERO || K == 0) && Beta == ONE ) ) + return; + + //* And when alpha.eq.zero. + if( Alpha == ZERO ) + { + if( UPPER ) + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < j ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + C[j*rsc + j*csc] = Beta*(C[j*rsc + j*csc]); + } + } + } + else + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + C[j*rsc + j*csc] = Beta*C[j*rsc + j*csc]; + for( i = (j+1) ; i < N ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + } + return; + } + + //* Start the operations. + if( NOTRANS ) + { + //* Form C := alpha*A*A**H + beta*C. + if( UPPER ) + { + for( j = 0; j < N ; j++ ) + { + if( Beta == ZERO ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta != ONE ) + { + for(i = 0 ; i < j ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + C[j*rsc + j*csc] = Beta*C[j*rsc + j*csc]; + } + for( l = 0 ; l < K ; l++ ) + { + if( A[j*rsa + l*csa] != ZERO ) + { + tmp = Alpha*A[j*rsa + l*csa] ; + for( i = 0 ; i < j ; i++ ) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + tmp*A[i*rsa + l*csa]; + } + C[j*rsc + j*csc] = C[j*rsc + j*csc] + tmp*A[i*rsa + l*csa]; + } + } + } + } + else + { + for( j = 0; j < N ; j++ ) + { + if( Beta == ZERO ) + { + for( i = j ; i < N; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta != ONE ) + { + C[j*rsc + j*csc] = Beta*C[j*rsc + j*csc]; + for(i = (j+1) ; i < N ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + for( l = 0 ; l < K ; l++ ) + { + if( A[j*rsa + l*csa] != ZERO ) + { + tmp = Alpha*A[j*rsa + l*csa]; + C[j*rsc + j*csc] = C[j*rsc + j*csc] + tmp*A[j*rsa + l*csa]; + for( i = (j+1) ; i < N ; i++ ) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + tmp*A[i*rsa + l*csa]; + } + } + } + } + } + } + else + { + //* Form C := alpha*A**H*A + beta*C. + if( UPPER ) + { + for( j = 0; j < N ; j++ ) + { + for( i = 0 ; i < j ; i++ ) + { + tmp = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp = tmp + A[l*rsa + i*csa]*A[l*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp; + } + else + { + C[i*rsc + j*csc] = Alpha*tmp + Beta*C[i*rsc + j*csc]; + } + } + rtmp = ZERO; + for( l = 0 ; l < K ; l++ ) + { + rtmp = rtmp + A[l*rsa + j*csa]*A[l*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[j*rsc + j*csc] = Alpha*rtmp; + } + else + { + C[j*rsc + j*csc] = Alpha*rtmp + Beta*C[j*rsc + j*csc]; + } + } + } + else + { + for( j = 0; j < N ; j++ ) + { + rtmp = ZERO; + for( l = 0 ; l < K ; l++ ) + { + rtmp = rtmp + A[l*rsa + j*csa]*A[l*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[j*rsc + j*csc] = Alpha*rtmp; + } + else + { + C[j*rsc + j*csc] = Alpha*rtmp + Beta*C[j*rsc + j*csc]; + } + for( i = (j+1) ; i < N ; i++ ) + { + tmp = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp = tmp + A[l*rsa + i*csa]*A[l*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp; + } + else + { + C[i*rsc + j*csc] = Alpha*tmp + Beta*C[i*rsc + j*csc]; + } + } + } + } + } + return; +} + +template +void libblis_icherk_check(uplo_t uplo, trans_t trans, dim_t N, dim_t K, + T Alpha,T* A, dim_t rsa, dim_t csa, T Beta, T* C, dim_t rsc, dim_t csc) +{ + T tmp; + T rtmp; + dim_t i, j, l; + bool UPPER, NOTRANS; + T ONE = {1.0 , 0.0}; + T ZERO = {0.0 , 0.0}; + + UPPER = (uplo == BLIS_UPPER); + NOTRANS = (trans == BLIS_NO_TRANSPOSE) || (trans == BLIS_CONJ_NO_TRANSPOSE); + + //* Quick return if possible. + if( (N == 0) || + (((Alpha.real == ZERO.real) || (K == 0)) && (Beta.real == ONE.real)) ) + { + return; + } + +//* And when alpha.eq.zero. + if( Alpha.real == ZERO.real ) + { + if( UPPER ) + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0; i < j ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + C[j*rsc + j*csc] = mulc(Beta , real(C[j*rsc + j*csc])); + } + } + } + else + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + C[j*rsc + j*csc] = mulc(Beta , real(C[j*rsc + j*csc])); + for( i = (j+1) ; i < N ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + } + return; + } + + //* Start the operations. + if( NOTRANS ) + { + //*Form C := alpha*A*A**H + beta*C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + if( Beta.real == ZERO.real ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta.real != ONE.real ) + { + for( i = 0 ; i < j ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + C[j*rsc + j*csc] = mulc(Beta , real(C[j*rsc + j*csc])); + } + else + { + C[j*rsc + j*csc] = real(C[j*rsc + j*csc]); + } + + for( l = 0; l < K ; l++ ) + { + if((A[j*rsa + l*csa].real != ZERO.real) || (A[j*rsa + l*csa].imag != ZERO.imag)) + { + tmp = mulc(Alpha , conjugate(A[j*rsa + l*csa])); + for( i = 0 ; i < j ; i++ ) + { + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , mulc(tmp , A[i*rsa + l*csa])); + } + C[j*rsc + j*csc] = addc(real(C[j*rsc + j*csc]) , real(mulc(tmp ,A[i*rsa + l*csa]))); + } + } + } + } + else + { + for( j = 0; j < N ; j++ ) + { + if( Beta.real == ZERO.real ) + { + for( i = j ; i < N ; i++ ) + { + C[j*rsc + j*csc] = ZERO; + } + } + else if( Beta.real != ONE.real ) + { + C[j*rsc + j*csc] = mulc(Beta ,real(C[j*rsc + j*csc])); + for( i = (j+1) ; i < N ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + else + { + C[j*rsc + j*csc] = real(C[j*rsc + j*csc]); + } + + for( l = 0; l < K ; l++ ) + { + if( (A[j*rsa + l*csa].real != ZERO.real)||(A[j*rsa + l*csa].imag != ZERO.imag) ) + { + tmp = mulc(Alpha , conjugate(A[j*rsa + l*csa])); + C[j*rsc + j*csc] = addc(real(C[j*rsc + j*csc]) , real(mulc(tmp , A[j*rsa + l*csa]))); + for( i = (j+1) ; i < N; i++ ) + { + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , mulc(tmp , A[i*rsa + l*csa])); + } + } + } + } + } + } + else + { + //* Form C := alpha*A**H*A + beta*C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < j ; i++ ) + { + tmp = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp = addc(tmp , mulc(conjugate(A[l*rsa + i*csa]) , A[l*rsa + j*csa])); + } + if( Beta.real == ZERO.real ) + { + C[i*rsc + j*csc] = mulc(Alpha , tmp); + } + else + { + C[i*rsc + j*csc] = addc(mulc(Alpha , tmp) , mulc(Beta , C[i*rsc + j*csc])); + } + } + rtmp = ZERO; + for( l = 0 ; l < K ; l++ ) + { + rtmp = addc(rtmp , mulc(conjugate(A[l*rsa + j*csa]) , A[l*rsa + j*csa])); + } + if( Beta.real == ZERO.real ) + { + C[j*rsc + j*csc] = mulc(Alpha , rtmp); + } + else + { + C[j*rsc + j*csc] = addc(mulc(Alpha , rtmp) , mulc(Beta , real(C[j*rsc + j*csc]))); + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + rtmp = ZERO; + for( l = 0 ; l < K ; l++ ) + { + rtmp = addc(rtmp , mulc(conjugate(A[l*rsa + j*csa]) , A[l*rsa + j*csa])); + } + if( Beta.real == ZERO.real ) + { + C[j*rsc + j*csc] = mulc(Alpha , rtmp); + } + else + { + C[j*rsc + j*csc] = addc(mulc(Alpha , rtmp) , mulc(Beta , real(C[j*rsc + j*csc]))); + } + for( i = (j+1) ; i < N ; i++ ) + { + tmp = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp = addc(tmp , mulc(conjugate(A[l*rsa + i*csa]) , A[l*rsa + j*csa])); + } + if( Beta.real == ZERO.real ) + { + C[i*rsc + j*csc] = mulc(Alpha , tmp); + } + else + { + C[i*rsc + j*csc] = addc(mulc(Alpha , tmp) , mulc(Beta , C[i*rsc + j*csc])); + } + } + } + } + } + return; +} + +double libblis_test_iherk_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig +){ + num_t dt = bli_obj_dt( a ); + dim_t M = bli_obj_length( c ); + dim_t K = bli_obj_width_after_trans( a ); + uplo_t uplo = bli_obj_uplo( c ); + trans_t trans = bli_obj_onlytrans_status( a ); + double resid = 0.0; + dim_t rsa, csa; + dim_t rsc, csc; + f77_int lda; + + rsa = bli_obj_row_stride( a ) ; + csa = bli_obj_col_stride( a ) ; + rsc = bli_obj_row_stride( c ) ; + csc = bli_obj_col_stride( c ) ; + + if( bli_obj_is_col_stored( c ) ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + int nrowa; + if (trans == BLIS_NO_TRANSPOSE) { + nrowa = M; + } else { + nrowa = K; + } + + if (lda < max(1, nrowa)) { + return resid; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* C = (float*) bli_obj_buffer( c_orig ); + float* CC = (float*) bli_obj_buffer( c ); + libblis_iherk_check( uplo, trans, M, K, *Alpha, + A, rsa, csa, *Beta, C, rsc, csc ); + resid = computediffrm(M, M, CC, C, rsc, csc); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* C = (double*) bli_obj_buffer( c_orig ); + double* CC = (double*) bli_obj_buffer( c ); + libblis_iherk_check(uplo, trans, M, K, *Alpha, + A, rsa, csa, *Beta, C, rsc, csc ); + resid = computediffrm(M, M, CC, C, rsc, csc); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* C = (scomplex*) bli_obj_buffer( c_orig ); + scomplex* CC = (scomplex*) bli_obj_buffer( c ); + Alpha->imag = 0.0 ; + Beta->imag = 0.0 ; + libblis_icherk_check(uplo, trans, M, K, *Alpha, + A, rsa, csa, *Beta, C, rsc, csc); + resid = computediffim(M, M, CC, C, rsc, csc); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* C = (dcomplex*) bli_obj_buffer( c_orig ); + dcomplex* CC = (dcomplex*) bli_obj_buffer( c ); + Alpha->imag = 0.0 ; + Beta->imag = 0.0 ; + libblis_icherk_check(uplo, trans, M, K, *Alpha, + A, rsa, csa, *Beta, C, rsc, csc); + resid = computediffim(M, M, CC, C, rsc, csc); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + +template +double libblis_check_nan_real( dim_t rsc, dim_t csc, obj_t* c ) { + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + double resid = 0.0; + T* C = (T*) bli_obj_buffer( c ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = C[ i*rsc + j*csc ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rsc, dim_t csc, obj_t* c ) { + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + double resid = 0.0; + U* C = (U*) bli_obj_buffer( c ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = C[ i*rsc + j*csc ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_herk(obj_t* c, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_is_col_stored( c ) ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_normfm.cpp b/gtestsuite/src/ref_normfm.cpp new file mode 100644 index 000000000..945c3504d --- /dev/null +++ b/gtestsuite/src/ref_normfm.cpp @@ -0,0 +1,109 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_normfm.h" + +using namespace std; + +//* ========================================================================== +//*> NORMFM performs matrix operation +//*> Compute the Frobenius norm (bli_?normfm()) +//*> of the elements in an m x n matrix A. The resulting norm is stored to norm +//* ========================================================================== + +template +T libblis_inormfm_check(dim_t M, dim_t N, T* X, dim_t rsx, dim_t csx ) { + + dim_t i, j; + T sum = 0.0; + T norm = 0.0; + + if ((M == 0) || (N == 0)) { + return norm; + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + sum += X[i*rsx + j*csx] * X[i*rsx + j*csx]; + } + } + + norm = sqrt( abs(sum) ); + + return norm; +} + +template +U libblis_icnormfm_check(dim_t M, dim_t N, T* X, dim_t rsx, dim_t csx ) { + + dim_t i, j; + T rr = { 0.0, 0.0 }; + U norm = 0.0; + + if ((M == 0) || (N == 0)) { + return norm; + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + auto a = X[i*rsx + j*csx]; + rr.real += a.real * a.real; + rr.imag += a.imag * a.imag; + } + } + + U r = rr.real + rr.imag; + norm = sqrt( abs(r) ); + + return norm; +} + +double libblis_test_inormfm_check( + test_params_t* params, + obj_t* x, + obj_t* norm +){ + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_length( x ); + dim_t N = bli_obj_width( x ); + dim_t rsx = bli_obj_row_stride( x ) ; + dim_t csx = bli_obj_col_stride( x ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* av = (float*) bli_obj_internal_scalar_buffer( norm ); + float rv = libblis_inormfm_check(M, N, X, rsx, csx); + resid = (double)(abs(rv - *av)/abs(rv)); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* av = (double*) bli_obj_internal_scalar_buffer( norm ); + double rv = libblis_inormfm_check(M, N, X, rsx, csx); + resid = (double)(abs(rv - *av)/abs(rv)); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + float* av = (float*) bli_obj_internal_scalar_buffer( norm ); + float rv = libblis_icnormfm_check(M, N, X, rsx, csx); + resid = (double)(abs(rv - *av)/abs(rv)); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + double* av = (double*) bli_obj_internal_scalar_buffer( norm ); + double rv = libblis_icnormfm_check(M, N, X, rsx, csx); + resid = (double)(abs(rv - *av)/abs(rv)); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return abs(resid); +} diff --git a/gtestsuite/src/ref_normfv.cpp b/gtestsuite/src/ref_normfv.cpp new file mode 100644 index 000000000..03f9d2db4 --- /dev/null +++ b/gtestsuite/src/ref_normfv.cpp @@ -0,0 +1,107 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_normfv.h" + +using namespace std; + +//* ========================================================================== +//*> NORMFV performs vector operations +//*> Compute the Frobenius norm (bli_?normfv()) +//*> of the elements in a vector x of length n. The resulting norm is stored to norm +//* ========================================================================== + +template +T libblis_inormfv_check(dim_t len, T* X, dim_t incx ) { + dim_t i, ix; + T sum = 0.0; + T norm = 0.0; + + if (len == 0){ + return norm; + } + + ix = 0; + for(i = 0 ; i < len ; i++) { + sum += X[ix] * X[ix]; + ix = ix + incx; + } + + norm = sqrt( abs(sum) ); + + return norm; +} + +template +U libblis_icnormfv_check(dim_t len, T* X, dim_t incx ) { + dim_t i, ix; + T rr = { 0.0, 0.0 }; + U norm = 0.0; + if(len == 0) { + return norm; + } + + ix = 0; + for(i = 0 ; i < len ; i++) { + //rr = addc(rr, mulc(X[ix] , X[ix])); + auto a = X[ix]; + rr.real += a.real * a.real; + rr.imag += a.imag * a.imag; + ix = ix + incx; + } + + U r = rr.real + rr.imag; + norm = sqrt( abs(r) ); + + return norm; +} + +double libblis_test_inormfv_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* n +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* av = (float*) bli_obj_internal_scalar_buffer( n ); + float rv = libblis_inormfv_check(M, X, incx ); + resid = (double)(abs(rv - *av)/abs(rv)); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* av = (double*) bli_obj_internal_scalar_buffer( n ); + double rv = libblis_inormfv_check(M, X, incx ); + resid = (double)(abs(rv - *av)/abs(rv)); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + float* av = (float*) bli_obj_internal_scalar_buffer( n ); + float rv = libblis_icnormfv_check(M, X, incx ); + resid = (double)(abs(rv - *av)/abs(rv)); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + double* av = (double*) bli_obj_internal_scalar_buffer( n ); + double rv = libblis_icnormfv_check(M, X, incx ); + resid = (double)(abs(rv - *av)/abs(rv)); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} diff --git a/gtestsuite/src/ref_scal2m.cpp b/gtestsuite/src/ref_scal2m.cpp new file mode 100644 index 000000000..a78d45c9a --- /dev/null +++ b/gtestsuite/src/ref_scal2m.cpp @@ -0,0 +1,163 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_scal2m.h" + +using namespace std; + +//* ========================================================================== +//*> SCAL2M performs matrix operations +//*> B := alpha * transa(A) +//*> where A is an m x n matrix, and alpha is a scalar. +//* ========================================================================== + +template +void libblis_iscal2m_check(dim_t M, dim_t N, T* alpha, + T* X, dim_t rsx, dim_t csx, T* Y, dim_t rsy, dim_t csy ) { + + dim_t i, j; + T ONE = 1.0 ; + T ZERO = 0.0 ; + T Alpha = alpha[0]; + + if ((M == 0) || (N == 0)) { + return; + } + + if (Alpha != ONE) { + if (Alpha == ZERO) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = ZERO; + } + } + } + else { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = Alpha * X[i*rsx + j*csx]; + } + } + } + } + + return; +} + +template +void libblis_icscal2m_check(dim_t M, dim_t N, T* alpha, + T* X, dim_t rsx, dim_t csx, bool conjx, T* Y, dim_t rsy, dim_t csy) { + dim_t i, j; + T ONE = {1.0, 0.0} ; + T ZERO = {0.0, 0.0} ; + T Alpha = *alpha; + + if ((M == 0) || (N == 0)) { + return; + } + + if(conjx) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = conjugate(X[i*rsx + j*csx]); + } + } + } + + /* First form x := Alpha*x. */ + if ((Alpha.real != ONE.real) && (Alpha.imag != ONE.imag)) { + if ((Alpha.real != ZERO.real) && (Alpha.imag != ZERO.imag)) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy]= ZERO; + } + } + } + else { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = mulc(Alpha , X[i*rsx + j*csx]); + } + } + } + } + + return; +} + +double libblis_test_iscal2m_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + dim_t M = bli_obj_length( y ); + dim_t N = bli_obj_width( y ); + bool transx = bli_obj_has_trans( x ); + bool conjx = bli_obj_has_conj( x ); + dim_t rsy = bli_obj_row_stride( y ) ; + dim_t csy = bli_obj_col_stride( y ) ; + dim_t rsx, csx; + double resid = 0.0; + + if( bli_obj_is_col_stored( x ) ) { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } else { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_iscal2m_check(M, N, Alpha, X, rsx, csx, + Y, rsy, csy); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_iscal2m_check(M, N, Alpha, X, rsx, csx, + Y, rsy, csy); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icscal2m_check(M, N, Alpha, X, rsx, csx, + conjx, Y, rsy, csy); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icscal2m_check(M, N, Alpha, X, rsx, csx, + conjx, Y, rsy, csy); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_scal2v.cpp b/gtestsuite/src/ref_scal2v.cpp new file mode 100644 index 000000000..8d1806b31 --- /dev/null +++ b/gtestsuite/src/ref_scal2v.cpp @@ -0,0 +1,146 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_scal2v.h" + +using namespace std; + +//* ========================================================================== +//*> SCAL2V performs vector operations +//*> y := alpha * conjx(x) +//*> where x is a vector of length n, and alpha is a scalar. +//* ========================================================================== + +template +void libblis_iscal2v_check(dim_t len, T* alpha, T* X, dim_t incx, + T* Y, dim_t incy) { + dim_t i, ix, iy; + //T ONE = 1.0 ; + T ZERO = 0.0 ; + T Alpha = alpha[0]; + + if (len == 0){ + return; + } + + ix = 0; + iy = 0; + if (Alpha == ZERO) { + for(i = 0 ; i < len ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < len ; i++) { + Y[iy] = Alpha * X[ix]; + iy = iy + incy; + ix = ix + incx; + } + } + + return; +} + +template +void libblis_icscal2v_check(dim_t len, T* alpha, T* X, dim_t incx, + T* Y, dim_t incy, bool cfx) { + dim_t i, ix, iy; + //T ONE = {1.0 , 0.0} ; + T ZERO = {0.0 , 0.0} ; + T Alpha = *alpha; + + if(len == 0) { + return; + } + + ix = 0; + if(cfx) { + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + ix = 0; + iy = 0; + if ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)) { + for(i = 0; i < len ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < len ; i++) { + Y[iy] = mulc(Alpha , X[ix]); + ix = ix + incx; + iy = iy + incy; + } + } + + return; +} + +double libblis_test_iscal2v_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y_orig ); + bool cfx = bli_obj_has_conj( x ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_iscal2v_check(M, Alpha, X, incx, Y, incy ); + resid = computediffrv(M, incx, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_iscal2v_check(M, Alpha, X, incx, Y, incy ); + resid = computediffrv(M, incx, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icscal2v_check(M, Alpha, X, incx, + Y, incy, cfx ); + resid = computediffiv(M, incx, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icscal2v_check(M, Alpha, X, incx, + Y, incy, cfx ); + resid = computediffiv(M, incx, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_scalm.cpp b/gtestsuite/src/ref_scalm.cpp new file mode 100644 index 000000000..cc9f8f3c5 --- /dev/null +++ b/gtestsuite/src/ref_scalm.cpp @@ -0,0 +1,139 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_scalm.h" + +using namespace std; + +//* ========================================================================== +//*> SCALM performs matrix operations +//*> A := conjalpha(alpha) * A +//*> where A is an m x n matrix, and alpha is a scalar. +//* ========================================================================== + +template +void libblis_iscalm_check(dim_t M, dim_t N, T* alpha, + T* X, dim_t rsx, dim_t csx ) { + + dim_t i, j; + T ONE = 1.0 ; + T ZERO = 0.0 ; + T Alpha = alpha[0]; + + if ((M == 0) || (N == 0)) { + return; + } + + if (Alpha != ONE) { + if (Alpha == ZERO) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = ZERO; + } + } + } + else { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = Alpha * X[i*rsx + j*csx]; + } + } + } + } + + return; +} + +template +void libblis_icscalm_check(dim_t M, dim_t N, T* alpha, + T* X, dim_t rsx, dim_t csx, bool cfalpha) { + dim_t i, j; + T ONE = {1.0, 0.0} ; + T ZERO = {0.0, 0.0} ; + T Alpha = *alpha; + + if ((M == 0) || (N == 0)) { + return; + } + + if(cfalpha) + Alpha = conjugate(Alpha); + + /* First form x := Alpha*x. */ + if ((Alpha.real != ONE.real) && (Alpha.imag != ONE.imag)) { + if ((Alpha.real != ZERO.real) && (Alpha.imag != ZERO.imag)) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = ZERO; + } + } + } + else { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = mulc(Alpha , X[i*rsx + j*csx]); + } + } + } + } + + return; +} + +double libblis_test_iscalm_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* x_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_length( x ); + dim_t N = bli_obj_width( x ); + dim_t rsx = bli_obj_row_stride( x ) ; + dim_t csx = bli_obj_col_stride( x ) ; + bool cfalpha = bli_obj_has_conj( alpha ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x_orig ); + float* XX = (float*) bli_obj_buffer( x ); + libblis_iscalm_check(M, N, Alpha, X, rsx, csx); + resid = computediffrm(M, N, XX, X, rsx, csx); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x_orig ); + double* XX = (double*) bli_obj_buffer( x ); + libblis_iscalm_check(M, N, Alpha, X, rsx, csx); + resid = computediffrm(M, N, XX, X, rsx, csx); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x_orig ); + scomplex* XX = (scomplex*) bli_obj_buffer( x ); + libblis_icscalm_check(M, N, Alpha, X, rsx, csx, cfalpha); + resid = computediffim(M, N, XX, X, rsx, csx); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x_orig ); + dcomplex* XX = (dcomplex*) bli_obj_buffer( x ); + libblis_icscalm_check(M, N, Alpha, X, rsx, csx, cfalpha); + resid = computediffim(M, N, XX, X, rsx, csx); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_scalv.cpp b/gtestsuite/src/ref_scalv.cpp new file mode 100644 index 000000000..2af4e2d8c --- /dev/null +++ b/gtestsuite/src/ref_scalv.cpp @@ -0,0 +1,130 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_scalv.h" + +using namespace std; + +//* ========================================================================== +//*> SCALV performs vector operations +//*> x := conjalpha(alpha) * x +//*> where x is a vector of length n, and alpha is a scalar. +//* ========================================================================== + +template +void libblis_iscalv_check(dim_t len, T* beta, T* X, dim_t incx) { + + dim_t i, ix; + T ONE = 1.0 ; + T ZERO = 0.0 ; + T Beta = beta[0]; + + if (len == 0){ + return; + } + + if( Beta != ONE ) { + ix = 0; + if (Beta == ZERO) { + for( i = 0 ; i < len ; i++ ) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for( i = 0 ; i < len ; i++ ) { + X[ix] = Beta * X[ix]; + ix = ix + incx; + } + } + } + return; +} + +template +void libblis_icscalv_check(dim_t len, T* beta, T* X, dim_t incx, bool cfbeta) { + dim_t i, ix; + T ONE = {1.0, 0.0} ; + T ZERO = {0.0, 0.0} ; + T Beta = *beta; + + if( len == 0 ) { + return; + } + + if( cfbeta ) + Beta = conjugate(Beta); + + /* First form x := beta*x. */ + if( Beta.real != ONE.real ) { + ix = 0; + if( (Beta.real != ZERO.real) && (Beta.imag != ZERO.imag) ) { + for(i = 0; i < len ; i++) { + X[ix] = ZERO; + ix = ix + incx; + } + } + else { + for( i = 0 ; i < len ; i++ ) { + X[ix] = mulc(Beta , X[ix]); + ix = ix + incx; + } + } + } + return; +} + +double libblis_test_iscalv_check( + test_params_t* params, + obj_t* beta, + obj_t* x, + obj_t* x_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + bool cfbeta = bli_obj_has_conj( beta ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Beta = (float*) bli_obj_buffer( beta ); + float* X = (float*) bli_obj_buffer( x_orig ); + float* XX = (float*) bli_obj_buffer( x ); + libblis_iscalv_check(M, Beta, X, incx ); + resid = computediffrv(M, incx, XX, X); + break; + } + case BLIS_DOUBLE : + { + double* Beta = (double*) bli_obj_buffer( beta ); + double* X = (double*) bli_obj_buffer( x_orig ); + double* XX = (double*) bli_obj_buffer( x ); + libblis_iscalv_check(M, Beta, X, incx ); + resid = computediffrv(M, incx, XX, X); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* X = (scomplex*) bli_obj_buffer( x_orig ); + scomplex* XX = (scomplex*) bli_obj_buffer( x ); + libblis_icscalv_check(M, Beta, X, incx, cfbeta ); + resid = computediffiv(M, incx, XX, X); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x_orig ); + dcomplex* XX = (dcomplex*) bli_obj_buffer( x ); + libblis_icscalv_check(M, Beta, X, incx, cfbeta ); + resid = computediffiv(M, incx, XX, X); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} diff --git a/gtestsuite/src/ref_subm.cpp b/gtestsuite/src/ref_subm.cpp new file mode 100644 index 000000000..8916a81eb --- /dev/null +++ b/gtestsuite/src/ref_subm.cpp @@ -0,0 +1,130 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_subm.h" + +using namespace std; + +//* ========================================================================== +//*> SUBM performs matrix operations +//*> B := B - transa(A) +//*> where B is an m x n matrix. +//* ========================================================================== + +template +void libblis_isubm_check(dim_t M, dim_t N, T* X, dim_t rsx, dim_t csx, + T* Y, dim_t rsy, dim_t csy, T* YY) { + + dim_t i, j; + + if ((M == 0) || (N == 0)) { + return; + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = Y[i*rsy + j*csy] - X[i*rsx + j*csx] ; + } + } + + return; +} + +template +void libblis_icsubm_check(dim_t M, dim_t N, T* X, dim_t rsx, dim_t csx, + conj_t conjx, T* Y, dim_t rsy, dim_t csy) { + + dim_t i, j; + + if ((M == 0) || (N == 0)) { + return; + } + + if(conjx) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = conjugate(X[i*rsx + j*csx]); + } + } + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = subc(Y[i*rsy + j*csy], X[i*rsx + j*csx]); + } + } + + return; +} + +double libblis_test_isubm_check( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + bool transx = bli_obj_has_trans( x ); + conj_t conjx = bli_obj_conj_status( x ); + dim_t M = bli_obj_length( y ); + dim_t N = bli_obj_width( y ); + dim_t rsy = bli_obj_row_stride( y ) ; + dim_t csy = bli_obj_col_stride( y ) ; + double resid = 0.0; + dim_t rsx, csx; + + if( bli_obj_is_col_stored( x ) ) { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } else { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_isubm_check( M, N, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_isubm_check( M, N, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icsubm_check( M, N, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icsubm_check( M, N, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_subv.cpp b/gtestsuite/src/ref_subv.cpp new file mode 100644 index 000000000..0137a8fe7 --- /dev/null +++ b/gtestsuite/src/ref_subv.cpp @@ -0,0 +1,117 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_subv.h" + +using namespace std; + +//* ========================================================================== +//*> SUBV performs vector operations +//*> y := y - conjx(x) +//*> where x and y are vectors of length n. +//* ========================================================================== + +template +void libblis_isubv_check(dim_t len, T* X, dim_t incx, T* Y, dim_t incy) { + + dim_t i, ix, iy; + if (len == 0) { + return; + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = Y[iy] - X[ix]; + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +template +void libblis_icsubv_check(dim_t len, T* X, dim_t incx, T* Y, + dim_t incy, bool cfx) { + dim_t i, ix, iy; + if (len == 0) { + return; + } + + ix = 0; + if(cfx) { + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = subc(Y[iy] , X[ix]); + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +double libblis_test_isubv_check( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + bool cfx = bli_obj_has_conj( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y_orig ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_isubv_check( M, X, incx, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_isubv_check( M, X, incx, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icsubv_check( M, X, incx, Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icsubv_check( M, X, incx, Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_symm.cpp b/gtestsuite/src/ref_symm.cpp new file mode 100644 index 000000000..177413ed5 --- /dev/null +++ b/gtestsuite/src/ref_symm.cpp @@ -0,0 +1,486 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_symm.h" + +using namespace std; + +//* ========================================================================== +//*> SYMM performs one of the matrix-matrix operations +//*> C := alpha*A*B + beta*C, +//*> or +//*> C := alpha*B*A + beta*C, +//*> where alpha and beta are scalars, A is a symmetric matrix and B and +//*> C are m by n matrices. +//* ========================================================================== + +template +void libblis_isymm_check(side_t side, uplo_t uplo, dim_t M, dim_t N, + T Alpha, T* A, dim_t rsa, dim_t csa, T* B, dim_t rsb, dim_t csb, T Beta, + T* C, dim_t rsc, dim_t csc ) +{ + T ONE = 1.0; + T ZERO = 0.0; + T tmp1, tmp2; + bool LSIDE, UPPER; + dim_t i, j, k; + + //* Test the input parameters. + LSIDE = (side == BLIS_LEFT); + UPPER = (uplo == BLIS_UPPER); + + if( (M == 0 || N == 0) || ( Alpha == ZERO && Beta == ONE ) ) + return; + + //* And when Alpha.eq.zero. + if( Alpha == ZERO ) + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + return; + } + + //* Start the operations. + if( LSIDE ) + { + //* Form C := Alpha*A*B + Beta*C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp1 = Alpha*B[i*rsb + j*csb]; + tmp2 = ZERO; + for( k = 0 ; k < i ; k++ ) + { + C[k*rsc + j*csc] = C[k*rsc + j*csc] + tmp1*A[k*rsa + i*csa]; + tmp2 = tmp2 + B[k*rsb + j*csb] * A[k*rsa + i*csa]; + } + if (Beta == ZERO) + { + C[i*rsc + j*csc] = tmp1*A[i*rsa + i*csa] + Alpha*tmp2; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + tmp1*A[i*rsa + i*csa] + Alpha*tmp2; + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = (M-1) ; i >= 0 ; i-- ) + { + tmp1 = Alpha*B[i*rsb + j*csb]; + tmp2 = ZERO; + for( k = (i+1) ; k < M ; k++ ) + { + C[k*rsc + j*csc] = C[k*rsc + j*csc] + tmp1*A[k*rsa + i*csa]; + tmp2 = tmp2 + B[k*rsb + j*csb]*A[k*rsa + i*csa]; + } + if (Beta == ZERO) + { + C[i*rsc + j*csc] = tmp1*A[i*rsa + i*csa] + Alpha*tmp2; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + tmp1*A[i*rsa + i*csa] + Alpha*tmp2; + } + } + } + } + } + else + { + //* Form C := Alpha*B*A + Beta*C. + for( j = 0 ; j < N ; j++ ) + { + tmp1 = Alpha*A[j*rsa + j*csa]; + if( Beta == ZERO ) + { + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = tmp1*B[i*rsb + j*csb]; + } + } + else + { + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + tmp1*B[i*rsb + j*csb]; + } + } + for( k = 0 ; k < j ; k++ ) + { + if( UPPER ) + { + tmp1 = Alpha*A[k*rsa + j*csa]; + } + else + { + tmp1 = Alpha*A[j*rsa + k*csa]; + } + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + tmp1*B[i*rsb + k*csb]; + } + } + for( k = (j+1) ; k < N ; k++ ) + { + if( UPPER ) + { + tmp1 = Alpha*A[j*rsa + k*csa]; + } + else + { + tmp1 = Alpha*A[k*rsa + j*csa]; + } + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + tmp1*B[i*rsb + k*csb]; + } + } + } + } + return; +} + +template +void libblis_icsymm_check(side_t side, uplo_t uplo, dim_t M, dim_t N, + T Alpha, T* A, dim_t rsa, dim_t csa, T* B, dim_t rsb, dim_t csb, T Beta, + T* C, dim_t rsc, dim_t csc ) +{ + T ONE = {1.0 , 0.0}; + T ZERO = {0.0 , 0.0}; + T tmp1, tmp2; + bool LSIDE, UPPER; + dim_t i, j, k; + + //* Test the input parameters. + LSIDE = (side == BLIS_LEFT); + UPPER = (uplo == BLIS_UPPER); + + if( (M == 0 || N == 0) || ( Alpha.real == ZERO.real && Beta.real == ONE.real ) ) + return; + + //* And when Alpha.eq.zero. + if( Alpha.real == ZERO.real ) + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + return; + } + + //* Start the operations. + if( LSIDE ) + { + //* Form C := Alpha*A*B + Beta*C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp1 = mulc(Alpha , B[i*rsb + j*csb]); + tmp2 = ZERO; + for( k = 0 ; k < i ; k++ ) + { + C[k*rsc + j*csc] = addc(C[k*rsc + j*csc] , mulc(tmp1 , A[k*rsa + i*csa])); + tmp2 = addc(tmp2 , mulc(B[k*rsb + j*csb] , A[k*rsa + i*csa])); + } + if (Beta.real == ZERO.real) + { + C[i*rsc + j*csc] = addc(mulc(tmp1 , A[i*rsa + i*csa]) , mulc(Alpha , tmp2)); + } + else + { + tmp2 = addc(mulc(tmp1 , A[i*rsa + i*csa]) , mulc(Alpha , tmp2)); + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , tmp2); + //C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + tmp1 * A[i*rsa + i*csa] + Alpha*tmp2; + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = (M-1) ; i >= 0 ; i-- ) + { + tmp1 = mulc(Alpha , B[i*rsb + j*csb]); + tmp2 = ZERO; + for( k = (i+1) ; k < M ; k++ ) + { + C[k*rsc + j*csc] = addc(C[k*rsc + j*csc] , mulc(tmp1 , A[k*rsa + i*csc])); + tmp2 = addc(tmp2 , mulc(B[k*rsb + j*csb] , A[k*rsa + i*csa])); + } + if (Beta.real == ZERO.real) + { + C[i*rsc + j*csc] = addc(mulc(tmp1 , A[i*rsa + i*csa]) , mulc(Alpha , tmp2)); + } + else + { + tmp2 = addc(mulc(tmp1 , A[i*rsa + i*csa]) , mulc(Alpha , tmp2)); + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , tmp2); + //C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + tmp1 * A[i*rsa + i*csa] + Alpha*tmp2; + } + } + } + } + } + else + { + //* Form C := Alpha*B*A + Beta*C. + for( j = 0 ; j < N ; j++ ) + { + tmp1 = mulc(Alpha , A[j*rsa + j*csa]); + if (Beta.real == ZERO.real) + { + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = mulc(tmp1 , B[i*rsb + j*csb]); + } + } + else + { + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , mulc(tmp1 , B[i*rsb + j*csb])); + } + } + for( k = 0 ; k < j ; k++ ) + { + if( UPPER ) + { + tmp1 = mulc(Alpha , A[k*rsa + j*csa]); + } + else + { + tmp1 = mulc(Alpha , A[j*rsa + k*csa]); + } + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , mulc(tmp1 , B[i*rsb + k*csb])); + } + } + for( k = (j+1) ; k < N ; k++ ) + { + if( UPPER ) + { + tmp1 = mulc(Alpha , A[j*rsa + k*csa]); + } + else + { + tmp1 = mulc(Alpha , A[k*rsa + j*csa]); + } + for(i = 0 ; i < M ; i++) + { + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , mulc(tmp1 , B[i*rsb + k*csb])); + } + } + } + } + return; +} + +double libblis_test_isymm_check + ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ) +{ + + num_t dt = bli_obj_dt( a ); + uplo_t uploa = bli_obj_uplo( a ); + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + dim_t rsb = bli_obj_row_stride( b ) ; + dim_t csb = bli_obj_col_stride( b ) ; + dim_t rsc = bli_obj_row_stride( c ) ; + dim_t csc = bli_obj_col_stride( c ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* B = (float*) bli_obj_buffer( b ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* C = (float*) bli_obj_buffer( c_orig ); + float* CC = (float*) bli_obj_buffer( c ); + libblis_isymm_check(side, uploa, M, N, *Alpha, A, rsa, csa, + B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, N, CC, C, rsc, csc); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* B = (double*) bli_obj_buffer( b ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* C = (double*) bli_obj_buffer( c_orig ); + double* CC = (double*) bli_obj_buffer( c ); + libblis_isymm_check(side, uploa, M, N, *Alpha, A, rsa, csa, + B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, N, CC, C, rsc, csc); + } + break; + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* B = (scomplex*) bli_obj_buffer( b ); + scomplex* C = (scomplex*) bli_obj_buffer( c_orig ); + scomplex* CC = (scomplex*) bli_obj_buffer( c ); + libblis_icsymm_check(side, uploa, M, N, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffim(M, N, CC, C, rsc, csc); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* B = (dcomplex*) bli_obj_buffer( b ); + dcomplex* C = (dcomplex*) bli_obj_buffer( c_orig ); + dcomplex* CC = (dcomplex*) bli_obj_buffer( c ); + libblis_icsymm_check(side, uploa, M, N, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffim(M, N, CC, C, rsc, csc); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +template +double libblis_check_nan_real( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_symm(obj_t* c, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( c ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_symv.cpp b/gtestsuite/src/ref_symv.cpp new file mode 100644 index 000000000..2b2e1acad --- /dev/null +++ b/gtestsuite/src/ref_symv.cpp @@ -0,0 +1,305 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_symv.h" + +using namespace std; + +//* ========================================================================== +//*> SYMV performs the matrix-vector operation +//*> y := alpha*A*x + beta*y +//*> where alpha and beta are scalars, x and y are n element vectors and +//*> A is an n by n symmetric matrix. +//* ========================================================================== + +template +void libblis_isymv_check(uplo_t uploa, dim_t M, T* alpha, T* A, + dim_t rsa, dim_t csa, T* X, dim_t incx, T* beta, T* Y, dim_t incy) { + T ONE = 1.0; + T ZERO = 0.0; + T Alpha = alpha[0]; + T Beta = beta[0]; + T tmp1, tmp2; + dim_t i, ix, iy, j, jx, jy, kx, ky; + + if ((M == 0) || + ((Alpha == ZERO) && (Beta == ONE))) + return ; + + //* Set up the start points in X and Y. + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (M * incx); + } + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (M * incy); + } + + //* First form y := beta*y. + if (Beta != ONE) { + iy = ky; + if (Beta == ZERO) { + for(i = 0 ; i < M ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < M ; i++) { + Y[iy] = (Beta * Y[iy]); + iy = iy + incy; + } + } + } + + if (Alpha == ZERO) + return; + + T tmp = 0.0 ; + if(uploa == BLIS_UPPER) { + //* Form y when A is stored in upper triangle. + jx = kx; + jy = ky; + for(j = 0 ; j < M ; j++) { + tmp1 = (Alpha * X[jx]); + tmp2 = ZERO; + ix = kx; + iy = ky; + for(i = 0 ; i < j ; i++) { + tmp = A[i*rsa + j*csa]; + Y[iy] = Y[iy] + (tmp1 * tmp); + tmp2 = tmp2 + (tmp * X[ix]); + ix = ix + incx; + iy = iy + incy; + } + tmp = A[j*rsa + j*csa]; + Y[jy] = Y[jy] + (tmp1 * tmp) + (Alpha * tmp2); + jx = jx + incx; + jy = jy + incy; + } + } + else { + //* Form y when A is stored in lower triangle. + jx = kx; + jy = ky; + for(j = 0 ; j < M ; j++) { + tmp1 = (Alpha * X[jx]); + tmp = A[j*rsa + j*csa]; + tmp2 = ZERO; + Y[jy] = Y[jy] + (tmp1 * tmp); + ix = jx; + iy = jy; + for(i = (j+1) ; i < M ; i++) { + ix = ix + incx; + iy = iy + incy; + tmp = A[i*rsa + j*csa]; + Y[iy] = Y[iy] + (tmp1 * tmp); + tmp2 = tmp2 + (tmp * X[ix]); + } + Y[jy] = Y[jy] + (Alpha * tmp2); + jx = jx + incx; + jy = jy + incy; + } + } + + return; +} + +template +void libblis_icsymv_check(uplo_t uploa, dim_t M, T* alpha, T* A, dim_t rsa, +dim_t csa, bool conja, T* X, dim_t incx, bool conjx, T* beta, T* Y, dim_t incy) { + T ONE = { 1.0, 0.0 }; + T ZERO = { 0.0, 0.0 }; + T Alpha = *alpha; + T Beta = *beta; + T tmp1, tmp2; + dim_t i, ix, iy, j, jx, jy, kx, ky; + + if ((M == 0) || + ((Alpha.real == ZERO.real) && (Beta.real == ONE.real))) + return ; + + //* Set up the start points in X and Y. + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (M * incx); + } + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (M * incy); + } + + //* First form y := beta*y. + if((Beta.real != ONE.real) && (Beta.imag != ONE.imag)) { + iy = ky; + if((Beta.real != ZERO.real) && (Beta.imag != ZERO.imag)) { + for(i = 0 ; i < M ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < M ; i++) { + Y[iy] = mulc(Beta , Y[iy]); + iy = iy + incy; + } + } + } + + if((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)) + return; + + if(conjx) { + ix = 0; + for(i = 0 ; i < M ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(conja) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < M ; j++) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + T tmp = {0.0, 0.0}; + if(uploa == BLIS_UPPER) { + //* Form y when A is stored in upper triangle. + jx = kx; + jy = ky; + for(j = 0 ; j < M ; j++) { + tmp1 = mulc(Alpha , X[jx]); + tmp2 = ZERO; + ix = kx; + iy = ky; + for(i = 0 ; i < j ; i++) { + tmp = A[i*rsa + j*csa]; + Y[iy] = addc(Y[iy] , mulc(tmp1 , tmp)); + tmp2 = addc(tmp2 , mulc(tmp , X[ix])); + ix = ix + incx; + iy = iy + incy; + } + tmp = A[j*rsa + j*csa]; + tmp = addc(mulc(tmp1 , tmp) , mulc(Alpha , tmp2)); + Y[jy] = addc(Y[jy] , tmp ); + jx = jx + incx; + jy = jy + incy; + } + } + else { + //* Form y when A is stored in lower triangle. + jx = kx; + jy = ky; + for(j = 0 ; j < M ; j++) { + tmp1 = mulc(Alpha , X[jx]); + tmp = A[j*rsa + j*csa]; + tmp2 = ZERO; + Y[jy] = addc(Y[jy] , mulc(tmp1 , tmp)); + ix = jx; + iy = jy; + for(i = (j+1) ; i < M ; i++) { + ix = ix + incx; + iy = iy + incy; + tmp = A[i*rsa + j*csa]; + Y[iy] = addc(Y[iy] , mulc(tmp1 , tmp)); + tmp2 = addc(tmp2 , mulc(tmp , X[ix])); + } + Y[jy] = addc(Y[jy] , mulc(Alpha , tmp2)); + jx = jx + incx; + jy = jy + incy; + } + } + + return; +} + +double libblis_test_isymv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( a ); + uplo_t uploa = bli_obj_uplo( a ); + dim_t M = bli_obj_length( a ); + dim_t rsa = bli_obj_row_stride( a ); + dim_t csa = bli_obj_col_stride( a ); + bool conja = bli_obj_has_conj( a ); + dim_t incx = bli_obj_vector_inc( x ); + dim_t incy = bli_obj_vector_inc( y ); + bool conjx = bli_obj_has_conj( x ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* X = (float*) bli_obj_buffer( x ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_isymv_check(uploa, M, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* X = (double*) bli_obj_buffer( x ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_isymv_check(uploa, M, Alpha, A, rsa, csa, + X, incx, Beta, Y, incy); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icsymv_check(uploa, M, Alpha, A, rsa, csa, + conja, X, incx, conjx, Beta, Y, incy); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icsymv_check(uploa, M, Alpha, A, rsa, csa, + conja, X, incx, conjx, Beta, Y, incy); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_syr.cpp b/gtestsuite/src/ref_syr.cpp new file mode 100644 index 000000000..1f29a5659 --- /dev/null +++ b/gtestsuite/src/ref_syr.cpp @@ -0,0 +1,195 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_syr.h" + +using namespace std; + +//* ========================================================================== +//*> SYR performs the symmetric rank 1 operation +//*> A := alpha*x*x**T + A, +//*> where alpha is a real scalar, x is an n element vector and A is an +//*> n by n symmetric matrix. +//* ========================================================================== + +template +void libblis_isyr_check(uplo_t uploa, dim_t N, T* alpha, T* X, dim_t incx, + T* A, dim_t rsa, dim_t csa) { + T ZERO = 0.0; + T Alpha = alpha[0]; + T temp; + int i, ix, j, jx, kx; + + if((N == 0) || (Alpha == ZERO)) + return; + + /* Set the start point in X if the increment is not unity. */ + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if(uploa == BLIS_UPPER) { + /* Form A when A is stored in upper triangle. */ + jx = kx; + for(j = 0; j < N ; j++) { + if (X[jx] != ZERO) { + temp = Alpha*X[jx]; + ix = kx; + for(i = 0 ; i <= j ; i++) { + A[i*rsa + j*csa] = A[i*rsa + j*csa] + X[ix]*temp; + ix = ix + incx; + } + } + jx = jx + incx; + } + } + else + { + /* Form A when A is stored in lower triangle. */ + jx = kx; + for(j = 0; j < N ; j++) { + if (X[jx] != ZERO) { + temp = Alpha*X[jx]; + ix = jx; + for(i = j ; i < N ; i++) { + A[i*rsa + j*csa] = A[i*rsa + j*csa] + X[ix]*temp; + ix = ix + incx; + } + } + jx = jx + incx; + } + } + return; +} + +template +void libblis_icsyr_check(uplo_t uploa, dim_t N, T* alpha, T* X, dim_t incx, + bool conjx, T* A, dim_t rsa, dim_t csa) { + T ZERO = {0.0 , 0.0}; + T Alpha = alpha[0]; + T temp; + int i, ix, j, jx, kx; + + if ((N == 0) || ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag))) + return; + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if(conjx) { + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(uploa == BLIS_UPPER) { + /* Form A when A is stored in upper triangle. */ + jx = kx; + for(j = 0 ; j < N ; j++) { + if ((X[jx].real != ZERO.real) || (X[jx].imag != ZERO.imag)) { + temp = mulc(Alpha , X[jx]); + ix = kx; + for(i = 0 ; i <= j ; i++) { + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , mulc(X[ix] , temp)); + ix = ix + incx; + } + } + jx = jx + incx; + } + } + else { + /* Form A when A is stored in lower triangle. */ + jx = kx; + for(j = 0; j < N ; j++) { + if ((X[jx].real != ZERO.real) || (X[jx].imag != ZERO.imag)) { + temp = mulc(Alpha , X[jx]); + ix = jx; + for(i = j ; i < N ; i++) { + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , mulc(X[ix] , temp)); + ix = ix + incx; + } + } + jx = jx + incx; + } + } + + return; +} + +double libblis_test_isyr_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig +){ + + num_t dt = bli_obj_dt( x ); + uplo_t uploa = bli_obj_uplo( a ); + dim_t M = bli_obj_length( a ); + dim_t N = bli_obj_width( a ); + dim_t incx = bli_obj_vector_inc( x ); + bool conjx = bli_obj_has_conj( x ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a_orig ); + float* X = (float*) bli_obj_buffer( x ); + float* AA = (float*) bli_obj_buffer( a ); + libblis_isyr_check(uploa, M, Alpha, X, incx, + A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a_orig ); + double* X = (double*) bli_obj_buffer( x ); + double* AA = (double*) bli_obj_buffer( a ); + libblis_isyr_check(uploa, M, Alpha, X, incx, + A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a_orig ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* AA = (scomplex*) bli_obj_buffer( a ); + libblis_icsyr_check(uploa, M, Alpha, X, incx, conjx, + A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a_orig ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* AA = (dcomplex*) bli_obj_buffer( a ); + libblis_icsyr_check(uploa, M, Alpha, X, incx, conjx, + A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + diff --git a/gtestsuite/src/ref_syr2.cpp b/gtestsuite/src/ref_syr2.cpp new file mode 100644 index 000000000..c0a923e7b --- /dev/null +++ b/gtestsuite/src/ref_syr2.cpp @@ -0,0 +1,243 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_syr2.h" + +using namespace std; + +//* ========================================================================== +//*> SYR2 performs the symmetric rank 2 operation +//*> A := alpha*x*y**T + alpha*y*x**T + A, +//*> where alpha is a scalar, x and y are n element vectors and A is an n +//*> by n symmetric matrix. +//* ========================================================================== + +template +void libblis_isyr2_check(uplo_t uploa, dim_t N, T* alpha, T* X, dim_t incx, + T* Y, dim_t incy, T* A, dim_t rsa, dim_t csa) { + + T ZERO = 0.0; + T Alpha = alpha[0]; + T tmp1, tmp2; + int i, ix, iy, j, jx, jy, kx, ky; + + if ((N == 0) || (Alpha == ZERO)) + return; + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (N * incy); + } + jx = kx; + jy = ky; + + if(uploa == BLIS_UPPER) { + //* Form A when A is stored in the upper triangle. + for(j = 0 ; j < N ; j++) { + if ((X[jx] != ZERO) || (Y[jy] != ZERO)) { + tmp1 = Alpha * Y[jy]; + tmp2 = Alpha * X[jx]; + ix = kx; + iy = ky; + for(i = 0 ; i <= j ; i++) { + A[i*rsa + j*csa] = A[i*rsa + j*csa] + (X[ix] * tmp1) + (Y[iy] * tmp2); + ix = ix + incx; + iy = iy + incy; + } + } + jx = jx + incx; + jy = jy + incy; + } + } + else { + //* Form A when A is stored in the lower triangle. + for(j = 0 ; j < N ; j++) { + if((X[jx] != ZERO) || (Y[jy] != ZERO)) { + tmp1 = Alpha * Y[jy]; + tmp2 = Alpha * X[jx]; + ix = jx; + iy = jy; + for(i = j ; i < N ; i++) { + A[i*rsa + j*csa] = A[i*rsa + j*csa] + (X[ix] * tmp1) + (Y[iy] * tmp2); + ix = ix + incx; + iy = iy + incy; + } + } + jx = jx + incx; + jy = jy + incy; + } + } + return; +} + +template +void libblis_icsyr2_check(uplo_t uploa, dim_t N, T* alpha, T* X, dim_t incx, + bool conjx, T* Y, dim_t incy, bool conjy, T* A, dim_t rsa, dim_t csa) { + + T ZERO = {0.0, 0.0}; + T Alpha = *alpha; + T tmp1, tmp2; + int i, ix, iy, j, jx, jy, kx, ky; + + if((N == 0) || ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag))) + return; + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if (incy > 0) { + ky = 0; + } + else { + ky = 1 - (N * incy); + } + jx = kx; + jy = ky; + + if(conjx) { + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + if(conjy) { + iy = 0; + for(i = 0 ; i < N ; i++) { + Y[iy] = conjugate(Y[iy]); + iy = iy + incy; + } + } + + T p1, p2, p; + if(uploa == BLIS_UPPER) { + //* Form A when A is stored in the upper triangle. + for(j = 0 ; j < N ; j++) { + tmp1 = mulc(Alpha , Y[jy]); + tmp2 = mulc(Alpha , X[jx]); + ix = kx; + iy = ky; + for(i = 0 ; i <= j ; i++) { + p1 = mulc(X[ix] , tmp1); + p2 = mulc(Y[iy] , tmp2); + p = addc(p1 , p2); + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , p); + ix = ix + incx; + iy = iy + incy; + } + jx = jx + incx; + jy = jy + incy; + } + } + else { + //* Form A when A is stored in the lower triangle. + for(j = 0 ; j < N ; j++) { + tmp1 = mulc(Alpha , Y[jy]); + tmp2 = mulc(Alpha , X[jx]); + ix = jx; + iy = jy; + for(i = j ; i < N ; i++) { + p1 = mulc(X[ix] , tmp1); + p2 = mulc(Y[iy] , tmp2); + p = addc(p1 , p2); + A[i*rsa + j*csa] = addc(A[i*rsa + j*csa] , p); + ix = ix + incx; + iy = iy + incy; + } + jx = jx + incx; + jy = jy + incy; + } + } + return; +} + +double libblis_test_isyr2_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +){ + + num_t dt = bli_obj_dt( x ); + uplo_t uploa = bli_obj_uplo( a ); + dim_t M = bli_obj_length( a ); + dim_t N = bli_obj_width( a ); + dim_t incx = bli_obj_vector_inc( x ); + dim_t incy = bli_obj_vector_inc( y ); + bool conjx = bli_obj_has_conj( x ); + bool conjy = bli_obj_has_conj( y ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a_orig ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y ); + float* AA = (float*) bli_obj_buffer( a ); + libblis_isyr2_check(uploa, M, Alpha, X, incx, + Y, incy, A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a_orig ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y ); + double* AA = (double*) bli_obj_buffer( a ); + libblis_isyr2_check(uploa, M, Alpha, X, incx, + Y, incy, A, rsa, csa); + resid = computediffrm(M, N, AA, A, rsa, csa); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a_orig ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y ); + scomplex* AA = (scomplex*) bli_obj_buffer( a ); + libblis_icsyr2_check(uploa, M, Alpha, X, incx, conjx, + Y, incy, conjy, A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a_orig ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y ); + dcomplex* AA = (dcomplex*) bli_obj_buffer( a ); + libblis_icsyr2_check(uploa, M, Alpha, X, incx, conjx, + Y, incy, conjy, A, rsa, csa); + resid = computediffim(M, N, AA, A, rsa, csa); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + + diff --git a/gtestsuite/src/ref_syr2k.cpp b/gtestsuite/src/ref_syr2k.cpp new file mode 100644 index 000000000..586399f8b --- /dev/null +++ b/gtestsuite/src/ref_syr2k.cpp @@ -0,0 +1,611 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_syr2k.h" + +using namespace std; + +//* ========================================================================== +//*> SYR2K performs one of the symmetric rank 2k operations +//*> C := alpha*A*B**T + alpha*B*A**T + beta*C, +//*> or +//*> C := alpha*A**T*B + alpha*B**T*A + beta*C, +//*> where alpha and beta are scalars, C is an n by n symmetric matrix +//*> and A and B are n by k matrices in the first case and k by n +//*> matrices in the second case. +//* ========================================================================== + +template +void libblis_isyr2k_check( uplo_t uplo, trans_t trans, dim_t N, dim_t K, + T Alpha, T* A, dim_t rsa, dim_t csa, T* B, dim_t rsb, dim_t csb, T Beta, + T* C, dim_t rsc, dim_t csc ) +{ + T tmp1, tmp2; + int i, j, l; + bool UPPER, NOTRANS; + + T ONE = 1.0 ; + T ZERO = 0.0 ; + + //* Test the input parameters. + UPPER = ( uplo == BLIS_UPPER ); + NOTRANS = ( trans == BLIS_NO_TRANSPOSE ); + + if( N == 0 || (( Alpha == ZERO || K == 0 ) && Beta == ONE )) + return; + + //* And when alpha.eq.zero. + if( Alpha == ZERO ) + { + if( UPPER ) + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + } + else + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + } + return; + } + + //* Start the operations. + if( NOTRANS ) + { + //* C := alpha*A*B**T + alpha*B*A**T + C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + if( Beta == ZERO ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta != ONE ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + for( l = 0 ; l < K ; l++ ) + { + if( (A[j*rsa + l*csa] != ZERO) || (B[j*rsb + l*csb] != ZERO) ) + { + tmp1 = Alpha*B[j*rsb + l*csb]; + tmp2 = Alpha*A[j*rsa + l*csa]; + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + A[i*rsa + l*csa]*tmp1 + B[i*rsb + l*csb]*tmp2; + } + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + if( Beta == ZERO ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( Beta != ONE ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + for( l = 0 ; l < K ; l++ ) + { + if( (A[j*rsa + l*csa] != ZERO) || (B[j*rsb + l*csb] != ZERO) ) + { + tmp1 = Alpha*B[j*rsb + l*csb]; + tmp2 = Alpha*A[j*rsa + l*csa]; + for( i = j; i < N ; i++ ) + { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + A[i*rsa + l*csa]*tmp1 + B[i*rsb + l*csb]*tmp2; + } + } + } + } + } + } + else + { + //* C := alpha*A**T*B + alpha*B**T*A + C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + tmp1 = ZERO; + tmp2 = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp1 = tmp1 + A[l*rsa + i*csa]*B[l*rsb + j*csb]; + tmp2 = tmp2 + B[l*rsb + i*csb]*A[l*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp1 + Alpha*tmp2; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + Alpha*tmp1 + Alpha*tmp2; + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + tmp1 = ZERO; + tmp2 = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp1 = tmp1 + A[l*rsa + i*csa]*B[l*rsb + j*csb]; + tmp2 = tmp2 + B[l*rsb + i*csb]*A[l*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp1 + Alpha*tmp2; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + Alpha*tmp1 + Alpha*tmp2; + } + } + } + } + } + return; +} + +template +void libblis_icsyr2k_check( uplo_t uplo, trans_t trans, dim_t N, dim_t K, + T Alpha, T* A, dim_t rsa, dim_t csa, T* B, dim_t rsb, dim_t csb, T Beta, + T* C, dim_t rsc, dim_t csc ) +{ + T tmp1, tmp2; + T tmpa, tmpb; + int i, j, l; + bool UPPER, NOTRANS; + + T ONE = { 1.0 , 0.0 }; + T ZERO = { 0.0 , 0.0 }; + + //* Test the input parameters. + UPPER = (uplo == BLIS_UPPER); + NOTRANS = (trans == BLIS_NO_TRANSPOSE); + + if( N == 0 || (( Alpha.real == ZERO.real || K == 0 ) && Beta.real == ONE.real )) + return; + + //* And when alpha.eq.zero. + if( Alpha.real == ZERO.real ) + { + if( UPPER ) + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + } + else + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + } + return; + } + + //* Start the operations. + if( NOTRANS ) + { + //* Form C := alpha*A*B**H + conjg( alpha )*B*A**H + C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + if( Beta.real == ZERO.real ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( (Beta.real != ONE.real) || (Beta.imag != ONE.imag) ) + { + for( i = 0 ; i <= j ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + for( l = 0 ; l < K ; l++ ) + { + if( ((A[j*rsa + l*csa].real != ZERO.real) || (A[j*rsa + l*csa].imag != ZERO.imag)) + || ((B[j*rsb + l*csb].real != ZERO.real) || (B[j*rsb + l*csb].imag != ZERO.imag)) ) + { + tmp1 = mulc(Alpha , B[j*rsb + l*csb]); + tmp2 = mulc(Alpha , A[j*rsa + l*csa]); + for( i = 0 ; i <= j ; i++) + { + tmpa = mulc(A[i*rsa + l*csa] , tmp1); + tmpb = mulc(B[i*rsb + l*csb] , tmp2); + tmpa = addc(tmpa , tmpb); + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , tmpa); + } + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + if( (Beta.real == ZERO.real) || (Beta.imag == ZERO.imag) ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + else if( (Beta.real != ONE.real) || (Beta.imag != ONE.imag) ) + { + for( i = j ; i < N ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + for( l = 0 ; l < K ; l++ ) + { + if( ((A[j*rsa + l*csa].real != ZERO.real) || (A[j*rsa + l*csa].imag != ZERO.imag)) + || ((B[j*rsb + l*csb].real != ZERO.real) || (B[j*rsb + l*csb].imag != ZERO.imag)) ) + { + tmp1 = mulc(Alpha , B[j*rsb + l*csb]); + tmp2 = mulc(Alpha , A[j*rsa + l*csa]); + for( i = j ; i < N ; i++ ) + { + tmpa = mulc(A[i*rsa + l*csa] , tmp1); + tmpb = mulc(B[i*rsb + l*csb] , tmp2); + tmpa = addc(tmpa, tmpb); + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , tmpa); + } + } + } + } + } + } + else + { + //* Form C := alpha*A**T*B + alpha*B**T*A + C. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i <= j ; i++ ) + { + tmp1 = ZERO; + tmp2 = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp1 = addc(tmp1 , mulc(A[l*rsa + i*csa] , B[l*rsb + j*csb])); + tmp2 = addc(tmp2 , mulc(B[l*rsb + i*csb] , A[l*rsa + j*csa])); + } + if( (Beta.real == ZERO.real) || (Beta.imag == ZERO.imag) ) + { + C[i*rsc + j*csc] = addc(mulc(Alpha , tmp1) , mulc(Alpha ,tmp2)); + } + else + { + tmpa = mulc(Alpha , tmp1); + tmpb = mulc(Alpha , tmp2); + tmpa = addc(tmpa , tmpb); + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) ,tmpa); + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = j ; i < N ; i++ ) + { + tmp1 = ZERO; + tmp2 = ZERO; + for( l = 0 ; l < K ; l++ ) + { + tmp1 = addc(tmp1 , mulc(A[l*rsa + i*csa] , B[l*rsb + j*csb])); + tmp2 = addc(tmp2 , mulc(B[l*rsb + i*csb] , A[l*rsa + j*csa])); + } + if( (Beta.real == ZERO.real) || (Beta.imag == ZERO.imag) ) + { + C[i*rsc + j*csc] = addc(mulc(Alpha , tmp1) , mulc(Alpha , tmp2)); + } + else + { + tmpa = mulc(Alpha , tmp1); + tmpb = mulc(Alpha , tmp2); + tmpa = addc(tmpa, tmpb); + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , tmpa); + } + } + } + } + } + return; +} + +double libblis_test_isyr2k_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ) +{ + num_t dt = bli_obj_dt( c ); + uplo_t uploc = bli_obj_uplo( c ); + dim_t M = bli_obj_length( c ); + dim_t K = bli_obj_width_after_trans( a ); + trans_t trans = bli_obj_onlytrans_status( a ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + dim_t rsb = bli_obj_row_stride( b ) ; + dim_t csb = bli_obj_col_stride( b ) ; + dim_t rsc = bli_obj_row_stride( c ) ; + dim_t csc = bli_obj_col_stride( c ) ; + double resid = 0.0; + f77_int lda, ldb, ldc; + + if( bli_obj_is_col_stored( c ) ) { + lda = bli_obj_col_stride( a ); + ldb = bli_obj_col_stride( b ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldb = bli_obj_row_stride( b ); + ldc = bli_obj_row_stride( c ); + } + + int nrowa; + if (trans == BLIS_NO_TRANSPOSE) { + nrowa = M; + } else { + nrowa = K; + } + + if( lda < max(1, nrowa) ) { + return resid; + } + if( ldb < max(1, nrowa) ) { + return resid; + } + if( ldc < max(1, (int)M) ) { + return resid; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* B = (float*) bli_obj_buffer( b ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* C = (float*) bli_obj_buffer( c_orig ); + float* CC = (float*) bli_obj_buffer( c ); + libblis_isyr2k_check(uploc, trans, M, K, *Alpha, A, + rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, M, CC, C, rsc, csc); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* B = (double*) bli_obj_buffer( b ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* C = (double*) bli_obj_buffer( c_orig ); + double* CC = (double*) bli_obj_buffer( c ); + libblis_isyr2k_check(uploc, trans, M, K, *Alpha, A, + rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, M, CC, C, rsc, csc); + } + break; + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* B = (scomplex*) bli_obj_buffer( b ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* C = (scomplex*) bli_obj_buffer( c_orig ); + scomplex* CC = (scomplex*) bli_obj_buffer( c ); + libblis_icsyr2k_check(uploc, trans, M, K, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffim(M, M, CC, C, rsc, csc); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* B = (dcomplex*) bli_obj_buffer( b ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* C = (dcomplex*) bli_obj_buffer( c_orig ); + dcomplex* CC = (dcomplex*) bli_obj_buffer( c ); + libblis_icsyr2k_check(uploc, trans, M, K, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffim(M, M, CC, C, rsc, csc); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return abs(resid); +} + +template +double libblis_check_nan_real( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_syr2k(obj_t* c, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( c ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_syrk.cpp b/gtestsuite/src/ref_syrk.cpp new file mode 100644 index 000000000..b4d806bcf --- /dev/null +++ b/gtestsuite/src/ref_syrk.cpp @@ -0,0 +1,503 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_syrk.h" + +using namespace std; + +//* ========================================================================== +//*> C := alpha*A*A**T + beta*C, +//*> or +//*> C := alpha*A**T*A + beta*C, +//* ========================================================================== + +template +void libblis_isyrk_check(uplo_t uplo, trans_t trans, dim_t N, dim_t K, + T* alpha, T* A, dim_t rsa, dim_t csa, T* beta, T* C, dim_t rsc, dim_t csc) { + + //* .. Local Scalars .. + T tmp; + dim_t i, j, l; + bool UPPER, NOTRANS; + T Alpha = alpha[0]; + T Beta = beta[0]; + + //* .. Parameters .. + T ONE, ZERO; + ONE = 1.0 ; + ZERO = 0.0 ; + + UPPER = (uplo == BLIS_UPPER); + NOTRANS = (trans == BLIS_NO_TRANSPOSE) || (trans == BLIS_CONJ_NO_TRANSPOSE); + + //* Quick return if possible. + if((N == 0) || + (((Alpha == ZERO) || (K == 0)) && (Beta == ONE))) { + return; + } + + //* And when alpha.eq.zero. + if (Alpha == ZERO) { + if (UPPER) { + if (Beta == ZERO) { + for(j = 0 ; j < N; j++) { + for(i = 0 ; i <= j ; i++) { + C[i*rsc + j*csc] = ZERO; + } + } + } + else { + for(j = 0 ; j < N ; j++) { + for(i = 0; i <= j ; i++) { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + } + else { + if (Beta == ZERO) { + for(j = 0 ; j < N ; j++) { + for(i = j ; i < N ; i++) { + C[i*rsc + j*csc] = ZERO; + } + } + } + else { + for(j = 0 ; j < N ; j++) { + for(i = j ; i < N ; i++) { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + } + return; + } + + //* Start the operations. + if(NOTRANS) { + //* Form C := alpha*A*A**T + beta*C. + if (UPPER) { + if(Beta == ZERO) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i <= j ; i++) { + C[i*rsc + j*csc] = ZERO; + } + } + } + else if(Beta != ONE) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i <= j ; i++) { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + + for(j = 0 ; j < N ; j++) { + for(l = 0; l < K ; l++) { + if (A[j*rsa + l*csa] != ZERO) { + tmp = Alpha*A[j*rsa + l*csa]; + for(i = 0 ; i <= j ; i++) { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + tmp*A[i*rsa + l*csa]; + } + } + } + } + } + else { + if(Beta == ZERO) { + for(j = 0; j < N ; j++) { + for(i = j ; i < N; i++) { + C[i*rsc + j*csc] = ZERO; + } + } + } + else if (Beta != ONE) { + for(j = 0; j < N ; j++) { + for(i = j; i < N; i++) { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + + for(j = 0; j < N ; j++) { + for(l = 0; l < K ; l++) { + if (A[j*rsa + l*csa] != ZERO) { + tmp = Alpha*A[j*rsa + l*csa]; + for(i = j ; i < N; i++) { + C[i*rsc + j*csc] = C[i*rsc + j*csc] + tmp*A[i*rsa + l*csa]; + } + } + } + } + } + } + else { + //* Form C := alpha*A**T*A + beta*C. + if (UPPER) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i <= j ; i++) { + tmp = ZERO; + for(l = 0; l < K ; l++) { + tmp = tmp + A[l*rsa + i*csa]*A[l*rsa + j*csa]; + } + if (Beta == ZERO) { + C[i*rsc + j*csc] = Alpha*tmp; + } + else { + C[i*rsc + j*csc] = Alpha*tmp + Beta*C[i*rsc + j*csc]; + } + } + } + } + else { + for(j = 0 ; j < N ; j++) { + for(i = j ; i < N ; i++) { + tmp = ZERO; + for(l = 0 ; l < K ; l++) { + tmp = tmp + A[l*rsa + i*csa]*A[l*rsa + j*csa]; + } + if (Beta == ZERO) { + C[i*rsc + j*csc] = Alpha*tmp; + } + else { + C[i*rsc + j*csc] = Alpha*tmp + Beta*C[i*rsc + j*csc]; + } + } + } + } + } + return; +} + +template +void libblis_icsyrk_check(uplo_t uplo, trans_t trans, dim_t N, dim_t K, + T* alpha, T* A, dim_t rsa, dim_t csa, T* beta, T* C, dim_t rsc, dim_t csc) { + + //* .. Local Scalars .. + T tmp; + dim_t i, j, l; + bool UPPER, NOTRANS; + T Alpha = *alpha; + T Beta = *beta; + + //* .. Parameters .. + T ONE, ZERO; + ONE = {1.0 , 0.0}; + ZERO = {0.0 , 0.0}; + + UPPER = (uplo == BLIS_UPPER); + NOTRANS = (trans == BLIS_NO_TRANSPOSE) || (trans == BLIS_CONJ_NO_TRANSPOSE); + + //* Quick return if possible. + if((N == 0) || + (((Alpha.real == ZERO.real) || (K == 0)) && (Beta.real == ONE.real))) { + return; + } + + //* And when alpha.eq.zero. + if((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)){ + if (UPPER) { + if((Beta.real == ZERO.real)&&(Beta.imag == ZERO.imag)) { + for(j = 0 ; j < N; j++) { + for(i = 0 ; i <= j ; i++) { + C[i*rsc + j*csc] = ZERO; + } + } + } + else { + for(j = 0 ; j < N ; j++) { + for(i = 0; i <= j ; i++) { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + } + else { + if((Beta.real == ZERO.real)&&(Beta.imag == ZERO.imag)) { + for(j = 0 ; j < N ; j++) { + for(i = j ; i < N ; i++) { + C[i*rsc + j*csc] = ZERO; + } + } + } + else { + for(j = 0 ; j < N ; j++) { + for(i = j ; i < N ; i++) { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + } + return; + } + + //* Start the operations. + if(NOTRANS) { + //* Form C := alpha*A*A**T + beta*C. + if (UPPER) { + if((Beta.real == ZERO.real)||(Beta.imag == ZERO.imag)) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i <= j ; i++) { + C[i*rsc + j*csc] = ZERO; + } + } + } + else if((Beta.real != ONE.real)||(Beta.imag != ONE.imag)) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i <= j ; i++) { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + + for(j = 0 ; j < N ; j++) { + for(l = 0; l < K ; l++) { + if((A[j*rsa + l*csa].real != ZERO.real) || (A[j*rsa + l*csa].imag != ZERO.imag)) { + tmp = mulc(Alpha , A[j*rsa + l*csa]); + for(i = 0 ; i <= j ; i++) { + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , mulc(tmp , A[i*rsa + l*csa])); + } + } + } + } + } + else { + if((Beta.real == ZERO.real)||(Beta.imag == ZERO.imag)) { + for(j = 0; j < N ; j++) { + for(i = j ; i < N; i++) { + C[i*rsc + j*csc] = ZERO; + } + } + } + else if((Beta.real != ONE.real) || (Beta.imag != ONE.imag)){ + for(j = 0; j < N ; j++) { + for(i = j; i < N; i++) { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + + for(j = 0; j < N ; j++) { + for(l = 0; l < K ; l++) { + if((A[j*rsa + l*csa].real != ZERO.real)||(A[j*rsa + l*csa].imag != ZERO.imag)) { + tmp = mulc(Alpha , A[j*rsa + l*csa]); + for(i = j ; i < N; i++) { + C[i*rsc + j*csc] = addc(C[i*rsc + j*csc] , mulc(tmp , A[i*rsa + l*csa])); + } + } + } + } + } + } + else { + //* Form C := alpha*A**T*A + beta*C. + if (UPPER) { + for(j = 0 ; j < N ; j++) { + for(i = 0 ; i <= j ; i++) { + tmp = ZERO; + for(l = 0; l < K ; l++) { + tmp = addc(tmp , mulc(A[l*rsa + i*csa] , A[l*rsa + j*csa])); + } + if((Beta.real == ZERO.real) ||(Beta.imag == ZERO.imag)){ + C[i*rsc + j*csc] = mulc(Alpha , tmp); + } + else { + C[i*rsc + j*csc] = addc(mulc(Alpha , tmp) , mulc(Beta , C[i*rsc + j*csc])); + } + } + } + } + else { + for(j = 0 ; j < N ; j++) { + for(i = j ; i < N ; i++) { + tmp = ZERO; + for(l = 0 ; l < K ; l++) { + tmp = addc(tmp , mulc(A[l*rsa + i*csa] , A[l*rsa + j*csa])); + } + if((Beta.real == ZERO.real) || (Beta.imag == ZERO.imag)) { + C[i*rsc + j*csc] = mulc(Alpha , tmp); + } + else { + C[i*rsc + j*csc] = addc(mulc(Alpha , tmp) , mulc(Beta , C[i*rsc + j*csc])); + } + } + } + } + } + return; +} + +double libblis_test_isyrk_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig +){ + num_t dt = bli_obj_dt( a ); + dim_t M = bli_obj_length( c ); + dim_t K = bli_obj_width_after_trans( a ); + uplo_t uploc = bli_obj_uplo( c ); + trans_t transa = bli_obj_onlytrans_status( a ); + double resid = 0.0; + dim_t rsa, csa; + dim_t rsc, csc; + + rsa = bli_obj_row_stride( a ) ; + csa = bli_obj_col_stride( a ) ; + rsc = bli_obj_row_stride( c ) ; + csc = bli_obj_col_stride( c ) ; + + f77_int lda; + if( bli_obj_is_col_stored( c ) ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + int nrowa; + if (transa == BLIS_NO_TRANSPOSE) { + nrowa = M; + } else { + nrowa = K; + } + + if( lda < max(1, nrowa) ) { + return resid; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* C = (float*) bli_obj_buffer( c_orig ); + float* CC = (float*) bli_obj_buffer( c ); + libblis_isyrk_check(uploc, transa, M, K, Alpha, + A, rsa, csa, Beta, C, rsc, csc); + resid = computediffrm(M, M, CC, C, rsc, csc); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* C = (double*) bli_obj_buffer( c_orig ); + double* CC = (double*) bli_obj_buffer( c ); + libblis_isyrk_check(uploc, transa, M, K, Alpha, + A, rsa, csa, Beta, C, rsc, csc); + resid = computediffrm(M, M, CC, C, rsc, csc); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* C = (scomplex*) bli_obj_buffer( c_orig ); + scomplex* CC = (scomplex*) bli_obj_buffer( c ); + libblis_icsyrk_check(uploc, transa, M, K, Alpha, + A, rsa, csa, Beta, C, rsc, csc); + resid = computediffim(M, M, CC, C, rsc, csc); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* C = (dcomplex*) bli_obj_buffer( c_orig ); + dcomplex* CC = (dcomplex*) bli_obj_buffer( c ); + libblis_icsyrk_check(uploc, transa, M, K, Alpha, + A, rsa, csa, Beta, C, rsc, csc); + resid = computediffim(M, M, CC, C, rsc, csc); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + +template +double libblis_check_nan_real( dim_t rsc, dim_t csc, obj_t* c ) { + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + double resid = 0.0; + T* C = (T*) bli_obj_buffer( c ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = C[ i*rsc + j*csc ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rsc, dim_t csc, obj_t* c ) { + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + dim_t i,j; + double resid = 0.0; + U* C = (U*) bli_obj_buffer( c ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = C[ i*rsc + j*csc ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_syrk(obj_t* c, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_is_col_stored( c ) ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_trmm.cpp b/gtestsuite/src/ref_trmm.cpp new file mode 100644 index 000000000..485325037 --- /dev/null +++ b/gtestsuite/src/ref_trmm.cpp @@ -0,0 +1,651 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trmm.h" + +using namespace std; + +//* ========================================================================== +//*> TRMM performs one of the matrix-matrix operations +//*> B := alpha*op( A )*B, or B := alpha*B*op( A ) +//*> where alpha is a scalar, B is an m by n matrix, A is a unit, or +//*> non-unit, upper or lower triangular matrix and op( A ) is one of +//*> op( A ) = A or op( A ) = A**T or op( A ) = A**H. +//* ========================================================================== + +template +void libblis_itrmm_check(side_t side, uplo_t uplo, trans_t transa, + diag_t diag, dim_t M, dim_t N, T Alpha, T* A, dim_t rsa, dim_t csa, + T* B, dim_t rsb, dim_t csb) +{ + T tmp; + int i, j, k; + bool LSIDE, NOUNIT, UPPER, NOTRANSA; + + T ONE = 1.0; + T ZERO = 0.0; + + LSIDE = ( side == BLIS_LEFT ); + NOTRANSA = ( transa == BLIS_NO_TRANSPOSE ); + NOUNIT = ( diag == BLIS_NONUNIT_DIAG ); + UPPER = ( uplo == BLIS_UPPER ); + + if( M == 0 || N == 0 ) + return; + + if( Alpha == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = ZERO; + } + } + return; + } + + + if( LSIDE ) + { + if( NOTRANSA ) + { + //* Form B := alpha*A*B. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( k = 0 ; k < M ; k++ ) + { + if( B[k*rsb + j*csb] != ZERO ) + { + tmp = Alpha*B[k*rsb + j*csb]; + for( i = 0 ; i < k ; i++ ) + { + B[i*rsb + j*csb] = B[i*rsb + j*csb] + tmp*A[i*rsa + k*csa]; + } + if( NOUNIT ) + tmp = tmp*A[k*rsa + k*csa]; + B[k*rsb + j*csb] = tmp; + } + } + } + } + else + { + for( j = 0; j < N ; j++ ) + { + for( k = (M-1) ; k >= 0 ; k-- ) + { + if( B[k*rsb + j*csb] != ZERO ) + { + tmp = Alpha*B[k*rsb + j*csb]; + B[k*rsb + j*csb] = tmp; + if( NOUNIT ) + B[k*rsb + j*csb] = B[k*rsb + j*csb]*A[k*rsa + k*csa]; + for( i = (k+1) ; i < M ; i++ ) + { + B[i*rsb + j*csb] = B[i*rsb + j*csb] + (tmp * A[i*rsa + k*csa]); + } + } + } + } + } + } + else + { + //* Form B := alpha*A**T*B. + if( UPPER ) + { + for( j = 0; j < N ; j++ ) + { + for( i = (M-1) ; i >= 0 ; i-- ) + { + tmp = B[i*rsb + j*csb]; + if( NOUNIT ) + tmp = tmp*A[i*rsa + i*csa]; + for( k = 0 ; k < i ; k++ ) + { + tmp = tmp + A[k*rsa + i*csa]*B[k*rsb + j*csb]; + } + B[i*rsb + j*csb] = Alpha*tmp; + } + } + } + else + { + for( j = 0; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp = B[i*rsb + j*csb]; + if( NOUNIT ) + tmp = tmp*A[i*rsa + i*csa]; + for( k =(i+1) ; k < M ; k++ ) + { + tmp = tmp + A[k*rsa + i*csa]*B[k*rsb + j*csb]; + } + B[i*rsb + j*csb] = Alpha*tmp; + } + } + } + } + } + else + { + if( NOTRANSA ) + { + //* Form B := alpha*B*A. + if( UPPER ) + { + for( j = (N-1) ; j >= 0 ; j-- ) + { + tmp = Alpha; + if( NOUNIT ) + tmp = tmp*A[j*rsa + j*csa]; + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = tmp*B[i*rsb + j*csb]; + } + for( k = 0 ; k < j ; k++ ) + { + if( A[k*rsa + j*csa] != ZERO ) + { + tmp = Alpha*A[k*rsa + j*csa]; + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = B[i*rsb + j*csb] + tmp*B[i*rsb + k*csb]; + } + } + } + } + } + else + { + for( j = 0; j < N ; j++ ) + { + tmp = Alpha; + if( NOUNIT ) + tmp = tmp*A[j*rsa + j*csa]; + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = tmp*B[i*rsb + j*csb]; + } + for( k =(j+1) ; k < N ; k++ ) + { + if( A[k*rsa + j*csa] != ZERO ) + { + tmp = Alpha*A[k*rsa + j*csa]; + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = B[i*rsb + j*csb] + tmp*B[i*rsb + k*csb]; + } + } + } + } + } + } + else + { + //* Form B := alpha*B*A**T. + if( UPPER ) + { + for( k = 0 ; k < N ; k++ ) + { + for( j = 0 ; j < k ; j++ ) + { + if( A[j*rsa + k*csa] != ZERO ) + { + tmp = Alpha*A[j*rsa + k*csa]; + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = B[i*rsb + j*csb] + tmp*B[i*rsb + k*csb]; + } + } + } + tmp = Alpha; + if( NOUNIT ) + tmp = tmp*A[k*rsa + k*csa]; + if( tmp != ONE ) + { + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + k*csb] = tmp*B[i*rsb + k*csb]; + } + } + } + } + else + { + for( k = (N-1) ; k >= 0 ; k-- ) + { + for( j = (k+1) ; j < N ; j++ ) + { + if( A[j*rsa + k*csa] != ZERO ) + { + tmp = Alpha*A[j*rsa + k*csa]; + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = B[i*rsb + j*csb] + tmp*B[i*rsb + k*csb]; + } + } + } + tmp = Alpha; + if( NOUNIT ) + tmp = tmp*A[k*rsa + k*csa]; + if( tmp != ONE ) + { + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + k*csb] = tmp*B[i*rsb + k*csb]; + } + } + } + } + } + } + return; +} + +template +void libblis_ictrmm_check(side_t side, uplo_t uplo, trans_t transa, + diag_t diag, dim_t M, dim_t N, T Alpha, T* A, dim_t rsa, dim_t csa, + bool conja, T* B, dim_t rsb, dim_t csb) +{ + T tmp; + int i, j, k; + bool LSIDE, NOTRANSA, NOUNIT, UPPER; + + T ONE = { 1.0 , 0.0 }; + T ZERO = { 0.0 , 0.0 }; + + //* Test the input parameters. + LSIDE = ( side == BLIS_LEFT ); + NOTRANSA = ( transa == BLIS_NO_TRANSPOSE ); + NOUNIT = ( diag == BLIS_NONUNIT_DIAG ); + UPPER = ( uplo == BLIS_UPPER ); + + if( M == 0 || N == 0 ) + return; + + if( (Alpha.real == ZERO.real) || (Alpha.imag == ZERO.imag) ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = ZERO; + } + } + return; + } + + if( conja ) + { + dim_t dim; + if (LSIDE) dim = M; + else dim = N; + for( i = 0 ; i < dim ; i++ ) + { + for( j = 0 ; j < dim ; j++ ) + { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + if( LSIDE ) + { + if( NOTRANSA ) + { + //* Form B := alpha*A*B. + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( k = 0 ; k < M ; k++ ) + { + if( (B[k*rsb + j*csb].real != ZERO.real) || (B[k*rsb + j*csb].imag != ZERO.imag) ) + { + tmp = mulc(Alpha , B[k*rsb + j*csb]); + for( i = 0 ; i < k ; i++ ) + { + B[i*rsb + j*csb] = addc(B[i*rsb + j*csb] , mulc(tmp , A[i*rsa + k*csa])); + } + if( NOUNIT ) + tmp = mulc(tmp , A[k*rsa + k*csa]); + B[k*rsb + j*csb] = tmp; + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( k = (M-1) ; k >= 0 ; k-- ) + { + if( (B[k*rsb + j*csb].real != ZERO.real) || (B[k*rsb + j*csb].imag != ZERO.imag) ) + { + tmp = mulc(Alpha , B[k*rsb + j*csb]); + B[k*rsb + j*csb] = tmp; + if( NOUNIT ) + B[k*rsb + j*csb] = mulc(B[k*rsb + j*csb] , A[k*rsa + k*csa]); + for( i = (k+1) ; i < M ; i++ ) + { + B[i*rsb + j*csb] = addc(B[i*rsb + j*csb] , mulc(tmp , A[i*rsa + k*csa])); + } + } + } + } + } + } + else + { + //* Form B := alpha*A**T*B or B := alpha*A**H*B. + if( UPPER ) + { + for( j = 0; j < N ; j++ ) + { + for( i = (M-1) ; i >= 0 ; i-- ) + { + tmp = B[i*rsb + j*csb]; + if( NOUNIT ) + tmp = mulc(tmp , A[i*rsa + i*csa]); + for( k = 0 ; k < i ; k++ ) + { + tmp = addc(tmp , mulc(A[k*rsa + i*csa] , B[k*rsb + j*csb])); + } + B[i*rsb + j*csb] = mulc(Alpha , tmp); + } + } + } + else + { + for( j = 0; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp = B[i*rsb + j*csb]; + if( NOUNIT ) + tmp = mulc(tmp , A[i*rsa + i*csa]); + for( k =(i+1) ; k < M ; k++ ) + { + tmp = addc(tmp , mulc(A[k*rsa + i*csa] , B[k*rsb + j*csb])); + } + B[i*rsb + j*csb] = mulc(Alpha , tmp); + } + } + } + } + } + else + { + if( NOTRANSA ) + { + //* Form B := alpha*B*A. + if( UPPER ) + { + for( j = (N-1) ; j >= 0 ; j-- ) + { + tmp = Alpha; + if( NOUNIT ) + tmp = mulc(tmp , A[j*rsa + j*csa]); + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = mulc(tmp , B[i*rsb + j*csb]); + } + for( k = 0 ; k < j ; k++ ) + { + if( (A[k*rsa + j*csa].real != ZERO.real)||(A[k*rsa + j*csa].imag != ZERO.imag) ) + { + tmp = mulc(Alpha , A[k*rsa + j*csa]); + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = addc(B[i*rsb + j*csb] , mulc(tmp , B[i*rsb + k*csb])); + } + } + } + } + } + else + { + for( j = 0; j < N ; j++ ) + { + tmp = Alpha; + if( NOUNIT ) + tmp = mulc(tmp , A[j*rsa + j*csa]); + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = mulc(tmp , B[i*rsb + j*csb]); + } + for( k =(j+1) ; k < N ; k++ ) + { + if( (A[k*rsa + j*csa].real != ZERO.real)||(A[k*rsa + j*csa].imag != ZERO.imag) ) + { + tmp = mulc(Alpha , A[k*rsa + j*csa]); + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = addc(B[i*rsb + j*csb] , mulc(tmp , B[i*rsb + k*csb])); + } + } + } + } + } + } + else + { + //* Form B := alpha*B*A**T or B := alpha*B*A**H. + if( UPPER ) + { + for( k = 0 ; k < N ; k++ ) + { + for( j = 0 ; j < k ; j++ ) + { + if( (A[j*rsa + k*csa].real != ZERO.real)||(A[j*rsa + k*csa].imag != ZERO.imag) ) + { + tmp = mulc(Alpha , A[j*rsa + k*csa]); + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = addc(B[i*rsb + j*csb] , mulc(tmp , B[i*rsb + k*csb])); + } + } + } + tmp = Alpha; + if( NOUNIT ) + tmp = mulc(tmp , A[k*rsa + k*csa]); + if( (tmp.real != ONE.real) || (tmp.imag != ONE.imag) ) + { + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + k*csb] = mulc(tmp , B[i*rsb + k*csb]); + } + } + } + } + else + { + for( k = (N-1) ; k >= 0 ; k-- ) + { + for( j = (k+1) ; j < N ; j++ ) + { + if( (A[j*rsa + k*csa].real != ZERO.real)||(A[j*rsa + k*csa].imag != ZERO.imag) ) + { + tmp = mulc(Alpha , A[j*rsa + k*csa]); + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + j*csb] = addc(B[i*rsb + j*csb] , mulc(tmp , B[i*rsb + k*csb])); + } + } + } + tmp = Alpha; + if( NOUNIT ) + tmp = mulc(tmp , A[k*rsa + k*csa]); + if( (tmp.real != ONE.real) || (tmp.imag != ONE.imag) ) + { + for( i = 0 ; i < M ; i++ ) + { + B[i*rsb + k*csb] = mulc(tmp , B[i*rsb + k*csb]); + } + } + } + } + } + } + return; +} + +double libblis_test_itrmm_check( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig, + num_t dt +){ + dim_t M = bli_obj_length( b_orig ); + dim_t N = bli_obj_width( b_orig ); + uplo_t uploa = bli_obj_uplo( a ); + trans_t transa = bli_obj_onlytrans_status( a ); + bool conja = bli_obj_has_conj( a ); + diag_t diaga = bli_obj_diag( a ); + dim_t rsa, csa; + dim_t rsb, csb; + double resid = 0.0; + + rsa = bli_obj_row_stride( a ) ; + csa = bli_obj_col_stride( a ) ; + rsb = bli_obj_row_stride( b ) ; + csb = bli_obj_col_stride( b ) ; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* B = (float*) bli_obj_buffer( b_orig ); + float* BB = (float*) bli_obj_buffer( b ); + libblis_itrmm_check(side, uploa, transa, + diaga, M, N, *Alpha, A, rsa, csa, B, rsb, csb ); + resid = computediffrm(M, N, BB, B, rsb, csb); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* B = (double*) bli_obj_buffer( b_orig ); + double* BB = (double*) bli_obj_buffer( b ); + libblis_itrmm_check(side, uploa, transa, + diaga, M, N, *Alpha, A, rsa, csa, B, rsb, csb ); + resid = computediffrm(M, N, BB, B, rsb, csb); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* B = (scomplex*) bli_obj_buffer( b_orig ); + scomplex* BB = (scomplex*) bli_obj_buffer( b ); + libblis_ictrmm_check(side, uploa, transa, + diaga, M, N, *Alpha, A, rsa, csa, conja, B, rsb, csb ); + resid = computediffim(M, N, BB, B, rsb, csb); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* B = (dcomplex*) bli_obj_buffer( b_orig ); + dcomplex* BB = (dcomplex*) bli_obj_buffer( b ); + libblis_ictrmm_check(side, uploa, transa, + diaga, M, N, *Alpha, A, rsa, csa, conja, B, rsb, csb ); + resid = computediffim(M, N, BB, B, rsb, csb); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +template +double libblis_check_nan_real( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_trmm(obj_t* b, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( b ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( b ); + } else { + rsc = bli_obj_row_stride( b ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, b ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, b ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, b ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, b ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_trmm3.cpp b/gtestsuite/src/ref_trmm3.cpp new file mode 100644 index 000000000..42e04c479 --- /dev/null +++ b/gtestsuite/src/ref_trmm3.cpp @@ -0,0 +1,551 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trmm3.h" + +using namespace std; + +//* ========================================================================== +//*> TRMM performs one of the matrix-matrix operations +//*> C := beta * C_orig + alpha * transa(A) * transb(B) +//*> or +//*> C := beta * C_orig + alpha * transb(B) * transa(A) +//*> where alpha and beta are scalars, A is an triangular matrix and B and +//*> C are m by n matrices. +//* ========================================================================== + +template +void libblis_itrmm3_check(side_t side, uplo_t uplo, diag_t diaga, + dim_t M, dim_t N, T Alpha, T* A, dim_t rsa, dim_t csa, + T* B, dim_t rsb, dim_t csb, T Beta, T* C, dim_t rsc, dim_t csc ) +{ + T ONE = 1.0; + T ZERO = 0.0; + T tmp; + bool LSIDE, UPPER, UNITDA; + dim_t i, j, k; + + //* Test the input parameters. + LSIDE = ( side == BLIS_LEFT ); + UPPER = ( uplo == BLIS_UPPER ); + UNITDA = ( diaga == BLIS_UNIT_DIAG ); + + if( (M == 0 || N == 0) || ( Alpha == ZERO && Beta == ONE ) ) + return; + + //* And when Alpha.eq.zero. + if( Alpha == ZERO ) + { + if( Beta == ZERO ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc]; + } + } + } + return; + } + + if( UNITDA ) + { + dim_t dim; + if( LSIDE ) dim = M; + else dim = N; + for( i = 0 ; i < dim ; i++ ) + { + for( j = 0 ; j < dim ; j++ ) + { + if( i==j ) + A[i*rsa + j*csa] = ONE ; + } + } + } + + //* Start the operations. + if( LSIDE ) + { + //* Form C := beta * C_orig + alpha * transa(A) * transb(B) + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp = ZERO; + for( k = i ; k < M ; k++ ) + { + tmp += A[i*rsa + k*csa] * B[k*rsb + j*csb]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + Alpha*tmp; + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp = ZERO; + for( k = 0 ; k <= i ; k++ ) + { + tmp += A[i*rsa + k*csa] * B[k*rsb + j*csb]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + Alpha*tmp; + } + } + } + } + } + else + { + //* C := beta * C_orig + alpha * transb(B) * transa(A) + if( UPPER ) + { + for( i = 0 ; i < M ; i++ ) + { + for( j = 0 ; j < N ; j++ ) + { + tmp = ZERO ; + for( k = 0 ; k <= j ; k++ ) + { + tmp += B[i*rsb + k*csb]* A[k*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + Alpha*tmp; + } + } + } + } + else + { + for( i = 0 ; i < M ; i++ ) + { + for( j = 0 ; j < N ; j++ ) + { + tmp = ZERO ; + for( k = j ; k < N ; k++ ) + { + tmp += B[i*rsb + k*csb]* A[k*rsa + j*csa]; + } + if( Beta == ZERO ) + { + C[i*rsc + j*csc] = Alpha*tmp; + } + else + { + C[i*rsc + j*csc] = Beta*C[i*rsc + j*csc] + Alpha*tmp; + } + } + } + } + } + return; +} + +template +void libblis_ictrmm3_check(side_t side, uplo_t uplo, diag_t diaga, dim_t M, + dim_t N, T Alpha, T* A, dim_t rsa, dim_t csa, bool conja, T* B, dim_t rsb, + dim_t csb, bool conjb, T Beta, T* C, dim_t rsc, dim_t csc ) +{ + T ONE = {1.0 , 0.0}; + T ZERO = {0.0 , 0.0}; + T tmp; + bool LSIDE, UPPER, UNITDA; + dim_t i, j, k; + + //* Test the input parameters. + LSIDE = ( side == BLIS_LEFT ); + UPPER = ( uplo == BLIS_UPPER ); + UNITDA = ( diaga == BLIS_UNIT_DIAG ); + + if( (M == 0 || N == 0) || ( Alpha.real == ZERO.real && Beta.real == ONE.real ) ) + return; + + if( conja ) + { + dim_t dim; + if( LSIDE ) dim = M; + else dim = N; + for( i = 0 ; i < dim ; i++ ) + { + for( j = 0 ; j < dim ; j++ ) + { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + if( conjb ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + B[i*rsc + j*csc] = conjugate(B[i*rsc + j*csc]); + } + } + } + + //* And when Alpha.eq.zero. + if( Alpha.real == ZERO.real ) + { + if( Beta.real == ZERO.real ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = ZERO; + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + C[i*rsc + j*csc] = mulc(Beta , C[i*rsc + j*csc]); + } + } + } + return; + } + + if( UNITDA ) + { + dim_t dim; + if( LSIDE ) dim = M; + else dim = N; + for( i = 0 ; i < dim ; i++ ) + { + for( j = 0 ; j < dim ; j++ ) + { + if( i==j ) + A[i*rsa + j*csa] = ONE ; + } + } + } + + //* Start the operations. + if( LSIDE ) + { + //* Form C := beta * C_orig + alpha * transa(A) * transb(B) + if( UPPER ) + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp = ZERO; + for( k = i ; k < M ; k++ ) + { + tmp = addc(tmp , mulc(A[i*rsa + k*csa] , B[k*rsb + j*csb])); + } + if( (Beta.real == ZERO.real) || (Beta.imag == ZERO.imag) ) + { + C[i*rsc + j*csc] = mulc(Alpha , tmp); + } + else + { + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , mulc(Alpha , tmp)); + } + } + } + } + else + { + for( j = 0 ; j < N ; j++ ) + { + for( i = 0 ; i < M ; i++ ) + { + tmp = ZERO; + for( k = 0 ; k <= i ; k++ ) + { + tmp = addc(tmp , mulc(A[i*rsa + k*csa] , B[k*rsb + j*csb])); + } + if( (Beta.real == ZERO.real) || (Beta.imag == ZERO.imag) ) + { + C[i*rsc + j*csc] = mulc(Alpha , tmp); + } + else + { + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , mulc(Alpha , tmp)); + } + } + } + } + } + else + { + //* C := beta * C_orig + alpha * transb(B) * transa(A) + if( UPPER ) + { + for( i = 0 ; i < M ; i++ ) + { + for( j = 0 ; j < N ; j++ ) + { + tmp = ZERO ; + for( k = 0 ; k <= j ; k++ ) + { + tmp = addc(tmp , mulc(B[i*rsb + k*csb] , A[k*rsa + j*csa])); + } + if( (Beta.real == ZERO.real) || (Beta.imag == ZERO.imag) ) + { + C[i*rsc + j*csc] = mulc(Alpha , tmp); + } + else + { + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , mulc(Alpha , tmp)); + } + } + } + } + else + { + for( i = 0 ; i < M ; i++ ) + { + for( j = 0 ; j < N ; j++ ) + { + tmp = ZERO ; + for( k = j ; k < N ; k++ ) + { + tmp = addc(tmp , mulc(B[i*rsb + k*csb] , A[k*rsa + j*csa])); + } + if( (Beta.real == ZERO.real) || (Beta.imag == ZERO.imag) ) + { + C[i*rsc + j*csc] = mulc(Alpha , tmp); + } + else + { + C[i*rsc + j*csc] = addc(mulc(Beta , C[i*rsc + j*csc]) , mulc(Alpha , tmp)); + } + } + } + } + } + return; +} + +double libblis_test_itrmm3_check + ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ) +{ + + num_t dt = bli_obj_dt( a ); + uplo_t uploa = bli_obj_uplo( a ); + diag_t diaga = bli_obj_diag( a ); + dim_t M = bli_obj_length( c ); + dim_t N = bli_obj_width( c ); + bool conja = bli_obj_has_conj( a ); + bool conjb = bli_obj_has_conj( b ); + trans_t transa = bli_obj_onlytrans_status( a ); + trans_t transb = bli_obj_onlytrans_status( b ); + dim_t rsa, csa; + dim_t rsb, csb; + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( c ) == 1 ) + { + rsa = transa ? bli_obj_col_stride( a ) : bli_obj_row_stride( a ) ; + csa = transa ? bli_obj_row_stride( a ) : bli_obj_col_stride( a ) ; + rsb = transb ? bli_obj_col_stride( b ) : bli_obj_row_stride( b ) ; + csb = transb ? bli_obj_row_stride( b ) : bli_obj_col_stride( b ) ; + rsc = 1; + csc = bli_obj_col_stride( c_orig ); + } + else + { + rsa = transa ? bli_obj_col_stride( a ) : bli_obj_row_stride( a ) ; + csa = transa ? bli_obj_row_stride( a ) : bli_obj_col_stride( a ) ; + rsb = transb ? bli_obj_col_stride( b ) : bli_obj_row_stride( b ) ; + csb = transb ? bli_obj_row_stride( b ) : bli_obj_col_stride( b ) ; + rsc = bli_obj_row_stride( c_orig ); + csc = 1 ; + } + + if( transa ) { + if( bli_obj_is_upper_or_lower( a ) ) { + bli_obj_toggle_uplo( a ); + } + uploa = bli_obj_uplo( a ); + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* B = (float*) bli_obj_buffer( b ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* C = (float*) bli_obj_buffer( c_orig ); + float* CC = (float*) bli_obj_buffer( c ); + libblis_itrmm3_check(side, uploa, diaga, M, N, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, N, CC, C, rsc, csc); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* B = (double*) bli_obj_buffer( b ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* C = (double*) bli_obj_buffer( c_orig ); + double* CC = (double*) bli_obj_buffer( c ); + libblis_itrmm3_check(side, uploa, diaga, M, N, *Alpha, + A, rsa, csa, B, rsb, csb, *Beta, C, rsc, csc ); + resid = computediffrm(M, N, CC, C, rsc, csc); + } + break; + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* B = (scomplex*) bli_obj_buffer( b ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* C = (scomplex*) bli_obj_buffer( c_orig ); + scomplex* CC = (scomplex*) bli_obj_buffer( c ); + libblis_ictrmm3_check(side, uploa, diaga, M, N, + *Alpha, A, rsa, csa, conja, B, rsb, csb, conjb, *Beta, C, rsc, csc ); + resid = computediffim(M, N, CC, C, rsc, csc); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* B = (dcomplex*) bli_obj_buffer( b ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* C = (dcomplex*) bli_obj_buffer( c_orig ); + dcomplex* CC = (dcomplex*) bli_obj_buffer( c ); + libblis_ictrmm3_check(side, uploa, diaga, M, N, + *Alpha, A, rsa, csa, conja, B, rsb, csb, conjb, *Beta, C, rsc, csc ); + resid = computediffim(M, N, CC, C, rsc, csc); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +template +double libblis_check_nan_real( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_trmm3(obj_t* c, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( c ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( c ); + } else { + rsc = bli_obj_row_stride( c ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, c ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, c ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/ref_trmv.cpp b/gtestsuite/src/ref_trmv.cpp new file mode 100644 index 000000000..33a89b135 --- /dev/null +++ b/gtestsuite/src/ref_trmv.cpp @@ -0,0 +1,278 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trmv.h" + +using namespace std; + +//* ========================================================================== +//*> TRMV performs one of the matrix-vector operations +//*> x := alpha * transa(A) * x +//*> where x is an n element vector and A is an n by n unit, or non-unit, +//*> upper or lower triangular matrix. +//* ========================================================================== + +template +void libblis_itrmv_check(uplo_t uploa, trans_t transa, diag_t diaga, + T* alpha, dim_t N, T* A, dim_t rsa, dim_t csa, T* X, dim_t incx){ + + T Alpha = *alpha; + T tmp; + int i, ix, j, jx, kx; + bool NOTRANS, NOUNIT; + + if (N == 0) + return; + + NOTRANS = (transa == BLIS_NO_TRANSPOSE); + NOUNIT = (diaga == BLIS_NONUNIT_DIAG); + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if(NOTRANS) { + //* Form x := A*x. + if(uploa == BLIS_UPPER){ + jx = kx; + for(j = 0 ; j < N ; j++){ + tmp = Alpha*X[jx]; + ix = kx; + for(i = 0 ; i < j ; i++) { + X[ix] = X[ix] + tmp*A[i*rsa + j*csa]; + ix = ix + incx; + } + if (NOUNIT) + tmp = tmp*A[j*rsa + j*csa]; + + X[jx] = tmp; + jx = jx + incx; + } + } + else{ + kx = kx + (N - 1)*incx; + jx = kx; + for(j = (N-1) ; j >= 0 ; j--){ + tmp = Alpha*X[jx]; + ix = kx; + for(i = (N-1) ; i > j ; i--){ + X[ix] = X[ix] + tmp*A[i*rsa + j*csa]; + ix = ix - incx; + } + if(NOUNIT) + tmp = tmp*A[j*rsa + j*csa]; + + X[jx] = tmp; + jx = jx - incx; + } + } + } + else { + //* Form x := A**T*x. + if(uploa == BLIS_UPPER){ + jx = kx + (N - 1)*incx; + for(j = (N-1) ; j >= 0 ; j--){ + tmp = X[jx]; + ix = jx; + if(NOUNIT) + tmp = tmp*A[j*rsa + j*csa]; + for(i = (j-1) ; i >= 0 ; i--) { + ix = ix - incx; + tmp = tmp + A[i*rsa + j*csa]*X[ix]; + } + X[jx] = Alpha*tmp; + jx = jx - incx; + } + } + else{ + jx = kx; + for(j = 0 ; j < N ; j++){ + tmp = X[jx]; + ix = jx; + if (NOUNIT) + tmp = tmp*A[j*rsa + j*csa]; + for(i = (j+1) ; i < N ; i++){ + ix = ix + incx; + tmp = tmp + X[ix]*A[i*rsa + j*csa]; + } + X[jx] = Alpha*tmp; + jx = jx + incx; + } + } + } + return; +} + +template +void libblis_ictrmv_check(uplo_t uploa, trans_t transa, diag_t diaga, +T* alpha, dim_t N, T* A, dim_t rsa, dim_t csa, bool conja, T* X, dim_t incx){ + + T Alpha = *alpha; + T tmp; + int i, ix, j, jx, kx; + bool NOTRANS, NOUNIT; + + if (N == 0) + return; + + NOTRANS = (transa == BLIS_NO_TRANSPOSE); + NOUNIT = (diaga == BLIS_NONUNIT_DIAG); + + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + if(conja) { + for(i = 0 ; i < N ; i++) { + for(j = 0 ; j < N ; j++) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + if(NOTRANS){ + //* Form x := A*x. + if(uploa == BLIS_UPPER){ + jx = kx; + for(j = 0 ; j < N ; j++){ + tmp = mulc(Alpha , X[jx]); + ix = kx; + for(i = 0 ; i < j ; i++) { + X[ix] = addc(X[ix] , mulc(tmp , A[i*rsa + j*csa])); + ix = ix + incx; + } + if (NOUNIT) + tmp = mulc(tmp , A[j*rsa + j*csa]); + + X[jx] = tmp; + jx = jx + incx; + } + } + else{ + kx = kx + (N - 1)*incx; + jx = kx; + for(j = (N-1) ; j >= 0 ; j--){ + tmp = mulc(Alpha , X[jx]); + ix = kx; + for(i = (N-1) ; i > j ; i--){ + X[ix] = addc(X[ix] , mulc(tmp , A[i*rsa + j*csa])); + ix = ix - incx; + } + if(NOUNIT) + tmp = mulc(tmp , A[j*rsa + j*csa]); + + X[jx] = tmp; + jx = jx - incx; + } + } + } + else { + //* Form x := A**T*x. + if(uploa == BLIS_UPPER){ + jx = kx + (N - 1)*incx; + for(j = (N-1) ; j >= 0 ; j--){ + tmp = X[jx]; + ix = jx; + if(NOUNIT) + tmp = mulc(tmp , A[j*rsa + j*csa]); + for(i = (j-1) ; i >= 0 ; i--) { + ix = ix - incx; + tmp = addc(tmp , mulc(A[i*rsa + j*csa] , X[ix])); + } + X[jx] = mulc(Alpha , tmp); + jx = jx - incx; + } + } + else{ + jx = kx; + for(j = 0 ; j < N ; j++){ + tmp = X[jx]; + ix = jx; + if (NOUNIT) + tmp = mulc(tmp , A[j*rsa + j*csa]); + for(i = (j+1) ; i < N ; i++){ + ix = ix + incx; + tmp = addc(tmp , mulc(X[ix] , A[i*rsa + j*csa])); + } + X[jx] = mulc(Alpha , tmp); + jx = jx + incx; + } + } + } + return; +} + +double libblis_test_itrmv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig +){ + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_length( a ); + dim_t incx = bli_obj_vector_inc( x ); + dim_t rsa = bli_obj_row_stride( a ); + dim_t csa = bli_obj_col_stride( a ); + uplo_t uploa = bli_obj_uplo( a ); + bool conja = bli_obj_has_conj( a ); + trans_t transa = bli_obj_onlytrans_status( a ); + diag_t diaga = bli_obj_diag( a ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x_orig ); + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* XX = (float*) bli_obj_buffer( x ); + libblis_itrmv_check(uploa, transa, diaga, Alpha, + M, A, rsa, csa, X, incx); + resid = computediffrv(M, incx, XX, X); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x_orig ); + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* XX = (double*) bli_obj_buffer( x ); + libblis_itrmv_check(uploa, transa, diaga, Alpha, + M, A, rsa, csa, X, incx); + resid = computediffrv(M, incx, XX, X); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x_orig ); + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* XX = (scomplex*) bli_obj_buffer( x ); + libblis_ictrmv_check(uploa, transa, diaga, Alpha, + M, A, rsa, csa, conja, X, incx); + resid = computediffiv(M, incx, XX, X); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x_orig ); + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* XX = (dcomplex*) bli_obj_buffer( x ); + libblis_ictrmv_check(uploa, transa, diaga, Alpha, + M, A, rsa, csa, conja, X, incx); + resid = computediffiv(M, incx, XX, X); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + diff --git a/gtestsuite/src/ref_trsm.cpp b/gtestsuite/src/ref_trsm.cpp new file mode 100644 index 000000000..81077932c --- /dev/null +++ b/gtestsuite/src/ref_trsm.cpp @@ -0,0 +1,534 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trsm.h" + +using namespace std; + +//* ========================================================================== +//*> TRSM solves one of the matrix equations +//*> op( A )*X = alpha*B, or X*op( A ) = alpha*B, +//*> where alpha is a scalar, X and B are m by n matrices, A is a unit, or +//*> non-unit, upper or lower triangular matrix and op( A ) is one of +//*> op( A ) = A or op( A ) = A**T. +//*> The matrix X is overwritten on B. +//* ========================================================================== + +template +void libblis_ictrsm_check(side_t side, uplo_t uplo, trans_t transa, + diag_t diaga, dim_t M, dim_t N, T Alpha, T* A, dim_t rsa, dim_t csa, + bool conja, T* B, dim_t rsb, dim_t csb){ + + T tmp; + dim_t i, j, k; + bool LSIDE, NOUNIT, UPPER, NOTRANS; + T ONE, ZERO; + ONE = {1.0 , 0.0}; + ZERO = {0.0 , 0.0}; + + //* Test the input parameters. + LSIDE = (side == BLIS_LEFT); + NOTRANS = (transa == BLIS_NO_TRANSPOSE) || (transa == BLIS_CONJ_NO_TRANSPOSE); + NOUNIT = (diaga == BLIS_NONUNIT_DIAG); + UPPER = (uplo == BLIS_UPPER); + + //* Quick return if possible. + if ((M == 0) || (N == 0) ) + return; + + //* And when alpha.eq.zero. + if ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)) { + for(i = 0; i < M ; i++) { + for(j = 0; j < N ; j++) { + B[i*rsb+ j*csb] = ZERO; + } + } + return; + } + + if(conja) { + dim_t dim; + if (LSIDE) dim = M; + else dim = N; + for( i = 0 ; i < dim ; i++ ) { + for( j = 0 ; j < dim ; j++ ) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + if((Alpha.real != ONE.real)&&(Alpha.imag != ONE.imag)){ + for(i = 0; i < M; i++) { + for(j = 0 ; j < N ; j++) { + B[i*rsb + j*csb] = mulc(Alpha , B[i*rsb + j*csb]); + } + } + } + + //* Start the operations. + if (LSIDE) { + if (NOTRANS) { + //* Form B := alpha*inv( A )*B. + if (UPPER) { /* AuXB : LUN */ + for(j = 0 ; j < N ; j++) { + for(k = M; k-- ; ) { + if((B[k*rsb + j*csb].real != ZERO.real) || (B[k*rsb + j*csb].imag != ZERO.imag)) { + if (NOUNIT) B[k*rsb + j*csb] = divc(B[k*rsb + j*csb] , A[k*rsa + k*csa]); + for(i = 0 ; i < k ; i++) { + B[i*rsb + j*csb] = subc(B[i*rsb + j*csb] , mulc(B[k*rsb + j*csb] , A[i*rsa + k*csa])); + } + } + } + } + } + else { + for(j = 0 ; j < N ; j++) { /* AlXB : LLN */ + for(k = 0 ; k < M ; k++) { + if ((B[k*rsb + j*csb].real != ZERO.real) || (B[k*rsb + j*csb].imag != ZERO.imag)) { + if (NOUNIT) B[k*rsb + j*csb] = divc(B[k*rsb + j*csb] , A[k*rsa + k*csa]); + for(i=(k+1) ; i < M ; i++) { + B[i*rsb + j*csb] = subc(B[i*rsb + j*csb] , mulc(B[k*rsb + j*csb] , A[i*rsa + k*csa])); + } + } + } + } + } + } + else { + //* Form B := alpha*inv( A**T )*B. + if (UPPER) { + for(j = 0 ; j < N ; j++) { /* AutXB : LUT */ + for(i = 0 ; i < M ; i++) { + tmp = B[i*rsb + j*csb]; + for(k = 0 ; k < i ; k++) { + tmp = subc(tmp , mulc(A[k*rsa + i*csa] , B[k*rsb + j*csb])); + } + if (NOUNIT) tmp = divc(tmp , A[i*rsa + i*csa]); + B[i*rsb + j*csb] = tmp; + } + } + } + else { + for(j = 0 ; j < N ; j++) { /* AltXB : LLT */ + for(i = M ; i-- ;) { + tmp = B[i*rsb + j*csb]; + for(k = (i+1) ; k < M ; k++) { + tmp = subc(tmp , mulc(A[k*rsa + i*csa] , B[k*rsb + j*csb])); + } + if (NOUNIT) tmp = divc(tmp , A[i*rsa + i*csa]); + B[i*rsb + j*csb] = tmp; + } + } + } + } + } + else { + if(NOTRANS) { + //* Form B := alpha*B*inv( A ). + if (UPPER) { + for(j = 0 ; j < N ; j++) { /* XAuB : RUN */ + for(k = 0 ; k < j ; k++) { + if ((A[k*rsa + j*csa].real != ZERO.real)||(A[k*rsa + j*csa].imag != ZERO.imag)) { + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = subc(B[i*rsb + j*csb] , mulc(A[k*rsa + j*csa] , B[i*rsb + k*csb])); + } + } + } + if (NOUNIT) { + tmp = divc(ONE , A[j*rsa + j*csa]); + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = mulc(tmp , B[i*rsb + j*csb]); + } + } + } + } + else { + for(j = N; j-- ; ) { /* XAlB : RLN */ + for(k = (j+1) ; k < N ; k++) { + if((A[k*rsa + j*csa].real != ZERO.real)||(A[k*rsa + j*csa].imag != ZERO.imag)) { + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = subc(B[i*rsb + j*csb] , mulc(A[k*rsa + j*csa] , B[i*rsb + k*csb])); + } + } + } + if (NOUNIT) { + tmp = divc(ONE , A[j*rsa + j*csa]); + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = mulc(tmp , B[i*rsb + j*csb]); + } + } + } + } + } + else { + //* Form B := alpha*B*inv( A**T ). + if (UPPER) { /* XAutB : RUT */ + for(k = N ; k-- ; ) { + if (NOUNIT) { + tmp = divc(ONE , A[k*rsa + k*csa]); + for(i = 0 ; i < M ; i++) { + B[i*rsb + k*csb] = mulc(tmp , B[i*rsb + k*csb]); + } + } + for(j = 0 ; j < k; j++) { + if((A[j*rsa + k*csa].real != ZERO.real)||(A[j*rsa + k*csa].imag != ZERO.imag)) { + tmp = A[j*rsa + k*csa]; + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = subc(B[i*rsb + j*csb] , mulc(tmp , B[i*rsb + k*csb])); + } + } + } + } + } + else { /* XAltB : RLT */ + for(k = 0 ; k < N; k++) { + if (NOUNIT) { + tmp = divc(ONE , A[k*rsa + k*csa]); + for(i = 0 ; i < M ; i++) { + B[i*rsb + k*csb] = mulc(tmp , B[i*rsb + k*csb]); + } + } + for(j = (k+1) ; j < N ; j++) { + if((A[j*rsa + k*csa].real != ZERO.real)||(A[j*rsa + k*csa].imag != ZERO.imag)) { + tmp = A[j*rsa + k*csa]; + for(i = 0 ; i < M; i++) { + B[i*rsb + j*csb] = subc(B[i*rsb + j*csb] , mulc(tmp , B[i*rsb + k*csb])); + } + } + } + } + } + } + } + return; +} + +template +void libblis_itrsm_check(side_t side, uplo_t uploa, trans_t transa, + diag_t diaga, dim_t M, dim_t N, T Alpha, T* A, dim_t rsa, dim_t csa, + T* B, dim_t rsb, dim_t csb) { + + T tmp; + dim_t i, j, k; + bool LSIDE, UPPER; + bool NOTRANS, NOUNIT; + T ONE = 1.0; + T ZERO = 0.0; + + LSIDE = (side == BLIS_LEFT); + NOTRANS = (transa == BLIS_NO_TRANSPOSE) || (transa == BLIS_CONJ_NO_TRANSPOSE); + NOUNIT = (diaga == BLIS_NONUNIT_DIAG); + UPPER = (uploa == BLIS_UPPER); + + if((M == 0) || (N == 0)) + return; + + if (Alpha == ZERO) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N; j++) { + B[i*rsb + j*csb] = ZERO; + } + } + return; + } + + if (Alpha != ONE) { + for(i = 0; i < M; i++) { + for(j = 0 ; j < N ; j++) { + B[i*rsb + j*csb] = Alpha*B[i*rsb + j*csb]; + } + } + } + + //* Start the operations. + if (LSIDE) { + if (NOTRANS) { + //* Form B := alpha*inv( A )*B. + if (UPPER) { /* AuXB : LUN */ + for(j = 0 ; j < N ; j++) { + for(k = M; k-- ; ) { + if (B[k*rsb + j*csb] != ZERO) { + if (NOUNIT) B[k*rsb + j*csb] = B[k*rsb + j*csb]/A[k*rsa + k*csa]; + for(i = 0 ; i < k ; i++) { + B[i*rsb + j*csb] = B[i*rsb + j*csb] - B[k*rsb + j*csb]*A[i*rsa + k*csa]; + } + } + } + } + } + else { + for(j = 0 ; j < N ; j++) { /* AlXB : LLN */ + for(k = 0 ; k < M ; k++) { + if (B[k*rsb + j*csb] != ZERO) { + if (NOUNIT) B[k*rsb + j*csb] = B[k*rsb + j*csb]/A[k*rsa + k*csa]; + for(i=(k+1) ; i < M ; i++) { + B[i*rsb + j*csb] = B[i*rsb + j*csb] - (B[k*rsb + j*csb]*A[i*rsa + k*csa]); + } + } + } + } + } + } + else { + //* Form B := alpha*inv( A**T )*B. + if (UPPER) { + for(j = 0 ; j < N ; j++) { /* AutXB : LUT */ + for(i = 0 ; i < M ; i++) { + tmp = B[i*rsb + j*csb]; + for(k = 0 ; k < i ; k++) { + tmp = tmp - A[k*rsa + i*csa]*B[k*rsb + j*csb]; + } + if (NOUNIT) tmp = tmp/A[i*rsa + i*csa]; + B[i*rsb + j*csb] = tmp; + } + } + } + else { + for(j = 0 ; j < N ; j++) { /* AltXB : LLT */ + for(i = M ; i-- ;) { + tmp = B[i*rsb + j*csb]; + for(k = (i+1) ; k < M ; k++) { + tmp = tmp - A[k*rsa + i*csa]*B[k*rsb + j*csb]; + } + if (NOUNIT) tmp = tmp/A[i*rsa + i*csa]; + B[i*rsb + j*csb] = tmp; + } + } + } + } + } + else { + if(NOTRANS) { + //* Form B := alpha*B*inv( A ). + if (UPPER) { + for(j = 0 ; j < N ; j++) { /* XAuB : RUN */ + for(k = 0 ; k < j ; k++) { + if (A[k*rsa + j*csa] != ZERO) { + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = B[i*rsb + j*csb] - A[k*rsa + j*csa]*B[i*rsb + k*csb]; + } + } + } + if (NOUNIT) { + tmp = ONE/A[j*rsa + j*csa]; + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = tmp*B[i*rsb + j*csb]; + } + } + } + } + else { + for(j = N; j-- ; ) { /* XAlB : RLN */ + for(k = (j+1) ; k < N ; k++) { + if (A[k*rsa + j*csa] != ZERO) { + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = B[i*rsb + j*csb] - A[k*rsa + j*csa]*B[i*rsb + k*csb]; + } + } + } + if (NOUNIT) { + tmp = ONE/A[j*rsa + j*csa]; + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = tmp*B[i*rsb + j*csb]; + } + } + } + } + } + else { + //* Form B := alpha*B*inv( A**T ). + if (UPPER) { /* XAutB : RUT */ + for(k = N ; k-- ; ) { + if (NOUNIT) { + tmp = ONE/A[k*rsa + k*csa]; + for(i = 0 ; i < M ; i++) { + B[i*rsb + k*csb] = tmp*B[i*rsb + k*csb]; + } + } + for(j = 0 ; j < k; j++) { + if (A[j*rsa + k*csa] != ZERO) { + tmp = A[j*rsa + k*csa]; + for(i = 0 ; i < M ; i++) { + B[i*rsb + j*csb] = B[i*rsb + j*csb] - tmp*B[i*rsb + k*csb]; + } + } + } + } + } + else { /* XAltB : RLT */ + for(k = 0 ; k < N; k++) { + if (NOUNIT) { + tmp = ONE/A[k*rsa + k*csa]; + for(i = 0 ; i < M ; i++) { + B[i*rsb + k*csb] = tmp*B[i*rsb + k*csb]; + } + } + for(j = (k+1) ; j < N ; j++) { + if (A[j*rsa + k*csa] != ZERO) { + tmp = A[j*rsa + k*csa]; + for(i = 0 ; i < M; i++) { + B[i*rsb + j*csb] = B[i*rsb + j*csb] - tmp*B[i*rsb + k*csb]; + } + } + } + } + } + } + } + return; +} + +double libblis_test_itrsm_check( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig, + num_t dt +){ + dim_t M = bli_obj_length( b_orig ); + dim_t N = bli_obj_width( b_orig ); + uplo_t uploa = bli_obj_uplo( a ); + trans_t transa = bli_obj_onlytrans_status( a ); + bool conja = bli_obj_has_conj( a ); + diag_t diaga = bli_obj_diag( a ); + dim_t rsa, csa; + dim_t rsb, csb; + double resid = 0.0; + + rsa = bli_obj_row_stride( a ) ; + csa = bli_obj_col_stride( a ) ; + rsb = bli_obj_row_stride( b ) ; + csb = bli_obj_col_stride( b ) ; + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* A = (float*) bli_obj_buffer( a ); + float* B = (float*) bli_obj_buffer( b_orig ); + float* BB = (float*) bli_obj_buffer( b ); + libblis_itrsm_check(side, uploa, transa, + diaga, M, N, *Alpha, A, rsa, csa, B, rsb, csb ); + resid = computediffrm(M, N, BB, B, rsb, csb); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* A = (double*) bli_obj_buffer( a ); + double* B = (double*) bli_obj_buffer( b_orig ); + double* BB = (double*) bli_obj_buffer( b ); + libblis_itrsm_check(side, uploa, transa, + diaga, M, N, *Alpha, A, rsa, csa, B, rsb, csb ); + resid = computediffrm(M, N, BB, B, rsb, csb); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* B = (scomplex*) bli_obj_buffer( b_orig ); + scomplex* BB = (scomplex*) bli_obj_buffer( b ); + libblis_ictrsm_check(side, uploa, transa, + diaga, M, N, *Alpha, A, rsa, csa, conja, B, rsb, csb ); + resid = computediffim(M, N, BB, B, rsb, csb); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* B = (dcomplex*) bli_obj_buffer( b_orig ); + dcomplex* BB = (dcomplex*) bli_obj_buffer( b ); + libblis_ictrsm_check(side, uploa, transa, + diaga, M, N, *Alpha, A, rsa, csa, conja, B, rsb, csb ); + resid = computediffim(M, N, BB, B, rsb, csb); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + +template +double libblis_check_nan_real( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv )) { + resid = tv ; + break; + } + } + } + return resid; +} + +template +double libblis_check_nan_complex( dim_t rs, dim_t cs, obj_t* b ) { + dim_t M = bli_obj_length( b ); + dim_t N = bli_obj_width( b ); + dim_t i,j; + double resid = 0.0; + T* B = (T*) bli_obj_buffer( b ); + + for( i = 0 ; i < M ; i++ ) { + for( j = 0 ; j < N ; j++ ) { + auto tv = B[ i*rs + j*cs ]; + if ( bli_isnan( tv.real ) || bli_isnan( tv.imag )) { + resid = bli_isnan( tv.real ) ? tv.real : tv.imag; + break; + } + } + } + return resid; +} + +double libblis_check_nan_trsm(obj_t* b, num_t dt ) { + dim_t rsc, csc; + double resid = 0.0; + + if( bli_obj_row_stride( b ) == 1 ) { + rsc = 1; + csc = bli_obj_col_stride( b ); + } else { + rsc = bli_obj_row_stride( b ); + csc = 1 ; + } + + switch( dt ) { + case BLIS_FLOAT: + { + resid = libblis_check_nan_real( rsc, csc, b ); + break; + } + case BLIS_DOUBLE: + { + resid = libblis_check_nan_real( rsc, csc, b ); + break; + } + case BLIS_SCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, b ); + break; + } + case BLIS_DCOMPLEX: + { + resid = libblis_check_nan_complex( rsc, csc, b ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_trsv.cpp b/gtestsuite/src/ref_trsv.cpp new file mode 100644 index 000000000..507f931a1 --- /dev/null +++ b/gtestsuite/src/ref_trsv.cpp @@ -0,0 +1,293 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trsv.h" + +using namespace std; + +//* ========================================================================== +//*> TRSV Solves a triangular system of equations with a single value for the +//*> right side +//*> x := alpha * inv(transa(A)) * x_orig +//*> where b and x are n element vectors and A is an n by n unit, or +//*> non-unit, upper or lower triangular matrix. +//* ========================================================================== + +template +void libblis_itrsv_check(uplo_t uploa, trans_t transa, diag_t diaga, + T* alpha, dim_t N, T* A, dim_t rsa, dim_t csa, T* X, dim_t incx){ + + T Alpha = alpha[0]; + T tmp; + int i, ix, j, jx, kx; + bool NOTRANS, NOUNIT; + + if(N == 0) + return; + + NOTRANS = (transa == BLIS_NO_TRANSPOSE); + NOUNIT = (diaga == BLIS_NONUNIT_DIAG); + + //* Set up the start point in X if the increment is not unity. This + //* will be ( N - 1 )*incx too small for descending loops. + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = (Alpha * X[ix]); + ix = ix + incx; + } + + //* Start the operations. In this version the elements of A are + //* accessed sequentially with one pass through A. + if(NOTRANS){ + //* Form x := inv( A )*x. + if(uploa == BLIS_UPPER){ + kx = kx + (N - 1)*incx; + ix = kx; + for(i = (N-1) ; i >= 0 ; i--){ + tmp = 0; + jx = (ix+1); + for(j = (i+1) ; j < N ; j++){ + tmp = tmp + X[jx]*A[i*rsa + j*csa]; + jx = jx + incx; + } + tmp = (X[ix] - tmp); + if(NOUNIT) + tmp = (tmp/A[i*rsa + i*csa]); + X[ix] = tmp; + ix = ix - incx; + } + } + else{ + ix = kx; + for(i = 0 ; i < N ; i++){ + tmp = 0; + jx = kx; + for(j = 0 ; j < i ; j++ ){ + tmp = tmp + (X[jx]*A[i*rsa + j*csa]); + jx = jx + incx; + } + tmp = (X[ix] - tmp); + if(NOUNIT) + tmp = (tmp/A[i*rsa + i*csa]); + X[ix] = tmp; + ix = ix + incx; + } + } + } + else{ + //* Form x := inv( A**T )*x. + if(uploa == BLIS_UPPER){ + ix = kx; + for(i = 0 ; i < N ; i++){ + if(NOUNIT) + X[ix] = (X[ix]/A[i*rsa + i*csa]); + tmp = X[ix]; + jx = ix; + for(j = (i+1) ; j < N ; j++){ + jx = jx + incx; + X[jx] = X[jx] - (tmp * A[i*rsa + j*csa]); + } + ix = ix + incx; + } + } + else{ + ix = kx + (N - 1)*incx; + for(i = (N-1) ; i >= 0 ; i--){ + if(NOUNIT) + X[ix] = (X[ix]/A[i*rsa + i*csa]); + tmp = X[ix]; + jx = ix; + for(j = (i-1) ; j >= 0 ; j--){ + jx = jx - incx; + X[jx] = X[jx] - (tmp * A[i*rsa + j*csa]); + } + ix = ix - incx; + } + } + } + return; +} + +template +void libblis_ictrsv_check(uplo_t uploa, trans_t transa, diag_t diaga, +T* alpha, dim_t N, T* A, dim_t rsa, dim_t csa, bool conja, T* X, dim_t incx){ + + T Alpha = *alpha; + T tmp; + int i, ix, j, jx, kx; + bool NOTRANS, NOUNIT; + + if (N == 0) + return; + + NOTRANS = (transa == BLIS_NO_TRANSPOSE); + NOUNIT = (diaga == BLIS_NONUNIT_DIAG); + + //* Set up the start point in X if the increment is not unity. This + //* will be ( N - 1 )*incx too small for descending loops. + if (incx > 0) { + kx = 0; + } + else { + kx = 1 - (N * incx); + } + + ix = 0; + for(i = 0 ; i < N ; i++) { + X[ix] = mulc(Alpha , X[ix]); + ix = ix + incx; + } + + if(conja) { + for(i = 0 ; i < N ; i++) { + for(j = 0 ; j < N ; j++) { + A[i*rsa + j*csa] = conjugate(A[i*rsa + j*csa]); + } + } + } + + if(NOTRANS){ + //* Form x := inv( A )*x. + if(uploa == BLIS_UPPER){ + kx = kx + (N - 1)*incx; + ix = kx; + for(i = (N-1) ; i >= 0 ; i--){ + tmp = {0.0,0.0}; + jx = (ix+1); + for(j = (i+1) ; j < N ; j++){ + tmp = addc(tmp , mulc(X[jx] , A[i*rsa + j*csa])); + jx = jx + incx; + } + tmp = subc(X[ix] , tmp); + if(NOUNIT) + tmp = divc(tmp , A[i*rsa + i*csa]); + X[ix] = tmp; + ix = ix - incx; + } + } + else{ + ix = kx; + for(i = 0 ; i < N ; i++){ + tmp = {0.0,0.0}; + jx = kx; + for(j = 0 ; j < i ; j++ ){ + tmp = addc(tmp , mulc(X[jx] , A[i*rsa + j*csa])); + jx = jx + incx; + } + tmp = subc(X[ix] , tmp); + if(NOUNIT) + tmp = divc(tmp , A[i*rsa + i*csa]); + X[ix] = tmp; + ix = ix + incx; + } + } + } + else{ + //* Form x := inv( A**T )*x. + if(uploa == BLIS_UPPER){ + ix = kx; + for(i = 0 ; i < N ; i++){ + if(NOUNIT) + X[ix] = divc(X[ix] , A[i*rsa + i*csa]); + tmp = X[ix]; + jx = ix; + for(j = (i+1) ; j < N ; j++){ + jx = jx + incx; + X[jx] = subc(X[jx] , mulc(tmp , A[i*rsa + j*csa])); + } + ix = ix + incx; + } + } + else{ + ix = kx + (N - 1)*incx; + for(i = (N-1) ; i >= 0 ; i--){ + if(NOUNIT) + X[ix] = divc(X[ix] , A[i*rsa + i*csa]); + tmp = X[ix]; + jx = ix; + for(j = (i-1) ; j >= 0 ; j--){ + jx = jx - incx; + X[jx] = subc(X[jx] , mulc(tmp , A[i*rsa + j*csa])); + } + ix = ix - incx; + } + } + } + return; +} + +double libblis_test_itrsv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig +){ + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_length( a ); + dim_t incx = bli_obj_vector_inc( x ); + dim_t rsa = bli_obj_row_stride( a ) ; + dim_t csa = bli_obj_col_stride( a ) ; + uplo_t uploa = bli_obj_uplo( a ); + bool conja = bli_obj_has_conj( a ); + trans_t transa = bli_obj_onlytrans_status( a ); + diag_t diaga = bli_obj_diag( a ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x_orig ); + float* A = (float*) bli_obj_buffer( a ); + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* XX = (float*) bli_obj_buffer( x ); + libblis_itrsv_check(uploa, transa, diaga, Alpha, + M, A, rsa, csa, X, incx); + resid = computediffrv(M, incx, XX, X); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x_orig ); + double* A = (double*) bli_obj_buffer( a ); + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* XX = (double*) bli_obj_buffer( x ); + libblis_itrsv_check(uploa, transa, diaga, Alpha, + M, A, rsa, csa, X, incx); + resid = computediffrv(M, incx, XX, X); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x_orig ); + scomplex* A = (scomplex*) bli_obj_buffer( a ); + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* XX = (scomplex*) bli_obj_buffer( x ); + libblis_ictrsv_check(uploa, transa, diaga, Alpha, + M, A, rsa, csa, conja, X, incx); + resid = computediffiv(M, incx, XX, X); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x_orig ); + dcomplex* A = (dcomplex*) bli_obj_buffer( a ); + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* XX = (dcomplex*) bli_obj_buffer( x ); + libblis_ictrsv_check(uploa, transa, diaga, Alpha, + M, A, rsa, csa, conja, X, incx); + resid = computediffiv(M, incx, XX, X); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return resid; +} + diff --git a/gtestsuite/src/ref_xpbym.cpp b/gtestsuite/src/ref_xpbym.cpp new file mode 100644 index 000000000..759025c7e --- /dev/null +++ b/gtestsuite/src/ref_xpbym.cpp @@ -0,0 +1,176 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_xpbym.h" + +using namespace std; + +//* ========================================================================== +//*> XPBYM performs vector operations +//*> B := B * alpha + conjx(A) +//*> where B is an m x n matrix. +//* ========================================================================== + +template +void libblis_ixpbym_check(dim_t M, dim_t N, T* alpha, + T* X, dim_t rsx, dim_t csx, T* Y, dim_t rsy, dim_t csy, T* YY) { + + dim_t i, j; + T ONE = 1.0 ; + T ZERO = 0.0 ; + T Alpha = alpha[0]; + + if ((M == 0) || (N == 0)) { + return; + } + + //* First form y := beta*y. + if (Alpha != ONE) { + if (Alpha == ZERO) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = ZERO; + } + } + } + else { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = (Alpha * Y[i*rsy + j*csy]); + } + } + } + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = Y[i*rsy + j*csy] + X[i*rsx + j*csx] ; + } + } + + return; +} + +template +void libblis_icxpbym_check(dim_t M, dim_t N, T* alpha, + T* X, dim_t rsx, dim_t csx, conj_t conjx, T* Y, dim_t rsy, dim_t csy) { + + dim_t i, j; + T ONE = {1.0 , 0.0}; + T ZERO = {0.0 , 0.0}; + T Alpha = *alpha; + + if ((M == 0) || (N == 0)) { + return; + } + + if(conjx) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + X[i*rsx + j*csx] = conjugate(X[i*rsx + j*csx]); + } + } + } + + if ((Alpha.real != ONE.real) && (Alpha.imag != ONE.imag)) { + if ((Alpha.real == ZERO.real) && (Alpha.imag == ZERO.imag)) { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = ZERO; + } + } + } + else { + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = mulc(Alpha , Y[i*rsy + j*csy]); + } + } + } + } + + for(i = 0 ; i < M ; i++) { + for(j = 0 ; j < N ; j++) { + Y[i*rsy + j*csy] = addc(Y[i*rsy + j*csy] , X[i*rsx + j*csx]); + } + } + + return; +} + +double libblis_test_ixpbym_check( + test_params_t* params, + obj_t* x, + obj_t* alpha, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + dim_t M = bli_obj_length( y ); + dim_t N = bli_obj_width( y ); + bool transx = bli_obj_has_trans( x ); + conj_t conjx = bli_obj_conj_status( x ); + dim_t rsy = bli_obj_row_stride( y ) ; + dim_t csy = bli_obj_col_stride( y ) ; + double resid = 0.0; + dim_t rsx, csx; + + if( bli_obj_is_col_stored( x ) ) { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } else { + rsx = transx ? bli_obj_col_stride( x ) : bli_obj_row_stride( x ) ; + csx = transx ? bli_obj_row_stride( x ) : bli_obj_col_stride( x ) ; + } + + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* X = (float*) bli_obj_buffer( x ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_ixpbym_check( M, N, Alpha, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* X = (double*) bli_obj_buffer( x ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_ixpbym_check( M, N, Alpha, X, rsx, csx, + Y, rsy, csy, YY ); + resid = computediffrm(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icxpbym_check( M, N, Alpha, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icxpbym_check( M, N, Alpha, X, rsx, csx, + conjx, Y, rsy, csy ); + resid = computediffim(M, N, YY, Y, rsy, csy); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/ref_xpbyv.cpp b/gtestsuite/src/ref_xpbyv.cpp new file mode 100644 index 000000000..71aea383c --- /dev/null +++ b/gtestsuite/src/ref_xpbyv.cpp @@ -0,0 +1,165 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_xpbyv.h" + +using namespace std; + +//* ========================================================================== +//*> XPBYV performs vector operations +//*> y := beta * y + conjx(x) +//*> where x and y are vectors of length n, and beta is scalar +//* ========================================================================== + +template +void libblis_ixpbyv_check(dim_t len, T* X, dim_t incx, + T* beta, T* Y, dim_t incy) { + + dim_t i, ix, iy; + T ONE, ZERO; + ONE = 1.0 ; + ZERO = 0.0 ; + T Beta = beta[0]; + if ((len == 0) || (Beta == ONE)){ + return; + } + + //* First form y := beta*y. + if (Beta != ONE) { + iy = 0; + if (Beta == ZERO) { + for(i = 0 ; i < len ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < len ; i++) { + Y[iy] = Beta*Y[iy]; + iy = iy + incy; + } + } + } + + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = Y[iy] + X[ix]; + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +template +void libblis_icxpbyv_check(dim_t len, T* X, dim_t incx, + T* beta, T* Y, dim_t incy, bool cfx) { + dim_t i, ix, iy; + T ONE, ZERO; + ONE = {1.0 , 0.0}; + ZERO = {0.0 , 0.0}; + T Beta = *beta; + + if (len == 0) { + return; + } + + if(cfx) { + ix = 0; + for(i = 0 ; i < len ; i++) { + X[ix] = conjugate(X[ix]); + ix = ix + incx; + } + } + + /* First form y := beta*y. */ + iy = 0; + if ((Beta.real == ZERO.real) && (Beta.imag == ZERO.imag)) { + for(i = 0; i < len ; i++) { + Y[iy] = ZERO; + iy = iy + incy; + } + } + else { + for(i = 0 ; i < len ; i++) { + Y[iy] = mulc(Beta , Y[iy]); + iy = iy + incy; + } + } + + ix = 0; + iy = 0; + for(i = 0 ; i < len ; i++) { + Y[iy] = addc(Y[iy] , X[ix]); + ix = ix + incx; + iy = iy + incy; + } + + return; +} + +double libblis_test_ixpbyv_check( + test_params_t* params, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( x ); + dim_t M = bli_obj_vector_dim( x ); + bool cfx = bli_obj_has_conj( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y_orig ); + double resid = 0.0; + + switch( dt ) { + case BLIS_FLOAT : + { + float* X = (float*) bli_obj_buffer( x ); + float* Beta = (float*) bli_obj_buffer( beta ); + float* Y = (float*) bli_obj_buffer( y_orig ); + float* YY = (float*) bli_obj_buffer( y ); + libblis_ixpbyv_check( M, X, incx, Beta, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_DOUBLE : + { + double* X = (double*) bli_obj_buffer( x ); + double* Beta = (double*) bli_obj_buffer( beta ); + double* Y = (double*) bli_obj_buffer( y_orig ); + double* YY = (double*) bli_obj_buffer( y ); + libblis_ixpbyv_check( M, X, incx, Beta, Y, incy ); + resid = computediffrv(M, incy, YY, Y); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* X = (scomplex*) bli_obj_buffer( x ); + scomplex* Beta = (scomplex*) bli_obj_buffer( beta ); + scomplex* Y = (scomplex*) bli_obj_buffer( y_orig ); + scomplex* YY = (scomplex*) bli_obj_buffer( y ); + libblis_icxpbyv_check( M, X, incx, Beta, + Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* X = (dcomplex*) bli_obj_buffer( x ); + dcomplex* Beta = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* Y = (dcomplex*) bli_obj_buffer( y_orig ); + dcomplex* YY = (dcomplex*) bli_obj_buffer( y ); + libblis_icxpbyv_check( M, X, incx, Beta, + Y, incy, cfx ); + resid = computediffiv(M, incy, YY, Y); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return resid; +} + diff --git a/gtestsuite/src/test_addm.cpp b/gtestsuite/src/test_addm.cpp new file mode 100644 index 000000000..148d4fc62 --- /dev/null +++ b/gtestsuite/src/test_addm.cpp @@ -0,0 +1,235 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_addm.h" + +// Local prototypes. +void libblis_test_addm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_addm_impl ( + iface_t iface, + obj_t* x, + obj_t* y +); + +double libblis_test_addm_check ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y +); + +double libblis_ref_addm( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_addm_check( params, alpha, beta, x, y ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iaddm_check( params, x, y, y_orig); + } + else { + resid = libblis_test_matrix_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_addm( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( y_orig, r ); + libblis_test_addm_impl( iface, x, r ); + resid = libblis_test_bitrp_matrix(y, r, dt); + } + return resid; +} + +double libblis_test_op_addm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +) { + num_t datatype; + dim_t m, n; + trans_t transx; + obj_t alpha, beta; + obj_t x, y, y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_trans( pc_str[0], &transx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transx, + sc_str[0], m, n, &x ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, n, &y ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, n, &y_save ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Initialize alpha and beta. + bli_setsc( -1.0, -1.0, &alpha ); + bli_setsc( 3.0, 3.0, &beta ); + + // Randomize x. + bli_setm( &alpha, &x ); + bli_setm( &beta, &y ); + } + else { + libblis_test_mobj_irandomize( params, &x ); + libblis_test_mobj_irandomize( params, &y ); + } + + // Apply the parameters. + bli_obj_set_conjtrans( transx, &x ); + + //Copy c to c_save + bli_copym( &y, &y_save ); + + libblis_test_addm_impl( iface, &x, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, n, &r ); + resid = libblis_test_bitrp_addm( params, iface, &x, &y, &y_save, + &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_addm( params, &alpha, &beta, &x, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_addm_impl( + iface_t iface, + obj_t* x, + obj_t* y +) { + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_addm( x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_addm_check ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + dim_t m = bli_obj_length( y ); + dim_t n = bli_obj_width( y ); + + conj_t conjx = bli_obj_conj_status( x ); + + obj_t aplusb; + obj_t alpha_conj; + obj_t norm_r, m_r, n_r, temp_r; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is set to alpha. + // - y_orig is set to beta. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := y_orig + conjx(x) + // + // is functioning correctly if + // + // normfm(y) - sqrt( absqsc( beta + conjx(alpha) ) * m * n ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt, &aplusb ); + bli_obj_scalar_init_detached( dt_real, &temp_r ); + bli_obj_scalar_init_detached( dt_real, &norm_r ); + bli_obj_scalar_init_detached( dt_real, &m_r ); + bli_obj_scalar_init_detached( dt_real, &n_r ); + + bli_obj_scalar_init_detached_copy_of( dt, conjx, alpha, &alpha_conj ); + + bli_normfm( y, &norm_r ); + + bli_copysc( beta, &aplusb ); + bli_addsc( &alpha_conj, &aplusb ); + + bli_setsc( ( double )m, 0.0, &m_r ); + bli_setsc( ( double )n, 0.0, &n_r ); + + bli_absqsc( &aplusb, &temp_r ); + bli_mulsc( &m_r, &temp_r ); + bli_mulsc( &n_r, &temp_r ); + bli_sqrtsc( &temp_r, &temp_r ); + bli_subsc( &temp_r, &norm_r ); + + bli_getsc( &norm_r, &resid, &junk ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_addm.h b/gtestsuite/src/test_addm.h new file mode 100644 index 000000000..1eafed499 --- /dev/null +++ b/gtestsuite/src/test_addm.h @@ -0,0 +1,16 @@ +#ifndef TEST_ADDM_H +#define TEST_ADDM_H + +#include "blis_test.h" + +double libblis_test_iaddm_check + ( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_addm( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_ADDM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_addv.cpp b/gtestsuite/src/test_addv.cpp new file mode 100644 index 000000000..51a9e0d60 --- /dev/null +++ b/gtestsuite/src/test_addv.cpp @@ -0,0 +1,216 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_addv.h" + +// Local prototypes. +void libblis_test_addv_deps(thread_data_t* tdata, + test_params_t* params, test_op_t* op ); + +void libblis_test_addv_impl (iface_t iface, obj_t* x, obj_t* y); + +double libblis_test_addv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y +); + +double libblis_ref_addv( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_addv_check(params, alpha, beta, x, y ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iaddv_check(params, alpha, beta, x, y, y_save); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_addv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_addv_impl( iface, x, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_addv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + dim_t m; + conj_t conjx; + obj_t alpha, beta; + obj_t x, y, y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y_save ); + + // Initialize alpha and beta. + bli_setsc( -1.0, -1.0, &alpha ); + bli_setsc( 3.0, 3.0, &beta ); + + // Set x and y to alpha and beta, respectively. + bli_setv( &alpha, &x ); + bli_setv( &beta, &y ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + + bli_copyv( &y, &y_save ); + + libblis_test_addv_impl( iface, &x, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[1], m, &r ); + + resid = libblis_test_bitrp_addv( params, iface, &x, &y, &y_save, + &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_addv( params, &alpha, &beta, &x, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_addv_impl ( + iface_t iface, + obj_t* x, + obj_t* y +){ + + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_addv( x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_addv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y +) { + num_t dt = bli_obj_dt( x ); + num_t dt_real = bli_obj_dt_proj_to_real( x ); + dim_t m = bli_obj_vector_dim( x ); + + conj_t conjx = bli_obj_conj_status( x ); + + obj_t aplusb; + obj_t alpha_conj; + obj_t norm_r, m_r, temp_r; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is set to alpha. + // - y_orig is set to beta. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := y_orig + conjx(x) + // + // is functioning correctly if + // + // normfv(y) - sqrt( absqsc( beta + conjx(alpha) ) * m ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt, &aplusb ); + bli_obj_scalar_init_detached( dt_real, &temp_r ); + bli_obj_scalar_init_detached( dt_real, &norm_r ); + bli_obj_scalar_init_detached( dt_real, &m_r ); + + bli_obj_scalar_init_detached_copy_of( dt, conjx, alpha, &alpha_conj ); + + bli_normfv( y, &norm_r ); + + bli_copysc( beta, &aplusb ); + bli_addsc( &alpha_conj, &aplusb ); + + bli_setsc( ( double )m, 0.0, &m_r ); + + bli_absqsc( &aplusb, &temp_r ); + bli_mulsc( &m_r, &temp_r ); + bli_sqrtsc( &temp_r, &temp_r ); + bli_subsc( &temp_r, &norm_r ); + + bli_getsc( &norm_r, &resid, &junk ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_addv.h b/gtestsuite/src/test_addv.h new file mode 100644 index 000000000..173fb5a5c --- /dev/null +++ b/gtestsuite/src/test_addv.h @@ -0,0 +1,18 @@ +#ifndef TEST_ADDV_H +#define TEST_ADDV_H + +#include "blis_test.h" + +double libblis_test_iaddv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_addv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_ADDV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_amaxv.cpp b/gtestsuite/src/test_amaxv.cpp new file mode 100644 index 000000000..26b29309c --- /dev/null +++ b/gtestsuite/src/test_amaxv.cpp @@ -0,0 +1,477 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_amaxv.h" + +// Local prototypes. +void libblis_test_amaxv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_amaxv_impl ( + iface_t iface, + obj_t* x, + obj_t* index +); + +double libblis_test_amaxv_check ( + test_params_t* params, + obj_t* x, + obj_t* index +); + +void bli_amaxv_test ( + obj_t* x, + obj_t* index +); + +double cblas_amaxv( + f77_int m, + obj_t* x, + f77_int incx, + gint_t* idx, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* xp = (float*) bli_obj_buffer( x ); + *idx = cblas_isamax( m, xp, incx ); + break; + } + case BLIS_DOUBLE : + { + double* xp = (double*) bli_obj_buffer( x ); + *idx = cblas_idamax( m, xp, incx ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + *idx = cblas_icamax( m, xp, incx ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + *idx = cblas_izamax( m, xp, incx ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_amaxv( + f77_int m, + obj_t* x, + f77_int incx, + gint_t* idx, + num_t dt +){ + gint_t index = 1; + switch( dt ) { + case BLIS_FLOAT : + { + float* xp = (float*) bli_obj_buffer( x ); + index = isamax_( &m, xp, &incx ); + break; + } + case BLIS_DOUBLE : + { + double* xp = (double*) bli_obj_buffer( x ); + index = idamax_( &m, xp, &incx ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + index = icamax_( &m, xp, &incx ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + index = izamax_( &m, xp, &incx ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + *idx = (index - 1); + return 0; +} + +void libblis_api_amaxv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* index, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_amaxv_impl( iface, x, index ); + } + else { /*CLBAS || BLAS */ + dim_t m = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + gint_t *idx = (gint_t *)bli_obj_buffer( index ); + + if( params->api == API_CBLAS ) { + cblas_amaxv( m, x, incx, idx, dt ); + } else { + blas_amaxv( m, x, incx, idx, dt );; + } + } + return ; +} + +double libblis_ref_amaxv( + test_params_t* params, + obj_t* x, + obj_t* index +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_amaxv_check( params, x, index ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iamaxv_check( params, x, index ); + } + else { + resid = libblis_test_vector_check(params, x); + } + } + + return resid; +} + +double libblis_test_bitrp_amaxv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* index, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_obj_scalar_init_detached( BLIS_INT, r ); + libblis_test_amaxv_impl( iface, x, r ); + resid = libblis_test_bitrp_vector(index, r, dt); + } + return resid; +} + +double libblis_test_op_amaxv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + dim_t m; + obj_t x; + obj_t index; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Create test scalars. + bli_obj_scalar_init_detached( BLIS_INT, &index ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + + // Randomize x. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, FALSE, &x ); + } else { + libblis_test_vobj_irandomize( params, &x ); + } + + libblis_api_amaxv( params, iface, &x, &index, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + resid = libblis_test_bitrp_amaxv( params, iface, &x, &index, &r, datatype ); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_amaxv( params, &x, &index ); + } +#endif + + // Zero out performance and residual if input vector is empty. + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + + return abs(resid); +} + +void libblis_test_amaxv_impl ( + iface_t iface, + obj_t* x, + obj_t* index +) { + + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_amaxv( x, index ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_amaxv_check ( + test_params_t* params, + obj_t* x, + obj_t* index +) { + obj_t index_test; + obj_t chi_i; + obj_t chi_i_test; + dim_t i; + dim_t i_test; + + double i_d, junk; + double i_d_test; + + double resid = 0.0; + // + // Pre-conditions: + // - x is randomized. + // + // Under these conditions, we assume that the implementation for + // + // index := amaxv( x ) + // + // is functioning correctly if + // + // x[ index ] = max( x ) + // + // where max() is implemented via the bli_?amaxv_test() function. + // + + // The following two calls have already been made by the caller. That + // is, the index object has already been created and the library's + // amaxv implementation has already been tested. + //bli_obj_scalar_init_detached( BLIS_INT, &index ); + //bli_amaxv( x, &index ); + bli_getsc( index, &i_d, &junk ); i = i_d; + + // If x is length 0, then we can't access any elements, and so we + // return early with a good residual. + if ( bli_obj_vector_dim( x ) == 0 ) { resid = 0.0; return resid; } + + bli_acquire_vi( i, x, &chi_i ); + + bli_obj_scalar_init_detached( BLIS_INT, &index_test ); + bli_amaxv_test( x, &index_test ); + bli_getsc( &index_test, &i_d_test, &junk ); i_test = i_d_test; + bli_acquire_vi( i_test, x, &chi_i_test ); + + // Verify that the values referenced by index and index_test are equal. + if ( bli_obj_equals( &chi_i, &chi_i_test ) ) resid = 0.0; + else resid = 1.0; + + return resid; +} + +// ----------------------------------------------------------------------------- + +// +// Prototype BLAS-like interfaces with typed operands for a local amaxv test +// operation +// + +#undef GENTPROT +#define GENTPROT( ctype, ch, opname ) \ +\ +void PASTEMAC(ch,opname) \ + ( \ + dim_t n, \ + ctype* restrict x, inc_t incx, \ + dim_t* restrict index \ + ); \ + +INSERT_GENTPROT_BASIC0( amaxv_test ) + + +// +// Prototype function pointer query interface. +// + +#undef GENPROT +#define GENPROT( tname, opname ) \ +\ +PASTECH(tname,_vft) \ +PASTEMAC(opname,_qfp)( num_t dt ); + +GENPROT( amaxv, amaxv_test ) + + +// +// Define function pointer query interfaces. +// + +#undef GENFRONT +#define GENFRONT( tname, opname ) \ +\ +GENARRAY_FPA( PASTECH(tname,_vft), \ + opname ); \ +\ +PASTECH(tname,_vft) \ +PASTEMAC(opname,_qfp)( num_t dt ) \ +{ \ + return PASTECH(opname,_fpa)[ dt ]; \ +} + +GENFRONT( amaxv, amaxv_test ) + + +// +// Define object-based interface for a local amaxv test operation. +// + +#undef GENFRONT +#define GENFRONT( tname, opname ) \ +\ +void PASTEMAC0(opname) \ + ( \ + obj_t* x, \ + obj_t* index \ + ) \ +{ \ + num_t dt = bli_obj_dt( x ); \ +\ + dim_t n = bli_obj_vector_dim( x ); \ + void* buf_x = bli_obj_buffer_at_off( x ); \ + inc_t incx = bli_obj_vector_inc( x ); \ +\ + dim_t* buf_index = (dim_t*)bli_obj_buffer_at_off( index ); \ +\ +/* + FGVZ: Disabling this code since bli_amaxv_check() is supposed to be a + non-public API function, and therefore unavailable unless all symbols + are scheduled to be exported at configure-time (which is not currently + the default behavior). + + if ( bli_error_checking_is_enabled() ) \ + bli_amaxv_check( x, index ); \ +*/ \ +\ + /* Query a type-specific function pointer, except one that uses + void* for function arguments instead of typed pointers. */ \ + PASTECH(tname,_vft) f = \ + PASTEMAC(opname,_qfp)( dt ); \ +\ + f \ + ( \ + n, \ + buf_x, incx, \ + buf_index \ + ); \ +} + +GENFRONT( amaxv, amaxv_test ) + + +// +// Define BLAS-like interfaces with typed operands for a local amaxv test +// operation. +// NOTE: This is based on a simplified version of the bli_?amaxv_ref() +// reference kernel. +// + +#undef GENTFUNCR +#define GENTFUNCR( ctype, ctype_r, ch, chr, varname ) \ +\ +void PASTEMAC(ch,varname) \ + ( \ + dim_t n, \ + ctype* x, inc_t incx, \ + dim_t* index \ + ) \ +{ \ + ctype_r* minus_one = PASTEMAC(chr,m1); \ + dim_t* zero_i = PASTEMAC(i,0); \ +\ + ctype_r chi1_r; \ + ctype_r chi1_i; \ + ctype_r abs_chi1; \ + ctype_r abs_chi1_max; \ + dim_t index_l; \ + dim_t i; \ +\ + /* If the vector length is zero, return early. This directly emulates + the behavior of netlib BLAS's i?amax() routines. */ \ + if ( bli_zero_dim1( n ) ) \ + { \ + PASTEMAC(i,copys)( *zero_i, *index ); \ + return; \ + } \ +\ + /* Initialize the index of the maximum absolute value to zero. */ \ + PASTEMAC(i,copys)( *zero_i, index_l ); \ +\ + /* Initialize the maximum absolute value search candidate with + -1, which is guaranteed to be less than all values we will + compute. */ \ + PASTEMAC(chr,copys)( *minus_one, abs_chi1_max ); \ +\ + { \ + for ( i = 0; i < n; ++i ) \ + { \ + ctype* chi1 = x + (i )*incx; \ +\ + /* Get the real and imaginary components of chi1. */ \ + PASTEMAC2(ch,chr,gets)( *chi1, chi1_r, chi1_i ); \ +\ + /* Replace chi1_r and chi1_i with their absolute values. */ \ + PASTEMAC(chr,abval2s)( chi1_r, chi1_r ); \ + PASTEMAC(chr,abval2s)( chi1_i, chi1_i ); \ +\ + /* Add the real and imaginary absolute values together. */ \ + PASTEMAC(chr,set0s)( abs_chi1 ); \ + PASTEMAC(chr,adds)( chi1_r, abs_chi1 ); \ + PASTEMAC(chr,adds)( chi1_i, abs_chi1 ); \ +\ + /* If the absolute value of the current element exceeds that of + the previous largest, save it and its index. If NaN is + encountered, then treat it the same as if it were a valid + value that was smaller than any previously seen. This + behavior mimics that of LAPACK's ?lange(). */ \ + if ( abs_chi1_max < abs_chi1 || bli_isnan( abs_chi1 ) ) \ + { \ + abs_chi1_max = abs_chi1; \ + index_l = i; \ + } \ + } \ + } \ +\ + /* Store the final index to the output variable. */ \ + PASTEMAC(i,copys)( index_l, *index ); \ +} +INSERT_GENTFUNCR_BASIC0( amaxv_test ) \ No newline at end of file diff --git a/gtestsuite/src/test_amaxv.h b/gtestsuite/src/test_amaxv.h new file mode 100644 index 000000000..043168492 --- /dev/null +++ b/gtestsuite/src/test_amaxv.h @@ -0,0 +1,15 @@ +#ifndef TEST_AMAXV_H +#define TEST_AMAXV_H + +#include "blis_test.h" + +double libblis_test_iamaxv_check + ( + test_params_t* params, + obj_t* x, + obj_t* index + ); + +double libblis_check_nan_amaxv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_AMAXV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_axpbyv.cpp b/gtestsuite/src/test_axpbyv.cpp new file mode 100644 index 000000000..e7d220e89 --- /dev/null +++ b/gtestsuite/src/test_axpbyv.cpp @@ -0,0 +1,380 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpbyv.h" + +// Local prototypes. +void libblis_test_axpbyv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_axpbyv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y +); + +double libblis_test_axpbyv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +); + +double cblas_axpbyv( + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* beta, + obj_t* y, + f77_int incy, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* betap = (float*) bli_obj_buffer( beta ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_saxpby( m, *alphap, xp, incx, *betap, yp, incy ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* betap = (double*) bli_obj_buffer( beta ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_daxpby( m, *alphap, xp, incx, *betap, yp, incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cblas_caxpby( m, alphap, xp, incx, betap, yp, incy ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + cblas_zaxpby( m, alphap, xp, incx, betap, yp, incy );; + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_axpbyv( + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* beta, + obj_t* y, + f77_int incy, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* betap = (float*) bli_obj_buffer( beta ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + saxpby_( &m, alphap, xp, &incx, betap, yp, &incy ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* betap = (double*) bli_obj_buffer( beta ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + daxpby_( &m, alphap, xp, &incx, betap, yp, &incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + caxpby_( &m, alphap, xp, &incx, betap, yp, &incy );; + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + zaxpby_( &m, alphap, xp, &incx, betap, yp, &incy );; + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_axpbyv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_axpbyv_impl( iface, alpha, x, beta, y ); + } + else { /*CLBAS || BLAS */ + dim_t m = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + + if(bli_obj_has_conj(x)) { + conjugate_tensor(x, dt); + bli_obj_set_conj( BLIS_NO_CONJUGATE, x ); + } + + if( params->api == API_CBLAS ) { + cblas_axpbyv( m, alpha, x, incx, beta, y, incy, dt ); + } else { + blas_axpbyv( m, alpha, x, incx, beta, y, incy, dt ); + } + } + return ; +} + +double libblis_ref_axpbyv( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_axpbyv_check( params, alpha, x, beta, y, y_save ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iaxpbyv_check( params, alpha, x, beta, y, y_save ); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_axpbyv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_axpbyv_impl( iface, alpha, x, beta, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_axpbyv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m; + conj_t conjx; + obj_t alpha, beta, x, y; + obj_t y_save; + double resid = 0.0; + obj_t xx; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[0], m, &xx ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y_save ); + + if ( bli_obj_is_real( &y ) ) + bli_setsc( -2.0, 0.0, &alpha ); + else + bli_setsc( 0.0, -2.0, &alpha ); + + bli_setsc( -1.0, 0.0, &beta ); + + // Randomize x and y, and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, FALSE, &x ); + libblis_test_vobj_randomize( params, FALSE, &y ); + } else { + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + + bli_copyv( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + + bli_copyv( &x, &xx ); + + libblis_api_axpbyv( params, iface, &alpha, &xx, &beta, &y, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[1], m, &r ); + + resid = libblis_test_bitrp_axpbyv( params, iface, &alpha, &x, + &beta, &y, &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_axpbyv( params, &alpha, &x, &beta, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_axpbyv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_axpbyv( alpha, x, beta, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_axpbyv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( y ); + + obj_t x_temp, y_temp; + obj_t norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - y_orig is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := beta * y_orig + alpha * conjx(x) + // + // is functioning correctly if + // + // normfv( y - ( beta * y_orig + alpha * conjx(x) ) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &x_temp ); + bli_obj_create( dt, m, 1, 0, 0, &y_temp ); + + bli_copyv( x, &x_temp ); + bli_copyv( y_orig, &y_temp ); + + bli_scalv( alpha, &x_temp ); + bli_scalv( beta, &y_temp ); + bli_addv( &x_temp, &y_temp ); + + bli_subv( &y_temp, y ); + bli_normfv( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + bli_obj_free( &y_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_axpbyv.h b/gtestsuite/src/test_axpbyv.h new file mode 100644 index 000000000..98dbb0a93 --- /dev/null +++ b/gtestsuite/src/test_axpbyv.h @@ -0,0 +1,18 @@ +#ifndef TEST_AXPBYV_H +#define TEST_AXPBYV_H + +#include "blis_test.h" + +double libblis_test_iaxpbyv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_axpbyv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_AXPBYV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_axpy2v.cpp b/gtestsuite/src/test_axpy2v.cpp new file mode 100644 index 000000000..456a60965 --- /dev/null +++ b/gtestsuite/src/test_axpy2v.cpp @@ -0,0 +1,274 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpy2v.h" + +// Local prototypes. +void libblis_test_axpy2v_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_axpy2v_impl ( + iface_t iface, + obj_t* alpha1, + obj_t* alpha2, + obj_t* x, + obj_t* y, + obj_t* z, + cntx_t* cntx +); + +double libblis_test_axpy2v_check ( + test_params_t* params, + obj_t* alpha1, + obj_t* alpha2, + obj_t* x, + obj_t* y, + obj_t* z, + obj_t* z_orig +); + +double libblis_ref_axpy2v ( + test_params_t* params, + obj_t* alpha1, + obj_t* alpha2, + obj_t* x, + obj_t* y, + obj_t* z, + obj_t* z_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_axpy2v_check( params, alpha1, alpha2, x, y, z, z_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iaxpy2v_check( params, alpha1, alpha2, x, y, z, z_orig ); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_axpy2v( + test_params_t* params, + iface_t iface, + obj_t* alpha1, + obj_t* alpha2, + obj_t* x, + obj_t* y, + obj_t* z, + cntx_t* cntx, + obj_t* z_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( z_orig, r ); + libblis_test_axpy2v_impl( iface, alpha1, alpha2, x, y, r, cntx); + resid = libblis_test_bitrp_vector(z, r, dt); + } + return resid; +} + +double libblis_test_op_axpy2v ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +) { + num_t datatype; + dim_t m; + conj_t conjx, conjy; + obj_t alpha1, alpha2, x, y, z; + obj_t z_save; + cntx_t* cntx; + double resid = 0.0; + + // Query a context. + cntx = bli_gks_query_cntx(); + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjy ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha1 ); + bli_obj_scalar_init_detached( datatype, &alpha2 ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[2], m, &z ); + libblis_test_vobj_create( params, datatype, sc_str[2], m, &z_save ); + + // Randomize x and y, and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Set alpha. + if ( bli_obj_is_real( &z ) ) { + bli_setsc( alpv.real, 0.0, &alpha1 ); + bli_setsc( betv.real, 0.0, &alpha2 ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha1 ); + bli_setsc( betv.real, (betv.real/1.2), &alpha2 ); + } + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_vobj_randomize( params, TRUE, &y ); + libblis_test_vobj_randomize( params, TRUE, &z ); + } else { + int32_t xx = (int32_t)alpv.real; + int32_t yy = (int32_t)betv.real; + if ( bli_obj_is_real( &z ) ) { + bli_setsc( (double)xx, 0.0, &alpha1 ); + bli_setsc( (double)yy, 0.0, &alpha2 ); + } + else { + int32_t ac = (int32_t)(xx/0.8); + int32_t bc = (int32_t)(yy/1.0); + bli_setsc( (double)xx, (double)ac, &alpha1 ); + bli_setsc( (double)yy, (double)bc, &alpha2 ); + } + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + libblis_test_vobj_irandomize( params, &z ); + } + + bli_copyv( &z, &z_save ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + bli_obj_set_conj( conjy, &y ); + + libblis_test_axpy2v_impl( iface, &alpha1, &alpha2, &x, &y, &z, cntx); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[2], m, &r ); + + resid = libblis_test_bitrp_axpy2v( params, iface, &alpha1, + &alpha2, &x, &y, &z, cntx, &z_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_axpy2v( params, &alpha1, &alpha2, &x, &y, &z, &z_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &z, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &z ); + libblis_test_obj_free( &z_save ); + + return abs(resid); +} + +void libblis_test_axpy2v_impl ( + iface_t iface, + obj_t* alpha1, + obj_t* alpha2, + obj_t* x, + obj_t* y, + obj_t* z, + cntx_t* cntx +){ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_axpy2v_ex( alpha1, alpha2, x, y, z, cntx, NULL ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_axpy2v_check ( + test_params_t* params, + obj_t* alpha1, + obj_t* alpha2, + obj_t* x, + obj_t* y, + obj_t* z, + obj_t* z_orig +) { + num_t dt = bli_obj_dt( z ); + num_t dt_real = bli_obj_dt_proj_to_real( z ); + + dim_t m = bli_obj_vector_dim( z ); + + obj_t x_temp, y_temp, z_temp; + obj_t norm; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is randomized. + // - y is randomized. + // - z_orig is randomized. + // Note: + // - alpha1, alpha2 should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // z := z_orig + alpha1 * conjx(x) + alpha2 * conjy(y) + // + // is functioning correctly if + // + // normfv( z - v ) + // + // is negligible, where v contains z as computed by two calls to axpyv. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &x_temp ); + bli_obj_create( dt, m, 1, 0, 0, &y_temp ); + bli_obj_create( dt, m, 1, 0, 0, &z_temp ); + + bli_copyv( x, &x_temp ); + bli_copyv( y, &y_temp ); + bli_copyv( z_orig, &z_temp ); + + bli_scalv( alpha1, &x_temp ); + bli_scalv( alpha2, &y_temp ); + bli_addv( &x_temp, &z_temp ); + bli_addv( &y_temp, &z_temp ); + + bli_subv( &z_temp, z ); + bli_normfv( z, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + bli_obj_free( &y_temp ); + bli_obj_free( &z_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_axpy2v.h b/gtestsuite/src/test_axpy2v.h new file mode 100644 index 000000000..4400a5c68 --- /dev/null +++ b/gtestsuite/src/test_axpy2v.h @@ -0,0 +1,19 @@ +#ifndef TEST_AXPY2V_H +#define TEST_AXPY2V_H + +#include "blis_test.h" + +double libblis_test_iaxpy2v_check + ( + test_params_t* params, + obj_t* alphax, + obj_t* alphay, + obj_t* x, + obj_t* y, + obj_t* z, + obj_t* z_orig + ); + +double libblis_check_nan_axpy2v( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_AXPY2V_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_axpyf.cpp b/gtestsuite/src/test_axpyf.cpp new file mode 100644 index 000000000..90fcf4127 --- /dev/null +++ b/gtestsuite/src/test_axpyf.cpp @@ -0,0 +1,268 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpyf.h" + +// Local prototypes. +void libblis_test_axpyf_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_axpyf_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* y, + cntx_t* cntx +); + +double libblis_test_axpyf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* y, + obj_t* y_orig +); + +double libblis_ref_axpyf ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_axpyf_check( params, alpha, a, x, y, y_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iaxpyf_check( params, alpha, a, x, y, y_orig ); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_axpyf( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* y, + cntx_t* cntx, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_axpyf_impl( iface, alpha, a, x, r, cntx ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_axpyf ( + test_params_t* params, + test_op_t* op, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +) { + num_t datatype; + dim_t m, b_n; + conj_t conja, conjx; + obj_t alpha, a, x, y; + obj_t y_save; + cntx_t* cntx; + double resid = 0.0; + + // Query a context. + cntx = bli_gks_query_cntx(); + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Query the operation's fusing factor for the current datatype. + b_n = bli_cntx_get_blksz_def_dt( datatype, BLIS_AF, cntx ); + + // Store the fusing factor so that the driver can retrieve the value + // later when printing results. + op->dim_aux[0] = b_n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conja ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, b_n, &a ); + libblis_test_vobj_create( params, datatype, sc_str[1], b_n, &x ); + libblis_test_vobj_create( params, datatype, sc_str[2], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[2], m, &y_save ); + + // Set alpha. + if ( bli_obj_is_real( &y ) ) { + bli_setsc( -1.0, 0.0, &alpha ); + } + else { + bli_setsc( 0.0, -1.0, &alpha ); + } + + // Randomize A, x, and y, and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_mobj_randomize( params, FALSE, &a ); + libblis_test_vobj_randomize( params, FALSE, &x ); + libblis_test_vobj_randomize( params, FALSE, &y ); + } else { + libblis_test_mobj_irandomize( params, &a ); + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + + bli_copyv( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conja, &a ); + bli_obj_set_conj( conjx, &x ); + + libblis_test_axpyf_impl( iface, &alpha, &a, &x, &y, cntx ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[2], m, &r ); + + resid = libblis_test_bitrp_axpyf( params, iface, &alpha, &a, + &x, &y, cntx, &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_axpyf( params, &alpha, &a, &x, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_axpyf_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* y, + cntx_t* cntx +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_axpyf_ex( alpha, a, x, y, cntx, NULL ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_axpyf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( y ); + dim_t b_n = bli_obj_width( a ); + + dim_t i; + + obj_t a1, chi1, v; + obj_t alpha_chi1; + obj_t norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is randomized. + // - x is randomized. + // - y is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := y_orig + alpha * conja(A) * conjx(x) + // + // is functioning correctly if + // + // normfv( y - v ) + // + // is negligible, where v contains y as computed by repeated calls to + // axpyv. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + bli_obj_scalar_init_detached( dt, &alpha_chi1 ); + + bli_obj_create( dt, m, 1, 0, 0, &v ); + + bli_copyv( y_orig, &v ); + + for ( i = 0; i < b_n; ++i ) { + bli_acquire_mpart_l2r( BLIS_SUBPART1, i, 1, a, &a1 ); + bli_acquire_vpart_f2b( BLIS_SUBPART1, i, 1, x, &chi1 ); + + bli_copysc( &chi1, &alpha_chi1 ); + bli_mulsc( alpha, &alpha_chi1 ); + + bli_axpyv( &alpha_chi1, &a1, &v ); + } + + bli_subv( y, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &v ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_axpyf.h b/gtestsuite/src/test_axpyf.h new file mode 100644 index 000000000..6b7532143 --- /dev/null +++ b/gtestsuite/src/test_axpyf.h @@ -0,0 +1,18 @@ +#ifndef TEST_AXPYF_H +#define TEST_AXPYF_H + +#include "blis_test.h" + +double libblis_test_iaxpyf_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_axpyf( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_AXPYF_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_axpym.cpp b/gtestsuite/src/test_axpym.cpp new file mode 100644 index 000000000..e48749c82 --- /dev/null +++ b/gtestsuite/src/test_axpym.cpp @@ -0,0 +1,232 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpym.h" + +// Local prototypes. +void libblis_test_axpym_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_axpym_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y +); + +double libblis_test_axpym_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_save +); + +double libblis_ref_axpym( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_axpym_check( params, alpha, x, y, y_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iaxpym_check( params, alpha, x, y, y_orig); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_axpym( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( y_orig, r ); + libblis_test_axpym_impl( iface, alpha, x, r ); + resid = libblis_test_bitrp_matrix(y, r, dt); + } + return resid; +} + +double libblis_test_op_axpym ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m, n; + trans_t transx; + obj_t alpha, x, y; + obj_t y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_trans( pc_str[0], &transx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transx, + sc_str[0], m, n, &x ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &y ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &y_save ); + + // Set alpha. + if ( bli_obj_is_real( &y ) ) + bli_setsc( -2.0, 0.0, &alpha ); + else + bli_setsc( 0.0, -2.0, &alpha ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Randomize and save y. + libblis_test_mobj_randomize( params, FALSE, &x ); + libblis_test_mobj_randomize( params, FALSE, &y ); + } + else { + libblis_test_mobj_irandomize( params, &x ); + libblis_test_mobj_irandomize( params, &y ); + } + + bli_copym( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conjtrans( transx, &x ); + + libblis_test_axpym_impl( iface, &alpha, &x, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + + resid = libblis_test_bitrp_axpym( params, iface, &alpha, &x, + &y, &y_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_axpym( params, &alpha, &x, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_axpym_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y +){ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_axpym( alpha, x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_axpym_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_length( y ); + dim_t n = bli_obj_width( y ); + + obj_t x_temp, y_temp; + obj_t norm; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is randomized. + // - y_orig is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := y_orig + alpha * conjx(x) + // + // is functioning correctly if + // + // normfm( y - ( y_orig + alpha * conjx(x) ) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, n, 0, 0, &x_temp ); + bli_obj_create( dt, m, n, 0, 0, &y_temp ); + + bli_copym( x, &x_temp ); + bli_copym( y_orig, &y_temp ); + + bli_scalm( alpha, &x_temp ); + bli_addm( &x_temp, &y_temp ); + + bli_subm( &y_temp, y ); + bli_normfm( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + bli_obj_free( &y_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_axpym.h b/gtestsuite/src/test_axpym.h new file mode 100644 index 000000000..54d0bb3c2 --- /dev/null +++ b/gtestsuite/src/test_axpym.h @@ -0,0 +1,17 @@ +#ifndef TEST_AXPYM_H +#define TEST_AXPYM_H + +#include "blis_test.h" + +double libblis_test_iaxpym_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_axpym( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_AXPYM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_axpyv.cpp b/gtestsuite/src/test_axpyv.cpp new file mode 100644 index 000000000..dc68abdaa --- /dev/null +++ b/gtestsuite/src/test_axpyv.cpp @@ -0,0 +1,357 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_axpyv.h" + +// Local prototypes. +void libblis_test_axpyv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_axpyv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y +); + +double libblis_test_axpyv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +); + +double cblas_axpyv( + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_saxpy( m, *alphap, xp, incx, yp, incy ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_daxpy( m, *alphap, xp, incx, yp, incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cblas_caxpy( m, alphap, xp, incx, yp, incy ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + cblas_zaxpy( m, alphap, xp, incx, yp, incy ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_axpyv( + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + saxpy_( &m, alphap, xp, &incx, yp, &incy ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + daxpy_( &m, alphap, xp, &incx, yp, &incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + caxpy_( &m, alphap, xp, &incx, yp, &incy ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + zaxpy_( &m, alphap, xp, &incx, yp, &incy ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_axpyv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_axpyv_impl( iface, alpha, x, y ); + } + else { /*CLBAS || BLAS */ + dim_t m = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + + if(bli_obj_has_conj(x)) { + conjugate_tensor(x, dt); + bli_obj_set_conj( BLIS_NO_CONJUGATE, x ); + } + + if( params->api == API_CBLAS ) { + cblas_axpyv( m, alpha, x, incx, y, incy, dt ); + } else { + blas_axpyv( m, alpha, x, incx, y, incy, dt ); + } + } + return ; +} + +double libblis_ref_axpyv( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_axpyv_check( params, alpha, x, y, y_save ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iaxpyv_check( params, alpha, x, y, y_save ); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_axpyv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_save, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_save, r ); + libblis_test_axpyv_impl( iface, alpha, x, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_axpyv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + conj_t conjx; + obj_t alpha, x, y; + obj_t y_save; + double resid = 0.0; + obj_t xx; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[0], m, &xx ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y_save ); + + // Set alpha. + if ( bli_obj_is_real( &y ) ) + bli_setsc( -2.0, 0.0, &alpha ); + else + bli_setsc( 0.0, -2.0, &alpha ); + + // Randomize x and y, and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, FALSE, &x ); + libblis_test_vobj_randomize( params, FALSE, &y ); + } else { + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + + bli_copyv( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + + bli_copyv( &x, &xx ); + + libblis_api_axpyv( params, iface, &alpha, &xx, &y, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[1], m, &r ); + + resid = libblis_test_bitrp_axpyv( params, iface, &alpha, &x, + &y, &y_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_axpyv( params, &alpha, &x, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_axpyv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_axpyv( alpha, x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_axpyv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( y ); + + obj_t x_temp, y_temp; + obj_t norm; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is randomized. + // - y_orig is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := y_orig + alpha * conjx(x) + // + // is functioning correctly if + // + // normfv( y - ( y_orig + alpha * conjx(x) ) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &x_temp ); + bli_obj_create( dt, m, 1, 0, 0, &y_temp ); + + bli_copyv( x, &x_temp ); + bli_copyv( y_orig, &y_temp ); + + bli_scalv( alpha, &x_temp ); + bli_addv( &x_temp, &y_temp ); + + bli_subv( &y_temp, y ); + bli_normfv( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + bli_obj_free( &y_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_axpyv.h b/gtestsuite/src/test_axpyv.h new file mode 100644 index 000000000..783fd83a4 --- /dev/null +++ b/gtestsuite/src/test_axpyv.h @@ -0,0 +1,17 @@ +#ifndef TEST_AXPYV_H +#define TEST_AXPYV_H + +#include "blis_test.h" + +double libblis_test_iaxpyv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_axpyv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_AXPYV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_copym.cpp b/gtestsuite/src/test_copym.cpp new file mode 100644 index 000000000..b06e320a2 --- /dev/null +++ b/gtestsuite/src/test_copym.cpp @@ -0,0 +1,189 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_copym.h" + +// Local prototypes. +void libblis_test_copym_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_copym_impl ( + iface_t iface, + obj_t* x, + obj_t* y +); + +double libblis_test_copym_check ( + test_params_t* params, + obj_t* x, + obj_t* y +); + +double libblis_ref_copym( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_copym_check( params, x, y ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_icopym_check( params, x, y, y_save ); + } + else { + resid = libblis_test_matrix_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_copym( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_setm( &BLIS_ONE, r ); + libblis_test_copym_impl( iface, x, r ); + resid = libblis_test_bitrp_matrix(y, r, dt); + } + return resid; +} + +double libblis_test_op_copym ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + dim_t m, n; + trans_t transx; + obj_t x, y, y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_trans( pc_str[0], &transx ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transx, + sc_str[0], m, n, &x ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, n, &y ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, n, &y_save ); + + // Randomize x and set y to one. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_mobj_randomize( params, FALSE, &x ); + } + else { + libblis_test_mobj_irandomize( params, &x ); + } + + bli_setm( &BLIS_ONE, &y ); + + // Apply the parameters. + bli_obj_set_conjtrans( transx, &x ); + + bli_copym( &y, &y_save ); + + libblis_test_copym_impl( iface, &x, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + resid = libblis_test_bitrp_copym( params, iface, &x, &y, &y_save, datatype); + } + else { + resid = libblis_ref_copym( params, &x, &y, &y_save); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_copym_impl( + iface_t iface, + obj_t* x, + obj_t* y +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_copym( x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_copym_check( + test_params_t* params, + obj_t* x, + obj_t* y +) { + num_t dt_real = bli_obj_dt_proj_to_real( x ); + + obj_t norm_y_r; + + double junk; + + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // + // Under these conditions, we assume that the implementation for + // + // y := conjx(x) + // + // is functioning correctly if + // + // normfm( y - conjx(x) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm_y_r ); + + bli_subm( x, y ); + + bli_normfm( y, &norm_y_r ); + + bli_getsc( &norm_y_r, &resid, &junk ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_copym.h b/gtestsuite/src/test_copym.h new file mode 100644 index 000000000..ac970f4fd --- /dev/null +++ b/gtestsuite/src/test_copym.h @@ -0,0 +1,16 @@ +#ifndef TEST_COPYM_H +#define TEST_COPYM_H + +#include "blis_test.h" + +double libblis_test_icopym_check + ( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_copym( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_COPYM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_copyv.cpp b/gtestsuite/src/test_copyv.cpp new file mode 100644 index 000000000..238165530 --- /dev/null +++ b/gtestsuite/src/test_copyv.cpp @@ -0,0 +1,306 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_copyv.h" + +// Local prototypes. +void libblis_test_copyv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_copyv_impl ( + iface_t iface, + obj_t* x, + obj_t* y +); + +double libblis_test_copyv_check ( + test_params_t* params, + obj_t* x, + obj_t* y +); + +double cblas_copyv( + f77_int m, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_scopy( m, xp, incx, yp, incy ); + break; + } + case BLIS_DOUBLE : + { + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_dcopy( m, xp, incx, yp, incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cblas_ccopy( m, xp, incx, yp, incy ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + cblas_zcopy( m, xp, incx, yp, incy ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_copyv( + f77_int m, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + scopy_( &m, xp, &incx, yp, &incy ); + break; + } + case BLIS_DOUBLE : + { + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + dcopy_( &m, xp, &incx, yp, &incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + ccopy_( &m, xp, &incx, yp, &incy ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + zcopy_( &m, xp, &incx, yp, &incy ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_copyv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_copyv_impl( iface, x, y ); + } + else { /*CLBAS || BLAS */ + dim_t m = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + + if(bli_obj_has_conj(x)) { + conjugate_tensor(x, dt); + bli_obj_set_conj( BLIS_NO_CONJUGATE, x ); + } + + if( params->api == API_CBLAS ) { + cblas_copyv( m, x, incx, y, incy, dt ); + } else { + blas_copyv( m, x, incx, y, incy, dt ); + } + } + return ; +} + +double libblis_ref_copyv( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_copyv_check( params, x, y ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_icopyv_check( params, x, y, y_save ); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_copyv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_setv( &BLIS_ONE, r ); + libblis_test_copyv_impl( iface, x, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_copyv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + dim_t m; + conj_t conjx; + obj_t x, y, y_save; + double resid = 0.0; + obj_t xx; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[0], m, &xx ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y_save ); + + + // Randomize x and set y to one. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, FALSE, &x ); + } + else { + libblis_test_vobj_irandomize( params, &x ); + } + + bli_setv( &BLIS_ONE, &y ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + + bli_copyv( &y, &y_save ); + + bli_copyv( &x, &xx ); + + libblis_api_copyv( params, iface, &xx, &y, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + resid = libblis_test_bitrp_copyv( params, iface, &x, &y, &y_save, datatype); + } + else { + resid = libblis_ref_copyv( params, &x, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_copyv_impl ( + iface_t iface, + obj_t* x, + obj_t* y +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_copym( x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_copyv_check ( + test_params_t* params, + obj_t* x, + obj_t* y +) { + num_t dt_real = bli_obj_dt_proj_to_real( x ); + + obj_t norm_y_r; + + double junk; + + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // + // Under these conditions, we assume that the implementation for + // + // y := conjx(x) + // + // is functioning correctly if + // + // normfv( y - conjx(x) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm_y_r ); + + bli_subv( x, y ); + + bli_normfv( y, &norm_y_r ); + + bli_getsc( &norm_y_r, &resid, &junk ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_copyv.h b/gtestsuite/src/test_copyv.h new file mode 100644 index 000000000..6ba8f163a --- /dev/null +++ b/gtestsuite/src/test_copyv.h @@ -0,0 +1,16 @@ +#ifndef TEST_COPYV_H +#define TEST_COPYV_H + +#include "blis_test.h" + +double libblis_test_icopyv_check + ( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_copyv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_COPYV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_dotaxpyv.cpp b/gtestsuite/src/test_dotaxpyv.cpp new file mode 100644 index 000000000..71c31709b --- /dev/null +++ b/gtestsuite/src/test_dotaxpyv.cpp @@ -0,0 +1,306 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotaxpyv.h" + +// Local prototypes. +void libblis_test_dotaxpyv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_dotaxpyv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* xt, + obj_t* x, + obj_t* y, + obj_t* rho, + obj_t* z, + cntx_t* cntx +); + +double libblis_test_dotaxpyv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* xt, + obj_t* x, + obj_t* y, + obj_t* rho, + obj_t* z, + obj_t* z_orig +); + +double libblis_ref_dotaxpyv ( + test_params_t* params, + obj_t* alpha, + obj_t* xt, + obj_t* x, + obj_t* y, + obj_t* rho, + obj_t* z, + obj_t* z_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_dotaxpyv_check( params, alpha, xt, x, y, rho, z, z_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_idotaxpyv_check( params, alpha, xt, x, y, rho, z, z_orig ); + } + else { + resid = libblis_test_vector_check(params, z); + } + } + return resid; +} + +double libblis_test_bitrp_dotxaxpyf( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* xt, + obj_t* x, + obj_t* y, + obj_t* rho, + obj_t* z, + obj_t* z_orig, + cntx_t* cntx, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + obj_t rh; + + for(i = 0; i < n_repeats; i++) { + bli_copysc( &BLIS_MINUS_ONE, &rh ); + bli_copyv( z_orig, r ); + libblis_test_dotaxpyv_impl( iface, alpha, xt, x, y, rho, r, cntx ); + resid = libblis_test_bitrp_vector(&rh, rho, dt); + resid += libblis_test_bitrp_vector(z, r, dt); + } + + return resid; +} + +double libblis_test_op_dotaxpyv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +) { + num_t datatype; + dim_t m; + conj_t conjxt, conjx, conjy; + conj_t conjconjxty; + obj_t alpha, xt, x, y, rho, z; + obj_t z_save; + cntx_t* cntx; + double resid = 0.0; + + // Query a context. + cntx = bli_gks_query_cntx(); + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjxt ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjx ); + bli_param_map_char_to_blis_conj( pc_str[2], &conjy ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &rho ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[2], m, &z ); + libblis_test_vobj_create( params, datatype, sc_str[2], m, &z_save ); + + // Randomize x and z, and save z. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Set alpha. + if ( bli_obj_is_real( &z ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + } + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_vobj_randomize( params, TRUE, &z ); + } else { + int32_t xx = (int32_t)alpv.real; + if ( bli_obj_is_real( &z ) ) { + bli_setsc( (double)xx, 0.0, &alpha ); + } + else { + int32_t ac = (int32_t)(xx/0.8); + bli_setsc( (double)xx, (double)ac, &alpha ); + } + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &z ); + } + + bli_copyv( &z, &z_save ); + + // Create an alias to x for xt. (Note that it doesn't actually need to be + // transposed.) + bli_obj_alias_to( &x, &xt ); + + // Determine whether to make a copy of x with or without conjugation. + // + // conjx conjy ~conjx^conjy y is initialized as + // n n c y = conj(x) + // n c n y = x + // c n n y = x + // c c c y = conj(x) + // + conjconjxty = bli_apply_conj( conjxt, conjy ); + conjconjxty = bli_conj_toggled( conjconjxty ); + bli_obj_set_conj( conjconjxty, &xt ); + bli_copyv( &xt, &y ); + + // Apply the parameters. + bli_obj_set_conj( conjxt, &xt ); + bli_obj_set_conj( conjx, &x ); + bli_obj_set_conj( conjy, &y ); + + libblis_test_dotaxpyv_impl( iface, &alpha, &xt, &x, &y, &rho, &z, cntx ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[2], m, &r ); + + resid = libblis_test_bitrp_dotxaxpyf(params, iface, &alpha, + &xt, &x, &y, &rho, &z, &z_save, cntx, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_dotaxpyv( params, &alpha, &xt, + &x, &y, &rho, &z, &z_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &z, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &z ); + libblis_test_obj_free( &z_save ); + + return abs(resid); +} + +void libblis_test_dotaxpyv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* xt, + obj_t* x, + obj_t* y, + obj_t* rho, + obj_t* z, + cntx_t* cntx +){ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_dotaxpyv_ex( alpha, xt, x, y, rho, z, cntx, NULL ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_dotaxpyv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* xt, + obj_t* x, + obj_t* y, + obj_t* rho, + obj_t* z, + obj_t* z_orig +) { + num_t dt = bli_obj_dt( z ); + num_t dt_real = bli_obj_dt_proj_to_real( z ); + + dim_t m = bli_obj_vector_dim( z ); + + obj_t rho_temp; + + obj_t z_temp; + obj_t norm_z; + + double resid1, resid2; + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - y is randomized. + // - z_orig is randomized. + // - xt is an alias to x. + // Note: + // - alpha should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // rho := conjxt(x^T) conjy(y) + // z := z_orig + alpha * conjx(x) + // + // is functioning correctly if + // + // ( rho - rho_temp ) + // + // and + // + // normfv( z - z_temp ) + // + // are negligible, where rho_temp and z_temp contain rho and z as + // computed by dotv and axpyv, respectively. + // + + bli_obj_scalar_init_detached( dt, &rho_temp ); + bli_obj_scalar_init_detached( dt_real, &norm_z ); + + bli_obj_create( dt, m, 1, 0, 0, &z_temp ); + bli_copyv( z_orig, &z_temp ); + + + bli_dotv( xt, y, &rho_temp ); + bli_axpyv( alpha, x, &z_temp ); + + + bli_subsc( rho, &rho_temp ); + bli_getsc( &rho_temp, &resid1, &junk ); + + bli_subv( &z_temp, z ); + bli_normfv( z, &norm_z ); + bli_getsc( &norm_z, &resid2, &junk ); + + resid = bli_fmaxabs( resid1, resid2 ); + + bli_obj_free( &z_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_dotaxpyv.h b/gtestsuite/src/test_dotaxpyv.h new file mode 100644 index 000000000..f6cb66832 --- /dev/null +++ b/gtestsuite/src/test_dotaxpyv.h @@ -0,0 +1,20 @@ +#ifndef TEST_DOTAXPYV_H +#define TEST_DOTAXPYV_H + +#include "blis_test.h" + +double libblis_test_idotaxpyv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* xt, + obj_t* x, + obj_t* y, + obj_t* rho_orig, + obj_t* z, + obj_t* z_orig + ); + +double libblis_check_nan_dotaxpyv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_DOTAXPYV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_dotv.cpp b/gtestsuite/src/test_dotv.cpp new file mode 100644 index 000000000..d35153289 --- /dev/null +++ b/gtestsuite/src/test_dotv.cpp @@ -0,0 +1,369 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotv.h" + +// Local prototypes. +void libblis_test_dotv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_dotv_impl ( + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* rho +); + +double libblis_test_dotv_check ( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* rho +); + +double cblas_dotv( + f77_int m, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + obj_t* rho, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + float* resp = (float*) bli_obj_buffer( rho ); + *resp = cblas_sdot( m, xp, incx, yp, incy ); + break; + } + case BLIS_DOUBLE : + { + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + double* resp = (double*) bli_obj_buffer( rho ); + *resp = cblas_ddot( m, xp, incx, yp, incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + scomplex* resp = (scomplex*) bli_obj_buffer( rho ); + cblas_cdotu_sub( m, xp, incx, yp, incy, resp ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + dcomplex* resp = (dcomplex*) bli_obj_buffer( rho ); + cblas_zdotu_sub( m, xp, incx, yp, incy, resp ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_dotv( + f77_int m, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + obj_t* rho, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + float* resp = (float*) bli_obj_buffer( rho ); + *resp = sdot_( &m, xp, &incx, yp, &incy ); + break; + } + case BLIS_DOUBLE : + { + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + double* resp = (double*) bli_obj_buffer( rho ); + *resp = ddot_( &m, xp, &incx, yp, &incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + scomplex* resp = (scomplex*) bli_obj_buffer( rho ); +#ifdef BLIS_DISABLE_COMPLEX_RETURN_INTEL + *resp = cdotu_( &m, xp, &incx, yp, &incy ); +#else + cdotu_( resp, &m, xp, &incx, yp, &incy ); +#endif // BLIS_DISABLE_COMPLEX_RETURN_INTEL ... + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + dcomplex* resp = (dcomplex*) bli_obj_buffer( rho ); +#ifdef BLIS_DISABLE_COMPLEX_RETURN_INTEL + *resp = zdotu_( &m, xp, &incx, yp, &incy ); +#else + zdotu_( resp, &m, xp, &incx, yp, &incy ); +#endif // BLIS_DISABLE_COMPLEX_RETURN_INTEL ... + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_dotv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* rho, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_dotv_impl( iface, x, y, rho ); + } + else { /*CLBAS || BLAS */ + dim_t m = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + + if(bli_obj_has_conj(x)) { + conjugate_tensor(x, dt); + bli_obj_set_conj( BLIS_NO_CONJUGATE, x ); + } + + if(bli_obj_has_conj(y)) { + conjugate_tensor(y, dt); + bli_obj_set_conj( BLIS_NO_CONJUGATE, y ); + } + + if( params->api == API_CBLAS ) { + cblas_dotv( m, x, incx, y, incy, rho, dt ); + } else { + blas_dotv( m, x, incx, y, incy, rho, dt ); + } + } + return ; +} + +double libblis_ref_dotv( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* rho +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_dotv_check( params, x, y, rho ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_idotv_check( params, x, y, rho ); + } + else { + resid = libblis_test_vector_check(params, rho); + } + } + return resid; +} + +double libblis_test_bitrp_dotv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* rho, + obj_t* rh, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copysc( &BLIS_MINUS_ONE, rh ); + libblis_test_dotv_impl( iface, x, y, rh ); + resid = libblis_test_bitrp_vector(rho, rh, dt); + } + return resid; +} + +double libblis_test_op_dotv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + dim_t m; + conj_t conjx, conjy, conjconjxy; + obj_t x, y, rho; + double resid = 0.0; + obj_t xx, yy; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjy ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &rho ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[0], m, &xx ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &yy ); + + // Randomize x. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, TRUE, &x ); + } else { + libblis_test_vobj_irandomize( params, &x ); + } + + // Determine whether to make a copy of x with or without conjugation. + // conjx conjy ~conjx^conjy y is initialized as + // n n c y = conj(x) + // n c n y = x + // c n n y = x + // c c c y = conj(x) + + conjconjxy = bli_apply_conj( conjx, conjy ); + conjconjxy = bli_conj_toggled( conjconjxy ); + bli_obj_set_conj( conjconjxy, &x ); + bli_copyv( &x, &y ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + bli_obj_set_conj( conjy, &y ); + + bli_copysc( &BLIS_MINUS_ONE, &rho ); + + bli_copyv( &x, &xx ); + bli_copyv( &y, &yy ); + + libblis_api_dotv( params, iface, &xx, &yy, &rho, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + bli_obj_scalar_init_detached( datatype, &r ); + + resid = libblis_test_bitrp_dotv( params, iface, &x, &y, &rho, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_dotv( params, &x, &y, &rho ); + } +#endif + + // Zero out performance and residual if output scalar is empty. + libblis_test_check_empty_problem( &rho, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &yy ); + + return abs(resid); +} + +void libblis_test_dotv_impl ( + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* rho +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_dotv( x, y, rho ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_dotv_check ( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* rho +){ + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + obj_t rho_r, rho_i; + obj_t norm_x, norm_xy; + + double zero; + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - y is equal to conj(conjx(conjy(x))). + // + // Under these conditions, we assume that the implementation for + // + // rho := conjx(x^T) conjy(y) + // + // is functioning correctly if + // + // sqrtsc( rho.real ) - normfv( x ) + // + // and + // + // rho.imag + // + // are negligible. + // + + bli_obj_scalar_init_detached( dt_real, &rho_r ); + bli_obj_scalar_init_detached( dt_real, &rho_i ); + bli_obj_scalar_init_detached( dt_real, &norm_x ); + bli_obj_scalar_init_detached( dt_real, &norm_xy ); + + bli_normfv( x, &norm_x ); + + bli_unzipsc( rho, &rho_r, &rho_i ); + + bli_sqrtsc( &rho_r, &norm_xy ); + + bli_subsc( &norm_x, &norm_xy ); + bli_getsc( &norm_xy, &resid, &junk ); + bli_getsc( &rho_i, &zero, &junk ); + + resid = bli_fmaxabs( resid, zero ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_dotv.h b/gtestsuite/src/test_dotv.h new file mode 100644 index 000000000..93849d020 --- /dev/null +++ b/gtestsuite/src/test_dotv.h @@ -0,0 +1,16 @@ +#ifndef TEST_DOTV_H +#define TEST_DOTV_H + +#include "blis_test.h" + +double libblis_test_idotv_check + ( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* rho + ); + +double libblis_check_nan_dotv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_DOTV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_dotxaxpyf.cpp b/gtestsuite/src/test_dotxaxpyf.cpp new file mode 100644 index 000000000..598c6d7ae --- /dev/null +++ b/gtestsuite/src/test_dotxaxpyf.cpp @@ -0,0 +1,371 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotxaxpyf.h" + +// Local prototypes. +void libblis_test_dotxaxpyf_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_dotxaxpyf_impl ( + iface_t iface, + obj_t* alpha, + obj_t* at, + obj_t* a, + obj_t* w, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* z, + cntx_t* cntx +); + +double libblis_test_dotxaxpyf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* at, + obj_t* a, + obj_t* w, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* z, + obj_t* y_orig, + obj_t* z_orig +); + +double libblis_ref_dotxaxpyf ( + test_params_t* params, + obj_t* alpha, + obj_t* at, + obj_t* a, + obj_t* w, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* z, + obj_t* y_orig, + obj_t* z_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_dotxaxpyf_check( params, alpha, at, a, w, x, + beta, y, z, y_orig, z_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_idotxaxpyf_check( params, alpha, at, a, w, x, + beta, y, z, y_orig, z_orig); + } + else { + resid = libblis_test_vector_check(params, y); + resid = libblis_test_vector_check(params, z); + } + } + return resid; +} + +double libblis_test_bitrp_dotxaxpyf( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* at, + obj_t* a, + obj_t* w, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* z, + cntx_t* cntx, + obj_t* y_orig, + obj_t* z_orig, + obj_t* r, + obj_t* v, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + bli_copyv( z_orig, v ); + libblis_test_dotxaxpyf_impl( iface, alpha, at, a, w, x, + beta, r, v, cntx ); + resid = libblis_test_bitrp_vector(y, r, dt); + resid += libblis_test_bitrp_vector(z, v, dt); + } + return resid; +} + +double libblis_test_op_dotxaxpyf ( + test_params_t* params, + test_op_t* op, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +) { + num_t datatype; + dim_t m, b_n; + conj_t conjat, conja, conjw, conjx; + obj_t alpha, at, a, w, x, beta, y, z; + obj_t y_save, z_save; + cntx_t* cntx; + double resid = 0.0; + + // Query a context. + cntx = bli_gks_query_cntx(); + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Query the operation's fusing factor for the current datatype. + b_n = bli_cntx_get_blksz_def_dt( datatype, BLIS_XF, cntx ); + + // Store the fusing factor so that the driver can retrieve the value + // later when printing results. + op->dim_aux[0] = b_n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjat ); + bli_param_map_char_to_blis_conj( pc_str[1], &conja ); + bli_param_map_char_to_blis_conj( pc_str[2], &conjw ); + bli_param_map_char_to_blis_conj( pc_str[3], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, b_n, &a ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &w ); + libblis_test_vobj_create( params, datatype, sc_str[2], b_n, &x ); + libblis_test_vobj_create( params, datatype, sc_str[3], b_n, &y ); + libblis_test_vobj_create( params, datatype, sc_str[3], b_n, &y_save ); + libblis_test_vobj_create( params, datatype, sc_str[4], m, &z ); + libblis_test_vobj_create( params, datatype, sc_str[4], m, &z_save ); + + // Randomize A, w, x, y, and z, and save y and z. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Set alpha. + if ( bli_obj_is_real( &y ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + bli_setsc( betv.real, (betv.real/1.2), &beta ); + } + libblis_test_mobj_randomize( params, FALSE, &a ); + libblis_test_vobj_randomize( params, FALSE, &w ); + libblis_test_vobj_randomize( params, FALSE, &x ); + libblis_test_vobj_randomize( params, FALSE, &y ); + libblis_test_vobj_randomize( params, FALSE, &z ); + } else { + int32_t xx = (int32_t)alpv.real; + int32_t yy = (int32_t)betv.real; + if ( bli_obj_is_real( &z ) ) { + bli_setsc( (double)xx, 0.0, &alpha ); + bli_setsc( (double)yy, 0.0, &beta ); + } + else { + int32_t ac = (int32_t)(xx/0.8); + int32_t bc = (int32_t)(yy/1.0); + bli_setsc( (double)xx, (double)ac, &alpha ); + bli_setsc( (double)yy, (double)bc, &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_vobj_irandomize( params, &w ); + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + libblis_test_vobj_irandomize( params, &z ); + } + + bli_copyv( &y, &y_save ); + bli_copyv( &z, &z_save ); + + // Create an alias to a for at. (Note that it should NOT actually be + // marked for transposition since the transposition is part of the dotxf + // subproblem.) + bli_obj_alias_to( &a, &at ); + + // Apply the parameters. + bli_obj_set_conj( conjat, &at ); + bli_obj_set_conj( conja, &a ); + bli_obj_set_conj( conjw, &w ); + bli_obj_set_conj( conjx, &x ); + + libblis_test_dotxaxpyf_impl( iface, &alpha, &at, &a, &w, &x, + &beta, &y, &z, cntx ); +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r,v; + + libblis_test_vobj_create( params, datatype, sc_str[3], b_n, &r ); + + libblis_test_vobj_create( params, datatype, sc_str[4], m, &v ); + + resid = libblis_test_bitrp_dotxaxpyf(params, iface, &alpha, &at, &a, &w, + &x, &beta, &y, &z, cntx, &y_save, &z_save, &r, &v, datatype); + + bli_obj_free( &r ); + bli_obj_free( &v ); + } + else { + resid = libblis_ref_dotxaxpyf( params, &alpha, &at, &a, &w, &x, + &beta, &y, &z, &y_save, &z_save); + } +#endif + + // Zero out performance and residual if either output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + libblis_test_check_empty_problem( &z, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &w ); + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &z ); + libblis_test_obj_free( &y_save ); + libblis_test_obj_free( &z_save ); + + return abs(resid); +} + +void libblis_test_dotxaxpyf_impl ( + iface_t iface, + obj_t* alpha, + obj_t* at, + obj_t* a, + obj_t* w, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* z, + cntx_t* cntx +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_dotxaxpyf_ex( alpha, at, a, w, x, beta, y, z, cntx, NULL ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_dotxaxpyf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* at, + obj_t* a, + obj_t* w, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* z, + obj_t* y_orig, + obj_t* z_orig +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( z ); + dim_t b_n = bli_obj_vector_dim( y ); + + dim_t i; + + obj_t a1, chi1, psi1, v, q; + obj_t alpha_chi1; + obj_t norm; + + double resid1, resid2; + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - a is randomized. + // - w is randomized. + // - x is randomized. + // - y is randomized. + // - z is randomized. + // - at is an alias to a. + // Note: + // - alpha and beta should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := beta * y_orig + alpha * conjat(A^T) * conjw(w) + // z := z_orig + alpha * conja(A) * conjx(x) + // + // is functioning correctly if + // + // normfv( y - v ) + // + // and + // + // normfv( z - q ) + // + // are negligible, where v and q contain y and z as computed by repeated + // calls to dotxv and axpyv, respectively. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + bli_obj_scalar_init_detached( dt, &alpha_chi1 ); + + bli_obj_create( dt, b_n, 1, 0, 0, &v ); + bli_obj_create( dt, m, 1, 0, 0, &q ); + + bli_copyv( y_orig, &v ); + bli_copyv( z_orig, &q ); + + // v := beta * v + alpha * conjat(at) * conjw(w) + for ( i = 0; i < b_n; ++i ) { + bli_acquire_mpart_l2r( BLIS_SUBPART1, i, 1, at, &a1 ); + bli_acquire_vpart_f2b( BLIS_SUBPART1, i, 1, &v, &psi1 ); + + bli_dotxv( alpha, &a1, w, beta, &psi1 ); + } + + // q := q + alpha * conja(a) * conjx(x) + for ( i = 0; i < b_n; ++i ) { + bli_acquire_mpart_l2r( BLIS_SUBPART1, i, 1, a, &a1 ); + bli_acquire_vpart_f2b( BLIS_SUBPART1, i, 1, x, &chi1 ); + + bli_copysc( &chi1, &alpha_chi1 ); + bli_mulsc( alpha, &alpha_chi1 ); + + bli_axpyv( &alpha_chi1, &a1, &q ); + } + + + bli_subv( y, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid1, &junk ); + + bli_subv( z, &q ); + bli_normfv( &q, &norm ); + bli_getsc( &norm, &resid2, &junk ); + + + resid = bli_fmaxabs( resid1, resid2 ); + + bli_obj_free( &v ); + bli_obj_free( &q ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_dotxaxpyf.h b/gtestsuite/src/test_dotxaxpyf.h new file mode 100644 index 000000000..397899bf2 --- /dev/null +++ b/gtestsuite/src/test_dotxaxpyf.h @@ -0,0 +1,23 @@ +#ifndef TEST_DOTXAXPYF_H +#define TEST_DOTXAXPYF_H + +#include "blis_test.h" + +double libblis_test_idotxaxpyf_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* at, + obj_t* a, + obj_t* w, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* z, + obj_t* y_orig, + obj_t* z_orig + ); + +double libblis_check_nan_dotxaxpyf( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_DOTXAXPYF_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_dotxf.cpp b/gtestsuite/src/test_dotxf.cpp new file mode 100644 index 000000000..db286b920 --- /dev/null +++ b/gtestsuite/src/test_dotxf.cpp @@ -0,0 +1,291 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotxf.h" + +// Local prototypes. +void libblis_test_dotxf_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_dotxf_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + cntx_t* cntx +); + +double libblis_test_dotxf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +); + +double libblis_ref_dotxf ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_dotxf_check( params, alpha, a, x, beta, y, y_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_idotxf_check( params, alpha, a, x, beta, y, y_orig ); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + + +double libblis_test_bitrp_dotxf( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + cntx_t* cntx, + obj_t* r, + num_t dt +){ + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_dotxf_impl( iface, alpha, a, x, beta, r, cntx ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_dotxf ( + test_params_t* params, + test_op_t* op, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +) { + num_t datatype; + dim_t m, b_n; + conj_t conjat, conjx; + obj_t alpha, a, x, beta, y; + obj_t y_save; + + cntx_t* cntx; + double resid = 0.0; + + // Query a context. + cntx = bli_gks_query_cntx(); + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Query the operation's fusing factor for the current datatype. + b_n = bli_cntx_get_blksz_def_dt( datatype, BLIS_DF, cntx ); + + // Store the fusing factor so that the driver can retrieve the value + // later when printing results. + op->dim_aux[0] = b_n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjat ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, b_n, &a ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[2], b_n, &y ); + libblis_test_vobj_create( params, datatype, sc_str[2], b_n, &y_save ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Set alpha. + if ( bli_obj_is_real( &y ) ) { + bli_setsc( 1.2, 0.0, &alpha ); + bli_setsc( -1.0, 0.0, &beta ); + } + else { + bli_setsc( 1.2, 0.1, &alpha ); + bli_setsc( -1.0, -0.1, &beta ); + } + + // Randomize A, x, and y, and save y. + libblis_test_mobj_randomize( params, FALSE, &a ); + libblis_test_vobj_randomize( params, FALSE, &x ); + libblis_test_vobj_randomize( params, FALSE, &y ); + } + else { + int32_t xx = (int32_t) 1.0; + int32_t yy = (int32_t)-1.0; + if ( bli_obj_is_real( &y ) ) { + bli_setsc( (double)xx, 0.0, &alpha ); + bli_setsc( (double)yy, 0.0, &beta ); + } + else { + // For syrk, both alpha and beta may be complex since, unlike herk, + // C is symmetric in both the real and complex cases. + int32_t ac = (int32_t)(xx/0.8); + int32_t bc = (int32_t)(yy/1.0); + bli_setsc( (double)xx, (double)ac, &alpha ); + bli_setsc( (double)yy, (double)bc, &beta ); + } + + // Randomize A, x, and y, and save y. + libblis_test_mobj_irandomize( params, &a ); + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + + bli_copyv( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conjat, &a ); + bli_obj_set_conj( conjx, &x ); + + libblis_test_dotxf_impl( iface, &alpha, &a, &x, &beta, &y, cntx ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[2], b_n, &r ); + + resid = libblis_test_bitrp_dotxf( params, iface, &alpha, &a, &x, + &beta, &y, &y_save, cntx, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_dotxf( params, &alpha, &a, &x, &beta, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_dotxf_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + cntx_t* cntx +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_dotxf_ex( alpha, a, x, beta, y, cntx, NULL ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_dotxf_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t b_n = bli_obj_vector_dim( y ); + + dim_t i; + + obj_t a1, psi1, v; + obj_t norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is randomized. + // - x is randomized. + // - y is randomized. + // Note: + // - alpha and beta should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := beta * y_orig + alpha * conjat(A^T) * conjx(x) + // + // is functioning correctly if + // + // normfv( y - v ) + // + // is negligible, where v contains y as computed by repeated calls to + // dotxv. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, b_n, 1, 0, 0, &v ); + + bli_copyv( y_orig, &v ); + + for ( i = 0; i < b_n; ++i ) { + bli_acquire_mpart_l2r( BLIS_SUBPART1, i, 1, a, &a1 ); + bli_acquire_vpart_f2b( BLIS_SUBPART1, i, 1, &v, &psi1 ); + + bli_dotxv( alpha, &a1, x, beta, &psi1 ); + } + + bli_subv( y, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &v ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_dotxf.h b/gtestsuite/src/test_dotxf.h new file mode 100644 index 000000000..b6a69f65d --- /dev/null +++ b/gtestsuite/src/test_dotxf.h @@ -0,0 +1,19 @@ +#ifndef TEST_DOTXF_H +#define TEST_DOTXF_H + +#include "blis_test.h" + +double libblis_test_idotxf_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_dotxf( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_DOTXF_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_dotxv.cpp b/gtestsuite/src/test_dotxv.cpp new file mode 100644 index 000000000..f0bc316e1 --- /dev/null +++ b/gtestsuite/src/test_dotxv.cpp @@ -0,0 +1,262 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_dotxv.h" + +// Local prototypes. +void libblis_test_dotxv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_dotxv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* beta, + obj_t* rho +); + +double libblis_test_dotxv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* beta, + obj_t* rho, + obj_t* rho_orig +); + +double libblis_ref_dotxv( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* beta, + obj_t* rho, + obj_t* rho_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_dotxv_check( params, alpha, x, y, beta, rho, + rho_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_idotxv_check( params, alpha, x, y, beta, rho, rho_orig ); + } + else { + resid = libblis_test_vector_check(params, rho); + } + } + return resid; +} + +double libblis_test_bitrp_dotxv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* beta, + obj_t* rho, + obj_t* rho_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copysc( rho_orig, r ); + libblis_test_dotxv_impl( iface, alpha, x, y, beta, r ); + resid = libblis_test_bitrp_vector(rho, r, dt); + } + return resid; +} + +double libblis_test_op_dotxv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m; + conj_t conjx, conjy, conjconjxy; + obj_t alpha, x, y, beta, rho, rho_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjy ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + bli_obj_scalar_init_detached( datatype, &rho ); + bli_obj_scalar_init_detached( datatype, &rho_save ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + + // Initialize alpha, beta, and rho. + bli_copysc( &BLIS_ONE, &alpha ); + bli_copysc( &BLIS_ZERO, &beta ); + bli_copysc( &BLIS_MINUS_ONE, &rho ); + bli_copysc( &rho, &rho_save ); + + // Randomize x. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, TRUE, &x ); + } else { + libblis_test_vobj_irandomize( params, &x ); + } + + // Determine whether to make a copy of x with or without conjugation. + // + // conjx conjy ~conjx^conjy y is initialized as + // n n c y = conj(x) + // n c n y = x + // c n n y = x + // c c c y = conj(x) + // + conjconjxy = bli_apply_conj( conjx, conjy ); + conjconjxy = bli_conj_toggled( conjconjxy ); + bli_obj_set_conj( conjconjxy, &x ); + bli_copyv( &x, &y ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + bli_obj_set_conj( conjy, &y ); + + libblis_test_dotxv_impl( iface, &alpha, &x, &y, &beta, &rho ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + bli_copysc( &rho, &r ); + + resid = libblis_test_bitrp_dotxv( params, iface, &alpha, + &x, &y, &beta, &rho, &rho_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_dotxv( params, &alpha, &x, &y, &beta, &rho, &rho_save ); + } +#endif + + // Zero out performance and residual if output scalar is empty. + libblis_test_check_empty_problem( &rho, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + + return abs(resid); +} + +void libblis_test_dotxv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* beta, + obj_t* rho +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_dotxv( alpha, x, y, beta, rho ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + + + +double libblis_test_dotxv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* beta, + obj_t* rho, + obj_t* rho_orig +) { + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + obj_t rho_r, rho_i; + obj_t norm_x_r, norm_xy_r; + obj_t temp_r; + + double zero; + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is randomized. + // - y is equal to conjx(conjy(x)). + // - alpha must be real-valued. + // - beta must be zero. + // Note: + // - We forgo fully exercising beta scaling in order to simplify the + // test. + // + // Under these conditions, we assume that the implementation for + // + // rho := beta * rho_orig + alpha * conjx(x^T) conjy(y) + // + // is functioning correctly if + // + // sqrtsc( rho.real ) - sqrtsc( alpha ) * normfv( x ) + // + // and + // + // rho.imag + // + // are negligible. + // + + bli_obj_scalar_init_detached( dt_real, &rho_r ); + bli_obj_scalar_init_detached( dt_real, &rho_i ); + bli_obj_scalar_init_detached( dt_real, &norm_x_r ); + bli_obj_scalar_init_detached( dt_real, &norm_xy_r ); + bli_obj_scalar_init_detached( dt_real, &temp_r ); + + bli_copysc( alpha, &temp_r ); + bli_sqrtsc( &temp_r, &temp_r ); + + bli_normfv( x, &norm_x_r ); + bli_mulsc( &temp_r, &norm_x_r ); + + bli_unzipsc( rho, &rho_r, &rho_i ); + + bli_sqrtsc( &rho_r, &norm_xy_r ); + + bli_subsc( &norm_x_r, &norm_xy_r ); + bli_getsc( &norm_xy_r, &resid, &junk ); + bli_getsc( &rho_i, &zero, &junk ); + + resid = bli_fmaxabs( resid, zero ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_dotxv.h b/gtestsuite/src/test_dotxv.h new file mode 100644 index 000000000..c62c39326 --- /dev/null +++ b/gtestsuite/src/test_dotxv.h @@ -0,0 +1,19 @@ +#ifndef TEST_DOTXV_H +#define TEST_DOTXV_H + +#include "blis_test.h" + +double libblis_test_idotxv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* beta, + obj_t* rho, + obj_t* rho_orig + ); + +double libblis_check_nan_dotxv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_DOTXV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_gemm.cpp b/gtestsuite/src/test_gemm.cpp new file mode 100644 index 000000000..88e1a160a --- /dev/null +++ b/gtestsuite/src/test_gemm.cpp @@ -0,0 +1,556 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_gemm.h" + +using namespace std; + +// Local prototypes. +void libblis_test_gemm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_gemm_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +); + +double libblis_test_gemm_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +); + +double cblas_gemm( + test_params_t* params, + f77_int m, + f77_int n, + f77_int k, + f77_int lda, + f77_int ldb, + f77_int ldc, + obj_t* a, + obj_t* b, + obj_t* c, + obj_t* alpha, + obj_t* beta, + num_t dt, + trans_t transa, + trans_t transb +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_TRANSPOSE cblas_transa; + enum CBLAS_TRANSPOSE cblas_transb; + + if ( bli_obj_row_stride( c ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_trans( transa ) ) + cblas_transa = CblasTrans; + else if( bli_is_conjtrans( transa ) ) + cblas_transa = CblasConjTrans; + else + cblas_transa = CblasNoTrans; + + if( bli_is_trans( transb ) ) + cblas_transb = CblasTrans; + else if( bli_is_conjtrans( transb ) ) + cblas_transb = CblasConjTrans; + else + cblas_transb = CblasNoTrans; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + cblas_sgemm( cblas_order, cblas_transa, cblas_transb, + m, n, k, *alphap, ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + cblas_dgemm( cblas_order, cblas_transa, cblas_transb, + m, n, k, *alphap, ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cblas_cgemm( cblas_order, cblas_transa, cblas_transb, + m, n, k, alphap, ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + cblas_zgemm( cblas_order, cblas_transa, cblas_transb, + m, n, k, alphap, ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return 0; +} + +double blas_gemm( + f77_int m, + f77_int n, + f77_int k, + f77_int lda, + f77_int ldb, + f77_int ldc, + obj_t* a, + obj_t* b, + obj_t* c, + obj_t* alpha, + obj_t* beta, + num_t dt, + f77_char f77_transa, + f77_char f77_transb +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + sgemm_( &f77_transa, &f77_transb, &m, &n, &k, alphap, ap, + (f77_int*)&lda, bp, (f77_int*)&ldb, betap, cp,(f77_int*)&ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + dgemm_( &f77_transa, &f77_transb, &m, &n, &k, alphap, ap, + (f77_int*)&lda, bp, (f77_int*)&ldb, betap, cp,(f77_int*)&ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cgemm_( &f77_transa, &f77_transb, &m, &n, &k, alphap, ap, + (f77_int*)&lda, bp, (f77_int*)&ldb, betap, cp,(f77_int*)&ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + zgemm_( &f77_transa, &f77_transb, &m, &n, &k, alphap, ap, + (f77_int*)&lda, bp, (f77_int*)&ldb, betap, cp,(f77_int*)&ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_gemm( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_gemm_impl( iface, alpha, a, b, beta, c ); + } + else { /*CLBAS || BLAS */ + + f77_int mm = bli_obj_length( c ); + f77_int kk = bli_obj_width_after_trans( a ); + f77_int nn = bli_obj_width( c ); + trans_t transa = bli_obj_conjtrans_status( a ); + trans_t transb = bli_obj_conjtrans_status( b ); + f77_int lda, ldb, ldc; + + if( bli_obj_row_stride( c ) == 1 ) { + lda = bli_obj_col_stride( a ); + ldb = bli_obj_col_stride( b ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldb = bli_obj_row_stride( b ); + ldc = bli_obj_row_stride( c ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldb = ldb + params->ld[1]; + ldc = ldc + params->ld[2]; + } + + if(bli_obj_has_notrans(a) && bli_obj_has_conj(a)) { + conjugate_tensor(a, dt); + transa = bli_obj_onlytrans_status( a ); + } + + if(bli_obj_has_notrans(b) && bli_obj_has_conj(b)) { + conjugate_tensor(b, dt); + transb = bli_obj_onlytrans_status( b ); + } + + if(params->api == API_CBLAS) { + cblas_gemm( params, mm, nn, kk, lda, ldb, ldc, a, b, c, + alpha, beta, dt, transa, transb); + } else { /**/ + f77_char f77_transa; + f77_char f77_transb; + if(transa == BLIS_TRANSPOSE) f77_transa='T'; + else if ( transa == BLIS_CONJ_TRANSPOSE ) f77_transa='C'; + else /*if ( transa == BLIS_NO_TRANSPOSE )*/ f77_transa='N'; + + if(transb == BLIS_TRANSPOSE) f77_transb='T'; + else if ( transb == BLIS_CONJ_TRANSPOSE ) f77_transb='C'; + else /*if ( transb == BLIS_NO_TRANSPOSE )*/ f77_transb='N'; + + if( bli_obj_row_stride( c ) == 1 ) { + blas_gemm(mm, nn, kk, lda, ldb, ldc, a, b, c, + alpha, beta, dt, f77_transa, f77_transb); + } + else { + blas_gemm(nn, mm, kk, ldb, lda, ldc, b, a, c, + alpha, beta, dt, f77_transb, f77_transa); + } + } + } + return ; +} + +double libblis_ref_gemm( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_save, + num_t dt +) { + + double resid = 0.0; + double *betap = (double *)bli_obj_buffer( beta ); + + if ((params->nanf) && (*betap == 0)) { + resid = libblis_check_nan_gemm(c, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_gemm_check( params, alpha, a, b, beta, c, c_save); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_igemm_check( params, alpha, a, b, beta, c, c_save, dt); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_gemm( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_gemm_impl( iface, alpha, a, b, beta, r ); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_gemm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m, n, k; + trans_t transa; + trans_t transb; + obj_t alpha, a, b, beta, c; + obj_t c_save; + double resid = 0.0; + obj_t aa, bb; + + // Use a different function to handle mixed datatypes. + if ( params->mixed_domain || params->mixed_precision ) { + // TODO : GtestSuite Not Implemented + return resid; + } + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->k; + n = dim->n; + + // Map parameter characters to BLIS constants. + if(params->api == API_BLIS) { + bli_param_map_char_to_blis_trans( pc_str[0], &transa ); + bli_param_map_char_to_blis_trans( pc_str[1], &transb ); + } else { + bli_param_map_char_to_blas_trans( pc_str[0], &transa ); + bli_param_map_char_to_blas_trans( pc_str[1], &transb ); + } + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], m, k, &a ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], m, k, &aa ); + libblis_test_mobj_create( params, datatype, transb, + sc_str[2], k, n, &b ); + libblis_test_mobj_create( params, datatype, transb, + sc_str[2], k, n, &bb ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &c ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &c_save ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &c ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + bli_setsc( betv.real, (betv.real/1.2), &beta ); + } + // Randomize A, B, and C, and save C. + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_mobj_randomize( params, TRUE, &b ); + libblis_test_mobj_randomize( params, TRUE, &c ); + } + else { + int32_t x = (int32_t)alpv.real; + int32_t y = (int32_t)betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + int32_t ac = (int32_t)(x/0.8); + int32_t bc = (int32_t)(y/1.0); + bli_setsc( (double)x, (double)ac, &alpha ); + bli_setsc( (double)y, (double)bc, &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_mobj_irandomize( params, &b ); + libblis_test_mobj_irandomize( params, &c ); + } + + if ((params->nanf) && (betv.real == 0) ) { + test_fillbuffmem(&c, datatype ); + } + + //Copy c to c_save + bli_copym( &c, &c_save ); + + bli_copym( &a, &aa ); + bli_copym( &b, &bb ); + + // Apply the parameters. + bli_obj_set_conjtrans( transa, &a ); + bli_obj_set_conjtrans( transb, &b ); + + bli_obj_set_conjtrans( transa, &aa ); + bli_obj_set_conjtrans( transb, &bb ); + + libblis_api_gemm(params, iface, &alpha, &aa, &bb, &beta, &c, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + resid = libblis_test_bitrp_gemm( params, iface, &alpha, &a, &b, &beta, + &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_gemm(params, &alpha, &a, &b, &beta, + &c, &c_save, datatype ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &c, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &b ); + libblis_test_obj_free( &bb ); + libblis_test_obj_free( &c ); + libblis_test_obj_free( &c_save ); + + return abs(resid); +} + +void libblis_test_gemm_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +){ + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_gemm( alpha, a, b, beta, c ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_gemm_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +){ + num_t dt = bli_obj_dt( c ); + num_t dt_real = bli_obj_dt_proj_to_real( c ); + + dim_t m = bli_obj_length( c ); + dim_t n = bli_obj_width( c ); + dim_t k = bli_obj_width_after_trans( a ); + + obj_t norm; + obj_t t, v, w, z; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is randomized. + // - b is randomized. + // - c_orig is randomized. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * transa(A) * transb(B) + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // z = ( beta * C_orig + alpha * transa(A) * transb(B) ) * t + // = beta * C_orig * t + alpha * transa(A) * transb(B) * t + // = beta * C_orig * t + alpha * transa(A) * w + // = beta * C_orig * t + z + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, k, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, c, &t, &BLIS_ZERO, &v ); + + bli_gemv( &BLIS_ONE, b, &t, &BLIS_ZERO, &w ); + bli_gemv( alpha, a, &w, &BLIS_ZERO, &z ); + bli_gemv( beta, c_orig, &t, &BLIS_ONE, &z ); + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + bli_obj_free( &z ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemm.h b/gtestsuite/src/test_gemm.h new file mode 100644 index 000000000..e3bce7ae8 --- /dev/null +++ b/gtestsuite/src/test_gemm.h @@ -0,0 +1,20 @@ +#ifndef TEST_GEMM_H +#define TEST_GEMM_H + +#include "blis_test.h" + +double libblis_test_igemm_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + num_t dt + ); + +double libblis_check_nan_gemm(obj_t* c, num_t dt ); + +#endif /* TEST_GEMM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_gemm_bf16bf16f32obf16.cpp b/gtestsuite/src/test_gemm_bf16bf16f32obf16.cpp new file mode 100644 index 000000000..9f5ad9652 --- /dev/null +++ b/gtestsuite/src/test_gemm_bf16bf16f32obf16.cpp @@ -0,0 +1,262 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "lpgemm_utils.h" + +#ifdef BLIS_ENABLE_ADDONS +static bfloat16* aocl_reorder(bfloat16* b, dim_t k, dim_t n, dim_t ldb) { + siz_t b_reorder_buf_siz_req; + b_reorder_buf_siz_req = aocl_get_reorder_buf_size_bf16bf16f32of32('B',k, n); + bfloat16* b_reorder = ( bfloat16* )malloc( b_reorder_buf_siz_req ); + aocl_reorder_bf16bf16f32of32('B', b, b_reorder, k, n, ldb ); + return b_reorder; +} + +static void aocl_gemm_driver_bf16bf16f32obf16( + uint32_t n_repeats, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + float alpha, + bfloat16* a, + dim_t lda, + char reordera, + bfloat16* b, + dim_t ldb, + char reorderb, + float beta, + bfloat16* c, + dim_t ldc, + aocl_post_op* post_op +) { + uint32_t i; + char storage = stor_order; + for ( i = 0; i < n_repeats; i++ ) { + memset( ( void* ) c, 0, sizeof( bfloat16 ) * (m * n) ); + + aocl_gemm_bf16bf16f32obf16(storage, transa, transb, m, n, k, + alpha, a, lda, reordera, b, + ldb, reorderb, beta, c, ldc, post_op ); +/* + aocl_gemm_bf16bf16f32obf16(storage, (const char)transa, (const char)transb, (const dim_t)m, (const dim_t)n, (const dim_t)k, + (const float)alpha, (const bfloat16 *)a, (const dim_t)lda, (const char)reordera, (const bfloat16 *)b, + (const dim_t)ldb, (const char)reorderb, (const float)beta, c, (const dim_t)ldc, post_op ); +*/ + } +} + +static void mat_mul_driver_bf16bf16f32obf16( + test_params_t* params, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + float alpha, + bfloat16* a, + dim_t lda, + bfloat16* b, + dim_t ldb, + float beta, + bfloat16* c, + dim_t ldc, + aocl_post_op* post_op +) { + char reordera; + char reorderb; + + if ( ( params->op_t == 'p' ) || ( params->op_t == 'P' ) ) + { + /* No reordering of B.*/ + reordera = 'n'; + reorderb = 'n'; + + aocl_gemm_driver_bf16bf16f32obf16(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b, ldb, reorderb, beta, c, ldc, post_op ); + } + else if ( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) + { + /* Reorder B.*/ + reordera = 'n'; + reorderb = 'r'; + + bfloat16* b_reorder = aocl_reorder( b, k, n, ldb ); + + aocl_gemm_driver_bf16bf16f32obf16(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b_reorder, ldb, reorderb, beta, c, ldc, post_op ); + + free( b_reorder ); + } +} + +static double mat_mul_accuracy_check_driver_bf16bf16f32obf16 + ( + const char stor_order, + dim_t m, + dim_t n, + dim_t k, + float alpha, + bfloat16* a, + dim_t lda, + bfloat16* b, + dim_t ldb, + float beta, + bfloat16* c, + dim_t ldc, + bfloat16* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_a = lda; + dim_t cs_a = 1; + dim_t rs_b = ldb; + dim_t cs_b = 1; + dim_t rs_c = ldc; + dim_t cs_c = 1; + + if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + rs_a = 1; + cs_a = lda; + rs_b = 1; + cs_b = ldb; + rs_c = 1; + cs_c = ldc; + } + + resid = mat_mul_accuracy_check_driver_bf16( m, n, k, + alpha, a, rs_a, cs_a, b, rs_b, cs_b, beta, c, rs_c, cs_c, c_ref, post_op, + dscale_out ); + + return resid; +} +#endif + +double libblis_test_op_gemm_bf16bf16f32obf16 ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + double resid = 0.0; +#ifdef BLIS_ENABLE_ADDONS + dim_t m, n, k; + dim_t lda, ldb, ldc; + char* post_ops_str = NULL; + char* post_ops_str_dest = NULL; + aocl_post_op* post_op = NULL; + char stor_order = sc_str[0]; + char transa = 'n'; //pc_str[0]; + char transb = 'n'; //pc_str[1]; + bool dscale_out = true; + + stor_order = ( ( stor_order == 'r' ) || ( stor_order == 'R' ) || + ( stor_order == 'c' ) || ( stor_order == 'C' ) ) ? + stor_order : 'r'; + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->k; + n = dim->n; + + if( ( stor_order == 'r' ) || ( stor_order == 'R' ) ) + { + lda = k; // a = mxk; + ldb = n; // b = kxn; + ldc = n; // c = mxn; + } + else if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + lda = m; + ldb = k; + ldc = m; + if( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) { + cout << "Recorer not supported in column major" << endl; + return resid; + } + } + + /* Get 64 byte aligned memory.*/ + bfloat16* a = ( bfloat16* ) malloc( sizeof( bfloat16 ) * m * k ); + float *a_float = ( float* ) malloc( m * k * sizeof( float )); + for ( int32_t i = 0; i < m*k; ++i ) + { + a_float[i] = ( float ) ( i % 5 ); + } + convert_float_arr_to_bf16( a_float, a, m * k ); + + bfloat16* b = ( bfloat16* ) malloc( sizeof( bfloat16 ) * n * k ); + float *b_float = ( float* ) malloc( k * n * sizeof( float )); + for ( int32_t i = 0; i < k*n; ++i ) + { + b_float[i] = ( float ) ( i % 5 ); + } + convert_float_arr_to_bf16( b_float, b, k * n ); + + bfloat16* c = ( bfloat16* ) malloc( sizeof( bfloat16 ) * m * n ); + memset( ( void* ) c, 0, sizeof( bfloat16 ) * m * n ); + + bfloat16* c_ref = ( bfloat16* ) malloc( sizeof( bfloat16 ) * m * n ); + memset( ( void* ) c_ref, 0, sizeof( bfloat16 ) * m * n ); + + float alpha = 2 ; + float beta = 9 ; + + if ( post_ops_str != NULL ) + { + post_ops_str_dest = strdup( post_ops_str ); + } + + if( ( post_ops_str != NULL ) || ( dscale_out ) ) + { + post_op = lpgemm_create_post_ops_struct + ( m, n, post_ops_str_dest, dscale_out ); + if ( post_op == NULL ) + { + printf(" post op struct allocation failure, returning.n"); + return -1; + } + } + + mat_mul_driver_bf16bf16f32obf16(params, stor_order, transa, transb, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, post_op ); + +#ifndef __GTEST_VALGRIND_TEST__ + resid = mat_mul_accuracy_check_driver_bf16bf16f32obf16( stor_order, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, c_ref, post_op, + dscale_out ); +#endif + + if ( post_op != NULL ) + lpgemm_destroy_post_ops_struct( post_op ); + + // Free the test objects. + if ( a != NULL ) + free( a ); + if ( a_float != NULL ) + free( a_float ); + if ( b != NULL ) + free( b ); + if ( b_float != NULL ) + free( b_float ); + if ( c != NULL ) + free( c ); + if ( c_ref != NULL ) + free( c_ref ); + + if ( post_ops_str_dest != NULL ) + free( post_ops_str_dest ); + +#else + cout << "CPU Arch do not support AVX512" << endl; +#endif + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemm_bf16bf16f32of32.cpp b/gtestsuite/src/test_gemm_bf16bf16f32of32.cpp new file mode 100644 index 000000000..168924d29 --- /dev/null +++ b/gtestsuite/src/test_gemm_bf16bf16f32of32.cpp @@ -0,0 +1,262 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "lpgemm_utils.h" + +#ifdef BLIS_ENABLE_ADDONS +static bfloat16* aocl_reorder(bfloat16* b, dim_t k, dim_t n, dim_t ldb) { + siz_t b_reorder_buf_siz_req; + b_reorder_buf_siz_req = aocl_get_reorder_buf_size_bf16bf16f32of32('B',k, n); + bfloat16* b_reorder = ( bfloat16* )malloc( b_reorder_buf_siz_req ); + aocl_reorder_bf16bf16f32of32('B', b, b_reorder, k, n, ldb ); + return b_reorder; +} + +static void aocl_gemm_driver_bf16bf16f32of32( + uint32_t n_repeats, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + float alpha, + bfloat16* a, + dim_t lda, + char reordera, + bfloat16* b, + dim_t ldb, + char reorderb, + float beta, + float* c, + dim_t ldc, + aocl_post_op* post_op +) { + uint32_t i; + char storage = stor_order; + for ( i = 0; i < n_repeats; i++ ) { + memset( ( void* ) c, 0, sizeof( float ) * (m * n) ); + + aocl_gemm_bf16bf16f32of32(storage, transa, transb, m, n, k, + alpha, a, lda, reordera, b, + ldb, reorderb, beta, c, ldc, post_op ); +/* + aocl_gemm_bf16bf16f32of32(storage, (const char)transa, (const char)transb, (const dim_t)m, (const dim_t)n, (const dim_t)k, + (const float)alpha, (const bfloat16 *)a, (const dim_t)lda, (const char)reordera, (const bfloat16 *)b, + (const dim_t)ldb, (const char)reorderb, (const float)beta, c, (const dim_t)ldc, post_op ); +*/ + } +} + +static void mat_mul_driver_bf16bf16f32of32( + test_params_t* params, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + float alpha, + bfloat16* a, + dim_t lda, + bfloat16* b, + dim_t ldb, + float beta, + float* c, + dim_t ldc, + aocl_post_op* post_op +) { + char reordera; + char reorderb; + + if ( ( params->op_t == 'p' ) || ( params->op_t == 'P' ) ) + { + /* No reordering of B.*/ + reordera = 'n'; + reorderb = 'n'; + + aocl_gemm_driver_bf16bf16f32of32(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b, ldb, reorderb, beta, c, ldc, post_op ); + } + else if ( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) + { + /* Reorder B.*/ + reordera = 'n'; + reorderb = 'r'; + + bfloat16* b_reorder = aocl_reorder( b, k, n, ldb ); + + aocl_gemm_driver_bf16bf16f32of32(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b_reorder, ldb, reorderb, beta, c, ldc, post_op ); + + free( b_reorder ); + } +} + +static double mat_mul_accuracy_check_driver_bf16bf16f32of32 + ( + const char stor_order, + dim_t m, + dim_t n, + dim_t k, + float alpha, + bfloat16* a, + dim_t lda, + bfloat16* b, + dim_t ldb, + float beta, + float* c, + dim_t ldc, + float* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_a = lda; + dim_t cs_a = 1; + dim_t rs_b = ldb; + dim_t cs_b = 1; + dim_t rs_c = ldc; + dim_t cs_c = 1; + + if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + rs_a = 1; + cs_a = lda; + rs_b = 1; + cs_b = ldb; + rs_c = 1; + cs_c = ldc; + } + + resid = mat_mul_accuracy_check_driver_bf16( m, n, k, + alpha, a, rs_a, cs_a, b, rs_b, cs_b, beta, c, rs_c, cs_c, c_ref, post_op, + dscale_out ); + + return resid; +} +#endif + +double libblis_test_op_gemm_bf16bf16f32of32 ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + double resid = 0.0; +#ifdef BLIS_ENABLE_ADDONS + dim_t m, n, k; + dim_t lda, ldb, ldc; + char* post_ops_str = NULL; + char* post_ops_str_dest = NULL; + aocl_post_op* post_op = NULL; + char stor_order = sc_str[0]; + char transa = 'n'; //pc_str[0]; + char transb = 'n'; //pc_str[1]; + bool dscale_out = false; + + stor_order = ( ( stor_order == 'r' ) || ( stor_order == 'R' ) || + ( stor_order == 'c' ) || ( stor_order == 'C' ) ) ? + stor_order : 'r'; + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->k; + n = dim->n; + + if( ( stor_order == 'r' ) || ( stor_order == 'R' ) ) + { + lda = k; // a = mxk; + ldb = n; // b = kxn; + ldc = n; // c = mxn; + } + else if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + lda = m; + ldb = k; + ldc = m; + if( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) { + cout << "Recorer not supported in column major" << endl; + return resid; + } + } + + /* Get 64 byte aligned memory.*/ + bfloat16* a = ( bfloat16* ) malloc( sizeof( bfloat16 ) * m * k ); + float *a_float = (float *)malloc( m * k * sizeof( float )); + for ( int32_t i = 0; i < m*k; ++i ) + { + a_float[i] = ( float ) ( i % 5 ); + } + convert_float_arr_to_bf16( a_float, a, m * k ); + + bfloat16* b = ( bfloat16* ) malloc( sizeof( bfloat16 ) * n * k ); + float *b_float = (float *)malloc( k * n * sizeof( float )); + for ( int32_t i = 0; i < k*n; ++i ) + { + b_float[i] = ( float ) ( i % 5 ); + } + convert_float_arr_to_bf16( b_float, b, k * n ); + + float* c = ( float* ) malloc( sizeof( float ) * m * n ); + memset( ( void* ) c, 0, sizeof( float ) * m * n ); + + float* c_ref = ( float* ) malloc( sizeof( float ) * m * n ); + memset( ( void* ) c_ref, 0, sizeof( float ) * m * n ); + + float alpha = 2 ; + float beta = 9 ; + + if ( post_ops_str != NULL ) + { + post_ops_str_dest = strdup( post_ops_str ); + } + + if( ( post_ops_str != NULL ) || ( dscale_out ) ) + { + post_op = lpgemm_create_post_ops_struct + ( m, n, post_ops_str_dest, dscale_out ); + if ( post_op == NULL ) + { + printf(" post op struct allocation failure, returning.n"); + return -1; + } + } + + mat_mul_driver_bf16bf16f32of32(params, stor_order, transa, transb, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, post_op ); + +#ifndef __GTEST_VALGRIND_TEST__ + resid = mat_mul_accuracy_check_driver_bf16bf16f32of32( stor_order, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, c_ref, post_op, + dscale_out ); +#endif + + if ( post_op != NULL ) + lpgemm_destroy_post_ops_struct( post_op ); + + // Free the test objects. + if ( a != NULL ) + free( a ); + if ( a_float != NULL ) + free( a_float ); + if ( b != NULL ) + free( b ); + if ( b_float != NULL ) + free( b_float ); + if ( c != NULL ) + free( c ); + if ( c_ref != NULL ) + free( c_ref ); + + if ( post_ops_str_dest != NULL ) + free( post_ops_str_dest ); + +#else + cout << "CPU Arch do not support AVX512" << endl; +#endif + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemm_f32f32f32of32.cpp b/gtestsuite/src/test_gemm_f32f32f32of32.cpp new file mode 100644 index 000000000..9a176bfe2 --- /dev/null +++ b/gtestsuite/src/test_gemm_f32f32f32of32.cpp @@ -0,0 +1,248 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "lpgemm_utils.h" + +#ifdef BLIS_ENABLE_ADDONS +static float* aocl_reorder(float* b, dim_t k, dim_t n, dim_t ldb) { + siz_t b_reorder_buf_siz_req; + b_reorder_buf_siz_req = aocl_get_reorder_buf_size_f32f32f32of32('B',k, n); + float* b_reorder = ( float* )malloc( b_reorder_buf_siz_req ); + aocl_reorder_f32f32f32of32('B', b, b_reorder, k, n, ldb ); + return b_reorder; +} + +static void aocl_gemm_driver_f32f32f32of32( + uint32_t n_repeats, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + float alpha, + float* a, + dim_t lda, + char reordera, + float* b, + dim_t ldb, + char reorderb, + float beta, + float* c, + dim_t ldc, + aocl_post_op* post_op +) { + uint32_t i; + char storage = stor_order; + for ( i = 0; i < n_repeats; i++ ) { + memset( ( void* ) c, 0, sizeof( float ) * (m * n) ); + + aocl_gemm_f32f32f32of32(storage, transa, transb, m, n, k, + alpha, a, lda, reordera, b, + ldb, reorderb, beta, c, ldc, post_op ); +/* + aocl_gemm_f32f32f32of32(storage, (const char)transa, (const char)transb, (const dim_t)m, (const dim_t)n, (const dim_t)k, + (const float)alpha, (const float *)a, (const dim_t)lda, (const char)reordera, (const float *)b, + (const dim_t)ldb, (const char)reorderb, (const float)beta, c, (const dim_t)ldc, post_op ); +*/ + } +} + +static void mat_mul_driver_f32f32f32of32( + test_params_t* params, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + float alpha, + float* a, + dim_t lda, + float* b, + dim_t ldb, + float beta, + float* c, + dim_t ldc, + aocl_post_op* post_op +) { + char reordera; + char reorderb; + + if ( ( params->op_t == 'p' ) || ( params->op_t == 'P' ) ) + { + /* No reordering of B.*/ + reordera = 'n'; + reorderb = 'n'; + + aocl_gemm_driver_f32f32f32of32(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b, ldb, reorderb, beta, c, ldc, post_op ); + } + else if ( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) + { + /* Reorder B.*/ + reordera = 'n'; + reorderb = 'r'; + + float* b_reorder = aocl_reorder( b, k, n, ldb ); + + aocl_gemm_driver_f32f32f32of32(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b_reorder, ldb, reorderb, beta, c, ldc, post_op ); + + free( b_reorder ); + } +} + +static double mat_mul_accuracy_check_driver_f32f32f32of32 + ( + const char stor_order, + dim_t m, + dim_t n, + dim_t k, + float alpha, + float* a, + dim_t lda, + float* b, + dim_t ldb, + float beta, + float* c, + dim_t ldc, + float* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_a = lda; + dim_t cs_a = 1; + dim_t rs_b = ldb; + dim_t cs_b = 1; + dim_t rs_c = ldc; + dim_t cs_c = 1; + + if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + rs_a = 1; + cs_a = lda; + rs_b = 1; + cs_b = ldb; + rs_c = 1; + cs_c = ldc; + } + + resid = mat_mul_accuracy_check_driver( m, n, k, + alpha, a, rs_a, cs_a, b, rs_b, cs_b, beta, c, rs_c, cs_c, c_ref, post_op, + dscale_out ); + + return resid; +} +#endif + +double libblis_test_op_gemm_f32f32f32of32 ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + double resid = 0.0; +#ifdef BLIS_ENABLE_ADDONS + dim_t m, n, k; + dim_t lda, ldb, ldc; + char* post_ops_str = NULL; + char* post_ops_str_dest = NULL; + aocl_post_op* post_op = NULL; + char stor_order = sc_str[0]; + char transa = 'n'; //pc_str[0]; + char transb = 'n'; //pc_str[1]; + bool dscale_out = false; + + stor_order = ( ( stor_order == 'r' ) || ( stor_order == 'R' ) || + ( stor_order == 'c' ) || ( stor_order == 'C' ) ) ? + stor_order : 'r'; + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->k; + n = dim->n; + + if( ( stor_order == 'r' ) || ( stor_order == 'R' ) ) + { + lda = k; // a = mxk; + ldb = n; // b = kxn; + ldc = n; // c = mxn; + } + else if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + lda = m; + ldb = k; + ldc = m; + cout << "Column Major not supported" << endl; + return resid; + } + + + /* Get 64 byte aligned memory.*/ + float* a = ( float* ) malloc( sizeof( float ) * m * k ); + + float* b = ( float* ) malloc( sizeof( float ) * n * k ); + + float* c = ( float* ) malloc( sizeof( float ) * m * n ); + memset( ( void* ) c, 0, sizeof( float ) * m * n ); + + float* c_ref = ( float* ) malloc( sizeof( float ) * m * n ); + memset( ( void* ) c_ref, 0, sizeof( float ) * m * n ); + + float alpha = 2; + float beta = 9 ; + + fill_array( a, ( m * k ) ); + fill_array( b, ( k * n ) ); + + if ( post_ops_str != NULL ) + { + post_ops_str_dest = strdup( post_ops_str ); + } + + if( ( post_ops_str != NULL ) || ( dscale_out ) ) + { + post_op = lpgemm_create_post_ops_struct + ( m, n, post_ops_str_dest, dscale_out ); + if ( post_op == NULL ) + { + printf(" post op struct allocation failure, returning.n"); + return -1; + } + } + + mat_mul_driver_f32f32f32of32(params, stor_order, transa, transb, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, post_op ); + +#ifndef __GTEST_VALGRIND_TEST__ + resid = mat_mul_accuracy_check_driver_f32f32f32of32( stor_order, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, c_ref, post_op, + dscale_out ); +#endif + + if ( post_op != NULL ) + lpgemm_destroy_post_ops_struct( post_op ); + + // Free the test objects. + if ( a != NULL ) + free( a ); + if ( b != NULL ) + free( b ); + if ( c != NULL ) + free( c ); + if ( c_ref != NULL ) + free( c_ref ); + + if ( post_ops_str_dest != NULL ) + free( post_ops_str_dest ); + +#else + cout << "CPU Arch do not support AVX512" << endl; +#endif + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemm_u8s8s16os16.cpp b/gtestsuite/src/test_gemm_u8s8s16os16.cpp new file mode 100644 index 000000000..2f61fc556 --- /dev/null +++ b/gtestsuite/src/test_gemm_u8s8s16os16.cpp @@ -0,0 +1,248 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "lpgemm_utils.h" + +#ifdef BLIS_ENABLE_ADDONS +static int8_t* aocl_reorder(int8_t* b, dim_t k, dim_t n, dim_t ldb) { + siz_t b_reorder_buf_siz_req; + b_reorder_buf_siz_req = aocl_get_reorder_buf_size_u8s8s16os16('B',k, n); + int8_t* b_reorder = ( int8_t* )malloc( b_reorder_buf_siz_req ); + aocl_reorder_u8s8s16os16('B', b, b_reorder, k, n, ldb ); + return b_reorder; +} + +static void aocl_gemm_driver_u8s8s16os16( + uint32_t n_repeats, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + int16_t alpha, + uint8_t* a, + dim_t lda, + char reordera, + int8_t* b, + dim_t ldb, + char reorderb, + int16_t beta, + int16_t* c, + dim_t ldc, + aocl_post_op* post_op +) { + uint32_t i; + char storage = stor_order; + for ( i = 0; i < n_repeats; i++ ) { + memset( ( void* ) c, 0, sizeof( int16_t ) * (m * n) ); + + aocl_gemm_u8s8s16os16(storage, transa, transb, m, n, k, + alpha, a, lda, reordera, b, + ldb, reorderb, beta, c, ldc, post_op ); +/* + aocl_gemm_u8s8s16os16(storage, (const char)transa, (const char)transb, (const dim_t)m, (const dim_t)n, (const dim_t)k, + (const int8_t)alpha, (const uint8_t *)a, (const dim_t)lda, (const char)reordera, (const int8_t *)b, + (const dim_t)ldb, (const char)reorderb, (const int8_t)beta, c, (const dim_t)ldc, post_op ); +*/ + } +} + +static void mat_mul_driver_u8s8s16os16( + test_params_t* params, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + int16_t alpha, + uint8_t* a, + dim_t lda, + int8_t* b, + dim_t ldb, + int16_t beta, + int16_t* c, + dim_t ldc, + aocl_post_op* post_op +) { + char reordera; + char reorderb; + + if ( ( params->op_t == 'p' ) || ( params->op_t == 'P' ) ) + { + /* No reordering of B.*/ + reordera = 'n'; + reorderb = 'n'; + + aocl_gemm_driver_u8s8s16os16(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b, ldb, reorderb, beta, c, ldc, post_op ); + } + else if ( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) + { + /* Reorder B.*/ + reordera = 'n'; + reorderb = 'r'; + + int8_t* b_reorder = aocl_reorder( b, k, n, ldb ); + + aocl_gemm_driver_u8s8s16os16(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b_reorder, ldb, reorderb, beta, c, ldc, post_op ); + + free( b_reorder ); + } +} + +static double mat_mul_accuracy_check_driver_u8s8s16os16 + ( + const char stor_order, + dim_t m, + dim_t n, + dim_t k, + int16_t alpha, + uint8_t* a, + dim_t lda, + int8_t* b, + dim_t ldb, + int16_t beta, + int16_t* c, + dim_t ldc, + int16_t* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_a = lda; + dim_t cs_a = 1; + dim_t rs_b = ldb; + dim_t cs_b = 1; + dim_t rs_c = ldc; + dim_t cs_c = 1; + + if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + rs_a = 1; + cs_a = lda; + rs_b = 1; + cs_b = ldb; + rs_c = 1; + cs_c = ldc; + } + + resid = mat_mul_accuracy_check_driver( m, n, k, + alpha, a, rs_a, cs_a, b, rs_b, cs_b, beta, c, rs_c, cs_c, c_ref, post_op, + dscale_out ); + + return resid; +} +#endif + +double libblis_test_op_gemm_u8s8s16os16 ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + double resid = 0.0; +#ifdef BLIS_ENABLE_ADDONS + dim_t m, n, k; + dim_t lda, ldb, ldc; + char* post_ops_str = NULL; + char* post_ops_str_dest = NULL; + aocl_post_op* post_op = NULL; + char stor_order = sc_str[0]; + char transa = 'n'; //pc_str[0]; + char transb = 'n'; //pc_str[1]; + bool dscale_out = false; + + stor_order = ( ( stor_order == 'r' ) || ( stor_order == 'R' ) || + ( stor_order == 'c' ) || ( stor_order == 'C' ) ) ? + stor_order : 'r'; + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->k; + n = dim->n; + + if( ( stor_order == 'r' ) || ( stor_order == 'R' ) ) + { + lda = k; // a = mxk; + ldb = n; // b = kxn; + ldc = n; // c = mxn; + } + else if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + lda = m; + ldb = k; + ldc = m; + cout << "Column Major not supported" << endl; + return resid; + } + + + /* Get 64 byte aligned memory.*/ + uint8_t* a = ( uint8_t* ) malloc( sizeof( uint8_t ) * m * k ); + + int8_t* b = ( int8_t* ) malloc( sizeof( int8_t ) * n * k ); + + int16_t* c = ( int16_t* ) malloc( sizeof( int16_t ) * m * n ); + memset( ( void* ) c, 0, sizeof( int16_t ) * m * n ); + + int16_t* c_ref = ( int16_t* ) malloc( sizeof( int16_t ) * m * n ); + memset( ( void* ) c_ref, 0, sizeof( int16_t ) * m * n ); + + int16_t alpha = 2; + int16_t beta = 9; + + fill_array( a, ( m * k ) ); + fill_array( b, ( k * n ) ); + + if ( post_ops_str != NULL ) + { + post_ops_str_dest = strdup( post_ops_str ); + } + + if( ( post_ops_str != NULL ) || ( dscale_out ) ) + { + post_op = lpgemm_create_post_ops_struct + ( m, n, post_ops_str_dest, dscale_out ); + if ( post_op == NULL ) + { + printf(" post op struct allocation failure, returning.n"); + return -1; + } + } + + mat_mul_driver_u8s8s16os16(params, stor_order, transa, transb, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, post_op ); + +#ifndef __GTEST_VALGRIND_TEST__ + resid = mat_mul_accuracy_check_driver_u8s8s16os16( stor_order, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, c_ref, post_op, + dscale_out ); +#endif + + if ( post_op != NULL ) + lpgemm_destroy_post_ops_struct( post_op ); + + // Free the test objects. + if ( a != NULL ) + free( a ); + if ( b != NULL ) + free( b ); + if ( c != NULL ) + free( c ); + if ( c_ref != NULL ) + free( c_ref ); + + if ( post_ops_str_dest != NULL ) + free( post_ops_str_dest ); + +#else + cout << "CPU Arch do not support AVX512" << endl; +#endif + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemm_u8s8s16os8.cpp b/gtestsuite/src/test_gemm_u8s8s16os8.cpp new file mode 100644 index 000000000..e0090fbb1 --- /dev/null +++ b/gtestsuite/src/test_gemm_u8s8s16os8.cpp @@ -0,0 +1,248 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "lpgemm_utils.h" + +#ifdef BLIS_ENABLE_ADDONS +static int8_t* aocl_reorder(int8_t* b, dim_t k, dim_t n, dim_t ldb) { + siz_t b_reorder_buf_siz_req; + b_reorder_buf_siz_req = aocl_get_reorder_buf_size_u8s8s16os16('B',k, n); + int8_t* b_reorder = ( int8_t* )malloc( b_reorder_buf_siz_req ); + aocl_reorder_u8s8s16os16('B', b, b_reorder, k, n, ldb ); + return b_reorder; +} + +static void aocl_gemm_driver_u8s8s16os8( + uint32_t n_repeats, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + int8_t alpha, + uint8_t* a, + dim_t lda, + char reordera, + int8_t* b, + dim_t ldb, + char reorderb, + int8_t beta, + int8_t* c, + dim_t ldc, + aocl_post_op* post_op +) { + uint32_t i; + char storage = stor_order; + for ( i = 0; i < n_repeats; i++ ) { + memset( ( void* ) c, 0, sizeof( int8_t ) * (m * n) ); + + aocl_gemm_u8s8s16os8(storage, transa, transb, m, n, k, + alpha, a, lda, reordera, b, + ldb, reorderb, beta, c, ldc, post_op ); +/* + aocl_gemm_u8s8s16os8(storage, (const char)transa, (const char)transb, (const dim_t)m, (const dim_t)n, (const dim_t)k, + (const int8_t)alpha, (const uint8_t *)a, (const dim_t)lda, (const char)reordera, (const int8_t *)b, + (const dim_t)ldb, (const char)reorderb, (const int8_t)beta, c, (const dim_t)ldc, post_op ); +*/ + } +} + +static void mat_mul_driver_u8s8s16os8( + test_params_t* params, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + int8_t alpha, + uint8_t* a, + dim_t lda, + int8_t* b, + dim_t ldb, + int8_t beta, + int8_t* c, + dim_t ldc, + aocl_post_op* post_op +) { + char reordera; + char reorderb; + + if ( ( params->op_t == 'p' ) || ( params->op_t == 'P' ) ) + { + /* No reordering of B.*/ + reordera = 'n'; + reorderb = 'n'; + + aocl_gemm_driver_u8s8s16os8(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b, ldb, reorderb, beta, c, ldc, post_op ); + } + else if ( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) + { + /* Reorder B.*/ + reordera = 'n'; + reorderb = 'r'; + + int8_t* b_reorder = aocl_reorder( b, k, n, ldb ); + + aocl_gemm_driver_u8s8s16os8(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b_reorder, ldb, reorderb, beta, c, ldc, post_op ); + + free( b_reorder ); + } +} + +static double mat_mul_accuracy_check_driver_u8s8s16os8 + ( + const char stor_order, + dim_t m, + dim_t n, + dim_t k, + int8_t alpha, + uint8_t* a, + dim_t lda, + int8_t* b, + dim_t ldb, + int8_t beta, + int8_t* c, + dim_t ldc, + int8_t* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_a = lda; + dim_t cs_a = 1; + dim_t rs_b = ldb; + dim_t cs_b = 1; + dim_t rs_c = ldc; + dim_t cs_c = 1; + + if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + rs_a = 1; + cs_a = lda; + rs_b = 1; + cs_b = ldb; + rs_c = 1; + cs_c = ldc; + } + + resid = mat_mul_accuracy_check_driver( m, n, k, + alpha, a, rs_a, cs_a, b, rs_b, cs_b, beta, c, rs_c, cs_c, c_ref, post_op, + dscale_out ); + + return resid; +} +#endif + +double libblis_test_op_gemm_u8s8s16os8 ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + double resid = 0.0; +#ifdef BLIS_ENABLE_ADDONS + dim_t m, n, k; + dim_t lda, ldb, ldc; + char* post_ops_str = NULL; + char* post_ops_str_dest = NULL; + aocl_post_op* post_op = NULL; + char stor_order = sc_str[0]; + char transa = 'n'; //pc_str[0]; + char transb = 'n'; //pc_str[1]; + bool dscale_out = true; + + stor_order = ( ( stor_order == 'r' ) || ( stor_order == 'R' ) || + ( stor_order == 'c' ) || ( stor_order == 'C' ) ) ? + stor_order : 'r'; + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->k; + n = dim->n; + + if( ( stor_order == 'r' ) || ( stor_order == 'R' ) ) + { + lda = k; // a = mxk; + ldb = n; // b = kxn; + ldc = n; // c = mxn; + } + else if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + lda = m; + ldb = k; + ldc = m; + cout << "Column Major not supported" << endl; + return resid; + } + + + /* Get 64 byte aligned memory.*/ + uint8_t* a = ( uint8_t* ) malloc( sizeof( uint8_t ) * m * k ); + + int8_t* b = ( int8_t* ) malloc( sizeof( int8_t ) * n * k ); + + int8_t* c = ( int8_t* ) malloc( sizeof( int8_t ) * m * n ); + memset( ( void* ) c, 0, sizeof( int8_t ) * m * n ); + + int8_t* c_ref = ( int8_t* ) malloc( sizeof( int8_t ) * m * n ); + memset( ( void* ) c_ref, 0, sizeof( int8_t ) * m * n ); + + int8_t alpha = 2; + int8_t beta = 9; + + fill_array( a, ( m * k ) ); + fill_array( b, ( k * n ) ); + + if ( post_ops_str != NULL ) + { + post_ops_str_dest = strdup( post_ops_str ); + } + + if( ( post_ops_str != NULL ) || ( dscale_out ) ) + { + post_op = lpgemm_create_post_ops_struct + ( m, n, post_ops_str_dest, dscale_out ); + if ( post_op == NULL ) + { + printf(" post op struct allocation failure, returning.n"); + return -1; + } + } + + mat_mul_driver_u8s8s16os8(params, stor_order, transa, transb, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, post_op ); + +#ifndef __GTEST_VALGRIND_TEST__ + resid = mat_mul_accuracy_check_driver_u8s8s16os8( stor_order, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, c_ref, post_op, + dscale_out ); +#endif + + if ( post_op != NULL ) + lpgemm_destroy_post_ops_struct( post_op ); + + // Free the test objects. + if ( a != NULL ) + free( a ); + if ( b != NULL ) + free( b ); + if ( c != NULL ) + free( c ); + if ( c_ref != NULL ) + free( c_ref ); + + if ( post_ops_str_dest != NULL ) + free( post_ops_str_dest ); + +#else + cout << "CPU Arch do not support AVX512" << endl; +#endif + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemm_u8s8s32os32.cpp b/gtestsuite/src/test_gemm_u8s8s32os32.cpp new file mode 100644 index 000000000..65ed46d97 --- /dev/null +++ b/gtestsuite/src/test_gemm_u8s8s32os32.cpp @@ -0,0 +1,248 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "lpgemm_utils.h" + +#ifdef BLIS_ENABLE_ADDONS +static int8_t* aocl_reorder(int8_t* b, dim_t k, dim_t n, dim_t ldb) { + siz_t b_reorder_buf_siz_req; + b_reorder_buf_siz_req = aocl_get_reorder_buf_size_u8s8s32os32('B',k, n); + int8_t* b_reorder = ( int8_t* )malloc( b_reorder_buf_siz_req ); + aocl_reorder_u8s8s32os32('B', b, b_reorder, k, n, ldb ); + return b_reorder; +} + +static void aocl_gemm_driver_u8s8s32os32( + uint32_t n_repeats, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + int32_t alpha, + uint8_t* a, + dim_t lda, + char reordera, + int8_t* b, + dim_t ldb, + char reorderb, + int32_t beta, + int32_t* c, + dim_t ldc, + aocl_post_op* post_op +) { + uint32_t i; + char storage = stor_order; + for ( i = 0; i < n_repeats; i++ ) { + memset( ( void* ) c, 0, sizeof( int32_t ) * (m * n) ); + + aocl_gemm_u8s8s32os32(storage, transa, transb, m, n, k, + alpha, a, lda, reordera, b, + ldb, reorderb, beta, c, ldc, post_op ); +/* + aocl_gemm_u8s8s32os32(storage, (const char)transa, (const char)transb, (const dim_t)m, (const dim_t)n, (const dim_t)k, + (const int32_t)alpha, (const uint8_t *)a, (const dim_t)lda, (const char)reordera, (const int8_t *)b, + (const dim_t)ldb, (const char)reorderb, (const int32_t)beta, c, (const dim_t)ldc, post_op ); +*/ + } +} + +static void mat_mul_driver_u8s8s32os32( + test_params_t* params, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + int32_t alpha, + uint8_t* a, + dim_t lda, + int8_t* b, + dim_t ldb, + int32_t beta, + int32_t* c, + dim_t ldc, + aocl_post_op* post_op +) { + char reordera; + char reorderb; + + if ( ( params->op_t == 'p' ) || ( params->op_t == 'P' ) ) + { + /* No reordering of B.*/ + reordera = 'n'; + reorderb = 'n'; + + aocl_gemm_driver_u8s8s32os32(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b, ldb, reorderb, beta, c, ldc, post_op ); + } + else if ( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) + { + /* Reorder B.*/ + reordera = 'n'; + reorderb = 'r'; + + int8_t* b_reorder = aocl_reorder( b, k, n, ldb ); + + aocl_gemm_driver_u8s8s32os32(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b_reorder, ldb, reorderb, beta, c, ldc, post_op ); + + free( b_reorder ); + } +} + +static double mat_mul_accuracy_check_driver_u8s8s32os32 + ( + const char stor_order, + dim_t m, + dim_t n, + dim_t k, + int32_t alpha, + uint8_t* a, + dim_t lda, + int8_t* b, + dim_t ldb, + int32_t beta, + int32_t* c, + dim_t ldc, + int32_t* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_a = lda; + dim_t cs_a = 1; + dim_t rs_b = ldb; + dim_t cs_b = 1; + dim_t rs_c = ldc; + dim_t cs_c = 1; + + if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + rs_a = 1; + cs_a = lda; + rs_b = 1; + cs_b = ldb; + rs_c = 1; + cs_c = ldc; + } + + resid = mat_mul_accuracy_check_driver( m, n, k, + alpha, a, rs_a, cs_a, b, rs_b, cs_b, beta, c, rs_c, cs_c, c_ref, post_op, + dscale_out ); + + return resid; +} +#endif + +double libblis_test_op_gemm_u8s8s32os32 ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + double resid = 0.0; +#ifdef BLIS_ENABLE_ADDONS + dim_t m, n, k; + dim_t lda, ldb, ldc; + char* post_ops_str = NULL; + char* post_ops_str_dest = NULL; + aocl_post_op* post_op = NULL; + char stor_order = sc_str[0]; + char transa = 'n'; //pc_str[0]; + char transb = 'n'; //pc_str[1]; + bool dscale_out = false; + + stor_order = ( ( stor_order == 'r' ) || ( stor_order == 'R' ) || + ( stor_order == 'c' ) || ( stor_order == 'C' ) ) ? + stor_order : 'r'; + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->k; + n = dim->n; + + if( ( stor_order == 'r' ) || ( stor_order == 'R' ) ) + { + lda = k; // a = mxk; + ldb = n; // b = kxn; + ldc = n; // c = mxn; + } + else if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + lda = m; + ldb = k; + ldc = m; + cout << "Column Major not supported" << endl; + return resid; + } + + + /* Get 64 byte aligned memory.*/ + uint8_t* a = ( uint8_t* ) malloc( sizeof( uint8_t ) * m * k ); + + int8_t* b = ( int8_t* ) malloc( sizeof( int8_t ) * n * k ); + + int32_t* c = ( int32_t* ) malloc( sizeof( int32_t ) * m * n ); + memset( ( void* ) c, 0, sizeof( int32_t ) * m * n ); + + int32_t* c_ref = ( int32_t* ) malloc( sizeof( int32_t ) * m * n ); + memset( ( void* ) c_ref, 0, sizeof( int32_t ) * m * n ); + + int32_t alpha = 2; + int32_t beta = 9; + + fill_array( a, ( m * k ) ); + fill_array( b, ( k * n ) ); + + if ( post_ops_str != NULL ) + { + post_ops_str_dest = strdup( post_ops_str ); + } + + if( ( post_ops_str != NULL ) || ( dscale_out ) ) + { + post_op = lpgemm_create_post_ops_struct + ( m, n, post_ops_str_dest, dscale_out ); + if ( post_op == NULL ) + { + printf(" post op struct allocation failure, returning.n"); + return -1; + } + } + + mat_mul_driver_u8s8s32os32(params, stor_order, transa, transb, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, post_op ); + +#ifndef __GTEST_VALGRIND_TEST__ + resid = mat_mul_accuracy_check_driver_u8s8s32os32( stor_order, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, c_ref, post_op, + dscale_out ); +#endif + + if ( post_op != NULL ) + lpgemm_destroy_post_ops_struct( post_op ); + + // Free the test objects. + if ( a != NULL ) + free( a ); + if ( b != NULL ) + free( b ); + if ( c != NULL ) + free( c ); + if ( c_ref != NULL ) + free( c_ref ); + + if ( post_ops_str_dest != NULL ) + free( post_ops_str_dest ); + +#else + cout << "CPU Arch do not support AVX512" << endl; +#endif + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemm_u8s8s32os8.cpp b/gtestsuite/src/test_gemm_u8s8s32os8.cpp new file mode 100644 index 000000000..374bd42e9 --- /dev/null +++ b/gtestsuite/src/test_gemm_u8s8s32os8.cpp @@ -0,0 +1,248 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "lpgemm_utils.h" + +#ifdef BLIS_ENABLE_ADDONS +static int8_t* aocl_reorder(int8_t* b, dim_t k, dim_t n, dim_t ldb) { + siz_t b_reorder_buf_siz_req; + b_reorder_buf_siz_req = aocl_get_reorder_buf_size_u8s8s32os32('B',k, n); + int8_t* b_reorder = ( int8_t* )malloc( b_reorder_buf_siz_req ); + aocl_reorder_u8s8s32os32('B', b, b_reorder, k, n, ldb ); + return b_reorder; +} + +static void aocl_gemm_driver_u8s8s32os8( + uint32_t n_repeats, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + int32_t alpha, + uint8_t* a, + dim_t lda, + char reordera, + int8_t* b, + dim_t ldb, + char reorderb, + int32_t beta, + int8_t* c, + dim_t ldc, + aocl_post_op* post_op +) { + uint32_t i; + char storage = stor_order; + for ( i = 0; i < n_repeats; i++ ) { + memset( ( void* ) c, 0, sizeof( int8_t ) * (m * n) ); + + aocl_gemm_u8s8s32os8(storage, transa, transb, m, n, k, + alpha, a, lda, reordera, b, + ldb, reorderb, beta, c, ldc, post_op ); +/* + aocl_gemm_u8s8s32os8(storage, (const char)transa, (const char)transb, (const dim_t)m, (const dim_t)n, (const dim_t)k, + (const int8_t)alpha, (const uint8_t *)a, (const dim_t)lda, (const char)reordera, (const int8_t *)b, + (const dim_t)ldb, (const char)reorderb, (const int8_t)beta, c, (const dim_t)ldc, post_op ); +*/ + } +} + +static void mat_mul_driver_u8s8s32os8( + test_params_t* params, + char stor_order, + char transa, + char transb, + dim_t m, + dim_t n, + dim_t k, + int32_t alpha, + uint8_t* a, + dim_t lda, + int8_t* b, + dim_t ldb, + int32_t beta, + int8_t* c, + dim_t ldc, + aocl_post_op* post_op +) { + char reordera; + char reorderb; + + if ( ( params->op_t == 'p' ) || ( params->op_t == 'P' ) ) + { + /* No reordering of B.*/ + reordera = 'n'; + reorderb = 'n'; + + aocl_gemm_driver_u8s8s32os8(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b, ldb, reorderb, beta, c, ldc, post_op ); + } + else if ( ( params->op_t == 'r' ) || ( params->op_t == 'R' ) ) + { + /* Reorder B.*/ + reordera = 'n'; + reorderb = 'r'; + + int8_t* b_reorder = aocl_reorder( b, k, n, ldb ); + + aocl_gemm_driver_u8s8s32os8(params->n_repeats, stor_order, transa, transb, m, n, k, + alpha, a, lda, reordera, b_reorder, ldb, reorderb, beta, c, ldc, post_op ); + + free( b_reorder ); + } +} + +static double mat_mul_accuracy_check_driver_u8s8s32os8 + ( + const char stor_order, + dim_t m, + dim_t n, + dim_t k, + int32_t alpha, + uint8_t* a, + dim_t lda, + int8_t* b, + dim_t ldb, + int32_t beta, + int8_t* c, + dim_t ldc, + int8_t* c_ref, + aocl_post_op* post_op, + bool dscale_out + ) +{ + double resid = 0.0; + dim_t rs_a = lda; + dim_t cs_a = 1; + dim_t rs_b = ldb; + dim_t cs_b = 1; + dim_t rs_c = ldc; + dim_t cs_c = 1; + + if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + rs_a = 1; + cs_a = lda; + rs_b = 1; + cs_b = ldb; + rs_c = 1; + cs_c = ldc; + } + + resid = mat_mul_accuracy_check_driver( m, n, k, + alpha, a, rs_a, cs_a, b, rs_b, cs_b, beta, c, rs_c, cs_c, c_ref, post_op, + dscale_out ); + + return resid; +} +#endif + +double libblis_test_op_gemm_u8s8s32os8 ( + test_params_t* params, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + double resid = 0.0; +#ifdef BLIS_ENABLE_ADDONS + dim_t m, n, k; + dim_t lda, ldb, ldc; + char* post_ops_str = NULL; + char* post_ops_str_dest = NULL; + aocl_post_op* post_op = NULL; + char stor_order = sc_str[0]; + char transa = 'n'; //pc_str[0]; + char transb = 'n'; //pc_str[1]; + bool dscale_out = true; + + stor_order = ( ( stor_order == 'r' ) || ( stor_order == 'R' ) || + ( stor_order == 'c' ) || ( stor_order == 'C' ) ) ? + stor_order : 'r'; + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->k; + n = dim->n; + + if( ( stor_order == 'r' ) || ( stor_order == 'R' ) ) + { + lda = k; // a = mxk; + ldb = n; // b = kxn; + ldc = n; // c = mxn; + } + else if ( ( stor_order == 'C' ) || ( stor_order == 'c' ) ) + { + lda = m; + ldb = k; + ldc = m; + cout << "Column Major not supported" << endl; + return resid; + } + + + /* Get 64 byte aligned memory.*/ + uint8_t* a = ( uint8_t* ) malloc( sizeof( uint8_t ) * m * k ); + + int8_t* b = ( int8_t* ) malloc( sizeof( int8_t ) * n * k ); + + int8_t* c = ( int8_t* ) malloc( sizeof( int8_t ) * m * n ); + memset( ( void* ) c, 0, sizeof( int8_t ) * m * n ); + + int8_t* c_ref = ( int8_t* ) malloc( sizeof( int8_t ) * m * n ); + memset( ( void* ) c_ref, 0, sizeof( int8_t ) * m * n ); + + int32_t alpha = 2; + int32_t beta = 9; + + fill_array( a, ( m * k ) ); + fill_array( b, ( k * n ) ); + + if ( post_ops_str != NULL ) + { + post_ops_str_dest = strdup( post_ops_str ); + } + + if( ( post_ops_str != NULL ) || ( dscale_out ) ) + { + post_op = lpgemm_create_post_ops_struct + ( m, n, post_ops_str_dest, dscale_out ); + if ( post_op == NULL ) + { + printf(" post op struct allocation failure, returning.n"); + return -1; + } + } + + mat_mul_driver_u8s8s32os8(params, stor_order, transa, transb, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, post_op ); + +#ifndef __GTEST_VALGRIND_TEST__ + resid = mat_mul_accuracy_check_driver_u8s8s32os8( stor_order, m, n, k, alpha, + a, lda, b, ldb, beta, c, ldc, c_ref, post_op, + dscale_out ); +#endif + + if ( post_op != NULL ) + lpgemm_destroy_post_ops_struct( post_op ); + + // Free the test objects. + if ( a != NULL ) + free( a ); + if ( b != NULL ) + free( b ); + if ( c != NULL ) + free( c ); + if ( c_ref != NULL ) + free( c_ref ); + + if ( post_ops_str_dest != NULL ) + free( post_ops_str_dest ); + +#else + cout << "CPU Arch do not support AVX512" << endl; +#endif + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemmt.cpp b/gtestsuite/src/test_gemmt.cpp new file mode 100644 index 000000000..f44c80fec --- /dev/null +++ b/gtestsuite/src/test_gemmt.cpp @@ -0,0 +1,597 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_gemmt.h" + +void libblis_test_gemmt_impl( + iface_t iface, + obj_t *alpha, + obj_t *a, + obj_t *b, + obj_t *beta, + obj_t *c +); + +double libblis_test_gemmt_check( + test_params_t *params, + obj_t *alpha, + obj_t *a, + obj_t *b, + obj_t *beta, + obj_t *c, + obj_t *c_orig +); + +double cblas_gemmt( + test_params_t* params, + uplo_t uploc, + f77_int n, + f77_int k, + f77_int lda, + f77_int ldb, + f77_int ldc, + obj_t* a, + obj_t* b, + obj_t* c, + obj_t* alpha, + obj_t* beta, + num_t dt, + trans_t transa, + trans_t transb +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_TRANSPOSE cblas_transa; + enum CBLAS_TRANSPOSE cblas_transb; + enum CBLAS_UPLO cblas_uplo; + + if ( bli_obj_row_stride( c ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_upper( uploc ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + if( bli_is_trans( transa ) ) + cblas_transa = CblasTrans; + else if( bli_is_conjtrans( transa ) ) + cblas_transa = CblasConjTrans; + else + cblas_transa = CblasNoTrans; + + if( bli_is_trans( transb ) ) + cblas_transb = CblasTrans; + else if( bli_is_conjtrans( transb ) ) + cblas_transb = CblasConjTrans; + else + cblas_transb = CblasNoTrans; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + cblas_sgemmt( cblas_order, cblas_uplo, cblas_transa, cblas_transb, + n, k, *alphap, ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + cblas_dgemmt( cblas_order, cblas_uplo, cblas_transa, cblas_transb, + n, k, *alphap, ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cblas_cgemmt( cblas_order, cblas_uplo, cblas_transa, cblas_transb, + n, k, alphap, ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + cblas_zgemmt( cblas_order, cblas_uplo, cblas_transa, cblas_transb, + n, k, alphap, ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return 0; +} + +double blas_gemmt( + f77_char f77_uploc, + f77_int n, + f77_int k, + f77_int lda, + f77_int ldb, + f77_int ldc, + obj_t* a, + obj_t* b, + obj_t* c, + obj_t* alpha, + obj_t* beta, + num_t dt, + f77_char f77_transa, + f77_char f77_transb +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + sgemmt_( &f77_uploc, &f77_transa, &f77_transb, &n, &k, alphap, ap, + (f77_int*)&lda, bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + dgemmt_( &f77_uploc, &f77_transa, &f77_transb, &n, &k, alphap, ap, + (f77_int*)&lda, bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cgemmt_( &f77_uploc, &f77_transa, &f77_transb, &n, &k, alphap, ap, + (f77_int*)&lda, bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + zgemmt_( &f77_uploc, &f77_transa, &f77_transb, &n, &k, alphap, ap, + (f77_int*)&lda, bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_gemmt( + test_params_t* params, + iface_t iface, + obj_t *alpha, + obj_t *a, + obj_t *b, + obj_t *beta, + obj_t *c, + num_t dt +) { + + if(params->api == API_BLIS) { + libblis_test_gemmt_impl(iface, alpha, a, b, beta, c); + } + else { /*CLBAS || BLAS */ + f77_int kk = bli_obj_width_after_trans( a ); + f77_int nn = bli_obj_width( c ); + uplo_t uploc = bli_obj_uplo( c ); + trans_t transa = bli_obj_conjtrans_status( a ); + trans_t transb = bli_obj_conjtrans_status( b ); + f77_int lda, ldb, ldc; + + if( bli_obj_row_stride( c ) == 1 ) { + lda = bli_obj_col_stride( a ); + ldb = bli_obj_col_stride( b ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldb = bli_obj_row_stride( b ); + ldc = bli_obj_row_stride( c ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldb = ldb + params->ld[1]; + ldc = ldc + params->ld[2]; + } + + if(bli_obj_has_notrans(a) && bli_obj_has_conj(a)) { + conjugate_tensor(a, dt); + transa = bli_obj_onlytrans_status( a ); + } + + if(bli_obj_has_notrans(b) && bli_obj_has_conj(b)) { + conjugate_tensor(b, dt); + transb = bli_obj_onlytrans_status( b ); + } + + if(params->api == API_CBLAS) { + cblas_gemmt( params, uploc, nn, kk, lda, ldb, ldc, a, b, c, + alpha, beta, dt, transa, transb); + } else { /**/ + f77_char f77_transa; + f77_char f77_transb; + f77_char f77_uploc; + + if(transa == BLIS_TRANSPOSE) f77_transa='T'; + else if ( transa == BLIS_CONJ_TRANSPOSE ) f77_transa='C'; + else /*if ( transa == BLIS_NO_TRANSPOSE )*/ f77_transa='N'; + + if(transb == BLIS_TRANSPOSE) f77_transb='T'; + else if ( transb == BLIS_CONJ_TRANSPOSE ) f77_transb='C'; + else /*if ( transb == BLIS_NO_TRANSPOSE )*/ f77_transb='N'; + + if( bli_obj_row_stride( c ) == 1 ) { + bli_param_map_blis_to_netlib_uplo( uploc, &f77_uploc ); + blas_gemmt(f77_uploc, nn, kk, lda, ldb, ldc, a, b, c, + alpha, beta, dt, f77_transa, f77_transb); + }else { + if( uploc == BLIS_UPPER) + uploc = BLIS_LOWER; + else if(uploc == BLIS_LOWER) + uploc = BLIS_UPPER; + + bli_param_map_blis_to_netlib_uplo( uploc, &f77_uploc ); + blas_gemmt(f77_uploc, nn, kk, ldb, lda, ldc, b, a, c, + alpha, beta, dt, f77_transb, f77_transa); + } + } + } + return ; +} + +double libblis_ref_gemmt( + test_params_t* params, + obj_t * alpha, + obj_t * a, + obj_t * b, + obj_t * beta, + obj_t * c, + obj_t * c_ref, + obj_t * c_orig +){ + double resid = 0.0; + double *betap = (double *)bli_obj_buffer( beta ); + + if ((params->nanf) && (*betap == 0)) { + resid = libblis_check_nan_gemmt( c ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_gemmt_check(params, alpha, a, b, beta, c, c_ref); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_igemmt_check(params, alpha, a, b, beta, c, c_orig); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_gemmt( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_gemmt_impl(iface, alpha, a, b, beta, r); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_gemmt ( + test_params_t *params, + iface_t iface, + char *dc_str, + char *pc_str, + char *sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m, k; + uplo_t uploc; + trans_t transa, transb; + obj_t alpha, a, b, beta; + obj_t c, c_ref, c_org_tri, c_result_tri, c_save; + double resid = 0.0; + obj_t aa,bb; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt(dc_str[0], &datatype); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo(pc_str[0], &uploc); + bli_param_map_char_to_blis_trans(pc_str[1], &transa); + bli_param_map_char_to_blis_trans(pc_str[2], &transb); + + // Create test scalars. + bli_obj_scalar_init_detached(datatype, &alpha); + bli_obj_scalar_init_detached(datatype, &beta); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create(params, datatype, transa, + sc_str[1], m, k, &a); + libblis_test_mobj_create(params, datatype, transa, + sc_str[1], m, k, &aa); + libblis_test_mobj_create(params, datatype, transb, + sc_str[2], k, m, &b); + libblis_test_mobj_create(params, datatype, transb, + sc_str[2], k, m, &bb); + libblis_test_mobj_create(params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c); + libblis_test_mobj_create(params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c_save); + libblis_test_mobj_create(params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c_ref); + libblis_test_mobj_create(params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c_org_tri); + libblis_test_mobj_create(params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c_result_tri); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if (bli_obj_is_real(&c)) { + bli_setsc(alpv.real, 0.0, &alpha); + bli_setsc(betv.real, 0.0, &beta); + } + else { + // For gemmt, both alpha and beta may be complex since, unlike herk, + // C is symmetric in both the real and complex cases. + bli_setsc(alpv.real, (alpv.real/0.8), &alpha); + bli_setsc(betv.real, (betv.real/1.2), &beta); + } + // Randomize A and B + libblis_test_mobj_randomize(params, TRUE, &a); + libblis_test_mobj_randomize(params, TRUE, &b); + + // Generate random input matrix + libblis_test_mobj_randomize(params, TRUE, &c); + } + else { + int32_t x = (int32_t)alpv.real; + int32_t y = (int32_t)betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + int32_t ac = (int32_t)(x/0.8); + int32_t bc = (int32_t)(y/1.0); + bli_setsc( (double)x, (double)ac, &alpha ); + bli_setsc( (double)y, (double)bc, &beta ); + } + + // Randomize A and B + libblis_test_mobj_irandomize( params, &a ); + libblis_test_mobj_irandomize( params, &b ); + + // Generate random input matrix + libblis_test_mobj_irandomize( params, &c ); + } + + bli_copym( &a, &aa ); + bli_copym( &b, &bb ); + + // Apply the remaining parameters. + // We need to do this before we create the referece matrix + bli_obj_set_conjtrans(transa, &a); + bli_obj_set_conjtrans(transb, &b); + + // Create the requried copies before setting the uplo attribute + bli_copym(&c, &c_save); + bli_copym(&c, &c_org_tri); + bli_copym(&c, &c_result_tri); + bli_obj_set_uplo(uploc, &c); + bli_obj_set_uplo(uploc, &c_save); + + // Create c_org_tri matrix using setm operation, this matrix will + // have original values from input matrix "c" for all elements outside + // triangle selected for GEMMT operation. + bli_obj_set_uplo(uploc, &c_org_tri); // Set to request uplo to set all elemnts in triangle to zero + bli_setm(&BLIS_ZERO, &c_org_tri); + bli_obj_toggle_uplo(&c_org_tri); // Toggle uplo now so that untouched triangle is active. + + // GEMMT output is same as GEMM for the triangle selected by uplo + // So we want to extract this triangle from complete GEMM results + // We do this by setting the uplo and converting the results + // to triangluer matrix. + // Perform gemm operation on original inputs + bli_gemm(&alpha, &a, &b, &beta, &c_result_tri); + // Set the values in other triangle to zero by converting it to trianguler matrix + bli_obj_set_uplo(uploc, &c_result_tri); + bli_mktrim(&c_result_tri); + + // Now we have two matrices with opposite triangles set to zero + // c_result_tri: It has output of GEMM in selected triangle (including diagonal) + // Rest of its elements are set to zero. + // c_org_tri: It has values from orignal C matrix in the non-selected triangle + // Rest of the elements including diagonal are set to zero + // The result of the GEMMT operation will be combined matrix of thse two matrics + // So add them togher + bli_setm(&BLIS_ZERO, &c_ref); // Both matrices we are going to add, have uplo settings + // Clear the destination matrix to avoid partial updates + bli_copym(&c_org_tri, &c_ref); + bli_addm(&c_result_tri, &c_ref); + + if ((params->nanf)) { + test_fillbuffmem(&c, datatype ); + } + + //Copy c to c_save + bli_copym( &c, &c_save ); + + bli_obj_set_conjtrans( transa, &aa ); + bli_obj_set_conjtrans( transb, &bb ); + + libblis_api_gemmt(params, iface, &alpha, &aa, &bb, &beta, &c, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create(params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &r); + + resid = libblis_test_bitrp_gemmt( params, iface, &alpha, &a, &b, &beta, + &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_gemmt(params, &alpha, &a, &b, &beta, &c, &c_ref, &c_save); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem(&c, &resid); + + // Free the test objects. + libblis_test_obj_free(&a); + libblis_test_obj_free(&aa); + libblis_test_obj_free(&b); + libblis_test_obj_free(&bb); + libblis_test_obj_free(&c); + libblis_test_obj_free(&c_ref); + libblis_test_obj_free(&c_org_tri); + libblis_test_obj_free(&c_result_tri); + libblis_test_obj_free(&c_save); + + return abs(resid); +} + +void libblis_test_gemmt_impl( + iface_t iface, + obj_t *alpha, + obj_t *a, + obj_t *b, + obj_t *beta, + obj_t *c +) { + switch (iface) { + case BLIS_TEST_SEQ_FRONT_END: + bli_gemmt(alpha, a, b, beta, c); + break; + + default: + libblis_test_printf_error("Invalid interface type.\n"); + } +} + +double libblis_test_gemmt_check( + test_params_t *params, + obj_t *alpha, + obj_t *a, + obj_t *b, + obj_t *beta, + obj_t *c, + obj_t *c_orig +) { + num_t dt = bli_obj_dt(c); + num_t dt_real = bli_obj_dt_proj_to_real(c); + + dim_t m = bli_obj_length(c); + + obj_t norm; + obj_t t, v, z; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - a is randomized. + // - b is randomized. + // - c is randomized with uplo set + // + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * transa(A) * transa(B) + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // z = C * C_reference + // + // + + bli_obj_scalar_init_detached(dt_real, &norm); + + bli_obj_create(dt, m, 1, 0, 0, &t); + bli_obj_create(dt, m, 1, 0, 0, &v); + bli_obj_create(dt, m, 1, 0, 0, &z); + + libblis_test_vobj_randomize(params, TRUE, &t); + + // Ensure result metrix has only selected triangle. + // Calculate V = C * t + bli_gemv(&BLIS_ONE, c, &t, &BLIS_ZERO, &v); + bli_gemv(&BLIS_ONE, c_orig, &t, &BLIS_ZERO, &z); + + // Find the norm + bli_subv(&z, &v); + bli_normfv(&v, &norm); + bli_getsc(&norm, &resid, &junk); + + bli_obj_free(&t); + bli_obj_free(&v); + bli_obj_free(&z); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemmt.h b/gtestsuite/src/test_gemmt.h new file mode 100644 index 000000000..2e8e88fb8 --- /dev/null +++ b/gtestsuite/src/test_gemmt.h @@ -0,0 +1,95 @@ +#ifndef TEST_GEMMT_H +#define TEST_GEMMT_H + +#include "blis_test.h" + +double libblis_test_igemmt_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ); + +template +void libblis_igemv_check + ( + trans_t transA, + dim_t M, + dim_t N, + T* alpha, + T* A, + dim_t rsa, + dim_t csa, + T* X, + dim_t incx, + T* beta, + T* Y, + dim_t incy + ); + +template +void libblis_icgemv_check + ( + trans_t transA, + dim_t M, + dim_t N, + T* alpha, + T* A, + dim_t rsa, + dim_t csa, + bool conja, + T* X, + dim_t incx, + T* beta, + T* Y, + dim_t incy, + bool conjx + ); + +template +void libblis_igemm_check + ( + dim_t M, + dim_t N, + dim_t K, + T* alpha, + T* A, + dim_t rsa, + dim_t csa, + T* B, + dim_t rsb, + dim_t csb, + T* beta, + T* C, + dim_t rsc, + dim_t csc + ); + +template +void libblis_icgemm_check + ( + dim_t M, + dim_t N, + dim_t K, + T* alpha, + T* A, + dim_t rsa, + dim_t csa, + bool conja, + T* B, + dim_t rsb, + dim_t csb, + bool conjb, + T* beta, + T* C, + dim_t rsc, + dim_t csc + ); + +double libblis_check_nan_gemmt( obj_t* c ); + +#endif /* TEST_GEMMT_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_gemv.cpp b/gtestsuite/src/test_gemv.cpp new file mode 100644 index 000000000..773468e76 --- /dev/null +++ b/gtestsuite/src/test_gemv.cpp @@ -0,0 +1,536 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_gemv.h" + +// Local prototypes. +void libblis_test_gemv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_gemv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y +); + +double libblis_test_gemv_check ( + test_params_t* params, + obj_t* kappa, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +); + +void cblas_gemv( + f77_int m, + f77_int n, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + obj_t* beta, + obj_t* y, + f77_int incy, + trans_t transa, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_TRANSPOSE cblas_trans; + + if ( bli_obj_row_stride( a ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_trans(transa ) ) + cblas_trans = CblasTrans; + else if( bli_is_conjtrans(transa ) ) + cblas_trans = CblasConjTrans; + else + cblas_trans = CblasNoTrans; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* betap = (float*) bli_obj_buffer( beta ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_sgemv( cblas_order, cblas_trans, m, n, + *alphap, ap, lda, xp, incx, *betap, yp, incy ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* betap = (double*) bli_obj_buffer( beta ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_dgemv( cblas_order, cblas_trans, m, n, + *alphap, ap, lda, xp, incx, *betap, yp, incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cblas_cgemv( cblas_order, cblas_trans, m, n, + alphap, ap, lda, xp, incx, betap, yp, incy ); + + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + cblas_zgemv( cblas_order, cblas_trans, m, n, + alphap, ap, lda, xp, incx, betap, yp, incy ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void gemv_(f77_char f77_trans, f77_int m, f77_int n, scomplex* alpha, +scomplex* ap, f77_int lda, scomplex* xp, f77_int incx, scomplex* beta, +scomplex* yp, f77_int incy){ + cgemv_( &f77_trans, &m, &n, alpha, ap, &lda, xp, &incx, beta, yp, &incy); +} + +void gemv_(f77_char f77_trans, f77_int m, f77_int n, dcomplex* alpha, +dcomplex* ap, f77_int lda, dcomplex* xp, f77_int incx, dcomplex* beta, +dcomplex* yp, f77_int incy){ + zgemv_( &f77_trans, &m, &n, alpha, ap, &lda, xp, &incx, beta, yp, &incy); +} + +void blas_gemv( + trans_t transa, + f77_int m, + f77_int n, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + obj_t* beta, + obj_t* y, + f77_int incy, + num_t dt +){ + f77_char f77_trans; + + bli_param_map_blis_to_netlib_trans( transa, &f77_trans ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* betap = (float*) bli_obj_buffer( beta ); + float* yp = (float*) bli_obj_buffer( y ); + sgemv_( &f77_trans, &m, &n, alphap, ap, &lda, xp, + &incx, betap, yp, &incy ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* betap = (double*) bli_obj_buffer( beta ); + double* yp = (double*) bli_obj_buffer( y ); + dgemv_( &f77_trans, &m, &n, alphap, ap, &lda, xp, + &incx, betap, yp, &incy ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cgemv_( &f77_trans, &m, &n, alphap, ap, &lda, xp, + &incx, betap, yp, &incy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + zgemv_( &f77_trans, &m, &n, alphap, ap, &lda, xp, + &incx, betap, yp, &incy ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_gemv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + num_t dt +) { + + if(params->api == API_BLIS) { + libblis_test_gemv_impl( iface, alpha, a, x, beta, y ); + } + else { /*CLBAS || BLAS */ + f77_int mm = bli_obj_length( a ); + f77_int nn = bli_obj_width( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + trans_t transa = bli_obj_conjtrans_status( a ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + if(bli_obj_has_notrans(a) && bli_obj_has_conj(a)) { + conjugate_tensor(a, dt); + transa = bli_obj_onlytrans_status( a ); + } + + if(bli_obj_has_conj(x)) { + conjugate_tensor(x, dt); + } + + if(params->api == API_CBLAS) { + cblas_gemv(mm, nn, alpha, a, lda, x, incx, beta, y, incy, transa, dt); + } + else { /**/ + if( bli_obj_row_stride( a ) == 1 ) { + blas_gemv(transa, mm, nn, alpha, a, lda, x, incx, beta, y, incy, dt); + } + else { + blas_gemv(transa, nn, mm, alpha, a, lda, x, incx, beta, y, incy, dt); + } + } + + if(bli_obj_has_conj(x)) { + conjugate_tensor(x, dt); + } + } + return ; +} + +double libblis_ref_gemv( + test_params_t* params, + obj_t* kappa, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + num_t dt +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_gemv_check( params, kappa, alpha, + a, x, beta, y, y_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_igemv_check( alpha, + a, x, beta, y, y_orig, dt); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_gemv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_gemv_impl( iface, alpha, a, x, beta, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + + +double libblis_test_op_gemv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m, n; + trans_t transa; + conj_t conjx; + obj_t kappa; + obj_t alpha, a, x, beta, y; + obj_t y_save; + double resid = 0.0; + obj_t aa; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + if(params->api != API_BLIS) { + bli_param_map_char_to_blas_trans( pc_str[0], &transa ); + } else { + bli_param_map_char_to_blis_trans( pc_str[0], &transa ); + } + + bli_param_map_char_to_blis_conj( pc_str[1], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &kappa ); + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transa, + sc_str[0], m, n, &a ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[0], m, n, &aa ); + libblis_test_vobj_create( params, datatype, + sc_str[1], n, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[2], m, &y ); + libblis_test_vobj_create( params, datatype, + sc_str[2], m, &y_save ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &y ) ) { + bli_setsc(alpv.real, 0.0, &alpha); + bli_setsc(betv.real, 0.0, &beta); + } + else { + bli_setsc(alpv.real, (alpv.real/0.8), &alpha); + bli_setsc(betv.real, (betv.real/1.2), &beta); + } + + // Randomize x and y, and save y. + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_vobj_randomize( params, TRUE, &y ); + } + else{ + int32_t xx = (int32_t)alpv.real; + int32_t yy = (int32_t)betv.real; + if ( bli_obj_is_real( &y ) ) { + bli_setsc( (double)xx, 0.0, &alpha ); + bli_setsc( (double)yy, 0.0, &beta ); + } + else { + // For syrk, both alpha and beta may be complex since, unlike herk, + // C is symmetric in both the real and complex cases. + int32_t ac = (int32_t)(xx/0.8); + int32_t bc = (int32_t)(yy/1.0); + bli_setsc( (double)xx, (double)ac, &alpha ); + bli_setsc( (double)yy, (double)bc, &beta ); + } + + // Randomize x and y, and save y. + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + // Initialize diagonal of matrix A. + bli_setsc( 2.0, -1.0, &kappa ); + bli_setm( &BLIS_ZERO, &a ); + bli_setd( &kappa, &a ); + + bli_copym( &a, &aa ); + + // Apply the parameters. + bli_obj_set_conjtrans( transa, &a ); + bli_obj_set_conj( conjx, &x ); + + bli_copyv( &y, &y_save ); + + bli_obj_set_conjtrans( transa, &aa ); + + libblis_api_gemv(params, iface, &alpha, &aa, &x, &beta, &y, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[2], m, &r ); + + resid = libblis_test_bitrp_gemv(params, iface, &alpha, &a, &x, &beta, + &y, &y_save, &r, datatype ); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_gemv(params, &kappa, &alpha, &a, &x, &beta, + &y, &y_save, datatype ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_gemv_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y +) { + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_gemv( alpha, a, x, beta, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_gemv_check ( + test_params_t* params, + obj_t* kappa, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + conj_t conja = bli_obj_conj_status( a ); + + dim_t n_x = bli_obj_vector_dim( x ); + dim_t m_y = bli_obj_vector_dim( y ); + + dim_t min_m_n = bli_min( m_y, n_x ); + + obj_t x_temp, y_temp; + obj_t kappac, norm; + obj_t xT_temp, yT_temp, yT; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is initialized to kappa along the diagonal. + // - x is randomized. + // - y_orig is randomized. + // Note: + // - alpha, beta, and kappa should have non-zero imaginary components in + // the complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := beta * y_orig + alpha * transa(A) * conjx(x) + // + // is functioning correctly if + // + // normfv( y - z ) + // + // is negligible, where + // + // z = beta * y_orig + alpha * conja(kappa) * x + // + + bli_obj_scalar_init_detached_copy_of( dt, conja, kappa, &kappac ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, n_x, 1, 0, 0, &x_temp ); + bli_obj_create( dt, m_y, 1, 0, 0, &y_temp ); + + bli_copyv( x, &x_temp ); + bli_copyv( y_orig, &y_temp ); + + bli_acquire_vpart_f2b( BLIS_SUBPART1, 0, min_m_n, + &x_temp, &xT_temp ); + bli_acquire_vpart_f2b( BLIS_SUBPART1, 0, min_m_n, + &y_temp, &yT_temp ); + bli_acquire_vpart_f2b( BLIS_SUBPART1, 0, min_m_n, + y, &yT ); + + bli_scalv( &kappac, &xT_temp ); + bli_scalv( beta, &yT_temp ); + bli_axpyv( alpha, &xT_temp, &yT_temp ); + + bli_subv( &yT_temp, &yT ); + bli_normfv( &yT, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + bli_obj_free( &y_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_gemv.h b/gtestsuite/src/test_gemv.h new file mode 100644 index 000000000..1b3ef82c6 --- /dev/null +++ b/gtestsuite/src/test_gemv.h @@ -0,0 +1,19 @@ +#ifndef TEST_GEMV_H +#define TEST_GEMV_H + +#include "blis_test.h" + +double libblis_test_igemv_check + ( + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + num_t dt + ); + +double libblis_check_nan_gemv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_GEMV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_ger.cpp b/gtestsuite/src/test_ger.cpp new file mode 100644 index 000000000..a6dbdbac7 --- /dev/null +++ b/gtestsuite/src/test_ger.cpp @@ -0,0 +1,455 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_ger.h" + +// Local prototypes. +void libblis_test_ger_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_ger_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a +); + +double libblis_test_ger_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +); + +void cblas_ger( + f77_int m, + f77_int n, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + obj_t* a, + f77_int lda, + num_t dt +){ + + enum CBLAS_ORDER cblas_order; + if ( bli_obj_row_stride( a ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_sger(cblas_order, m, n, *alphap, xp, incx, yp, incy, ap, lda ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_dger(cblas_order, m, n, *alphap, xp, incx, yp, incy, ap, lda ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + if( bli_obj_has_conj(x) != bli_obj_has_conj(y)) { + cblas_cgerc(cblas_order, m, n, alphap, xp, incx, yp, incy, ap, lda ); + } + else{ + cblas_cgeru(cblas_order, m, n, alphap, xp, incx, yp, incy, ap, lda ); + } + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + if( bli_obj_has_conj(x) != bli_obj_has_conj(y)) { + cblas_zgerc(cblas_order, m, n, alphap, xp, incx, yp, incy, ap, lda ); + } + else{ + cblas_zgeru(cblas_order, m, n, alphap, xp, incx, yp, incy, ap, lda ); + } + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_ger( + f77_int m, + f77_int n, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + obj_t* a, + f77_int lda, + num_t dt +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + sger_(&m, &n, alphap, xp, &incx, yp, &incy, ap, &lda ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + dger_(&m, &n, alphap, xp, &incx, yp, &incy, ap, &lda ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + if( bli_obj_has_conj(x) != bli_obj_has_conj(y)) { + cgerc_(&m, &n, alphap, xp, &incx, yp, &incy, ap, &lda ); + } + else { + cgeru_(&m, &n, alphap, xp, &incx, yp, &incy, ap, &lda ); + } + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + if( bli_obj_has_conj(x) != bli_obj_has_conj(y)) { + zgerc_(&m, &n, alphap, xp, &incx, yp, &incy, ap, &lda ); + } + else{ + zgeru_(&m, &n, alphap, xp, &incx, yp, &incy, ap, &lda ); + } + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_ger( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + num_t dt +){ + + if(params->api == API_BLIS) { + libblis_test_ger_impl( iface, alpha, x, y, a ); + } + else { /*CLBAS || BLAS */ + f77_int mm = bli_obj_length( a ); + f77_int nn = bli_obj_width( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + if(params->api == API_CBLAS) { + cblas_ger(mm, nn, alpha, x, incx, y, incy, a, lda, dt ); + } + else { /**/ + if ( bli_obj_row_stride( a ) == 1 ){ + blas_ger(mm, nn, alpha, x, incx, y, incy, a, lda, dt ); + } + else { + blas_ger(nn, mm, alpha, y, incy, x, incx, a, lda, dt ); + } + } + } + return ; +} + +double libblis_ref_ger( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_ger_check( params, alpha, x, y, a, a_save); + } + else { + resid = libblis_test_iger_check( params, alpha, x, y, a, a_save); + } + return resid; +} + +double libblis_test_bitrp_ger( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( a_orig, r ); + libblis_test_ger_impl( iface, alpha, x, y, r ); + resid = libblis_test_bitrp_vector(a, r, dt); + } + return resid; +} + +double libblis_test_op_ger ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m, n; + conj_t conjx, conjy; + obj_t alpha, x, y, a; + obj_t a_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjy ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, + sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[1], n, &y ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, n, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, n, &a_save ); + + // Set alpha. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &y ) ) { + //bli_setsc(alpv, 0.0, &alpha); + bli_setsc( -1.0, 1.0, &alpha ); + } + else { + //bli_setsc(alpv, (alpv/0.8), &alpha); + bli_setsc( -1.0, 1.0, &alpha ); + } + + // Randomize x and y. + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_vobj_randomize( params, TRUE, &y ); + } + else{ + int32_t xx = (int32_t)alpv.real; + if ( bli_obj_is_real( &y ) ) { + bli_setsc( (double)xx, 0.0, &alpha ); + } + else { + // For syrk, both alpha and beta may be complex since, unlike herk, + // C is symmetric in both the real and complex cases. + int32_t ac = (int32_t)(xx/0.8); + bli_setsc( (double)xx, (double)ac, &alpha ); + } + + // Randomize x and y, and save y. + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + + // Initialize A to identity and save. + bli_setm( &BLIS_ZERO, &a ); + bli_setd( &BLIS_ONE, &a ); + bli_copym( &a, &a_save ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + bli_obj_set_conj( conjy, &y ); + + // Perform checks. + libblis_api_ger(params, iface, &alpha, &x, &y, &a, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, n, &r ); + + resid = libblis_test_bitrp_ger( params, iface, &alpha, &x, &y, &a, + &a_save, &r, datatype ); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_ger( params, &alpha, &x, &y, &a, &a_save); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &a, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &a ); + libblis_test_obj_free( &a_save ); + + return abs(resid); +} + +void libblis_test_ger_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a +){ + switch( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_ger( alpha, x, y, a ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_ger_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +){ + num_t dt = bli_obj_dt( a ); + num_t dt_real = bli_obj_dt_proj_to_real( a ); + + dim_t m_a = bli_obj_length( a ); + dim_t n_a = bli_obj_width( a ); + + obj_t t, v, w; + obj_t rho, norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - y is randomized. + // - a is identity. + // Note: + // - alpha should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // A := A_orig + alpha * conjx(x) * conjy(y) + // + // is functioning correctly if + // + // normfv( v - w ) + // + // is negligible, where + // + // v = A * t + // w = ( A_orig + alpha * conjx(x) * conjy(y)^T ) * t + // = A_orig * t + alpha * conjx(x) * conjy(y)^T * t + // = A_orig * t + alpha * conjx(x) * rho + // = A_orig * t + w + // + + bli_obj_scalar_init_detached( dt, &rho ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, n_a, 1, 0, 0, &t ); + bli_obj_create( dt, m_a, 1, 0, 0, &v ); + bli_obj_create( dt, m_a, 1, 0, 0, &w ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, a, &t, &BLIS_ZERO, &v ); + + bli_dotv( y, &t, &rho ); + bli_mulsc( alpha, &rho ); + bli_scal2v( &rho, x, &w ); + bli_gemv( &BLIS_ONE, a_orig, &t, &BLIS_ONE, &w ); + + bli_subv( &w, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_ger.h b/gtestsuite/src/test_ger.h new file mode 100644 index 000000000..784374ed0 --- /dev/null +++ b/gtestsuite/src/test_ger.h @@ -0,0 +1,18 @@ +#ifndef TEST_GER_H +#define TEST_GER_H + +#include "blis_test.h" + +double libblis_test_iger_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig + ); + +double libblis_check_nan_ger( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_GER_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_hemm.cpp b/gtestsuite/src/test_hemm.cpp new file mode 100644 index 000000000..37a87be49 --- /dev/null +++ b/gtestsuite/src/test_hemm.cpp @@ -0,0 +1,551 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_hemm.h" + +using namespace std; + +// Local prototypes. +void libblis_test_hemm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_hemm_impl( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +); + +double libblis_test_hemm_check( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +); + +double cblas_hemm( + side_t side, + uplo_t uploa, + f77_int mm, + f77_int nn, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* b, + f77_int ldb, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uplo; + enum CBLAS_SIDE cblas_side; + + if ( bli_obj_row_stride( c ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if(bli_is_upper(uploa)) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + if(bli_is_left(side)) + cblas_side = CblasLeft; + else + cblas_side = CblasRight; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + cblas_ssymm( cblas_order, cblas_side, cblas_uplo, mm, nn, *alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + cblas_dsymm( cblas_order, cblas_side, cblas_uplo, mm, nn, *alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cblas_chemm( cblas_order, cblas_side, cblas_uplo, mm, nn, alphap, + ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + cblas_zhemm( cblas_order, cblas_side, cblas_uplo, mm, nn, alphap, + ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return 0; +} + +double blas_hemm( + side_t side, + uplo_t uploa, + f77_int mm, + f77_int nn, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* b, + f77_int ldb, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + + f77_char f77_side; + f77_char f77_uploa; + + bli_param_map_blis_to_netlib_side( side, &f77_side ); + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + ssymm_( &f77_side, &f77_uploa, &mm, &nn, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + dsymm_( &f77_side, &f77_uploa, &mm, &nn, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + chemm_( &f77_side, &f77_uploa, &mm, &nn, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + zhemm_( &f77_side, &f77_uploa, &mm, &nn, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_hemm( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_hemm_impl( iface, side, alpha, a, b, beta, c ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + f77_int mm = bli_obj_length( c ); + f77_int nn = bli_obj_width( c ); + f77_int lda, ldb, ldc; + + if( bli_obj_row_stride( c ) == 1 ) { + lda = bli_obj_col_stride( a ); + ldb = bli_obj_col_stride( b ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldb = bli_obj_row_stride( b ); + ldc = bli_obj_row_stride( c ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldb = ldb + params->ld[1]; + ldc = ldc + params->ld[2]; + } + + if(params->api == API_CBLAS) { + cblas_hemm( side, uploa, mm, nn, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } else { /**/ + if( bli_obj_row_stride( c ) == 1 ) { + blas_hemm( side, uploa, mm, nn, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } + else { + if( side == BLIS_LEFT) + side = BLIS_RIGHT; + else if(side == BLIS_RIGHT) + side = BLIS_LEFT; + + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + blas_hemm( side, uploa, nn, mm, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } + } + } + return ; +} + +double libblis_ref_hemm( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_save, + num_t dt +) { + + double resid = 0.0; + double *betap = (double *)bli_obj_buffer( beta ); + + if ((params->nanf) && (*betap == 0)) { + resid = libblis_check_nan_hemm(c, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_hemm_check( params, side, alpha, a, b, beta, c, c_save ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_ihemm_check( params, side, alpha, a, b, beta, c, c_save ); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_hemm( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_hemm_impl( iface, side, alpha, a, b, beta, r ); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_hemm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +) { + num_t datatype; + dim_t m, n; + dim_t mn_side; + side_t side; + uplo_t uploa; + obj_t alpha, a, b, beta, c; + obj_t c_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_side( pc_str[0], &side ); + bli_param_map_char_to_blis_uplo( pc_str[1], &uploa ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + bli_set_dim_with_side( side, m, n, &mn_side ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], mn_side, mn_side, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, n, &b ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &c ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &c_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_HERMITIAN, &a ); + bli_obj_set_uplo( uploa, &a ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &c ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + bli_setsc( betv.real, (betv.real/1.2), &beta ); + } + // Randomize A, B, and C, and save C. + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_mobj_randomize( params, TRUE, &b ); + libblis_test_mobj_randomize( params, TRUE, &c ); + } + else { + int32_t x = (int32_t)1.0; //alpv.real; + int32_t y = (int32_t)1.0; //betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + int32_t ac = (int32_t)(x/0.8); + int32_t bc = (int32_t)(y/1.0); + bli_setsc( (double)x, (double)ac, &alpha ); + bli_setsc( (double)y, (double)bc, &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_mobj_irandomize( params, &b ); + libblis_test_mobj_irandomize( params, &c ); + } + + if ((params->nanf) && (betv.real == 0) ) { + test_fillbuffmem(&c, datatype ); + } + + // Randomize A, make it densely Hermitian, and zero the unstored triangle + // to ensure the implementation reads only from the stored region. + bli_mkherm( &a ); + bli_mktrim( &a ); + + //Copy c to c_save + bli_copym( &c, &c_save ); + + libblis_api_hemm(params, iface, side, &alpha, &a, &b, &beta, &c, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + resid = libblis_test_bitrp_hemm( params, iface, side,&alpha, &a, &b, + &beta, &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_hemm(params, side, &alpha, &a, &b, &beta, + &c, &c_save, datatype ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &c, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &b ); + libblis_test_obj_free( &c ); + libblis_test_obj_free( &c_save ); + + return resid; +} + +void libblis_test_hemm_impl ( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +){ + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_hemm( side, alpha, a, b, beta, c ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_hemm_check ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +) { + num_t dt = bli_obj_dt( c ); + num_t dt_real = bli_obj_dt_proj_to_real( c ); + + dim_t m = bli_obj_length( c ); + dim_t n = bli_obj_width( c ); + + obj_t norm; + obj_t t, v, w, z; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - a is randomized and Hermitian. + // - b is randomized. + // - c_orig is randomized. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * conja(A) * transb(B) (side = left) + // C := beta * C_orig + alpha * transb(B) * conja(A) (side = right) + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // + // z = ( beta * C_orig + alpha * conja(A) * transb(B) ) * t (side = left) + // = beta * C_orig * t + alpha * conja(A) * transb(B) * t + // = beta * C_orig * t + alpha * conja(A) * w + // = beta * C_orig * t + z + // + // z = ( beta * C_orig + alpha * transb(B) * conja(A) ) * t (side = right) + // = beta * C_orig * t + alpha * transb(B) * conja(A) * t + // = beta * C_orig * t + alpha * transb(B) * w + // = beta * C_orig * t + z + + bli_obj_scalar_init_detached( dt_real, &norm ); + + if ( bli_is_left( side ) ) + { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, m, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + else // else if ( bli_is_right( side ) ) + { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, n, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, c, &t, &BLIS_ZERO, &v ); + + if ( bli_is_left( side ) ) + { + bli_gemv( &BLIS_ONE, b, &t, &BLIS_ZERO, &w ); + bli_hemv( alpha, a, &w, &BLIS_ZERO, &z ); + } + else // else if ( bli_is_right( side ) ) + { + bli_hemv( &BLIS_ONE, a, &t, &BLIS_ZERO, &w ); + bli_gemv( alpha, b, &w, &BLIS_ZERO, &z ); + } + + bli_gemv( beta, c_orig, &t, &BLIS_ONE, &z ); + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + bli_obj_free( &z ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_hemm.h b/gtestsuite/src/test_hemm.h new file mode 100644 index 000000000..68713eec3 --- /dev/null +++ b/gtestsuite/src/test_hemm.h @@ -0,0 +1,20 @@ +#ifndef TEST_HEMM_H +#define TEST_HEMM_H + +#include "blis_test.h" + +double libblis_test_ihemm_check + ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ); + +double libblis_check_nan_hemm(obj_t* c, num_t dt ); + +#endif /* TEST_HEMM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_hemv.cpp b/gtestsuite/src/test_hemv.cpp new file mode 100644 index 000000000..9a6c2bf71 --- /dev/null +++ b/gtestsuite/src/test_hemv.cpp @@ -0,0 +1,497 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_hemv.h" + +// Local prototypes. +void libblis_test_hemv_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_hemv_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y +); + +double libblis_test_hemv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +); + +void cblas_hemv( + uplo_t uploa, + f77_int m, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + obj_t* beta, + obj_t* y, + f77_int incy, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uplo ; + + if ( bli_obj_row_stride( a ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_upper( uploa ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* betap = (float*) bli_obj_buffer( beta ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_ssymv(cblas_order, cblas_uplo, m, *alphap, ap, lda, xp, incx, + *betap, yp, incy); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* betap = (double*) bli_obj_buffer( beta ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_dsymv(cblas_order, cblas_uplo, m, *alphap, ap, lda, xp, incx, + *betap, yp, incy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cblas_chemv(cblas_order, cblas_uplo, m, alphap, ap, lda, xp, incx, + betap, yp, incy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + cblas_zhemv(cblas_order, cblas_uplo, m, alphap, ap, lda, xp, incx, + betap, yp, incy); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_hemv( + f77_char f77_uploa, + f77_int m, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + obj_t* beta, + obj_t* y, + f77_int incy, + num_t dt +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* betap = (float*) bli_obj_buffer( beta ); + float* yp = (float*) bli_obj_buffer( y ); + ssymv_(&f77_uploa, &m, alphap, ap, (f77_int*)&lda, xp, &incx, + betap, yp, &incy); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* betap = (double*) bli_obj_buffer( beta ); + double* yp = (double*) bli_obj_buffer( y ); + dsymv_(&f77_uploa, &m, alphap, ap, (f77_int*)&lda, xp, &incx, + betap, yp, &incy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + chemv_(&f77_uploa, &m, alphap, ap, (f77_int*)&lda, xp, &incx, + betap, yp, &incy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + zhemv_(&f77_uploa, &m, alphap, ap, (f77_int*)&lda, xp, &incx, + betap, yp, &incy); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_hemv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y +){ + + if(params->api == API_BLIS) { + libblis_test_hemv_impl(iface, alpha, a, x, beta, y); + } + else { /*CLBAS || BLAS */ + num_t dt = bli_obj_dt( a ); + uplo_t uploa = bli_obj_uplo( a ); + f77_int mm = bli_obj_length( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + if( bli_obj_has_conj(a) ) { + conjugate_tensor(a, dt); + } + if( bli_obj_has_conj(x) ) { + conjugate_tensor(x, dt); + } + + if(params->api == API_CBLAS) { + cblas_hemv(uploa, mm, alpha, a, lda, x, incx, beta, y, incy, dt ); + } + else { /**/ + f77_char f77_uploa; + if ( bli_obj_row_stride( a ) == 1 ){ + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_hemv(f77_uploa, mm, alpha, a, lda, x, incx, beta, y, incy, dt ); + } + else { + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_hemv(f77_uploa, mm, alpha, a, lda, x, incx, beta, y, incy, dt ); + } + } + } + return ; +} + +double libblis_ref_hemv( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_hemv_check( params, alpha, a, x, beta, y, y_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_ihemv_check( params, alpha, a, x, beta, y, y_orig ); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_hemv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_hemv_impl( iface, alpha, a, x, beta, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_hemv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m; + uplo_t uploa; + conj_t conja; + conj_t conjx; + obj_t alpha, a, x, beta, y; + obj_t y_save; + double resid = 0.0; + obj_t aa, xx; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploa ); + bli_param_map_char_to_blis_conj( pc_str[1], &conja ); + bli_param_map_char_to_blis_conj( pc_str[2], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &aa ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &xx ); + libblis_test_vobj_create( params, datatype, + sc_str[2], m, &y ); + libblis_test_vobj_create( params, datatype, + sc_str[2], m, &y_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_HERMITIAN, &a ); + bli_obj_set_uplo( uploa, &a ); + + bli_obj_set_struc( BLIS_HERMITIAN, &aa ); + bli_obj_set_uplo( uploa, &aa ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &y ) ){ + bli_setsc( 1.0, 0.0, &alpha ); + bli_setsc( -1.0, 0.0, &beta ); + } + else{ + bli_setsc( 0.5, 0.5, &alpha ); + bli_setsc( -0.5, 0.5, &beta ); + } + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_vobj_randomize( params, TRUE, &y ); + } + else { + int32_t xx = (int32_t) 1.0; + int32_t yy = (int32_t)-1.0; + if ( bli_obj_is_real( &y ) ){ + bli_setsc( xx, 0.0, &alpha ); + bli_setsc( yy, 0.0, &beta ); + } + else{ + xx = (int32_t)(xx/0.8); + yy = (int32_t)(yy/1.5); + bli_setsc( xx, (xx+yy), &alpha ); + bli_setsc( yy, (xx-yy), &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + + // Randomize A, make it densely Hermitian, and zero the unstored triangle + // to ensure the implementation reads only from the stored region. + bli_mkherm( &a ); + bli_mktrim( &a ); + + // Randomize x and y, and save y. + bli_copyv( &y, &y_save ); + + bli_copym( &a, &aa ); + bli_copyv( &x, &xx ); + + // Apply the remaining parameters. + bli_obj_set_conj( conja, &a ); + bli_obj_set_conj( conjx, &x ); + + bli_obj_set_conj( conja, &aa ); + bli_obj_set_conj( conjx, &xx ); + + libblis_api_hemv(params, iface, &alpha, &aa, &xx, &beta, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[2], m, &r ); + + resid = libblis_test_bitrp_hemv( params, iface, &alpha, &a, &x, + &beta, &y, &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_hemv( params, &alpha, &a, &x, &beta, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_hemv_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_hemv( alpha, a, x, beta, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_hemv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( y ); + + obj_t v; + obj_t norm; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - a is randomized and Hermitian. + // - x is randomized. + // - y_orig is randomized. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := beta * y_orig + alpha * conja(A) * conjx(x) + // + // is functioning correctly if + // + // normfv( y - v ) + // + // is negligible, where + // + // v = beta * y_orig + alpha * conja(A_dense) * x + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &v ); + + bli_copyv( y_orig, &v ); + + bli_mkherm( a ); + bli_obj_set_struc( BLIS_GENERAL, a ); + bli_obj_set_uplo( BLIS_DENSE, a ); + + bli_gemv( alpha, a, x, beta, &v ); + + bli_subv( &v, y ); + bli_normfv( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &v ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_hemv.h b/gtestsuite/src/test_hemv.h new file mode 100644 index 000000000..d04d8bf15 --- /dev/null +++ b/gtestsuite/src/test_hemv.h @@ -0,0 +1,19 @@ +#ifndef TEST_HEMV_H +#define TEST_HEMV_H + +#include "blis_test.h" + +double libblis_test_ihemv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_hemv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_HEMV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_her.cpp b/gtestsuite/src/test_her.cpp new file mode 100644 index 000000000..a79133ec2 --- /dev/null +++ b/gtestsuite/src/test_her.cpp @@ -0,0 +1,436 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_her.h" + +// Local prototypes. +void libblis_test_her_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_her_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* a +); + +double libblis_test_her_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig +); + +void cblas_her( + uplo_t uploa, + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* a, + f77_int lda, + num_t dt +){ + enum CBLAS_UPLO cblas_uplo; + enum CBLAS_ORDER cblas_order = CblasColMajor; + + if ( bli_obj_row_stride( a ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_upper( uploa ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + cblas_ssyr(cblas_order, cblas_uplo, m, *alphap, xp, incx, ap, lda); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + cblas_dsyr(cblas_order, cblas_uplo, m, *alphap, xp, incx, ap, lda); + break; + } + case BLIS_SCOMPLEX : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cblas_cher(cblas_order, cblas_uplo, m, *alphap, xp, incx, ap, lda); + break; + } + case BLIS_DCOMPLEX : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + cblas_zher(cblas_order, cblas_uplo, m, *alphap, xp, incx, ap, lda); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_her( + f77_char f77_uploa, + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* a, + f77_int lda, + num_t dt +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + ssyr_(&f77_uploa, &m, alphap, xp, &incx, ap, (f77_int*)&lda ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + dsyr_(&f77_uploa, &m, alphap, xp, &incx, ap, (f77_int*)&lda ); + break; + } + case BLIS_SCOMPLEX : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cher_(&f77_uploa, &m, alphap, xp, &incx, ap, (f77_int*)&lda ); + break; + } + case BLIS_DCOMPLEX : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + zher_(&f77_uploa, &m, alphap, xp, &incx, ap, (f77_int*)&lda ); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_her( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* a, + num_t dt +){ + + if(params->api == API_BLIS) { + libblis_test_her_impl( iface, alpha, x, a ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + f77_int mm = bli_obj_length( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + if(params->api == API_CBLAS) { + cblas_her(uploa, mm, alpha, x, incx, a, lda, dt ); + } + else { /**/ + f77_char f77_uploa; + if ( bli_obj_row_stride( a ) == 1 ){ + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_her(f77_uploa, mm, alpha, x, incx, a, lda, dt ); + } + else { + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + conjugate_tensor(x, dt); + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_her(f77_uploa, mm, alpha, x, incx, a, lda, dt ); + } + } + } + return ; +} + +double libblis_ref_her( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_her_check( params, alpha, x, a, a_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iher_check( params, alpha, x, a, a_orig ); + } + else { + resid = libblis_test_matrix_check(params, a); + } + } + return resid; +} + +double libblis_test_bitrp_her( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( a_orig, r ); + bli_mktrim( r ); + libblis_test_her_impl( iface, alpha, x, r ); + resid = libblis_test_bitrp_matrix(a, r, dt); + } + return resid; +} + +double libblis_test_op_her ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + uplo_t uploa; + conj_t conjx; + obj_t alpha, x, a; + obj_t a_save; + double resid = 0.0; + obj_t xx; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploa ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, + sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[0], m, &xx ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, m, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, m, &a_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_HERMITIAN, &a ); + bli_obj_set_uplo( uploa, &a ); + + // Set alpha. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + bli_setsc( alpv.real, 0.0, &alpha ); + // Randomize x. + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_mobj_randomize( params, TRUE, &a ); + } + else{ + int32_t xx = (int32_t)alpv.real; + bli_setsc( (double)xx, (double)0.0, &alpha ); + // Randomize x. + libblis_test_vobj_irandomize( params, &x ); + libblis_test_mobj_irandomize( params, &a ); + } + + // Randomize A, make it densely Hermitian, and zero the unstored triangle + // to ensure the implementation is reads only from the stored region. + bli_mkherm( &a ); + bli_mktrim( &a ); + + // Save A and set its structure and uplo properties. + bli_obj_set_struc( BLIS_HERMITIAN, &a_save ); + bli_obj_set_uplo( uploa, &a_save ); + bli_copym( &a, &a_save ); + bli_mktrim( &a_save ); + + // Apply the remaining parameters. + bli_obj_set_conj( conjx, &x ); + + bli_copyv( &x, &xx ); + + libblis_api_her(params, iface, &alpha, &xx, &a, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, m, &r ); + bli_obj_set_struc( BLIS_HERMITIAN, &r ); + bli_obj_set_uplo( uploa, &r ); + + resid = libblis_test_bitrp_her( params, iface, &alpha, &x, &a, &a_save, + &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_her( params, &alpha, &x, &a, &a_save ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &a, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &a ); + libblis_test_obj_free( &a_save ); + + return abs(resid); +} + +void libblis_test_her_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* a +){ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_her( alpha, x, a ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_her_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig +){ + num_t dt = bli_obj_dt( a ); + num_t dt_real = bli_obj_dt_proj_to_real( a ); + + dim_t m_a = bli_obj_length( a ); + + obj_t xh, t, v, w; + obj_t rho, norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - a is randomized and Hermitian. + // Note: + // - alpha must be real-valued. + // + // Under these conditions, we assume that the implementation for + // + // A := A_orig + alpha * conjx(x) * conjx(x)^H + // + // is functioning correctly if + // + // normfv( v - w ) + // + // is negligible, where + // + // v = A * t + // w = ( A_orig + alpha * conjx(x) * conjx(x)^H ) * t + // = A_orig * t + alpha * conjx(x) * conjx(x)^H * t + // = A_orig * t + alpha * conjx(x) * rho + // = A_orig * t + w + // + + bli_mkherm( a ); + bli_mkherm( a_orig ); + bli_obj_set_struc( BLIS_GENERAL, a ); + bli_obj_set_struc( BLIS_GENERAL, a_orig ); + bli_obj_set_uplo( BLIS_DENSE, a ); + bli_obj_set_uplo( BLIS_DENSE, a_orig ); + + bli_obj_scalar_init_detached( dt, &rho ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m_a, 1, 0, 0, &t ); + bli_obj_create( dt, m_a, 1, 0, 0, &v ); + bli_obj_create( dt, m_a, 1, 0, 0, &w ); + + bli_obj_alias_with_conj( BLIS_CONJUGATE, x, &xh ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, a, &t, &BLIS_ZERO, &v ); + + bli_dotv( &xh, &t, &rho ); + bli_mulsc( alpha, &rho ); + bli_scal2v( &rho, x, &w ); + bli_gemv( &BLIS_ONE, a_orig, &t, &BLIS_ONE, &w ); + + bli_subv( &w, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_her.h b/gtestsuite/src/test_her.h new file mode 100644 index 000000000..1ebe673bb --- /dev/null +++ b/gtestsuite/src/test_her.h @@ -0,0 +1,17 @@ +#ifndef TEST_HER_H +#define TEST_HER_H + +#include "blis_test.h" + +double libblis_test_iher_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig + ); + +double libblis_check_nan_her( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_HER_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_her2.cpp b/gtestsuite/src/test_her2.cpp new file mode 100644 index 000000000..80fee07c3 --- /dev/null +++ b/gtestsuite/src/test_her2.cpp @@ -0,0 +1,497 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_her2.h" + +// Local prototypes. +void libblis_test_her2_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_her2_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a +); + +double libblis_test_her2_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +); + +void cblas_her2( + uplo_t uploa, + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + obj_t* a, + f77_int lda, + num_t dt +){ + enum CBLAS_UPLO cblas_uplo; + enum CBLAS_ORDER cblas_order; + if ( bli_obj_row_stride( a ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_upper( uploa ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_ssyr2(cblas_order, cblas_uplo, m, *alphap, xp, incx, + yp, incy, ap, lda); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_dsyr2(cblas_order, cblas_uplo, m, *alphap, xp, incx, + yp, incy, ap, lda); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cblas_cher2(cblas_order, cblas_uplo, m, alphap, xp, incx, + yp, incy, ap, lda); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + cblas_zher2(cblas_order, cblas_uplo, m, alphap, xp, incx, + yp, incy, ap, lda); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_her2( + f77_char f77_uploa, + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + obj_t* a, + f77_int lda, + num_t dt +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + ssyr2_(&f77_uploa, &m, alphap, xp, &incx, yp, &incy, ap, (f77_int*)&lda); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + dsyr2_(&f77_uploa, &m, alphap, xp, &incx, yp, &incy, ap, (f77_int*)&lda); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cher2_(&f77_uploa, &m, alphap, xp, &incx, yp, &incy, ap, (f77_int*)&lda); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + zher2_(&f77_uploa, &m, alphap, xp, &incx, yp, &incy, ap, (f77_int*)&lda); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_her2( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + num_t dt +){ + + if(params->api == API_BLIS) { + libblis_test_her2_impl( iface, alpha, x, y, a ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + f77_int mm = bli_obj_length( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + if(params->api == API_CBLAS) { + cblas_her2(uploa, mm, alpha, x, incx, y, incy, a, lda, dt ); + } + else { /**/ + f77_char f77_uploa; + if ( bli_obj_row_stride( a ) == 1 ){ + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_her2(f77_uploa, mm, alpha, x, incx, y, incy, a, lda, dt ); + } + else { + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + conjugate_tensor(x, dt); + conjugate_tensor(y, dt); + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_her2(f77_uploa, mm, alpha, y, incy, x, incx, a, lda, dt ); + } + } + } + return ; +} + +double libblis_ref_her2( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_her2_check( params, alpha, x, y, a, a_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iher2_check( params, alpha, x, y, a, a_orig); + } + else { + resid = libblis_test_matrix_check(params, a); + } + } + return resid; +} + +double libblis_test_bitrp_her2( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( a_orig, r ); + bli_mkherm( r ); + bli_mktrim( r ); + libblis_test_her2_impl( iface, alpha, x, y, r ); + resid = libblis_test_bitrp_matrix(a, r, dt); + } + return resid; +} + +double libblis_test_op_her2 ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + uplo_t uploa; + conj_t conjx, conjy; + obj_t alpha, x, y, a; + obj_t a_save; + double resid = 0.0; + obj_t xx, yy; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploa ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjx ); + bli_param_map_char_to_blis_conj( pc_str[2], &conjy ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, + sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[0], m, &xx ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &yy ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, m, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, m, &a_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_HERMITIAN, &a ); + bli_obj_set_uplo( uploa, &a ); + + // Set alpha. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &x ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + } + else { + bli_setsc( alpv.real, alpv.imag, &alpha ); + } + // Randomize x and y. + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_vobj_randomize( params, TRUE, &y ); + libblis_test_mobj_randomize( params, TRUE, &a ); + } + else{ + int32_t xx = (int32_t)alpv.real; + if ( bli_obj_is_real( &x ) ) { + bli_setsc( (double)xx, 0.0, &alpha ); + } + else { + int32_t ax = (int32_t)(xx/0.8); + bli_setsc( (double)xx, (double)ax, &alpha ); + } + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + libblis_test_mobj_irandomize( params, &a ); + } + + // Randomize A, make it densely Hermitian, and zero the unstored triangle + // to ensure the implementation is reads only from the stored region. + bli_mkherm( &a ); + bli_mktrim( &a ); + + // Save A and set its structure and uplo properties. + bli_obj_set_struc( BLIS_HERMITIAN, &a_save ); + bli_obj_set_uplo( uploa, &a_save ); + bli_copym( &a, &a_save ); + bli_mkherm( &a_save ); + bli_mktrim( &a_save ); + + // Apply the remaining parameters. + bli_obj_set_conj( conjx, &x ); + bli_obj_set_conj( conjy, &y ); + + bli_copyv( &x, &xx ); + bli_copyv( &y, &yy ); + + libblis_api_her2(params, iface, &alpha, &xx, &yy, &a, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, m, &r ); + bli_obj_set_struc( BLIS_HERMITIAN, &r ); + bli_obj_set_uplo( uploa, &r ); + + resid = libblis_test_bitrp_her2( params, iface, &alpha, &x, &y, + &a, &a_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_her2( params, &alpha, &x, &y, &a, &a_save ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &a, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &yy ); + libblis_test_obj_free( &a ); + libblis_test_obj_free( &a_save ); + + return abs(resid); +} + +void libblis_test_her2_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_her2( alpha, x, y, a ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_her2_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +){ + num_t dt = bli_obj_dt( a ); + num_t dt_real = bli_obj_dt_proj_to_real( a ); + + dim_t m_a = bli_obj_length( a ); + + obj_t xh, yh, alphac; + obj_t t, v, w1, w2; + obj_t rho, norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - y is randomized. + // - a is randomized and Hermitian. + // + // Under these conditions, we assume that the implementation for + // + // A := A_orig + alpha * conjx(x) * conjy(y)^H + conj(alpha) * conjy(y) * conjx(x)^H + // + // is functioning correctly if + // + // normfv( v - w ) + // + // is negligible, where + // + // v = A * t + // w = ( A_orig + alpha * conjx(x) * conjy(y)^H + conj(alpha) * conjy(y) * conjx(x)^H ) * t + // = A_orig * t + alpha * conjx(x) * conjy(y)^H * t + conj(alpha) * conjy(y) * conjx(x)^H * t + // = A_orig * t + alpha * conjx(x) * conjy(y)^H * t + conj(alpha) * conjy(y) * rho + // = A_orig * t + alpha * conjx(x) * conjy(y)^H * t + w1 + // = A_orig * t + alpha * conjx(x) * rho + w1 + // = A_orig * t + w2 + w1 + // + + bli_mkherm( a ); + bli_mkherm( a_orig ); + bli_obj_set_struc( BLIS_GENERAL, a ); + bli_obj_set_struc( BLIS_GENERAL, a_orig ); + bli_obj_set_uplo( BLIS_DENSE, a ); + bli_obj_set_uplo( BLIS_DENSE, a_orig ); + + bli_obj_scalar_init_detached( dt, &rho ); + bli_obj_scalar_init_detached( dt, &alphac ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m_a, 1, 0, 0, &t ); + bli_obj_create( dt, m_a, 1, 0, 0, &v ); + bli_obj_create( dt, m_a, 1, 0, 0, &w1 ); + bli_obj_create( dt, m_a, 1, 0, 0, &w2 ); + + bli_obj_alias_with_conj( BLIS_CONJUGATE, x, &xh ); + bli_obj_alias_with_conj( BLIS_CONJUGATE, y, &yh ); + bli_obj_alias_with_conj( BLIS_CONJUGATE, alpha, &alphac ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, a, &t, &BLIS_ZERO, &v ); + + bli_dotv( &xh, &t, &rho ); + bli_mulsc( &alphac, &rho ); + bli_scal2v( &rho, y, &w1 ); + + bli_dotv( &yh, &t, &rho ); + bli_mulsc( alpha, &rho ); + bli_scal2v( &rho, x, &w2 ); + + bli_addv( &w2, &w1 ); + + bli_gemv( &BLIS_ONE, a_orig, &t, &BLIS_ONE, &w1 ); + + bli_subv( &w1, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w1 ); + bli_obj_free( &w2 ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_her2.h b/gtestsuite/src/test_her2.h new file mode 100644 index 000000000..b11061689 --- /dev/null +++ b/gtestsuite/src/test_her2.h @@ -0,0 +1,18 @@ +#ifndef TEST_HER2_H +#define TEST_HER2_H + +#include "blis_test.h" + +double libblis_test_iher2_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig + ); + +double libblis_check_nan_her2( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_HER2_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_her2k.cpp b/gtestsuite/src/test_her2k.cpp new file mode 100644 index 000000000..1e1d62962 --- /dev/null +++ b/gtestsuite/src/test_her2k.cpp @@ -0,0 +1,554 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_her2k.h" + +using namespace std; + +// Local prototypes. +void libblis_test_her2k_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +); + +double libblis_test_her2k_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +); + +double cblas_her2k( + uplo_t uploc, + trans_t trans, + f77_int mm, + f77_int kk, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* b, + f77_int ldb, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uploc; + enum CBLAS_TRANSPOSE cblas_trans; + + if( bli_is_trans( trans ) ) + cblas_trans = CblasConjTrans; + else + cblas_trans = CblasNoTrans; + + if ( bli_obj_row_stride( c ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if(bli_is_upper(uploc)) + cblas_uploc = CblasUpper; + else + cblas_uploc = CblasLower; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + cblas_ssyr2k( cblas_order, cblas_uploc, cblas_trans, mm, kk, *alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + cblas_dsyr2k( cblas_order, cblas_uploc, cblas_trans, mm, kk, *alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cblas_cher2k( cblas_order, cblas_uploc, cblas_trans, mm, kk, alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + cblas_zher2k( cblas_order, cblas_uploc, cblas_trans, mm, kk, alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return 0; +} + +double blas_her2k( + uplo_t uploc, + trans_t trans, + f77_int mm, + f77_int kk, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* b, + f77_int ldb, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + + f77_char f77_uploc; + f77_char f77_trans; + + bli_param_map_blis_to_netlib_uplo( uploc, &f77_uploc ); + bli_param_map_blis_to_netlib_trans( trans, &f77_trans ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + ssyr2k_( &f77_uploc, &f77_trans, &mm, &kk, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + dsyr2k_( &f77_uploc, &f77_trans, &mm, &kk, alphap, ap,(f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cher2k_( &f77_uploc, &f77_trans, &mm, &kk, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + zher2k_( &f77_uploc, &f77_trans, &mm, &kk, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_her2k( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_her2k_impl( iface, alpha, a, b, beta, c ); + } + else { /*CLBAS || BLAS */ + uplo_t uploc = bli_obj_uplo( c ); + dim_t m = bli_obj_length( c ); + dim_t k = bli_obj_width_after_trans( a ); + trans_t trans = bli_obj_onlytrans_status( a ); + f77_int lda, ldb, ldc; + + if( bli_obj_row_stride( c ) == 1 ) { + lda = bli_obj_col_stride( a ); + ldb = bli_obj_col_stride( b ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldb = bli_obj_row_stride( b ); + ldc = bli_obj_row_stride( c ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldb = ldb + params->ld[1]; + ldc = ldc + params->ld[2]; + } + + if(params->api == API_CBLAS) { + cblas_her2k( uploc, trans, m, k, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } else { + if( bli_obj_row_stride( c ) == 1 ) { + blas_her2k( uploc, trans, m, k, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } + else { + if( uploc == BLIS_UPPER) + uploc = BLIS_LOWER; + else if(uploc == BLIS_LOWER) + uploc = BLIS_UPPER; + + if( trans == BLIS_NO_TRANSPOSE) + trans = BLIS_TRANSPOSE; + else if(trans == BLIS_TRANSPOSE) + trans = BLIS_NO_TRANSPOSE; + + blas_her2k( uploc, trans, m, k, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } + } + } + return ; +} + +double libblis_ref_her2k( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_save, + num_t dt +) { + + double resid = 0.0; + double *betap = (double *)bli_obj_buffer( beta ); + + if ((params->nanf) && (*betap == 0)) { + resid = libblis_check_nan_her2k(c, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_her2k_check( params, alpha, a, b, beta, c, c_save ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iher2k_check( params, alpha, a, b, beta, c, c_save ); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_her2k( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_her2k_impl( iface, alpha, a, b, beta, r ); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_her2k ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +) { + num_t datatype; + dim_t m, k; + uplo_t uploc; + trans_t trans; + obj_t alpha, a, b, beta, c; + obj_t c_save; + double resid = 0.0; + obj_t aa, bb; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploc ); + bli_param_map_char_to_herk_trans( pc_str[1], &trans ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, trans, + sc_str[1], m, k, &a ); + libblis_test_mobj_create( params, datatype, trans, + sc_str[1], m, k, &aa ); + libblis_test_mobj_create( params, datatype, trans, + sc_str[2], m, k, &b ); + libblis_test_mobj_create( params, datatype, trans, + sc_str[2], m, k, &bb ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c_save ); + + // Set the structure and uplo properties of C. + bli_obj_set_struc( BLIS_HERMITIAN, &c ); + bli_obj_set_uplo( uploc, &c ); + + // Set alpha and beta. + // For her2k, alpha may be complex, but beta must be real-valued + // (in order to preserve the Hermitian structure of C). + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &c ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + // Randomize A, B, and C, and save C. + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_mobj_randomize( params, TRUE, &b ); + libblis_test_mobj_randomize( params, TRUE, &c ); + } + else { + int32_t x = (int32_t)1.0; //alpv.real; + int32_t y = (int32_t)1.0; //betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + int32_t ac = (int32_t)(x/0.8); + int32_t bc = (int32_t)(y/1.0); + bli_setsc( (double)x, (double)ac, &alpha ); + bli_setsc( (double)y, (double)bc, &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_mobj_irandomize( params, &b ); + libblis_test_mobj_irandomize( params, &c ); + } + + if ((params->nanf) && (betv.real == 0) ) { + test_fillbuffmem(&c, datatype ); + } + + // Randomize A, make it densely Hermitian, and zero the unstored triangle + // to ensure the implementation is reads only from the stored region. + bli_mkherm( &c ); + bli_mktrim( &c ); + + // Save C and set its structure and uplo properties. + bli_obj_set_struc( BLIS_HERMITIAN, &c_save ); + bli_obj_set_uplo( uploc, &c_save ); + bli_copym( &c, &c_save ); + bli_mkherm( &c_save ); + bli_mktrim( &c_save ); + + // Apply the remaining parameters. + bli_copym( &a, &aa ); + bli_copym( &b, &bb ); + + bli_obj_set_conjtrans( trans, &a ); + bli_obj_set_conjtrans( trans, &b ); + + bli_obj_set_conjtrans( trans, &aa ); + bli_obj_set_conjtrans( trans, &bb ); + + libblis_api_her2k(params, iface, &alpha, &aa, &bb, &beta, &c, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &r ); + + resid = libblis_test_bitrp_her2k( params, iface, &alpha, &a, &b, + &beta, &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_her2k(params, &alpha, &a, &b, &beta, + &c, &c_save, datatype ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &c, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &b ); + libblis_test_obj_free( &bb ); + libblis_test_obj_free( &c ); + libblis_test_obj_free( &c_save ); + + return abs(resid); +} + +void libblis_test_her2k_impl + ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c + ) +{ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_her2k( alpha, a, b, beta, c ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_her2k_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ) +{ + num_t dt = bli_obj_dt( c ); + num_t dt_real = bli_obj_dt_proj_to_real( c ); + + dim_t m = bli_obj_length( c ); + dim_t k = bli_obj_width_after_trans( a ); + + obj_t alphac, ah, bh; + obj_t norm; + obj_t t, v, w1, w2, z; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is randomized. + // - b is randomized. + // - c_orig is randomized and Hermitian. + // Note: + // - alpha should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // - beta must be real-valued. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * transa(A) * transb(B)^H + conj(alpha) * transb(B) * transa(A)^H + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // z = ( beta * C_orig + alpha * transa(A) * transb(B)^H + conj(alpha) * transb(B) * transa(A)^H ) * t + // = beta * C_orig * t + alpha * transa(A) * transb(B)^H * t + conj(alpha) * transb(B) * transa(A)^H * t + // = beta * C_orig * t + alpha * transa(A) * transb(B)^H * t + conj(alpha) * transb(B) * w2 + // = beta * C_orig * t + alpha * transa(A) * w1 + conj(alpha) * transb(B) * w2 + // = beta * C_orig * t + alpha * transa(A) * w1 + z + // = beta * C_orig * t + z + // + + bli_obj_alias_with_trans( BLIS_CONJ_TRANSPOSE, a, &ah ); + bli_obj_alias_with_trans( BLIS_CONJ_TRANSPOSE, b, &bh ); + + bli_obj_scalar_init_detached( dt_real, &norm ); + bli_obj_scalar_init_detached_copy_of( dt, BLIS_CONJUGATE, alpha, &alphac ); + + bli_obj_create( dt, m, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, k, 1, 0, 0, &w1 ); + bli_obj_create( dt, k, 1, 0, 0, &w2 ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_hemv( &BLIS_ONE, c, &t, &BLIS_ZERO, &v ); + + bli_gemv( &BLIS_ONE, &ah, &t, &BLIS_ZERO, &w2 ); + bli_gemv( &BLIS_ONE, &bh, &t, &BLIS_ZERO, &w1 ); + bli_gemv( alpha, a, &w1, &BLIS_ZERO, &z ); + bli_gemv( &alphac, b, &w2, &BLIS_ONE, &z ); + bli_hemv( beta, c_orig, &t, &BLIS_ONE, &z ); + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w1 ); + bli_obj_free( &w2 ); + bli_obj_free( &z ); + + return resid; +} + diff --git a/gtestsuite/src/test_her2k.h b/gtestsuite/src/test_her2k.h new file mode 100644 index 000000000..cd5759728 --- /dev/null +++ b/gtestsuite/src/test_her2k.h @@ -0,0 +1,19 @@ +#ifndef TEST_HER2K_H +#define TEST_HER2K_H + +#include "blis_test.h" + +double libblis_test_iher2k_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ); + +double libblis_check_nan_her2k(obj_t* c, num_t dt ); + +#endif /* TEST_HER2K_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_herk.cpp b/gtestsuite/src/test_herk.cpp new file mode 100644 index 000000000..396a1be3c --- /dev/null +++ b/gtestsuite/src/test_herk.cpp @@ -0,0 +1,505 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_herk.h" + +void libblis_test_herk_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c +); + +double libblis_test_herk_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig +); + +double cblas_herk( + uplo_t uploc, + trans_t transa, + f77_int n, + f77_int k, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_TRANSPOSE cblas_trans; + enum CBLAS_UPLO cblas_uplo; + + if ( bli_obj_row_stride( c ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_upper( uploc ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + if( bli_is_trans( transa ) ) + cblas_trans = CblasConjTrans; + else + cblas_trans = CblasNoTrans; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + cblas_ssyrk( cblas_order, cblas_uplo, cblas_trans, n, k, + *alphap, ap, lda, *betap, cp, ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + cblas_dsyrk( cblas_order, cblas_uplo, cblas_trans, n, k, + *alphap, ap, lda, *betap, cp, ldc ); + break; + } + case BLIS_SCOMPLEX : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + float* betap = (float*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cblas_cherk( cblas_order, cblas_uplo, cblas_trans, n, k, + *alphap, ap, lda, *betap, cp, ldc ); + break; + } + case BLIS_DCOMPLEX : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + double* betap = (double*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + cblas_zherk( cblas_order, cblas_uplo, cblas_trans, n, k, + *alphap, ap, lda, *betap, cp, ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_herk( + uplo_t uploc, + f77_char f77_transa, + f77_int n, + f77_int k, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + f77_char f77_uploc; + + bli_param_map_blis_to_netlib_uplo( uploc, &f77_uploc ); + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + ssyrk_( &f77_uploc, &f77_transa, &n, &k, alphap, ap, (f77_int*)&lda, + betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + dsyrk_( &f77_uploc, &f77_transa, &n, &k, alphap, ap, + (f77_int*)&lda, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_SCOMPLEX : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + float* betap = (float*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cherk_( &f77_uploc, &f77_transa, &n, &k, alphap, ap, + (f77_int*)&lda, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DCOMPLEX : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + double* betap = (double*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + zherk_( &f77_uploc, &f77_transa, &n, &k, alphap, ap, + (f77_int*)&lda, betap, cp, (f77_int*)&ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_herk( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + num_t dt +){ + + if(params->api == API_BLIS) { + libblis_test_herk_impl( iface, alpha, a, beta, c ); + } + else { /*CLBAS || BLAS */ + f77_int m = bli_obj_length( c ); + f77_int k = bli_obj_width_after_trans( a ); + uplo_t uploc = bli_obj_uplo( c ); + trans_t transa = bli_obj_onlytrans_status( a ); + f77_int lda, ldc; + + if( bli_obj_is_col_stored( c ) ) { + lda = bli_obj_col_stride( a ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldc = bli_obj_row_stride( c ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldc = ldc + params->ld[2]; + } + + if(params->api == API_CBLAS) { + cblas_herk(uploc, transa, m, k, alpha, a, lda, beta, c, ldc, dt); + } + else { /**/ + f77_char f77_transa; + if(bli_obj_is_col_stored( c )) { + if(transa == BLIS_TRANSPOSE) f77_transa='T'; + else if ( transa == BLIS_CONJ_TRANSPOSE ) f77_transa='C'; + else /*if ( transa == BLIS_NO_TRANSPOSE )*/ f77_transa='N'; + + blas_herk(uploc, f77_transa, m, k, alpha, a, lda, + beta, c, ldc, dt); + } + else { + if(transa == BLIS_TRANSPOSE) f77_transa='N'; + else if ( transa == BLIS_CONJ_TRANSPOSE ) f77_transa='N'; + else /*if ( transa == BLIS_NO_TRANSPOSE )*/ f77_transa='C'; + + if( uploc == BLIS_UPPER) + uploc = BLIS_LOWER; + else if(uploc == BLIS_LOWER) + uploc = BLIS_UPPER; + + blas_herk(uploc, f77_transa, m, k, alpha, a, lda, + beta, c, ldc, dt); + } + } + } + return ; +} + +double libblis_ref_herk( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + num_t dt +){ + double resid = 0.0; +// double *betap = (double *)bli_obj_buffer( beta ); + + if (params->nanf) { + resid = libblis_check_nan_herk(c, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_herk_check( params, alpha, a, beta, c, c_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iherk_check( params, alpha, a, beta, c, c_orig); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_herk( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_herk_impl( iface, alpha, a, beta, r ); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_herk ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m, k; + uplo_t uploc; + trans_t transa; + obj_t alpha, a, beta, c; + obj_t c_save; + double resid = 0.0; + obj_t aa; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploc ); + bli_param_map_char_to_herk_trans( pc_str[1], &transa ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], m, k, &a ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], m, k, &aa ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c_save ); + + // Set the structure and uplo properties of C. + bli_obj_set_struc( BLIS_HERMITIAN, &c ); + bli_obj_set_uplo( uploc, &c ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &c ) ) { + bli_setsc(alpv.real, 0.0, &alpha); + bli_setsc(betv.real, 0.0, &beta); + } + else { + // For herk, alpha and beta must both be real-valued, even in the + // complex case (in order to preserve the Hermitian structure of C). + bli_setsc(alpv.real, 0.0, &alpha); + bli_setsc(betv.real, 0.0, &beta); + } + // Randomize A. + libblis_test_mobj_randomize( params, TRUE, &a ); + + libblis_test_mobj_randomize( params, TRUE, &c ); + } + else { + int32_t x = (int32_t)alpv.real; + int32_t y = (int32_t)betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + // For herk, both alpha and beta may be complex since, unlike herk, + // C is symmetric in both the real and complex cases. + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + // Randomize A. + libblis_test_mobj_irandomize( params, &a ); + + libblis_test_mobj_irandomize( params, &c ); + } + + bli_mkherm( &c ); + bli_mktrim( &c ); + + // Save C and set its structure and uplo properties. + bli_obj_set_struc( BLIS_HERMITIAN, &c_save ); + bli_obj_set_uplo( uploc, &c_save ); + bli_copym( &c, &c_save ); + + bli_mkherm( &c_save ); + bli_mktrim( &c_save ); + + bli_copym( &a, &aa ); + + // Apply the remaining parameters. + bli_obj_set_conjtrans( transa, &a ); + + bli_obj_set_conjtrans( transa, &aa ); + + libblis_api_herk(params, iface, &alpha, &aa, &beta, &c, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &r ); + resid = libblis_test_bitrp_herk( params, iface, &alpha, &a, &beta, + &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_herk(params, &alpha, &a, &beta, &c, &c_save, datatype); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &c, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &c ); + libblis_test_obj_free( &c_save ); + + return abs(resid); +} + +void libblis_test_herk_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c +) +{ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_herk( alpha, a, beta, c ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_herk_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ) +{ + num_t dt = bli_obj_dt( c ); + num_t dt_real = bli_obj_dt_proj_to_real( c ); + + dim_t m = bli_obj_length( c ); + dim_t k = bli_obj_width_after_trans( a ); + + obj_t ah; + obj_t norm; + obj_t t, v, w, z; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is randomized. + // - c_orig is randomized and Hermitian. + // Note: + // - alpha and beta must be real-valued. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * transa(A) * transa(A)^H + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // z = ( beta * C_orig + alpha * transa(A) * transa(A)^H ) * t + // = beta * C_orig * t + alpha * transa(A) * transa(A)^H * t + // = beta * C_orig * t + alpha * transa(A) * w + // = beta * C_orig * t + z + // + + bli_obj_alias_with_trans( BLIS_CONJ_TRANSPOSE, a, &ah ); + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, k, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_hemv( &BLIS_ONE, c, &t, &BLIS_ZERO, &v ); + + bli_gemv( &BLIS_ONE, &ah, &t, &BLIS_ZERO, &w ); + bli_gemv( alpha, a, &w, &BLIS_ZERO, &z ); + bli_hemv( beta, c_orig, &t, &BLIS_ONE, &z ); + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + bli_obj_free( &z ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_herk.h b/gtestsuite/src/test_herk.h new file mode 100644 index 000000000..48934ec65 --- /dev/null +++ b/gtestsuite/src/test_herk.h @@ -0,0 +1,18 @@ +#ifndef TEST_HERK_H +#define TEST_HERK_H + +#include "blis_test.h" + +double libblis_test_iherk_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ); + +double libblis_check_nan_herk(obj_t* b, num_t dt ); + +#endif /* TEST_HERK_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_normfm.cpp b/gtestsuite/src/test_normfm.cpp new file mode 100644 index 000000000..1c0af239a --- /dev/null +++ b/gtestsuite/src/test_normfm.cpp @@ -0,0 +1,199 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_normfm.h" + +// Local prototypes. +void libblis_test_normfm_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_normfm_impl( + iface_t iface, + obj_t* x, + obj_t* norm +); + +double libblis_test_normfm_check( + test_params_t* params, + obj_t* beta, + obj_t* x, + obj_t* norm +); + +double libblis_ref_normfm( + test_params_t* params, + obj_t* beta, + obj_t* x, + obj_t* norm +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_normfm_check( params, beta, x, norm ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_inormfm_check( params, x, norm); + } + else { + resid = libblis_test_matrix_check(params, x); + } + } + return resid; +} + +double libblis_test_bitrp_normfm( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* norm, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + num_t dt_real = bli_dt_proj_to_real( dt ); + + for(i = 0; i < n_repeats; i++) { + bli_obj_scalar_init_detached( dt_real, r ); + libblis_test_normfm_impl( iface, x, r ); + resid = libblis_test_bitrp_matrix(norm, r, dt); + } + return resid; +} + +double libblis_test_op_normfm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + num_t dt_real; + dim_t m, n; + obj_t beta, norm; + obj_t x; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Compute the real projection of the chosen datatype. + dt_real = bli_dt_proj_to_real( datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &beta ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &x ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Initialize beta to 2 - 2i. + bli_setsc( 2.0, -2.0, &beta ); + // Set all elements of x to beta. + bli_setm( &beta, &x ); + } + else { + libblis_test_mobj_irandomize( params, &x ); + } + + libblis_test_normfm_impl( iface, &x, &norm ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + resid = libblis_test_bitrp_normfm( params, iface, &x, &norm, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_normfm( params, &beta, &x, &norm ); + } +#endif + + // Zero out performance and residual if input matrix is empty. + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + + return abs(resid); +} + +void libblis_test_normfm_impl( + iface_t iface, + obj_t* x, + obj_t* norm +){ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_normfm( x, norm ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_normfm_check ( + test_params_t* params, + obj_t* beta, + obj_t* x, + obj_t* norm +){ + num_t dt_real = bli_obj_dt_proj_to_real( x ); + dim_t m = bli_obj_length( x ); + dim_t n = bli_obj_width( x ); + + obj_t m_r, n_r, temp_r; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is set to beta. + // Note: + // - beta should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // norm := normfm( x ) + // + // is functioning correctly if + // + // norm = sqrt( absqsc( beta ) * m * n ) + // + // where m and n are the dimensions of x. + // + + bli_obj_scalar_init_detached( dt_real, &temp_r ); + bli_obj_scalar_init_detached( dt_real, &m_r ); + bli_obj_scalar_init_detached( dt_real, &n_r ); + + bli_setsc( ( double )m, 0.0, &m_r ); + bli_setsc( ( double )n, 0.0, &n_r ); + + bli_absqsc( beta, &temp_r ); + bli_mulsc( &m_r, &temp_r ); + bli_mulsc( &n_r, &temp_r ); + bli_sqrtsc( &temp_r, &temp_r ); + bli_subsc( &temp_r, norm ); + + bli_getsc( norm, &resid, &junk ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_normfm.h b/gtestsuite/src/test_normfm.h new file mode 100644 index 000000000..a32f21f83 --- /dev/null +++ b/gtestsuite/src/test_normfm.h @@ -0,0 +1,15 @@ +#ifndef TEST_NORMFM_H +#define TEST_NORMFM_H + +#include "blis_test.h" + +double libblis_test_inormfm_check + ( + test_params_t* params, + obj_t* x, + obj_t* n + ); + +double libblis_check_nan_normfm( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_NORMFM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_normfv.cpp b/gtestsuite/src/test_normfv.cpp new file mode 100644 index 000000000..ac2bf7a0b --- /dev/null +++ b/gtestsuite/src/test_normfv.cpp @@ -0,0 +1,296 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_normfv.h" + +// Local prototypes. +void libblis_test_normfv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_normfv_impl ( + iface_t iface, + obj_t* x, + obj_t* norm +); + +double libblis_test_normfv_check ( + test_params_t* params, + obj_t* beta, + obj_t* x, + obj_t* norm +); + +double cblas_normfv( + f77_int mm, + obj_t* x, + f77_int incx, + obj_t* norm, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* nrm2 = (float*) bli_obj_buffer( norm ); + float* xp = (float*) bli_obj_buffer( x ); + *nrm2 = cblas_snrm2( mm, xp, incx ); + break; + } + case BLIS_DOUBLE : + { + double* nrm2 = (double*) bli_obj_buffer( norm ); + double* xp = (double*) bli_obj_buffer( x ); + *nrm2 = cblas_dnrm2( mm, xp, incx ); + break; + } + case BLIS_SCOMPLEX : + { + float* nrm2 = (float*) bli_obj_buffer( norm ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + *nrm2 = cblas_scnrm2( mm, xp, incx ); + break; + } + case BLIS_DCOMPLEX : + { + double* nrm2 = (double*) bli_obj_buffer( norm ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + *nrm2 = cblas_dznrm2( mm, xp, incx ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_normfv( + f77_int mm, + obj_t* x, + f77_int incx, + obj_t* norm, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* nrm2 = (float*) bli_obj_buffer( norm ); + float* xp = (float*) bli_obj_buffer( x ); + *nrm2 = snrm2_( &mm, xp, &incx ); + break; + } + case BLIS_DOUBLE : + { + double* nrm2 = (double*) bli_obj_buffer( norm ); + double* xp = (double*) bli_obj_buffer( x ); + *nrm2 = dnrm2_( &mm, xp, &incx ); + break; + } + case BLIS_SCOMPLEX : + { + float* nrm2 = (float*) bli_obj_buffer( norm ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + *nrm2 = scnrm2_( &mm, xp, &incx ); + break; + } + case BLIS_DCOMPLEX : + { + double* nrm2 = (double*) bli_obj_buffer( norm ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + *nrm2 = dznrm2_( &mm, xp, &incx ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_normfv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* norm, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_normfv_impl( iface, x, norm ); + } + else { /*CLBAS || BLAS */ + f77_int m = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + + if( params->api == API_CBLAS ) { + cblas_normfv( m, x, incx, norm, dt ); + } else { + blas_normfv( m, x, incx, norm, dt ); + } + } + return ; +} + +double libblis_ref_normfv( + test_params_t* params, + obj_t* beta, + obj_t* x, + obj_t* norm +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_normfv_check( params, beta, x, norm); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_inormfv_check( params, beta, x, norm); + } + else { + resid = libblis_test_vector_check(params, x); + } + } + return resid; +} + +double libblis_test_bitrp_normfv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* norm, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + num_t dt_real = bli_dt_proj_to_real( dt ); + + for(i = 0; i < n_repeats; i++) { + bli_obj_scalar_init_detached( dt_real, r ); + libblis_test_normfv_impl( iface, x, r ); + resid = libblis_test_bitrp_vector(norm, r, dt); + } + return resid; +} + +double libblis_test_op_normfv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +) { + num_t datatype; + num_t dt_real; + dim_t m; + obj_t beta, norm; + obj_t x; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Compute the real projection of the chosen datatype. + dt_real = bli_dt_proj_to_real( datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &beta ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + + // Initialize beta to 2 - 2i. + bli_setsc( 2.0, -2.0, &beta ); + + // Set all elements of x to beta. + bli_setv( &beta, &x ); + + libblis_api_normfv( params, iface, &x, &norm, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + resid = libblis_test_bitrp_normfv( params, iface, &x, &norm, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_normfv( params, &beta, &x, &norm); + } +#endif + + // Zero out performance and residual if input vector is empty. + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + + return abs(resid); +} + +void libblis_test_normfv_impl ( + iface_t iface, + obj_t* x, + obj_t* norm +){ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_normfv( x, norm ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_normfv_check ( + test_params_t* params, + obj_t* beta, + obj_t* x, + obj_t* norm +) { + num_t dt_real = bli_obj_dt_proj_to_real( x ); + dim_t m = bli_obj_vector_dim( x ); + + obj_t m_r, temp_r; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is set to beta. + // Note: + // - beta should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // norm := normfv( x ) + // + // is functioning correctly if + // + // norm = sqrt( absqsc( beta ) * m ) + // + // where m is the length of x. + // + + bli_obj_scalar_init_detached( dt_real, &temp_r ); + bli_obj_scalar_init_detached( dt_real, &m_r ); + + bli_setsc( ( double )m, 0.0, &m_r ); + + bli_absqsc( beta, &temp_r ); + bli_mulsc( &m_r, &temp_r ); + bli_sqrtsc( &temp_r, &temp_r ); + bli_subsc( &temp_r, norm ); + + bli_getsc( norm, &resid, &junk ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_normfv.h b/gtestsuite/src/test_normfv.h new file mode 100644 index 000000000..c0e708c90 --- /dev/null +++ b/gtestsuite/src/test_normfv.h @@ -0,0 +1,16 @@ +#ifndef TEST_NORMFV_H +#define TEST_NORMFV_H + +#include "blis_test.h" + +double libblis_test_inormfv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* n + ); + +double libblis_check_nan_normfv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_NORMFV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_process.cpp b/gtestsuite/src/test_process.cpp new file mode 100644 index 000000000..2b928ef57 --- /dev/null +++ b/gtestsuite/src/test_process.cpp @@ -0,0 +1,1737 @@ +#include + +#include "blis_utils.h" +#include "blis_api.h" + +using namespace std; + +char libblis_test_sp_chars[ 2 + 1 ] = "sc"; +char libblis_test_dp_chars[ 2 + 1 ] = "dz"; + +char libblis_test_rd_chars[ 2 + 1 ] = "sd"; +char libblis_test_cd_chars[ 2 + 1 ] = "cz"; + +char libblis_test_dt_chars[ 4 + 1 ] = "sdcz"; + +char libblis_test_store_chars[ NUM_OPERAND_TYPES ][ MAX_STORE_VALS_PER_TYPE + 1 ]; +char libblis_test_param_chars[ NUM_PARAM_TYPES ][ MAX_PARAM_VALS_PER_TYPE + 1 ]; + +char libblis_test_pass_string[ MAX_PASS_STRING_LENGTH + 1 ]; +char libblis_test_warn_string[ MAX_PASS_STRING_LENGTH + 1 ]; +char libblis_test_fail_string[ MAX_PASS_STRING_LENGTH + 1 ]; +char libblis_test_overflow_string[ MAX_PASS_STRING_LENGTH + 1 ]; +char libblis_test_underflow_string[ MAX_PASS_STRING_LENGTH + 1 ]; + +#define SIGN(number) (number > 0 ? 1 : 0) +int BlisTestSuite::libblis_test_init_strings( blis_string_t *test_data ) +{ + // Copy default parameters filename into its global string. + strncpy( test_data->libblis_test_parameters_filename, + PARAMETERS_FILENAME, MAX_FILENAME_LENGTH ); + + // Copy default operations filename into its global string. + strncpy( test_data->libblis_test_operations_filename, + OPERATIONS_FILENAME, MAX_FILENAME_LENGTH ); + + // Copy default alpha-beta parameter filename . + strncpy( test_data->libblis_test_alphabeta_parameter, + ALPHA_BETA_FILENAME, MAX_FILENAME_LENGTH ); + + strcpy( libblis_test_pass_string, BLIS_TEST_PASS_STRING ); + strcpy( libblis_test_warn_string, BLIS_TEST_WARN_STRING ); + strcpy( libblis_test_fail_string, BLIS_TEST_FAIL_STRING ); + strcpy( libblis_test_overflow_string, BLIS_TEST_OVERFLOW_STRING ); + strcpy( libblis_test_underflow_string, BLIS_TEST_UNDERFLOW_STRING ); + + strcpy( libblis_test_param_chars[BLIS_TEST_PARAM_SIDE], BLIS_TEST_PARAM_SIDE_CHARS ); + strcpy( libblis_test_param_chars[BLIS_TEST_PARAM_UPLO], BLIS_TEST_PARAM_UPLO_CHARS ); + strcpy( libblis_test_param_chars[BLIS_TEST_PARAM_UPLODE], BLIS_TEST_PARAM_UPLODE_CHARS ); + strcpy( libblis_test_param_chars[BLIS_TEST_PARAM_TRANS], BLIS_TEST_PARAM_TRANS_CHARS ); + strcpy( libblis_test_param_chars[BLIS_TEST_PARAM_CONJ], BLIS_TEST_PARAM_CONJ_CHARS ); + strcpy( libblis_test_param_chars[BLIS_TEST_PARAM_DIAG], BLIS_TEST_PARAM_DIAG_CHARS ); + + strcpy( libblis_test_store_chars[BLIS_TEST_MATRIX_OPERAND], BLIS_TEST_MSTORE_CHARS ); + strcpy( libblis_test_store_chars[BLIS_TEST_VECTOR_OPERAND], BLIS_TEST_VSTORE_CHARS ); + + return 0; +} + +int BlisTestSuite::libblis_test_read_params_file + ( + char* input_filename, + test_params_t* params, + char* abpf + ) +{ + FILE* input_stream; + char buffer[ INPUT_BUFFER_SIZE ]; + char temp[ INPUT_BUFFER_SIZE ]; + unsigned int i; + + // Attempt to open input file corresponding to input_filename as + // read-only/binary. + input_stream = fopen( input_filename, "r" ); + libblis_test_fopen_check_stream( input_filename, input_stream ); + + // Read the number of repeats. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->n_repeats) ); + + // Read the matrix storage schemes to test. We should have at most three: + // 'r' for row-major, 'c' for column-major, and 'g' for general strides. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%s ", temp ); + + params->n_mstorage = strlen( temp ); + if( params->n_mstorage > MAX_NUM_MSTORAGE ) + { + printf( "Detected too many matrix storage schemes (%u) in input file.\n", + params->n_mstorage ); + } + strcpy( params->storage[ BLIS_TEST_MATRIX_OPERAND ], temp ); + + // Read the vector storage schemes to test. We should have at most four: + // 'r' for row vectors with unit stride, 'c' for column vectors with unit + // stride, 'i' for row vectors with non-unit stride, and 'j' for column + // vectors with non-unit stride. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%s ", temp ); + + params->n_vstorage = strlen( temp ); + if( params->n_vstorage > MAX_NUM_VSTORAGE ) + { + printf( "Detected too many vector storage schemes (%u) in input file.\n", + params->n_vstorage ); + } + strcpy( params->storage[ BLIS_TEST_VECTOR_OPERAND ], temp ); + + // Read whether to mix all storage combinations. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->mix_all_storage) ); + + // Read whether to perform all tests with aligned addresses and ldims. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->alignment) ); + +#ifdef __GTEST_VALGRIND_TEST__ + params->alignment = 0; +#endif + + // Read the randomization method. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->rand_method) ); + + if( params->rand_method != BLIS_TEST_RAND_REAL_VALUES && + params->rand_method != BLIS_TEST_RAND_NARROW_POW2 ) + { + printf( "Invalid randomization method (%u) in input file.\n", + params->rand_method ); + } + + // Read the general stride "spacing". + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->gs_spacing) ); + + // Overwrite the existing storage character arrays with the sets provided. + strcpy( libblis_test_store_chars[BLIS_TEST_MATRIX_OPERAND], + params->storage[BLIS_TEST_MATRIX_OPERAND] ); + strcpy( libblis_test_store_chars[BLIS_TEST_VECTOR_OPERAND], + params->storage[BLIS_TEST_VECTOR_OPERAND] ); + + // Read the datatypes to test. We should have at most four: 's', 'd', 'c', + // and 'z'. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%s ", temp ); + + params->n_datatypes = strlen( temp ); + if( params->n_datatypes > MAX_NUM_DATATYPES ) + { + printf( "Detected too many datatype requests (%u) in input file.\n", + params->n_datatypes ); + } + + for( i = 0 ; i < params->n_datatypes ; ++i ) + { + // Map the char in temp[i] to the corresponding num_t value. + bli_param_map_char_to_blis_dt( temp[i], &(params->datatype[i]) ); + params->datatype_char[i] = temp[i]; + } + + // Read whether to test gemm with mixed-domain operands. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->mixed_domain) ); + + // Read whether to test gemm with mixed-precision operands. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->mixed_precision) ); + + // Read the initial problem size to test. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->p_first) ); + + // Read the maximum problem size to test. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->p_max) ); + + // Read the problem size increment to test. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->p_inc) ); + + // Read whether to enable 3mh. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->ind_enable[ BLIS_3MH ]) ); + + // Read whether to enable 3m1. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->ind_enable[ BLIS_3M1 ]) ); + + // Read whether to enable 4mh. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->ind_enable[ BLIS_4MH ]) ); + + // Read whether to enable 4m1b (4mb). + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->ind_enable[ BLIS_4M1B ]) ); + + // Read whether to enable 4m1a (4m1). + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->ind_enable[ BLIS_4M1A ]) ); + + // Read whether to enable 1m. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->ind_enable[ BLIS_1M ]) ); + + // Read whether to native (complex) execution. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->ind_enable[ BLIS_NAT ]) ); + + // Read whether to simulate application-level threading. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->n_app_threads) ); + + // Silently interpret non-positive numbers the same as 1. + if( params->n_app_threads < 1 ) params->n_app_threads = 1; + + // Disable induced methods when simulating more than one application + // threads. + if( params->n_app_threads > 1 ) + { + if( params->ind_enable[ BLIS_3MH ] || + params->ind_enable[ BLIS_3M1 ] || + params->ind_enable[ BLIS_4MH ] || + params->ind_enable[ BLIS_4M1B ] || + params->ind_enable[ BLIS_4M1A ] || + params->ind_enable[ BLIS_1M ] ) + { + // Due to an inherent race condition in the way induced methods + // are enabled and disabled at runtime, all induced methods must be + // disabled when simulating multiple application threads. + printf( "simulating multiple application threads; disabling induced methods.\n" ); + + params->ind_enable[ BLIS_3MH ] = 0; + params->ind_enable[ BLIS_3M1 ] = 0; + params->ind_enable[ BLIS_4MH ] = 0; + params->ind_enable[ BLIS_4M1B ] = 0; + params->ind_enable[ BLIS_4M1A ] = 0; + params->ind_enable[ BLIS_1M ] = 0; + } + } + + // Read the requested error-checking level. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->error_checking_level) ); + + // Read the requested course of action if a test fails. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%c ", &(params->reaction_to_failure) ); + + if( params->reaction_to_failure != ON_FAILURE_IGNORE_CHAR && + params->reaction_to_failure != ON_FAILURE_SLEEP_CHAR && + params->reaction_to_failure != ON_FAILURE_ABORT_CHAR ) + { + printf( "Invalid reaction-to-failure character code (%c) in input file.\n", + params->reaction_to_failure ); + } + + // Read whether to output in matlab format. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->output_matlab_format) ); + + // Read whether to output to files in addition to stdout. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &(params->output_files) ); + + // Read the requested api path. + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", &i ); + params->api = (api_t)i; + + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", ¶ms->dimf ); + + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", ¶ms->abf ); + + { + FILE *input_abpf = fopen( abpf, "r" ); + libblis_test_fopen_check_stream( abpf, input_abpf ); + + libblis_test_read_next_line( buffer, input_abpf ); + sscanf( buffer, "%u ", ¶ms->nab ); + + params->alpha = ( atom_t * ) malloc( params->nab * sizeof( atom_t ) ); + params->beta = ( atom_t * ) malloc( params->nab * sizeof( atom_t ) ); + + for( i = 0 ; i < params->nab ; i++) + { + libblis_test_read_next_line( buffer, input_abpf ); + sscanf( buffer, "%lf %lf", ¶ms->alpha[i].real, ¶ms->alpha[i].imag ); + } + + for( i = 0 ; i < params->nab ; i++) + { + libblis_test_read_next_line( buffer, input_abpf ); + sscanf( buffer, "%lf %lf", ¶ms->beta[i].real, ¶ms->beta[i].imag); + } + fclose(input_abpf); + } + + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", ¶ms->bitextf ); + + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", ¶ms->passflag ); + + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%u ", ¶ms->bitrp ); + + libblis_test_read_next_line( buffer, input_stream ); + sscanf( buffer, "%c ", &(params->op_t) ); + + // Close the file. + fclose( input_stream ); + + if(params->oruflw != 0) + params->bitextf = 1; + + // Output the parameter struct. + libblis_test_output_params_struct( stdout, params ); + return 0; +} + +int BlisTestSuite::libblis_test_read_ops_file( char* input_filename, test_ops_t* ops ) +{ + FILE* input_stream; + + // Attempt to open input file corresponding to input_filename as + // read-only/binary. + input_stream = fopen( input_filename, "r" ); + libblis_test_fopen_check_stream( input_filename, input_stream ); + + // Initialize the individual override field to FALSE. + ops->indiv_over = FALSE; + + // Begin reading operations input file. +#if 0 + // Section overrides + libblis_test_read_section_override( ops, input_stream, &(ops->util_over) ); + libblis_test_read_section_override( ops, input_stream, &(ops->l1v_over) ); + libblis_test_read_section_override( ops, input_stream, &(ops->l1m_over) ); + libblis_test_read_section_override( ops, input_stream, &(ops->l1f_over) ); + libblis_test_read_section_override( ops, input_stream, &(ops->l2_over) ); + libblis_test_read_section_override( ops, input_stream, &(ops->l3ukr_over) ); + libblis_test_read_section_override( ops, input_stream, &(ops->l3_over) ); +#endif + // dimensions n_param operation + + // Utility operations + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 0, &(ops->randv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 0, &(ops->randm) ); + + // Level-1v + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->addv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 0, &(ops->amaxv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->axpbyv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->axpyv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->copyv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->dotv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->dotxv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 0, &(ops->normfv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->scalv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->scal2v) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 0, &(ops->setv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->subv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 1, &(ops->xpbyv) ); + + // Level-1m + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->addm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->axpym) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->copym) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 0, &(ops->normfm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->scalm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->scal2m) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 0, &(ops->setm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->subm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 1, &(ops->xpbym) ); + + // Level-1f + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->axpy2v) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->dotaxpyv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MF, 2, &(ops->axpyf) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MF, 2, &(ops->dotxf) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MF, 4, &(ops->dotxaxpyf) ); + + // Level-2 + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 2, &(ops->gemv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MN, 2, &(ops->ger) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->hemv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->her) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->her2) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->symv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 2, &(ops->syr) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->syr2) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->trmv) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_M, 3, &(ops->trsv) ); + + // Level-3 micro-kernels + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_K, 0, &(ops->gemm_ukr) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_NO_DIMS, 1, &(ops->trsm_ukr) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_K, 1, &(ops->gemmtrsm_ukr) ); + + // Level-3 + libblis_test_read_op_info( ops, input_stream, BLIS_GEMM, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_GEMMT, BLIS_TEST_DIMS_MK, 3, &(ops->gemmt) ); + libblis_test_read_op_info( ops, input_stream, BLIS_HEMM, BLIS_TEST_DIMS_MN, 2, &(ops->hemm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_HERK, BLIS_TEST_DIMS_MK, 2, &(ops->herk) ); + libblis_test_read_op_info( ops, input_stream, BLIS_HER2K, BLIS_TEST_DIMS_MK, 2, &(ops->her2k) ); + libblis_test_read_op_info( ops, input_stream, BLIS_SYMM, BLIS_TEST_DIMS_MN, 2, &(ops->symm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_SYRK, BLIS_TEST_DIMS_MK, 2, &(ops->syrk) ); + libblis_test_read_op_info( ops, input_stream, BLIS_SYR2K, BLIS_TEST_DIMS_MK, 2, &(ops->syr2k) ); + libblis_test_read_op_info( ops, input_stream, BLIS_TRMM, BLIS_TEST_DIMS_MN, 4, &(ops->trmm) ); + libblis_test_read_op_info( ops, input_stream, BLIS_TRMM3, BLIS_TEST_DIMS_MN, 5, &(ops->trmm3) ); + libblis_test_read_op_info( ops, input_stream, BLIS_TRSM, BLIS_TEST_DIMS_MN, 4, &(ops->trsm) ); + + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_u8s8s32os32) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_u8s8s32os8) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_f32f32f32of32) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_u8s8s16os16) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_u8s8s16os8) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_bf16bf16f32of32) ); + libblis_test_read_op_info( ops, input_stream, BLIS_NOID, BLIS_TEST_DIMS_MNK, 2, &(ops->gemm_bf16bf16f32obf16) ); + + // Output the section overrides. + libblis_test_output_section_overrides( stdout, ops ); + + // Close the file. + fclose( input_stream ); + + return 0; +} + +ind_t ind_enable_get_str( test_params_t* params, unsigned int d, + unsigned int x, test_op_t* op ) +{ + ind_t indi = (ind_t)params->indim[d][x]; + num_t datatype = params->dt[d]; + + bli_ind_oper_enable_only( op->opid, indi, datatype ); + + return bli_ind_oper_find_avail( op->opid, datatype ); +} + +void libblis_test_build_function_string + ( + char* prefix_str, + opid_t opid, + ind_t method, + char* ind_str, + const char* op_str, + unsigned int is_mixed_dt, + char* dc_str, + unsigned int n_param_combos, + char* pc_str, + char* sc_str, + char* funcname_str + ) +{ + // We only print the full datatype combination string if is_mixed_dt + // is set and the operation is gemm. Otherwise, we print only + // the first char (since they are all the same). + if( is_mixed_dt == TRUE ) //&& opid == BLIS_GEMM ) + sprintf( funcname_str, "%s_%s%s", prefix_str, dc_str, op_str ); + else + sprintf( funcname_str, "%s_%c%s", prefix_str, dc_str[0], op_str ); + + // If the method is non-native (ie: induced), append a string + // identifying the induced method. + if( method != BLIS_NAT ) + sprintf( &funcname_str[strlen(funcname_str)], "%s", ind_str ); + + // We check the string length of pc_str in case the user is running an + // operation that has parameters (and thus generally more than one + // parameter combination), but has fixed all parameters in the input + // file, which would result in n_param_combos to equal one. This way, + // the function string contains the parameter string associated with + // the parameters that were fixed. + if( n_param_combos > 1 || strlen( pc_str ) > 0 ) + sprintf( &funcname_str[strlen(funcname_str)], "_%s_%s", pc_str, sc_str ); + else + sprintf( &funcname_str[strlen(funcname_str)], "_%s", sc_str ); + + if( strlen( funcname_str ) > MAX_FUNC_STRING_LENGTH ) + libblis_test_printf_error( "Function name string length (%d) exceeds maximum (%d).\n", + strlen( funcname_str ), MAX_FUNC_STRING_LENGTH ); + return; +} + +// % dtoper_params_storage m n k gflops resid result +void libblis_test_build_col_labels_string + ( + test_params_t* params, + test_op_t* op, + char* l_str + ) +{ + unsigned int n_spaces; + char blank_str[64]; + + strcpy( l_str, "" ); + + if( op->n_params > 0 ) + { + sprintf( &l_str[strlen(l_str)], "%c %s_%s", OUTPUT_COMMENT_CHAR, + BLIS_FILEDATA_PREFIX_STR, + "

__" ); + } + else // ( n_params == 0 ) + { + sprintf( &l_str[strlen(l_str)], "%c %s_%s", OUTPUT_COMMENT_CHAR, + BLIS_FILEDATA_PREFIX_STR, + "
_ " ); + } + + if( params->output_matlab_format ) n_spaces = 11; + else n_spaces = 1; + + fill_string_with_n_spaces( blank_str, n_spaces ); + + sprintf( &l_str[strlen(l_str)], "%s", blank_str ); + + if( op->dimset == BLIS_TEST_DIMS_MNK || + op->dimset == BLIS_TEST_DIMS_MN || + op->dimset == BLIS_TEST_DIMS_MK || + op->dimset == BLIS_TEST_DIMS_M || + op->dimset == BLIS_TEST_DIMS_K || + op->dimset == BLIS_TEST_DIMS_MF || + op->dimset == BLIS_TEST_NO_DIMS ) + sprintf( &l_str[strlen(l_str)], " %5s", "m" ); + + if( op->dimset == BLIS_TEST_DIMS_MNK || + op->dimset == BLIS_TEST_DIMS_MN || + op->dimset == BLIS_TEST_DIMS_K || + op->dimset == BLIS_TEST_DIMS_MF || + op->dimset == BLIS_TEST_NO_DIMS ) + sprintf( &l_str[strlen(l_str)], " %5s", "n" ); + + if( op->dimset == BLIS_TEST_DIMS_MNK || + op->dimset == BLIS_TEST_DIMS_MK || + op->dimset == BLIS_TEST_DIMS_K ) + sprintf( &l_str[strlen(l_str)], " %5s", "k" ); + + sprintf( &l_str[strlen(l_str)], "%s", " resid result" ); +} + +BlisTestSuite::~BlisTestSuite( ) +{ + free( params.alpha ); + free( params.beta ); + bli_finalize(); + cout << "BlisTestSuite destructor completed" << endl; +} + +bool AoclBlisTestFixture::destroy_params( test_params_t *params ) +{ + unsigned int pci, sci, dci; + char** pc_str = params->pc_str; + char** sc_str = params->sc_str; + char** dc_str = params->dc_str; + + // Free the parameter combination strings and then the master pointer. + for ( pci = 0 ; pci < params->n_param_combos ; ++pci ) + free( pc_str[pci] ); + free( pc_str ); + + // Free the storage combination strings and then the master pointer. + for( sci = 0 ; sci < params->n_store_combos ; ++sci ) + free( sc_str[sci] ); + free( sc_str ); + + // Free the datatype combination strings and then the master pointer. + for( dci = 0 ; dci < params->n_dt_combos ; ++dci ) + free( dc_str[dci] ); + free( dc_str ); + + free( params->dim ); + + return true; +} + +bool AoclBlisTestFixture::libblis_test_preprocess_params + ( + test_params_t* params, + test_op_t* op, + iface_t iface, + const char* p_types, + const char* o_types + ) +{ + unsigned int n_mstorage = params->n_mstorage; + unsigned int n_vstorage = params->n_vstorage; + unsigned int n_datatypes = params->n_datatypes; + + unsigned int mix_all_storage = params->mix_all_storage; + unsigned int mixed_domain = params->mixed_domain; + unsigned int mixed_precision = params->mixed_precision; + char dt_char; + + char* p_spec_str; + unsigned int n_params; + char** chars_for_param; + + unsigned int n_param_combos; + unsigned int n_store_combos; + unsigned int n_dt_combos; + char** pc_str; + char** sc_str; + char** dc_str; + + char s_spec_str[ MAX_NUM_OPERANDS + 1 ]; + unsigned int n_operands; + unsigned int n_operandsp1; + char** chars_for_storage; + + char d_spec_str[ MAX_NUM_OPERANDS + 1 ]; + char** chars_for_spdt; + char** chars_for_dpdt; + unsigned int n_spdt_combos; + unsigned int n_dpdt_combos; + + char** chars_for_dt; + char** chars_for_rddt; + char** chars_for_cddt; + unsigned int n_rddt_combos; + unsigned int n_cddt_combos; + + unsigned int sci, dci, i, j, o; + + // These arrays are malloc()'ed in select branches. Here, we set + // them to NULL so they can be unconditionally free()'ed at the + // end of the function. + chars_for_rddt = NULL; + chars_for_cddt = NULL; + chars_for_spdt = NULL; + chars_for_dpdt = NULL; + + // Set the error-checking level according to what was specified in the + // input file. + if( params->error_checking_level == 0 ) + bli_error_checking_level_set( BLIS_NO_ERROR_CHECKING ); + else + bli_error_checking_level_set( BLIS_FULL_ERROR_CHECKING ); + + // Obtain the parameter specification (filter) string. + p_spec_str = op->params; + + // Figure out how many parameters we have. + n_params = strlen( p_types ); + + if( strlen( p_types ) != strlen( p_spec_str) ) { + libblis_test_printf_error( "Parameter specification string from input file does not match length of p_types string.\n" ); + } + + // Allocate an array that stores pointers to the sets of possible parameter + // chars for each parameter. + chars_for_param = ( char** ) malloc( n_params * sizeof( char* ) ); + + // Set the values in chars_for_param to the appropriate string addresses. + for( i = 0 ; i < n_params ; ++i ) + { + param_t param_type = libblis_test_get_param_type_for_char( p_types[i] ); + chars_for_param[i] = libblis_test_param_chars[ param_type ]; + } + + // Compute the total number of parameter combinations to test (which is + // simply the product of the string lengths of chars_for_param[i]. + n_param_combos = libblis_test_count_combos( n_params, p_spec_str, + chars_for_param ); + + // Allocate an array of parameter combination strings, one for each + // parameter combination that needs to be tested. + pc_str = ( char** ) malloc( n_param_combos * sizeof( char* ) ); + for( i = 0 ; i < n_param_combos ; ++i ) + pc_str[i] = ( char* ) malloc( ( n_params + 1 ) * sizeof( char ) ); + + // Fill the parameter combination strings in pc_str with the parameter + // combinations called for by the parameter string p_spec_str. + libblis_test_fill_param_strings( p_spec_str, + chars_for_param, + n_params, + n_param_combos, + pc_str ); + + // Figure out how many operands we have. + n_operands = strlen( o_types ); + + // If we are testing a micro-kernel, unconditionally disable the + // "mix all storage" option. + if( iface == BLIS_TEST_SEQ_UKERNEL ) + mix_all_storage = DISABLE; + + // Enumerate all combinations of storage schemes requested. + if( mix_all_storage ) + { + // Fill storage specification string with wildcard chars. + for( i = 0 ; i < n_operands ; ++i ) + s_spec_str[i] = '?'; + s_spec_str[i] = '\0'; + + // Allocate an array that stores pointers to the sets of possible + // storage chars for each operand. + chars_for_storage = ( char** ) malloc( n_operands * sizeof( char* ) ); + + // Set the values in chars_for_storage to the address of the string + // that holds the storage chars. + for( i = 0 ; i < n_operands ; ++i ) + { + operand_t operand_type = libblis_test_get_operand_type_for_char( o_types[i] ); + chars_for_storage[i] = libblis_test_store_chars[ operand_type ]; + } + + // Compute the total number of storage combinations to test (which is + // simply the product of the string lengths of chars_for_storage[i]. + n_store_combos = libblis_test_count_combos( n_operands, s_spec_str, + chars_for_storage ); + + // Allocate an array of storage combination strings, one for each + // storage combination that needs to be tested. + sc_str = ( char** ) malloc( n_store_combos * sizeof( char* ) ); + for( sci = 0 ; sci < n_store_combos ; ++sci ) + sc_str[sci] = ( char* ) malloc( ( n_operands + 1 ) * sizeof( char ) ); + + + // Fill the storage combination strings in sc_str with the storage + // combinations called for by the storage string p_spec_str. + libblis_test_fill_param_strings( s_spec_str, + chars_for_storage, + n_operands, + n_store_combos, + sc_str ); + free( chars_for_storage ); + } + else // if ( !mix_all_storage ) + { + // Only run combinations where all operands of either type (matrices + // or vectors) are stored in one storage scheme or another (no mixing + // of schemes within the same operand type). + unsigned int n_mat_operands = 0; + unsigned int n_vec_operands = 0; + + for( o = 0 ; o < n_operands ; ++o ) { + operand_t operand_type + = libblis_test_get_operand_type_for_char( o_types[o] ); + if( operand_type == BLIS_TEST_MATRIX_OPERAND ) + ++n_mat_operands; + else if( operand_type == BLIS_TEST_VECTOR_OPERAND ) + ++n_vec_operands; + } + + // We compute the total number of storage combinations based on whether + // the current operation has only matrix operands, only vector operands, + // or both. + if( n_vec_operands == 0 ) + { + n_store_combos = n_mstorage; + n_vstorage = 1; + } + else if( n_mat_operands == 0 ) + { + n_store_combos = n_vstorage; + n_mstorage = 1; + } + else { + n_store_combos = n_mstorage * n_vstorage; + } + + sc_str = ( char** ) malloc( n_store_combos * sizeof( char* ) ); + + for( j = 0 ; j < n_mstorage ; ++j ) + { + for( i = 0 ; i < n_vstorage ; ++i ) + { + sci = j*n_vstorage + i; + sc_str[ sci ] = ( char* ) malloc( ( n_operands + 1 ) * sizeof( char ) ); + + for( o = 0 ; o < n_operands ; ++o ) + { + unsigned int ij; + operand_t operand_type + = libblis_test_get_operand_type_for_char( o_types[o] ); + + if ( operand_type == BLIS_TEST_MATRIX_OPERAND ) + ij = j; + else + ij = i; + + sc_str[sci][o] = params->storage[ operand_type ][ij]; + } + sc_str[sci][n_operands] = '\0'; + } + } + } + + // Enumerate all combinations of datatype domains requested, but only + // for the gemm operation. + if( !mixed_domain && mixed_precision && op->opid == BLIS_GEMM ) + { + params->is_mixed_dt = TRUE; + + // Increment the number of operands by one to account for the + // computation precision (or computation datatype, as we will encode + // it in the char string). + n_operandsp1 = n_operands + 1; + + unsigned int has_rd = libblis_test_dt_str_has_rd_char( params ); + unsigned int has_cd = libblis_test_dt_str_has_cd_char( params ); + + // Fill datatype specification string with wildcard chars. + for( i = 0 ; i < n_operandsp1 ; ++i ) + d_spec_str[i] = '?'; + d_spec_str[i] = '\0'; + + // Allocate an array that stores pointers to the sets of possible + // datatype chars for each operand. + chars_for_rddt = ( char** ) malloc( n_operandsp1 * sizeof( char* ) ); + chars_for_cddt = ( char** ) malloc( n_operandsp1 * sizeof( char* ) ); + + // Set the values in chars_for_rddt/cddt to the address of the string + // that holds the datatype chars. + for( i = 0 ; i < n_operandsp1 ; ++i ) + { + chars_for_rddt[i] = libblis_test_rd_chars; + chars_for_cddt[i] = libblis_test_cd_chars; + } + + // Set the last set of chars in chars_for_cddt to the real domain + // charset. This is because the last char will be the computation + // precision. + chars_for_cddt[i-1] = libblis_test_rd_chars; + + // Compute the total number of datatype combinations to test (which is + // simply the product of the string lengths of chars_for_spdt/dpdt[i]). + // NOTE: We skip inspecting/branching off of the d_spec_str chars since + // we know they are all '?'. + n_rddt_combos = 0; n_cddt_combos = 0; + + if( has_rd ) + n_rddt_combos = libblis_test_count_combos( n_operandsp1, d_spec_str, + chars_for_rddt ); + + if( has_cd ) + n_cddt_combos = libblis_test_count_combos( n_operandsp1, d_spec_str, + chars_for_cddt ); + + // Add real and complex domain combinations. + n_dt_combos = n_rddt_combos + n_cddt_combos; + + // Allocate an array of datatype combination strings, one for each + // datatype combination that needs to be tested. + dc_str = ( char** ) malloc( n_dt_combos * sizeof( char* ) ); + for( dci = 0 ; dci < n_dt_combos ; ++dci ) + dc_str[dci] = ( char* ) malloc( ( n_operandsp1 + 1 ) * sizeof( char ) ); + + char** dc_str_p = dc_str; + + // Fill the datatype combination strings in dc_str with the datatype + // combinations implied by chars_for_rddt/cddt. + if ( has_rd ) + { + libblis_test_fill_param_strings( d_spec_str, + chars_for_rddt, + n_operandsp1, + n_rddt_combos, + dc_str_p ); + dc_str_p += n_rddt_combos; + } + if ( has_cd ) + { + libblis_test_fill_param_strings( d_spec_str, + chars_for_cddt, + n_operandsp1, + n_cddt_combos, + dc_str_p ); + dc_str_p += n_cddt_combos; + } + } + else if( mixed_domain && !mixed_precision && op->opid == BLIS_GEMM ) + { + params->is_mixed_dt = TRUE; + + // Increment the number of operands by one to account for the + // computation precision (or computation datatype, as we will encode + // it in the char string). + n_operandsp1 = n_operands + 1; + + unsigned int has_sp = libblis_test_dt_str_has_sp_char( params ); + unsigned int has_dp = libblis_test_dt_str_has_dp_char( params ); + + // Fill datatype specification string with wildcard chars. + for( i = 0 ; i < n_operands ; ++i ) + d_spec_str[i] = '?'; + d_spec_str[i] = '\0'; + + // Allocate an array that stores pointers to the sets of possible + // datatype chars for each operand (plus the computation precision + // char). + chars_for_spdt = ( char** ) malloc( n_operands * sizeof( char* ) ); + chars_for_dpdt = ( char** ) malloc( n_operands * sizeof( char* ) ); + + // Set the values in chars_for_spdt/dpdt to the address of the string + // that holds the datatype chars. + for( i = 0 ; i < n_operands ; ++i ) + { + chars_for_spdt[i] = libblis_test_sp_chars; + chars_for_dpdt[i] = libblis_test_dp_chars; + } + + // Compute the total number of datatype combinations to test (which is + // simply the product of the string lengths of chars_for_spdt/dpdt[i]). + // NOTE: We skip inspecting/branching off of the d_spec_str chars since + // we know they are all '?'. + n_spdt_combos = 0; n_dpdt_combos = 0; + + if( has_sp ) + n_spdt_combos = libblis_test_count_combos( n_operands, d_spec_str, + chars_for_spdt ); + + if( has_dp ) + n_dpdt_combos = libblis_test_count_combos( n_operands, d_spec_str, + chars_for_dpdt ); + + // Add single- and double-precision combinations. + n_dt_combos = n_spdt_combos + n_dpdt_combos; + + // Allocate an array of datatype combination strings, one for each + // datatype combination that needs to be tested. + dc_str = ( char** ) malloc( n_dt_combos * sizeof( char* ) ); + for( dci = 0 ; dci < n_dt_combos ; ++dci ) + dc_str[dci] = ( char* ) malloc( ( n_operandsp1 + 1 ) * sizeof( char ) ); + + char** dc_str_p = dc_str; + + // Fill the datatype combination strings in dc_str with the datatype + // combinations implied by chars_for_spdt/dpdt. + if ( has_sp ) + { + libblis_test_fill_param_strings( d_spec_str, + chars_for_spdt, + n_operands, + n_spdt_combos, + dc_str_p ); + dc_str_p += n_spdt_combos; + } + if ( has_dp ) + { + libblis_test_fill_param_strings( d_spec_str, + chars_for_dpdt, + n_operands, + n_dpdt_combos, + dc_str_p ); + dc_str_p += n_dpdt_combos; + } + + // Manually set the computation char to the real projection of the + // first char of each combination. + int prec_i = n_operands; + for( i = 0 ; i < n_dt_combos ; ++i ) + { + dc_str[i][prec_i] = libblis_test_proj_dtchar_to_precchar( dc_str[i][0] ); + dc_str[i][prec_i+1] = '\0'; + } + } + else if( mixed_domain && mixed_precision && op->opid == BLIS_GEMM ) + { + params->is_mixed_dt = TRUE; + + // Increment the number of operands by one to account for the + // computation precision (or computation datatype, as we will encode + // it in the char string). + n_operandsp1 = n_operands + 1; + + // Fill datatype specification string with wildcard chars. + for ( i = 0 ; i < n_operandsp1 ; ++i ) + d_spec_str[i] = '?'; + d_spec_str[i] = '\0'; + + // Allocate an array that stores pointers to the sets of possible + // datatype chars for each operand. + chars_for_dt = ( char** ) malloc( n_operandsp1 * sizeof( char* ) ); + + // Set the values in chars_for_rddt/cddt to the address of the string + // that holds the datatype chars. + for( i = 0; i < n_operandsp1; ++i ) + { + chars_for_dt[i] = libblis_test_dt_chars; + } + + // Set the last set of chars in chars_for_dt to the real domain + // charset. This is because the last char will be the computation + // precision, with the computation domain implied by the operands' + // storage datatypes. + chars_for_dt[i-1] = libblis_test_rd_chars; + + // Compute the total number of datatype combinations to test (which is + // simply the product of the string lengths of chars_for_dt[i]). + // NOTE: We skip inspecting/branching off of the d_spec_str chars since + // we know they are all '?'. + n_dt_combos = libblis_test_count_combos( n_operandsp1, d_spec_str, + chars_for_dt ); + + // Allocate an array of datatype combination strings, one for each + // datatype combination that needs to be tested. + dc_str = ( char** ) malloc( n_dt_combos * sizeof( char* ) ); + for( dci = 0 ; dci < n_dt_combos ; ++dci ) + dc_str[dci] = ( char* ) malloc( ( n_operandsp1 + 1 ) * sizeof( char ) ); + + // Fill the datatype combination strings in dc_str with the datatype + // combinations implied by chars_for_rddt/cddt. + libblis_test_fill_param_strings( d_spec_str, + chars_for_dt, + n_operandsp1, + n_dt_combos, + dc_str ); + } + else // ( ( !mixed_domain && !mixed_precision ) || op->opid != BLIS_GEMM ) + { + params->is_mixed_dt = FALSE; + + // Increment the number of operands by one to account for the + // computation precision (or computation datatype, as we will encode + // it in the char string). + n_operandsp1 = n_operands + 1; + + // Since we are not mixing domains, we only consider n_datatype + // datatype combinations, where each combination is actually + // homogeneous (e.g. "sss", "ddd", etc., if n_operands == 3). + n_dt_combos = n_datatypes; + + // Allocate an array of datatype combination strings, one for each + // datatype specified. + dc_str = ( char** ) malloc( n_dt_combos * sizeof( char* ) ); + for ( dci = 0 ; dci < n_dt_combos ; ++dci ) + dc_str[dci] = ( char* ) malloc( ( n_operandsp1 + 1 ) * sizeof( char ) ); + + // Fill each datatype combination string with the same dt char for + // each operand in the current operation. + for( dci = 0 ; dci < n_dt_combos ; ++dci ) + { + dt_char = params->datatype_char[dci]; + + for ( i = 0; i < n_operands; ++i ) + dc_str[dci][i] = dt_char; + + // Encode the computation precision as the last char. + dc_str[dci][i] = libblis_test_proj_dtchar_to_precchar( dc_str[dci][0] ); + dc_str[dci][i+1] = '\0'; + } + } + + if( (mixed_domain) || (mixed_precision) ) + { + params->is_mixed_dt = TRUE; + } + + { + unsigned int ind, indi; + num_t datatype; + num_t dt_check; + // Loop over the requested datatypes. + for( dci = 0 ; dci < n_dt_combos ; ++dci ) + { + // We need a datatype to use for induced method related things + // as well as to decide which set of residual thresholds to use. + // We must choose the first operand's dt char since that's the + // only operand we know is guaranteed to exist. + bli_param_map_char_to_blis_dt( dc_str[dci][0], &datatype ); + dt_check = datatype; + + int has_sp = + libblis_test_dt_str_has_sp_char_str( n_operandsp1, dc_str[dci] ); + int has_dp = + libblis_test_dt_str_has_dp_char_str( n_operandsp1, dc_str[dci] ); + + int has_samep = ( has_sp && !has_dp ) || ( has_dp && !has_sp ); + + // Notice that we use n_operands here instead of + // n_operandsp1 since we only want to chars for the + // storage datatypes of the matrix operands, not the + // computation precision char. + int has_cd_only = + !libblis_test_dt_str_has_rd_char_str( n_operands, dc_str[dci] ); + + if( has_sp ) + { + // If any of the operands are single precision, ensure that + // dt_check is also single precision so that the residual is + // compared to datatype-appropriate thresholds. + dt_check = bli_dt_proj_to_single_prec( datatype ); + } + + // Start by assuming we will only test native execution. + ind_t ind_first = BLIS_NAT; + dim_t ind_last = BLIS_NAT; + + // If the operation is level-3, and all operand domains are complex, + // then we iterate over all induced methods. + if( bli_opid_is_level3( op->opid ) && has_cd_only ) + ind_first = BLIS_IND_FIRST; + + // Loop over induced methods (or just BLIS_NAT). + ind = 0; + for( indi = ind_first ; indi <= ind_last ; ++indi ) + { + // If the current datatype is real, OR if the current + // induced method is implemented (for the operation + // being tested) AND it was requested, then we enable + // ONLY that method and proceed. Otherwise, we skip the + // current method and go to the next method. + if( bli_is_real( datatype ) ) { ; } + else if( bli_ind_oper_is_impl( op->opid, (ind_t)indi ) && + params->ind_enable[ indi ] == 1 ) + { + // If the current induced method is 1m, make sure that + // we only proceed for gemm where all operands are stored + // in the complex domain. (This prevents 1m from being + // executed on mixed-datatype combinations that contain + // real domain datatypes.) + if ( indi == BLIS_1M ) + { + if ( op->opid == BLIS_GEMM && has_cd_only ) { ; } + else if ( has_samep && has_cd_only ) { ; } + else { continue; } + } + else { ; } + } + else { continue; } + params->indim[dci][ind] = indi; + ind++; + } + params->indn[dci] = ind; + params->dt[dci] = dt_check; + } + } + // Free the array that stored pointers to the sets of possible parameter + // chars for each parameter. + free( chars_for_param ); + + // Free some auxiliary arrays used by the mixed-domain/mixed-precision + // datatype-handling logic. + free( chars_for_rddt ); + free( chars_for_cddt ); + free( chars_for_spdt ); + free( chars_for_dpdt ); + /* + if ( params->bitextf ) { + params->dimf = 0; + } + */ + + if ( params->nanf ) + { + params->bitextf = 0; + } + + params->n_param_combos = n_param_combos; + params->n_store_combos = n_store_combos; + params->n_dt_combos = n_dt_combos; + + params->pc_str = pc_str; + params->sc_str = sc_str; + params->dc_str = dc_str; + + if (params->abf != 1) + params->nab = 1; + + if(params->ldf == 1) + { + params->ld[0] = (int)rand()%100; + params->ld[1] = (int)rand()%100; + params->ld[2] = (int)rand()%100; + } + else + { + params->ld[0] = 0; + params->ld[1] = 0; + params->ld[2] = 0; + } + + tensor_t *v; + unsigned int d = ( ( ( params->p_max - params->p_first ) + params->p_inc ) / params->p_inc ); + j = 0; + if( params->dimf == 1 ) + { + if( op->n_dims == 3) + { + unsigned int nc = 1; + for( i = 0 ; i < op->n_dims ; i++ ) + { + if( op->dim_spec[i] < 0 ) + nc *= d; + } + params->ndim = nc; + v = ( tensor_t* ) malloc( nc * sizeof( tensor_t ) ); + dim_t mm = abs( op->dim_spec[0] ); + dim_t nn = abs( op->dim_spec[1] ); + dim_t kk = abs( op->dim_spec[2] ); + dim_t m,n,k; + dim_t mmax = ( op->dim_spec[0] > 0 ) ? params->p_first : params->p_max ; + dim_t nmax = ( op->dim_spec[1] > 0 ) ? params->p_first : params->p_max ; + dim_t kmax = ( op->dim_spec[2] > 0 ) ? params->p_first : params->p_max ; + for( k = params->p_first ; k <= kmax ; k += params->p_inc ) + { + for( n = params->p_first ; n <= nmax ; n += params->p_inc ) + { + for( m = params->p_first ; m <= mmax ; m += params->p_inc ) + { + v[j].m = ( op->dim_spec[0] > 0 ) ? op->dim_spec[0] : (m/mm) ; + v[j].n = ( op->dim_spec[1] > 0 ) ? op->dim_spec[1] : (n/nn) ; + v[j].k = ( op->dim_spec[2] > 0 ) ? op->dim_spec[2] : (k/kk) ; + j++; + } + } + } + params->ndim = j; + } + else if(op->n_dims == 2) + { + unsigned int nc = 1; + for( i = 0 ; i < op->n_dims ; i++ ) + { + if( op->dim_spec[i] < 0 ) + nc *= d; + } + params->ndim = nc; + v = ( tensor_t* ) malloc( nc * sizeof( tensor_t ) ); + dim_t mm = abs( op->dim_spec[0] ); + dim_t nn = abs( op->dim_spec[1] ); + dim_t m,n; + dim_t mmax = ( op->dim_spec[0] > 0 ) ? params->p_first : params->p_max ; + dim_t nmax = ( op->dim_spec[1] > 0 ) ? params->p_first : params->p_max ; + for( n = params->p_first ; n <= nmax ; n += params->p_inc ) + { + for( m = params->p_first ; m <= mmax ; m += params->p_inc ) + { + v[j].m = ( op->dim_spec[0] > 0 ) ? op->dim_spec[0] : (m/mm) ; + v[j].n = ( op->dim_spec[1] > 0 ) ? op->dim_spec[1] : (n/nn) ; + v[j].k = 0; + j++; + } + } + params->ndim = j; + } + else + { + unsigned int nc = 1; + for( i = 0 ; i < op->n_dims ; i++ ) + { + if( op->dim_spec[i] < 0 ) + nc *= d; + } + params->ndim = nc; + v = ( tensor_t* ) malloc( nc * sizeof( tensor_t ) ); + dim_t mm = abs( op->dim_spec[0] ); + dim_t m; + dim_t mmax = ( op->dim_spec[0] > 0 ) ? params->p_first : params->p_max ; + for( m = params->p_first ; m <= mmax; m += params->p_inc ) { + v[j].m = ( op->dim_spec[0] > 0 ) ? op->dim_spec[0] : (m/mm) ; + v[j].n = 0; + v[j].k = 0; + j++; + } + params->ndim = j; + } + } + else + { + if( op->n_dims == 3 ) + { + if( SIGN( op->dim_spec[0] ) && + SIGN( op->dim_spec[1] ) && + SIGN( op->dim_spec[2] ) ) + { + d = 1 ; + } + params->ndim = d; + v = ( tensor_t* ) malloc( d * sizeof( tensor_t ) ); + dim_t mm = abs( op->dim_spec[0] ); + dim_t nn = abs( op->dim_spec[1] ); + dim_t kk = abs( op->dim_spec[2] ); + dim_t m; + dim_t mmax = d == 1 ? params->p_first : params->p_max ; + for( m = params->p_first ; m <= mmax ; m += params->p_inc ) + { + v[j].m = ( op->dim_spec[0] > 0 ) ? op->dim_spec[0] : (m/mm) ; + v[j].n = ( op->dim_spec[1] > 0 ) ? op->dim_spec[1] : (m/nn) ; + v[j].k = ( op->dim_spec[2] > 0 ) ? op->dim_spec[2] : (m/kk) ; + j++; + } + params->ndim = j; + } + else if( op->n_dims == 2 ) + { + if( SIGN( op->dim_spec[0] ) && SIGN( op->dim_spec[1] ) ) + { + d = 1 ; + } + params->ndim = d; + v = ( tensor_t* ) malloc( d * sizeof( tensor_t ) ); + dim_t mm = abs( op->dim_spec[0] ); + dim_t nn = abs( op->dim_spec[1] ); + dim_t m; + dim_t mmax = d == 1 ? params->p_first : params->p_max ; + for( m = params->p_first ; m <= mmax; m += params->p_inc ) + { + v[j].m = ( op->dim_spec[0] > 0 ) ? op->dim_spec[0] : (m/mm) ; + v[j].n = ( op->dim_spec[1] > 0 ) ? op->dim_spec[1] : (m/nn) ; + v[j].k = 0; + j++; + } + params->ndim = j; + } + else + { + if( SIGN( op->dim_spec[0] ) ) + { + d = 1 ; + } + params->ndim = d; + v = ( tensor_t* ) malloc( d * sizeof( tensor_t ) ); + dim_t mm = abs(op->dim_spec[0]); + dim_t m; + dim_t mmax = d == 1 ? params->p_first : params->p_max ; + for ( m = params->p_first ; m <= mmax; m += params->p_inc) + { + v[j].m = ( op->dim_spec[0] > 0 ) ? op->dim_spec[0] : (m/mm) ; + v[j].n = 0 ; + v[j].k = 0; + j++; + } + params->ndim = j; + } + } + params->dim = v; + return true; +} + +static int test_check_func( test_op_t* op ) +{ + return op->op_switch; +} + +void BlisTestSuite::CreateGtestFilters( test_ops_t* ops, string &str ) +{ + if( test_check_func( &(ops->randv) ) ) + { + str = str + "*AOCL_BLIS_RANDV"; + str = str + "*:"; + } + if( test_check_func( &(ops->randm) ) ) + { + str = str + "*AOCL_BLIS_RANDM"; + str = str + "*:"; + } + if( test_check_func( &(ops->addv) ) ) + { + str = str + "*AOCL_BLIS_ADDV"; + str = str + "*:"; + } + if( test_check_func( &(ops->amaxv) ) ) + { + str = str + "*AOCL_BLIS_AMAXV"; + str = str + "*:"; + } + if( test_check_func( &(ops->axpbyv) ) ) + { + str = str + "*AOCL_BLIS_AXPBYV"; + str = str + "*:"; + } + if( test_check_func( &(ops->axpyv) ) ) + { + str = str + "*AOCL_BLIS_AXPYV"; + str = str + "*:"; + } + if( test_check_func( &(ops->copyv) ) ) + { + str = str + "*AOCL_BLIS_COPYV"; + str = str + "*:"; + } + if( test_check_func( &(ops->dotv) ) ) + { + str = str + "*AOCL_BLIS_DOTV"; + str = str + "*:"; + } + if( test_check_func( &(ops->dotxv) ) ) + { + str = str + "*AOCL_BLIS_DOTXV"; + str = str + "*:"; + } + if( test_check_func( &(ops->normfv) ) ) + { + str = str + "*AOCL_BLIS_NORMFV"; + str = str + "*:"; + } + if( test_check_func( &(ops->scal2v) ) ) + { + str = str + "*AOCL_BLIS_SCAL2V"; + str = str + "*:"; + } + if( test_check_func( &(ops->scalv) ) ) + { + str = str + "*AOCL_BLIS_SCALV"; + str = str + "*:"; + } + if( test_check_func( &(ops->setv) ) ) + { + str = str + "*AOCL_BLIS_SETV"; + str = str + "*:"; + } + if( test_check_func( &(ops->xpbyv) ) ) + { + str = str + "*AOCL_BLIS_XPBYV"; + str = str + "*:"; + } + if( test_check_func( &(ops->subv) ) ) + { + str = str + "*AOCL_BLIS_SUBV"; + str = str + "*:"; + } + if( test_check_func( &(ops->axpyf) ) ) + { + str = str + "*AOCL_BLIS_AXPYF"; + str = str + "*:"; + } + if( test_check_func( &(ops->axpy2v) ) ) + { + str = str + "*AOCL_BLIS_AXPY2V"; + str = str + "*:"; + } + if( test_check_func( &(ops->dotxf) ) ) + { + str = str + "*AOCL_BLIS_DOTXF"; + str = str + "*:"; + } + if( test_check_func( &(ops->dotaxpyv) ) ) + { + str = str + "*AOCL_BLIS_DOTAXPYV"; + str = str + "*:"; + } + if( test_check_func( &(ops->dotxaxpyf) ) ) + { + str = str + "*AOCL_BLIS_DOTXAXPYF"; + str = str + "*:"; + } + if( test_check_func( &(ops->addm) ) ) + { + str = str + "*AOCL_BLIS_ADDM"; + str = str + "*:"; + } + if( test_check_func( &(ops->axpym) ) ) + { + str = str + "*AOCL_BLIS_AXPYM"; + str = str + "*:"; + } + if( test_check_func( &(ops->copym) ) ) + { + str = str + "*AOCL_BLIS_COPYM"; + str = str + "*:"; + } + if( test_check_func( &(ops->normfm) ) ) + { + str = str + "*AOCL_BLIS_NORMFM"; + str = str + "*:"; + } + if( test_check_func( &(ops->scalm) ) ) + { + str = str + "*AOCL_BLIS_SCALM"; + str = str + "*:"; + } + if( test_check_func( &(ops->scal2m) ) ) + { + str = str + "*AOCL_BLIS_SCAL2M"; + str = str + "*:"; + } + if( test_check_func( &(ops->setm) ) ) + { + str = str + "*AOCL_BLIS_SETM"; + str = str + "*:"; + } + if( test_check_func( &(ops->subm) ) ) + { + str = str + "*AOCL_BLIS_SUBM"; + str = str + "*:"; + } + if( test_check_func( &(ops->xpbym) ) ) + { + str = str + "*AOCL_BLIS_XPBYM"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemv) ) ) + { + str = str + "*AOCL_BLIS_GEMV"; + str = str + "*:"; + } + if( test_check_func( &(ops->ger) ) ) + { + str = str + "*AOCL_BLIS_GER"; + str = str + "*:"; + } + if( test_check_func( &(ops->hemv) ) ) + { + str = str + "*AOCL_BLIS_HEMV"; + str = str + "*:"; + } + if( test_check_func( &(ops->her) ) ) + { + str = str + "*AOCL_BLIS_L2HER"; + str = str + "*:"; + } + if( test_check_func( &(ops->her2) ) ) + { + str = str + "*AOCL_BLIS_L2HER2"; + str = str + "*:"; + } + if( test_check_func( &(ops->symv) ) ) + { + str = str + "*AOCL_BLIS_SYMV"; + str = str + "*:"; + } + if( test_check_func( &(ops->syr) ) ) + { + str = str + "*AOCL_BLIS_L2SYR"; + str = str + "*:"; + } + if( test_check_func( &(ops->syr2) ) ) + { + str = str + "*AOCL_BLIS_L2SYR2"; + str = str + "*:"; + } + if( test_check_func( &(ops->trmv) ) ) + { + str = str + "*AOCL_BLIS_TRMV"; + str = str + "*:"; + } + if( test_check_func( &(ops->trsv) ) ) + { + str = str + "*AOCL_BLIS_TRSV"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemm) ) ) + { + str = str + "*AOCL_BLIS_GEMM"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemmt) ) ) + { + str = str + "*AOCL_BLIS_L3GEMMT"; + str = str + "*:"; + } + if( test_check_func( &(ops->hemm) ) ) + { + str = str + "*AOCL_BLIS_HEMM"; + str = str + "*:"; + } + if( test_check_func( &(ops->herk) ) ) + { + str = str + "*AOCL_BLIS_HERK"; + str = str + "*:"; + } + if( test_check_func( &(ops->her2k) ) ) + { + str = str + "*AOCL_BLIS_HER2K"; + str = str + "*:"; + } + if( test_check_func( &(ops->symm) ) ) + { + str = str + "*AOCL_BLIS_SYMM"; + str = str + "*:"; + } + if( test_check_func( &(ops->syrk) ) ) + { + str = str + "*AOCL_BLIS_SYRK"; + str = str + "*:"; + } + if( test_check_func( &(ops->syr2k) ) ) + { + str = str + "*AOCL_BLIS_SYR2K"; + str = str + "*:"; + } + if( test_check_func( &(ops->trmm) ) ) + { + str = str + "*AOCL_BLIS_L3TRMM"; + str = str + "*:"; + } + if( test_check_func( &(ops->trmm3) ) ) + { + str = str + "*AOCL_BLIS_TRMM3"; + str = str + "*:"; + } + if( test_check_func( &(ops->trsm) ) ) + { + str = str + "*AOCL_BLIS_TRSM"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemm_u8s8s32os32) ) ) + { + str = str + "*AOCL_GEMM_S32S32"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemm_u8s8s32os8) ) ) + { + str = str + "*AOCL_GEMM_S8S32"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemm_f32f32f32of32) ) ) + { + str = str + "*AOCL_GEMM_F32F32"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemm_u8s8s16os16) ) ) + { + str = str + "*AOCL_GEMM_S16S16"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemm_u8s8s16os8) ) ) + { + str = str + "*AOCL_GEMM_S8S16"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemm_bf16bf16f32of32) ) ) + { + str = str + "*AOCL_GEMM_F32BF16"; + str = str + "*:"; + } + if( test_check_func( &(ops->gemm_bf16bf16f32obf16) ) ) + { + str = str + "*AOCL_GEMM_BF16BF16"; + str = str + "*:"; + } + cout << "Filter_data :" << str.c_str() << endl; +} + +int BlisTestSuite::libblis_test_inpfile( char* filename, input_file_t* pfile ) +{ + ifstream input_filename( filename ); + if( !input_filename.is_open() ) + { + cerr << "Could not open the input file - '" << filename << " " << endl; + return EXIT_FAILURE; + } + strncpy( pfile->inputfile, filename, MAX_FILENAME_LENGTH ); + pfile->fileread = 1; + + input_filename.close(); + return 0; +} + +int AoclBlisTestFixture::libblis_test_read_params_inpfile( char* filename, + test_params_t* params, test_ops_t* ops, printres_t* pfr ) +{ + string line; + ifstream input_filename( filename ); + + if( !input_filename.is_open() ) + { + cerr << "Could not open the input file - '" << filename << " " << endl; + return EXIT_FAILURE; + } + + while( getline(input_filename, line) ) + { + libblis_read_inpprms( line, params, ops, pfr ); + } + + input_filename.close(); + return 0; +} + +bool AoclBlisTestFixture::create_params( test_params_t *params ) +{ + char** pc_str; + char** sc_str; + char** dc_str; + unsigned int i; + unsigned int n_params = 4; //max n_params = 4 + unsigned int n_dims = 3; //max n_dims = 3 + + params->n_param_combos = n_params; + params->n_store_combos = n_dims; + params->n_dt_combos = 1; + + // Free the parameter combination strings and then the master pointer. + pc_str = ( char** ) malloc( params->n_param_combos * sizeof( char* ) ); + for ( i = 0 ; i < params->n_param_combos ; ++i ) + { + pc_str[i] = ( char* ) malloc( ( n_params + 1 ) * sizeof( char ) ); + memset( pc_str[i], 0, ( n_params + 1 ) ); + } + + // Free the storage combination strings and then the master pointer. + sc_str = ( char** ) malloc( params->n_store_combos * sizeof( char* ) ); + for ( i = 0 ; i < params->n_store_combos ; ++i ) + { + sc_str[i] = ( char* ) malloc( ( n_dims + 1 ) * sizeof( char ) ); + memset( sc_str[i], 0, ( n_dims + 1 ) ); + } + + // Free the datatype combination strings and then the master pointer. + dc_str = ( char** ) malloc( params->n_dt_combos * sizeof( char* ) ); + for ( i = 0 ; i < params->n_dt_combos ; ++i ) + { + dc_str[i] = ( char* ) malloc( ( params->n_dt_combos + 1 ) * sizeof( char ) ); + memset( dc_str[i], 0, ( params->n_dt_combos + 1 ) ); + } + + params->n_repeats = 1 ; + + params->rand_method = 0 ; + params->gs_spacing = 32; + params->alignment = 0 ; + params->n_app_threads = 1 ; + params->error_checking_level = 1; + + params->bitextf = 0 ; + params->nab = 1 ; + params->passflag = 1 ; + params->api = API_CBLAS; + + params->pc_str = pc_str; + params->sc_str = sc_str; + params->dc_str = dc_str; + + params->alpha = ( atom_t * ) malloc( params->nab * sizeof( atom_t ) ); + params->beta = ( atom_t * ) malloc( params->nab * sizeof( atom_t ) ); + + params->dim = ( tensor_t* ) malloc(3 * sizeof( tensor_t ) ); + memset( params->dim, 0, (3 * sizeof( tensor_t )) ); + + return true; +} + +void BlisTestSuite::CreateGtestFilters_api(input_file_t* pfile, string &str) +{ + if(pfile->fileread == 1) + { + str = str + "*AOCL_BLIS_READ_INPUTFILE"; + str = str + "*:"; + } + cout << "Filter_data :" << str.c_str() << endl; +} diff --git a/gtestsuite/src/test_randm.cpp b/gtestsuite/src/test_randm.cpp new file mode 100644 index 000000000..002d8aff0 --- /dev/null +++ b/gtestsuite/src/test_randm.cpp @@ -0,0 +1,227 @@ +#include "blis_test.h" +#include "blis_utils.h" + +void libblis_test_randm_impl(iface_t iface, obj_t* x ); + +double libblis_test_randm_check(test_params_t* params, obj_t* x ); + +double libblis_test_bitrp_randm( + test_params_t* params, + iface_t iface, + obj_t* x, + num_t dt +) { + double resid = 0.0; + resid = libblis_test_matrix_check(params, x); + return resid; +} + +double libblis_test_op_randm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* sc_str, + tensor_t* dim +) +{ + num_t datatype; + dim_t m, n; + char x_store; + double resid = 0.0; + obj_t x; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Extract the storage character for each operand. + x_store = sc_str[0]; + + // Create the test objects. + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, x_store, m, n, &x ); + + libblis_test_randm_impl( iface, &x ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + resid = libblis_test_bitrp_randm( params, iface, &x, datatype); + } + else { + resid = libblis_test_randm_check( params, &x ); + } +#endif + + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + + return abs(resid); +} + +void libblis_test_randm_impl ( + iface_t iface, + obj_t* x +) +{ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_randm( x ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +void absummval(dim_t m, dim_t n, float* x, inc_t rs_x, inc_t cs_x, float* sum_x) +{ + float abs_chi1; + float sum; + dim_t i, j; + + bli_sset0s(sum); + for ( j = 0; j < n; j++ ) { + for ( i = 0; i < m; i++ ) { + float* chi1 = x + i*rs_x + j*cs_x; + bli_ssabval2s(*chi1, abs_chi1); + bli_ssadds(abs_chi1, sum); + } + } + + bli_sscopys(sum, *sum_x); +} + +void absummval(dim_t m, dim_t n, double* x, inc_t rs_x, inc_t cs_x, double* sum_x) +{ + double abs_chi1; + double sum; + dim_t i, j; + + bli_dset0s(sum); + for ( j = 0; j < n; j++ ) { + for ( i = 0; i < m; i++ ) { + double* chi1 = x + i*rs_x + j*cs_x; + bli_ddabval2s(*chi1, abs_chi1); + bli_ddadds(abs_chi1, sum); + } + } + + bli_ddcopys(sum, *sum_x); +} + +void absummval(dim_t m, dim_t n, scomplex* x, inc_t rs_x, inc_t cs_x, float* sum_x) +{ + float abs_chi1; + float sum; + dim_t i, j; + + bli_sset0s(sum); + for ( j = 0; j < n; j++ ) { + for ( i = 0; i < m; i++ ) { + scomplex* chi1 = x + i*rs_x + j*cs_x; + bli_csabval2s(*chi1, abs_chi1); + bli_ssadds(abs_chi1, sum); + } + } + + bli_sscopys(sum, *sum_x); +} + +void absummval(dim_t m, dim_t n, dcomplex* x, inc_t rs_x, inc_t cs_x, double* sum_x) +{ + double abs_chi1; + double sum; + dim_t i, j; + + bli_dset0s(sum); + for ( j = 0; j < n; j++ ) { + for ( i = 0; i < m; i++ ) { + dcomplex* chi1 = x + i*rs_x + j*cs_x; + bli_zdabval2s(*chi1, abs_chi1); + bli_ddadds(abs_chi1, sum); + } + } + + bli_ddcopys(sum, *sum_x); +} + +template +void absumm ( obj_t* x, obj_t* sum_x ) +{ + dim_t m = bli_obj_length( x ); + dim_t n = bli_obj_width( x ); + + T* buf_x =(T*) bli_obj_buffer_at_off( x ); + inc_t rs_x = bli_obj_row_stride( x ); + inc_t cs_x = bli_obj_col_stride( x ); + + U* buf_sum_x = (U*)bli_obj_buffer_at_off( sum_x ); + + // Invoke the function. + absummval( m, n, buf_x, rs_x, cs_x, buf_sum_x ); +} + +double libblis_test_randm_check( test_params_t* params, obj_t* x ) +{ + num_t dt = bli_obj_dt( x ); + num_t dt_real = bli_obj_dt_proj_to_real( x ); + dim_t m_x = bli_obj_length( x ); + dim_t n_x = bli_obj_width( x ); + obj_t sum; + + // + // The two most likely ways that randm would fail is if all elements + // were zero, or if all elements were greater than or equal to one. + // We check both of these conditions by computing the sum of the + // absolute values of the elements of x. + // + + double resid = 0.0; + + bli_obj_scalar_init_detached( dt_real, &sum ); + + switch( dt ) { + case BLIS_FLOAT : + { + absumm( x, &sum ); + break; + } + case BLIS_DOUBLE : + { + absumm( x, &sum ); + break; + } + case BLIS_SCOMPLEX : + { + absumm( x, &sum ); + break; + } + case BLIS_DCOMPLEX : + { + absumm( x, &sum ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + if ( bli_is_float( dt_real )) { + float* sum_x = (float*)bli_obj_buffer_at_off( &sum ); + + if ( *sum_x == *bli_d0 ) resid = 1.0; + else if ( *sum_x >= 2.0 * m_x * n_x ) resid = 2.0; + } + else /* if ( bli_is_double( dt_real ) )*/ { + double* sum_x = (double*)bli_obj_buffer_at_off( &sum ); + + if ( *sum_x == *bli_d0 ) resid = 1.0; + else if ( *sum_x >= 2.0 * m_x * n_x ) resid = 2.0; + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_randv.cpp b/gtestsuite/src/test_randv.cpp new file mode 100644 index 000000000..d627f645b --- /dev/null +++ b/gtestsuite/src/test_randv.cpp @@ -0,0 +1,107 @@ +#include "blis_test.h" +#include "blis_utils.h" + +void libblis_test_randv_impl(iface_t iface, obj_t* x ); + +double libblis_test_randv_check(test_params_t* params, obj_t* x ); + +double libblis_test_bitrp_randv( + test_params_t* params, + iface_t iface, + obj_t* x, + num_t dt +) +{ + double resid = 0.0; + resid = libblis_test_vector_check(params, x); + return resid; +} + +double libblis_test_op_randv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* sc_str, + tensor_t* dim +) +{ + num_t datatype; + dim_t m; + char x_store; + obj_t x; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Extract the storage character for each operand. + x_store = sc_str[0]; + + // Create the test objects. + libblis_test_vobj_create( params, datatype, x_store, m, &x ); + + libblis_test_randv_impl( iface, &x ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + resid = libblis_test_bitrp_randv( params, iface, &x, datatype); + } + else { + resid = libblis_test_randv_check( params, &x ); + } +#endif + + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + + return abs(resid); +} + +void libblis_test_randv_impl( + iface_t iface, + obj_t* x +) +{ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_randv( x ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_randv_check (test_params_t* params, obj_t* x ) +{ + num_t dt_real = bli_obj_dt_proj_to_real( x ); + dim_t m_x = bli_obj_vector_dim( x ); + obj_t sum; + + double resid = 0.0; + + bli_obj_scalar_init_detached( dt_real, &sum ); + + bli_norm1v( x, &sum ); + + if (bli_is_float( dt_real )) { + float* sum_x = (float*)bli_obj_buffer_at_off( &sum ); + + if ( *sum_x == *bli_d0 ) resid = 1.0; + else if ( *sum_x >= 2.0 * m_x ) resid = 2.0; + } + else /* if ( bli_is_double(dt_real )) */ { + double* sum_x = (double*)bli_obj_buffer_at_off( &sum ); + + if ( *sum_x == *bli_d0 ) resid = 1.0; + else if ( *sum_x >= 2.0 * m_x ) resid = 2.0; + } + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_scal2m.cpp b/gtestsuite/src/test_scal2m.cpp new file mode 100644 index 000000000..66e891688 --- /dev/null +++ b/gtestsuite/src/test_scal2m.cpp @@ -0,0 +1,226 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_scal2m.h" + +// Local prototypes. +void libblis_test_scal2m_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_scal2m_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y +); + +double libblis_test_scal2m_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_save +); + +double libblis_ref_scal2m( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_scal2m_check( params, alpha, x, y, y_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iscal2m_check( params, alpha, x, y, y_orig); + } + else { + resid = libblis_test_matrix_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_scal2m( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( y_orig, r ); + libblis_test_scal2m_impl( iface, alpha, x, r ); + resid = libblis_test_bitrp_matrix(y, r, dt); + } + return resid; +} + + +double libblis_test_op_scal2m( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m, n; + trans_t transx; + obj_t alpha, x, y; + obj_t y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_trans( pc_str[0], &transx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transx, + sc_str[0], m, n, &x ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &y ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &y_save ); + + // Set alpha. + if ( bli_obj_is_real( &y ) ) + bli_setsc( -2.0, 0.0, &alpha ); + else + bli_setsc( 0.0, -2.0, &alpha ); + + // Randomize and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_mobj_randomize( params, FALSE, &x ); + } else { + libblis_test_mobj_irandomize( params, &x ); + } + bli_setm( &BLIS_ONE, &y ); + bli_copym( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conjtrans( transx, &x ); + + libblis_test_scal2m_impl( iface, &alpha, &x, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + + resid = libblis_test_bitrp_scal2m( params, iface, &alpha, &x, + &y, &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_scal2m( params, &alpha, &x, &y, &y_save); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_scal2m_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_scal2m( alpha, x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_scal2m_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_length( y ); + dim_t n = bli_obj_width( y ); + + obj_t x_temp; + obj_t norm; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is randomized. + // - y_orig is set to one. + // Note: + // - alpha should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := alpha * conjx(x) + // + // is functioning correctly if + // + // normfm( y - alpha * conjx(x) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, n, 0, 0, &x_temp ); + + bli_copym( x, &x_temp ); + + bli_scalm( alpha, &x_temp ); + + bli_subm( &x_temp, y ); + bli_normfm( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_scal2m.h b/gtestsuite/src/test_scal2m.h new file mode 100644 index 000000000..62aa0758e --- /dev/null +++ b/gtestsuite/src/test_scal2m.h @@ -0,0 +1,17 @@ +#ifndef TEST_SCAL2M_H +#define TEST_SCAL2M_H + +#include "blis_test.h" + +double libblis_test_iscal2m_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_scal2m( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SCAL2M_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_scal2v.cpp b/gtestsuite/src/test_scal2v.cpp new file mode 100644 index 000000000..9189438a4 --- /dev/null +++ b/gtestsuite/src/test_scal2v.cpp @@ -0,0 +1,222 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_scal2v.h" + +// Local prototypes. +void libblis_test_scal2v_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_scal2v_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y +); + +double libblis_test_scal2v_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +); + +double libblis_ref_scal2v( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_scal2v_check( params, alpha, x, y, y_save); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iscal2v_check( params, alpha, x, y, y_save); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_scal2v( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_scal2v_impl( iface, alpha, x, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_scal2v ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + conj_t conjx; + obj_t alpha, x, y; + obj_t y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y_save ); + + // Set alpha. + if ( bli_obj_is_real( &y ) ) + bli_setsc( -2.0, 0.0, &alpha ); + else + bli_setsc( 0.0, -2.0, &alpha ); + + // Randomize x and y, and save y. + // Randomize and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, FALSE, &x ); + libblis_test_vobj_randomize( params, FALSE, &y ); + } else { + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + bli_copyv( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + + libblis_test_scal2v_impl( iface, &alpha, &x, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[1], m, &r ); + + resid = libblis_test_bitrp_scal2v( params, iface, &alpha, &x, + &y, &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_scal2v( params, &alpha, &x, &y, &y_save); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_scal2v_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y +){ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_scal2v( alpha, x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_scal2v_check ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( y ); + + obj_t x_temp; + obj_t norm; + + double junk; + double resid = 0.0 ; + // + // Pre-conditions: + // - x is randomized. + // - y_orig is set to one. + // Note: + // - alpha should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := alpha * conjx(x) + // + // is functioning correctly if + // + // normfv( y - alpha * conjx(x) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &x_temp ); + + bli_copyv( x, &x_temp ); + + bli_scalv( alpha, &x_temp ); + + bli_subv( &x_temp, y ); + bli_normfv( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_scal2v.h b/gtestsuite/src/test_scal2v.h new file mode 100644 index 000000000..2edca5359 --- /dev/null +++ b/gtestsuite/src/test_scal2v.h @@ -0,0 +1,17 @@ +#ifndef TEST_SCAL2V_H +#define TEST_SCAL2V_H + +#include "blis_test.h" + +double libblis_test_iscal2v_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_scal2v( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SCAL2V_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_scalm.cpp b/gtestsuite/src/test_scalm.cpp new file mode 100644 index 000000000..dbf9aa648 --- /dev/null +++ b/gtestsuite/src/test_scalm.cpp @@ -0,0 +1,221 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_scalm.h" + +// Local prototypes. +void libblis_test_scalm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_scalm_impl ( + iface_t iface, + obj_t* beta, + obj_t* y +); + +double libblis_test_scalm_check ( + test_params_t* params, + obj_t* beta, + obj_t* y, + obj_t* y_save +); + +double libblis_ref_scalm( + test_params_t* params, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_scalm_check( params, beta, y, y_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iscalm_check( params, beta, y, y_orig); + } + else { + resid = libblis_test_matrix_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_scalm( + test_params_t* params, + iface_t iface, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( y_orig, r ); + libblis_test_scalm_impl( iface, beta, r ); + resid = libblis_test_bitrp_matrix(y, r, dt); + } + return resid; +} + +double libblis_test_op_scalm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m, n; + conj_t conjbeta; + obj_t beta, y; + obj_t y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjbeta ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &y ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &y_save ); + + if ( bli_obj_is_real( &y ) ) + bli_setsc( -2.0, 0.0, &beta ); + else + bli_setsc( 0.0, -2.0, &beta ); + + // Randomize and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_mobj_randomize( params, FALSE, &y ); + } else { + libblis_test_mobj_irandomize( params, &y ); + } + + bli_copym( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conjbeta, &beta ); + + libblis_test_scalm_impl( iface, &beta, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + + resid = libblis_test_bitrp_scalm( params, iface, &beta, &y, + &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_scalm( params, &beta, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_scalm_impl( + iface_t iface, + obj_t* beta, + obj_t* y +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_scalm( beta, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_scalm_check( + test_params_t* params, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_length( y ); + dim_t n = bli_obj_width( y ); + + obj_t norm_y_r; + obj_t nbeta; + + obj_t y2; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - y_orig is randomized. + // Note: + // - beta should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := conjbeta(beta) * y_orig + // + // is functioning correctly if + // + // normfm( y + -conjbeta(beta) * y_orig ) + // + // is negligible. + // + + bli_obj_create( dt, m, n, 0, 0, &y2 ); + bli_copym( y_orig, &y2 ); + + bli_obj_scalar_init_detached( dt, &nbeta ); + bli_obj_scalar_init_detached( dt_real, &norm_y_r ); + + bli_copysc( beta, &nbeta ); + bli_mulsc( &BLIS_MINUS_ONE, &nbeta ); + + bli_scalm( &nbeta, &y2 ); + bli_addm( &y2, y ); + + bli_normfm( y, &norm_y_r ); + + bli_getsc( &norm_y_r, &resid, &junk ); + + bli_obj_free( &y2 ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_scalm.h b/gtestsuite/src/test_scalm.h new file mode 100644 index 000000000..abbb92e4a --- /dev/null +++ b/gtestsuite/src/test_scalm.h @@ -0,0 +1,16 @@ +#ifndef TEST_SCALM_H +#define TEST_SCALM_H + +#include "blis_test.h" + +double libblis_test_iscalm_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_scalm( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SCALM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_scalv.cpp b/gtestsuite/src/test_scalv.cpp new file mode 100644 index 000000000..5ca85e290 --- /dev/null +++ b/gtestsuite/src/test_scalv.cpp @@ -0,0 +1,505 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_scalv.h" + +// Local prototypes. +void libblis_test_scalv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_scalv_impl ( + iface_t iface, + obj_t* beta, + obj_t* y +); + +double libblis_test_scalv_check ( + test_params_t* params, + obj_t* beta, + obj_t* y, + obj_t* y_orig +); + +double cblas_scalv( + f77_int mm, + obj_t* beta, + obj_t* x, + f77_int incx, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* betap = (float*) bli_obj_buffer( beta ); + float* xp = (float*) bli_obj_buffer( x ); + cblas_sscal( mm, *betap, xp, incx ); + break; + } + case BLIS_DOUBLE : + { + double* betap = (double*) bli_obj_buffer( beta ); + double* xp = (double*) bli_obj_buffer( x ); + cblas_dscal( mm, *betap, xp, incx ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cblas_cscal( mm, betap, xp, incx ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + cblas_zscal( mm, betap, xp, incx ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double cblas_cscalv( + f77_int mm, + obj_t* beta, + obj_t* x, + f77_int incx, + num_t dt +){ + switch( dt ) { + case BLIS_SCOMPLEX : + { + float* betap = (float*) bli_obj_buffer( beta ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cblas_csscal( mm, *betap, xp, incx ); + break; + } + case BLIS_DCOMPLEX : + { + double* betap = (double*) bli_obj_buffer( beta ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + cblas_zdscal( mm, *betap, xp, incx ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_scalv( + f77_int mm, + obj_t* beta, + obj_t* x, + f77_int incx, + num_t dt +){ + switch( dt ) { + case BLIS_FLOAT : + { + float* betap = (float*) bli_obj_buffer( beta ); + float* xp = (float*) bli_obj_buffer( x ); + sscal_( &mm, betap, xp, &incx ); + break; + } + case BLIS_DOUBLE : + { + double* betap = (double*) bli_obj_buffer( beta ); + double* xp = (double*) bli_obj_buffer( x ); + dscal_( &mm, betap, xp, &incx ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cscal_( &mm, betap, xp, &incx ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + zscal_( &mm, betap, xp, &incx ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_cscalv( + f77_int mm, + obj_t* beta, + obj_t* x, + f77_int incx, + num_t dt +){ + switch( dt ) { + case BLIS_SCOMPLEX : + { + float* betap = (float*) bli_obj_buffer( beta ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + csscal_( &mm, betap, xp, &incx ); + break; + } + case BLIS_DCOMPLEX : + { + double* betap = (double*) bli_obj_buffer( beta ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + zdscal_( &mm, betap, xp, &incx ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_scalv( + test_params_t* params, + iface_t iface, + obj_t* beta, + obj_t* x, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_scalv_impl( iface, beta, x ); + } + else { /*CLBAS || BLAS */ + dim_t m = bli_obj_vector_dim( x ); + f77_int incx = bli_obj_vector_inc( x ); + + if(bli_obj_has_conj(beta)) { + conjugate_tensor(beta, dt); + bli_obj_set_conj( BLIS_NO_CONJUGATE, beta ); + } + + if( params->mixed_precision == 0 ) { + if( params->api == API_CBLAS ) { + cblas_scalv( m, beta, x, incx, dt ); + } else { + blas_scalv( m, beta, x, incx, dt ); + } + } + else{ + if( params->api == API_CBLAS ) { + cblas_cscalv( m, beta, x, incx, dt ); + } else { + blas_cscalv( m, beta, x, incx, dt ); + } + } + } + return ; +} + +double libblis_ref_scalv( + test_params_t* params, + obj_t* beta, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_scalv_check( params, beta, y, y_save); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_iscalv_check( params, beta, y, y_save); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_scalv( + test_params_t* params, + iface_t iface, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0 ; i < n_repeats ; i++) { + bli_copyv( y_orig, r ); + libblis_test_scalv_impl( iface, beta, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_scalv_md ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t dt_beta, dt_y; + dim_t m; + conj_t conjbeta; + obj_t beta, y; + obj_t y_save; + double resid = 0.0; + obj_t dbeta; + + // Decode the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &dt_y ); + bli_param_map_char_to_blis_dt( dc_str[1], &dt_beta ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjbeta ); + + // Create test scalars. + bli_obj_scalar_init_detached( dt_beta, &beta ); + bli_obj_scalar_init_detached( dt_beta, &dbeta ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, dt_y, sc_str[0], m, &y ); + libblis_test_vobj_create( params, dt_y, sc_str[0], m, &y_save ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &beta ) ) + bli_setsc( -2.0, 0.0, &beta ); + else + bli_setsc( 0.0, -2.0, &beta ); + + // Randomize x. + libblis_test_vobj_randomize( params, FALSE, &y ); + } + else{ + if ( bli_obj_is_real( &beta ) ) + bli_setsc( -2.0, 0.0, &beta ); + else + bli_setsc( 0.0, -2.0, &beta ); + + // Randomize x. + libblis_test_vobj_irandomize( params, &y ); + } + + bli_copyv( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conjbeta, &beta ); + + bli_copysc( &beta, &dbeta ); + + libblis_api_scalv( params, iface, &dbeta, &y, dt_y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, dt_y, sc_str[0], m, &r ); + + + resid = libblis_test_bitrp_scalv( params, iface, &beta, &y, + &y_save, &r, dt_y); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_scalv( params, &beta, &y, &y_save); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return resid; +} + +double libblis_test_op_scalv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + conj_t conjbeta; + obj_t beta, y; + obj_t y_save; + double resid = 0.0; + obj_t dbeta; + + // Use a different function to handle mixed datatypes. + if ( params->mixed_domain || params->mixed_precision ) + { + resid = libblis_test_op_scalv_md( params, iface, dc_str, + pc_str, sc_str, dim, alpv ); + return resid; + } + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjbeta ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &beta ); + bli_obj_scalar_init_detached( datatype, &dbeta ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[0], m, &y_save ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &beta ) ) + bli_setsc( -2.0, 0.0, &beta ); + else + bli_setsc( 0.0, -2.0, &beta ); + + // Randomize x. + libblis_test_vobj_randomize( params, FALSE, &y ); + } + else{ + if ( bli_obj_is_real( &beta ) ) + bli_setsc( -2.0, 0.0, &beta ); + else + bli_setsc( 0.0, -2.0, &beta ); + + // Randomize x. + libblis_test_vobj_irandomize( params, &y ); + } + + bli_copyv( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conjbeta, &beta ); + + bli_copysc( &beta, &dbeta ); + + libblis_api_scalv( params, iface, &dbeta, &y, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[0], m, &r ); + + + resid = libblis_test_bitrp_scalv( params, iface, &beta, &y, + &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_scalv( params, &beta, &y, &y_save); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_scalv_impl ( + iface_t iface, + obj_t* beta, + obj_t* y +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_scalv( beta, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_scalv_check ( + test_params_t* params, + obj_t* beta, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( y ); + + obj_t norm_y_r; + obj_t nbeta; + + obj_t y2; + + double junk; + + double resid = 0.0; + + // + // Pre-conditions: + // - y_orig is randomized. + // Note: + // - beta should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := conjbeta(beta) * y_orig + // + // is functioning correctly if + // + // normfv( y + -conjbeta(beta) * y_orig ) + // + // is negligible. + // + + bli_obj_create( dt, m, 1, 0, 0, &y2 ); + bli_copyv( y_orig, &y2 ); + + bli_obj_scalar_init_detached( dt, &nbeta ); + bli_obj_scalar_init_detached( dt_real, &norm_y_r ); + + bli_copysc( beta, &nbeta ); + bli_mulsc( &BLIS_MINUS_ONE, &nbeta ); + + bli_scalv( &nbeta, &y2 ); + bli_addv( &y2, y ); + + bli_normfv( y, &norm_y_r ); + + bli_getsc( &norm_y_r, &resid, &junk ); + + bli_obj_free( &y2 ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_scalv.h b/gtestsuite/src/test_scalv.h new file mode 100644 index 000000000..947b43246 --- /dev/null +++ b/gtestsuite/src/test_scalv.h @@ -0,0 +1,16 @@ +#ifndef TEST_SCALV_H +#define TEST_SCALV_H + +#include "blis_test.h" + +double libblis_test_iscalv_check + ( + test_params_t* params, + obj_t* beta, + obj_t* x, + obj_t* x_orig + ); + +double libblis_check_nan_scalv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SCALV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_setm.cpp b/gtestsuite/src/test_setm.cpp new file mode 100644 index 000000000..7986fb124 --- /dev/null +++ b/gtestsuite/src/test_setm.cpp @@ -0,0 +1,205 @@ +#include "blis_test.h" +#include "blis_utils.h" + +// Local prototypes. +void libblis_test_setm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_setm_impl ( + iface_t iface, + obj_t* beta, + obj_t* x +); + +double libblis_test_setm_check ( + test_params_t* params, + obj_t* beta, + obj_t* x +); + +double libblis_test_bitrp_setm( + test_params_t* params, + iface_t iface, + obj_t* beta, + obj_t* x, + obj_t* r, + num_t dt +){ + + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + libblis_test_setm_impl( iface, beta, r ); + resid = libblis_test_bitrp_matrix(x, r, dt); + } + + return resid; +} + +double libblis_test_op_setm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + dim_t m, n; + obj_t beta; + obj_t x; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &x ); + + // Initialize beta to unit. + bli_copysc( &BLIS_ONE, &beta ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Randomize x. + libblis_test_mobj_randomize( params, FALSE, &x ); + } + else { + libblis_test_mobj_irandomize( params, &x ); + } + + libblis_test_setm_impl( iface, &beta, &x ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + + resid = libblis_test_bitrp_setm( params, iface, &beta, &x, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_test_setm_check( params, &beta, &x ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + + return abs(resid); +} + +void libblis_test_setm_impl ( + iface_t iface, + obj_t* beta, + obj_t* x +){ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_setm( beta, x ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_setm_check( + test_params_t* params, + obj_t* beta, + obj_t* x +){ + num_t dt_x = bli_obj_dt( x ); + dim_t m_x = bli_obj_length( x ); + dim_t n_x = bli_obj_width( x ); + inc_t rs_x = bli_obj_row_stride( x ); + inc_t cs_x = bli_obj_col_stride( x ); + void* buf_x = (void*)bli_obj_buffer_at_off( x ); + void* buf_beta = (void*)bli_obj_buffer_for_1x1( dt_x, beta ); + dim_t i, j; + double resid = 0.0; + + // The easiest way to check that setm was successful is to confirm + // that each element of x is equal to beta. + + if ( bli_obj_is_float( x ) ) { + float* beta_cast = (float*)buf_beta; + float* buf_x_cast = (float*)buf_x; + float* chi1; + + for ( j = 0; j < n_x; ++j ) { + for ( i = 0; i < m_x; ++i ) { + chi1 = buf_x_cast + (i )*rs_x + (j )*cs_x; + if ( !bli_seq( *chi1, *beta_cast ) ) { + resid = 1.0; + return resid; + } + } + } + } + else if ( bli_obj_is_double( x ) ) { + double* beta_cast = (double*)buf_beta; + double* buf_x_cast = (double*)buf_x; + double* chi1; + + for ( j = 0; j < n_x; ++j ) { + for ( i = 0; i < m_x; ++i ) { + chi1 = buf_x_cast + (i )*rs_x + (j )*cs_x; + if ( !bli_deq( *chi1, *beta_cast ) ) { + resid = 1.0; + return resid; + } + } + } + } + else if ( bli_obj_is_scomplex( x ) ) { + scomplex* beta_cast = (scomplex*)buf_beta; + scomplex* buf_x_cast = (scomplex*)buf_x; + scomplex* chi1; + + for ( j = 0; j < n_x; ++j ) { + for ( i = 0; i < m_x; ++i ) { + chi1 = buf_x_cast + (i )*rs_x + (j )*cs_x; + if ( !bli_ceq( *chi1, *beta_cast ) ) { + resid = 1.0; + return resid; + } + } + } + } + else /* if ( bli_obj_is_dcomplex( x ) )*/ { + dcomplex* beta_cast = (dcomplex*)buf_beta; + dcomplex* buf_x_cast = (dcomplex*)buf_x; + dcomplex* chi1; + + for ( j = 0; j < n_x; ++j ) { + for ( i = 0; i < m_x; ++i ) { + chi1 = buf_x_cast + (i )*rs_x + (j )*cs_x; + if ( !bli_zeq( *chi1, *beta_cast ) ) { + resid = 1.0; + return resid; + } + } + } + } + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_setv.cpp b/gtestsuite/src/test_setv.cpp new file mode 100644 index 000000000..f76db8a3f --- /dev/null +++ b/gtestsuite/src/test_setv.cpp @@ -0,0 +1,201 @@ +#include "blis_test.h" +#include "blis_utils.h" + +// Local prototypes. +void libblis_test_setv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_setv_impl ( + iface_t iface, + obj_t* beta, + obj_t* x +); + +double libblis_test_setv_check ( + test_params_t* params, + obj_t* beta, + obj_t* x +); + +double libblis_ref_setv( + test_params_t* params, + obj_t* beta, + obj_t* x +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_setv_check( params, beta, x ); + } + return resid; +} + +double libblis_test_bitrp_setv( + test_params_t* params, + iface_t iface, + obj_t* beta, + obj_t* x, + obj_t* r, + num_t dt +){ + + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + libblis_test_setv_impl( iface, beta, r ); + resid = libblis_test_bitrp_matrix(x, r, dt); + } + + return resid; +} + +double libblis_test_op_setv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + dim_t m; + obj_t beta; + obj_t x; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + + // Initialize beta to unit. + bli_copysc( &BLIS_ONE, &beta ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, FALSE, &x ); + } + else { + libblis_test_vobj_irandomize( params, &x ); + } + + libblis_test_setv_impl( iface, &beta, &x ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[0], m, &r ); + + resid = libblis_test_bitrp_setv( params, iface, &beta, &x, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_setv( params, &beta, &x); + } +#endif + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + + return abs(resid); +} + +void libblis_test_setv_impl ( + iface_t iface, + obj_t* beta, + obj_t* x +) { + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_setv( beta, x ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_setv_check ( + test_params_t* params, + obj_t* beta, + obj_t* x +) { + num_t dt_x = bli_obj_dt( x ); + dim_t m_x = bli_obj_vector_dim( x ); + inc_t inc_x = bli_obj_vector_inc( x ); + void* buf_x = (void*)bli_obj_buffer_at_off( x ); + void* buf_beta = (void*)bli_obj_buffer_for_1x1( dt_x, beta ); + dim_t i; + + double resid = 0.0; + + // + // The easiest way to check that setv was successful is to confirm + // that each element of x is equal to beta. + // + + if ( bli_obj_is_float( x ) ) { + float* chi1 = (float*)buf_x; + float* beta_cast = (float*)buf_beta; + + for ( i = 0; i < m_x; ++i ) { + if ( !bli_seq( *chi1, *beta_cast ) ) { + resid = 1.0; + return resid; + } + chi1 += inc_x; + } + } + else if ( bli_obj_is_double( x ) ) { + double* chi1 = (double*)buf_x; + double* beta_cast = (double*)buf_beta; + + for ( i = 0; i < m_x; ++i ) { + if ( !bli_deq( *chi1, *beta_cast ) ) { + resid = 1.0; + return resid; + } + chi1 += inc_x; + } + } + else if ( bli_obj_is_scomplex( x ) ) { + scomplex* chi1 = (scomplex*)buf_x; + scomplex* beta_cast = (scomplex*)buf_beta; + + for ( i = 0; i < m_x; ++i ) { + if ( !bli_ceq( *chi1, *beta_cast ) ) { + resid = 1.0; + return resid; + } + chi1 += inc_x; + } + } + else /* if ( bli_obj_is_dcomplex( x ) ) */{ + dcomplex* chi1 = (dcomplex*)buf_x; + dcomplex* beta_cast = (dcomplex*)buf_beta; + + for ( i = 0; i < m_x; ++i ) { + if ( !bli_zeq( *chi1, *beta_cast ) ) { + resid = 1.0; + return resid; + } + chi1 += inc_x; + } + } + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_subm.cpp b/gtestsuite/src/test_subm.cpp new file mode 100644 index 000000000..d4c2c664b --- /dev/null +++ b/gtestsuite/src/test_subm.cpp @@ -0,0 +1,235 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_subm.h" + +// Local prototypes. +void libblis_test_subm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_subm_impl ( + iface_t iface, + obj_t* x, + obj_t* y +); + +double libblis_test_subm_check ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y +); + +double libblis_ref_subm( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_subm_check( params, alpha, beta, x, y ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_isubm_check( params, x, y, y_orig); + } + else { + resid = libblis_test_matrix_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_subm( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( y_orig, r ); + libblis_test_subm_impl( iface, x, r ); + resid = libblis_test_bitrp_matrix(y, r, dt); + } + return resid; +} + +double libblis_test_op_subm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +) { + num_t datatype; + dim_t m, n; + trans_t transx; + obj_t alpha, beta; + obj_t x, y, y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_trans( pc_str[0], &transx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transx, + sc_str[0], m, n, &x ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, n, &y ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, n, &y_save ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Initialize alpha and beta. + bli_setsc( -1.0, -1.0, &alpha ); + bli_setsc( 3.0, 3.0, &beta ); + + // Randomize x. + bli_setm( &alpha, &x ); + bli_setm( &beta, &y ); + } + else { + libblis_test_mobj_irandomize( params, &x ); + libblis_test_mobj_irandomize( params, &y ); + } + + // Apply the parameters. + bli_obj_set_conjtrans( transx, &x ); + + //Copy c to c_save + bli_copym( &y, &y_save ); + + libblis_test_subm_impl( iface, &x, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, n, &r ); + resid = libblis_test_bitrp_subm( params, iface, &x, &y, &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_subm( params, &alpha, &beta, &x, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_subm_impl ( + iface_t iface, + obj_t* x, + obj_t* y +) { + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_subm( x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_subm_check ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + dim_t m = bli_obj_length( y ); + dim_t n = bli_obj_width( y ); + + conj_t conjx = bli_obj_conj_status( x ); + + obj_t aminusb; + obj_t alpha_conj; + obj_t norm_r, m_r, n_r, temp_r; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is set to alpha. + // - y_orig is set to beta. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := y_orig - conjx(x) + // + // is functioning correctly if + // + // normfm(y) - sqrt( absqsc( beta - conjx(alpha) ) * m * n ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt, &aminusb ); + bli_obj_scalar_init_detached( dt_real, &temp_r ); + bli_obj_scalar_init_detached( dt_real, &norm_r ); + bli_obj_scalar_init_detached( dt_real, &m_r ); + bli_obj_scalar_init_detached( dt_real, &n_r ); + + bli_obj_scalar_init_detached_copy_of( dt, conjx, alpha, &alpha_conj ); + + bli_normfm( y, &norm_r ); + + bli_copysc( beta, &aminusb ); + bli_subsc( &alpha_conj, &aminusb ); + + bli_setsc( ( double )m, 0.0, &m_r ); + bli_setsc( ( double )n, 0.0, &n_r ); + + bli_absqsc( &aminusb, &temp_r ); + bli_mulsc( &m_r, &temp_r ); + bli_mulsc( &n_r, &temp_r ); + bli_sqrtsc( &temp_r, &temp_r ); + bli_subsc( &temp_r, &norm_r ); + + bli_getsc( &norm_r, &resid, &junk ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_subm.h b/gtestsuite/src/test_subm.h new file mode 100644 index 000000000..59513da64 --- /dev/null +++ b/gtestsuite/src/test_subm.h @@ -0,0 +1,16 @@ +#ifndef TEST_SUBM_H +#define TEST_SUBM_H + +#include "blis_test.h" + +double libblis_test_isubm_check + ( + test_params_t* params, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_subm( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SUBM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_subv.cpp b/gtestsuite/src/test_subv.cpp new file mode 100644 index 000000000..0f15dd4ef --- /dev/null +++ b/gtestsuite/src/test_subv.cpp @@ -0,0 +1,218 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_subv.h" + +// Local prototypes. +void libblis_test_subv_deps(thread_data_t* tdata, + test_params_t* params, test_op_t* op ); + +void libblis_test_subv_impl(iface_t iface, obj_t* x, obj_t* y ); + +double libblis_test_subv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y +); + +double libblis_ref_subv( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_subv_check(params, alpha, beta, x, y ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_isubv_check(params, alpha, beta, x, y, y_save); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_subv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_subv_impl( iface, x, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_subv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim +){ + num_t datatype; + dim_t m; + conj_t conjx; + obj_t alpha, beta; + obj_t x, y, y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y_save ); + + // Initialize alpha and beta. + bli_setsc( 1.0, 1.0, &alpha ); + bli_setsc( 3.0, 3.0, &beta ); + + // Set x and y to alpha and beta, respectively. + bli_setv( &alpha, &x ); + bli_setv( &beta, &y ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + + bli_copyv( &y, &y_save ); + + libblis_test_subv_impl( iface, &x, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[1], m, &r ); + + resid = libblis_test_bitrp_subv( params, iface, &x, &y, &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_subv( params, &alpha, &beta, &x, &y, &y_save); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_subv_impl ( + iface_t iface, + obj_t* x, + obj_t* y +){ + + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_subv( x, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_subv_check ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y +) { + num_t dt = bli_obj_dt( x ); + num_t dt_real = bli_obj_dt_proj_to_real( x ); + dim_t m = bli_obj_vector_dim( x ); + + conj_t conjx = bli_obj_conj_status( x ); + + obj_t aminusb; + obj_t alpha_conj; + obj_t norm_r, m_r, temp_r; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is set to alpha. + // - y_orig is set to beta. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := y_orig - conjx(x) + // + // is functioning correctly if + // + // normfv(y) - sqrt( absqsc( beta - conjx(alpha) ) * m ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt, &aminusb ); + bli_obj_scalar_init_detached( dt_real, &temp_r ); + bli_obj_scalar_init_detached( dt_real, &norm_r ); + bli_obj_scalar_init_detached( dt_real, &m_r ); + + bli_obj_scalar_init_detached_copy_of( dt, conjx, alpha, &alpha_conj ); + + bli_normfv( y, &norm_r ); + + bli_copysc( beta, &aminusb ); + bli_subsc( &alpha_conj, &aminusb ); + + bli_setsc( ( double )m, 0.0, &m_r ); + + bli_absqsc( &aminusb, &temp_r ); + bli_mulsc( &m_r, &temp_r ); + bli_sqrtsc( &temp_r, &temp_r ); + bli_subsc( &temp_r, &norm_r ); + + bli_getsc( &norm_r, &resid, &junk ); + + return resid; +} + + diff --git a/gtestsuite/src/test_subv.h b/gtestsuite/src/test_subv.h new file mode 100644 index 000000000..0733e50da --- /dev/null +++ b/gtestsuite/src/test_subv.h @@ -0,0 +1,18 @@ +#ifndef TEST_SUBV_H +#define TEST_SUBV_H + +#include "blis_test.h" + +double libblis_test_isubv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* beta, + obj_t* x, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_subv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SUBV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_symm.cpp b/gtestsuite/src/test_symm.cpp new file mode 100644 index 000000000..40fa863a9 --- /dev/null +++ b/gtestsuite/src/test_symm.cpp @@ -0,0 +1,551 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_symm.h" + +using namespace std; + +// Local prototypes. +void libblis_test_symm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_symm_impl( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +); + +double libblis_test_symm_check( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +); + +double cblas_symm( + side_t side, + uplo_t uploa, + f77_int mm, + f77_int nn, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* b, + f77_int ldb, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uplo; + enum CBLAS_SIDE cblas_side; + + if ( bli_obj_row_stride( c ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if(bli_is_upper(uploa)) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + if(bli_is_left(side)) + cblas_side = CblasLeft; + else + cblas_side = CblasRight; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + cblas_ssymm( cblas_order, cblas_side, cblas_uplo, mm, nn, *alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + cblas_dsymm( cblas_order, cblas_side, cblas_uplo, mm, nn, *alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cblas_csymm( cblas_order, cblas_side, cblas_uplo, mm, nn, alphap, + ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + cblas_zsymm( cblas_order, cblas_side, cblas_uplo, mm, nn, alphap, + ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return 0; +} + +double blas_symm( + side_t side, + uplo_t uploa, + f77_int mm, + f77_int nn, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* b, + f77_int ldb, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + + f77_char f77_side; + f77_char f77_uploa; + + bli_param_map_blis_to_netlib_side( side, &f77_side ); + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + ssymm_( &f77_side, &f77_uploa, &mm, &nn, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + dsymm_( &f77_side, &f77_uploa, &mm, &nn, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + csymm_( &f77_side, &f77_uploa, &mm, &nn, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + zsymm_( &f77_side, &f77_uploa, &mm, &nn, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_symm( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_symm_impl( iface, side, alpha, a, b, beta, c ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + f77_int mm = bli_obj_length( c ); + f77_int nn = bli_obj_width( c ); + f77_int lda, ldb, ldc; + + if( bli_obj_row_stride( c ) == 1 ) { + lda = bli_obj_col_stride( a ); + ldb = bli_obj_col_stride( b ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldb = bli_obj_row_stride( b ); + ldc = bli_obj_row_stride( c ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldb = ldb + params->ld[1]; + ldc = ldc + params->ld[2]; + } + + if(params->api == API_CBLAS) { + cblas_symm( side, uploa, mm, nn, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } else { /**/ + if( bli_obj_row_stride( c ) == 1 ) { + blas_symm( side, uploa, mm, nn, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } + else { + if( side == BLIS_LEFT) + side = BLIS_RIGHT; + else if(side == BLIS_RIGHT) + side = BLIS_LEFT; + + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + blas_symm( side, uploa, nn, mm, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } + } + } + return ; +} + +double libblis_ref_symm( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_save, + num_t dt +) { + + double resid = 0.0; + double *betap = (double *)bli_obj_buffer( beta ); + + if ((params->nanf) && (*betap == 0)) { + resid = libblis_check_nan_symm(c, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_symm_check( params, side, alpha, a, b, beta, c, c_save ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_isymm_check( params, side, alpha, a, b, beta, c, c_save ); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_symm( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_symm_impl( iface, side, alpha, a, b, beta, r ); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_symm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +) { + num_t datatype; + dim_t m, n; + dim_t mn_side; + side_t side; + uplo_t uploa; + obj_t alpha, a, b, beta, c; + obj_t c_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_side( pc_str[0], &side ); + bli_param_map_char_to_blis_uplo( pc_str[1], &uploa ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + bli_set_dim_with_side( side, m, n, &mn_side ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], mn_side, mn_side, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, n, &b ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &c ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &c_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_SYMMETRIC, &a ); + bli_obj_set_uplo( uploa, &a ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &c ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + bli_setsc( betv.real, (betv.real/1.2), &beta ); + } + // Randomize A, B, and C, and save C. + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_mobj_randomize( params, TRUE, &b ); + libblis_test_mobj_randomize( params, TRUE, &c ); + } + else { + int32_t x = (int32_t)1.0; //alpv.real; + int32_t y = (int32_t)1.0; //betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + int32_t ac = (int32_t)(x/0.8); + int32_t bc = (int32_t)(y/1.0); + bli_setsc( (double)x, (double)ac, &alpha ); + bli_setsc( (double)y, (double)bc, &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_mobj_irandomize( params, &b ); + libblis_test_mobj_irandomize( params, &c ); + } + + if ((params->nanf) && (betv.real == 0) ) { + test_fillbuffmem(&c, datatype ); + } + + // Randomize A, make it densely symmetric, and zero the unstored triangle + // to ensure the implementation reads only from the stored region. + bli_mksymm( &a ); + bli_mktrim( &a ); + + //Copy c to c_save + bli_copym( &c, &c_save ); + + libblis_api_symm(params, iface, side, &alpha, &a, &b, &beta, &c, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + resid = libblis_test_bitrp_symm( params, iface, side,&alpha, &a, &b, + &beta, &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_symm(params, side, &alpha, &a, &b, &beta, + &c, &c_save, datatype ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &c, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &b ); + libblis_test_obj_free( &c ); + libblis_test_obj_free( &c_save ); + + return abs(resid); +} + +void libblis_test_symm_impl ( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +){ + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_symm( side, alpha, a, b, beta, c ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_symm_check ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +) { + num_t dt = bli_obj_dt( c ); + num_t dt_real = bli_obj_dt_proj_to_real( c ); + + dim_t m = bli_obj_length( c ); + dim_t n = bli_obj_width( c ); + + obj_t norm; + obj_t t, v, w, z; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - a is randomized and symmetric. + // - b is randomized. + // - c_orig is randomized. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * conja(A) * transb(B) (side = left) + // C := beta * C_orig + alpha * transb(B) * conja(A) (side = right) + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // + // z = ( beta * C_orig + alpha * conja(A) * transb(B) ) * t (side = left) + // = beta * C_orig * t + alpha * conja(A) * transb(B) * t + // = beta * C_orig * t + alpha * conja(A) * w + // = beta * C_orig * t + z + // + // z = ( beta * C_orig + alpha * transb(B) * conja(A) ) * t (side = right) + // = beta * C_orig * t + alpha * transb(B) * conja(A) * t + // = beta * C_orig * t + alpha * transb(B) * w + // = beta * C_orig * t + z + + bli_obj_scalar_init_detached( dt_real, &norm ); + + if ( bli_is_left( side ) ) + { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, m, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + else // else if ( bli_is_left( side ) ) + { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, n, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, c, &t, &BLIS_ZERO, &v ); + + if ( bli_is_left( side ) ) + { + bli_gemv( &BLIS_ONE, b, &t, &BLIS_ZERO, &w ); + bli_symv( alpha, a, &w, &BLIS_ZERO, &z ); + } + else + { + bli_symv( &BLIS_ONE, a, &t, &BLIS_ZERO, &w ); + bli_gemv( alpha, b, &w, &BLIS_ZERO, &z ); + } + + bli_gemv( beta, c_orig, &t, &BLIS_ONE, &z ); + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + bli_obj_free( &z ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_symm.h b/gtestsuite/src/test_symm.h new file mode 100644 index 000000000..b47940980 --- /dev/null +++ b/gtestsuite/src/test_symm.h @@ -0,0 +1,20 @@ +#ifndef TEST_SYMM_H +#define TEST_SYMM_H + +#include "blis_test.h" + +double libblis_test_isymm_check + ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ); + +double libblis_check_nan_symm(obj_t* c, num_t dt ); + +#endif /* TEST_SYMM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_symv.cpp b/gtestsuite/src/test_symv.cpp new file mode 100644 index 000000000..6c0c68a73 --- /dev/null +++ b/gtestsuite/src/test_symv.cpp @@ -0,0 +1,497 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_symv.h" + +// Local prototypes. +void libblis_test_symv_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_symv_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y +); + +double libblis_test_symv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +); + +void cblas_symv( + uplo_t uploa, + f77_int m, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + obj_t* beta, + obj_t* y, + f77_int incy, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uplo ; + + if ( bli_obj_row_stride( a ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_upper( uploa ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* betap = (float*) bli_obj_buffer( beta ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_ssymv(cblas_order, cblas_uplo, m, *alphap, ap, lda, xp, incx, + *betap, yp, incy); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* betap = (double*) bli_obj_buffer( beta ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_dsymv(cblas_order, cblas_uplo, m, *alphap, ap, lda, xp, incx, + *betap, yp, incy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cblas_chemv(cblas_order, cblas_uplo, m, alphap, ap, lda, xp, incx, + betap, yp, incy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + cblas_zhemv(cblas_order, cblas_uplo, m, alphap, ap, lda, xp, incx, + betap, yp, incy); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_symv( + f77_char f77_uploa, + f77_int m, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + obj_t* beta, + obj_t* y, + f77_int incy, + num_t dt +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* betap = (float*) bli_obj_buffer( beta ); + float* yp = (float*) bli_obj_buffer( y ); + ssymv_(&f77_uploa, &m, alphap, ap, (f77_int*)&lda, xp, &incx, + betap, yp, &incy); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* betap = (double*) bli_obj_buffer( beta ); + double* yp = (double*) bli_obj_buffer( y ); + dsymv_(&f77_uploa, &m, alphap, ap, (f77_int*)&lda, xp, &incx, + betap, yp, &incy); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + chemv_(&f77_uploa, &m, alphap, ap, (f77_int*)&lda, xp, &incx, + betap, yp, &incy); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + zhemv_(&f77_uploa, &m, alphap, ap, (f77_int*)&lda, xp, &incx, + betap, yp, &incy); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_symv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y +){ + + if(params->api == API_BLIS) { + libblis_test_symv_impl( iface, alpha, a, x, beta, y); + } + else { /*CLBAS || BLAS */ + num_t dt = bli_obj_dt( a ); + uplo_t uploa = bli_obj_uplo( a ); + f77_int mm = bli_obj_length( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + if( bli_obj_has_conj(a) ) { + conjugate_tensor(a, dt); + } + if( bli_obj_has_conj(x) ) { + conjugate_tensor(x, dt); + } + + if(params->api == API_CBLAS) { + cblas_symv(uploa, mm, alpha, a, lda, x, incx, beta, y, incy, dt ); + } + else { /**/ + f77_char f77_uploa; + if ( bli_obj_row_stride( a ) == 1 ){ + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_symv(f77_uploa, mm, alpha, a, lda, x, incx, beta, y, incy, dt ); + } + else { + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_symv(f77_uploa, mm, alpha, a, lda, x, incx, beta, y, incy, dt ); + } + } + } + return ; +} + +double libblis_ref_symv( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_symv_check( params, alpha, a, x, beta, y, y_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_isymv_check( params, alpha, a, x, beta, y, y_orig); + } + else { + resid = libblis_test_vector_check(params, y); + } + } + return resid; +} + +double libblis_test_bitrp_symv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_symv_impl( iface, alpha, a, x, beta, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_symv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m; + uplo_t uploa; + conj_t conja; + conj_t conjx; + obj_t alpha, a, x, beta, y; + obj_t y_save; + double resid = 0.0; + obj_t aa, xx; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploa ); + bli_param_map_char_to_blis_conj( pc_str[1], &conja ); + bli_param_map_char_to_blis_conj( pc_str[2], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &aa ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &xx ); + libblis_test_vobj_create( params, datatype, + sc_str[2], m, &y ); + libblis_test_vobj_create( params, datatype, + sc_str[2], m, &y_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_SYMMETRIC, &a ); + bli_obj_set_uplo( uploa, &a ); + + bli_obj_set_struc( BLIS_SYMMETRIC, &aa ); + bli_obj_set_uplo( uploa, &aa ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &y ) ){ + bli_setsc( 1.0, 0.0, &alpha ); + bli_setsc( -1.0, 0.0, &beta ); + } + else{ + bli_setsc( 0.5, 0.5, &alpha ); + bli_setsc( -0.5, 0.5, &beta ); + } + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_vobj_randomize( params, TRUE, &y ); + } + else { + int32_t xx = (int32_t) 1.0; + int32_t yy = (int32_t)-1.0; + if ( bli_obj_is_real( &y ) ){ + bli_setsc( xx, 0.0, &alpha ); + bli_setsc( yy, 0.0, &beta ); + } + else{ + xx = (int32_t)(xx/0.8); + yy = (int32_t)(yy/1.5); + bli_setsc( xx, (xx+yy), &alpha ); + bli_setsc( yy, (xx-yy), &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + + // Randomize A, make it densely symmetric, and zero the unstored triangle + // to ensure the implementation reads only from the stored region. + bli_mksymm( &a ); + bli_mktrim( &a ); + + // Randomize x and y, and save y. + bli_copyv( &y, &y_save ); + + bli_copym( &a, &aa ); + bli_copyv( &x, &xx ); + + // Apply the remaining parameters. + bli_obj_set_conj( conja, &a ); + bli_obj_set_conj( conjx, &x ); + + bli_obj_set_conj( conja, &aa ); + bli_obj_set_conj( conjx, &xx ); + + libblis_api_symv(params, iface, &alpha, &aa, &xx, &beta, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[2], m, &r ); + + resid = libblis_test_bitrp_symv( params, iface, &alpha, &a, &x, + &beta, &y, &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_symv( params, &alpha, &a, &x, &beta, &y, &y_save); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_symv_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_symv( alpha, a, x, beta, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_symv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( y ); + + obj_t v; + obj_t norm; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - a is randomized and symmetric. + // - x is randomized. + // - y_orig is randomized. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := beta * y_orig + alpha * conja(A) * conjx(x) + // + // is functioning correctly if + // + // normfv( y - v ) + // + // is negligible, where + // + // v = beta * y_orig + alpha * conja(A_dense) * x + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &v ); + + bli_copyv( y_orig, &v ); + + bli_mksymm( a ); + bli_obj_set_struc( BLIS_GENERAL, a ); + bli_obj_set_uplo( BLIS_DENSE, a ); + + bli_gemv( alpha, a, x, beta, &v ); + + bli_subv( &v, y ); + bli_normfv( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &v ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_symv.h b/gtestsuite/src/test_symv.h new file mode 100644 index 000000000..b8e1b6e51 --- /dev/null +++ b/gtestsuite/src/test_symv.h @@ -0,0 +1,19 @@ +#ifndef TEST_SYMV_H +#define TEST_SYMV_H + +#include "blis_test.h" + +double libblis_test_isymv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_symv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SYMV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_syr.cpp b/gtestsuite/src/test_syr.cpp new file mode 100644 index 000000000..83319ecca --- /dev/null +++ b/gtestsuite/src/test_syr.cpp @@ -0,0 +1,420 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_syr.h" + +// Local prototypes. +void libblis_test_syr_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_syr_impl ( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* a +); + +double libblis_test_syr_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig +); + +void cblas_syr( + uplo_t uploa, + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* a, + f77_int lda, + num_t dt +){ + enum CBLAS_UPLO cblas_uplo; + enum CBLAS_ORDER cblas_order = CblasColMajor; + + if( bli_is_upper( uploa ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + cblas_ssyr(cblas_order, cblas_uplo, m, *alphap, xp, incx, ap, lda); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + cblas_dsyr(cblas_order, cblas_uplo, m, *alphap, xp, incx, ap, lda); + break; + } + case BLIS_SCOMPLEX : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cblas_cher(cblas_order, cblas_uplo, m, *alphap, xp, incx, ap, lda); + break; + } + case BLIS_DCOMPLEX : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + cblas_zher(cblas_order, cblas_uplo, m, *alphap, xp, incx, ap, lda); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_syr( + f77_char f77_uploa, + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* a, + f77_int lda, + num_t dt +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + ssyr_(&f77_uploa, &m, alphap, xp, &incx, ap, (f77_int*)&lda ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + dsyr_(&f77_uploa, &m, alphap, xp, &incx, ap, (f77_int*)&lda ); + break; + } + case BLIS_SCOMPLEX : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cher_(&f77_uploa, &m, alphap, xp, &incx, ap, (f77_int*)&lda ); + break; + } + case BLIS_DCOMPLEX : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + zher_(&f77_uploa, &m, alphap, xp, &incx, ap, (f77_int*)&lda ); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_syr( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* a, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_syr_impl( iface, alpha, x, a ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + f77_int mm = bli_obj_length( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + if(params->api == API_CBLAS) { + cblas_syr(uploa, mm, alpha, x, incx, a, lda, dt ); + } + else { /**/ + f77_char f77_uploa; + if ( bli_obj_row_stride( a ) == 1 ){ + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_syr(f77_uploa, mm, alpha, x, incx, a, lda, dt ); + } + else { + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_syr(f77_uploa, mm, alpha, x, incx, a, lda, dt ); + } + } + } + return ; +} + +double libblis_ref_syr( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_syr_check( params, alpha, x, a, a_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_isyr_check( params, alpha, x, a, a_orig ); + } + else { + resid = libblis_test_vector_check(params, a); + } + } + return resid; +} + +double libblis_test_bitrp_syr( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( a_orig, r ); + libblis_test_syr_impl( iface, alpha, x, r ); + resid = libblis_test_bitrp_vector(a, r, dt); + } + return resid; +} + +double libblis_test_op_syr ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + uplo_t uploa; + conj_t conjx; + obj_t alpha, x, a; + obj_t a_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploa ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, + sc_str[0], m, &x ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, m, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, m, &a_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_SYMMETRIC, &a ); + bli_obj_set_uplo( uploa, &a ); + + // Set alpha. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + bli_setsc( alpv.real, 0.0, &alpha ); + // Randomize x. + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_mobj_randomize( params, TRUE, &a ); + } + else{ + int32_t xx = (int32_t)alpv.real; + bli_setsc( (double)xx, (double)0.0, &alpha ); + // Randomize x. + libblis_test_vobj_irandomize( params, &x ); + libblis_test_mobj_irandomize( params, &a ); + } + + // Randomize A, make it densely symmetric, and zero the unstored triangle + // to ensure the implementation is reads only from the stored region. + bli_mksymm( &a ); + bli_mktrim( &a ); + + // Save A and set its structure and uplo properties. + bli_obj_set_struc( BLIS_SYMMETRIC, &a_save ); + bli_obj_set_uplo( uploa, &a_save ); + bli_copym( &a, &a_save ); + bli_mktrim( &a_save ); + + // Apply the remaining parameters. + bli_obj_set_conj( conjx, &x ); + + libblis_api_syr(params, iface, &alpha, &x, &a, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[1], m, m, &r ); + + resid = libblis_test_bitrp_syr( params, iface, &alpha, &x, + &a, &a_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_syr( params, &alpha, &x, &a, &a_save ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &a, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &a ); + libblis_test_obj_free( &a_save ); + + return abs(resid); +} + +void libblis_test_syr_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* a +){ + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_syr( alpha, x, a ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_syr_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig +){ + num_t dt = bli_obj_dt( a ); + num_t dt_real = bli_obj_dt_proj_to_real( a ); + + dim_t m_a = bli_obj_length( a ); + + obj_t xt, t, v, w; + obj_t rho, norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - a is randomized and symmetric. + // Note: + // - alpha should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // A := A_orig + alpha * conjx(x) * conjx(x)^T + // + // is functioning correctly if + // + // normfv( v - w ) + // + // is negligible, where + // + // v = A * t + // w = ( A_orig + alpha * conjx(x) * conjx(x)^T ) * t + // = A_orig * t + alpha * conjx(x) * conjx(x)^T * t + // = A_orig * t + alpha * conjx(x) * rho + // = A_orig * t + w + // + + bli_mksymm( a ); + bli_mksymm( a_orig ); + bli_obj_set_struc( BLIS_GENERAL, a ); + bli_obj_set_struc( BLIS_GENERAL, a_orig ); + bli_obj_set_uplo( BLIS_DENSE, a ); + bli_obj_set_uplo( BLIS_DENSE, a_orig ); + + bli_obj_scalar_init_detached( dt, &rho ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m_a, 1, 0, 0, &t ); + bli_obj_create( dt, m_a, 1, 0, 0, &v ); + bli_obj_create( dt, m_a, 1, 0, 0, &w ); + + bli_obj_alias_to( x, &xt ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, a, &t, &BLIS_ZERO, &v ); + + bli_dotv( &xt, &t, &rho ); + bli_mulsc( alpha, &rho ); + bli_scal2v( &rho, x, &w ); + bli_gemv( &BLIS_ONE, a_orig, &t, &BLIS_ONE, &w ); + + bli_subv( &w, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_syr.h b/gtestsuite/src/test_syr.h new file mode 100644 index 000000000..33b592a93 --- /dev/null +++ b/gtestsuite/src/test_syr.h @@ -0,0 +1,17 @@ +#ifndef TEST_SYR_H +#define TEST_SYR_H + +#include "blis_test.h" + +double libblis_test_isyr_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* a, + obj_t* a_orig + ); + +double libblis_check_nan_syr( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SYR_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_syr2.cpp b/gtestsuite/src/test_syr2.cpp new file mode 100644 index 000000000..44360fba8 --- /dev/null +++ b/gtestsuite/src/test_syr2.cpp @@ -0,0 +1,496 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_syr2.h" + +// Local prototypes. +void libblis_test_syr2_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_syr2_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a +); + +double libblis_test_syr2_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +); + +void cblas_syr2( + uplo_t uploa, + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + obj_t* a, + f77_int lda, + num_t dt +){ + enum CBLAS_UPLO cblas_uplo; + enum CBLAS_ORDER cblas_order; + if ( bli_obj_row_stride( a ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_upper( uploa ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + cblas_ssyr2(cblas_order, cblas_uplo, m, *alphap, xp, incx, + yp, incy, ap, lda); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + cblas_dsyr2(cblas_order, cblas_uplo, m, *alphap, xp, incx, + yp, incy, ap, lda); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cblas_cher2(cblas_order, cblas_uplo, m, alphap, xp, incx, + yp, incy, ap, lda); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + cblas_zher2(cblas_order, cblas_uplo, m, alphap, xp, incx, + yp, incy, ap, lda); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_syr2( + f77_char f77_uploa, + f77_int m, + obj_t* alpha, + obj_t* x, + f77_int incx, + obj_t* y, + f77_int incy, + obj_t* a, + f77_int lda, + num_t dt +){ + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + float* yp = (float*) bli_obj_buffer( y ); + ssyr2_(&f77_uploa, &m, alphap, xp, &incx, yp, &incy, ap, (f77_int*)&lda); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + double* yp = (double*) bli_obj_buffer( y ); + dsyr2_(&f77_uploa, &m, alphap, xp, &incx, yp, &incy, ap, (f77_int*)&lda); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + scomplex* yp = (scomplex*) bli_obj_buffer( y ); + cher2_(&f77_uploa, &m, alphap, xp, &incx, yp, &incy, ap, (f77_int*)&lda); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + dcomplex* yp = (dcomplex*) bli_obj_buffer( y ); + zher2_(&f77_uploa, &m, alphap, xp, &incx, yp, &incy, ap, (f77_int*)&lda); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_syr2( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + num_t dt +){ + + if(params->api == API_BLIS) { + libblis_test_syr2_impl( iface, alpha, x, y, a ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + f77_int mm = bli_obj_length( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int incy = bli_obj_vector_inc( y ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + if(params->api == API_CBLAS) { + cblas_syr2(uploa, mm, alpha, x, incx, y, incy, a, lda, dt ); + } + else { /**/ + f77_char f77_uploa; + if ( bli_obj_row_stride( a ) == 1 ){ + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_syr2(f77_uploa, mm, alpha, x, incx, y, incy, a, lda, dt ); + } + else { + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + conjugate_tensor(x, dt); + conjugate_tensor(y, dt); + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + blas_syr2(f77_uploa, mm, alpha, x, incx, y, incy, a, lda, dt ); + } + } + } + return ; +} + +double libblis_ref_syr2( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_syr2_check( params, alpha, x, y, a, a_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_isyr2_check( params, alpha, x, y, a, a_orig); + } + else { + resid = libblis_test_matrix_check(params, a); + } + } + return resid; +} + +double libblis_test_bitrp_syr2( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( a_orig, r ); + bli_mksymm( r ); + bli_mktrim( r ); + libblis_test_syr2_impl( iface, alpha, x, y, r); + resid = libblis_test_bitrp_matrix(a, r, dt); + } + return resid; +} + +double libblis_test_op_syr2 ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + uplo_t uploa; + conj_t conjx, conjy; + obj_t alpha, x, y, a; + obj_t a_save; + double resid = 0.0; + obj_t xx, yy; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploa ); + bli_param_map_char_to_blis_conj( pc_str[1], &conjx ); + bli_param_map_char_to_blis_conj( pc_str[2], &conjy ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, + sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[0], m, &xx ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &yy ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, m, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, m, &a_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_SYMMETRIC, &a ); + bli_obj_set_uplo( uploa, &a ); + + // Set alpha. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &x ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + } + else { + bli_setsc( alpv.real, alpv.imag, &alpha ); + } + // Randomize x and y. + libblis_test_vobj_randomize( params, TRUE, &x ); + libblis_test_vobj_randomize( params, TRUE, &y ); + libblis_test_mobj_randomize( params, TRUE, &a ); + } + else{ + int32_t xx = (int32_t)alpv.real; + if ( bli_obj_is_real( &x ) ) { + bli_setsc( (double)xx, 0.0, &alpha ); + } + else { + int32_t ax = (int32_t)(xx/0.8); + bli_setsc( (double)xx, (double)ax, &alpha ); + } + + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + libblis_test_mobj_irandomize( params, &a ); + } + + // Randomize A, make it densely symmetric, and zero the unstored triangle + // to ensure the implementation is reads only from the stored region. + bli_mksymm( &a ); + bli_mktrim( &a ); + + // Save A and set its structure and uplo properties. + bli_obj_set_struc( BLIS_SYMMETRIC, &a_save ); + bli_obj_set_uplo( uploa, &a_save ); + bli_copym( &a, &a_save ); + bli_mksymm( &a_save ); + bli_mktrim( &a_save ); + + // Apply the remaining parameters. + bli_obj_set_conj( conjx, &x ); + bli_obj_set_conj( conjy, &y ); + + bli_copyv( &x, &xx ); + bli_copyv( &y, &yy ); + + libblis_api_syr2( params, iface, &alpha, &xx, &yy, &a, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[2], m, m, &r ); + bli_obj_set_struc( BLIS_SYMMETRIC, &r ); + bli_obj_set_uplo( uploa, &r ); + + resid = libblis_test_bitrp_syr2( params, iface, &alpha, &x, &y, + &a, &a_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_syr2( params, &alpha, &x, &y, &a, &a_save); + } +#endif + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &a, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &xx ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &yy ); + libblis_test_obj_free( &a ); + libblis_test_obj_free( &a_save ); + + return abs(resid); +} + +void libblis_test_syr2_impl( + iface_t iface, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_syr2( alpha, x, y, a ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_syr2_check( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig +){ + num_t dt = bli_obj_dt( a ); + num_t dt_real = bli_obj_dt_proj_to_real( a ); + + dim_t m_a = bli_obj_length( a ); + + obj_t xt, yt; + obj_t t, v, w1, w2; + obj_t rho, norm; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - x is randomized. + // - y is randomized. + // - a is randomized and symmetric. + // Note: + // - alpha should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // A := A_orig + alpha * conjx(x) * conjy(y)^T + alpha * conjy(y) * conjx(x)^T + // + // is functioning correctly if + // + // normfv( v - w ) + // + // is negligible, where + // + // v = A * t + // w = ( A_orig + alpha * conjx(x) * conjy(y)^T + alpha * conjy(y) * conjx(x)^T ) * t + // = A_orig * t + alpha * conjx(x) * conjy(y)^T * t + alpha * conjy(y) * conjx(x)^T * t + // = A_orig * t + alpha * conjx(x) * conjy(y)^T * t + alpha * conjy(y) * rho + // = A_orig * t + alpha * conjx(x) * conjy(y)^T * t + w1 + // = A_orig * t + alpha * conjx(x) * rho + w1 + // = A_orig * t + w2 + w1 + // + + bli_mksymm( a ); + bli_mksymm( a_orig ); + bli_obj_set_struc( BLIS_GENERAL, a ); + bli_obj_set_struc( BLIS_GENERAL, a_orig ); + bli_obj_set_uplo( BLIS_DENSE, a ); + bli_obj_set_uplo( BLIS_DENSE, a_orig ); + + bli_obj_scalar_init_detached( dt, &rho ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m_a, 1, 0, 0, &t ); + bli_obj_create( dt, m_a, 1, 0, 0, &v ); + bli_obj_create( dt, m_a, 1, 0, 0, &w1 ); + bli_obj_create( dt, m_a, 1, 0, 0, &w2 ); + + bli_obj_alias_to( x, &xt ); + bli_obj_alias_to( y, &yt ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, a, &t, &BLIS_ZERO, &v ); + + bli_dotv( &xt, &t, &rho ); + bli_mulsc( alpha, &rho ); + bli_scal2v( &rho, y, &w1 ); + + bli_dotv( &yt, &t, &rho ); + bli_mulsc( alpha, &rho ); + bli_scal2v( &rho, x, &w2 ); + + bli_addv( &w2, &w1 ); + + bli_gemv( &BLIS_ONE, a_orig, &t, &BLIS_ONE, &w1 ); + + bli_subv( &w1, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w1 ); + bli_obj_free( &w2 ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_syr2.h b/gtestsuite/src/test_syr2.h new file mode 100644 index 000000000..ce9621f6a --- /dev/null +++ b/gtestsuite/src/test_syr2.h @@ -0,0 +1,18 @@ +#ifndef TEST_SYR2_H +#define TEST_SYR2_H + +#include "blis_test.h" + +double libblis_test_isyr2_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* x, + obj_t* y, + obj_t* a, + obj_t* a_orig + ); + +double libblis_check_nan_syr2( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_SYR2_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_syr2k.cpp b/gtestsuite/src/test_syr2k.cpp new file mode 100644 index 000000000..7092c53cd --- /dev/null +++ b/gtestsuite/src/test_syr2k.cpp @@ -0,0 +1,552 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_syr2k.h" + +using namespace std; + +// Local prototypes. +void libblis_test_syr2k_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +); + +double libblis_test_syr2k_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +); + +double cblas_syr2k( + uplo_t uploc, + trans_t trans, + f77_int mm, + f77_int kk, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* b, + f77_int ldb, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uploc; + enum CBLAS_TRANSPOSE cblas_trans; + + if( bli_is_trans( trans ) ) + cblas_trans = CblasTrans; + else + cblas_trans = CblasNoTrans; + + if ( bli_obj_row_stride( c ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if(bli_is_upper(uploc)) + cblas_uploc = CblasUpper; + else + cblas_uploc = CblasLower; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + cblas_ssyr2k( cblas_order, cblas_uploc, cblas_trans, mm, kk, *alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + cblas_dsyr2k( cblas_order, cblas_uploc, cblas_trans, mm, kk, *alphap, + ap, lda, bp, ldb, *betap, cp, ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cblas_csyr2k( cblas_order, cblas_uploc, cblas_trans, mm, kk, alphap, + ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + cblas_zsyr2k( cblas_order, cblas_uploc, cblas_trans, mm, kk, alphap, + ap, lda, bp, ldb, betap, cp, ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + + return 0; +} + +double blas_syr2k( + uplo_t uploc, + trans_t trans, + f77_int mm, + f77_int kk, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* b, + f77_int ldb, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + + f77_char f77_uploc; + f77_char f77_trans; + + bli_param_map_blis_to_netlib_uplo( uploc, &f77_uploc ); + bli_param_map_blis_to_netlib_trans( trans, &f77_trans ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + ssyr2k_( &f77_uploc, &f77_trans, &mm, &kk, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + dsyr2k_( &f77_uploc, &f77_trans, &mm, &kk, alphap, ap,(f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + csyr2k_( &f77_uploc, &f77_trans, &mm, &kk, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + zsyr2k_( &f77_uploc, &f77_trans, &mm, &kk, alphap, ap, (f77_int*)&lda, + bp, (f77_int*)&ldb, betap, cp, (f77_int*)&ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_syr2k( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + num_t dt +){ + if(params->api == API_BLIS) { + libblis_test_syr2k_impl( iface, alpha, a, b, beta, c ); + } + else { /*CLBAS || BLAS */ + uplo_t uploc = bli_obj_uplo( c ); + dim_t m = bli_obj_length( c ); + dim_t k = bli_obj_width_after_trans( a ); + trans_t trans = bli_obj_onlytrans_status( a ); + f77_int lda, ldb, ldc; + + if( bli_obj_row_stride( c ) == 1 ) { + lda = bli_obj_col_stride( a ); + ldb = bli_obj_col_stride( b ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldb = bli_obj_row_stride( b ); + ldc = bli_obj_row_stride( c ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldb = ldb + params->ld[1]; + ldc = ldc + params->ld[2]; + } + + if(params->api == API_CBLAS) { + cblas_syr2k( uploc, trans, m, k, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } else { + if( bli_obj_row_stride( c ) == 1 ) { + blas_syr2k( uploc, trans, m, k, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } + else { + if( uploc == BLIS_UPPER) + uploc = BLIS_LOWER; + else if(uploc == BLIS_LOWER) + uploc = BLIS_UPPER; + + if( trans == BLIS_NO_TRANSPOSE) + trans = BLIS_TRANSPOSE; + else if(trans == BLIS_TRANSPOSE) + trans = BLIS_NO_TRANSPOSE; + + blas_syr2k( uploc, trans, m, k, alpha, a, lda, b, ldb, beta, c, ldc, dt ); + } + } + } + return ; +} + +double libblis_ref_syr2k( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_save, + num_t dt +) { + + double resid = 0.0; + double *betap = (double *)bli_obj_buffer( beta ); + + if ((params->nanf) && (*betap == 0)) { + resid = libblis_check_nan_syr2k(c, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_syr2k_check( params, alpha, a, b, beta, c, c_save ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_isyr2k_check( params, alpha, a, b, beta, c, c_save ); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_syr2k( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_syr2k_impl( iface, alpha, a, b, beta, r ); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_syr2k ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +) { + num_t datatype; + dim_t m, k; + uplo_t uploc; + trans_t trans; + obj_t alpha, a, b, beta, c; + obj_t c_save; + double resid = 0.0; + obj_t aa, bb; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploc ); + bli_param_map_char_to_syrk_trans( pc_str[1], &trans ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, trans, + sc_str[1], m, k, &a ); + libblis_test_mobj_create( params, datatype, trans, + sc_str[1], m, k, &aa ); + libblis_test_mobj_create( params, datatype, trans, + sc_str[2], m, k, &b ); + libblis_test_mobj_create( params, datatype, trans, + sc_str[2], m, k, &bb ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c_save ); + + // Set the structure and uplo properties of C. + bli_obj_set_struc( BLIS_SYMMETRIC, &c ); + bli_obj_set_uplo( uploc, &c ); + + // Set alpha and beta. + // For syr2k, both alpha and beta may be complex since, unlike her2k, + // C is symmetric in both the real and complex cases. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &c ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + // Randomize A, B, and C, and save C. + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_mobj_randomize( params, TRUE, &b ); + libblis_test_mobj_randomize( params, TRUE, &c ); + } + else { + int32_t x = (int32_t)1.0; //alpv.real; + int32_t y = (int32_t)1.0; //betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + int32_t ac = (int32_t)(x/0.8); + int32_t bc = (int32_t)(y/1.0); + bli_setsc( (double)x, (double)ac, &alpha ); + bli_setsc( (double)y, (double)bc, &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_mobj_irandomize( params, &b ); + libblis_test_mobj_irandomize( params, &c ); + } + + if ((params->nanf) && (betv.real == 0) ) { + test_fillbuffmem(&c, datatype ); + } + + // Randomize A, make it densely symmetric, and zero the unstored triangle + // to ensure the implementation is reads only from the stored region. + bli_mksymm( &c ); + bli_mktrim( &c ); + + // Save C and set its structure and uplo properties. + bli_obj_set_struc( BLIS_SYMMETRIC, &c_save ); + bli_obj_set_uplo( uploc, &c_save ); + bli_copym( &c, &c_save ); + bli_mksymm( &c_save ); + bli_mktrim( &c_save ); + + // Apply the remaining parameters. + bli_copym( &a, &aa ); + bli_copym( &b, &bb ); + + bli_obj_set_conjtrans( trans, &a ); + bli_obj_set_conjtrans( trans, &b ); + + bli_obj_set_conjtrans( trans, &aa ); + bli_obj_set_conjtrans( trans, &bb ); + + libblis_api_syr2k(params, iface, &alpha, &aa, &bb, &beta, &c, datatype ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &r ); + + resid = libblis_test_bitrp_syr2k( params, iface, &alpha, &a, &b, + &beta, &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_syr2k(params, &alpha, &a, &b, &beta, + &c, &c_save, datatype ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &c, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &b ); + libblis_test_obj_free( &bb ); + libblis_test_obj_free( &c ); + libblis_test_obj_free( &c_save ); + + return abs(resid); +} + +void libblis_test_syr2k_impl + ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c + ) +{ + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_syr2k( alpha, a, b, beta, c ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_syr2k_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ) +{ + num_t dt = bli_obj_dt( c ); + num_t dt_real = bli_obj_dt_proj_to_real( c ); + + dim_t m = bli_obj_length( c ); + dim_t k = bli_obj_width_after_trans( a ); + + obj_t at, bt; + obj_t norm; + obj_t t, v, w1, w2, z; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is randomized. + // - b is randomized. + // - c_orig is randomized and symmetric. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * transa(A) * transb(B)^T + alpha * transb(B) * transa(A)^T + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // z = ( beta * C_orig + alpha * transa(A) * transb(B)^T + alpha * transb(B) * transa(A)^T ) * t + // = beta * C_orig * t + alpha * transa(A) * transb(B)^T * t + alpha * transb(B) * transa(A)^T * t + // = beta * C_orig * t + alpha * transa(A) * transb(B)^T * t + alpha * transb(B) * w2 + // = beta * C_orig * t + alpha * transa(A) * w1 + alpha * transb(B) * w2 + // = beta * C_orig * t + alpha * transa(A) * w1 + z + // = beta * C_orig * t + z + // + + bli_obj_alias_with_trans( BLIS_TRANSPOSE, a, &at ); + bli_obj_alias_with_trans( BLIS_TRANSPOSE, b, &bt ); + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, k, 1, 0, 0, &w1 ); + bli_obj_create( dt, k, 1, 0, 0, &w2 ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_symv( &BLIS_ONE, c, &t, &BLIS_ZERO, &v ); + + bli_gemv( &BLIS_ONE, &at, &t, &BLIS_ZERO, &w2 ); + bli_gemv( &BLIS_ONE, &bt, &t, &BLIS_ZERO, &w1 ); + bli_gemv( alpha, a, &w1, &BLIS_ZERO, &z ); + bli_gemv( alpha, b, &w2, &BLIS_ONE, &z ); + bli_symv( beta, c_orig, &t, &BLIS_ONE, &z ); + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w1 ); + bli_obj_free( &w2 ); + bli_obj_free( &z ); + + return resid; +} + diff --git a/gtestsuite/src/test_syr2k.h b/gtestsuite/src/test_syr2k.h new file mode 100644 index 000000000..eb32e953a --- /dev/null +++ b/gtestsuite/src/test_syr2k.h @@ -0,0 +1,19 @@ +#ifndef TEST_SYR2K_H +#define TEST_SYR2K_H + +#include "blis_test.h" + +double libblis_test_isyr2k_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ); + +double libblis_check_nan_syr2k(obj_t* c, num_t dt ); + +#endif /* TEST_SYR2K_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_syrk.cpp b/gtestsuite/src/test_syrk.cpp new file mode 100644 index 000000000..613271278 --- /dev/null +++ b/gtestsuite/src/test_syrk.cpp @@ -0,0 +1,504 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_syrk.h" + +void libblis_test_syrk_impl ( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c +); + +double libblis_test_syrk_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig +); + +double cblas_syrk( + uplo_t uploc, + trans_t transa, + f77_int n, + f77_int k, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_TRANSPOSE cblas_trans; + enum CBLAS_UPLO cblas_uplo; + + if ( bli_obj_row_stride( c ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_upper( uploc ) ) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + if( bli_is_trans( transa ) ) + cblas_trans = CblasTrans; + else + cblas_trans = CblasNoTrans; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + cblas_ssyrk( cblas_order, cblas_uplo, cblas_trans, n, k, + *alphap, ap, lda, *betap, cp, ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + cblas_dsyrk( cblas_order, cblas_uplo, cblas_trans, n, k, + *alphap, ap, lda, *betap, cp, ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + cblas_csyrk( cblas_order, cblas_uplo, cblas_trans, n, k, + alphap, ap, lda, betap, cp, ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + cblas_zsyrk( cblas_order, cblas_uplo, cblas_trans, n, k, + alphap, ap, lda, betap, cp, ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_syrk( + uplo_t uploc, + f77_char f77_transa, + f77_int n, + f77_int k, + obj_t* alpha, + obj_t* a, + f77_int lda, + obj_t* beta, + obj_t* c, + f77_int ldc, + num_t dt +){ + f77_char f77_uploc; + + bli_param_map_blis_to_netlib_uplo( uploc, &f77_uploc ); + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* betap = (float*) bli_obj_buffer( beta ); + float* cp = (float*) bli_obj_buffer( c ); + ssyrk_( &f77_uploc, &f77_transa, &n, &k, alphap, ap, (f77_int*)&lda, + betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* betap = (double*) bli_obj_buffer( beta ); + double* cp = (double*) bli_obj_buffer( c ); + dsyrk_( &f77_uploc, &f77_transa, &n, &k, alphap, ap, + (f77_int*)&lda, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* betap = (scomplex*) bli_obj_buffer( beta ); + scomplex* cp = (scomplex*) bli_obj_buffer( c ); + csyrk_( &f77_uploc, &f77_transa, &n, &k, alphap, ap, + (f77_int*)&lda, betap, cp, (f77_int*)&ldc ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* betap = (dcomplex*) bli_obj_buffer( beta ); + dcomplex* cp = (dcomplex*) bli_obj_buffer( c ); + zsyrk_( &f77_uploc, &f77_transa, &n, &k, alphap, ap, + (f77_int*)&lda, betap, cp, (f77_int*)&ldc ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_syrk( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + num_t dt +){ + + if(params->api == API_BLIS) { + libblis_test_syrk_impl( iface, alpha, a, beta, c ); + } + else { /*CLBAS || BLAS */ + f77_int m = bli_obj_length( c ); + f77_int k = bli_obj_width_after_trans( a ); + uplo_t uploc = bli_obj_uplo( c ); + trans_t transa = bli_obj_onlytrans_status( a ); + f77_int lda, ldc; + + if( bli_obj_is_col_stored( c ) ) { + lda = bli_obj_col_stride( a ); + ldc = bli_obj_col_stride( c ); + } else { + lda = bli_obj_row_stride( a ); + ldc = bli_obj_row_stride( c ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldc = ldc + params->ld[2]; + } + + if(params->api == API_CBLAS) { + cblas_syrk(uploc, transa, m, k, alpha, a, lda, beta, c, ldc, dt); + } + else { /**/ + f77_char f77_transa; + if(bli_obj_is_col_stored( c )) { + if(transa == BLIS_TRANSPOSE) f77_transa='T'; + else if ( transa == BLIS_CONJ_TRANSPOSE ) f77_transa='N'; + else /*if ( transa == BLIS_NO_TRANSPOSE )*/ f77_transa='N'; + + blas_syrk(uploc, f77_transa, m, k, alpha, a, lda, + beta, c, ldc, dt); + } + else { + if(transa == BLIS_TRANSPOSE) f77_transa='N'; + else if ( transa == BLIS_CONJ_TRANSPOSE ) f77_transa='N'; + else /*if ( transa == BLIS_NO_TRANSPOSE )*/ f77_transa='T'; + + if( uploc == BLIS_UPPER) + uploc = BLIS_LOWER; + else if(uploc == BLIS_LOWER) + uploc = BLIS_UPPER; + + blas_syrk(uploc, f77_transa, m, k, alpha, a, lda, + beta, c, ldc, dt); + } + } + } + return ; +} + +double libblis_ref_syrk( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + num_t dt +){ + double resid = 0.0; +// double *betap = (double *)bli_obj_buffer( beta ); + + if (params->nanf) { + resid = libblis_check_nan_syrk(c, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_syrk_check( params, alpha, a, beta, c, c_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_isyrk_check( params, alpha, a, beta, c, c_orig); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_syrk( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_syrk_impl( iface, alpha, a, beta, r ); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_syrk ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +){ + num_t datatype; + dim_t m, k; + uplo_t uploc; + trans_t transa; + obj_t alpha, a, beta, c; + obj_t c_save; + double resid = 0.0; + obj_t aa; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + k = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploc ); + bli_param_map_char_to_syrk_trans( pc_str[1], &transa ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], m, k, &a ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], m, k, &aa ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &c_save ); + + // Set the structure and uplo properties of C. + bli_obj_set_struc( BLIS_SYMMETRIC, &c ); + bli_obj_set_uplo( uploc, &c ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &c ) ) { + bli_setsc(alpv.real, 0.0, &alpha); + bli_setsc(betv.real, 0.0, &beta); + } + else { + // For syrk, both alpha and beta may be complex since, unlike herk, + // C is symmetric in both the real and complex cases. + bli_setsc(alpv.real, (alpv.real/0.8), &alpha); + bli_setsc(betv.real, (betv.real/1.2), &beta); + } + // Randomize A. + libblis_test_mobj_randomize( params, TRUE, &a ); + + libblis_test_mobj_randomize( params, TRUE, &c ); + } + else { + int32_t x = (int32_t)alpv.real; + int32_t y = (int32_t)betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + // For syrk, both alpha and beta may be complex since, unlike herk, + // C is symmetric in both the real and complex cases. + int32_t ac = (int32_t)(x/0.8); + int32_t bc = (int32_t)(y/1.0); + bli_setsc( (double)x, (double)ac, &alpha ); + bli_setsc( (double)y, (double)bc, &beta ); + } + // Randomize A. + libblis_test_mobj_irandomize( params, &a ); + + libblis_test_mobj_irandomize( params, &c ); + } + + bli_mksymm( &c ); + bli_mktrim( &c ); + + // Save C and set its structure and uplo properties. + bli_obj_set_struc( BLIS_SYMMETRIC, &c_save ); + bli_obj_set_uplo( uploc, &c_save ); + bli_copym( &c, &c_save ); + + bli_mksymm( &c_save ); + bli_mktrim( &c_save ); + + bli_copym( &a, &aa ); + + // Apply the remaining parameters. + bli_obj_set_conjtrans( transa, &a ); + + bli_obj_set_conjtrans( transa, &aa ); + + libblis_api_syrk(params, iface, &alpha, &aa, &beta, &c, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &r ); + resid = libblis_test_bitrp_syrk( params, iface, &alpha, &a, &beta, + &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_syrk(params, &alpha, &a, &beta, &c, &c_save, datatype); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &c, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &c ); + libblis_test_obj_free( &c_save ); + + return abs(resid); +} + +void libblis_test_syrk_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c +) { + + switch ( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_syrk( alpha, a, beta, c ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_syrk_check ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig +){ + num_t dt = bli_obj_dt( c ); + num_t dt_real = bli_obj_dt_proj_to_real( c ); + + dim_t m = bli_obj_length( c ); + dim_t k = bli_obj_width_after_trans( a ); + + obj_t at; + obj_t norm; + obj_t t, v, w, z; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - a is randomized. + // - c_orig is randomized and symmetric. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * transa(A) * transa(A)^T + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // z = ( beta * C_orig + alpha * transa(A) * transa(A)^T ) * t + // = beta * C_orig * t + alpha * transa(A) * transa(A)^T * t + // = beta * C_orig * t + alpha * transa(A) * w + // = beta * C_orig * t + z + // + + bli_obj_alias_with_trans( BLIS_TRANSPOSE, a, &at ); + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, k, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_symv( &BLIS_ONE, c, &t, &BLIS_ZERO, &v ); + + bli_gemv( &BLIS_ONE, &at, &t, &BLIS_ZERO, &w ); + bli_gemv( alpha, a, &w, &BLIS_ZERO, &z ); + bli_symv( beta, c_orig, &t, &BLIS_ONE, &z ); + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + bli_obj_free( &z ); + + return resid; +} diff --git a/gtestsuite/src/test_syrk.h b/gtestsuite/src/test_syrk.h new file mode 100644 index 000000000..cce2c8cf2 --- /dev/null +++ b/gtestsuite/src/test_syrk.h @@ -0,0 +1,18 @@ +#ifndef TEST_SYRK_H +#define TEST_SYRK_H + +#include "blis_test.h" + +double libblis_test_isyrk_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ); + +double libblis_check_nan_syrk(obj_t* b, num_t dt ); + +#endif /* TEST_SYRK_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_trmm.cpp b/gtestsuite/src/test_trmm.cpp new file mode 100644 index 000000000..95d528003 --- /dev/null +++ b/gtestsuite/src/test_trmm.cpp @@ -0,0 +1,551 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trmm.h" + +// Local prototypes. +void libblis_test_trmm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_trmm_impl ( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b +); + +double libblis_test_trmm_check ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig +); + +double cblas_trmm( + f77_int mm, + f77_int nn, + f77_int lda, + f77_int ldb, + obj_t* a, + obj_t* b, + obj_t* alpha, + uplo_t uploa, + side_t side, + diag_t diaga, + trans_t transa, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uplo; + enum CBLAS_SIDE cblas_side; + enum CBLAS_DIAG cblas_diag; + enum CBLAS_TRANSPOSE cblas_transa; + + if ( bli_obj_row_stride( b ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_trans( transa ) ) + cblas_transa = CblasTrans; + else if( bli_is_conjtrans( transa ) ) + cblas_transa = CblasConjTrans; + else + cblas_transa = CblasNoTrans; + + if(bli_is_upper(uploa)) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + if(bli_is_left(side)) + cblas_side = CblasLeft; + else + cblas_side = CblasRight; + + if(bli_is_unit_diag(diaga)) + cblas_diag = CblasUnit; + else + cblas_diag = CblasNonUnit; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + cblas_strmm( cblas_order, cblas_side, cblas_uplo, cblas_transa, + cblas_diag, mm, nn, *alphap, ap, lda, bp, ldb ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + cblas_dtrmm( cblas_order, cblas_side, cblas_uplo, cblas_transa, + cblas_diag, mm, nn, *alphap, ap, lda, bp, ldb ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + cblas_ctrmm( cblas_order, cblas_side, cblas_uplo, cblas_transa, + cblas_diag, mm, nn, alphap, ap, lda, bp, ldb ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + cblas_ztrmm( cblas_order, cblas_side, cblas_uplo, cblas_transa, + cblas_diag, mm, nn, alphap, ap, lda, bp, ldb ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_trmm( + f77_int mm, + f77_int nn, + f77_int lda, + f77_int ldb, + obj_t* a, + obj_t* b, + obj_t* alpha, + uplo_t uploa, + side_t side, + diag_t diaga, + trans_t transa, + num_t dt +){ + f77_char f77_side; + f77_char f77_uploa; + f77_char f77_transa; + f77_char f77_diaga; + + bli_param_map_blis_to_netlib_side( side, &f77_side ); + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + bli_param_map_blis_to_netlib_trans( transa, &f77_transa ); + bli_param_map_blis_to_netlib_diag( diaga, &f77_diaga ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + strmm_( &f77_side, &f77_uploa, &f77_transa, &f77_diaga, + &mm, &nn, alphap, ap, &lda, bp, &ldb ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + dtrmm_( &f77_side, &f77_uploa, &f77_transa, &f77_diaga, + &mm, &nn, alphap, ap, &lda, bp, &ldb ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + ctrmm_( &f77_side, &f77_uploa, &f77_transa, &f77_diaga, + &mm, &nn, alphap, ap, &lda, bp, &ldb ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + ztrmm_( &f77_side, &f77_uploa, &f77_transa, &f77_diaga, + &mm, &nn, alphap, ap, &lda, bp, &ldb ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_trmm( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + num_t dt +) { + if(params->api == API_BLIS) { + libblis_test_trmm_impl( iface, side, alpha, a, b ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + trans_t transa = bli_obj_conjtrans_status( a ); + diag_t diaga = bli_obj_diag( a ); + f77_int mm = bli_obj_length( b ); + f77_int nn = bli_obj_width( b ); + f77_int lda, ldb; + + if ( bli_obj_row_stride( a ) == 1 ) + lda = bli_obj_col_stride( a ); + else + lda = bli_obj_row_stride( a ); + + if ( bli_obj_row_stride( b ) == 1 ) + ldb = bli_obj_col_stride( b ); + else + ldb = bli_obj_row_stride( b ); + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldb = ldb + params->ld[1]; + } + + if(bli_obj_has_notrans(a) && bli_obj_has_conj(a)) { + conjugate_tensor(a, dt); + transa = bli_obj_onlytrans_status( a ); + } + + if(params->api == API_CBLAS) { + cblas_trmm(mm, nn, lda, ldb, a, b, alpha, + uploa, side, diaga, transa, dt); + } else { /**/ + if( bli_obj_row_stride( a ) == 1 ) { + blas_trmm(mm, nn, lda, ldb, a, b, alpha, + uploa, side, diaga, transa, dt); + } + else { + if( side == BLIS_LEFT) + side = BLIS_RIGHT; + else if(side == BLIS_RIGHT) + side = BLIS_LEFT; + + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + blas_trmm(nn, mm, lda, ldb, a, b, alpha, + uploa, side, diaga, transa, dt); + } + } + } + return ; +} + +double libblis_ref_trmm( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig, + num_t dt +){ + + double resid = 0.0; + + if (params->nanf) { + resid = libblis_check_nan_trmm(b, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_trmm_check(params, side, alpha, a, b, b_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_itrmm_check(params, side, alpha, a, b, b_orig, dt); + } + else { + resid = libblis_test_matrix_check(params, b); + } + } + return resid; +} + +double libblis_test_bitrp_trmm( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( b_orig, r ); + libblis_test_trmm_impl( iface, side, alpha, a, r ); + resid = libblis_test_bitrp_matrix(b, r, dt); + } + return resid; +} + +double libblis_test_op_trmm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +) { + num_t datatype; + dim_t m, n; + dim_t mn_side; + side_t side; + uplo_t uploa; + trans_t transa; + diag_t diaga; + obj_t alpha, a, b; + obj_t b_save; + double resid = 0.0; + obj_t aa; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_side( pc_str[0], &side ); + bli_param_map_char_to_blis_uplo( pc_str[1], &uploa ); + bli_param_map_char_to_blis_diag( pc_str[3], &diaga ); + + if(params->api == API_BLIS) { + bli_param_map_char_to_blis_trans( pc_str[2], &transa ); + } else { + bli_param_map_char_to_blas_trans( pc_str[2], &transa ); + } + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + bli_set_dim_with_side( side, m, n, &mn_side ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], mn_side, mn_side, &a ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], mn_side, mn_side, &aa ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &b ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &b_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_TRIANGULAR, &a ); + bli_obj_set_uplo( uploa, &a ); + + bli_obj_set_struc( BLIS_TRIANGULAR, &aa ); + bli_obj_set_uplo( uploa, &aa ); + + // Set alpha. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &b ) ) + bli_setsc( alpv.real, 0.0, &alpha ); + else + bli_setsc( alpv.real, 0.0, &alpha ); + + // Randomize A, load the diagonal, make it densely triangular. + libblis_test_mobj_randomize( params, TRUE, &a ); + + // Randomize B and save B. + libblis_test_mobj_randomize( params, TRUE, &b ); + } + else { + int32_t x = (int32_t)alpv.real; + if ( bli_obj_is_real( &b ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + } + else { + int32_t ac = (int32_t)(x/0.8); + bli_setsc( (double)x, (double)ac, &alpha ); + } + + // Randomize A, load the diagonal, make it densely triangular + libblis_test_mobj_irandomize( params, &a ); + + // Randomize B and save B. + libblis_test_mobj_irandomize( params, &b ); + } + + if (params->nanf) { + test_fillbuffmem( &b, datatype ); + test_fillbuffmem_diag( &b, datatype ); + } + + bli_mktrim( &a ); + + //Copy b to b_save + bli_copym( &a, &aa ); + bli_copym( &b, &b_save ); + + // Apply the remaining parameters. + bli_obj_set_conjtrans( transa, &a ); + bli_obj_set_diag( diaga, &a ); + + bli_obj_set_conjtrans( transa, &aa ); + bli_obj_set_diag( diaga, &aa ); + + libblis_api_trmm(params, iface, side, &alpha, &aa, &b, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + resid = libblis_test_bitrp_trmm(params, iface, side, &alpha, &a, + &b, &b_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_trmm(params, side, &alpha, &a, &b, &b_save, datatype); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &b, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &b ); + libblis_test_obj_free( &b_save ); + + return abs(resid); +} + +void libblis_test_trmm_impl( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b +) { + switch( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_trmm( side, alpha, a, b ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_trmm_check ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig +) { + num_t dt = bli_obj_dt( b ); + num_t dt_real = bli_obj_dt_proj_to_real( b ); + + dim_t m = bli_obj_length( b ); + dim_t n = bli_obj_width( b ); + + obj_t norm; + obj_t t, v, w, z; + + double junk; + double resid = 0.0; + + // Pre-conditions: + // - a is randomized and triangular. + // - b_orig is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // B := alpha * transa(A) * B_orig (side = left) + // B := alpha * B_orig * transa(A) (side = right) + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = B * t + // + // z = ( alpha * transa(A) * B ) * t (side = left) + // = alpha * transa(A) * B * t + // = alpha * transa(A) * w + // + // z = ( alpha * B * transa(A) ) * t (side = right) + // = alpha * B * transa(A) * t + // = alpha * B * w + + bli_obj_scalar_init_detached( dt_real, &norm ); + + if ( bli_is_left( side ) ) + { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, m, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + else // else if ( bli_is_left( side ) ) + { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, n, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, b, &t, &BLIS_ZERO, &v ); + + if ( bli_is_left( side ) ) + { + bli_gemv( &BLIS_ONE, b_orig, &t, &BLIS_ZERO, &w ); + bli_trmv( alpha, a, &w ); + bli_copyv( &w, &z ); + } + else + { + bli_copyv( &t, &w ); + bli_trmv( &BLIS_ONE, a, &w ); + bli_gemv( alpha, b_orig, &w, &BLIS_ZERO, &z ); + } + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + bli_obj_free( &z ); + + return resid; +} diff --git a/gtestsuite/src/test_trmm.h b/gtestsuite/src/test_trmm.h new file mode 100644 index 000000000..07847fe1a --- /dev/null +++ b/gtestsuite/src/test_trmm.h @@ -0,0 +1,20 @@ +#ifndef TEST_TRMM_H +#define TEST_TRMM_H + +#include "blis_test.h" + +double libblis_test_itrmm_check + ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig, + num_t dt + ); + +double libblis_check_nan_trmm(obj_t* b, num_t dt ); + + +#endif /* TEST_TRMM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_trmm3.cpp b/gtestsuite/src/test_trmm3.cpp new file mode 100644 index 000000000..81eaac964 --- /dev/null +++ b/gtestsuite/src/test_trmm3.cpp @@ -0,0 +1,358 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trmm3.h" + +using namespace std; + +// Local prototypes. +void libblis_test_trmm3_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_trmm3_impl( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +); + +double libblis_test_trmm3_check( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +); + +void libblis_api_trmm3( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +) +{ + libblis_test_trmm3_impl( iface, side, alpha, a, b, beta, c ); + return ; +} + +double libblis_ref_trmm3( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_save, + num_t dt +) { + + double resid = 0.0; + double *betap = (double *)bli_obj_buffer( beta ); + + if ((params->nanf) && (*betap == 0)) { + resid = libblis_check_nan_trmm3(c, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_trmm3_check( params, side, alpha, a, b, beta, c, c_save ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_itrmm3_check( params, side, alpha, a, b, beta, c, c_save ); + } + else { + resid = libblis_test_matrix_check(params, c); + } + } + return resid; +} + +double libblis_test_bitrp_trmm3( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( c_orig, r ); + libblis_test_trmm3_impl( iface, side, alpha, a, b, beta, r ); + resid = libblis_test_bitrp_matrix(c, r, dt); + } + return resid; +} + +double libblis_test_op_trmm3 ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv, + atom_t betv +) { + num_t datatype; + dim_t m, n; + dim_t mn_side; + side_t side; + uplo_t uploa; + trans_t transa, transb; + diag_t diaga; + obj_t alpha, a, b, beta, c; + obj_t c_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_side ( pc_str[0], &side ); + bli_param_map_char_to_blis_uplo ( pc_str[1], &uploa ); + bli_param_map_char_to_blis_trans( pc_str[2], &transa ); + bli_param_map_char_to_blis_diag ( pc_str[3], &diaga ); + bli_param_map_char_to_blis_trans( pc_str[4], &transb ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + bli_set_dim_with_side( side, m, n, &mn_side ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], mn_side, mn_side, &a ); + libblis_test_mobj_create( params, datatype, transb, + sc_str[2], m, n, &b ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &c ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &c_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_TRIANGULAR, &a ); + bli_obj_set_uplo( uploa, &a ); + + // Set alpha and beta. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &c ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + bli_setsc( betv.real, 0.0, &beta ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + bli_setsc( betv.real, (betv.real/1.2), &beta ); + } + // Randomize A, B, and C, and save C. + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_mobj_randomize( params, TRUE, &b ); + libblis_test_mobj_randomize( params, TRUE, &c ); + } + else { + int32_t x = alpv.real; + int32_t y = betv.real; + if ( bli_obj_is_real( &c ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + bli_setsc( (double)y, 0.0, &beta ); + } + else { + int32_t ac = (int32_t)(x/0.8); + int32_t bc = (int32_t)(y/1.0); + bli_setsc( (double)x, (double)ac, &alpha ); + bli_setsc( (double)y, (double)bc, &beta ); + } + libblis_test_mobj_irandomize( params, &a ); + libblis_test_mobj_irandomize( params, &b ); + libblis_test_mobj_irandomize( params, &c ); + } + + if ((params->nanf) && (betv.real == 0) ) { + test_fillbuffmem(&c, datatype ); + } + + // Randomize A, make it densely triangular. + bli_mktrim( &a ); + + bli_obj_set_conjtrans( transa, &a ); + bli_obj_set_diag( diaga, &a ); + bli_obj_set_conjtrans( transb, &b ); + + //Copy c to c_save + bli_copym( &c, &c_save ); + + libblis_api_trmm3(params, iface, side, &alpha, &a, &b, &beta, &c ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + resid = libblis_test_bitrp_trmm3( params, iface, side,&alpha, &a, &b, + &beta, &c, &c_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_trmm3(params, side, &alpha, &a, &b, &beta, + &c, &c_save, datatype ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &c, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &b ); + libblis_test_obj_free( &c ); + libblis_test_obj_free( &c_save ); + + return abs(resid); +} + +void libblis_test_trmm3_impl ( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c +) +{ + switch( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_trmm3( side, alpha, a, b, beta, c ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_trmm3_check ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig +) +{ + num_t dt = bli_obj_dt( c ); + num_t dt_real = bli_obj_dt_proj_to_real( c ); + + dim_t m = bli_obj_length( c ); + dim_t n = bli_obj_width( c ); + + obj_t norm; + obj_t t, v, w, z; + + double junk; + double resid = 0.0; + + // Pre-conditions: + // - a is randomized and triangular. + // - b is randomized. + // - c_orig is randomized. + // Note: + // - alpha and beta should have non-zero imaginary components in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // C := beta * C_orig + alpha * transa(A) * transb(B) (side = left) + // C := beta * C_orig + alpha * transb(B) * transa(A) (side = right) + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = C * t + // + // z = ( beta * C_orig + alpha * transa(A) * transb(B) ) * t (side = left) + // = beta * C_orig * t + alpha * transa(A) * transb(B) * t + // = beta * C_orig * t + alpha * transa(A) * w + // = beta * C_orig * t + z + // + // z = ( beta * C_orig + alpha * transb(B) * transa(A) ) * t (side = right) + // = beta * C_orig * t + alpha * transb(B) * transa(A) * t + // = beta * C_orig * t + alpha * transb(B) * w + // = beta * C_orig * t + z + + bli_obj_scalar_init_detached( dt_real, &norm ); + + if ( bli_is_left( side ) ) + { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, m, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + else // else if ( bli_is_left( side ) ) + { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, n, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, c, &t, &BLIS_ZERO, &v ); + + if ( bli_is_left( side ) ) + { + bli_gemv( &BLIS_ONE, b, &t, &BLIS_ZERO, &w ); + bli_trmv( alpha, a, &w ); + bli_copyv( &w, &z ); + } + else + { + bli_copyv( &t, &w ); + bli_trmv( &BLIS_ONE, a, &w ); + bli_gemv( alpha, b, &w, &BLIS_ZERO, &z ); + } + + bli_gemv( beta, c_orig, &t, &BLIS_ONE, &z ); + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + bli_obj_free( &z ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_trmm3.h b/gtestsuite/src/test_trmm3.h new file mode 100644 index 000000000..1467586fb --- /dev/null +++ b/gtestsuite/src/test_trmm3.h @@ -0,0 +1,20 @@ +#ifndef TEST_TRMM3_H +#define TEST_TRMM3_H + +#include "blis_test.h" + +double libblis_test_itrmm3_check + ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* beta, + obj_t* c, + obj_t* c_orig + ); + +double libblis_check_nan_trmm3(obj_t* c, num_t dt ); + +#endif /* TEST_TRMM3_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_trmv.cpp b/gtestsuite/src/test_trmv.cpp new file mode 100644 index 000000000..0f5a518ae --- /dev/null +++ b/gtestsuite/src/test_trmv.cpp @@ -0,0 +1,500 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trmv.h" + +// Local prototypes. +void libblis_test_trmv_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_trmv_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x +); + +double libblis_test_trmv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig +); + +void libblis_trmv_alphax( + obj_t* alpha, + f77_int m, + obj_t* x, + f77_int incx, + num_t dt +){ + int i, ix = 0; + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* xp = (float*) bli_obj_buffer( x ); + for(i = 0 ; i < m ; i++) { + xp[ix] = (*Alpha * xp[ix]); + ix = ix + incx; + } + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* xp = (double*) bli_obj_buffer( x ); + for(i = 0 ; i < m ; i++) { + xp[ix] = (*Alpha * xp[ix]); + ix = ix + incx; + } + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + for(i = 0 ; i < m ; i++) { + xp[ix] = mulc(*Alpha , xp[ix]); + ix = ix + incx; + } + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + for(i = 0 ; i < m ; i++) { + xp[ix] = mulc(*Alpha , xp[ix]); + ix = ix + incx; + } + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void cblas_trmv( + uplo_t uploa, + trans_t transa, + diag_t diaga, + f77_int m, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + num_t dt +){ + enum CBLAS_ORDER cblas_order = CblasColMajor; + enum CBLAS_UPLO cblas_uploa; + enum CBLAS_DIAG cblas_diaga; + enum CBLAS_TRANSPOSE cblas_transa; + + if(bli_is_upper(uploa)) + cblas_uploa = CblasUpper; + else + cblas_uploa = CblasLower; + + if( bli_is_trans( transa ) ) + cblas_transa = CblasTrans; + else if( bli_is_conjtrans( transa ) ) + cblas_transa = CblasConjTrans; + else + cblas_transa = CblasNoTrans; + + if(bli_is_unit_diag(diaga)) + cblas_diaga = CblasUnit; + else + cblas_diaga = CblasNonUnit; + + switch( dt ) { + case BLIS_FLOAT : + { + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + cblas_strmv(cblas_order, cblas_uploa, cblas_transa, cblas_diaga, + m, ap, lda, xp, incx ); + break; + } + case BLIS_DOUBLE : + { + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + cblas_dtrmv(cblas_order, cblas_uploa, cblas_transa, cblas_diaga, + m, ap, lda, xp, incx ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cblas_ctrmv(cblas_order, cblas_uploa, cblas_transa, cblas_diaga, + m, ap, lda, xp, incx ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + cblas_ztrmv(cblas_order, cblas_uploa, cblas_transa, cblas_diaga, + m, ap, lda, xp, incx ); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_trmv( + uplo_t uploa, + trans_t transa, + diag_t diaga, + f77_int m, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + num_t dt +){ + f77_char f77_uploa; + f77_char f77_transa; + f77_char f77_diaga; + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + bli_param_map_blis_to_netlib_trans( transa, &f77_transa ); + bli_param_map_blis_to_netlib_diag( diaga, &f77_diaga ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + strmv_(&f77_uploa, &f77_transa, &f77_diaga, &m, ap, (f77_int*)&lda, xp, &incx); + break; + } + case BLIS_DOUBLE : + { + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + dtrmv_(&f77_uploa, &f77_transa, &f77_diaga, &m, ap, (f77_int*)&lda, xp, &incx); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + ctrmv_(&f77_uploa, &f77_transa, &f77_diaga, &m, ap, (f77_int*)&lda, xp, &incx); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + ztrmv_(&f77_uploa, &f77_transa, &f77_diaga, &m, ap, (f77_int*)&lda, xp, &incx); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_trmv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + num_t dt +){ + + if(params->api == API_BLIS) { + libblis_test_trmv_impl( iface, alpha, a, x ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + trans_t transa = bli_obj_conjtrans_status( a ); + diag_t diaga = bli_obj_diag( a ); + f77_int mm = bli_obj_length( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + libblis_trmv_alphax(alpha, mm, x, incx, dt); + + if(bli_obj_has_notrans(a) && bli_obj_has_conj(a)) { + conjugate_tensor(a, dt); + transa = bli_obj_onlytrans_status( a ); + } + + if(params->api == API_CBLAS) { + cblas_trmv(uploa, transa, diaga, mm, a, lda, x, incx, dt ); + } + else { /**/ + if ( bli_obj_row_stride( a ) == 1 ){ + blas_trmv(uploa, transa, diaga, mm, a, lda, x, incx, dt ); + } + else { + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + blas_trmv(uploa, transa, diaga, mm, a, lda, x, incx, dt ); + } + } + } + return ; +} + +double libblis_ref_trmv( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_trmv_check( params, alpha, a, x, x_orig ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_itrmv_check( params, alpha, a, x, x_orig ); + } + else { + resid = libblis_test_vector_check(params, x); + } + } + return resid; +} + +double libblis_test_bitrp_trmv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( x_orig, r ); + libblis_test_trmv_impl( iface, alpha, a, r); + resid = libblis_test_bitrp_vector(x, r, dt); + } + return resid; +} + +double libblis_test_op_trmv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + uplo_t uploa; + trans_t transa; + diag_t diaga; + obj_t alpha, a, x; + obj_t x_save; + double resid = 0.0; + obj_t aa; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploa ); + bli_param_map_char_to_blis_trans( pc_str[1], &transa ); + bli_param_map_char_to_blis_diag( pc_str[2], &diaga ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &aa ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &x_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_TRIANGULAR, &a ); + bli_obj_set_uplo( uploa, &a ); + + bli_obj_set_struc( BLIS_TRIANGULAR, &aa ); + bli_obj_set_uplo( uploa, &aa ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &x ) ) + bli_setsc( -1.0, 0.0, &alpha ); + else + bli_setsc( -0.5, 0.5, &alpha ); + + // Randomize A, make it densely triangular. + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_vobj_randomize( params, TRUE, &x ); + } + else{ + if ( bli_obj_is_real( &x ) ) + bli_setsc( -1.0, 0.0, &alpha ); + else + bli_setsc( 1.0, -1.5, &alpha ); + + // Randomize A, make it densely triangular. + libblis_test_mobj_irandomize( params, &a ); + libblis_test_vobj_irandomize( params, &x ); + } + + bli_mktrim( &a ); + bli_copyv( &x, &x_save ); + + bli_copym( &a, &aa ); + + // Apply the remaining parameters. + bli_obj_set_conjtrans( transa, &a ); + bli_obj_set_diag( diaga, &a ); + + bli_obj_set_conjtrans( transa, &aa ); + bli_obj_set_diag( diaga, &aa ); + + libblis_api_trmv(params, iface, &alpha, &aa, &x, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[1], m, &r ); + + resid = libblis_test_bitrp_trmv( params, iface, &alpha, &a, &x, + &x_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_trmv( params, &alpha, &a, &x, &x_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &x ); + libblis_test_obj_free( &x_save ); + + return abs(resid); +} + +void libblis_test_trmv_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_trmv( alpha, a, x ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_trmv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig +){ + num_t dt = bli_obj_dt( x ); + num_t dt_real = bli_obj_dt_proj_to_real( x ); + + dim_t m = bli_obj_vector_dim( x ); + + uplo_t uploa = bli_obj_uplo( a ); + trans_t transa = bli_obj_conjtrans_status( a ); + + obj_t a_local, y; + obj_t norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is randomized and triangular. + // - x is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // x := alpha * transa(A) * x_orig + // + // is functioning correctly if + // + // normfv( y - x ) + // + // is negligible, where + // + // y = alpha * conja(A_dense) * x_orig + // + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &y ); + bli_obj_create( dt, m, m, 0, 0, &a_local ); + + bli_obj_set_struc( BLIS_TRIANGULAR, &a_local ); + bli_obj_set_uplo( uploa, &a_local ); + bli_obj_toggle_uplo_if_trans( transa, &a_local ); + bli_copym( a, &a_local ); + bli_mktrim( &a_local ); + + bli_obj_set_struc( BLIS_GENERAL, &a_local ); + bli_obj_set_uplo( BLIS_DENSE, &a_local ); + + bli_gemv( alpha, &a_local, x_orig, &BLIS_ZERO, &y ); + + bli_subv( x, &y ); + bli_normfv( &y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &y ); + bli_obj_free( &a_local ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_trmv.h b/gtestsuite/src/test_trmv.h new file mode 100644 index 000000000..9319880ac --- /dev/null +++ b/gtestsuite/src/test_trmv.h @@ -0,0 +1,17 @@ +#ifndef TEST_TRMV_H +#define TEST_TRMV_H + +#include "blis_test.h" + +double libblis_test_itrmv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig + ); + +double libblis_check_nan_trmv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_TRMV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_trsm.cpp b/gtestsuite/src/test_trsm.cpp new file mode 100644 index 000000000..83ba4f768 --- /dev/null +++ b/gtestsuite/src/test_trsm.cpp @@ -0,0 +1,549 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trsm.h" + +// Local prototypes. +void libblis_test_trsm_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_trsm_impl ( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b +); + +double libblis_test_trsm_check ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig +); + +double cblas_trsm( + f77_int mm, + f77_int nn, + f77_int lda, + f77_int ldb, + obj_t* a, + obj_t* b, + obj_t* alpha, + uplo_t uploa, + side_t side, + diag_t diaga, + trans_t transa, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uplo; + enum CBLAS_SIDE cblas_side; + enum CBLAS_DIAG cblas_diag; + enum CBLAS_TRANSPOSE cblas_transa; + + if ( bli_obj_row_stride( b ) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if( bli_is_trans( transa ) ) + cblas_transa = CblasTrans; + else if( bli_is_conjtrans( transa ) ) + cblas_transa = CblasConjTrans; + else + cblas_transa = CblasNoTrans; + + if(bli_is_upper(uploa)) + cblas_uplo = CblasUpper; + else + cblas_uplo = CblasLower; + + if(bli_is_left(side)) + cblas_side = CblasLeft; + else + cblas_side = CblasRight; + + if(bli_is_unit_diag(diaga)) + cblas_diag = CblasUnit; + else + cblas_diag = CblasNonUnit; + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + cblas_strsm( cblas_order, cblas_side, cblas_uplo, cblas_transa, + cblas_diag, mm, nn, *alphap, ap, lda, bp, ldb ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + cblas_dtrsm( cblas_order, cblas_side, cblas_uplo, cblas_transa, + cblas_diag, mm, nn, *alphap, ap, lda, bp, ldb ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + cblas_ctrsm( cblas_order, cblas_side, cblas_uplo, cblas_transa, + cblas_diag, mm, nn, alphap, ap, lda, bp, ldb ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + cblas_ztrsm( cblas_order, cblas_side, cblas_uplo, cblas_transa, + cblas_diag, mm, nn, alphap, ap, lda, bp, ldb ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +double blas_trsm( + f77_int mm, + f77_int nn, + f77_int lda, + f77_int ldb, + obj_t* a, + obj_t* b, + obj_t* alpha, + uplo_t uploa, + side_t side, + diag_t diaga, + trans_t transa, + num_t dt +){ + f77_char f77_side; + f77_char f77_uploa; + f77_char f77_transa; + f77_char f77_diaga; + + bli_param_map_blis_to_netlib_side( side, &f77_side ); + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + bli_param_map_blis_to_netlib_trans( transa, &f77_transa ); + bli_param_map_blis_to_netlib_diag( diaga, &f77_diaga ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* alphap = (float*) bli_obj_buffer( alpha ); + float* ap = (float*) bli_obj_buffer( a ); + float* bp = (float*) bli_obj_buffer( b ); + strsm_( &f77_side, &f77_uploa, &f77_transa, &f77_diaga, + &mm, &nn, alphap, ap, &lda, bp, &ldb ); + break; + } + case BLIS_DOUBLE : + { + double* alphap = (double*) bli_obj_buffer( alpha ); + double* ap = (double*) bli_obj_buffer( a ); + double* bp = (double*) bli_obj_buffer( b ); + dtrsm_( &f77_side, &f77_uploa, &f77_transa, &f77_diaga, + &mm, &nn, alphap, ap, &lda, bp, &ldb ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* alphap = (scomplex*) bli_obj_buffer( alpha ); + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* bp = (scomplex*) bli_obj_buffer( b ); + ctrsm_( &f77_side, &f77_uploa, &f77_transa, &f77_diaga, + &mm, &nn, alphap, ap, &lda, bp, &ldb ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* alphap = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* bp = (dcomplex*) bli_obj_buffer( b ); + ztrsm_( &f77_side, &f77_uploa, &f77_transa, &f77_diaga, + &mm, &nn, alphap, ap, &lda, bp, &ldb ); + break; + } + default : + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } + return 0; +} + +void libblis_api_trsm( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + num_t dt +) { + if(params->api == API_BLIS) { + libblis_test_trsm_impl( iface, side, alpha, a, b ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + trans_t transa = bli_obj_conjtrans_status( a ); + diag_t diaga = bli_obj_diag( a ); + f77_int mm = bli_obj_length( b ); + f77_int nn = bli_obj_width( b ); + f77_int lda, ldb; + + if ( bli_obj_row_stride( a ) == 1 ) + lda = bli_obj_col_stride( a ); + else + lda = bli_obj_row_stride( a ); + + if ( bli_obj_row_stride( b ) == 1 ) + ldb = bli_obj_col_stride( b ); + else + ldb = bli_obj_row_stride( b ); + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + ldb = ldb + params->ld[1]; + } + + if(bli_obj_has_notrans(a) && bli_obj_has_conj(a)) { + conjugate_tensor(a, dt); + transa = bli_obj_onlytrans_status( a ); + } + + if(params->api == API_CBLAS) { + cblas_trsm(mm, nn, lda, ldb, a, b, alpha, + uploa, side, diaga, transa, dt); + } else { /**/ + if( bli_obj_row_stride( a ) == 1 ) { + blas_trsm(mm, nn, lda, ldb, a, b, alpha, + uploa, side, diaga, transa, dt); + } + else { + if( side == BLIS_LEFT) + side = BLIS_RIGHT; + else if(side == BLIS_RIGHT) + side = BLIS_LEFT; + + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + + blas_trsm(nn, mm, lda, ldb, a, b, alpha, + uploa, side, diaga, transa, dt); + } + } + } + return ; +} + +double libblis_ref_trsm( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig, + num_t dt +){ + + double resid = 0.0; + + if (params->nanf) { + resid = libblis_check_nan_trsm(b, dt ); + } + else if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_trsm_check(params, side, alpha, a, b, b_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_itrsm_check(params, side, alpha, a, b, b_orig, dt); + } + else { + resid = libblis_test_matrix_check(params, b); + } + } + return resid; +} + +double libblis_test_bitrp_trsm( + test_params_t* params, + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( b_orig, r ); + libblis_test_trsm_impl( iface, side, alpha, a, r ); + resid = libblis_test_bitrp_matrix(b, r, dt); + } + return resid; +} + +double libblis_test_op_trsm ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +) { + num_t datatype; + dim_t m, n; + dim_t mn_side; + side_t side; + uplo_t uploa; + trans_t transa; + diag_t diaga; + obj_t alpha, a, b; + obj_t b_save; + double resid = 0.0; + obj_t aa; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_side( pc_str[0], &side ); + bli_param_map_char_to_blis_uplo( pc_str[1], &uploa ); + bli_param_map_char_to_blis_diag( pc_str[3], &diaga ); + + if(params->api == API_BLIS) { + bli_param_map_char_to_blis_trans( pc_str[2], &transa ); + } else { + bli_param_map_char_to_blas_trans( pc_str[2], &transa ); + } + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + bli_set_dim_with_side( side, m, n, &mn_side ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], mn_side, mn_side, &a ); + libblis_test_mobj_create( params, datatype, transa, + sc_str[1], mn_side, mn_side, &aa ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &b ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &b_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_TRIANGULAR, &a ); + bli_obj_set_uplo( uploa, &a ); + + bli_obj_set_struc( BLIS_TRIANGULAR, &aa ); + bli_obj_set_uplo( uploa, &aa ); + + // Set alpha. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &b ) ) + bli_setsc( alpv.real, 0.0, &alpha ); + else + bli_setsc( alpv.real, 0.0, &alpha ); + + // Randomize A, load the diagonal, make it densely triangular. + libblis_test_mobj_randomize( params, TRUE, &a ); + + // Randomize B and save B. + libblis_test_mobj_randomize( params, TRUE, &b ); + } + else { + int32_t x = (int32_t)alpv.real; + if ( bli_obj_is_real( &b ) ) { + bli_setsc( (double)x, 0.0, &alpha ); + } + else { + int32_t ac = (int32_t)(x/0.8); + bli_setsc( (double)x, (double)ac, &alpha ); + } + + // Randomize A, load the diagonal, make it densely triangular. + libblis_test_mobj_irandomize( params, &a ); + + // Randomize B and save B. + libblis_test_mobj_irandomize( params, &b ); + } + + if (params->nanf) { + test_fillbuffmem( &b, datatype ); + test_fillbuffmem_diag( &b, datatype ); + } + + libblis_test_mobj_load_diag( params, &a ); + bli_mktrim( &a ); + + //Copy b to b_save + bli_copym( &a, &aa ); + bli_copym( &b, &b_save ); + + // Apply the remaining parameters. + bli_obj_set_conjtrans( transa, &a ); + bli_obj_set_diag( diaga, &a ); + + bli_obj_set_conjtrans( transa, &aa ); + bli_obj_set_diag( diaga, &aa ); + + libblis_api_trsm(params, iface, side, &alpha, &aa, &b, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + resid = libblis_test_bitrp_trsm(params, iface, side, &alpha, &a, + &b, &b_save, &r, datatype); + bli_obj_free( &r ); + } + else { + resid = libblis_ref_trsm(params, side, &alpha, &a, &b, &b_save, datatype); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &b, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &b ); + libblis_test_obj_free( &b_save ); + + return resid; +} + +void libblis_test_trsm_impl( + iface_t iface, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b +) +{ + switch( iface ) { + case BLIS_TEST_SEQ_FRONT_END: + bli_trsm( side, alpha, a, b ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_trsm_check ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig +) { + num_t dt = bli_obj_dt( b ); + num_t dt_real = bli_obj_dt_proj_to_real( b ); + + dim_t m = bli_obj_length( b ); + dim_t n = bli_obj_width( b ); + + obj_t norm; + obj_t t, v, w, z; + + double junk; + double resid = 0.0; + // + // Pre-conditions: + // - a is randomized and triangular. + // - b_orig is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // B := alpha * inv(transa(A)) * B_orig (side = left) + // B := alpha * B_orig * inv(transa(A)) (side = right) + // + // is functioning correctly if + // + // normfv( v - z ) + // + // is negligible, where + // + // v = B * t + // + // z = ( alpha * inv(transa(A)) * B ) * t (side = left) + // = alpha * inv(transa(A)) * B * t + // = alpha * inv(transa(A)) * w + // + // z = ( alpha * B * inv(transa(A)) ) * t (side = right) + // = alpha * B * tinv(ransa(A)) * t + // = alpha * B * w + + bli_obj_scalar_init_detached( dt_real, &norm ); + + if ( bli_is_left( side ) ) { + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, m, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + else { // else if ( bli_is_left( side ) ) + bli_obj_create( dt, n, 1, 0, 0, &t ); + bli_obj_create( dt, m, 1, 0, 0, &v ); + bli_obj_create( dt, n, 1, 0, 0, &w ); + bli_obj_create( dt, m, 1, 0, 0, &z ); + } + + libblis_test_vobj_randomize( params, TRUE, &t ); + + bli_gemv( &BLIS_ONE, b, &t, &BLIS_ZERO, &v ); + + if ( bli_is_left( side ) ) { + bli_gemv( alpha, b_orig, &t, &BLIS_ZERO, &w ); + bli_trsv( &BLIS_ONE, a, &w ); + bli_copyv( &w, &z ); + } + else { + bli_copyv( &t, &w ); + bli_trsv( &BLIS_ONE, a, &w ); + bli_gemv( alpha, b_orig, &w, &BLIS_ZERO, &z ); + } + + bli_subv( &z, &v ); + bli_normfv( &v, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &t ); + bli_obj_free( &v ); + bli_obj_free( &w ); + bli_obj_free( &z ); + + return resid; +} diff --git a/gtestsuite/src/test_trsm.h b/gtestsuite/src/test_trsm.h new file mode 100644 index 000000000..5da828a0d --- /dev/null +++ b/gtestsuite/src/test_trsm.h @@ -0,0 +1,20 @@ +#ifndef TEST_TRSM_H +#define TEST_TRSM_H + +#include "blis_test.h" + +double libblis_test_itrsm_check + ( + test_params_t* params, + side_t side, + obj_t* alpha, + obj_t* a, + obj_t* b, + obj_t* b_orig, + num_t dt + ); + +double libblis_check_nan_trsm(obj_t* b, num_t dt ); + + +#endif /* TEST_TRSM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_trsv.cpp b/gtestsuite/src/test_trsv.cpp new file mode 100644 index 000000000..aea316038 --- /dev/null +++ b/gtestsuite/src/test_trsv.cpp @@ -0,0 +1,529 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_trsv.h" + +// Local prototypes. +void libblis_test_trsv_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_trsv_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x +); + +double libblis_test_trsv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig +); + +void libblis_alphax( + obj_t* alpha, + f77_int m, + obj_t* x, + f77_int incx, + num_t dt +){ + int i, ix = 0; + switch( dt ) { + case BLIS_FLOAT : + { + float* Alpha = (float*) bli_obj_buffer( alpha ); + float* xp = (float*) bli_obj_buffer( x ); + for(i = 0 ; i < m ; i++) { + xp[ix] = (*Alpha * xp[ix]); + ix = ix + incx; + } + break; + } + case BLIS_DOUBLE : + { + double* Alpha = (double*) bli_obj_buffer( alpha ); + double* xp = (double*) bli_obj_buffer( x ); + for(i = 0 ; i < m ; i++) { + xp[ix] = (*Alpha * xp[ix]); + ix = ix + incx; + } + break; + } + case BLIS_SCOMPLEX : + { + scomplex* Alpha = (scomplex*) bli_obj_buffer( alpha ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + for(i = 0 ; i < m ; i++) { + xp[ix] = mulc(*Alpha , xp[ix]); + ix = ix + incx; + } + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* Alpha = (dcomplex*) bli_obj_buffer( alpha ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + for(i = 0 ; i < m ; i++) { + xp[ix] = mulc(*Alpha , xp[ix]); + ix = ix + incx; + } + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void cblas_trsv( + uplo_t uploa, + trans_t transa, + diag_t diaga, + f77_int m, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + num_t dt +){ + enum CBLAS_ORDER cblas_order; + enum CBLAS_UPLO cblas_uploa; + enum CBLAS_DIAG cblas_diaga; + enum CBLAS_TRANSPOSE cblas_transa; + + if(bli_obj_row_stride(a) == 1 ) + cblas_order = CblasColMajor; + else + cblas_order = CblasRowMajor; + + if(bli_is_upper(uploa)) + cblas_uploa = CblasUpper; + else + cblas_uploa = CblasLower; + + if( bli_is_trans( transa ) ) + cblas_transa = CblasTrans; + else if( bli_is_conjtrans( transa ) ) + cblas_transa = CblasConjTrans; + else + cblas_transa = CblasNoTrans; + + if(bli_is_unit_diag(diaga)) + cblas_diaga = CblasUnit; + else + cblas_diaga = CblasNonUnit; + + switch( dt ) { + case BLIS_FLOAT : + { + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + cblas_strsv(cblas_order, cblas_uploa, cblas_transa, cblas_diaga, + m, ap, lda, xp, incx ); + break; + } + case BLIS_DOUBLE : + { + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + cblas_dtrsv(cblas_order, cblas_uploa, cblas_transa, cblas_diaga, + m, ap, lda, xp, incx ); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + cblas_ctrsv(cblas_order, cblas_uploa, cblas_transa, cblas_diaga, + m, ap, lda, xp, incx ); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + cblas_ztrsv(cblas_order, cblas_uploa, cblas_transa, cblas_diaga, + m, ap, lda, xp, incx ); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void blas_trsv( + uplo_t uploa, + trans_t transa, + diag_t diaga, + f77_int m, + obj_t* a, + f77_int lda, + obj_t* x, + f77_int incx, + num_t dt +){ + f77_char f77_uploa; + f77_char f77_transa; + f77_char f77_diaga; + trans_t trans; + + if( bli_obj_row_stride( a ) == 1 ){ + if ( transa == BLIS_TRANSPOSE ) trans = BLIS_TRANSPOSE; + else if ( transa == BLIS_CONJ_TRANSPOSE ) trans = BLIS_CONJ_TRANSPOSE; + else /*if(transa == BLIS_NO_TRANSPOSE)*/ trans = BLIS_NO_TRANSPOSE; + } + else { + if( uploa == BLIS_UPPER) + uploa = BLIS_LOWER; + else if(uploa == BLIS_LOWER) + uploa = BLIS_UPPER; + if(transa == BLIS_NO_TRANSPOSE) trans = BLIS_TRANSPOSE; + else if(transa == BLIS_TRANSPOSE) trans = BLIS_NO_TRANSPOSE; + else /*if ( transa == BLIS_CONJ_TRANSPOSE)*/ trans = BLIS_NO_TRANSPOSE; + } + + bli_param_map_blis_to_netlib_uplo( uploa, &f77_uploa ); + bli_param_map_blis_to_netlib_trans( trans, &f77_transa ); + bli_param_map_blis_to_netlib_diag( diaga, &f77_diaga ); + + switch( dt ) { + case BLIS_FLOAT : + { + float* ap = (float*) bli_obj_buffer( a ); + float* xp = (float*) bli_obj_buffer( x ); + strsv_(&f77_uploa, &f77_transa, &f77_diaga, &m, ap, (f77_int*)&lda, xp, &incx); + break; + } + case BLIS_DOUBLE : + { + double* ap = (double*) bli_obj_buffer( a ); + double* xp = (double*) bli_obj_buffer( x ); + dtrsv_(&f77_uploa, &f77_transa, &f77_diaga, &m, ap, (f77_int*)&lda, xp, &incx); + break; + } + case BLIS_SCOMPLEX : + { + scomplex* ap = (scomplex*) bli_obj_buffer( a ); + scomplex* xp = (scomplex*) bli_obj_buffer( x ); + ctrsv_(&f77_uploa, &f77_transa, &f77_diaga, &m, ap, (f77_int*)&lda, xp, &incx); + break; + } + case BLIS_DCOMPLEX : + { + dcomplex* ap = (dcomplex*) bli_obj_buffer( a ); + dcomplex* xp = (dcomplex*) bli_obj_buffer( x ); + ztrsv_(&f77_uploa, &f77_transa, &f77_diaga, &m, ap, (f77_int*)&lda, xp, &incx); + break; + } + default: + bli_check_error_code( BLIS_INVALID_DATATYPE ); + } +} + +void libblis_api_trsv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + num_t dt +){ + + if(params->api == API_BLIS) { + libblis_test_trsv_impl( iface, alpha, a, x ); + } + else { /*CLBAS || BLAS */ + uplo_t uploa = bli_obj_uplo( a ); + trans_t transa = bli_obj_conjtrans_status( a ); + diag_t diaga = bli_obj_diag( a ); + f77_int mm = bli_obj_length( a ); + f77_int incx = bli_obj_vector_inc( x ); + f77_int lda ; + + if ( bli_obj_row_stride( a ) == 1 ) { + lda = bli_obj_col_stride( a ); + } else { + lda = bli_obj_row_stride( a ); + } + + if(params->ldf == 1) { + lda = lda + params->ld[0]; + } + + libblis_alphax(alpha, mm, x, incx, dt); + + if(bli_obj_has_notrans(a) && bli_obj_has_conj(a)) { + conjugate_tensor(a, dt); + transa = bli_obj_onlytrans_status( a ); + } + + if(params->api == API_CBLAS) { + cblas_trsv(uploa, transa, diaga, mm, a, lda, x, incx, dt ); + } + else { /**/ + if ( bli_obj_row_stride( a ) == 1 ){ + blas_trsv(uploa, transa, diaga, mm, a, lda, x, incx, dt ); + } + else { + blas_trsv(uploa, transa, diaga, mm, a, lda, x, incx, dt ); + } + } + } + return ; +} + +double libblis_ref_trsv( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + resid = libblis_test_trsv_check( params, alpha, a, x, x_orig); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_itrsv_check( params, alpha, a, x, x_orig); + } + else { + resid = libblis_test_vector_check(params, x); + } + } + return resid; +} + +double libblis_test_bitrp_trsv( + test_params_t* params, + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( x_orig, r ); + libblis_test_trsv_impl( iface, alpha, a, x ); + resid = libblis_test_bitrp_vector(x, r, dt); + } + return resid; +} + +double libblis_test_op_trsv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpv +){ + num_t datatype; + dim_t m; + uplo_t uploa; + trans_t transa; + diag_t diaga; + obj_t alpha, a, x; + obj_t x_save; + double resid = 0.0; + obj_t aa; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to an actual dimension. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_uplo( pc_str[0], &uploa ); + bli_param_map_char_to_blis_trans( pc_str[1], &transa ); + bli_param_map_char_to_blis_diag( pc_str[2], &diaga ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &alpha ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &a ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, m, &aa ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &x ); + libblis_test_vobj_create( params, datatype, + sc_str[1], m, &x_save ); + + // Set the structure and uplo properties of A. + bli_obj_set_struc( BLIS_TRIANGULAR, &a ); + bli_obj_set_uplo( uploa, &a ); + + bli_obj_set_struc( BLIS_TRIANGULAR, &aa ); + bli_obj_set_uplo( uploa, &aa ); + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + if ( bli_obj_is_real( &x ) ) { + bli_setsc( alpv.real, 0.0, &alpha ); + } + else { + bli_setsc( alpv.real, (alpv.real/0.8), &alpha ); + } + // Randomize A, make it densely triangular. + libblis_test_mobj_randomize( params, TRUE, &a ); + libblis_test_vobj_randomize( params, TRUE, &x ); + } + else{ + int32_t xx = (int32_t)alpv.real; + if ( bli_obj_is_real( &x ) ) { + bli_setsc( (double)xx, 0.0, &alpha ); + } + else { + int32_t ac = (int32_t)(xx/0.8); + bli_setsc( (double)xx, (double)ac, &alpha ); + } + // Randomize A, make it densely triangular. + libblis_test_mobj_irandomize( params, &a ); + libblis_test_vobj_irandomize( params, &x ); + } + + // Randomize A, load the diagonal, make it densely triangular. + libblis_test_mobj_load_diag( params, &a ); + bli_mktrim( &a ); + bli_copyv( &x, &x_save ); + + bli_copym( &a, &aa ); + + // Apply the remaining parameters. + bli_obj_set_conjtrans( transa, &a ); + bli_obj_set_diag( diaga, &a ); + + bli_obj_set_conjtrans( transa, &aa ); + bli_obj_set_diag( diaga, &aa ); + + libblis_api_trsv(params, iface, &alpha, &aa, &x, datatype); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[1], m, &r ); + + resid = libblis_test_bitrp_trsv( params, iface, &alpha, &a, &x, + &x_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_trsv( params, &alpha, &a, &x, &x_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &x, &resid ); + + // Free the test objects. + libblis_test_obj_free( &a ); + libblis_test_obj_free( &aa ); + libblis_test_obj_free( &x ); + libblis_test_obj_free( &x_save ); + + return resid; +} + +void libblis_test_trsv_impl( + iface_t iface, + obj_t* alpha, + obj_t* a, + obj_t* x +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_trsv( alpha, a, x ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_trsv_check( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig +){ + num_t dt = bli_obj_dt( x ); + num_t dt_real = bli_obj_dt_proj_to_real( x ); + + dim_t m = bli_obj_vector_dim( x ); + + uplo_t uploa = bli_obj_uplo( a ); + trans_t transa = bli_obj_conjtrans_status( a ); + + obj_t alpha_inv; + obj_t a_local, y; + obj_t norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - a is randomized and triangular. + // - x is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the + // complex cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // x := alpha * inv(transa(A)) * x_orig + // + // is functioning correctly if + // + // normfv( y - x_orig ) + // + // is negligible, where + // + // y = inv(alpha) * transa(A_dense) * x + // + + bli_obj_scalar_init_detached( dt, &alpha_inv ); + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_copysc( &BLIS_ONE, &alpha_inv ); + bli_divsc( alpha, &alpha_inv ); + + bli_obj_create( dt, m, 1, 0, 0, &y ); + bli_obj_create( dt, m, m, 0, 0, &a_local ); + + bli_obj_set_struc( BLIS_TRIANGULAR, &a_local ); + bli_obj_set_uplo( uploa, &a_local ); + bli_obj_toggle_uplo_if_trans( transa, &a_local ); + bli_copym( a, &a_local ); + bli_mktrim( &a_local ); + + bli_obj_set_struc( BLIS_GENERAL, &a_local ); + bli_obj_set_uplo( BLIS_DENSE, &a_local ); + + bli_gemv( &alpha_inv, &a_local, x, &BLIS_ZERO, &y ); + + bli_subv( x_orig, &y ); + bli_normfv( &y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &y ); + bli_obj_free( &a_local ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_trsv.h b/gtestsuite/src/test_trsv.h new file mode 100644 index 000000000..8e8a4b765 --- /dev/null +++ b/gtestsuite/src/test_trsv.h @@ -0,0 +1,17 @@ +#ifndef TEST_TRSV_H +#define TEST_TRSV_H + +#include "blis_test.h" + +double libblis_test_itrsv_check + ( + test_params_t* params, + obj_t* alpha, + obj_t* a, + obj_t* x, + obj_t* x_orig + ); + +double libblis_check_nan_trsv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_TRMV_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_xpbym.cpp b/gtestsuite/src/test_xpbym.cpp new file mode 100644 index 000000000..fd2b939cc --- /dev/null +++ b/gtestsuite/src/test_xpbym.cpp @@ -0,0 +1,227 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_xpbym.h" + +// Local prototypes. +void libblis_test_xpbym_deps( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_xpbym_impl( + iface_t iface, + obj_t* x, + obj_t* beta, + obj_t* y +); + +double libblis_test_xpbym_check( + test_params_t* params, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_save +); + +double libblis_ref_xpbym( + test_params_t* params, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_xpbym_check( params, x, beta, y, y_orig ); + } + else { + resid = libblis_test_ixpbym_check( params, x, beta, y, y_orig ); + } + return resid; +} + +double libblis_test_bitrp_xpbym( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copym( y_orig, r ); + libblis_test_xpbym_impl( iface, x, beta, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_xpbym ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha +){ + num_t datatype; + dim_t m, n; + trans_t transx; + obj_t x, beta, y; + obj_t y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + n = dim->n; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_trans( pc_str[0], &transx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_mobj_create( params, datatype, transx, + sc_str[0], m, n, &x ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &y ); + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &y_save ); + + // Set beta. + if ( bli_obj_is_real( &y ) ) + bli_setsc( -2.0, 0.0, &beta ); + else + bli_setsc( 0.0, -2.0, &beta ); + + // Randomize and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_mobj_randomize( params, FALSE, &x ); + libblis_test_mobj_randomize( params, FALSE, &y ); + } else { + libblis_test_mobj_irandomize( params, &x ); + libblis_test_mobj_irandomize( params, &y ); + } + bli_copym( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conjtrans( transx, &x ); + + libblis_test_xpbym_impl( iface, &x, &beta, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_mobj_create( params, datatype, BLIS_NO_TRANSPOSE, + sc_str[0], m, n, &r ); + + resid = libblis_test_bitrp_xpbym(params, iface, &x, &beta, &y, + &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_xpbym( params, &x, &beta, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output matrix is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_xpbym_impl( + iface_t iface, + obj_t* x, + obj_t* beta, + obj_t* y +){ + switch ( iface ){ + case BLIS_TEST_SEQ_FRONT_END: + bli_xpbym( x, beta, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_xpbym_check( + test_params_t* params, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +){ + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_length( y ); + dim_t n = bli_obj_width( y ); + + obj_t x_temp, y_temp; + obj_t norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - y_orig is randomized. + // Note: + // - alpha should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := beta * y_orig + conjx(x) + // + // is functioning correctly if + // + // normfm( y - ( beta * y_orig + conjx(x) ) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, n, 0, 0, &x_temp ); + bli_obj_create( dt, m, n, 0, 0, &y_temp ); + + bli_copym( x, &x_temp ); + bli_copym( y_orig, &y_temp ); + + bli_scalm( beta, &y_temp ); + bli_addm( &x_temp, &y_temp ); + + bli_subm( &y_temp, y ); + bli_normfm( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + bli_obj_free( &y_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_xpbym.h b/gtestsuite/src/test_xpbym.h new file mode 100644 index 000000000..76301d978 --- /dev/null +++ b/gtestsuite/src/test_xpbym.h @@ -0,0 +1,17 @@ +#ifndef TEST_XPBYM_H +#define TEST_XPBYM_H + +#include "blis_test.h" + +double libblis_test_ixpbym_check + ( + test_params_t* params, + obj_t* x, + obj_t* alpha, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_xpbym( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_XPBYM_H */ \ No newline at end of file diff --git a/gtestsuite/src/test_xpbyv.cpp b/gtestsuite/src/test_xpbyv.cpp new file mode 100644 index 000000000..13fd5d9bb --- /dev/null +++ b/gtestsuite/src/test_xpbyv.cpp @@ -0,0 +1,228 @@ +#include "blis_test.h" +#include "blis_utils.h" +#include "test_xpbyv.h" + +// Local prototypes. +void libblis_test_xpbyv_deps ( + thread_data_t* tdata, + test_params_t* params, + test_op_t* op +); + +void libblis_test_xpbyv_impl ( + iface_t iface, + obj_t* x, + obj_t* beta, + obj_t* y +); + +double libblis_test_xpbyv_check ( + test_params_t* params, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +); + +double libblis_ref_xpbyv( + test_params_t* params, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_save +) { + double resid = 0.0; + + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + // Perform checks. + resid = libblis_test_xpbyv_check( params, x, beta, y, y_save ); + } + else { + if(params->oruflw == BLIS_DEFAULT) { + resid = libblis_test_ixpbyv_check( params, x, beta, y, y_save ); + } + else { + resid = libblis_test_vector_check(params, x); + } + } + return resid; +} + +double libblis_test_bitrp_xpbyv( + test_params_t* params, + iface_t iface, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig, + obj_t* r, + num_t dt +) { + double resid = 0.0; + unsigned int n_repeats = params->n_repeats; + unsigned int i; + + for(i = 0; i < n_repeats; i++) { + bli_copyv( y_orig, r ); + libblis_test_xpbyv_impl( iface, x, beta, r ); + resid = libblis_test_bitrp_vector(y, r, dt); + } + return resid; +} + +double libblis_test_op_xpbyv ( + test_params_t* params, + iface_t iface, + char* dc_str, + char* pc_str, + char* sc_str, + tensor_t* dim, + atom_t alpha +){ + num_t datatype; + dim_t m; + conj_t conjx; + obj_t beta, x, y; + obj_t y_save; + double resid = 0.0; + + // Use the datatype of the first char in the datatype combination string. + bli_param_map_char_to_blis_dt( dc_str[0], &datatype ); + + // Map the dimension specifier to actual dimensions. + m = dim->m; + + // Map parameter characters to BLIS constants. + bli_param_map_char_to_blis_conj( pc_str[0], &conjx ); + + // Create test scalars. + bli_obj_scalar_init_detached( datatype, &beta ); + + // Create test operands (vectors and/or matrices). + libblis_test_vobj_create( params, datatype, sc_str[0], m, &x ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y ); + libblis_test_vobj_create( params, datatype, sc_str[1], m, &y_save ); + + // Set beta. + if ( bli_obj_is_real( &y ) ) + bli_setsc( -2.0, 0.0, &beta ); + else + bli_setsc( 0.0, -2.0, &beta ); + + // Randomize x and y, and save y. + if((params->bitextf == 0) && (params->oruflw == BLIS_DEFAULT)) { + libblis_test_vobj_randomize( params, FALSE, &x ); + libblis_test_vobj_randomize( params, FALSE, &y ); + } else { + libblis_test_vobj_irandomize( params, &x ); + libblis_test_vobj_irandomize( params, &y ); + } + + bli_copyv( &y, &y_save ); + + // Apply the parameters. + bli_obj_set_conj( conjx, &x ); + + libblis_test_xpbyv_impl( iface, &x, &beta, &y ); + +#ifndef __GTEST_VALGRIND_TEST__ + if(params->bitrp) { + obj_t r; + + libblis_test_vobj_create( params, datatype, sc_str[1], m, &r ); + + resid = libblis_test_bitrp_xpbyv(params, iface, &x, &beta, &y, + &y_save, &r, datatype); + + bli_obj_free( &r ); + } + else { + resid = libblis_ref_xpbyv( params, &x, &beta, &y, &y_save ); + } +#endif + + // Zero out performance and residual if output vector is empty. + libblis_test_check_empty_problem( &y, &resid ); + + // Free the test objects. + libblis_test_obj_free( &x ); + libblis_test_obj_free( &y ); + libblis_test_obj_free( &y_save ); + + return abs(resid); +} + +void libblis_test_xpbyv_impl ( + iface_t iface, + obj_t* x, + obj_t* beta, + obj_t* y +) { + switch ( iface ) + { + case BLIS_TEST_SEQ_FRONT_END: + bli_xpbyv( x, beta, y ); + break; + + default: + libblis_test_printf_error( "Invalid interface type.\n" ); + } +} + +double libblis_test_xpbyv_check ( + test_params_t* params, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig +) { + num_t dt = bli_obj_dt( y ); + num_t dt_real = bli_obj_dt_proj_to_real( y ); + + dim_t m = bli_obj_vector_dim( y ); + + obj_t x_temp, y_temp; + obj_t norm; + + double junk; + double resid = 0.0; + + // + // Pre-conditions: + // - x is randomized. + // - y_orig is randomized. + // Note: + // - beta should have a non-zero imaginary component in the complex + // cases in order to more fully exercise the implementation. + // + // Under these conditions, we assume that the implementation for + // + // y := beta * y_orig + conjx(x) + // + // is functioning correctly if + // + // normfv( y - ( beta * y_orig + conjx(x) ) ) + // + // is negligible. + // + + bli_obj_scalar_init_detached( dt_real, &norm ); + + bli_obj_create( dt, m, 1, 0, 0, &x_temp ); + bli_obj_create( dt, m, 1, 0, 0, &y_temp ); + + bli_copyv( x, &x_temp ); + bli_copyv( y_orig, &y_temp ); + + bli_scalv( beta, &y_temp ); + bli_addv( &x_temp, &y_temp ); + + bli_subv( &y_temp, y ); + bli_normfv( y, &norm ); + bli_getsc( &norm, &resid, &junk ); + + bli_obj_free( &x_temp ); + bli_obj_free( &y_temp ); + + return resid; +} \ No newline at end of file diff --git a/gtestsuite/src/test_xpbyv.h b/gtestsuite/src/test_xpbyv.h new file mode 100644 index 000000000..f51b8c423 --- /dev/null +++ b/gtestsuite/src/test_xpbyv.h @@ -0,0 +1,17 @@ +#ifndef TEST_XPBYV_H +#define TEST_XPBYV_H + +#include "blis_test.h" + +double libblis_test_ixpbyv_check + ( + test_params_t* params, + obj_t* x, + obj_t* beta, + obj_t* y, + obj_t* y_orig + ); + +double libblis_check_nan_xpbyv( char* sc_str, obj_t* b, num_t dt ); + +#endif /* TEST_XPYV_H */ \ No newline at end of file