Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds run_benchmarks CMake target and adapt existing test to be a benchmark #1222

Merged
merged 21 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8c4210a
add extra metadata tags
chapman39 Aug 22, 2024
83127e0
Merge remote-tracking branch 'origin/develop' into feature/chapman39/…
chapman39 Aug 22, 2024
094066f
Create script to run benchmarks and move caliper files to shared loca…
chapman39 Aug 23, 2024
01414d2
Merge remote-tracking branch 'origin/develop' into feature/chapman39/…
chapman39 Aug 27, 2024
94f2591
print spot dir, add -e option, skip building docs
chapman39 Aug 28, 2024
b016796
Merge remote-tracking branch 'origin/develop' into feature/chapman39/…
chapman39 Aug 30, 2024
8808849
Update nonlinear solve test to run specific solvers/ prec one after a…
chapman39 Sep 5, 2024
b5e4315
attempt to make a benchmark custom cmake target
chapman39 Sep 5, 2024
65c0789
use blt_add_benchmark, run across variable task counts
chapman39 Sep 5, 2024
b3f190c
Merge remote-tracking branch 'origin/develop' into feature/chapman39/…
chapman39 Sep 9, 2024
c5caac6
update shared file name
chapman39 Sep 9, 2024
ea1f981
bring back cmd line options, optionally enter them with string
chapman39 Sep 9, 2024
232fe88
update blt with benchmark fix
chapman39 Sep 9, 2024
36c82a2
run_benchmarks documentation
chapman39 Sep 9, 2024
7417e4b
working
chapman39 Sep 9, 2024
75aa408
style
chapman39 Sep 10, 2024
69024a7
Update src/docs/sphinx/dev_guide/profiling.rst
chapman39 Sep 11, 2024
19ce9e8
Update src/docs/sphinx/dev_guide/profiling.rst
chapman39 Sep 11, 2024
f434964
prefix benchmarks with physics, remove manual error prefix in slic calls
chapman39 Sep 11, 2024
f130b87
Merge branch 'feature/chapman39/spot' of github.com:LLNL/serac into f…
chapman39 Sep 11, 2024
18d1d8e
Tie benchmark command in with spot
chapman39 Sep 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions scripts/llnl/build_devtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

from argparse import ArgumentParser

import os


def parse_args():
"Parses args from command line"
Expand Down
4 changes: 4 additions & 0 deletions scripts/llnl/common_build_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,10 @@ def get_shared_libs_dir():
return pjoin(get_shared_base_dir(), "libs", get_project_name())


def get_shared_spot_dir():
return pjoin(get_shared_base_dir(), "califiles")
chapman39 marked this conversation as resolved.
Show resolved Hide resolved


def get_uberenv_path():
return pjoin(get_script_dir(), "../uberenv/uberenv.py")

Expand Down
22 changes: 20 additions & 2 deletions src/docs/sphinx/dev_guide/profiling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ Introduction to SPOT
LLNL for vizualizing performance data. SPOT is an external tool and does not need to be
linked into Serac.

Build Instructions
------------------
TPL Build Instructions
----------------------

To use Adiak and Caliper with Serac, install the ``profiling`` variant of ``serac``
with Spack, i.e., ``serac+profiling``. Note that these libraries are pre-built as
Expand Down Expand Up @@ -109,3 +109,21 @@ of this file, use `cali-query <https://software.llnl.gov/Caliper/tools.html#cali

To view this data with SPOT, open a browser, navigate to the SPOT server (e.g. `LC <https://lc.llnl.gov/spot2>`_), and open the directory containing one or more ``.cali`` files. For more information, watch this recorded `tutorial <https://www.youtube.com/watch?v=p8gjA6rbpvo>`_.

Benchmarking Serac
------------------

To run all of Serac's benchmarks in one command, first make sure Serac is configured
with benchmarking enabled (off by default). Then, run the build target ``run_benchmarks``.

.. code-block:: bash

./config-build.py -hc <host config file> -DENABLE_BENCHMARKS=ON
chapman39 marked this conversation as resolved.
Show resolved Hide resolved
cd <serac build location>
make -j
make run_benchmarks
find . -name "*.cali" -print0 | xargs -0 mv -t .
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@white238 Added this part to the docs just now. The Caliper files will not be located at the root of the build dir by default.

It's somewhat unfortunate we have to do that command but it might be avoidable in the future if blt_add_test and blt_add_benchmark added a WORKING_DIRECTORY option. https://cmake.org/cmake/help/latest/command/add_test.html#add-test

pwd

This will run all of Serac's benchmarks multiple times with varying MPI task counts, and generate a Caliper file for
each benchmark run. The ``find`` command afterwards ensures all Caliper files are moved to the same directory. Now, you
can visualize the results with SPOT, entering the path printed from ``pwd``.
2 changes: 2 additions & 0 deletions src/serac/infrastructure/tests/profiling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ TEST(Profiling, MeshRefinement)
pmesh->UniformRefinement();
}

// Add metadata
SERAC_SET_METADATA("test", "profiling");
SERAC_SET_METADATA("mesh_file", mesh_file.c_str());
SERAC_SET_METADATA("number_mesh_elements", pmesh->GetNE());

Expand Down
34 changes: 23 additions & 11 deletions src/serac/physics/benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,28 @@
#
# SPDX-License-Identifier: (BSD-3-Clause)

set(benchmark_depends serac_physics)
set(physics_benchmark_depends serac_physics)

blt_add_executable(NAME benchmark_thermal
SOURCES benchmark_thermal.cpp
DEPENDS_ON ${benchmark_depends}
OUTPUT_DIR ${PROJECT_BINARY_DIR}/benchmarks
FOLDER serac/benchmarks)
set(physics_benchmark_targets
physics_benchmark_functional
physics_benchmark_solid_nonlinear_solve
physics_benchmark_thermal
)

blt_add_executable(NAME benchmark_functional
SOURCES benchmark_functional.cpp
DEPENDS_ON ${benchmark_depends}
OUTPUT_DIR ${PROJECT_BINARY_DIR}/benchmarks
FOLDER serac/benchmarks)
# Create executable for each benchmark
foreach(physics_benchmark ${physics_benchmark_targets})
blt_add_executable(NAME ${physics_benchmark}
SOURCES ${physics_benchmark}.cpp
DEPENDS_ON ${physics_benchmark_depends}
OUTPUT_DIR ${PROJECT_BINARY_DIR}/benchmarks
FOLDER serac/benchmarks
)

# Add benchmarks with various task counts
foreach(task_count 1 4 16)
blt_add_benchmark(NAME ${physics_benchmark}_${task_count}_task_count
COMMAND ${physics_benchmark}
NUM_MPI_TASKS ${task_count}
)
endforeach()
endforeach()
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ int main(int argc, char* argv[])
// Initialize profiling
serac::profiling::initialize();

// Add metadata
SERAC_SET_METADATA("test", "functional");

SERAC_MARK_BEGIN("scalar H1");

SERAC_MARK_BEGIN("dimension 2, order 1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
#include "serac/physics/solid_mechanics.hpp"
#include "serac/physics/solid_mechanics_contact.hpp"

#include <functional>
#include <algorithm>
#include <fstream>
#include <functional>
#include <ostream>
#include <set>
#include <string>
#include <algorithm>

#include "axom/slic/core/SimpleLogger.hpp"
#include <gtest/gtest.h>
#include "mfem.hpp"

#include "serac/physics/materials/liquid_crystal_elastomer.hpp"
Expand All @@ -28,30 +28,62 @@

using namespace serac;

std::string mesh_path = ".";

enum Prec
enum class Prec
{
JACOBI,
STRUMPACK,
CHOLESKI,
LU,
MULTIGRID,
PETSC_MULTIGRID
PETSC_MULTIGRID,
NONE
};

enum NonlinSolve
enum class NonlinSolve
{
NEWTON,
LINESEARCH,
CRITICALPOINT,
TRUSTREGION
TRUSTREGION,
NONE
};

NonlinSolve nonlinSolve = NonlinSolve::TRUSTREGION;
Prec prec = Prec::JACOBI;
std::string mesh_path = ".";
// string->value matching for optionally entering options as string in command line
std::map<std::string, Prec> precMap = {
{"jacobi", Prec::JACOBI}, {"strumpack", Prec::STRUMPACK}, {"choleski", Prec::CHOLESKI},
{"lu", Prec::LU}, {"multigrid", Prec::MULTIGRID}, {"petsc_multigrid", Prec::PETSC_MULTIGRID},
{"none", Prec::NONE},
};
std::map<std::string, NonlinSolve> nonlinSolveMap = {
{"newton", NonlinSolve::NEWTON},
{"linesearch", NonlinSolve::LINESEARCH},
{"critialpoint", NonlinSolve::CRITICALPOINT},
{"trustregion", NonlinSolve::TRUSTREGION},
{"none", NonlinSolve::NONE},
};

const std::string precToString(Prec prec)
{
for (const auto& p : precMap) {
if (p.second == prec) {
return p.first;
}
}
return "unknown";
}

auto get_opts(int max_iters, double abs_tol = 1e-9)
const std::string nonlinSolveToString(NonlinSolve nonlinSolve)
{
for (const auto& n : nonlinSolveMap) {
if (n.second == nonlinSolve) {
return n.first;
}
}
return "unknown";
}

auto get_opts(NonlinSolve nonlinSolve, Prec prec, int max_iters, double abs_tol = 1e-9)
{
serac::NonlinearSolverOptions nonlinear_options{
.nonlin_solver = NonlinearSolver::TrustRegion,
Expand Down Expand Up @@ -108,6 +140,10 @@ auto get_opts(int max_iters, double abs_tol = 1e-9)
nonlinear_options.nonlin_solver = NonlinearSolver::TrustRegion;
break;
}
case NonlinSolve::NONE:
default: {
SLIC_ERROR_ROOT("invalid nonlinear solver specified");
}
}

switch (prec) {
Expand Down Expand Up @@ -149,18 +185,16 @@ auto get_opts(int max_iters, double abs_tol = 1e-9)
linear_options.petsc_preconditioner = PetscPCType::HMG;
break;
}
case Prec::NONE:
default: {
SLIC_ERROR_ROOT("error, invalid preconditioner specified");
SLIC_ERROR_ROOT("invalid preconditioner specified");
}
}

return std::make_pair(nonlinear_options, linear_options);
}

#include <ostream>
#include <fstream>

void functional_solid_test_euler()
void functional_solid_test_euler(NonlinSolve nonlinSolve, Prec prec)
{
// initialize serac
axom::sidre::DataStore datastore;
Expand Down Expand Up @@ -192,7 +226,7 @@ void functional_solid_test_euler()
// solid mechanics
using seracSolidType = serac::SolidMechanics<ORDER, DIM, serac::Parameters<>>;

auto [nonlinear_options, linear_options] = get_opts(3 * Nx * Ny * Nz, 1e-9);
auto [nonlinear_options, linear_options] = get_opts(nonlinSolve, prec, 3 * Nx * Ny * Nz, 1e-9);

auto seracSolid = std::make_unique<seracSolidType>(
nonlinear_options, linear_options, serac::solid_mechanics::default_quasistatic_options,
Expand Down Expand Up @@ -224,7 +258,7 @@ void functional_solid_test_euler()
}
}

void functional_solid_test_nonlinear_buckle(double loadMagnitude)
void functional_solid_test_nonlinear_buckle(NonlinSolve nonlinSolve, Prec prec, double loadMagnitude)
{
// initialize serac
axom::sidre::DataStore datastore;
Expand Down Expand Up @@ -258,7 +292,7 @@ void functional_solid_test_nonlinear_buckle(double loadMagnitude)
// solid mechanics
using seracSolidType = serac::SolidMechanics<ORDER, DIM, serac::Parameters<>>;

auto [nonlinear_options, linear_options] = get_opts(3 * Nx * Ny * Nz, 1e-11);
auto [nonlinear_options, linear_options] = get_opts(nonlinSolve, prec, 3 * Nx * Ny * Nz, 1e-11);

auto seracSolid = std::make_unique<seracSolidType>(
nonlinear_options, linear_options, serac::solid_mechanics::default_quasistatic_options,
Expand All @@ -280,30 +314,64 @@ void functional_solid_test_nonlinear_buckle(double loadMagnitude)
seracSolid->outputStateToDisk("paraview_buckle_easy");
}

TEST(SolidMechanics, nonlinear_solve_buckle_easy) { functional_solid_test_nonlinear_buckle(5e-10); }
// TEST(SolidMechanics, nonlinear_solve_buckle_medium) { functional_solid_test_nonlinear_buckle(4e-4); }
// TEST(SolidMechanics, nonlinear_solve_buckle_hard) { functional_solid_test_nonlinear_buckle(3e-2); }
// TEST(SolidMechanics, nonlinear_solve_euler) { functional_solid_test_euler(); }

int main(int argc, char* argv[])
{
axom::CLI::App app{"Nonlinear problems"};
// app.add_option("-p", mesh_path, "Path to mesh files")->check(axom::CLI::ExistingDirectory);
app.add_option("--nonlinear-solver", nonlinSolve, "Nonlinear solver", true);
app.add_option("--preconditioner", prec, "Preconditioner", true);
app.set_help_flag("--help");
app.allow_extras()->parse(argc, argv);
serac::initialize(argc, argv);

::testing::InitGoogleTest(&argc, argv);
SERAC_MARK_FUNCTION;

serac::initialize(argc, argv);
NonlinSolve nonlinSolve = NonlinSolve::NONE;
Prec prec = Prec::NONE;

axom::CLI::App app{"Solid Nonlinear Solve Benchmark"};
// app.add_option("-m,--mesh", mesh_path, "Path to mesh files")->check(axom::CLI::ExistingDirectory);
app.add_option("-n,--nonlinear-solver", nonlinSolve, "Nonlinear solver")
->transform(axom::CLI::CheckedTransformer(nonlinSolveMap, axom::CLI::ignore_case));
app.add_option("-p,--preconditioner", prec, "Preconditioner")
->transform(axom::CLI::CheckedTransformer(precMap, axom::CLI::ignore_case));

// Parse the arguments and check if they are good
try {
CLI11_PARSE(app, argc, argv);
} catch (const axom::CLI::ParseError& e) {
serac::logger::flush();
if (e.get_name() == "CallForHelp") {
auto msg = app.help();
SLIC_INFO_ROOT(msg);
serac::exitGracefully();
} else {
auto err_msg = axom::CLI::FailureMessage::simple(&app, e);
SLIC_ERROR_ROOT(err_msg);
}
}

SERAC_SET_METADATA("test", "solid_nonlinear_solve");
SERAC_SET_METADATA("nonlinear solver", std::to_string(nonlinSolve));
SERAC_SET_METADATA("preconditioner", std::to_string(prec));

int result = RUN_ALL_TESTS();
serac::exitGracefully(result);
// If you do not specify preconditioner and nonlinear solver, run the following pre-selected options
if (nonlinSolve == NonlinSolve::NONE && prec == Prec::NONE) {
SERAC_MARK_BEGIN("Jacobi Preconditioner");
functional_solid_test_nonlinear_buckle(NonlinSolve::NEWTON, Prec::JACOBI, 5e-10);
SERAC_MARK_END("Jacobi Preconditioner");

SERAC_MARK_BEGIN("Multigrid Preconditioner");
functional_solid_test_nonlinear_buckle(NonlinSolve::NEWTON, Prec::MULTIGRID, 5e-10);
SERAC_MARK_END("Multigrid Preconditioner");

SERAC_MARK_BEGIN("Petsc Multigrid Preconditioner");
functional_solid_test_nonlinear_buckle(NonlinSolve::NEWTON, Prec::PETSC_MULTIGRID, 5e-10);
SERAC_MARK_END("Petsc Multigrid Preconditioner");
} else {
SERAC_SET_METADATA("nonlinear solver", nonlinSolveToString(nonlinSolve));
SERAC_SET_METADATA("preconditioner", precToString(prec));

SERAC_MARK_BEGIN("Custom Preconditioner");
functional_solid_test_nonlinear_buckle(nonlinSolve, prec, 5e-10);
SERAC_MARK_END("Custom Preconditioner");
}

// functional_solid_test_nonlinear_buckle(4e-4);
// functional_solid_test_nonlinear_buckle(3e-2);
// functional_solid_test_euler();

return result;
serac::exitGracefully(0);
}
1 change: 0 additions & 1 deletion src/serac/physics/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ set(physics_parallel_test_sources
dynamic_thermal_adjoint.cpp
solid_reaction_adjoint.cpp
thermal_nonlinear_solve.cpp
solid_nonlinear_solve.cpp
)
blt_list_append(TO physics_parallel_test_sources ELEMENTS contact_patch.cpp contact_beam.cpp IF TRIBOL_FOUND)

Expand Down