Skip to content

Commit

Permalink
Merge pull request #254 from Krzmbrzl/benchmarks
Browse files Browse the repository at this point in the history
Implement Wick benchmark
  • Loading branch information
Krzmbrzl authored Feb 7, 2025
2 parents 2643891 + 66278e0 commit c70044d
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
-DSEQUANT_USE_SYSTEM_BOOST_HASH=OFF
-DCMAKE_CXX_STANDARD=20
-DCMAKE_CXX_EXTENSIONS=OFF
-DSEQUANT_BUILD_BENCHMARKS=ON
-DSEQUANT_BENCHMARKS=ON
steps:
- uses: actions/checkout@v4

Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ set(SEQUANT_INSTALL_DOCDIR "${SEQUANT_INSTALL_SHAREDIR}/doc"
CACHE PATH "SeQuant DOC install directory")
set(SEQUANT_INSTALL_CMAKEDIR "lib/cmake/sequant"
CACHE PATH "SeQuant CMAKE install directory")
option(SEQUANT_BENCHMARKS "Enable SeQuant benchmarks" OFF)

############################
# Additional build variables
Expand Down Expand Up @@ -413,6 +414,10 @@ if (SEQUANT_IWYU)
endif()
endif()

if (SEQUANT_BENCHMARKS)
add_subdirectory(benchmarks)
endif()

### unit tests
include(CTest)

Expand Down
12 changes: 12 additions & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
include(FindOrFetchGoogleBenchmark)

add_executable(sequant_benchmarks
"main.cpp"
"wick.cpp"
)

target_link_libraries(sequant_benchmarks
PRIVATE
benchmark::benchmark
SeQuant::SeQuant
)
26 changes: 26 additions & 0 deletions benchmarks/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <benchmark/benchmark.h>

#include <SeQuant/core/context.hpp>
#include <SeQuant/core/runtime.hpp>
#include <SeQuant/domain/mbpt/convention.hpp>

using namespace sequant;

int main(int argc, char *argv[]) {
// Disable multithreading
set_num_threads(1);
set_locale();
set_default_context(Context(mbpt::make_sr_spaces(), Vacuum::SingleProduct,
IndexSpaceMetric::Unit, BraKetSymmetry::nonsymm,
SPBasis::spinorbital));

::benchmark::Initialize(&argc, argv);
if (::benchmark::ReportUnrecognizedArguments(argc, argv)) {
return 1;
}

::benchmark::RunSpecifiedBenchmarks();
::benchmark::Shutdown();

return 0;
}
112 changes: 112 additions & 0 deletions benchmarks/wick.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include <benchmark/benchmark.h>

#include <SeQuant/core/expr.hpp>
#include <SeQuant/core/op.hpp>
#include <SeQuant/core/parse.hpp>
#include <SeQuant/core/wick.hpp>

using namespace sequant;

static constexpr std::size_t nInputs = 5;

template <Statistics stats>
ExprPtr get_op_sequence(std::size_t i) {
using OpSeq = NormalOperatorSequence<stats>;
using Op = NormalOperator<stats>;

switch (i) {
case 1:
return parse_expr(L"f{p1;p2} t{p3;p4}") *
ex<Op>(cre({L"p_1"}), ann({L"p_2"})) *
ex<Op>(cre({L"p_3"}), ann({L"p_4"}));
case 2:
return parse_expr(L"A{p1,p2;p3,p4}:A g{p5,p6;p7,p8}:A") *
ex<Op>(cre({L"p_1", L"p_2"}), ann({L"p_3", L"p_4"})) *
ex<Op>(cre({L"p_5", L"p_6"}), ann({L"p_7", L"p_8"}));
case 3:
return parse_expr(L"A{p1,p2,p3;p4,p5,p6}:A g{p7,p8;p9,p10}:A") *
ex<Op>(cre({L"p_1", L"p_2", L"p_3"}),
ann({L"p_4", L"p_5", L"p_6"})) *
ex<Op>(cre({L"p_7", L"p_8"}), ann({L"p_9", L"p_10"}));
case 4:
return parse_expr(
L"A{p1,p2,p3;p4,p5,p6}:A g{p7,p8;p9,p10}:A "
L"t{p11,p12,p13;p14,p15,p16}:A") *
ex<Op>(cre({L"p_1", L"p_2", L"p_3"}),
ann({L"p_4", L"p_5", L"p_6"})) *
ex<Op>(cre({L"p_7", L"p_8"}), ann({L"p_9", L"p_10"})) *
ex<Op>(cre({L"p_11", L"p_12", L"p_13"}),
ann({L"p_14", L"p_15", L"p_16"}));
case 5:
return parse_expr(
L"A{p1,p2;p3,p4}:A g{p5,p6;p7,p8}:A "
L"t{p9,p10;p11,p12}:A t{p13,p14;p15,p16}:A") *
ex<Op>(cre({L"p_1", L"p_2"}), ann({L"p_3", L"p_4"})) *
ex<Op>(cre({L"p_5", L"p_6"}), ann({L"p_7", L"p_8"})) *
ex<Op>(cre({L"p_9", L"p_10"}), ann({L"p_11", L"p_12"})) *
ex<Op>(cre({L"p_13", L"p_14"}), ann({L"p_15", L"p_16"}));
}

throw "Invalid index";
};

template <Statistics stats>
static void wick(benchmark::State &state, bool full_conractions_only,
bool use_topology) {
const ExprPtr &input = get_op_sequence<stats>(state.range(0));

std::size_t n_attempted = 0;
std::size_t n_useful = 0;

// Note: only what is contained in this loop will be part
// of the benchmark timings
for (auto _ : state) {
WickTheorem<stats> wick(input->clone());
wick.full_contractions(full_conractions_only);
wick.use_topology(use_topology);

// We only don't explicitly create the expressions for all contractions in
// order to not blow up the memory consumption of the benchmark in the cases
// where we compute all contractions.
ExprPtr result = wick.compute(true);

// Prevent the Wick computation from being optimized away by the compiler
benchmark::DoNotOptimize(result);

const auto &statistics = wick.stats();
n_attempted = statistics.num_attempted_contractions;
n_useful = statistics.num_useful_contractions;
}

state.counters["produced"] = n_useful;
state.counters["attempted"] = n_attempted;
state.counters["percentage"] = static_cast<int>(
100 * static_cast<float>(n_useful) / static_cast<float>(n_attempted));
}

BENCHMARK_CAPTURE(wick<Statistics::FermiDirac>, full_only_with_topology, true,
true)
->DenseRange(1, nInputs);
BENCHMARK_CAPTURE(wick<Statistics::BoseEinstein>, full_only_with_topology, true,
true)
->DenseRange(1, nInputs);

BENCHMARK_CAPTURE(wick<Statistics::FermiDirac>, full_only_without_topology,
true, false)
->DenseRange(1, nInputs);
BENCHMARK_CAPTURE(wick<Statistics::BoseEinstein>, full_only_without_topology,
true, false)
->DenseRange(1, nInputs);

BENCHMARK_CAPTURE(wick<Statistics::FermiDirac>, all_with_topology, false, true)
->DenseRange(1, nInputs);
BENCHMARK_CAPTURE(wick<Statistics::BoseEinstein>, all_with_topology, false,
true)
->DenseRange(1, nInputs);

BENCHMARK_CAPTURE(wick<Statistics::FermiDirac>, all_without_topology, false,
false)
->DenseRange(1, nInputs);
BENCHMARK_CAPTURE(wick<Statistics::BoseEinstein>, all_without_topology, false,
false)
->DenseRange(1, nInputs);
17 changes: 17 additions & 0 deletions cmake/modules/FindOrFetchGoogleBenchmark.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
find_package(benchmark)

if (NOT TARGET benchmark::benchmark)
include(${vg_cmake_kit_SOURCE_DIR}/modules/VRGFindOrFetchPackage.cmake)

set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "" FORCE)

VRGFindOrFetchPackage(benchmark "https://github.com/google/benchmark.git" "v1.9.1"
ADD_SUBDIR
CONFIG_SUBDIR
)
endif()

# postcond check
if (NOT TARGET benchmark::benchmark)
message(FATAL_ERROR "FindOrFetchGoogleBenchmark could not make TARGET benchmark::benchmark available")
endif(NOT TARGET libperm)

0 comments on commit c70044d

Please sign in to comment.