diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 69d08d9b36..76f48347a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: - name: Build run: | - cmake -B build -DBUILD_TESTING=ON -DENABLE_DEEPKS=ON -DENABLE_LIBXC=ON -DENABLE_LIBRI=ON -DENABLE_PAW=ON + cmake -B build -DBUILD_TESTING=ON -DENABLE_DEEPKS=ON -DENABLE_LIBXC=ON -DENABLE_LIBRI=ON -DENABLE_PAW=ON -DENABLE_GOOGLEBENCH=ON cmake --build build -j8 cmake --install build diff --git a/CMakeLists.txt b/CMakeLists.txt index 99a6fc2650..c474d23ae1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ option(DEBUG_INFO "Print message for developers to debug." OFF) option(ENABLE_NATIVE_OPTIMIZATION "Enable compilation optimization for the native machine's CPU type" OFF) option(COMMIT_INFO "Print commit information in log" ON) option(ENABLE_FFT_TWO_CENTER "Enable FFT-based two-center integral method." ON) +option(ENABLE_GOOGLEBENCH "Enable GOOGLE-benchmark usage." OFF) option(ENABLE_RAPIDJSON "Enable rapid-json usage." OFF) @@ -594,6 +595,25 @@ if(INFO) # modifications on blas_connector and lapack_connector endif() +# Add performance test in abacus +IF (ENABLE_GOOGLEBENCH) + set(BUILD_TESTING ON) + find_package(benchmark HINTS ${BENCHMARK_DIR}) + if(NOT ${benchmark_FOUND}) + set(BENCHMARK_USE_BUNDLED_GTEST OFF) + include(FetchContent) + FetchContent_Declare( + benchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG "origin/main" + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) + set(BENCHMARK_ENABLE_TESTING OFF) + FetchContent_MakeAvailable(benchmark) + endif() +endif() + IF (BUILD_TESTING) set_if_higher(CMAKE_CXX_STANDARD 14) # Required in orbital include(CTest) @@ -623,8 +643,14 @@ IF (BUILD_TESTING) endif() #dependencies & link library - target_link_libraries(${UT_TARGET} ${UT_LIBS} - Threads::Threads GTest::gtest_main GTest::gmock_main) + if(ENABLE_GOOGLEBENCH) + target_link_libraries(${UT_TARGET} ${UT_LIBS} + Threads::Threads GTest::gtest_main GTest::gmock_main benchmark::benchmark) + else() + target_link_libraries(${UT_TARGET} ${UT_LIBS} + Threads::Threads GTest::gtest_main GTest::gmock_main) + endif() + if(USE_OPENMP) target_link_libraries(${UT_TARGET} OpenMP::OpenMP_CXX) endif() @@ -634,6 +660,7 @@ IF (BUILD_TESTING) WORKING_DIRECTORY $ ) endfunction(AddTest) + endif() add_subdirectory(source) diff --git a/Dockerfile.cuda b/Dockerfile.cuda index 719f7c4278..e950f097f9 100644 --- a/Dockerfile.cuda +++ b/Dockerfile.cuda @@ -2,7 +2,7 @@ FROM nvidia/cuda:12.2.0-devel-ubuntu22.04 RUN apt update && apt install -y --no-install-recommends \ libopenblas-openmp-dev liblapack-dev libscalapack-mpi-dev libelpa-dev libfftw3-dev libcereal-dev \ - libxc-dev libgtest-dev libgmock-dev python3-numpy \ + libxc-dev libgtest-dev libgmock-dev libbenchmark-dev python3-numpy \ bc cmake git g++ make bc time sudo unzip vim wget ENV GIT_SSL_NO_VERIFY=true TERM=xterm-256color \ diff --git a/Dockerfile.gnu b/Dockerfile.gnu index 0b6b45d248..060d930563 100644 --- a/Dockerfile.gnu +++ b/Dockerfile.gnu @@ -1,7 +1,7 @@ FROM ubuntu:22.04 RUN apt update && apt install -y --no-install-recommends \ libopenblas-openmp-dev liblapack-dev libscalapack-mpi-dev libelpa-dev libfftw3-dev libcereal-dev \ - libxc-dev libgtest-dev libgmock-dev python3-numpy \ + libxc-dev libgtest-dev libgmock-dev libbenchmark-dev python3-numpy \ bc cmake git g++ make bc time sudo unzip vim wget gfortran ENV GIT_SSL_NO_VERIFY=true TERM=xterm-256color \ diff --git a/Dockerfile.intel b/Dockerfile.intel index 6cac8c9f5f..3947f05b9e 100644 --- a/Dockerfile.intel +++ b/Dockerfile.intel @@ -2,7 +2,7 @@ FROM ubuntu:22.04 RUN apt-get update && apt-get install -y \ bc cmake git gnupg gcc g++ python3-numpy sudo wget vim unzip \ - libcereal-dev libxc-dev libgtest-dev libgmock-dev + libcereal-dev libxc-dev libgtest-dev libgmock-dev libbenchmark-dev # Following steps by https://software.intel.com/content/www/us/en/develop/documentation/installation-guide-for-intel-oneapi-toolkits-linux/top/installation/install-using-package-managers/apt.html . RUN wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \ diff --git a/docs/advanced/install.md b/docs/advanced/install.md index e929fac34c..d6201a060f 100644 --- a/docs/advanced/install.md +++ b/docs/advanced/install.md @@ -69,6 +69,16 @@ After building and installing, unit tests can be performed with `ctest`. To run a subset of unit test, use `ctest -R ` to perform tests with name matched by given pattern. +## Build Performance Tests + +To build performance tests for ABACUS, define `ENABLE_GOOGLEBENCH` flag. You can also specify the path to a local installation of [Google Benchmark](https://github.com/google/benchmark.git) by setting `BENCHMARK_DIR` flags. If not found locally, the configuration process will try to download it automatically. + +```bash +cmake -B build -DENABLE_GOOGLEBENCH=1 +``` + +Google Benchmark requires Google Test to build and run the tests. When setting `ENABLE_GOOGLEBENCH` to ON, `BUILD_TESTING` is automatically enabled. After building and installing, performance tests can be executed with `ctest`. + ## Build with CUDA support ### Extra prerequisites diff --git a/docs/quick_start/easy_install.md b/docs/quick_start/easy_install.md index 32ae5b87d3..edbfd41f67 100644 --- a/docs/quick_start/easy_install.md +++ b/docs/quick_start/easy_install.md @@ -126,6 +126,7 @@ Here, 'build' is the path for building ABACUS; and '-D' is used for setting up s - `ENABLE_LIBRI=OFF`: [Enable LibRI](../advanced/install.md#add-libri-support) to suppport variety of functionals. If `LIBRI_DIR` and `LIBCOMM_DIR` is defined, `ENABLE_LIBRI` will set to 'ON'. - `USE_OPENMP=ON`: Enable OpenMP support. Building ABACUS without OpenMP is not fully tested yet. - `BUILD_TESTING=OFF`: [Build unit tests](../advanced/install.md#build-unit-tests). + - `ENABLE_GOOGLEBENCH=OFF`: [Build performance tests](../advanced/install.md#build-performance-tests) - `ENABLE_MPI=ON`: Enable MPI parallel compilation. If set to `OFF`, a serial version of ABACUS with PW basis only will be compiled. Currently serial version of ABACUS with LCAO basis is not supported yet, so `ENABLE_LCAO` will be automatically set to `OFF`. - `ENABLE_COVERAGE=OFF`: Build ABACUS executable supporting [coverage analysis](../CONTRIBUTING.md#generating-code-coverage-report). This feature has a drastic impact on performance. - `ENABLE_ASAN=OFF`: Build with Address Sanitizer. This feature would help detecting memory problems. diff --git a/source/module_base/test/CMakeLists.txt b/source/module_base/test/CMakeLists.txt index 185727ef93..008df422e5 100644 --- a/source/module_base/test/CMakeLists.txt +++ b/source/module_base/test/CMakeLists.txt @@ -217,6 +217,13 @@ AddTest( SOURCES assoc_laguerre_test.cpp ../assoc_laguerre.cpp ../tool_quit.cpp ../global_variable.cpp ../global_file.cpp ../global_function.cpp ../memory.cpp ../timer.cpp LIBS ${math_libs} formatter ) +if(ENABLE_GOOGLEBENCH) + AddTest( + TARGET perf_sphbes + LIBS formatter + SOURCES perf_sphbes_test.cpp ../math_sphbes.cpp ../timer.cpp + ) +endif() if(ENABLE_RAPIDJSON) AddTest( diff --git a/source/module_base/test/perf_sphbes_test.cpp b/source/module_base/test/perf_sphbes_test.cpp new file mode 100644 index 0000000000..4c574baa8e --- /dev/null +++ b/source/module_base/test/perf_sphbes_test.cpp @@ -0,0 +1,72 @@ +#include"../math_sphbes.h" +#include +#include +#include +#include +#include + +/************************************************ +* performace test of class Sphbes +***********************************************/ + +/** + * Tested function: + * - sphbesj + * - Spherical_Bessel + */ + +class PerfSphbes : public benchmark::Fixture { +public: + const double q = 1; + const int n = 1000; + double stop = 1000.0; + double dr = 0.0; + double* rc, *rinf, *jc, *jinf; + void SetUp(const benchmark::State& state){ + const double rcut = state.range(0) + 0.5; + rc = new double[n + 10]; + rinf = new double[n + 10]; + jc = new double[n + 10]; + jinf = new double[n + 10]; + + // generate data points in (0, rcut] in log scale + double rmin = 0.0001; + double log_rmin = std::log(rmin); + double log_rcut = std::log(rcut); + dr = (log_rcut - log_rmin) / (n-1); + memset(rc, 0, (n+10) * sizeof(double)); + for (int i = 0; i < n; i++) + rc[i] = std::exp(log_rmin + i * dr); + + // generate data points in [rcut, stop] in linear scale + memset(rinf, 0, (n+10) * sizeof(double)); + rinf[0] = rcut; + dr = (stop - rcut) / (n-1); + for (int i = 1; i < n; i++) + rinf[i] += rinf[i-1] + dr; + } + void TearDown(const benchmark::State& state){ + delete[] rc; + delete[] rinf; + delete[] jc; + delete[] jinf; + } +}; + +BENCHMARK_DEFINE_F(PerfSphbes, BM_Spherical_Bessel)(benchmark::State& state) { + for (auto _ : state) { + ModuleBase::Sphbes::Spherical_Bessel(n, rc, q, state.range(0), jc); + ModuleBase::Sphbes::Spherical_Bessel(n, rinf, q, state.range(0), jinf); + } +} + +BENCHMARK_DEFINE_F(PerfSphbes, BM_sphbesj)(benchmark::State& state) { + for (auto _ : state) { + ModuleBase::Sphbes::sphbesj(n, rc, q, state.range(0), jc); + ModuleBase::Sphbes::sphbesj(n, rinf, q, state.range(0), jinf); + } +} + +BENCHMARK_REGISTER_F(PerfSphbes, BM_sphbesj)->DenseRange(0, 11, 1)->Unit(benchmark::kMicrosecond); +BENCHMARK_REGISTER_F(PerfSphbes, BM_Spherical_Bessel)->DenseRange(0, 11, 1)->Unit(benchmark::kMicrosecond); +BENCHMARK_MAIN(); \ No newline at end of file