pax_global_header00006660000000000000000000000064146262531460014523gustar00rootroot0000000000000052 comment=c16ca65ffacc1fa796c2dfba11ea8120c760e8c5 testsweeper-2024.05.31/000077500000000000000000000000001462625314600144735ustar00rootroot00000000000000testsweeper-2024.05.31/.github/000077500000000000000000000000001462625314600160335ustar00rootroot00000000000000testsweeper-2024.05.31/.github/workflows/000077500000000000000000000000001462625314600200705ustar00rootroot00000000000000testsweeper-2024.05.31/.github/workflows/build.sh000077500000000000000000000007231462625314600215300ustar00rootroot00000000000000#!/bin/bash -x maker=$1 compiler=$2 mydir=$(dirname $0) source ${mydir}/setup_env.sh print "======================================== Build" make -j8 || exit 10 print "======================================== Install" make -j8 install || exit 11 ls -R ${top}/install print "======================================== Verify build" ldd_result=$(ldd test/tester) || exit 12 echo "${ldd_result}" print "======================================== Finished build" exit 0 testsweeper-2024.05.31/.github/workflows/configure.sh000077500000000000000000000015661462625314600224200ustar00rootroot00000000000000#!/bin/bash -x maker=$1 compiler=$2 if [ "${maker}" = "cmake" ]; then rm -rf build mkdir -p build fi mydir=$(dirname $0) source ${mydir}/setup_env.sh print "======================================== Environment" # Show environment variables, excluding functions. (set -o posix; set) print "======================================== Modules" quiet module list -l print "======================================== Setup build" # Note: set all env variables in setup_env.sh, # else build.sh and test.sh won't see them. rm -rf ${top}/install if [ "${maker}" = "make" ]; then make distclean make config prefix=${top}/install \ || exit 10 elif [ "${maker}" = "cmake" ]; then cmake -Dcolor=no \ -DCMAKE_INSTALL_PREFIX=${top}/install \ .. \ || exit 12 fi print "======================================== Finished configure" exit 0 testsweeper-2024.05.31/.github/workflows/main.yml000066400000000000000000000017371462625314600215470ustar00rootroot00000000000000# This is a basic workflow to help you get started with Actions name: CI # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the master branch push: branches: [ master ] pull_request: branches: [ master ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: icl_testsweeper: timeout-minutes: 120 strategy: matrix: maker: [make, cmake] compiler: [gnu, intel] fail-fast: false runs-on: self-hosted steps: - uses: actions/checkout@v3 - name: Configure run: .github/workflows/configure.sh ${{matrix.maker}} ${{matrix.compiler}} - name: Build run: .github/workflows/build.sh ${{matrix.maker}} ${{matrix.compiler}} - name: Test run: .github/workflows/test.sh ${{matrix.maker}} ${{matrix.compiler}} testsweeper-2024.05.31/.github/workflows/setup_env.sh000077500000000000000000000032661462625314600224460ustar00rootroot00000000000000#!/bin/bash #------------------------------------------------------------------------------- # Functions # Suppress echo (-x) output of commands executed with `quiet`. # Useful for sourcing files, loading modules, spack, etc. # set +x, set -x are not echo'd. quiet() { { set +x; } 2> /dev/null; $@; set -x } # `print` is like `echo`, but suppresses output of the command itself. # https://superuser.com/a/1141026 echo_and_restore() { builtin echo "$*" date case "${save_flags}" in (*x*) set -x esac } alias print='{ save_flags="$-"; set +x; } 2> /dev/null; echo_and_restore' #------------------------------------------------------------------------------- quiet source /etc/profile hostname && pwd export top=$(pwd) shopt -s expand_aliases quiet module load python quiet which python quiet which python3 python --version python3 --version quiet module load pkgconf quiet which pkg-config export color=no export CXXFLAGS="-Werror -Wno-unused-command-line-argument" #----------------------------------------------------------------- Compiler if [ "${compiler}" = "intel" ]; then print "======================================== Load Intel oneAPI compiler" quiet module load intel-oneapi-compilers else print "======================================== Load GNU compiler" quiet module load gcc@8.5.0 fi print "---------------------------------------- Verify compiler" print "CXX = $CXX" print "CC = $CC" print "FC = $FC" ${CXX} --version ${CC} --version ${FC} --version if [ "${maker}" = "cmake" ]; then print "======================================== Load cmake" quiet module load cmake quiet which cmake cmake --version cd build fi testsweeper-2024.05.31/.github/workflows/test.sh000077500000000000000000000006501462625314600214070ustar00rootroot00000000000000#!/bin/bash -x maker=$1 compiler=$2 mydir=$(dirname $0) source ${mydir}/setup_env.sh # Instead of exiting on the first failed test (bash -e), # run all the tests and accumulate failures into $err. err=0 export OMP_NUM_THREADS=8 print "======================================== Tests" cd test ./run_tests.py (( err += $? )) # todo smoke tests print "======================================== Finished test" exit ${err} testsweeper-2024.05.31/.gitignore000066400000000000000000000004061462625314600164630ustar00rootroot00000000000000__pycache__ .DS_Store .id *.bak *.d *.mod *.o *.pyc *.svg build* config/compiler_cxx config/log.txt config/openmp docs/doxygen/errors.txt docs/html/ files.txt issues/ *.a *.so lib/*.a lib/*.so lib/pkgconfig/*.pc make.inc test/tester test/out testsweeper-* wiki/ testsweeper-2024.05.31/CHANGELOG.md000066400000000000000000000015031462625314600163030ustar00rootroot000000000000002024.05.31 - Added shared library version (ABI version 1.0.0) - Updated enum parameters to have `to_string`, `from_string`; deprecate `2str`, `str2` 2023.11.05 - Improve set_default to reset value - Add half precision 2023.08.25 - Use yyyy.mm.dd version scheme, instead of yyyy.mm.release - Fixes for Intel clang compiler - Bug fixes and more robust testing 2023.06.00 - Add metric (k, M, G), binary (Ki, Mi, Gi), and exponent (1e3) notation for integers - Update string parsing 2023.01.00 - Move repo to GitHub: https://github.com/icl-utk-edu/testsweeper/ - Adjustable column widths - Use python3 2021.04.00 - Add ParamComplex - Fix bug in printing header 2020.09.00 - CMake improvements to use as sub-project 2020.06.00 - Convert repo to git 2020.03.00 - Initial release testsweeper-2024.05.31/CMakeLists.txt000066400000000000000000000200751462625314600172370ustar00rootroot00000000000000# Copyright (c) 2017-2023, University of Tennessee. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause # This program is free software: you can redistribute it and/or modify it under # the terms of the BSD 3-Clause license. See the accompanying LICENSE file. # # CMake script for TestSweeper library. cmake_minimum_required( VERSION 3.15 ) # 3.1 target_compile_features # 3.8 target_compile_features( cxx_std_17 ) # 3.14 install( LIBRARY DESTINATION lib ) default # 3.15 $<$COMPILE_LANG_AND_ID # optional # 3.15 message DEBUG project( testsweeper VERSION 2024.05.31 LANGUAGES CXX ) # See notes in GNUmakefile about using abi-compliance-checker. # soversion is major ABI version. set( abi_version 1.0.0 ) string( REPLACE "." ";" abi_list "${abi_version}" ) list( GET abi_list 0 soversion ) include( CheckCXXCompilerFlag ) # When built as a sub-project, add a namespace to make targets unique, # e.g., `make example` becomes `make testsweeper_example`. if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set( testsweeper_is_project true ) set( testsweeper_ "" ) else() set( testsweeper_is_project false ) set( testsweeper_ "testsweeper_" ) endif() #------------------------------------------------------------------------------- # Options if (testsweeper_is_project) set( log "" CACHE STRING "Shorthand for CMAKE_MESSAGE_LOG_LEVEL" ) set_property( CACHE log PROPERTY STRINGS FATAL_ERROR SEND_ERROR WARNING AUTHOR_WARNING DEPRECATION NOTICE STATUS VERBOSE DEBUG TRACE ) if (log) set( CMAKE_MESSAGE_LOG_LEVEL "${log}" ) endif() endif() option( BUILD_SHARED_LIBS "Build shared libraries" true ) option( build_tests "Build test suite" "${testsweeper_is_project}" ) option( color "Use ANSI color output" true ) option( use_openmp "Use OpenMP, if available" true ) option( testsweeper_install "Add install target" "${testsweeper_is_project}" ) # Default prefix=/opt/slate if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND testsweeper_is_project) set( CMAKE_INSTALL_PREFIX "/opt/slate" CACHE PATH "Install path prefix, prepended onto install directories." FORCE ) message( STATUS "Setting CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}" ) # Append the new CMAKE_INSTALL_PREFIX, since CMake appended the old value. list( APPEND CMAKE_SYSTEM_PREFIX_PATH ${CMAKE_INSTALL_PREFIX} ) else() message( STATUS "Using CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}" ) endif() # Provide menu of options. (Why doesn't CMake do this?) set_property( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS None Debug Release RelWithDebInfo MinSizeRel ) message( DEBUG "Settings: CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX} CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE} BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS} build_tests = ${build_tests} color = ${color} use_openmp = ${use_openmp} testsweeper_install = ${testsweeper_install} testsweeper_is_project = ${testsweeper_is_project} testsweeper_ = ${testsweeper_} abi_version = ${abi_version} soversion = ${soversion} " ) #------------------------------------------------------------------------------- # Enforce out-of-source build string( TOLOWER "${CMAKE_CURRENT_SOURCE_DIR}" source_dir ) string( TOLOWER "${CMAKE_CURRENT_BINARY_DIR}" binary_dir ) if ("${source_dir}" STREQUAL "${binary_dir}") message( FATAL_ERROR "Compiling TestSweeper with CMake requires an out-of-source build. To proceed: rm -rf CMakeCache.txt CMakeFiles/ # delete files in ${CMAKE_CURRENT_SOURCE_DIR} mkdir build cd build cmake .. make" ) endif() #------------------------------------------------------------------------------- # Build library. add_library( testsweeper testsweeper.cc version.cc ) # Include directory. # During build it's {source}; after install it's {prefix}/include. target_include_directories( testsweeper PUBLIC "$" "$" ) # OpenMP support. if (NOT use_openmp) message( STATUS "User has requested to NOT use OpenMP" ) else() find_package( OpenMP ) if (OpenMP_CXX_FOUND) target_link_libraries( testsweeper PUBLIC OpenMP::OpenMP_CXX ) endif() endif() # Get git commit id. if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") execute_process( COMMAND git rev-parse --short HEAD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE testsweeper_id ) string( STRIP "${testsweeper_id}" testsweeper_id ) message( STATUS "testsweeper_id = ${testsweeper_id}" ) target_compile_definitions( testsweeper PRIVATE TESTSWEEPER_ID="${testsweeper_id}" ) endif() # Use and export -std=c++17. # CMake inexplicably allows gnu++17 or "decay" to earlier c++; prohibit those. target_compile_features( testsweeper PUBLIC cxx_std_17 ) set_target_properties( testsweeper PROPERTIES CXX_STANDARD_REQUIRED true # prohibit < c++17 CXX_EXTENSIONS false # prohibit gnu++17 WINDOWS_EXPORT_ALL_SYMBOLS ON VERSION "${abi_version}" SOVERSION "${soversion}" ) if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.15) # Conditionally add -Wall. See CMake tutorial. set( gcc_like_cxx "$" ) target_compile_options( testsweeper PRIVATE "$<${gcc_like_cxx}:$>" ) endif() # Handle NaN correctly with Intel icpx. check_cxx_compiler_flag( "-fp-model=precise" fp_model ) if (fp_model) target_compile_options( testsweeper PUBLIC -fp-model=precise ) endif() # Avoid annoying icpx warning: 'linker' input unused check_cxx_compiler_flag( "-Wno-unused-command-line-argument" warn_unused ) if (warn_unused) target_compile_options( testsweeper PUBLIC -Wno-unused-command-line-argument ) endif() if (NOT color) target_compile_definitions( testsweeper PUBLIC "NO_COLOR" ) endif() #------------------------------------------------------------------------------- if (build_tests) add_subdirectory( test ) endif() #------------------------------------------------------------------------------- # Add 'make lib' target. if (testsweeper_is_project) add_custom_target( lib DEPENDS testsweeper ) endif() #------------------------------------------------------------------------------- # Install rules. # When TestSweeper is used as a sub-project, # the parent (e.g., BLAS++) may not want to install it. if (testsweeper_install) # GNU Filesystem Conventions include( GNUInstallDirs ) if (WIN32) set( install_configdir "testsweeper" ) else() set( install_configdir "${CMAKE_INSTALL_LIBDIR}/cmake/testsweeper" ) endif() # Install library and add to Targets.cmake install( TARGETS testsweeper EXPORT testsweeperTargets LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" ) # Install header files install( FILES "testsweeper.hh" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" ) # Install Targets.cmake install( EXPORT testsweeperTargets DESTINATION "${install_configdir}" ) # Also export Targets.cmake in build directory export( EXPORT testsweeperTargets FILE "testsweeperTargets.cmake" ) # Install Config.cmake and ConfigVersion.cmake, # to enable find_package( ). include( CMakePackageConfigHelpers ) configure_package_config_file( "testsweeperConfig.cmake.in" "testsweeperConfig.cmake" INSTALL_DESTINATION "${install_configdir}" ) write_basic_package_version_file( "testsweeperConfigVersion.cmake" VERSION "${testsweeper_VERSION}" COMPATIBILITY AnyNewerVersion ) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/testsweeperConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/testsweeperConfigVersion.cmake" DESTINATION "${install_configdir}" ) endif() testsweeper-2024.05.31/GNUmakefile000066400000000000000000000224401462625314600165470ustar00rootroot00000000000000# Copyright (c) 2017-2023, University of Tennessee. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause # This program is free software: you can redistribute it and/or modify it under # the terms of the BSD 3-Clause license. See the accompanying LICENSE file. # # See INSTALL.md for usage. #------------------------------------------------------------------------------- # Configuration # Variables defined in make.inc, or use make's defaults: # CXX, CXXFLAGS -- C compiler and flags # LD, LDFLAGS, LIBS -- Linker, options, library paths, and libraries # AR, RANLIB -- Archiver, ranlib updates library TOC # prefix -- where to install TestSweeper # # OpenMP is optional; used only for timer and flushing caches. ifeq (${MAKECMDGOALS},config) # For `make config`, don't include make.inc with previous config; # force re-creating make.inc. .PHONY: config config: make.inc make.inc: force else ifneq (clean,${findstring clean,${MAKECMDGOALS}}) # For `make clean` or `make distclean`, don't include make.inc, # which could generate it. Otherwise, include make.inc. include make.inc endif python ?= python3 force: ; make.inc: ${python} configure.py # Defaults if not given in make.inc. GNU make doesn't have defaults for these. RANLIB ?= ranlib prefix ?= /opt/slate abs_prefix := ${abspath ${prefix}} # Default LD=ld won't work; use CXX. Can override in make.inc or environment. ifeq (${origin LD},default) LD = ${CXX} endif # Use abi-compliance-checker to compare the ABI (application binary # interface) of 2 releases. Changing the ABI does not necessarily change # the API (application programming interface). Rearranging a struct or # changing a by-value argument from int64 to int doesn't change the # API--no source code changes are required, just a recompile. # # if structs or routines are changed or removed: # bump major version and reset minor, revision = 0; # else if structs or routines are added: # bump minor version and reset revision = 0; # else (e.g., bug fixes): # bump revision # # soversion is major ABI version. abi_version = 1.0.0 soversion = ${word 1, ${subst ., ,${abi_version}}} #------------------------------------------------------------------------------- ldflags_shared = -shared # auto-detect OS # $OSTYPE may not be exported from the shell, so echo it ostype := ${shell echo $${OSTYPE}} ifneq (,${findstring darwin, ${ostype}}) # MacOS is darwin macos = 1 # MacOS needs shared library's path set, and shared library version. ldflags_shared += -install_name @rpath/${notdir $@} \ -current_version ${abi_version} \ -compatibility_version ${soversion} so = dylib so2 = .dylib # on macOS, .dylib comes after version: libfoo.4.dylib else # Linux needs shared library's soname. ldflags_shared += -Wl,-soname,${notdir ${lib_soname}} so = so so1 = .so # on Linux, .so comes before version: libfoo.so.4 endif #------------------------------------------------------------------------------- # if shared ifneq (${static},1) CXXFLAGS += -fPIC LDFLAGS += -fPIC lib_ext = ${so} else lib_ext = a endif #------------------------------------------------------------------------------- # Files lib_src = testsweeper.cc version.cc lib_obj = ${addsuffix .o, ${basename ${lib_src}}} dep += ${addsuffix .d, ${basename ${lib_src}}} tester_src = test/test.cc test/test_sort.cc tester_obj = ${addsuffix .o, ${basename ${tester_src}}} dep += ${addsuffix .d, ${basename ${tester_src}}} tester = test/tester #------------------------------------------------------------------------------- # Get Mercurial id, and make version.o depend on it via .id file. ifneq (${wildcard .git},) id := ${shell git rev-parse --short HEAD} version.o: CXXFLAGS += -DTESTSWEEPER_ID='"${id}"' endif last_id := ${shell [ -e .id ] && cat .id || echo 'NA'} ifneq (${id},${last_id}) .id: force endif .id: echo ${id} > .id version.o: .id #------------------------------------------------------------------------------- # TestSweeper specific flags and libraries # additional flags and libraries for testers TEST_CXXFLAGS += -I. TEST_LDFLAGS += -L. -Wl,-rpath,${abspath .} TEST_LIBS += -ltestsweeper ${tester_obj}: CXXFLAGS += ${TEST_CXXFLAGS} #------------------------------------------------------------------------------- # Rules .DELETE_ON_ERROR: .SUFFIXES: .PHONY: all docs hooks lib src test tester headers include clean distclean .DEFAULT_GOAL = all all: lib tester hooks install: lib mkdir -p ${DESTDIR}${abs_prefix}/include mkdir -p ${DESTDIR}${abs_prefix}/lib${LIB_SUFFIX} cp ${headers} ${DESTDIR}${abs_prefix}/include/ cp -av ${lib_name}* ${DESTDIR}${abs_prefix}/lib${LIB_SUFFIX}/ uninstall: ${RM} ${addprefix ${DESTDIR}${abs_prefix}/include/, ${headers}} ${RM} ${DESTDIR}${abs_prefix}/lib${LIB_SUFFIX}/${notdir ${lib_name}.*} #------------------------------------------------------------------------------- # if re-configured, recompile everything ${lib_obj} ${tester_obj}: make.inc #------------------------------------------------------------------------------- # Generic rule for shared libraries. # For libfoo.so version 4.5.6, this creates libfoo.so.4.5.6 and symlinks # libfoo.so.4 -> libfoo.so.4.5.6 # libfoo.so -> libfoo.so.4 # # Needs [private] variables set (shown with example values): # LDFLAGS = -L/path/to/lib # LIBS = -lmylib # lib_obj = src/foo.o src/bar.o # lib_so_abi = libfoo.so.4.5.6 # lib_soname = libfoo.so.4 # abi_version = 4.5.6 # soversion = 4 %.${lib_ext}: ${LD} ${LDFLAGS} ${ldflags_shared} ${LIBS} ${lib_obj} -o ${lib_so_abi} ln -fs ${notdir ${lib_so_abi}} ${lib_soname} ln -fs ${notdir ${lib_soname}} $@ # Generic rule for static libraries, creates libfoo.a. # The library should depend only on its objects. %.a: ${RM} $@ ${AR} cr $@ $^ ${RANLIB} $@ #------------------------------------------------------------------------------- # TestSweeper library # so is like libfoo.so or libfoo.dylib # so_abi is like libfoo.so.4.5.6 or libfoo.4.5.6.dylib # soname is like libfoo.so.4 or libfoo.4.dylib lib_name = libtestsweeper lib_a = ${lib_name}.a lib_so = ${lib_name}.${so} lib = ${lib_name}.${lib_ext} lib_so_abi = ${lib_name}${so1}.${abi_version}${so2} lib_soname = ${lib_name}${so1}.${soversion}${so2} ${lib_so}: ${lib_obj} ${lib_a}: ${lib_obj} lib: ${lib} #------------------------------------------------------------------------------- # tester ${tester}: ${tester_obj} ${lib} ${LD} ${TEST_LDFLAGS} ${LDFLAGS} ${tester_obj} \ ${TEST_LIBS} ${LIBS} -o $@ # sub-directory rules # Note 'test' is sub-directory rule; 'tester' is CMake-compatible rule. test: ${tester} tester: ${tester} check: tester cd test; ${python} run_tests.py #------------------------------------------------------------------------------- # headers # precompile headers to verify self-sufficiency headers = testsweeper.hh headers_gch = ${addsuffix .gch, ${basename ${headers}}} headers: ${headers_gch} headers/clean: ${RM} ${headers_gch} #------------------------------------------------------------------------------- # documentation docs: @echo "Doxygen not yet implemented." docs-todo: doxygen docs/doxygen/doxyfile.conf @echo ======================================== cat docs/doxygen/errors.txt @echo ======================================== @echo "Documentation available in docs/html/index.html" @echo ======================================== #------------------------------------------------------------------------------- # general rules clean: ${RM} ${lib_a} ${lib_so} ${lib_so_abi} ${lib_soname} \ ${lib_obj} ${tester_obj} ${dep} ${headers_gch} ${tester} distclean: clean ${RM} make.inc %.o: %.cc ${CXX} ${CXXFLAGS} -c $< -o $@ # preprocess source %.i: %.cc ${CXX} ${CXXFLAGS} -E $< -o $@ # precompile header to check for errors %.gch: %.h ${CXX} ${CXXFLAGS} -c $< -o $@ %.gch: %.hh ${CXX} ${CXXFLAGS} -c $< -o $@ -include ${dep} #------------------------------------------------------------------------------- # debugging echo: @echo "---------- Options" @echo "static = '${static}'" @echo "prefix = '${prefix}'" @echo "abs_prefix = '${abs_prefix}'" @echo @echo "---------- Internal variables" @echo "ostype = '${ostype}'" @echo "macos = '${macos}'" @echo "id = '${id}'" @echo "last_id = '${last_id}'" @echo "abi_version = '${abi_version}'" @echo "soversion = '${soversion}'" @echo @echo "---------- Libraries" @echo "lib_name = ${lib_name}" @echo "lib_a = ${lib_a}" @echo "lib_so = ${lib_so}" @echo "lib = ${lib}" @echo "lib_so_abi = ${lib_so_abi}" @echo "lib_soname = ${lib_soname}" @echo @echo "lib_src = ${lib_src}" @echo @echo "lib_obj = ${lib_obj}" @echo @echo "tester_src = ${tester_src}" @echo @echo "tester_obj = ${tester_obj}" @echo @echo "tester = ${tester}" @echo @echo "dep = ${dep}" @echo @echo "---------- C++ compiler" @echo "CXX = ${CXX}" @echo "CXXFLAGS = ${CXXFLAGS}" @echo @echo "---------- Link flags" @echo "LD = ${LD}" @echo "LDFLAGS = ${LDFLAGS}" @echo "LIBS = ${LIBS}" @echo "ldflags_shared = ${ldflags_shared}" @echo @echo "TEST_LDFLAGS = ${TEST_LDFLAGS}" @echo "TEST_LIBS = ${TEST_LIBS}" testsweeper-2024.05.31/GNUmakefile.subdir000066400000000000000000000026341462625314600200410ustar00rootroot00000000000000# Copyright (c) 2017-2023, University of Tennessee. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause # This program is free software: you can redistribute it and/or modify it under # the terms of the BSD 3-Clause license. See the accompanying LICENSE file. # # Subdirectories include this makefile to forward rules to the top level makefile. # Define ${top} for where the top level is. # Example: src/GNUmakefile: # top = .. # include ${top}/GNUmakefile.subdir .SUFFIXES: pwd := ${shell pwd} abs_top := ${abspath ${top}} cdir := ${subst ${abs_top}/,,${pwd}} .DEFAULT_GOAL: ${cdir} .PHONY: ${cdir} ${cdir}: cd ${top} && ${MAKE} $@ DONT_FORWARD += echo_sub echo_sub: @echo "pwd ${pwd}" @echo "abs_top ${abs_top}" @echo "cdir ${cdir}" # ------------------------------------------------------------------------------ ifneq (${MAKECMDGOALS},) # If arguments are given, presumably files like test.o, forward them to top # with cdir prefix. # All files are forwarded as one rule, based on first; rest are quietly ignored. goals := ${filter-out echo ${DONT_FORWARD}, ${MAKECMDGOALS}} forward := ${addprefix ${cdir}/, ${goals}} first := ${firstword ${goals}} rest := ${wordlist 2, ${words ${goals}}, ${goals}} ${first}: force cd ${top} && ${MAKE} ${forward} ${rest}: force @echo > /dev/null endif # ------------------------------------------------------------------------------ force: ; testsweeper-2024.05.31/INSTALL.md000066400000000000000000000153331462625314600161300ustar00rootroot00000000000000TestSweeper Installation Notes ================================================================================ [TOC] Synopsis -------------------------------------------------------------------------------- Configure and compile the TestSweeper library and its tester, then install the headers and library. Option 1: Makefile make && make install Option 2: CMake mkdir build && cd build cmake .. make && make install Environment variables (Makefile and CMake) -------------------------------------------------------------------------------- Standard environment variables affect both Makefile (configure.py) and CMake. These include: LD Linker; defaults to CXX CXX C++ compiler CXXFLAGS C++ compiler flags LDFLAGS linker flags CPATH compiler include search path LIBRARY_PATH compile-time library search path LD_LIBRARY_PATH runtime library search path DYLD_LIBRARY_PATH runtime library search path on macOS TestSweeper does not rely on any libraries, other than optionally OpenMP, so setting LDFLAGS, CPATH, LIBRARY_PATH, etc. is not generally needed. Options (Makefile and CMake) -------------------------------------------------------------------------------- TestSweeper specific options include (all values are case insensitive): color Whether to use ANSI colors in output. One of: auto uses color if output is a TTY (default with Makefile; not support with CMake) yes (default with CMake) no With Makefile, options are specified as environment variables or on the command line using `option=value` syntax, such as: python3 configure.py color=no With CMake, options are specified on the command line using `-Doption=value` syntax (not as environment variables), such as: cmake -Dcolor=no .. Makefile Installation -------------------------------------------------------------------------------- Available targets: make - configures (if make.inc is missing), then compiles the library and tester make config - configures TestSweeper, creating a make.inc file make lib - compiles the library (lib/libtestsweeper.so) make tester - compiles test/tester make check - run basic checks using tester make docs - todo: generates documentation in docs/html/index.html make install - installs the library and headers to ${prefix} make uninstall - remove installed library and headers from ${prefix} make clean - deletes object (*.o) and library (*.a, *.so) files make distclean - also deletes make.inc and dependency files (*.d) ### Options make config [options] or python3 configure.py [options] Runs the `configure.py` script to detect your compiler and library properties, then creates a make.inc configuration file. You can also manually edit the make.inc file. Options are name=value pairs to set variables. Besides the Environment variables and Options listed above, additional options include: static Whether to build as a static or shared library. 0 shared library (default) 1 static library prefix Where to install, default /opt/slate. Headers go in ${prefix}/include, library goes in ${prefix}/lib${LIB_SUFFIX} These can be set in your environment or on the command line, e.g., python3 configure.py CXX=g++ prefix=/usr/local ### Manual configuration If you have a specific configuration that you want, set CXX, CXXFLAGS, LDFLAGS, and LIBS, e.g.: export CXX="g++" export CXXFLAGS="-fopenmp" export LDFLAGS="-fopenmp" These can also be set when running configure: make config CXX=g++ \ CXXFLAGS="-fopenmp" \ LDFLAGS="-fopenmp" Note that all test programs are compiled with those options, so errors may cause configure to fail. If you experience unexpected problems, please see config/log.txt to diagnose the issue. The log shows the option being tested, the exact command run, the command's standard output (stdout), error output (stderr), and exit status. All test files are in the config directory. CMake Installation -------------------------------------------------------------------------------- The CMake script enforces an out-of-source build. Create a build directory under the TestSweeper root directory: cd /path/to/testsweeper mkdir build && cd build cmake [-DCMAKE_INSTALL_PREFIX=/path/to/install] [options] .. make make install ### Options Besides the Environment variables and Options listed above, additional options include: use_openmp Whether to use OpenMP, if available. One of: yes (default) no build_tests Whether to build test suite (test/tester). Requires TestSweeper, CBLAS, and LAPACK. One of: yes (default) no Standard CMake options include: BUILD_SHARED_LIBS Whether to build as a static or shared library. One of: yes shared library (default) no static library CMAKE_INSTALL_PREFIX (alias prefix) Where to install, default /opt/slate. Headers go in ${prefix}/include, library goes in ${prefix}/lib CMAKE_PREFIX_PATH Where to look for CMake packages such as BLAS++ and TestSweeper. CMAKE_BUILD_TYPE Type of build. One of: [empty] default compiler optimization (no flags) Debug no optimization, with asserts (-O0 -g) Release optimized, no asserts, no debug info (-O3 -DNDEBUG) RelWithDebInfo optimized, no asserts, with debug info (-O2 -DNDEBUG -g) MinSizeRel Release, but optimized for size (-Os -DNDEBUG) CMAKE_MESSAGE_LOG_LEVEL (alias log) Level of messages to report. In ascending order: FATAL_ERROR, SEND_ERROR, WARNING, AUTHOR_WARNING, DEPRECATION, NOTICE, STATUS, VERBOSE, DEBUG, TRACE. Particularly, DEBUG or TRACE gives useful information. With CMake, options are specified on the command line using `-Doption=value` syntax (not as environment variables), such as: # in build directory cmake -Dbuild_tests=no -DCMAKE_INSTALL_PREFIX=/usr/local .. Alternatively, use the `ccmake` text-based interface or the CMake app GUI. # in build directory ccmake .. # Type 'c' to configure, then 'g' to generate Makefile To re-configure CMake, you may need to delete CMake's cache: # in build directory rm CMakeCache.txt # or rm -rf * cmake [options] .. To debug the build, set `VERBOSE`: # in build directory, after running cmake make VERBOSE=1 testsweeper-2024.05.31/LICENSE000066400000000000000000000030101462625314600154720ustar00rootroot00000000000000Copyright (c) 2017-2023, University of Tennessee. 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 the University of Tennessee 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 HOLDERS 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. testsweeper-2024.05.31/README.md000066400000000000000000000112271462625314600157550ustar00rootroot00000000000000 ______ __ _____ /_ __/__ _____/ /_/ ___/ _____ ___ ____ ___ _____ / / / _ \/ ___/ __/\__ \ | /| / / _ \/ _ \/ __ \/ _ \/ ___/ / / / __(__ ) /_ ___/ / |/ |/ / __/ __/ /_/ / __/ / /_/ \___/____/\__//____/|__/|__/\___/\___/ .___/\___/_/ /_/ **Innovative Computing Laboratory** **University of Tennessee** * * * [TOC] * * * About -------------------------------------------------------------------------------- TestSweeper is a C++ testing framework for parameter sweeps. It handles parsing command line options, iterating over the test space, and printing results. This simplifies test functions by allowing them to concentrate on setting up and solving one problem at a time. TestSweeper is part of the SLATE project ([Software for Linear Algebra Targeting Exascale](http://icl.utk.edu/slate/)), which is funded by the [Department of Energy](https://energy.gov) as part of its [Exascale Computing Initiative](https://exascaleproject.org) (ECP). * * * Documentation -------------------------------------------------------------------------------- * [INSTALL.md](INSTALL.md) for installation notes. * TODO: Doxygen forthcoming. * * * Getting Help -------------------------------------------------------------------------------- For assistance, visit the *SLATE User Forum* at . Join by signing in with your Google credentials, then clicking *Join group to post*. Bug reports can be filed directly on Github's issue tracker: . * * * Resources -------------------------------------------------------------------------------- * Visit the [SLATE website](http://icl.utk.edu/slate/) for more information about the SLATE project. * Visit the [ECP website](https://exascaleproject.org) to find out more about the DOE Exascale Computing Initiative. * * * Contributing -------------------------------------------------------------------------------- The SLATE project welcomes contributions from new developers. Contributions can be offered through the standard Github pull request model. We strongly encourage you to coordinate large contributions with the SLATE development team early in the process. * * * Acknowledgments -------------------------------------------------------------------------------- This research was supported by the Exascale Computing Project (17-SC-20-SC), a joint project of the U.S. Department of Energy's Office of Science and National Nuclear Security Administration, responsible for delivering a capable exascale ecosystem, including software, applications, and hardware technology, to support the nation’s exascale computing imperative. This research uses resources of the Oak Ridge Leadership Computing Facility, which is a DOE Office of Science User Facility supported under Contract DE-AC05-00OR22725. This research also uses resources of the Argonne Leadership Computing Facility, which is a DOE Office of Science User Facility supported under Contract DE-AC02-06CH11357. * * * License -------------------------------------------------------------------------------- Copyright (c) 2017-2023, University of Tennessee. 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 the University of Tennessee 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 holders 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.** testsweeper-2024.05.31/config/000077500000000000000000000000001462625314600157405ustar00rootroot00000000000000testsweeper-2024.05.31/config/__init__.py000066400000000000000000000000261462625314600200470ustar00rootroot00000000000000from .config import * testsweeper-2024.05.31/config/ansicodes.py000066400000000000000000000346031462625314600202700ustar00rootroot00000000000000# Copyright (c) 2017-2023, University of Tennessee. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause # This program is free software: you can redistribute it and/or modify it under # the terms of the BSD 3-Clause license. See the accompanying LICENSE file. ''' ANSI font and color codes. ''' import sys ansi_esc_ = chr(0x1B) + '[' #------------------------------------------------------------------------------- class Font( object ): ''' ANSI font and color codes. The Font class implements all settings, and is accessible by a global object `font`. Member functions that take a string `msg`, e.g., `font.bold( msg )`, return a string of an ANSI code + msg + an ANSI code to restore the state. Member functions that don't take a string just return an ANSI code, usually to restore the state, e.g., `font.not_italic()`. Example use: from ansicodes import font font.set_enabled( True ) # enabled by default print( font.bold( font.red( 'red' ) + ' bold' ) + ' normal.' ) Styles and one color can be nested: print( 'normal' + font.bold( 'bold ' + font.italic( 'bold-italic ' + fg.red( 'red-bold-italic' ) + ' bold-italic' ) + ' bold' ) + ' normal' ) Multiple colors cannot be nested: print( fg.red( 'red ' + fg.blue( 'blue' ) + ' *black' ) + ' black' ) where one might expect the ' *black' text to be red, but that color is lost. ''' #-------------------- def __init__( self ): self.enabled_ = True #-------------------- def set_enabled( self, val ): ''' Enable or disable ANSI codes. Enable if val == True, 'y', 'yes', or 'always', or if val = 'auto' and output is to a console (TTY). ''' self.enabled_ = (val in (True, 'y', 'yes', 'always') or (val == 'auto' and sys.stdout.isatty())) # end #-------------------- def code( self, val ): ''' If ANSI codes are enabled, returns "ESC[" + val + "m"; otherwise returns empty string. ''' if (self.enabled_): return ansi_esc_ + val + 'm' else: return '' # end #-------------------- font styles def reset( self, msg ): return self.code('0') def bold( self, msg ): return self.code('1') + msg + self.normal() def faint( self, msg ): return self.code('2') + msg + self.normal() def italic( self, msg ): return self.code('3') + msg + self.not_italic() def underline( self, msg ): return self.code('4') + msg + self.not_underline() def blink( self, msg ): return self.code('5') + msg + self.steady() def blink_fast( self, msg ): return self.code('6') + msg + self.steady() def negative( self, msg ): return self.code('7') + msg + self.positive() def conceal( self, msg ): return self.code('8') + msg + self.reveal() def strike( self, msg ): return self.code('9') + msg + self.not_strike() def fraktur( self, msg ): return self.code('20') + msg + self.not_italic() # 21 is either not-bold or double underline, an unfortunate ambiguity. def not_bold( self ): return self.code('21') def normal( self ): return self.code('22') # not bold, not faint def not_italic( self ): return self.code('23') def not_fraktur( self ): return self.code('23') def not_underline( self ): return self.code('24') def steady( self ): return self.code('25') def positive( self ): return self.code('27') def reveal( self ): return self.code('28') def not_strike( self ): return self.code('29') #-------------------- fonts (rarely supported) def default_font( self ): return self.code('10') def font1( self, msg ): return self.code('11') + msg + self.default_font() def font2( self, msg ): return self.code('12') + msg + self.default_font() def font3( self, msg ): return self.code('13') + msg + self.default_font() def font4( self, msg ): return self.code('14') + msg + self.default_font() def font5( self, msg ): return self.code('15') + msg + self.default_font() def font6( self, msg ): return self.code('16') + msg + self.default_font() def font7( self, msg ): return self.code('17') + msg + self.default_font() def font8( self, msg ): return self.code('18') + msg + self.default_font() def font9( self, msg ): return self.code('19') + msg + self.default_font() #-------------------- frames (rarely supported) def framed( self, msg ): return self.code('51') + msg + self.not_framed() def encircled( self, msg ): return self.code('52') + msg + self.not_encircled() def overlined( self, msg ): return self.code('53') + msg + self.not_overlined() def not_framed( self ): return self.code('54') def not_encircled( self ): return self.code('54') def not_overlined( self ): return self.code('55') #-------------------- foreground colors def black( self, msg ): return self.code('30') + msg + self.default_color() def red( self, msg ): return self.code('31') + msg + self.default_color() def green( self, msg ): return self.code('32') + msg + self.default_color() def yellow( self, msg ): return self.code('33') + msg + self.default_color() def blue( self, msg ): return self.code('34') + msg + self.default_color() def magenta( self, msg ): return self.code('35') + msg + self.default_color() def cyan( self, msg ): return self.code('36') + msg + self.default_color() def gray( self, msg ): return self.code('37') + msg + self.default_color() def default_color( self ): return self.code('39') def color( self, r, g, b, msg ): ''' Returns string to display msg using a 24-bit RGB foreground color. Supported on Xterm, Konsole, Gnome, libvte, etc. May produce weird results on others like macOS Terminal. ''' return self.code('38;2;%d;%d;%d' % (r, g, b)) + msg + self.default_color() #-------------------- background colors def black_bg( self, msg ): return self.code('40') + msg + self.default_bgcolor() def red_bg( self, msg ): return self.code('41') + msg + self.default_bgcolor() def green_bg( self, msg ): return self.code('42') + msg + self.default_bgcolor() def yellow_bg( self, msg ): return self.code('43') + msg + self.default_bgcolor() def blue_bg( self, msg ): return self.code('44') + msg + self.default_bgcolor() def magenta_bg( self, msg ): return self.code('45') + msg + self.default_bgcolor() def cyan_bg( self, msg ): return self.code('46') + msg + self.default_bgcolor() def gray_bg( self, msg ): return self.code('47') + msg + self.default_bgcolor() def default_bgcolor( self ): return self.code('49') def bgcolor( self, r, g, b, msg ): ''' Returns string to display msg using a 24-bit RGB background color. ''' return self.code('48;2;%d;%d;%d' % (r, g, b)) + msg + self.default_bgcolor() # end #------------------------------------------------------------------------------- # Global object to access the Font class. font = Font() #------------------------------------------------------------------------------- def test(): print( font.bold( 'Styles' ) ) print( 'bold: ', font.bold ( ' text ' ), 'post' ) print( 'faint: ', font.faint ( ' text ' ), 'post' ) print( 'italic: ', font.italic ( ' text ' ), 'post' ) print( 'underline: ', font.underline ( ' text ' ), 'post' ) print( 'blink: ', font.blink ( ' text ' ), 'post' ) print( 'blink_fast:', font.blink_fast( ' text ' ), 'post *' ) print( 'negative: ', font.negative ( ' text ' ), 'post' ) print( 'conceal: ', font.conceal ( ' text ' ), 'post' ) print( 'strike: ', font.strike ( ' text ' ), 'post' ) print( 'fraktur: ', font.fraktur ( ' text ' ), 'post *' ) print( 'framed: ', font.framed ( ' text ' ), 'post *' ) print( 'encircled: ', font.encircled ( ' text ' ), 'post *' ) print( 'overlined: ', font.overlined ( ' text ' ), 'post *' ) print( font.bold( '\nFonts (* rarely supported)' ) ) print( 'font1:', font.font1( ' text ' ), 'post *' ) print( 'font2:', font.font2( ' text ' ), 'post *' ) print( 'font3:', font.font3( ' text ' ), 'post *' ) print( 'font4:', font.font4( ' text ' ), 'post *' ) print( 'font5:', font.font5( ' text ' ), 'post *' ) print( 'font6:', font.font6( ' text ' ), 'post *' ) print( 'font7:', font.font7( ' text ' ), 'post *' ) print( 'font8:', font.font8( ' text ' ), 'post *' ) print( 'font9:', font.font9( ' text ' ), 'post *' ) print( font.bold( '\nForeground colors' ) ) print( 'default:', font.default_color() + ' text ', 'post' ) print( 'black: ', font.black ( ' text ' ), 'post' ) print( 'red: ', font.red ( ' text ' ), 'post' ) print( 'green: ', font.green ( ' text ' ), 'post' ) print( 'yellow: ', font.yellow ( ' text ' ), 'post' ) print( 'blue: ', font.blue ( ' text ' ), 'post' ) print( 'magenta:', font.magenta( ' text ' ), 'post' ) print( 'cyan: ', font.cyan ( ' text ' ), 'post' ) print( 'gray: ', font.gray ( ' text ' ), 'post' ) # aka, "white" print( font.bold( 'RGB colors' ) ) print( 'red: ', font.color( 255, 0, 0, ' text ' ), 'post' ) print( 'purple: ', font.color( 148, 33, 147, ' text ' ), 'post' ) print( 'orange: ', font.color( 255, 147, 0, ' text ' ), 'post' ) print( font.bold( '\nForeground colors + bold ("bright")' ) ) print( 'default:', font.bold( font.default_color() + ' text ' ), 'post' ) print( 'black: ', font.bold( font.black ( ' text ' ) ), 'post' ) print( 'red: ', font.bold( font.red ( ' text ' ) ), 'post' ) print( 'green: ', font.bold( font.green ( ' text ' ) ), 'post' ) print( 'yellow: ', font.bold( font.yellow ( ' text ' ) ), 'post' ) print( 'blue: ', font.bold( font.blue ( ' text ' ) ), 'post' ) print( 'magenta:', font.bold( font.magenta( ' text ' ) ), 'post' ) print( 'cyan: ', font.bold( font.cyan ( ' text ' ) ), 'post' ) print( 'gray: ', font.bold( font.gray ( ' text ' ) ), 'post' ) print( font.bold( 'RGB colors' ) ) print( 'red: ', font.bold( font.color( 255, 0, 0, ' text ' ) ), 'post' ) print( 'purple: ', font.bold( font.color( 148, 33, 147, ' text ' ) ), 'post' ) print( 'orange: ', font.bold( font.color( 255, 147, 0, ' text ' ) ), 'post' ) print( font.bold( '\nBackground colors' ) ) print( 'bg default:', font.default_bgcolor() + ' text ', 'post' ) print( 'bg black: ', font.black_bg ( ' text ' ), 'post' ) print( 'bg red: ', font.red_bg ( ' text ' ), 'post' ) print( 'bg green: ', font.green_bg ( ' text ' ), 'post' ) print( 'bg yellow: ', font.yellow_bg ( ' text ' ), 'post' ) print( 'bg blue: ', font.blue_bg ( ' text ' ), 'post' ) print( 'bg magenta:', font.magenta_bg( ' text ' ), 'post' ) print( 'bg cyan: ', font.cyan_bg ( ' text ' ), 'post' ) print( 'bg gray: ', font.gray_bg ( ' text ' ), 'post' ) print( font.bold( 'bg RGB colors' ) ) print( 'bg red: ', font.bgcolor( 255, 0, 0, ' text ' ), 'post' ) print( 'bg purple: ', font.bgcolor( 148, 33, 147, ' text ' ), 'post' ) print( 'bg orange: ', font.bgcolor( 255, 147, 0, ' text ' ), 'post' ) print( font.bold( '\nBackground colors + bold ("bright")' ) ) print( 'bg black: ', font.bold( font.black_bg ( ' text ' ) ), 'post' ) print( 'bg red: ', font.bold( font.red_bg ( ' text ' ) ), 'post' ) print( 'bg green: ', font.bold( font.green_bg ( ' text ' ) ), 'post' ) print( 'bg yellow: ', font.bold( font.yellow_bg ( ' text ' ) ), 'post' ) print( 'bg blue: ', font.bold( font.blue_bg ( ' text ' ) ), 'post' ) print( 'bg magenta:', font.bold( font.magenta_bg( ' text ' ) ), 'post' ) print( 'bg cyan: ', font.bold( font.cyan_bg ( ' text ' ) ), 'post' ) print( 'bg gray: ', font.bold( font.gray_bg ( ' text ' ) ), 'post' ) print( font.bold( 'bg RGB colors' ) ) print( 'bg red: ', font.bold( font.bgcolor( 255, 0, 0, ' text ' ) ), 'post' ) print( 'bg purple: ', font.bold( font.bgcolor( 148, 33, 147, ' text ' ) ), 'post' ) print( 'bg orange: ', font.bold( font.bgcolor( 255, 147, 0, ' text ' ) ), 'post' ) print( font.bold( '\nCombinations' ) ) # bold + italic, bold + underline print( 'pre ' + font.bold( 'bold ' + font.italic( 'bold-italic' ) + ' bold' ) + ' normal' ) print( 'pre ' + font.bold( 'bold ' + font.underline( 'bold-underline' ) + ' bold' ) + ' normal' ) # italic + bold, italic + underline print( 'pre ' + font.italic( 'italic ' + font.bold( 'italic-bold' ) + ' italic' ) + ' normal' ) print( 'pre ' + font.italic( 'italic ' + font.underline( 'italic-underline' ) + ' italic' ) + ' normal' ) # underline + bold, underline + italic print( 'pre ' + font.underline( 'underline ' + font.bold( 'underline-bold' ) + ' underline' ) + ' normal' ) print( 'pre ' + font.underline( 'underline ' + font.italic( 'underline-italic' ) + ' underline' ) + ' normal' ) # bold + italic + underline print( 'pre ' + font.bold( 'bold ' + font.underline( 'bold-underline ' + font.italic( 'bold-italic-underline' ) + ' bold-underline' ) + ' bold' ) + ' normal' ) # bold + fg color, bold + bg color print( 'pre ' + font.bold( 'bold ' + font.red( 'bold-red' ) + ' bold' ) + ' normal' ) print( 'pre ' + font.bold( 'bold ' + font.red_bg( 'bold/red' ) + ' bold' ) + ' normal' ) # colors: fg + bg, bg + fg, negative bg + fg print( 'pre ' + font.red( 'red ' + font.yellow_bg( 'red/yellow' ) + ' red' ) + ' normal' ) print( 'pre ' + font.red_bg( 'black/red ' + font.yellow( 'yellow/red' ) + ' black/red' ) + ' normal' ) print( 'pre ' + font.negative( 'negative ' + font.red_bg( 'black/red ' + font.yellow( 'yellow/red' ) + ' black/red' ) + ' negative' ) + ' normal' ) # end testsweeper-2024.05.31/config/compiler_cxx.cc000066400000000000000000000026301462625314600207440ustar00rootroot00000000000000// Copyright (c) 2017-2023, University of Tennessee. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // This program is free software: you can redistribute it and/or modify it under // the terms of the BSD 3-Clause license. See the accompanying LICENSE file. #ifdef __cplusplus #include #else #include #endif int main() { // xlc must come before clang; clang and icc must come before gcc const char* compiler = #ifdef __cplusplus // IBM's documentation says __IBMCPP__, // but xlc -qshowmacros shows __ibmxl_version__. #if defined(__IBMCPP__) || defined(__ibmxl_version__) "xlc++"; #elif defined(__ICC) "icpc"; #elif defined(_MSC_VER) "MSC"; #elif defined(__clang__) "clang++"; #elif defined(__GNUG__) "g++"; #else "unknown C++"; #endif #else #if defined(__IBMC__) || defined(__ibmxl_version__) "xlc"; #elif defined(__ICC) "icc"; #elif defined(_MSC_VER) "MSC"; #elif defined(__clang__) "clang"; #elif defined(__GNUC__) "gcc"; #else "unknown C"; #endif #endif #ifdef __cplusplus std::cout << compiler << "\n"; #else printf( "%s\n", compiler ); #endif return 0; } testsweeper-2024.05.31/config/config.py000066400000000000000000000677211462625314600175740ustar00rootroot00000000000000# Copyright (c) 2017-2023, University of Tennessee. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause # This program is free software: you can redistribute it and/or modify it under # the terms of the BSD 3-Clause license. See the accompanying LICENSE file. from __future__ import print_function import os import shlex import subprocess from subprocess import PIPE import math import sys import time import re import tarfile import argparse # This relative import syntax works in both python2 and 3. from .ansicodes import font # Python 3 renames raw_input => input. if (sys.version_info.major < 3): input = raw_input #------------------------------------------------------------------------------- def urlretrieve( url, filename ): ''' Downloads url and saves to filename. Works for both Python 2 and 3, which differ in where urlretrieve is located. ''' if (sys.version_info.major >= 3): import urllib.request as urllib_request else: import urllib as urllib_request urllib_request.urlretrieve( url, filename ) # end #------------------------------------------------------------------------------- interactive_ = False # Function to get and set interactive flag. If True, config finds all possible # values and gives user a choice. If False, config picks the first valid value. # value = interactive() returns value of interactive. # interactive( value ) sets value of interactive. # Making this a function config.interactive() avoids issues with the # package __init__.py importing it if it were a variable. def interactive( value=None ): global interactive_ if (value is not None): interactive_ = value return interactive_ # end # ------------------------------------------------------------------------------ debug_ = False def debug( value=None ): global debug_ if (value is not None): debug_ = value return debug_ # end # ------------------------------------------------------------------------------ namespace_ = None def namespace( value ): return namespace_ def define( var, value=None ): txt = '-D' + namespace_ + '_' + var if (value): txt += '=' + value return txt # ------------------------------------------------------------------------------ # variables to replace instead of appending/prepending replace_vars = ['CC', 'CXX', 'NVCC', 'FC', 'AR', 'RANLIB', 'prefix'] # ------------------------------------------------------------------------------ # map file extensions to languages lang_map = { '.c': 'CC', '.cc': 'CXX', '.cxx': 'CXX', '.cpp': 'CXX', '.cu': 'NVCC', '.f': 'FC', '.f90': 'FC', '.f77': 'FC', '.F90': 'FC', '.F77': 'FC', } # ------------------------------------------------------------------------------ # map languages to compiler flags flag_map = { 'CC': 'CFLAGS', 'CXX': 'CXXFLAGS', 'NVCC': 'NVCCFLAGS', 'FC': 'FFLAGS', } # ------------------------------------------------------------------------------ def flatten( data, ltypes=(list, tuple) ): ''' Flattens nested list or tuple. Ex: flatten( [1, 2, [3, [4, 5], 6]] ) returns [1, 2, 3, 4, 5, 6] see http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html ''' ltype = type(data) data = list(data) i = 0 while i < len(data): while isinstance(data[i], ltypes): if not data[i]: data.pop(i) i -= 1 break else: data[i:i + 1] = data[i] i += 1 return ltype(data) # end #------------------------------------------------------------------------------- def get( dictionary, key ): ''' Returns dictionary[ key ] or '' ''' if (key in dictionary): return dictionary[ key ] else: return '' # end #------------------------------------------------------------------------------- def print_header( header ): ''' Prints a header, with bold font, both to console and the log. ''' txt = font.bold( header ) print( '\n' + '-'*80 + '\n' + txt, file=log ) print( '\n' + txt ) # end #------------------------------------------------------------------------------- def print_subhead( subhead ): ''' Prints a subhead, both to console and the log. ''' print( '-'*40 + '\n' + subhead, file=log ) print( subhead ) # end #------------------------------------------------------------------------------- def print_msg( msg ): ''' Prints msg, both to console and the log. ''' print( msg, file=log ) print( msg ) # end #------------------------------------------------------------------------------- def print_warn( msg ): ''' Prints warning msg, with bold red font, both to console and the log. ''' txt = font.bold( font.red( 'Warning: ' + msg ) ) print( txt, file=log ) print( txt ) # end #------------------------------------------------------------------------------- def print_test( label ): ''' If label is given, prints the label, both to console and the log. On the console, it doesn't print the trailing newline; a subsequent print_result() will print it. If no label is given, does nothing. This simplifies functions like compile_obj that take an optional label to print. ''' if (label): print( '-'*20 + '\n' + label, file=log ) print( '%-72s' % label, end='' ) sys.stdout.flush() # end #------------------------------------------------------------------------------- def print_result( label, rc, extra='' ): ''' If label is given, prints either "yes" (if rc == 0) or "no" (otherwise). Extra is printed after yes or no. If no label is given, does nothing. @see print_test(). ''' if (label): if (rc == 0): print( font.blue( 'yes' ), extra, file=log ) print( font.blue( ' yes' ), extra ) else: print( font.red( 'no' ), extra, file=log ) print( font.red( ' no' ), extra ) # end # ------------------------------------------------------------------------------ # Used for all errors. # Allows Python Exceptions to fall through, giving tracebacks. class Error( Exception ): pass class Quit( Error ): pass #------------------------------------------------------------------------------- class Environments( object ): ''' Manages stack of environments, which are dictionaries of name=value pairs. ''' # ---------------------------------------- def __init__( self ): ''' Initializes the environment stack. The bottom is os.environ. The top is an empty environment. ''' self.stack = [ os.environ, {} ] # ---------------------------------------- def push( self, env=None ): ''' Push an empty enviroment on the environment stack. If env is given, also merge env into the environment stack. ''' self.stack.append( {} ) if (env): self.merge( env ) # ---------------------------------------- def top( self ): ''' Return top-most environment in the environment stack. ''' return self.stack[-1] # ---------------------------------------- def pop( self ): ''' Remove the top-most environment from the environment stack. ''' if (len(self.stack) == 2): raise Error( "can't pop last 2 environments" ) return self.stack.pop() # ---------------------------------------- def __contains__( self, key ): ''' Returns true if a key exists in the environment stack. ''' for env in self.stack[::-1]: if (key in env): return True return False # ---------------------------------------- def __getitem__( self, key ): ''' Returns the value of the key, searching from the top of the environment stack down. As in a Makefile, unknown keys return empty string (''). Use 'x in environ' to test whether a key exists. ''' for env in self.stack[::-1]: if (key in env): return env[ key ] return '' # ---------------------------------------- def __setitem__( self, key, value ): ''' Sets the key's value in the top-most environment in the environment stack. ''' self.stack[ -1 ][ key ] = value # ---------------------------------------- def append( self, key, val ): ''' Append val to key's value, saving the result in the top-most environment in the enviornment stack. ''' orig = self[ key ] if (val): if (orig): val = orig + ' ' + val self[ key ] = val return orig # ---------------------------------------- def prepend( self, key, val ): ''' Prepend val to key's value, saving the result in the top-most environment in the enviornment stack. ''' orig = self[ key ] if (val): if (orig): val = val + ' ' + orig self[ key ] = val return orig # ---------------------------------------- def merge( self, env ): ''' Merges env, a dictionary of environment variables, into the existing environment stack. For most variables, the value in env is appended to any existing value. For LIBS, the value is prepended. For variables in config.replace_vars (like CXX), the value in env replaces the existing value. ''' for key in env: if (key in replace_vars): self[ key ] = env[ key ] elif (key == 'LIBS'): self.prepend( key, env[ key ] ) else: self.append( key, env[ key ] ) # end #------------------------------------------------------------------------------- def choose( prompt, choices ): ''' Asks the user to choose among the given choices. Returns the index of the chosen item in the range [0, len(choices)-1], or raises Error or Quit exceptions. ''' choices = list( choices ) n = len( choices ) if (n == 0): print( font.bold( font.red( 'none found' ) ) ) raise Error elif (n == 1): ##print() return 0 else: width = int( math.log10( n ) + 1 ) print( '\n' + prompt ) for i in range( n ): print( '[%*d] %s' % (width, i+1, choices[i]) ) while (True): print( 'Enter [1-%d] or quit: ' % (n), end='' ) sys.stdout.flush() i = input() if (i == 'q' or i == 'quit'): raise Quit try: i = int( i ) except: i = -1 if (i >= 1 and i <= len( choices )): ##print() return i-1 # end # end # end #------------------------------------------------------------------------------- def run( cmd, env=None ): ''' Runs the command cmd. cmd can be a string or a nested list. Pushes env beforehand and pops afterward. stdout and stderr are written to the log. Returns (return_code, stdout, stderr) from the command. Ex: run( ['gcc', '-c', 'file.c'], {'CPATH': '/opt/include'} ) runs: gcc -c file.c ''' environ.push( env ) if (not isinstance( cmd, str )): cmd = ' '.join( flatten( cmd )) print( '>>>', cmd, file=log ) cmd_list = shlex.split( cmd ) try: proc = subprocess.Popen( cmd_list, stdout=PIPE, stderr=PIPE ) (stdout, stderr) = proc.communicate() stdout = stdout.decode('utf-8') stderr = stderr.decode('utf-8') rc = proc.wait() log.write( stdout ) if (stderr): log.write( font.red( stderr ) ) print( 'exit status = %d' % rc, file=log ) except Exception as ex: print( 'Exception:', str(ex), file=log ) rc = -1 stdout = '' stderr = str(ex) environ.pop() return (rc, stdout, stderr) # end #------------------------------------------------------------------------------- def compile_obj( src, env=None, label=None ): ''' Compiles source file src into an object (.o) file. Pushes env beforehand and pops afterwards. If label is given, prints label & result. Returns (return_code, stdout, stderr) from the compiler. Ex: compile_obj( 'foo.c', {'CC': 'gcc'}, 'Test foo' ) runs: gcc $CFLAGS -c foo.c -o foo.o ''' environ.push( env ) print_test( label ) (base, ext) = os.path.splitext( src ) obj = base + '.o' lang = lang_map[ ext ] compiler = environ[ lang ] flags = environ[ flag_map[ lang ]] (rc, stdout, stderr) = run([ compiler, flags, '-c', src, '-o', obj ]) print_result( label, rc ) environ.pop() return (rc, stdout, stderr) # end #------------------------------------------------------------------------------- def link_exe( src, env=None, label=None ): ''' Links the object file (.o) associated with the source file src into an executable. Assumes compile_obj( src ) was called previously to generate the object file. Pushes env beforehand and pops afterward. If label is given, prints label & result. Returns (return_code, stdout, stderr) from the compiler. Ex: link_exe( 'foo.c', {'CC': 'gcc'}, 'Test foo' ) runs: gcc $LDFLAGS $LIBS foo.o -o foo ''' environ.push( env ) print_test( label ) (base, ext) = os.path.splitext( src ) obj = base + '.o' lang = lang_map[ ext ] compiler = environ[ lang ] LDFLAGS = environ['LDFLAGS'] LIBS = environ['LIBS'] or environ['LDLIBS'] (rc, stdout, stderr) = run([ compiler, obj, '-o', base, LDFLAGS, LIBS ]) print_result( label, rc ) environ.pop() return (rc, stdout, stderr) # end #------------------------------------------------------------------------------- def compile_exe( src, env=None, label=None ): ''' Compiles source file src into an object file via compile_obj(), then links it into an exe. Ex: compile_exe( 'foo.c', {'CC': 'gcc'}, 'Test foo' ) runs: gcc $CFLAGS -c foo.c -o foo.o gcc $LDFLAGS $LIBS foo.o -o foo ''' environ.push( env ) print_test( label ) (base, ext) = os.path.splitext( src ) obj = base + '.o' lang = lang_map[ ext ] compiler = environ[ lang ] LDFLAGS = environ['LDFLAGS'] LIBS = environ['LIBS'] or environ['LDLIBS'] (rc, stdout, stderr) = compile_obj( src ) if (rc == 0): (rc, stdout, stderr) = run([ compiler, obj, '-o', base, LDFLAGS, LIBS ]) print_result( label, rc ) environ.pop() return (rc, stdout, stderr) # end #------------------------------------------------------------------------------- # Ex: # compile_run( 'foo.c', {'CC': 'gcc'}, 'Test foo' ) def compile_run( src, env=None, label=None ): ''' Compiles source file src into an object file and exe via compile_exe(), then executes the exe. Ex: compile_exe( 'foo.c', {'CC': 'gcc'}, 'Test foo' ) runs: gcc $CFLAGS -c foo.c -o foo.o gcc $LDFLAGS $LIBS foo.o -o foo ./foo ''' environ.push( env ) print_test( label ) (base, ext) = os.path.splitext( src ) (rc, stdout, stderr) = compile_exe( src ) if (rc == 0): (rc, stdout, stderr) = run( './' + base ) print_result( label, rc ) environ.pop() return (rc, stdout, stderr) # end #------------------------------------------------------------------------------- def run_exe( src, env=None, label=None ): ''' Runs the exe associated with src. Assumes compile_exe( src ) was called previously to generate the exe. Ex: run_exe( 'foo.c', {'CC': 'gcc'}, 'Test foo' ) runs: ./foo ''' environ.push( env ) print_test( label ) (base, ext) = os.path.splitext( src ) (rc, stdout, stderr) = run( './' + base ) print_result( label, rc ) environ.pop() return (rc, stdout, stderr) # end #------------------------------------------------------------------------------- def prog_cxx( choices=['g++', 'c++', 'CC', 'cxx', 'icpc', 'xlc++', 'clang++'] ): ''' Searches for available C++ compilers from the list of choices. Sets CXX to the chosen one. ''' print_header( 'C++ compiler' ) cxx = environ['CXX'] if (cxx): print( 'Trying $CXX =', cxx ) choices = [ cxx ] passed = [] # CXX compilers, e.g., g++ or mpicxx actual = [] # Detected underlying compilers, e.g., g++ or clang++ for cxx in choices: print_test( cxx ) (rc, out, err) = compile_run( 'config/compiler_cxx.cc', {'CXX': cxx} ) # print (g++), (clang++), etc., as output by compiler_cxx, after yes if (rc == 0): cxx_actual = out.strip() out = '(' + cxx_actual + ')' actual.append( cxx_actual ) print_result( cxx, rc, out ) if (rc == 0): passed.append( cxx ) if (not interactive()): break # end # end i = choose( 'Choose C++ compiler:', passed ) environ['CXX'] = passed[i] environ['CXX_actual'] = actual[i] # end #------------------------------------------------------------------------------- def prog_cxx_flag( flags ): ''' Tests each flag in flags; the first that passes is added to CXXFLAGS. flags can be an individual string or an iterable (list, tuple, etc.). ''' if (type( flags ) == str): flags = [ flags ] # end for flag in flags: print_test( flag ) (rc, out, err) = compile_obj( 'config/compiler_cxx.cc', {'CXXFLAGS': flag} ) # assume a mention of the flag in stderr means it isn't supported if (flag in err): rc = 1 print_result( flag, rc ) if (rc == 0): environ.append( 'CXXFLAGS', flag ) break # end # end #------------------------------------------------------------------------------- def openmp( flags=['-fopenmp', '-qopenmp', '-openmp', '-omp', ''] ): ''' Tests for OpenMP support with one of the given flags. If a flag works, it is added to both CXXFLAGS and LDFLAGS. ''' print_header( 'OpenMP support' ) src = 'config/openmp.cc' for flag in flags: print_test( flag ) env = {'CXXFLAGS': flag, 'LDFLAGS': flag, 'HAS_OPENMP': True} (rc, out, err) = compile_run( src, env ) print_result( flag, rc ) if (rc == 0): environ.merge( env ) break # end # end #------------------------------------------------------------------------------- def get_package( name, directories, repo_url, tar_url, tar_filename ): ''' Searches for a package, generally used for internal packages. Looks for a directory in directories; if found return directory. If not found, tries to 'git clone repo_url' to the last directory. If that fails, tries to download tar_url and unpack it to the last directory. ''' global log print_header( name ) for directory in directories: print_test( directory ) err = not os.path.exists( directory ) print_result( directory, err ) if (not err): return directory # end if (repo_url): if (interactive()): print( name +' not found; git clone '+ repo_url +'? [Y/n] ', end='' ) sys.stdout.flush() i = input().lower() if (not interactive() or i in ('', 'y', 'yes')): cmd = 'git clone '+ repo_url +' '+ directory print_test( 'download: ' + cmd ) (err, stdout, stderr) = run( cmd ) print_result( 'download', err ) if (not err): return directory # end if (tar_url): if (interactive()): print( name +' not found; download from '+ tar_url +'? [Y/n] ', end='' ) sys.stdout.flush() i = input().lower() if (not interactive() or i in ('', 'y', 'yes')): try: print_test( 'download: '+ tar_url +' as '+ tar_filename ) urlretrieve( tar_url, tar_filename ) print( 'untar', tar_filename, file=log ) tar = tarfile.open( tar_filename ) files = tar.getnames() last = '' for f in files: # sanitize file names: disallow beginning with / or having ../ if (re.search( r'^/|\.\./', f )): print( 'skipping', f ) continue tar.extract( f ) lastfile = f # end # rename directory, # e.g., from icl-testsweeper-dbd960ebf706 to testsweeper # todo: os.path.sep intsead of '/'? dirs = re.split( '/', lastfile ) print( 'rename', dirs[0], directory, file=log ) os.rename( dirs[0], directory ) err = 0 except Exception as ex: print( 'Exception:', str(ex), file=log ) # end print_result( 'download', err ) if (not err): return directory # end # end # otherwise, not found return None # end #------------------------------------------------------------------------------- def extract_defines_from_flags( flags='CXXFLAGS', var='HEADER_DEFINES' ): ''' Extracts all "-Dname[=value]" defines from the given flags. Adds all "-Dname[=value]" defines to DEFINES. Adds all "#define name [value]" defines to HEADER_DEFINES. Stores all name=value defines for autoconf-like "#undef name" substitution in output_files(). ''' global environ, defines exp = r'(-D(\w+)(?:=(\S*))?) *' defs = re.findall( exp, environ[ flags ] ) environ[ flags ] = re.sub( exp, '', environ[ flags ] ).strip() header = '' for (name_value, name, value) in defs: environ.append( 'DEFINES', name_value ) defines[ name ] = value if (value): header += '#define '+ name +' '+ value + '\n' else: header += '#define '+ name + '\n' # end environ[ var ] = header # end #------------------------------------------------------------------------------- def sub_env( match ): ''' Given a re (regular expression) match object, returns value of environment variable. Used in output_files(). ''' return environ[ match.group(1) ] #------------------------------------------------------------------------------- def sub_define( match ): ''' Given a re regexp match object, returns "#define name [value]" or "// #undef name" Used in output_files(). ''' global defines name = match.group(1) if (name in defines): value = defines[ name ] if (value): return '#define '+ name +' '+ value else: return '#define '+ name else: return '// #undef '+ name # end #------------------------------------------------------------------------------- def read( filename ): ''' Reads and returns the entire contents of filename. ''' f = open( filename, 'r' ) txt = f.read() f.close() return txt # end #------------------------------------------------------------------------------- def write( filename, txt ): ''' Writes txt to filename. ''' f = open( filename, 'w' ) f.write( txt ) f.close() # end #------------------------------------------------------------------------------- def output_files( files ): ''' Create each file in files from file.in, substituting @foo@ with variable foo. This avoids re-creating the file if the contents did not change. files can be a single file or list of files. ''' print_header( 'Output files' ) if (isinstance( files, str )): files = [ files ] for fname in files: txt = read( fname + '.in' ) txt = re.sub( r'@(\w+)@', sub_env, txt ) txt = re.sub( r'#undef (\w+)', sub_define, txt ) exists = os.path.exists( fname ) if (exists and txt == read( fname )): print( fname, 'is unchanged' ) else: if (exists): bak = fname + '.bak' print( 'backing up', fname, 'to', bak ) os.rename( fname, bak ) # end print( 'creating', fname ) write( fname, txt ) # end # end # end #------------------------------------------------------------------------------- def parse_args(): ''' Parses command line options. Sets if interactive and if ansicodes are enabled. ''' global opts, parser, debug #-------------------- # Parse command line. We'll handle help ourselves. parser = argparse.ArgumentParser( add_help=False ) parser.add_argument( '-i', '--interactive', action='store_true', help='Find all available choices and ask user which to use;' +' otherwise use first choice found.' ) parser.add_argument( '--color', action='store', default='auto', help='Use ANSI colors: yes, no, or auto; default %(default)s.' ) parser.add_argument( '--debug', action='store_true', help='Enable debugging output.' ) parser.add_argument( '-h', '--help', action='store_true', help='Print help and exit.' ) parser.add_argument( 'options', nargs=argparse.REMAINDER, help='name=value pairs of options to define.' ) opts = parser.parse_args() # Parse name=value pairs. for arg in opts.options: s = re.search( '^(\w+)=(.*)', arg ) if (s): environ[ s.group(1) ] = s.group(2) else: print( 'Unknown argument:', arg ) exit(1) # end if (environ['color']): opts.color = environ['color'] font.set_enabled( opts.color ) if (environ['interactive']): opts.interactive = environ['interactive'] if (opts.interactive): interactive( True ) debug( opts.debug ) # end #------------------------------------------------------------------------------- def init( namespace, prefix='/usr/local' ): ''' Initializes config. Opens the logfile and deals with OS-specific issues. ''' global log, namespace_ namespace_ = namespace # Default prefix. if (not environ['prefix']): environ['prefix'] = prefix #-------------------- logfile = 'config/log.txt' print( 'opening log file ' + logfile + '\n' ) log = open( logfile, 'w' ) #-------------------- # Workaround if MacOS SIP may have prevented inheriting DYLD_LIBRARY_PATH. if (sys.platform.startswith('darwin') and 'LD_LIBRARY_PATH' not in os.environ and 'DYLD_LIBRARY_PATH' not in os.environ): txt = font.bold( 'NOTICE: $DYLD_LIBRARY_PATH was not set or not inherited.\n' ) if ('LIBRARY_PATH' in os.environ): os.environ['DYLD_LIBRARY_PATH'] = os.environ['LIBRARY_PATH'] txt += 'Setting $DYLD_LIBRARY_PATH = $LIBRARY_PATH to run test programs.\n' txt += '$LIBRARY_PATH = ' + os.environ['LIBRARY_PATH'] + '\n' else: txt += '$LIBRARY_PATH is not set. Leaving $DYLD_LIBRARY_PATH unset.\n' # end txt += ''' MacOS System Integrity Protection (SIP) prevents configure.py from inheriting $DYLD_LIBRARY_PATH. Using python3 configure.py directly (not via make), with a 3rd party python3 from python.org, Homebrew, etc. (i.e., not /usr/bin/python3), will allow $DYLD_LIBRARY_PATH to be inherited. ''' txt = font.red( txt ) txt += '-'*80 print( txt ) print( txt, file=log ) # end #-------------------- if (opts.help): parser.print_help() exit(0) # end # ------------------------------------------------------------------------------ # Initialize global variables here, rather than in init(), # so they are imported by __init__.py. environ = Environments() environ['argv'] = ' '.join( sys.argv ) environ['datetime'] = time.ctime() defines = {} # Parse command line early, so ANSI codes are enabled or disabled early on. parse_args() testsweeper-2024.05.31/config/openmp.cc000066400000000000000000000010761462625314600175510ustar00rootroot00000000000000// Copyright (c) 2017-2023, University of Tennessee. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // This program is free software: you can redistribute it and/or modify it under // the terms of the BSD 3-Clause license. See the accompanying LICENSE file. #include #include int main() { int nthreads = 1; int tid = 0; #pragma omp parallel { nthreads = omp_get_max_threads(); tid = omp_get_thread_num(); printf( "tid %d, nthreads %d\n", tid, nthreads ); } printf( "ok\n" ); return 0; } testsweeper-2024.05.31/configure.py000077500000000000000000000050221462625314600170300ustar00rootroot00000000000000#!/usr/bin/env python3 # # Copyright (c) 2017-2023, University of Tennessee. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause # This program is free software: you can redistribute it and/or modify it under # the terms of the BSD 3-Clause license. See the accompanying LICENSE file. # # Usage: python3 configure.py [--interactive] from __future__ import print_function import sys import re import config from config import Error, font, print_msg, print_warn, print_header #------------------------------------------------------------------------------- # header print( '-'*80 + '\n' + font.bold( font.blue( ' Welcome to TestSweeper.' ) ) + ''' By default, configure will automatically choose the first valid value it finds for each option. You can set it to interactive to find all possible values and give you a choice: ''' + font.blue( 'make config interactive=1' ) + ''' If you have multiple compilers, we suggest specifying your desired compiler by setting CXX, as the automated search may prefer a different compiler. For ANSI colors, set color=auto (when output is TTY), color=yes, or color=no. See INSTALL.md for more details. ''' + '-'*80 ) #------------------------------------------------------------------------------- def main(): config.init( namespace='TestSweeper', prefix='/opt/slate' ) config.prog_cxx() print_header( 'C++ compiler flags' ) # Pick highest level supported. oneAPI needs C++17. # Crusher had issue with -std=c++20 (2022-07). config.prog_cxx_flag( ['-std=c++17', '-std=c++14', '-std=c++11']) config.prog_cxx_flag( '-O2' ) config.prog_cxx_flag( '-MMD' ) config.prog_cxx_flag( '-Wall' ) config.prog_cxx_flag( '-Wno-unused-local-typedefs' ) config.prog_cxx_flag( '-Wno-unused-function' ) config.prog_cxx_flag( '-Wno-unused-command-line-argument' ) config.prog_cxx_flag( '-pedantic' ) config.prog_cxx_flag( '-Wshadow' ) config.prog_cxx_flag( '-fp-model=precise' ) # Handle NaN correctly with Intel icpx. #config.prog_cxx_flag( '-Wmissing-declarations' ) #config.prog_cxx_flag( '-Wconversion' ) #config.prog_cxx_flag( '-Werror' ) config.openmp() config.output_files( 'make.inc' ) print( 'log in config/log.txt' ) print( '-'*80 ) # end #------------------------------------------------------------------------------- try: main() except Error as ex: print_warn( 'A fatal error occurred. ' + str(ex) + '\nTestSweeper could not be configured. Log in config/log.txt' ) exit(1) testsweeper-2024.05.31/make.inc.in000066400000000000000000000004501462625314600165070ustar00rootroot00000000000000#------------------------------------------------------------------------------- # make.inc file # auto-generated by: @argv@ # host: @HOSTNAME@ # CPATH: @CPATH@ # LIBRARY_PATH: @LIBRARY_PATH@ # CXX = @CXX@ CXXFLAGS = @CXXFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ prefix = @prefix@ testsweeper-2024.05.31/test/000077500000000000000000000000001462625314600154525ustar00rootroot00000000000000testsweeper-2024.05.31/test/CMakeLists.txt000066400000000000000000000015071462625314600202150ustar00rootroot00000000000000#------------------------------------------------------------------------------- set( tester "${testsweeper_}tester" ) add_executable( ${tester} test.cc test_sort.cc ) # C++11 is inherited from testsweeper, but disabling extensions is not. set_target_properties( ${tester} PROPERTIES CXX_EXTENSIONS false ) target_link_libraries( ${tester} testsweeper ) # Copy run_tests script and reference output to build directory. add_custom_command( TARGET ${tester} POST_BUILD COMMAND cp -a ${CMAKE_CURRENT_SOURCE_DIR}/run_tests.py ${CMAKE_CURRENT_SOURCE_DIR}/ref ${CMAKE_CURRENT_BINARY_DIR}/ ) if (testsweeper_is_project) add_custom_target( "check" COMMAND python3 run_tests.py WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) endif() testsweeper-2024.05.31/test/GNUmakefile000066400000000000000000000000531462625314600175220ustar00rootroot00000000000000top = .. include ${top}/GNUmakefile.subdir testsweeper-2024.05.31/test/ref/000077500000000000000000000000001462625314600162265ustar00rootroot00000000000000testsweeper-2024.05.31/test/ref/000.txt000066400000000000000000000011051462625314600172630ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester Usage: ./tester [-h|--help] ./tester [-h|--help] routine ./tester [parameters] routine Available routines: Level 1 sort sort2 sort3 sort4 sort5 sort6 sort7 sort8 Level 2 bar bar2 bar3 bar4 bar5 bar6 Level 3 baz baz2 baz3 baz4 baz5 testsweeper-2024.05.31/test/ref/001.txt000066400000000000000000000011101462625314600172600ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester -h Usage: ./tester [-h|--help] ./tester [-h|--help] routine ./tester [parameters] routine Available routines: Level 1 sort sort2 sort3 sort4 sort5 sort6 sort7 sort8 Level 2 bar bar2 bar3 bar4 bar5 bar6 Level 3 baz baz2 baz3 baz4 baz5 testsweeper-2024.05.31/test/ref/002.txt000066400000000000000000000011141462625314600172650ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --help Usage: ./tester [-h|--help] ./tester [-h|--help] routine ./tester [parameters] routine Available routines: Level 1 sort sort2 sort3 sort4 sort5 sort6 sort7 sort8 Level 2 bar bar2 bar3 bar4 bar5 bar6 Level 3 baz baz2 baz3 baz4 baz5 testsweeper-2024.05.31/test/ref/003.txt000066400000000000000000000017411462625314600172740ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester -h sort Usage: test [-h|--help] test [-h|--help] routine test [parameters] routine Parameters for sort: --check check the results; default y; valid: [ny] --ref run reference; sometimes check implies ref; default n; valid: [ny] --tol tolerance (e.g., error < tol*epsilon to pass); default 50 --repeat times to repeat each test; default 1 --verbose verbose level; default 0 --cache total cache size, in MiB; default 20 Parameters that take comma-separated list of values and may be repeated: --type one of: r16, h, or half; r32, s, single, or float; r64, d, or double; c32, c, or complex-float; c64, z, or complex-double; i, int, or integer; default d --dim m by n by k dimensions --nb block size; default 384 --alpha scalar alpha; default 3.1+1.4i --beta scalar beta; default 2.7 testsweeper-2024.05.31/test/ref/004.txt000066400000000000000000000017451462625314600173010ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --help sort Usage: test [-h|--help] test [-h|--help] routine test [parameters] routine Parameters for sort: --check check the results; default y; valid: [ny] --ref run reference; sometimes check implies ref; default n; valid: [ny] --tol tolerance (e.g., error < tol*epsilon to pass); default 50 --repeat times to repeat each test; default 1 --verbose verbose level; default 0 --cache total cache size, in MiB; default 20 Parameters that take comma-separated list of values and may be repeated: --type one of: r16, h, or half; r32, s, single, or float; r64, d, or double; c32, c, or complex-float; c64, z, or complex-double; i, int, or integer; default d --dim m by n by k dimensions --nb block size; default 384 --alpha scalar alpha; default 3.1+1.4i --beta scalar beta; default 2.7 testsweeper-2024.05.31/test/ref/005.txt000066400000000000000000000017571462625314600173050ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester sort SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 3.1+1.4i 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 3.1+1.4i 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/006.txt000066400000000000000000000032401462625314600172730ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --dim '100:1000:100' sort SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 3.1+1.4i 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 3.1+1.4i 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass d 600 600 600 384 3.1+1.4i 2.7 7.41e-15 --------- ------------ ---------------- ----------------- pass d 700 700 700 384 3.1+1.4i 2.7 8.64e-15 --------- ------------ ---------------- ----------------- pass d 800 800 800 384 3.1+1.4i 2.7 9.88e-15 --------- ------------ ---------------- ----------------- pass d 900 900 900 384 3.1+1.4i 2.7 1.11e-14 --------- ------------ ---------------- ----------------- FAILED d 1000 1000 1000 384 3.1+1.4i 2.7 1.23e-14 --------- ------------ ---------------- ----------------- FAILED 2 tests FAILED. testsweeper-2024.05.31/test/ref/100.txt000066400000000000000000000032331462625314600172700ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type 's,d' sort SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass s 400 400 400 384 3.1+1.4i 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass s 500 500 500 384 3.1+1.4i 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 3.1+1.4i 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 3.1+1.4i 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/101.txt000066400000000000000000000020221462625314600172640ustar00rootroot00000000000000 Error: --type: invalid datatype 'x' TestSweeper version NA, id NA input: ./tester --type 's,x,d' sort Usage: test [-h|--help] test [-h|--help] routine test [parameters] routine Parameters for sort: --check check the results; default y; valid: [ny] --ref run reference; sometimes check implies ref; default n; valid: [ny] --tol tolerance (e.g., error < tol*epsilon to pass); default 50 --repeat times to repeat each test; default 1 --verbose verbose level; default 0 --cache total cache size, in MiB; default 20 Parameters that take comma-separated list of values and may be repeated: --type one of: r16, h, or half; r32, s, single, or float; r64, d, or double; c32, c, or complex-float; c64, z, or complex-double; i, int, or integer; default d --dim m by n by k dimensions --nb block size; default 384 --alpha scalar alpha; default 3.1+1.4i --beta scalar beta; default 2.7 testsweeper-2024.05.31/test/ref/200.txt000066400000000000000000000014011462625314600172640ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100' sort2 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/201.txt000066400000000000000000000014021462625314600172660ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '300:100:-100' sort2 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass s 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/202.txt000066400000000000000000000007541462625314600173000ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim 1234 sort2 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 1234 1234 1234 384 3.1+1.4i 2.7 1.52e-14 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/203.txt000066400000000000000000000016221462625314600172740ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim 1234 --dim '100:300:100' sort2 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 1234 1234 1234 384 3.1+1.4i 2.7 1.52e-14 --------- ------------ ---------------- ----------------- pass s 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/204.txt000066400000000000000000000040271462625314600172770ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --dim '1k:4kx1ki:4ki' --dim '1M:4Mx1Mi:4Mi' --dim '1G:4Gx1Gi:4Gi' sort2 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 1000 1024 1024 384 3.1+1.4i 2.7 1.26e-14 --------- ------------ ---------------- ----------------- FAILED d 2000 2048 2048 384 3.1+1.4i 2.7 2.53e-14 --------- ------------ ---------------- ----------------- FAILED d 3000 3072 3072 384 3.1+1.4i 2.7 3.79e-14 --------- ------------ ---------------- ----------------- FAILED d 4000 4096 4096 384 3.1+1.4i 2.7 5.06e-14 --------- ------------ ---------------- ----------------- FAILED d 1000000 1048576 1048576 384 3.1+1.4i 2.7 1.29e-11 --------- ------------ ---------------- ----------------- FAILED d 2000000 2097152 2097152 384 3.1+1.4i 2.7 2.59e-11 --------- ------------ ---------------- ----------------- FAILED d 3000000 3145728 3145728 384 3.1+1.4i 2.7 3.88e-11 --------- ------------ ---------------- ----------------- FAILED d 4000000 4194304 4194304 384 3.1+1.4i 2.7 5.18e-11 --------- ------------ ---------------- ----------------- FAILED d 1000000000 1073741824 1073741824 384 3.1+1.4i 2.7 1.33e-08 --------- ------------ ---------------- ----------------- FAILED d 2000000000 2147483648 2147483648 384 3.1+1.4i 2.7 2.65e-08 --------- ------------ ---------------- ----------------- FAILED d 3000000000 3221225472 3221225472 384 3.1+1.4i 2.7 3.98e-08 --------- ------------ ---------------- ----------------- FAILED d 4000000000 4294967296 4294967296 384 3.1+1.4i 2.7 5.30e-08 --------- ------------ ---------------- ----------------- FAILED 12 tests FAILED. testsweeper-2024.05.31/test/ref/205.txt000066400000000000000000000026541462625314600173040ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --dim '1e3:4e3' --dim '1e6:4e6' sort2 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 1000 1000 1000 384 3.1+1.4i 2.7 1.23e-14 --------- ------------ ---------------- ----------------- FAILED d 2000 2000 2000 384 3.1+1.4i 2.7 2.47e-14 --------- ------------ ---------------- ----------------- FAILED d 3000 3000 3000 384 3.1+1.4i 2.7 3.70e-14 --------- ------------ ---------------- ----------------- FAILED d 4000 4000 4000 384 3.1+1.4i 2.7 4.94e-14 --------- ------------ ---------------- ----------------- FAILED d 1000000 1000000 1000000 384 3.1+1.4i 2.7 1.23e-11 --------- ------------ ---------------- ----------------- FAILED d 2000000 2000000 2000000 384 3.1+1.4i 2.7 2.47e-11 --------- ------------ ---------------- ----------------- FAILED d 3000000 3000000 3000000 384 3.1+1.4i 2.7 3.70e-11 --------- ------------ ---------------- ----------------- FAILED d 4000000 4000000 4000000 384 3.1+1.4i 2.7 4.94e-11 --------- ------------ ---------------- ----------------- FAILED 8 tests FAILED. testsweeper-2024.05.31/test/ref/206.txt000066400000000000000000000007521462625314600173020ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --nb 32 --dim 100 sort2 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 32 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/207.txt000066400000000000000000000026351462625314600173050ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --nb '32:256:32' --dim 100 sort2 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 32 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 64 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 96 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 128 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 160 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 192 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 224 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 256 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/208.txt000066400000000000000000000020721462625314600173010ustar00rootroot00000000000000 Error: --nb: invalid argument at '', expected integer or range start:end:step TestSweeper version NA, id NA input: ./tester --nb '0:5' sort2 Usage: test [-h|--help] test [-h|--help] routine test [parameters] routine Parameters for sort2: --check check the results; default y; valid: [ny] --ref run reference; sometimes check implies ref; default n; valid: [ny] --tol tolerance (e.g., error < tol*epsilon to pass); default 50 --repeat times to repeat each test; default 1 --verbose verbose level; default 0 --cache total cache size, in MiB; default 20 Parameters that take comma-separated list of values and may be repeated: --type one of: r16, h, or half; r32, s, single, or float; r64, d, or double; c32, c, or complex-float; c64, z, or complex-double; i, int, or integer; default d --dim m by n by k dimensions --nb block size; default 384 --alpha scalar alpha; default 3.1+1.4i --beta scalar beta; default 2.7 testsweeper-2024.05.31/test/ref/300.txt000066400000000000000000000014131462625314600172700ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100x50:200:50' sort3 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 150 150 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/301.txt000066400000000000000000000014161462625314600172740ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100x50:200:50x50' sort3 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 150 50 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/302.txt000066400000000000000000000014101462625314600172670ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100x100x50' sort3 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/303.txt000066400000000000000000000014241462625314600172750ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100x50:200:50x10:50:10' sort3 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 100 20 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 150 30 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/400.txt000066400000000000000000000152311462625314600172740ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100*50:200:50' sort4 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 100 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 150 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 200 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 150 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 200 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 150 50 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 100 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 150 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 200 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 200 50 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 100 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 150 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 100 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 150 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 200 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 100 150 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 100 200 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 150 50 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 150 100 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 150 150 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 150 200 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 200 50 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 200 100 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 200 150 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 100 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 150 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 200 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 100 150 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 100 200 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 150 50 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 150 100 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 150 150 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 150 200 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 200 50 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 200 100 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 200 150 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/401.txt000066400000000000000000000203521462625314600172750ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100*50:200:50*10:50:10' sort4 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 20 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 30 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 40 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 100 10 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 20 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 30 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 40 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 150 10 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 20 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 30 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 40 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 50 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 200 10 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 20 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 30 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 40 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 50 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 20 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 30 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 40 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 100 10 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 100 20 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 100 30 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 100 40 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 150 10 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 150 20 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 150 30 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 150 40 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 150 50 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 200 10 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 200 20 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 200 30 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 200 40 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 200 50 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 20 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 30 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 40 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 100 10 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 100 20 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 100 30 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 100 40 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 150 10 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 150 20 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 150 30 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 150 40 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 150 50 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 200 10 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 200 20 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 200 30 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 200 40 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 200 50 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/402.txt000066400000000000000000000057621462625314600173060ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100*50:200:50*10:50:10' sort4 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 20 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 30 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 40 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 100 10 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 20 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 30 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 40 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 100 50 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 150 10 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 20 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 30 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 40 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 150 50 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 200 10 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 20 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 30 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 40 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 100 200 50 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/403.txt000066400000000000000000000045251462625314600173030ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100*50*10:50:10' sort4 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 20 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 30 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 40 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 20 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 30 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 40 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 20 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 30 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 40 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 50 50 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/404.txt000066400000000000000000000037041462625314600173020ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --type s --dim '100:300:100*50:200:50*10' sort4 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status s 100 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 100 100 10 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 100 150 10 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 100 200 10 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 200 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 200 100 10 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 200 150 10 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 200 200 10 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass s 300 50 10 384 3.1+1.4i 2.7 6.17e-16 --------- ------------ ---------------- ----------------- pass s 300 100 10 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass s 300 150 10 384 3.1+1.4i 2.7 1.85e-15 --------- ------------ ---------------- ----------------- pass s 300 200 10 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/500.txt000066400000000000000000000017721462625314600173020ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --check y sort5 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 3.1+1.4i 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 3.1+1.4i 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/501.txt000066400000000000000000000020041462625314600172700ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --check n sort5 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 2.7 NA --------- ------------ ---------------- ----------------- no check d 200 200 200 384 3.1+1.4i 2.7 NA --------- ------------ ---------------- ----------------- no check d 300 300 300 384 3.1+1.4i 2.7 NA --------- ------------ ---------------- ----------------- no check d 400 400 400 384 3.1+1.4i 2.7 NA --------- ------------ ---------------- ----------------- no check d 500 500 500 384 3.1+1.4i 2.7 NA --------- ------------ ---------------- ----------------- no check All tests passed. testsweeper-2024.05.31/test/ref/502.txt000066400000000000000000000017701462625314600173020ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --ref y sort5 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 3.1+1.4i 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 3.1+1.4i 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/503.txt000066400000000000000000000017701462625314600173030ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --ref n sort5 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 3.1+1.4i 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 3.1+1.4i 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 3.1+1.4i 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 3.1+1.4i 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/600.txt000066400000000000000000000044751462625314600173060ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --alpha '-2,0,2' sort6 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 -2 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 0 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 2 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 -2 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 0 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 2 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 -2 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 0 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 2 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 -2 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 0 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 2 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 -2 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 0 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 2 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/601.txt000066400000000000000000000045001462625314600172740ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --alpha '-inf,0,inf' sort6 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 -inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 100 100 100 384 0 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 200 200 200 384 -inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 200 200 200 384 0 2.7 2.47e-15 --------- ------------ ---------------- ----------------- pass d 200 200 200 384 inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 300 300 300 384 -inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 300 300 300 384 0 2.7 3.70e-15 --------- ------------ ---------------- ----------------- pass d 300 300 300 384 inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 400 400 400 384 -inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 400 400 400 384 0 2.7 4.94e-15 --------- ------------ ---------------- ----------------- pass d 400 400 400 384 inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 500 500 500 384 -inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED d 500 500 500 384 0 2.7 6.17e-15 --------- ------------ ---------------- ----------------- pass d 500 500 500 384 inf 2.7 nan --------- ------------ ---------------- ----------------- FAILED 10 tests FAILED. testsweeper-2024.05.31/test/ref/602.txt000066400000000000000000000012101462625314600172700ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --alpha '1.23+2.34i,1.23-2.34i' --dim 100 sort6 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 1.2+2.3i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 1.2-2.3i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/603.txt000066400000000000000000000030531462625314600173000ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --beta '1.234:5.678:0.5' --dim 100 sort6 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 1.2 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 1.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 2.2 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 2.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 3.2 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 3.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 4.2 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 4.7 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 5.2 1.23e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/604.txt000066400000000000000000000020141462625314600172750ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --beta '2.5:12.5' --dim 100 sort6 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 2.5 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 5.0 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 7.5 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 10.0 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 12.5 1.23e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/ref/605.txt000066400000000000000000000021111462625314600172740ustar00rootroot00000000000000 Error: --beta: invalid argument at '', expected float or range start:end:step TestSweeper version NA, id NA input: ./tester --beta '0:12.5' --dim 100 sort6 Usage: test [-h|--help] test [-h|--help] routine test [parameters] routine Parameters for sort6: --check check the results; default y; valid: [ny] --ref run reference; sometimes check implies ref; default n; valid: [ny] --tol tolerance (e.g., error < tol*epsilon to pass); default 50 --repeat times to repeat each test; default 1 --verbose verbose level; default 0 --cache total cache size, in MiB; default 20 Parameters that take comma-separated list of values and may be repeated: --type one of: r16, h, or half; r32, s, single, or float; r64, d, or double; c32, c, or complex-float; c64, z, or complex-double; i, int, or integer; default d --dim m by n by k dimensions --nb block size; default 384 --alpha scalar alpha; default 3.1+1.4i --beta scalar beta; default 2.7 testsweeper-2024.05.31/test/ref/606.txt000066400000000000000000000034631462625314600173100ustar00rootroot00000000000000TestSweeper version NA, id NA input: ./tester --beta '0:12.5:1.25' --dim 100 sort6 SLATE LAPACK Reference LAPACK type m n k nb alpha beta error time (ms) gflop/s time (ms) reference gflop/s status d 100 100 100 384 3.1+1.4i 0. 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 1.2 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 2.5 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 3.8 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 5.0 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 6.2 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 7.5 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 8.8 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 10.0 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 11.2 1.23e-15 --------- ------------ ---------------- ----------------- pass d 100 100 100 384 3.1+1.4i 12.5 1.23e-15 --------- ------------ ---------------- ----------------- pass All tests passed. testsweeper-2024.05.31/test/run_tests.py000077500000000000000000000244711462625314600200650ustar00rootroot00000000000000#!/usr/bin/env python3 # # Copyright (c) 2017-2023, University of Tennessee. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause # This program is free software: you can redistribute it and/or modify it under # the terms of the BSD 3-Clause license. See the accompanying LICENSE file. from __future__ import print_function import sys import os import re import argparse import subprocess import xml.etree.ElementTree as ET import io import time #------------------------------------------------------------------------------- # command line arguments parser = argparse.ArgumentParser() parser.add_argument( '--xml', help='generate report.xml for jenkins' ) parser.add_argument( 'tests', nargs=argparse.REMAINDER ) opts = parser.parse_args() opts.tests = list( map( int, opts.tests ) ) #------------------------------------------------------------------------------- # 4 tuple: [ index, command, expected exit code=0 ] cmds = [ #---------- # Basics # # help (no input) [ 0, './tester' ], # help -h [ 1, './tester -h' ], # help --help [ 2, './tester --help' ], # routine help -h [ 3, './tester -h sort' ], # routine help --help [ 4, './tester --help sort' ], # Defaults (--type d --dim 100:500:100). [ 5, './tester sort' ], # Larger range; should elicit 2 failures (error = 1.23456e-17 * n). [ 6, './tester --dim 100:1000:100 sort', 2 ], #---------- # Types (enum) # # Specify types. [ 100, './tester --type s,d sort' ], # Invalid type x; should return error. [ 101, './tester --type s,x,d sort', 255 ], #---------- # Dimensions # # m == n == k [ 200, './tester --type s --dim 100:300:100 sort2' ], # m == n == k, descending [ 201, './tester --type s --dim 300:100:-100 sort2' ], # single dimension [ 202, './tester --type s --dim 1234 sort2' ], # multiple --dim [ 203, './tester --type s --dim 1234 --dim 100:300:100 sort2' ], # metric and binary prefix [ 204, './tester --dim 1k:4kx1ki:4ki --dim 1M:4Mx1Mi:4Mi --dim 1G:4Gx1Gi:4Gi sort2', 12 ], # ... ' --dim 1T:4Tx1Ti:4Ti --dim 1P:4Px1Pi:4Pi --dim 1E:4Ex1Ei:4Ei', 24 # exponent [ 205, './tester --dim 1e3:4e3 --dim 1e6:4e6 sort2', 8 ], # single nb [ 206, './tester --nb 32 --dim 100 sort2' ], # range nb [ 207, './tester --nb 32:256:32 --dim 100 sort2' ], # with illegal step = start = 0 [ 208, './tester --nb 0:5 sort2', 255 ], #---------- # Zip of dimensions # # m x n == k. [ 300, './tester --type s --dim 100:300:100x50:200:50 sort3' ], # m x n; k fixed. [ 301, './tester --type s --dim 100:300:100x50:200:50x50 sort3' ], # m; n, k fixed. [ 302, './tester --type s --dim 100:300:100x100x50 sort3' ], # m x n x k. [ 303, './tester --type s --dim 100:300:100x50:200:50x10:50:10 sort3' ], #---------- # Cartesian product of dimensions # # m * n == k [ 400, './tester --type s --dim 100:300:100*50:200:50 sort4' ], # m * n * k [ 401, './tester --type s --dim 100:300:100*50:200:50*10:50:10 sort4' ], # m fixed * n * k [ 402, './tester --type s --dim 100*50:200:50*10:50:10 sort4' ], # m * n fixed * k [ 403, './tester --type s --dim 100:300:100*50*10:50:10 sort4' ], # m * n * k fixed [ 404, './tester --type s --dim 100:300:100*50:200:50*10 sort4' ], #---------- # Check and ref # # check y [ 500, './tester --check y sort5' ], # check n [ 501, './tester --check n sort5' ], # ref y [ 502, './tester --ref y sort5' ], # ref n [ 503, './tester --ref n sort5' ], #---------- # Float and complex [ 600, './tester --alpha -2,0,2 sort6' ], # inf [ 601, './tester --alpha -inf,0,inf sort6', 10 ], # complex [ 602, './tester --alpha 1.23+2.34i,1.23-2.34i --dim 100 sort6' ], # float range [ 603, './tester --beta 1.234:5.678:0.5 --dim 100 sort6' ], # with step = start [ 604, './tester --beta 2.5:12.5 --dim 100 sort6' ], # with illegal step = start = 0 [ 605, './tester --beta 0:12.5 --dim 100 sort6', 255 ], # with start = 0, step != 0 [ 606, './tester --beta 0:12.5:1.25 --dim 100 sort6' ], ] #------------------------------------------------------------------------------- # When output is redirected to file instead of TTY console, # print extra messages to stderr on TTY console. # output_redirected = not sys.stdout.isatty() #------------------------------------------------------------------------------- # If output is redirected, prints to both stderr and stdout; # otherwise prints to just stdout. # def print_tee( *args ): global output_redirected print( *args ) if (output_redirected): print( *args, file=sys.stderr ) # end #------------------------------------------------------------------------------- # Used in # re.sub( pattern, strip_time_sub, line ) # where pattern matches 4 time or Gflop/s fields to replace with hyphens, # and status field to keep. # If re.sub matched line ' 3.5 4.5 12.34 5.23 pass', # this returns string ' ----- -------- ----- ----- pass' # def strip_time_sub( match ): result = '' for i in range( 1, 5 ): result += ' ' + '-' * (len( match.group( i ) ) - 2) result += ' ' + match.group( 5 ) return result # end #------------------------------------------------------------------------------- # Runs cmd. Returns exit code and output (stdout and stderr merged). # def run_test( num, cmd, expected_err=0 ): print_tee( str(num) + ': ' + cmd ) output = '' p = subprocess.Popen( cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) p_out = p.stdout if (sys.version_info.major >= 3): p_out = io.TextIOWrapper(p.stdout, encoding='utf-8') # Read unbuffered ("for line in p.stdout" will buffer). for line in iter(p_out.readline, ''): print( line, end='' ) output += line err = p.wait() if (err == expected_err): if (err == 0): print_tee( 'pass' ) else: print_tee( 'pass: got expected exit code =', err ) else: print_tee( 'FAILED: got exit code = %d, expected exit code = %d' % (err, expected_err) ) # end # Save output. outfile = 'out/%03d.txt' % (num) print( 'Saving to', outfile ) try: # Always strip out ANSI codes and version numbers. output2 = re.sub( r'\x1B\[\d+m', r'', output ) output2 = re.sub( r'version \S+, id \S+', r'version NA, id NA', output2 ) # Strip out 4 time and Gflop/s fields before status. # Using ( +(?:\d+\.\d+|inf|NA)){4} captures only 1 group, the last, # hence repeating it 4 times to capture 4 groups. output2 = re.sub( r'( +(?:\d+\.\d+|inf|NA))( +(?:\d+\.\d+|inf|NA))( +(?:\d+\.\d+|inf|NA))( +(?:\d+\.\d+|inf|NA)) +(pass|FAIL|no check)', strip_time_sub, output2 ) # end out = open( outfile, 'w' ) out.write( output2 ) out.close() except Exception as ex: print_tee( 'FAILED: ' + outfile + ': ' + str(ex) ) err = -2 # Compare with reference. reffile = 'ref/%03d.txt' % (num) print( 'Comparing to', reffile ) try: file = open( reffile ) ref = file.read() if (ref != output2): print_tee( 'FAILED: diff', outfile, reffile ) err = -1 except Exception as ex: print_tee( 'FAILED: ' + reffile + ': ' + str(ex) ) err = -2 return (err, output) # end #------------------------------------------------------------------------------- # Utility to pretty print XML. # See https://stackoverflow.com/a/33956544/1655607 # def indent_xml( elem, level=0 ): i = "\n" + level*" " if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + " " if not elem.tail or not elem.tail.strip(): elem.tail = i for elem in elem: indent_xml( elem, level+1 ) if not elem.tail or not elem.tail.strip(): elem.tail = i else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = i # end #------------------------------------------------------------------------------- # run each test start = time.time() print_tee( time.ctime() ) failed_tests = [] passed_tests = [] ntests = len(opts.tests) run_all = (ntests == 0) if (not os.path.exists( 'out' )): os.mkdir( 'out' ) seen = set() for tst in cmds: num = tst[0] cmd = tst[1] expected_err = 0 if (len( tst ) > 2): expected_err = tst[2] if (run_all or tst[0] in opts.tests): seen.add( tst[0] ) (err, output) = run_test( num, cmd, expected_err ) if (err != expected_err): failed_tests.append( (cmd, err, output) ) else: passed_tests.append( cmd ) not_seen = list( filter( lambda x: x not in seen, opts.tests ) ) if (not_seen): print_tee( 'Warning: unknown tests:', ' '.join( map( str, not_seen ))) # print summary of failures nfailed = len( failed_tests ) if (nfailed > 0): print_tee( '\n' + str(nfailed) + ' tests FAILED:\n' + '\n'.join( [x[0] for x in failed_tests] ) ) else: print_tee( '\n' + 'All tests passed.' ) # generate jUnit compatible test report if opts.xml: print( 'writing XML file', opts.xml ) root = ET.Element("testsuites") doc = ET.SubElement(root, "testsuite", name="TestSweeper_suite", tests=str(ntests), errors="0", failures=str(nfailed)) for (test, err, output) in failed_tests: testcase = ET.SubElement(doc, "testcase", name=test) failure = ET.SubElement(testcase, "failure") if (err < 0): failure.text = "exit with signal " + str(-err) else: failure.text = str(err) + " tests failed" system_out = ET.SubElement(testcase, "system-out") system_out.text = output # end for test in passed_tests: testcase = ET.SubElement(doc, 'testcase', name=test) testcase.text = 'PASSED' tree = ET.ElementTree(root) indent_xml( root ) tree.write( opts.xml ) # end elapsed = time.time() - start print_tee( 'Elapsed %.2f sec' % elapsed ) print_tee( time.ctime() ) exit( nfailed ) testsweeper-2024.05.31/test/test.cc000066400000000000000000000233641462625314600167500ustar00rootroot00000000000000// Copyright (c) 2017-2023, University of Tennessee. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // This program is free software: you can redistribute it and/or modify it under // the terms of the BSD 3-Clause license. See the accompanying LICENSE file. #include #include #include #include #include #include "test.hh" // ----------------------------------------------------------------------------- using testsweeper::ParamType; using testsweeper::DataType; using testsweeper::DataType_help; #ifdef DEPRECATED using testsweeper::char2datatype; using testsweeper::datatype2char; using testsweeper::str2datatype; using testsweeper::datatype2str; #endif using testsweeper::ansi_bold; using testsweeper::ansi_red; using testsweeper::ansi_normal; const ParamType PT_Value = ParamType::Value; const ParamType PT_List = ParamType::List; const ParamType PT_Out = ParamType::Output; const double no_data = testsweeper::no_data_flag; const char* pi_rt2i = "3.141592653589793 + 1.414213562373095i"; const char* e_rt3i = "2.718281828459045 + 1.732050807568877i"; const double pi = 3.141592653589793; const double e = 2.718281828459045; // ----------------------------------------------------------------------------- // each section must have a corresponding entry in section_names enum Section { newline = 0, // zero flag forces newline level1, level2, level3, num_sections, // last }; const char* section_names[] = { "", // none "Level 1", "Level 2", "Level 3", }; // { "", nullptr, Section::newline } entries force newline in help std::vector< testsweeper::routines_t > routines = { // Level 1 { "sort", test_sort, Section::level1 }, { "sort2", test_sort, Section::level1 }, { "sort3", test_sort, Section::level1 }, { "sort4", test_sort, Section::level1 }, { "sort5", test_sort, Section::level1 }, { "sort6", test_sort, Section::level1 }, { "sort7", test_sort, Section::level1 }, { "sort8", test_sort, Section::level1 }, // Level 2 { "bar", test_bar, Section::level2 }, { "bar2", test_bar, Section::level2 }, { "bar3", test_bar, Section::level2 }, { "", nullptr, Section::newline }, { "bar4", test_bar, Section::level2 }, { "bar5", test_bar, Section::level2 }, { "bar6", test_bar, Section::level2 }, // Level 3 { "baz", test_baz, Section::level3 }, { "baz2", test_baz, Section::level3 }, { "baz3", test_baz, Section::level3 }, { "", nullptr, Section::newline }, { "baz4", test_baz, Section::level3 }, { "baz5", test_baz, Section::level3 }, }; // ----------------------------------------------------------------------------- // Params class // List of parameters Params::Params(): ParamsBase(), // w = width // p = precision //----- test framework parameters // name, w, type, default, valid, help check ( "check", 0, PT_Value, 'y', "ny", "check the results" ), ref ( "ref", 0, PT_Value, 'n', "ny", "run reference; sometimes check implies ref" ), // name, w, p, type, default, min, max, help tol ( "tol", 0, 0, PT_Value, 50, 1, 1000, "tolerance (e.g., error < tol*epsilon to pass)" ), repeat ( "repeat", 0, PT_Value, 1, 1, 1000, "times to repeat each test" ), verbose ( "verbose", 0, PT_Value, 0, 0, 10, "verbose level" ), cache ( "cache", 0, PT_Value, 20, 1, 1024, "total cache size, in MiB" ), //----- routine parameters, enums #ifdef DEPRECATED // name, w, type, default; char2enum, enum2char, enum2str, help datatype_old ( "type-old", 4, PT_List, DataType::Double, char2datatype, datatype2char, datatype2str, DataType_help ), // name, w, type, default; str2enum, enum2str, help datatype_old2 ( "type-old2", 4, PT_List, DataType::Double, str2datatype, datatype2str, DataType_help ), #endif // name, w, type, default, help datatype ( "type", 4, PT_List, DataType::Double, DataType_help ), //----- routine parameters, numeric // name, w, p, type, default, min, max, help dim ( "dim", 6, PT_List, 0, 1e10, "m by n by k dimensions" ), nb ( "nb", 4, PT_List, 384, 0, 1e6, "block size" ), alpha ( "alpha", 3, 1, PT_List, pi_rt2i, -inf, inf, "scalar alpha" ), beta ( "beta", 3, 1, PT_List, e, -inf, inf, "scalar beta" ), grid ( "grid", 3, PT_List, "1x1", 0, 1e6, "MPI grid p by q dimensions" ), //----- output parameters // min, max are ignored // error: %8.2e allows 9.99e-99 // time: %9.3f allows 99999.999 s = 2.9 days // gflops: %12.3f allows 99999999.999 Gflop/s = 100 Pflop/s // name, w, p, type, default, min, max, help error ( "error", 8, 2, PT_Out, no_data, 0, 0, "numerical error" ), ortho ( "orth.", 8, 2, PT_Out, no_data, 0, 0, "orthogonality error" ), time ( "time (s)", 9, 3, PT_Out, no_data, 0, 0, "time to solution" ), gflops ( "gflop/s", 12, 3, PT_Out, no_data, 0, 0, "Gflop/s rate" ), ref_time ( "ref time (s)", 9, 3, PT_Out, no_data, 0, 0, "reference time to solution" ), ref_gflops( "ref gflop/s", 12, 3, PT_Out, no_data, 0, 0, "reference Gflop/s rate" ), // default -1 means "no check" // name, w, type, default, min, max, help okay ( "status", 6, PT_Out, -1, 0, 0, "success indicator" ), msg ( "", 1, PT_Out, "", "error message" ) { // mark standard set of output fields as used okay(); error(); time(); // mark framework parameters as used, so they will be accepted on the command line check(); tol(); repeat(); verbose(); cache(); // routine's parameters are marked by the test routine; see main } // ----------------------------------------------------------------------------- int main( int argc, char** argv ) { using testsweeper::QuitException; // These may or may not be used; mark unused to silence warnings. #define unused( var ) ((void)var) unused( pi_rt2i ); unused( e_rt3i ); unused( pi ); unused( e ); // check that all sections have names assert( sizeof(section_names)/sizeof(*section_names) == Section::num_sections ); int status = 0; try { int version = testsweeper::version(); printf( "TestSweeper version %d.%02d.%02d, id %s\n", version / 10000, (version % 10000) / 100, version % 100, testsweeper::id() ); // print input so running `test [input] > out.txt` documents input printf( "input: %s", argv[0] ); for (int i = 1; i < argc; ++i) { // quote arg if necessary std::string arg( argv[i] ); const char* wordchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-="; if (arg.find_first_not_of( wordchars ) != std::string::npos) printf( " '%s'", argv[i] ); else printf( " %s", argv[i] ); } printf( "\n" ); // Usage: test [params] routine if (argc < 2 || strcmp( argv[argc-1], "-h" ) == 0 || strcmp( argv[argc-1], "--help" ) == 0) { usage( argc, argv, routines, section_names ); throw QuitException(); } // find routine to test const char* routine = argv[ argc-1 ]; testsweeper::test_func_ptr test_routine = find_tester( routine, routines ); if (test_routine == nullptr) { usage( argc, argv, routines, section_names ); throw std::runtime_error( std::string("routine ") + routine + " not found" ); } // mark fields that are used (run=false) Params params; test_routine( params, false ); // parse parameters up to routine name try { params.parse( routine, argc-2, argv+1 ); } catch (const std::exception& ex) { params.help( routine ); throw; } // run tests int repeat = params.repeat(); testsweeper::DataType last = params.datatype(); params.header(); do { if (params.datatype() != last) { last = params.datatype(); printf( "\n" ); } for (int iter = 0; iter < repeat; ++iter) { try { test_routine( params, true ); } catch (const std::exception& ex) { fprintf( stderr, "%s%sError: %s%s\n", ansi_bold, ansi_red, ex.what(), ansi_normal ); params.okay() = false; } params.print(); status += ! params.okay(); params.reset_output(); } if (repeat > 1) { printf( "\n" ); } } while( params.next() ); if (status) { printf( "%d tests FAILED.\n", status ); } else { printf( "All tests passed.\n" ); } } catch (const QuitException& ex) { // pass: no error to print } catch (const std::exception& ex) { fprintf( stderr, "\n%s%sError: %s%s\n", ansi_bold, ansi_red, ex.what(), ansi_normal ); status = -1; } return status; } testsweeper-2024.05.31/test/test.hh000066400000000000000000000043001462625314600167470ustar00rootroot00000000000000// Copyright (c) 2017-2023, University of Tennessee. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // This program is free software: you can redistribute it and/or modify it under // the terms of the BSD 3-Clause license. See the accompanying LICENSE file. #ifndef TEST_HH #define TEST_HH #include "testsweeper.hh" //------------------------------------------------------------------------------ class Params: public testsweeper::ParamsBase { public: const double inf = std::numeric_limits::infinity(); const double nan = std::numeric_limits::quiet_NaN(); Params(); // Field members are explicitly public. // Order here determines output order. //----- test framework parameters testsweeper::ParamChar check; testsweeper::ParamChar ref; testsweeper::ParamDouble tol; testsweeper::ParamInt repeat; testsweeper::ParamInt verbose; testsweeper::ParamInt cache; //----- routine parameters, enums #ifdef DEPRECATED testsweeper::ParamEnum< testsweeper::DataType > datatype_old; testsweeper::ParamEnum< testsweeper::DataType > datatype_old2; #endif testsweeper::ParamEnum< testsweeper::DataType > datatype; //----- routine parameters, numeric testsweeper::ParamInt3 dim; testsweeper::ParamInt nb; testsweeper::ParamComplex alpha; testsweeper::ParamDouble beta; testsweeper::ParamInt3 grid; //----- output parameters testsweeper::ParamScientific error; testsweeper::ParamScientific ortho; testsweeper::ParamDouble time; testsweeper::ParamDouble gflops; testsweeper::ParamDouble ref_time; testsweeper::ParamDouble ref_gflops; testsweeper::ParamOkay okay; testsweeper::ParamString msg; }; //------------------------------------------------------------------------------ // Level 1 void test_sort( Params& params, bool run ); //------------------------------------------------------------------------------ // Level 2 void test_bar( Params& params, bool run ); //------------------------------------------------------------------------------ // Level 3 void test_baz( Params& params, bool run ); #endif // #ifndef TEST_HH testsweeper-2024.05.31/test/test_sort.cc000066400000000000000000000165111462625314600200130ustar00rootroot00000000000000// Copyright (c) 2017-2023, University of Tennessee. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // This program is free software: you can redistribute it and/or modify it under // the terms of the BSD 3-Clause license. See the accompanying LICENSE file. #include "test.hh" // ----------------------------------------------------------------------------- /// An enum class without to_string, from_string. enum class EnumOld { a, b, c }; // ----------------------------------------------------------------------------- /// An enum class with wrong to_string, from_string. enum class EnumOld2 { a, b, c }; const char* to_string( EnumOld2 value ) { return "value"; } void from_string( std::string const& str, EnumOld2 value ) { } // ----------------------------------------------------------------------------- /// An enum class with to_string, from_string. enum class EnumNew { x, y, z }; std::string to_string( EnumNew value ) { return "value"; } void from_string( std::string const& str, EnumNew* value ) { *value = EnumNew::x; } // ----------------------------------------------------------------------------- // traits class maps data type to real_t and scalar_t. // for float, double: // norm and scalar are float, double, respectively. template class traits { public: typedef T real_t; typedef T scalar_t; }; // for std::complex, std::complex: // norm is float, double, respectively; // scalar is std::complex, std::complex, respectively. template class traits< std::complex > { public: typedef T real_t; typedef std::complex scalar_t; }; // ----------------------------------------------------------------------------- // Example function to test. // In this case, it sorts the vector x, using C++ std::sort. // template void my_sort( std::vector& x ) { std::sort( x.begin(), x.end() ); } // ----------------------------------------------------------------------------- // Comparison function for qsort. Returns negative, zero, or positive // if x is less than, equal to, or greater than y, respectively. // template int compare( const void* x, const void* y ) { T x_ = ((T*)x)[0]; T y_ = ((T*)y)[0]; return (x_ < y_ ? -1 : x_ == y_ ? 0 : 1); } // ----------------------------------------------------------------------------- // Example function to test -- reference implementation. // In this case, it sorts the vector x, using C's qsort. // template void ref_sort( std::vector& x ) { qsort( &x[0], x.size(), sizeof(T), compare ); } // ----------------------------------------------------------------------------- // Print vector. // template void print( const char* label, std::vector& x ) { printf( "%s = [\n", label ); for (auto x_i: x) { printf( " %9.6f\n", x_i ); } printf( "];\n" ); } // ----------------------------------------------------------------------------- template void test_sort_work( Params ¶ms, bool run ) { using llong = long long; using testsweeper::get_wtime; typedef typename traits::real_t real_t; // get & mark input and non-standard output values int64_t nb = params.nb(); int64_t m = params.dim.m(); int64_t n = params.dim.n(); int64_t k = params.dim.k(); int64_t cache = params.cache(); int verbose = params.verbose(); bool check = (params.check() == 'y'); bool ref = (params.ref() == 'y') || check; // check requires ref scalar_t alpha = params.alpha.get(); real_t beta = params.beta(); (void) nb; // Mark as unused. // mark non-standard output values params.gflops(); params.ref_time(); params.ref_gflops(); // adjust header to msec params.time.name( "SLATE\ntime (ms)" ); params.gflops.name( "gflop/s" ); params.ref_time.name( "LAPACK Reference\ntime (ms)" ); params.ref_gflops.name( "LAPACK\nreference gflop/s" ); assert( params.time.width() == 9 ); // default width assert( params.gflops.width() == 12 ); // default width assert( params.ref_time.width() == 16 ); // LAPACK Reference (1st line) assert( params.ref_gflops.width() == 17 ); // reference gflop/s (2nd line) if (! run) return; //---------- // Test has_to_string, has_from_string static_assert( ! testsweeper::has_to_string::value ); static_assert( ! testsweeper::has_from_string::value ); static_assert( ! testsweeper::has_to_string::value ); static_assert( ! testsweeper::has_from_string::value ); static_assert( testsweeper::has_to_string::value ); static_assert( testsweeper::has_from_string::value ); // ---------- // setup int64_t imax = 100000; size_t len = std::min( m, imax ) + std::min( n, imax ) + std::min( k, imax ); std::vector x( len ); for (auto& x_i: x) { x_i = rand() / double(RAND_MAX) + std::abs( alpha ) + beta; } std::vector x_ref = x; // copy if (verbose >= 2) { print( "x_in", x ); } double time; double gflop = len * log2( len ) * 1e-9; // run test testsweeper::flush_cache( cache ); time = get_wtime(); my_sort( x ); time = get_wtime() - time; params.time() = time * 1000; // msec params.gflops() = gflop / time; if (verbose >= 2) { print( "x_out", x ); } if (ref) { // run reference testsweeper::flush_cache( cache ); time = get_wtime(); ref_sort( x_ref ); // reference implementation time = get_wtime() - time; params.ref_time() = time * 1000; // msec params.ref_gflops() = gflop / time; if (verbose >= 2) { print( "x_ref", x_ref ); } } // check error if (check) { real_t error = 0; error = 1.23456e-17 * n; // placeholder; fails for n >= 900 for (size_t i = 0; i < len; ++i) { error += std::abs( x[i] - x_ref[i] ); } real_t eps = std::numeric_limits< real_t >::epsilon(); real_t tol = params.tol() * eps; params.error() = error; params.okay() = (error < tol); } } // ----------------------------------------------------------------------------- void test_sort( Params ¶ms, bool run ) { switch (params.datatype()) { case testsweeper::DataType::Single: test_sort_work< float >( params, run ); break; case testsweeper::DataType::Double: test_sort_work< double >( params, run ); break; case testsweeper::DataType::SingleComplex: test_sort_work< std::complex >( params, run ); break; case testsweeper::DataType::DoubleComplex: test_sort_work< std::complex >( params, run ); break; default: throw std::runtime_error( "unknown datatype: " + to_string( params.datatype() ) ); break; } } // ----------------------------------------------------------------------------- void test_bar( Params ¶ms, bool run ) { test_sort( params, run ); } // ----------------------------------------------------------------------------- void test_baz( Params ¶ms, bool run ) { test_sort( params, run ); } testsweeper-2024.05.31/testsweeper.cc000066400000000000000000001162121462625314600173570ustar00rootroot00000000000000// Copyright (c) 2017-2023, University of Tennessee. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // This program is free software: you can redistribute it and/or modify it under // the terms of the BSD 3-Clause license. See the accompanying LICENSE file. #include #include #include #include #include // prefer OpenMP get_wtime; else use gettimeofday #ifdef _OPENMP #include #else #include #endif #include "testsweeper.hh" namespace testsweeper { //================================================== // Copied from blaspp/include/blas/util.hh // ----------------------------------------------------------------------------- // for any combination of types, determine associated real, scalar, // and complex types. // // real_type< float > is float // real_type< float, double, complex > is double // // complex_type< float > is complex // complex_type< float, double > is complex // complex_type< float, double, complex > is complex // for zero types template struct real_type_traits; // define real_type<> type alias template using real_type = typename real_type_traits< Types... >::real_t; // define complex_type<> type alias template using complex_type = std::complex< real_type< Types... > >; // for one type template struct real_type_traits { using real_t = T; }; // for one complex type, strip complex template struct real_type_traits< std::complex > { using real_t = T; }; //================================================== //------------------------------------------------------------------------------ // Global constants // numeric flag indicating no data; printed as "NA" instead of "nan" double no_data_flag = nan("1234"); // ----------------------------------------------------------------------------- // ANSI color codes - enabled by default #ifndef NO_COLOR const char *ansi_esc = "\x1b["; const char *ansi_red = "\x1b[31m"; const char *ansi_green = "\x1b[92m"; const char *ansi_blue = "\x1b[34m"; const char *ansi_cyan = "\x1b[36m"; const char *ansi_magenta = "\x1b[35m"; const char *ansi_yellow = "\x1b[33m"; const char *ansi_white = "\x1b[37m"; const char *ansi_gray = "\x1b[90m"; // "bright black" const char *ansi_bold = "\x1b[1m"; const char *ansi_normal = "\x1b[0m"; #else const char *ansi_esc = ""; const char *ansi_red = ""; const char *ansi_green = ""; const char *ansi_blue = ""; const char *ansi_cyan = ""; const char *ansi_magenta = ""; const char *ansi_yellow = ""; const char *ansi_white = ""; const char *ansi_gray = ""; const char *ansi_bold = ""; const char *ansi_normal = ""; #endif //------------------------------------------------------------------------------ const char* DataType_help = "one of:" " r16, h, or half;" " r32, s, single, or float;" " r64, d, or double;" " c32, c, or complex-float;" " c64, z, or complex-double;" " i, int, or integer"; // ----------------------------------------------------------------------------- // static class variables std::vector< ParamBase* > ParamBase::s_params; // ----------------------------------------------------------------------------- // Compare a == b, bitwise. Returns true if a and b are both the same NaN value, // unlike (a == b) which is false for NaNs. bool same( double a, double b ) { return (memcmp( &a, &b, sizeof(double) ) == 0); } // ----------------------------------------------------------------------------- /// Throws a std::runtime_error, using a printf-formatted message in format /// and subsequent arguments. void throw_error( const char* format, ... ) { char msg[1000]; va_list va; va_start( va, format ); vsnprintf( msg, sizeof(msg), format, va ); throw std::runtime_error( msg ); } //------------------------------------------------------------------------------ /// Scan string for metric or binary prefix and return multiplier. /// E.g., for "k" returns 1000, for "Ki" returns 1024. /// If no prefix is recognized, returns 1. /// Also recognizes exponents "eN" for integer N >= 0. /// /// metric | binary /// -----------------------|---------------------------- /// k: kilo 1000 = 1e3 | Ki: kibi kilobinary 1024 /// M: mega 1000^2 = 1e6 | Mi: mebi megabinary 1024^2 /// G: giga 1000^3 = 1e9 | Gi: gibi gigabinary 1024^3 /// T: tera 1000^4 = 1e12 | Ti: tebi terabinary 1024^4 /// P: peta 1000^5 = 1e15 | Pi: pebi petabinary 1024^5 /// E: exa 1000^6 = 1e18 | Ei: exbi exabinary 1024^6 /// /// @param[in,out] pstr /// Pointer to string to scan. /// On exit, updated to point after any prefix that was scanned. /// /// @return multiplier /// int64_t scan_multiplier( const char **pstr ) { const int64_t i1024 = 1024; int exponent, bytes; // Metric is lowercase k, but IEC is uppercase Ki for binary; // ignore case for k only. if (tolower(**pstr) == 'k') { *pstr += 1; if (**pstr == 'i') { *pstr += 1; return i1024; } else { return 1e3; } } else if (**pstr == 'M') { *pstr += 1; if (**pstr == 'i') { *pstr += 1; return i1024 * i1024; } else { return 1e6; } } else if (**pstr == 'G') { *pstr += 1; if (**pstr == 'i') { *pstr += 1; return i1024 * i1024 * i1024; } else { return 1e9; } } else if (**pstr == 'T') { *pstr += 1; if (**pstr == 'i') { *pstr += 1; return i1024 * i1024 * i1024 * i1024; } else { return 1e12; } } else if (**pstr == 'P') { *pstr += 1; if (**pstr == 'i') { *pstr += 1; return i1024 * i1024 * i1024 * i1024 * i1024; } else { return 1e15; } } else if (**pstr == 'E') { *pstr += 1; if (**pstr == 'i') { *pstr += 1; return i1024 * i1024 * i1024 * i1024 * i1024 * i1024; } else { return 1e18; } } else if (sscanf( *pstr, "e%d%n", &exponent, &bytes ) == 1) { // pow() function can lead to undesireable rounding, 1e6 = 999999, // so multiply with loop. *pstr += bytes; int64_t mul = 1; for (int i = 0; i < exponent; ++i) mul *= 10; return mul; } else { return 1; } } ///----------------------------------------------------------------------------- /// Scans string for single integer or range of integers (start:end:step). /// Advances the string to after the range or number. /// /// @param[in,out] pstr: pointer to string containing an integer or range. /// On output, advanced to after the number or range. /// @param[out] start: start of range /// @param[out] end: end of range /// @param[out] step: step size; default is start; 0 if start = end. /// /// @retval 1: failure /// @retval 0: success /// int scan_range( const char** pstr, int64_t* start, int64_t* end, int64_t* step ) { long long start_ = 0, end_ = 0, step_ = 0; int bytes; const char* str = *pstr; // cnt of numbers scanned (start, end, step). int cnt = 0; // Start number. int info = sscanf( str, "%lld %n", &start_, &bytes ); if (info == 1) { cnt += 1; str += bytes; start_ *= scan_multiplier( &str ); // End number. info = sscanf( str, " : %lld %n", &end_, &bytes ); if (info == 1) { cnt += 1; str += bytes; end_ *= scan_multiplier( &str ); // Step number. info = sscanf( str, " : %lld %n", &step_, &bytes ); if (info == 1) { cnt += 1; str += bytes; step_ *= scan_multiplier( &str ); } } } *pstr = str; *start = start_; *end = end_; *step = step_; if (cnt == 3) { if (*start == *end) *step = 0; } else if (cnt == 2) { if (*start == *end) *step = 0; else *step = *start; } else if (cnt == 1) { *end = *start; *step = 0; } else { return 1; // failure } return ! ((*step == 0 && *start == *end) || (*step > 0 && *start < *end) || (*step < 0 && *start > *end)); } ///----------------------------------------------------------------------------- /// Scans string for a double or range of doubles (start:end:step). /// Advances the string to after the number or range. /// /// @param[in,out] pstr: pointer to string containing a double or range. /// On output, advanced to after the number or range. /// @param[out] start: start of range /// @param[out] end: end of range /// @param[out] step: step size; default is start; 0 if start = end. /// /// @retval 1: failure /// @retval 0: success /// int scan_range( const char** pstr, double* start, double* end, double* step ) { int bytes1, bytes2, bytes3, cnt; cnt = sscanf( *pstr, "%lf %n: %lf %n: %lf %n", start, &bytes1, end, &bytes2, step, &bytes3 ); if (cnt == 3) { if (*start == *end) *step = 0; *pstr += bytes3; } else if (cnt == 2) { *pstr += bytes2; if (*start == *end) *step = 0; else *step = *start; } else if (cnt == 1) { *pstr += bytes1; *end = *start; *step = 0; } else { return 1; // failure } return ! ((*step == 0 && *start == *end) || (*step > 0 && *start < *end) || (*step < 0 && *start > *end)); } // ----------------------------------------------------------------------------- // Flushes cache by allocating buffer of 2*cache size (in MiB), // and writing it in parallel. void flush_cache( size_t cache_size ) { size_t len = 2 * cache_size * 1024 * 1024; unsigned char *buf = (unsigned char*) malloc( len ); int nthread = 1; #pragma omp parallel #pragma omp master { #ifdef _OPENMP nthread = omp_get_num_threads(); #endif } size_t per_core = len / nthread; #pragma omp parallel { int tid = 0; #ifdef _OPENMP tid = omp_get_thread_num(); #endif for (size_t i = tid * per_core; i < (tid + 1) * per_core; ++i) { buf[i] = i % 256; } } free( buf ); } // ============================================================================= // ParamBase class // ----------------------------------------------------------------------------- // if name has \n, for line=0, print 1st line; for line=1, print 2nd line. // otherwise, for line=0, print blank; for line=1, print name. // virtual void ParamBase::header( int line ) const { if (used_ && width_ > 0) { size_t i = name_.find( '\n' ); std::string str; if (i != std::string::npos) { str = (line == 0 ? name_.substr( 0, i ).c_str() : name_.substr( i+1 ).c_str() ); } else { str = (line == 0 ? "" : name_.c_str() ); } printf( "%*s ", width_, str.c_str() ); } } // ----------------------------------------------------------------------------- // virtual void ParamBase::help() const { if (type_ == ParamType::Value || type_ == ParamType::List) { printf( " %-16s %s\n", option_.c_str(), help_.c_str() ); } } // ----------------------------------------------------------------------------- // virtual bool ParamBase::next() { assert( index_ >= 0 && index_ < size() ); if (index_ == size() - 1) { index_ = 0; return false; } else { index_ += 1; return true; } } // ============================================================================= // ParamInt class // Integer parameters // ----------------------------------------------------------------------------- // virtual void ParamInt::parse( const char *str ) { while (true) { int64_t start, end, step; if (scan_range( &str, &start, &end, &step ) != 0) { throw_error( "invalid argument at '%s'," " expected integer or range start:end:step", str ); } if (start == end) { push_back( start ); } else { for (int64_t val = start; val <= end; val += step) { push_back( val ); } } if (*str == '\0') { break; } if (*str != ',' && *str != ';') { throw_error( "invalid argument at '%s', expected comma", str ); } str += 1; } } // ----------------------------------------------------------------------------- void ParamInt::push_back( int64_t val ) { if (val < min_value_ || val > max_value_) { throw_error( "invalid argument, %lld outside [%lld, %lld]", (long long) val, (long long) min_value_, (long long) max_value_ ); } TParamBase::push_back( val ); } // ----------------------------------------------------------------------------- // virtual void ParamInt::print() const { if (used_ && width_ > 0) { printf( "%*lld ", width_, (long long) values_[ index_ ] ); } } // ----------------------------------------------------------------------------- // virtual void ParamInt::help() const { if (type_ == ParamType::Value || type_ == ParamType::List) { printf( " %-16s %s; default %lld\n", option_.c_str(), help_.c_str(), (long long) default_value_ ); } } // ============================================================================= // ParamOkay class // same as ParamInt, but prints pass (for non-zero) or FAILED (for zero). // ----------------------------------------------------------------------------- // virtual void ParamOkay::print() const { if (used_ && width_ > 0) { const char *msg = ""; switch (values_[ index_ ]) { case 0: msg = "FAILED"; break; case 1: msg = "pass"; break; case -1: msg = "no check"; break; } printf( "%-*s ", width_, msg ); } } // ============================================================================= // ParamInt3 class // Integer 3-tuple parameters for M x N x K dimensions // ----------------------------------------------------------------------------- // virtual void ParamInt3::parse( const char *str ) { int64_t m_start, m_end, m_step; int64_t n_start, n_end, n_step; int64_t k_start, k_end, k_step; int len; while (true) { // scan M if (scan_range( &str, &m_start, &m_end, &m_step ) != 0) { throw_error( "invalid m dimension at '%s', " "expected integer or range start:end:step", str ); } // if "*", use Cartesian product // if "x", use "inner" product // if "*" or "x", scan N; else K = N = M len = 0; bool cartesian = false; sscanf( str, " * %n", &len ); if (len > 0) cartesian = true; else sscanf( str, " x %n", &len ); if (len > 0) { str += len; if (scan_range( &str, &n_start, &n_end, &n_step ) != 0) { throw_error( "invalid n dimension at '%s', " "expected integer or range start:end:step", str ); } // if "*" or "x", scan K; else K = N len = 0; if (cartesian) sscanf( str, " * %n", &len ); else sscanf( str, " x %n", &len ); if (len > 0) { str += len; if (scan_range( &str, &k_start, &k_end, &k_step ) != 0) { throw_error( "invalid k dimension at '%s', " "expected integer or range start:end:step", str ); } } else { k_start = n_start; k_end = n_end; k_step = n_step; } } else { k_start = n_start = m_start; k_end = n_end = m_end; k_step = n_step = m_step; } if (m_start == m_end && n_start == n_end && k_start == k_end) { // single size int3_t dim = { m_start, n_start, k_start }; push_back( dim ); } else if (cartesian) { // Cartesian product of M x N x K // require non-zero step if (m_step == 0) m_step = 1; if (n_step == 0) n_step = 1; if (k_step == 0) k_step = 1; for (int64_t m = m_start; (m_step >= 0 ? m <= m_end : m >= m_end); m += m_step) { for (int64_t n = n_start; (n_step >= 0 ? n <= n_end : n >= n_end); n += n_step) { for (int64_t k = k_start; (k_step >= 0 ? k <= k_end : k >= k_end); k += k_step) { int3_t dim = { m, n, k }; push_back( dim ); } } } } else { // inner product of M x N x K // at least one of the variables must advance assert( m_step != 0 || n_step != 0 || k_step != 0 ); for (int64_t m = m_start, n = n_start, k = k_start; (m_step >= 0 ? m <= m_end : m >= m_end) && (n_step >= 0 ? n <= n_end : n >= n_end) && (k_step >= 0 ? k <= k_end : k >= k_end); m += m_step, n += n_step, k += k_step) { int3_t dim = { m, n, k }; push_back( dim ); } } if (*str == '\0') { break; } if (*str != ',' && *str != ';') { throw_error( "invalid argument at '%s', expected comma", str ); } str += 1; } } // ----------------------------------------------------------------------------- void ParamInt3::push_back( int3_t val ) { if (val.m < min_value_ || val.m > max_value_ || val.n < min_value_ || val.n > max_value_ || val.k < min_value_ || val.k > max_value_) { throw_error( "invalid value, %lld x %lld x %lld outside [%lld, %lld]", (long long) val.m, (long long) val.n, (long long) val.k, (long long) min_value_, (long long) max_value_ ); } TParamBase::push_back( val ); } // ----------------------------------------------------------------------------- // virtual void ParamInt3::print() const { if (width_ > 0) { if (used_ & m_mask) { printf( "%*lld ", width_, (long long) values_[ index_ ].m ); } if (used_ & n_mask) { printf( "%*lld ", width_, (long long) values_[ index_ ].n ); } if (used_ & k_mask) { printf( "%*lld ", width_, (long long) values_[ index_ ].k ); } } } // ----------------------------------------------------------------------------- // for line=0, print blanks // for line=1, print whichever of m, n, k are used // virtual void ParamInt3::header( int line ) const { if (width_ > 0) { if (used_ & m_mask) { printf( "%*s ", width_, (line == 0 ? "" : m_name_.c_str()) ); } if (used_ & n_mask) { printf( "%*s ", width_, (line == 0 ? "" : n_name_.c_str()) ); } if (used_ & k_mask) { printf( "%*s ", width_, (line == 0 ? "" : k_name_.c_str()) ); } } } // ============================================================================= // ParamComplex class // ----------------------------------------------------------------------------- // Scans single real or complex value and lists of values. // std::complex ParamComplex::scan_complex( const char** str ) { char op, suffix; double x, y; std::complex value; int cnt, bytes1, bytes2, bytes3; cnt = sscanf( *str, "%lf %n %c %n %lf%c %n", &x, &bytes1, &op, &bytes2, &y, &suffix, &bytes3 ); if (cnt == 4 && (op == '+' || op == '-') && suffix == 'i') { // x+yi or x-yi complex value if (op == '+') value = std::complex( x, y ); else value = std::complex( x, -y ); *str += bytes3; } else if (cnt == 2 && op == 'i') { // xi imaginary value value = std::complex( 0, x ); *str += bytes2; } else if (cnt == 1) { // x real value value = x; *str += bytes1; } else if (cnt > 1 && op == ',') { //handles case of two real values "2.34,1.11", or real and img "2.34,1.11i" // x real value value = x; *str += bytes2 - 1; //leave comma } else { std::string err = std::string("invalid value '") + *str + "'; expected format like '1.2' or '1.2+3.4i'"; throw std::runtime_error( err ); } return value; } // ----------------------------------------------------------------------------- // virtual void ParamComplex::parse( const char *str ) { //printf("ParamComplex::parse\n"); while (true) { std::complex val = scan_complex( &str ); TParamBase< std::complex >::push_back( val ); if (*str == '\0') { break; } if (*str != ',' && *str != ';') { throw_error( "invalid argument at '%s', expected comma", str ); } str += 1; } } //------------------------------------------------------------------------------ // Output the entire field in a fixed width W, // different than the width passed here. W = 2*width + 3, // to account for initial -, [+-] between real & complex parts, and i at end. // For instance, print calls snprintf_value with width=4, precision=2, // and then prints the resulting string in a field width 11 (%-11s). // template const char* snprintf_value( char* buf, size_t buf_len, int width, int precision, scalar_t value) { using real_t = real_type; real_t re = std::real( value ); real_t im = std::imag( value ); if (re == int(re) && im == int(im)) { // exactly integer, print without digits after decimal point if (im != 0) { snprintf(buf, buf_len, "% *.0f%c%.0fi", width - precision, re, (im >= 0 ? '+' : '-'), std::abs(im)); } else { snprintf(buf, buf_len, "% *.0f%*s", width - precision, re, precision, ""); } } else { // general case if (im != 0) { snprintf(buf, buf_len, "% *.*f%c%.*fi", width, precision, re, (im >= 0 ? '+' : '-'), precision, std::abs(im)); } else { snprintf(buf, buf_len, "% *.*f", width, precision, re); } } return buf; } // ----------------------------------------------------------------------------- /// If field has been used, prints the value. /// If value is set to no_data_flag, it prints "NA". /// The output width and precision are set in the constructor. // virtual void ParamComplex::print() const { char buf[ 1000 ]; if (used_ && display_width_ > 0) { if (same( no_data_flag, values_[ index_ ].real() )) { //TODO: check also for imaginary? printf( "%*s ", display_width_, "NA" ); } else { snprintf_value( buf, sizeof(buf), display_width_, precision_, values_[ index_ ] ); printf( "%-*s ", width_, buf); } } } // ----------------------------------------------------------------------------- // virtual void ParamComplex::help() const { if (type_ == ParamType::Value || type_ == ParamType::List) { printf( " %-16s %s; default ", option_.c_str(), help_.c_str() ); if (same( no_data_flag, default_value_.real() )) { printf( "NA\n" ); } else { char buf[ 1000 ]; snprintf_value( buf, sizeof(buf), display_width_, precision_, default_value_ ); printf( "%s\n", buf ); } } } // ============================================================================= // ParamDouble class // Double precision parameter // ----------------------------------------------------------------------------- // virtual void ParamDouble::parse( const char *str ) { double start = 0, end = 0, step = 0; while (true) { if (scan_range( &str, &start, &end, &step ) != 0) { throw_error( "invalid argument at '%s', " "expected float or range start:end:step", str ); } if (start == end) { push_back( start ); } else { end += step / 10.; // avoid rounding issues for (double val = start; val <= end; val += step) { push_back( val ); } } if (*str == '\0') { break; } if (*str != ',' && *str != ';') { throw_error( "invalid argument at '%s', expected comma", str ); } str += 1; } } // ----------------------------------------------------------------------------- void ParamDouble::push_back( double val ) { if (val < min_value_ || val > max_value_) { throw_error( "invalid argument, %.*f outside [%.*f, %.*f]", precision_, val, precision_, min_value_, precision_, max_value_ ); } TParamBase::push_back( val ); } // ----------------------------------------------------------------------------- /// If field has been used, prints the floating point value. /// If value is set to no_data_flag, it prints "NA". /// If value < 1, it prints with precision (p) significant digits (%.pg). /// Otherwise, it prints with precision (p) digits after the decimal point (%.pf). /// The output width and precision are set in the constructor. // virtual void ParamDouble::print() const { if (used_ && width_ > 0) { if (same( no_data_flag, values_[ index_ ] )) { printf( "%*s ", width_, "NA" ); } else { if (std::abs( values_[ index_ ] ) < 1) printf( "%#*.*g ", width_, precision_, values_[ index_ ] ); else printf( "%*.*f ", width_, precision_, values_[ index_ ] ); } } } // ----------------------------------------------------------------------------- // virtual void ParamDouble::help() const { if (type_ == ParamType::Value || type_ == ParamType::List) { printf( " %-16s %s; default ", option_.c_str(), help_.c_str() ); if (same( no_data_flag, default_value_ )) { printf( "NA\n" ); } else { printf( "%.*f\n", precision_, default_value_ ); } } } // ============================================================================= // ParamScientific class // same as ParamDouble, but prints using scientific notation (%e) // ----------------------------------------------------------------------------- // virtual void ParamScientific::print() const { if (used_ && width_ > 0) { if (same( no_data_flag, values_[ index_ ] )) { printf( "%*s ", width_, "NA" ); } else { printf( "%*.*e ", width_, precision_, values_[ index_ ] ); } } } // ----------------------------------------------------------------------------- // virtual void ParamScientific::help() const { if (type_ == ParamType::Value || type_ == ParamType::List) { printf( " %-16s %s; default ", option_.c_str(), help_.c_str() ); if (same( no_data_flag, default_value_ )) { printf( "NA\n" ); } else { printf( "%.*e\n", precision_, default_value_ ); } } } // ============================================================================= // ParamString class // String parameters // ----------------------------------------------------------------------------- // Return true if str is in the list of valid strings. // If no valid strings are set, always returns true. bool ParamString::is_valid( const std::string& str ) { if (valid_.size() == 0) return true; for (auto iter = valid_.begin(); iter != valid_.end(); ++iter) { if (str == *iter) return true; } return false; } // ----------------------------------------------------------------------------- // virtual void ParamString::parse( const char *str ) { char* copy = strdup( str ); char* token = strtok( copy, "," ); while (token != nullptr) { push_back( token ); token = strtok( nullptr, "," ); } free( copy ); } // ----------------------------------------------------------------------------- void ParamString::push_back( const char* str ) { if (! is_valid(str)) { throw_error( "invalid argument '%s'", str ); } TParamBase< std::string >::push_back( str ); } // ----------------------------------------------------------------------------- // virtual void ParamString::print() const { if (used_ && width_ > 0) { printf( "%-*s ", width_, values_[ index_ ].c_str() ); } } // ----------------------------------------------------------------------------- // virtual void ParamString::help() const { if (type_ == ParamType::Value || type_ == ParamType::List) { printf( " %-16s %s; default '%s'", option_.c_str(), help_.c_str(), default_value_.c_str() ); if (valid_.size() > 0) { printf( "; valid: " ); for (auto iter = valid_.begin(); iter != valid_.end(); ++iter) { printf( "%s ", iter->c_str() ); } } printf( "\n" ); } } // ----------------------------------------------------------------------------- // Set the allowed strings void ParamString::add_valid( const char* str ) { valid_.push_back( str ); } // ----------------------------------------------------------------------------- // for line=0, print blanks // for line=1, print name (left aligned) // virtual void ParamString::header( int line ) const { if (used_ && width_ > 0) { printf( "%-*s ", width_, (line == 0 ? "" : name_.c_str()) ); } } // ============================================================================= // ParamChar class // Character parameters // ----------------------------------------------------------------------------- // virtual void ParamChar::parse( const char *str ) { while (true) { char val; int len; int i = sscanf( str, "%c %n", &val, &len ); if (i != 1) { throw_error( "invalid argument at '%s', expected one char", str ); } str += len; push_back( val ); if (*str == '\0') { break; } if (*str != ',' && *str != ';') { throw_error( "invalid argument at '%s', expected comma", str ); } str += 1; } } // ----------------------------------------------------------------------------- void ParamChar::push_back( char val ) { if (valid_.find( val ) == std::string::npos) { // not found throw_error( "invalid option, %c not in [%s]", val, valid_.c_str() ); } TParamBase::push_back( val ); } // ----------------------------------------------------------------------------- // virtual void ParamChar::print() const { if (used_ && width_ > 0) { printf( "%*c ", width_, values_[ index_ ] ); } } // ----------------------------------------------------------------------------- // virtual void ParamChar::help() const { if (type_ == ParamType::Value || type_ == ParamType::List) { printf( " %-16s %s; default %c; valid: [%s]\n", option_.c_str(), help_.c_str(), default_value_, valid_.c_str() ); } } // ============================================================================= // ParamsBase class // List of parameters // ----------------------------------------------------------------------------- /// Throws QuitException if --help is encountered. /// Throws std::runtime_error for errors. void ParamsBase::parse( const char *routine, int n, char **args ) { // Usage: test [params] command for (int i = 0; i < n; ++i) { const char *arg = args[i]; size_t len = strlen( arg ); try { bool found = false; if (strncmp( arg, "-h", 2 ) == 0 || strncmp( arg, "--help", 6 ) == 0) { throw QuitException(); } for (auto param = ParamBase::s_params.begin(); param != ParamBase::s_params.end(); ++param) { // handles both "--option value" (two arg) // and "--option=value" (one arg) size_t plen = (*param)->option_.size(); if ((len == plen || (len >= plen && arg[plen] == '=')) && strncmp( arg, (*param)->option_.c_str(), plen ) == 0) { if (! (*param)->used()) { throw_error( "invalid parameter for routine '%s'", routine ); } const char *value = nullptr; if (len == plen && i+1 < n) { // --arg value (two arguments) i += 1; value = args[i]; } else if (len > plen+1 && arg[plen] == '=') { // --arg=value (one argument) value = arg + (*param)->option_.size() + 1; } else { throw_error( "requires an argument" ); } (*param)->parse( value ); found = true; break; } } if (! found) { throw_error( "invalid parameter" ); } } // QuitException is not a runtime_error, // so it is caught at a higher level. catch (const std::runtime_error& ex) { // prepend arg to error message throw std::runtime_error( std::string(arg) + ": " + ex.what() ); } } } // ----------------------------------------------------------------------------- bool ParamsBase::next() { // "Cartesian product" iteration // uses reverse order so in output, parameters on right cycle fastest for (auto param = ParamBase::s_params.rbegin(); param != ParamBase::s_params.rend(); ++param) { if ((*param)->next()) { return true; } } return false; } // ----------------------------------------------------------------------------- void ParamsBase::header() { for (int line = 0; line < 2; ++line) { for (auto param = ParamBase::s_params.begin(); param != ParamBase::s_params.end(); ++param) { (*param)->header( line ); } printf( "\n" ); } } // ----------------------------------------------------------------------------- void ParamsBase::print() { for (auto param = ParamBase::s_params.begin(); param != ParamBase::s_params.end(); ++param) { (*param)->print(); } printf( "\n" ); } // ----------------------------------------------------------------------------- void ParamsBase::reset_output() { for (auto param = ParamBase::s_params.begin(); param != ParamBase::s_params.end(); ++param) { (*param)->reset_output(); } } // ----------------------------------------------------------------------------- void ParamsBase::help( const char *routine ) { // todo: pass in argv[0] instead of assuming test. printf( "%sUsage:%s test [-h|--help]\n" " test [-h|--help] routine\n" " test [parameters] routine\n\n" "%sParameters for %s:%s\n", ansi_bold, ansi_normal, ansi_bold, routine, ansi_normal ); for (auto param = ParamBase::s_params.begin(); param != ParamBase::s_params.end(); ++param) { if ((*param)->used_ && (*param)->type_ == ParamType::Value) (*param)->help(); } printf( "\n%sParameters that take comma-separated list of values and may be repeated:%s\n", ansi_bold, ansi_normal ); for (auto param = ParamBase::s_params.begin(); param != ParamBase::s_params.end(); ++param) { if ((*param)->used_ && (*param)->type_ == ParamType::List) (*param)->help(); } } // ----------------------------------------------------------------------------- test_func_ptr find_tester( const char *name, std::vector< routines_t >& routines ) { for (size_t i = 0; i < routines.size(); ++i) { if (strcmp( name, routines[i].name ) == 0) { return routines[i].func; } } return nullptr; } // ----------------------------------------------------------------------------- void usage( int argc, char **argv, std::vector< routines_t >& routines, const char **section_names, int col_width, int ncols ) { using namespace testsweeper; printf( "%sUsage:%s %s [-h|--help]\n" " %s [-h|--help] routine\n" " %s [parameters] routine\n\n" "%sAvailable routines:%s", ansi_bold, ansi_normal, argv[0], argv[0], argv[0], ansi_bold, ansi_normal ); int last_section = 0; int cnt = 0; for (size_t i = 0; i < routines.size(); ++i) { if (routines[i].section == 0) { cnt = 0; // force newline before next routine continue; } if (routines[i].section != last_section) { last_section = routines[i].section; cnt = 0; printf( "\n\n%s%s%s\n", ansi_bold, section_names[last_section], ansi_normal ); } else if (cnt % ncols == 0) { printf( "\n" ); } printf( " %-*s", col_width, routines[i].name ); cnt += 1; } printf( "\n" ); } // ----------------------------------------------------------------------------- // prefer OpenMP get_wtime; else use gettimeofday double get_wtime() { #ifdef _OPENMP return omp_get_wtime(); #else struct timeval tv; gettimeofday( &tv, nullptr ); return tv.tv_sec + tv.tv_usec*1e-6; #endif } } // namespace testsweeper testsweeper-2024.05.31/testsweeper.hh000066400000000000000000000642321462625314600173750ustar00rootroot00000000000000// Copyright (c) 2017-2023, University of Tennessee. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // This program is free software: you can redistribute it and/or modify it under // the terms of the BSD 3-Clause license. See the accompanying LICENSE file. #ifndef LIBTEST_HH #define LIBTEST_HH #include #include #include #include #include #include #include #include #include // Version is updated by make_release.py; DO NOT EDIT. // Version 2024.05.31 #define TESTSWEEPER_VERSION 20240531 namespace testsweeper { int version(); const char* id(); extern double no_data_flag; // ----------------------------------------------------------------------------- // ANSI color codes extern const char *ansi_esc; extern const char *ansi_red; extern const char *ansi_green; extern const char *ansi_blue; extern const char *ansi_cyan; extern const char *ansi_magenta; extern const char *ansi_yellow; extern const char *ansi_white; extern const char *ansi_gray; extern const char *ansi_bold; extern const char *ansi_normal; // ----------------------------------------------------------------------------- class QuitException: public std::exception { public: explicit QuitException() : std::exception() {} }; // ----------------------------------------------------------------------------- void throw_error( const char* format, ... ); // ============================================================================= // Enums // ----------------------------------------------------------------------------- enum class DataType { Integer = 'i', Half = 'h', Single = 's', Double = 'd', SingleComplex = 'c', DoubleComplex = 'z', }; extern const char* DataType_help; //---------------------------------------- /// Convert string to DataType enum. Accepts a variety of inputs: /// /// { i, int, integer } => Integer /// /// { h, r16, half } => Half /// { s, r32, float, single } => Float /// { d, r64, double } => Double /// { c, c32, complex } => FloatComplex /// { z, c64, complex } => DoubleComplex /// /// Single letters come from traditional BLAS names (i, s, d, c, z) /// and a few commonly accepted new ones (h, q). /// The r32, c32, etc. come from XBLAS proposal, /// https://bit.ly/blas-g2-proposal /// /// @param[in] str /// String value to convert. /// /// @param[in] dummy /// Dummy argument used to specify the return type for overloading. /// inline void from_string( std::string const& str, DataType* val ) { std::string str_ = str; if (str_ == "i" || str_ == "int" || str_ == "integer" ) *val = DataType::Integer; else if (str_ == "h" || str_ == "r16" || str_ == "half" ) *val = DataType::Half; else if (str_ == "s" || str_ == "r32" || str_ == "float" || str_ == "single" ) *val = DataType::Single; else if (str_ == "d" || str_ == "r64" || str_ == "double" ) *val = DataType::Double; else if (str_ == "c" || str_ == "c32" || str_ == "complex" || str_ == "complex-float" || str_ == "complex-single") *val = DataType::SingleComplex; else if (str_ == "z" || str_ == "c64" || str_ == "complex" || str_ == "complex-double") *val = DataType::DoubleComplex; else throw_error( "invalid datatype '%s'", str.c_str() ); } //-------------------- [[deprecated("Use from_string. To be removed 2025-05.")]] inline DataType char2datatype( char ch ) { ch = tolower( ch ); if (ch != 'i' && ch != 's' && ch != 'd' && ch != 'c' && ch != 'z') { throw_error( "invalid datatype '%c'", ch ); } return DataType( ch ); } //-------------------- [[deprecated("Use from_string. To be removed 2025-05.")]] inline DataType str2datatype( const char* str ) { DataType val; from_string( str, &val ); return val; } //---------------------------------------- /// Convert DataType enum to C-style string representation. /// Temporary common low-level implementation for to_string and datatype2str. /// inline const char* to_c_string( DataType value ) { switch (value) { case DataType::Integer: return "i"; case DataType::Half: return "h"; case DataType::Single: return "s"; case DataType::Double: return "d"; case DataType::SingleComplex: return "c"; case DataType::DoubleComplex: return "z"; } throw_error( "invalid datatype" ); return "?"; } //-------------------- /// Convert DataType enum to C++ string representation. /// inline std::string to_string( DataType value ) { return std::string( to_c_string( value ) ); } //-------------------- [[deprecated("Use to_string. To be removed 2025-05.")]] inline const char* datatype2str( DataType value ) { // Can't write datatype2str using return to_string( value ).c_str() // since string is on stack. return to_c_string( value ); } //-------------------- [[deprecated("Use to_string. To be removed 2025-05.")]] inline char datatype2char( DataType value ) { return to_c_string( value )[ 0 ]; } //============================================================================== // Utilities //------------------------------------------------------------------------------ /// Use SFINAE to test for existence of from_string( string, T* ) function. template class has_from_string { private: typedef T* T_ptr; /// Matches `from_string( string str, T* val )`; return type is void. template static auto test( std::string str, T2* val ) -> decltype( from_string( str, val ) ); /// Matches everything else; return type is int (something other than void). template static int test(...); public: // True if `void from_string( string, T* )` exists. static constexpr bool value = std::is_same< void, decltype( test( std::string(), T_ptr() ) ) >::value; }; //------------------------------------------------------------------------------ /// Use SFINAE to test for existence of to_string( T ) function. /// This relies on ADL; it doesn't check the std namespace, so it won't /// work for basic types (int, float, etc.) -- not sure how to do that. template class has_to_string { private: /// Matches `to_string( T val )`; return type is string. template static auto test( T2 val ) -> decltype( to_string( val ) ); /// Matches everything else; return type is int (something other than string). template static int test(...); public: // True if `std::string to_string( T val )` exists. static constexpr bool value = std::is_same< std::string, decltype( test( T() ) ) >::value; }; // ----------------------------------------------------------------------------- int scan_range( const char **strp, int64_t *start, int64_t *end, int64_t *step ); int scan_range( const char **strp, double *start, double *end, double *step ); void flush_cache( size_t cache_size ); // ----------------------------------------------------------------------------- /// For integers x >= 0, y > 0, returns ceil( x/y ). /// For x == 0, this is 0. /// @ingroup ceildiv inline int64_t ceildiv( int64_t x, int64_t y ) { return (x + y - 1)/y; } /// For integers x >= 0, y > 0, returns x rounded up to multiple of y. /// That is, ceil(x/y)*y. /// For x == 0, this is 0. /// This implementation does not assume y is a power of 2. /// @ingroup ceildiv inline int64_t roundup( int64_t x, int64_t y ) { return ceildiv( x, y ) * y; } // ----------------------------------------------------------------------------- enum class ParamType { Output, Value, List, }; // ============================================================================= // class hierarchy // ParamBase // TParamBase (template) // ParamInt // ParamOkay // ParamInt3 // ParamDouble // ParamScientific // ParamChar // ParamEnum (template) class ParamBase { public: friend class ParamsBase; //---------------------------------------- /// Create parameter. /// /// @param[in] in_name /// Parameter's name, used as header in output and command line option. /// @see name() to override command line option. /// /// @param[in] width /// Minimum width of column in output. If width=0, column is hidden. /// Actual column width is max( width, length( name ) ). /// /// @param[in] type /// Parameter type: /// - Output: output-only parameter like time and gflops. /// - Value: single-valued parameter like check and ref. /// - List: parameter that can have multiple values for /// TestSweeper to iterate over, like datatype. /// /// @param[in] help /// Description of parameter to print with `tester -h routine`. /// ParamBase( const char* in_name, int width, ParamType type, const char* help ): help_ ( help ), index_ ( 0 ), width_ ( width ), type_ ( type ), is_default_( true ), used_ ( false ) { name( in_name ); s_params.push_back( this ); } virtual ~ParamBase() { auto iter = std::find( s_params.begin(), s_params.end(), this ); if (iter != s_params.end()) s_params.erase( iter ); } virtual void parse( const char* str ) = 0; virtual void print() const = 0; virtual void reset_output() = 0; virtual void header( int line ) const; virtual void help() const; virtual bool next(); virtual size_t size() const = 0; bool used() const { return used_; } void used( bool in_used ) { used_ = in_used; } //---------------------------------------- /// Set parameter's name. /// /// @param[in] in_name /// Parameter's name, used as header in output. /// Increases the column width to accomodate the new name as needed, /// if the width is not zero. /// /// @param[in] in_option /// If not null, used as command line option to set paramater. /// If null, in_name is used as command line option. /// void name( const char* in_name, const char* in_option=nullptr ) { name_ = in_name; if (width_ > 0) { int line1 = 0; while (in_name[ line1 ] != '\0' && in_name[ line1 ] != '\n') { ++line1; } int line2 = line1; while (in_name[ line2 ] != '\0') { ++line2; } line2 = line2 - line1 - 1; width_ = std::max( width_, std::max( line1, line2 ) ); } if (in_option) option_ = "--" + std::string(in_option); else option_ = "--" + name_; } int width() const { return width_; } void width( int w ) { width_ = w; } protected: // s_params is list of ParamBase objects, used by Params class static std::vector< ParamBase* > s_params; std::string name_; std::string option_; std::string help_; size_t index_; int width_; ParamType type_; bool is_default_; int used_; }; // ============================================================================= template class TParamBase : public ParamBase { public: TParamBase( const char* name, int width, ParamType type, T default_value, const char* help ): ParamBase( name, width, type, help ), default_value_( default_value ) { values_.push_back( default_value ); } virtual size_t size() const { return values_.size(); } T& operator ()() { used_ = true; return values_[ index_ ]; } T const& operator ()() const { return values_[ index_ ]; } void operator ()( T const& value ) { used_ = true; values_[ index_ ] = value; } void set_default( const T& default_value ) { default_value_ = default_value; if (is_default_) { values_.clear(); values_.push_back( default_value ); } } virtual void reset_output() { if (type_ == ParamType::Output) { values_[0] = default_value_; } } void push_back( T val ); protected: std::vector< T > values_; T default_value_; }; // ----------------------------------------------------------------------------- template void TParamBase::push_back( T val ) { if (type_ == ParamType::List) { if (is_default_) { values_.clear(); is_default_ = false; } values_.push_back( val ); } else { values_[0] = val; } } // ============================================================================= class ParamInt : public TParamBase< int64_t > { public: friend class Params; ParamInt( const char* name, int width, ParamType type, int64_t default_value, int64_t min_value, int64_t max_value, const char* help ): TParamBase( name, width, type, default_value, help ), min_value_( min_value ), max_value_( max_value ) {} virtual void parse( const char* str ); virtual void print() const; virtual void help() const; void push_back( int64_t val ); protected: int64_t min_value_; int64_t max_value_; }; // ============================================================================= // same as ParamInt, but prints ok (for non-zero) or FAILED (for zero). class ParamOkay : public ParamInt { public: ParamOkay( const char* name, int width, ParamType type, int64_t default_value, int64_t min_value, int64_t max_value, const char* help ): ParamInt( name, width, type, default_value, min_value, max_value, help ) {} virtual void print() const; }; // ============================================================================= typedef struct { int64_t m, n, k; } int3_t; class ParamInt3 : public TParamBase< int3_t > { public: friend class Params; enum { m_mask = 0x1, n_mask = 0x2, k_mask = 0x4, }; /// default range 100 : 500 : 100 ParamInt3( const char* name, int width, ParamType type, int64_t min_value, int64_t max_value, const char* help ): TParamBase( name, width, type, int3_t(), help ), min_value_( min_value ), max_value_( max_value ), m_name_("m"), n_name_("n"), k_name_("k") { values_.clear(); for (int64_t i = 100; i <= 500; i += 100) { int3_t tmp = { i, i, i }; values_.push_back( tmp ); } } /// application gives default range as string ParamInt3( const char* name, int width, ParamType type, const char* default_value, int64_t min_value, int64_t max_value, const char* help ): TParamBase( name, width, type, int3_t(), help ), min_value_( min_value ), max_value_( max_value ), m_name_("m"), n_name_("n"), k_name_("k") { values_.clear(); parse( default_value ); is_default_ = true; } virtual void parse( const char* str ); virtual void print() const; virtual void header( int line ) const; void push_back( int3_t val ); int64_t& m() { used_ |= m_mask; return values_[ index_ ].m; } int64_t& n() { used_ |= n_mask; return values_[ index_ ].n; } int64_t& k() { used_ |= k_mask; return values_[ index_ ].k; } /// Sets the names of the header values. void names(const char* m, const char* n, const char* k="") { m_name_ = m; n_name_ = n; k_name_ = k; } protected: int64_t min_value_; int64_t max_value_; std::string m_name_; std::string n_name_; std::string k_name_; }; //------------------------------------------------------------------------------ // Derived from BLAS++. /// For real scalar types. template struct MakeScalarTraits { static real_t make( real_t re, real_t im ) { return re; } }; /// For complex scalar types. template struct MakeScalarTraits< std::complex > { static std::complex make( real_t re, real_t im ) { return std::complex( re, im ); } }; /// Converts complex value into scalar_t, /// discarding imaginary part if scalar_t is real. template scalar_t make_scalar( std::complex val ) { return MakeScalarTraits::make( std::real(val), std::imag(val) ); } // ============================================================================= class ParamComplex : public TParamBase< std::complex > { public: friend class Params; ParamComplex( const char* name, int width, int precision, ParamType type, const char* default_value, double min_value, double max_value, const char* help ): // Compute width to account for // initial -, [+-] between real & complex parts, and i at end. TParamBase< std::complex >( name, 2*width + 3, type, std::complex(), help ), display_width_( width ), precision_( precision ), min_value_( min_value ), max_value_( max_value ) { values_.clear(); parse( default_value ); default_value_ = values_[ 0 ]; is_default_ = true; } template T get() { used_ = true; return make_scalar( values_[ index_ ] ); } std::complex scan_complex( const char** str ); virtual void parse( const char* str ); virtual void print() const; virtual void help() const; protected: int display_width_; int precision_; double min_value_; double max_value_; }; // ============================================================================= class ParamDouble : public TParamBase< double > { public: ParamDouble( const char* name, int width, int precision, ParamType type, double default_value, double min_value, double max_value, const char* help ): TParamBase( name, width, type, default_value, help ), precision_( precision ), min_value_( min_value ), max_value_( max_value ) {} virtual void parse( const char* str ); virtual void print() const; virtual void help() const; void push_back( double val ); protected: int precision_; double min_value_; double max_value_; }; // ============================================================================= // same as ParamDouble, but prints using scientific notation (%e) class ParamScientific : public ParamDouble { public: ParamScientific( const char* name, int width, int precision, ParamType type, double default_value, double min_value, double max_value, const char* help ): ParamDouble( name, width, precision, type, default_value, min_value, max_value, help ) {} virtual void print() const; virtual void help() const; }; // ============================================================================= class ParamChar : public TParamBase< char > { public: ParamChar( const char* name, int width, ParamType type, char default_value, const char* valid, const char* help ): TParamBase( name, width, type, default_value, help ), valid_( valid ) {} virtual void parse( const char* str ); virtual void print() const; virtual void help() const; void push_back( char val ); protected: std::string valid_; }; // ============================================================================= class ParamString : public TParamBase< std::string > { public: ParamString( const char* name, int width, ParamType type, const char* default_value, const char* help ): TParamBase( name, width, type, default_value, help ) {} virtual void parse( const char* str ); virtual void print() const; virtual void header( int line ) const; virtual void help() const; void push_back( const char* str ); void add_valid( const char* str ); bool is_valid( const std::string& str ); protected: std::vector< std::string > valid_; }; // ============================================================================= template class ParamEnum : public TParamBase< ENUM > { public: typedef ENUM (*char2enum)( char ch ); typedef char (*enum2char)( ENUM en ); typedef ENUM (*str2enum)( const char* str ); typedef const char* (*enum2str)( ENUM en ); /// Constructor for enums that have to_string and from_string. ParamEnum( const char* name, int width, ParamType type, ENUM default_value, const char* help ): TParamBase( name, width, type, default_value, help ), char2enum_( nullptr ), enum2char_( nullptr ), str2enum_ ( nullptr ), enum2str_ ( nullptr ) {} /// Deprecated constructor taking char2enum, enum2char, enum2str. [[deprecated("Use constructor without char2enum, etc. To be removed 2025-05.")]] ParamEnum( const char* name, int width, ParamType type, ENUM default_value, char2enum in_char2enum, enum2char in_enum2char, enum2str in_enum2str, const char* help ): TParamBase( name, width, type, default_value, help ), char2enum_( in_char2enum ), enum2char_( in_enum2char ), str2enum_( nullptr ), enum2str_( in_enum2str ) {} /// Deprecated constructor taking str2enum, enum2str. [[deprecated("Use constructor without char2enum, etc. To be removed 2025-05.")]] ParamEnum( const char* name, int width, ParamType type, ENUM default_value, str2enum in_str2enum, enum2str in_enum2str, const char* help ): TParamBase( name, width, type, default_value, help ), char2enum_( nullptr ), enum2char_( nullptr ), str2enum_( in_str2enum ), enum2str_( in_enum2str ) {} virtual void parse( const char* str ); virtual void print() const; virtual void help() const; protected: // Deprecated: char2enum_, etc. char2enum char2enum_; enum2char enum2char_; str2enum str2enum_; enum2str enum2str_; }; // ----------------------------------------------------------------------------- // virtual template void ParamEnum::parse( const char *str ) { char buf[81] = { 0 }; while (true) { // Read next word, up to 80 chars. int len; int i = sscanf( str, " %80[a-zA-Z0-9_<>-] %n", buf, &len ); if (i != 1) { throw_error( "invalid argument at '%s'", str ); } str += len; // Parse word into enum. str2enum_ & char2enum_ throw errors. ENUM val{}; if constexpr (has_from_string::value) { from_string( buf, &val ); } else if (str2enum_) { val = str2enum_( buf ); } else { assert( char2enum_ != nullptr ); val = char2enum_( buf[0] ); } this->push_back( val ); if (*str == '\0') { break; } if (*str != ',' && *str != ';') { throw_error( "invalid argument at '%s', expected comma", str ); } str += 1; } } // ----------------------------------------------------------------------------- // virtual template void ParamEnum::print() const { if (this->used_ && this->width_ > 0) { if constexpr (has_to_string::value) { printf( "%*s ", this->width_, to_string( this->values_[ this->index_ ] ).c_str() ); } else if (enum2str_) { printf( "%*s ", this->width_, this->enum2str_( this->values_[ this->index_ ] )); } else { throw_error( "no to_string method available" ); } } } // ----------------------------------------------------------------------------- // virtual template void ParamEnum::help() const { if (this->type_ == ParamType::Value || this->type_ == ParamType::List) { if constexpr (has_to_string::value) { printf( " %-16s %s; default %s\n", this->option_.c_str(), this->help_.c_str(), to_string( this->default_value_ ).c_str() ); } else if (enum2str_) { printf( " %-16s %s; default %s\n", this->option_.c_str(), this->help_.c_str(), this->enum2str_( this->default_value_ )); } else { throw_error( "no to_string method available" ); } } } // ============================================================================= class ParamsBase { public: ParamsBase() {} void parse( const char* routine, int n, char** args ); bool next(); void header(); void print(); void reset_output(); void help( const char* routine ); }; } // namespace testsweeper // ============================================================================= // main must define Params class (which is not in testsweeper namespace), // as a subclass of ParamsBase class Params; namespace testsweeper { typedef void (*test_func_ptr)( Params& params, bool run ); typedef struct { const char* name; test_func_ptr func; int section; } routines_t; test_func_ptr find_tester( const char *name, std::vector< routines_t >& routines ); void usage( int argc, char **argv, std::vector< routines_t >& routines, const char **section_names, int col_width=18, int ncols=4 ); double get_wtime(); } // namespace testweeper #endif // #ifndef LIBTEST_HH testsweeper-2024.05.31/testsweeperConfig.cmake.in000066400000000000000000000002411462625314600215770ustar00rootroot00000000000000@PACKAGE_INIT@ # testsweeperTargets.cmake is in same dir as this file (CMAKE_CURRENT_LIST_DIR). include( "${CMAKE_CURRENT_LIST_DIR}/testsweeperTargets.cmake" ) testsweeper-2024.05.31/tools/000077500000000000000000000000001462625314600156335ustar00rootroot00000000000000testsweeper-2024.05.31/tools/copyright.py000077500000000000000000000000731462625314600202200ustar00rootroot00000000000000#!/usr/bin/env python3 import release release.copyright() testsweeper-2024.05.31/tools/make_release.py000077500000000000000000000001451462625314600206250ustar00rootroot00000000000000#!/usr/bin/env python3 import release release.make( 'testsweeper', 'testsweeper.hh', 'version.cc' ) testsweeper-2024.05.31/tools/release.py000066400000000000000000000157601462625314600176360ustar00rootroot00000000000000# Copyright (c) 2017-2023, University of Tennessee. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause # This program is free software: you can redistribute it and/or modify it under # the terms of the BSD 3-Clause license. See the accompanying LICENSE file. ''' Tags project with version based on current date, and creates tar file. Tag is yyyy.mm.dd, based on current year, month, and day. Version is an integer yyyymmdd, to allow simple comparisons. Requires Python >= 3.7. Usage: #!/usr/bin/env python3 import release release.copyright() release.make( 'project', 'version.h', 'version.c' ) 'project' is the name of the project, used for the tar filename. 'version.h' is a header containing the following #define for the version, with PROJECT changed to the project's name. // Version is updated by make_release.py; DO NOT EDIT. // Version 2020.02.00 #define PROJECT_VERSION 20200200 'version.c' is a source file containing the following #define for the id: // PROJECT_ID is the git commit hash ID, either // defined by `git rev-parse --short HEAD` in Makefile, // or defined here by make_release.py for release tar files. DO NOT EDIT. #ifndef PROJECT_ID #define PROJECT_ID "unknown" #endif const char* id() { return PROJECT_ID; } int version() { return PROJECT_VERSION; } Steps this takes: 1. Marks version in repo. - Saves the Version to version.h. - Updates copyright year in all files. - Commits that change. - Tags that commit. 2. Prepares archive in directory project-tag. - Saves the `git rev-parse --short HEAD` to version.c. - Generates Doxygen docs. 3. Generates tar file project-tag.tar.gz ''' from __future__ import print_function import sys MIN_PYTHON = (3, 7) assert sys.version_info >= MIN_PYTHON, "requires Python >= %d.%d" % MIN_PYTHON import os import datetime import re import subprocess from subprocess import PIPE #------------------------------------------------------------------------------- def myrun( cmd, **kwargs ): ''' Simple wrapper around subprocess.run(), with check=True. If cmd is a str, it is split on spaces before being passed to run. Prints cmd. kwargs are passed to run(). Set `stdout=PIPE, text=True` if you want the output returned. ''' if (type(cmd) is str): cmd = cmd.split(' ') print( '\n>>', ' '.join( cmd ) ) return subprocess.run( cmd, check=True, **kwargs ).stdout # end #------------------------------------------------------------------------------- def file_sub( filename, search, replace, **kwargs ): ''' Replaces search regexp with replace in file filename. ''' #print( 'reading', filename ) txt = open( filename ).read() txt2 = re.sub( search, replace, txt, **kwargs ) if (txt != txt2): #print( 'writing', filename ) open( filename, mode='w' ).write( txt2 ) else: print( '##### Warning: no change in', filename, '#####' ) # end #------------------------------------------------------------------------------- def copyright(): ''' Update copyright in all files. ''' today = datetime.date.today() year = today.year files = myrun( 'git ls-tree -r master --name-only', stdout=PIPE, text=True ).rstrip().split( '\n' ) print( '\n>> Updating copyright in:', end=' ' ) for file in files: if (re.search( r'^(old/|src/hip/)', file ) or os.path.isdir( file )): continue print( file, end=', ' ) file_sub( file, r'Copyright \(c\) (\d+)(-\d+)?, University of Tennessee', r'Copyright (c) \1-%04d, University of Tennessee' % (year) ) # end print() myrun( 'git diff' ) print( '>> Commit changes [yn]? ', end='' ) response = input() if (response != 'y'): print( '>> Release aborted. Please revert changes as desired.' ) exit(1) myrun( ['git', 'commit', '-m', 'copyright '+ str(year), '.'] ) # end #------------------------------------------------------------------------------- def make( project, version_h, version_c ): ''' Makes project release. ''' today = datetime.date.today() year = today.year month = today.month mday = today.day top_dir = os.getcwd() tag = '%04d.%02d.%02d' % (year, month, mday) vtag = 'v' + tag version = '%04d%02d%02d' % (year, month, mday) print( '\n>> Tag '+ tag +', Version '+ version ) #-------------------- # Check change log txt = open( 'CHANGELOG.md' ).read() if (not re.search( tag, txt )): print( '>> Add', tag, 'to CHANGELOG.md. Release aborted.' ) exit(1) #-------------------- # Update version in version_h. print( '\n>> Updating version in:', version_h ) file_sub( version_h, r'// Version \d\d\d\d.\d\d.\d\d\n(#define \w+_VERSION) \d+', r'// Version %s\n\1 %s' % (tag, version), count=1 ) print( '\n>> Updating version in: GNUmakefile' ) file_sub( 'GNUmakefile', r'(VERSION.)\d\d\d\d.\d\d.\d\d', r'\g<1>%s' % (tag), count=1 ) print( '\n>> Updating version in: CMakeLists.txt' ) file_sub( 'CMakeLists.txt', r'VERSION \d\d\d\d.\d\d.\d\d', r'VERSION %s' % (tag), count=1 ) #print( '\n>> Updating version in: doxyfile.conf' ) #file_sub( 'docs/doxygen/doxyfile.conf', # r'(PROJECT_NUMBER *=) *"\d+\.\d+\.\d+"', # r'\1 "%s"' % (tag), count=1 ) myrun( 'git diff' ) myrun( 'git diff --staged' ) print( '>> Do changes look good? Continue building release [yn]? ', end='' ) response = input() if (response != 'y'): print( '>> Release aborted. Please revert changes as desired.' ) exit(1) myrun( ['git', 'commit', '-m', 'Version '+ tag, '.'] ) myrun( ['git', 'tag', vtag, '-a', '-m', 'Version '+ tag] ) #-------------------- # Prepare tar file. dir = project +'-'+ tag print( '\n>> Preparing files in', dir ) # Move any existing dir to dir-#; maximum # is 100. if (os.path.exists( dir )): for index in range( 1, 100 ): backup = '%s-%d' % (dir, index) if (not os.path.exists( backup )): os.rename( dir, backup ) print( 'backing up', dir, 'to', backup ) break # end os.mkdir( dir ) subprocess.run( 'git archive ' + vtag + ' | tar -x -C ' + dir, shell=True ) os.chdir( dir ) # Update hash ID in version_c. id = myrun( 'git rev-parse --short HEAD', stdout=PIPE, text=True ).strip() print( '\n>> Setting ID in:', version_c ) file_sub( version_c, r'^(#define \w+_ID) "unknown"', r'\1 "'+ id +'"', count=1, flags=re.M ) # Build Doxygen docs. Create dummy 'make.inc' to avoid 'make config'. open( 'make.inc', mode='a' ).close() myrun( 'make docs' ) os.unlink( 'make.inc' ) os.chdir( '..' ) tar = dir + '.tar.gz' print( '\n>> Creating tar file', tar ) myrun( 'tar -zcvf '+ tar +' '+ dir ) # end testsweeper-2024.05.31/version.cc000066400000000000000000000021361462625314600164710ustar00rootroot00000000000000// Copyright (c) 2017-2023, University of Tennessee. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // This program is free software: you can redistribute it and/or modify it under // the terms of the BSD 3-Clause license. See the accompanying LICENSE file. #include "testsweeper.hh" namespace testsweeper { //------------------------------------------------------------------------------ /// @return TestSweeper version. /// Version is integer of form yyyymmrr, where yyyy is year, mm is month, /// and rr is release counter within month, starting at 00. /// int version() { return TESTSWEEPER_VERSION; } // TESTSWEEPER_ID is the Mercurial or git commit hash ID, either // defined by `hg id` or `git rev-parse --short HEAD` in Makefile, // or defined here by make_release.py for release tar files. DO NOT EDIT. #ifndef TESTSWEEPER_ID #define TESTSWEEPER_ID "unknown" #endif //------------------------------------------------------------------------------ /// @return TestSweeper Mercurial or git commit hash ID. /// const char* id() { return TESTSWEEPER_ID; } } // namespace testsweeper