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

[External] Adding Google benchmark option in CMake #12867

Merged
merged 4 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ endif()
# If no test policy enable by default
option(KRATOS_BUILD_TESTING "KRATOS_BUILD_TESTING defines if the C++ tests are compiled. These increase compilation time, but if not set only python tests can be executed. Default setting is ON" ON)

# If no benchmark policy enable by default
option(KRATOS_BUILD_BENCHMARK "KRATOS_BUILD_BENCHMARK defines if the C++ benchmarks (Google benchmark) are compiled. These increase compilation time. Default setting is OFF" OFF)

# If no pch policy disable by default
option(KRATOS_USE_PCH "KRATOS_USE_PCH defines if pch will be used during the compilation. This may will decrease compilation for clean build or if core components are touched. Default setting is OFF" OFF)

Expand Down Expand Up @@ -288,6 +291,7 @@ SET(INSTALL_PYTHON_FILES ON) # To be removed when all applications are po
include(install_function)
include(KratosDependencies)
include(KratosGTest)
include(KratosGBenchmark)
include(FetchContent)

# Logger configuration
Expand Down Expand Up @@ -320,6 +324,31 @@ if(KRATOS_BUILD_TESTING MATCHES ON)
set_directory_properties(PROPERTIES COMPILE_OPTIONS "${kratos_root_compile_options}")
endif(KRATOS_BUILD_TESTING MATCHES ON)

# Benchmarking
if(KRATOS_BUILD_BENCHMARK MATCHES ON)
# Add the definitions if required
ADD_DEFINITIONS(-DKRATOS_BUILD_BENCHMARKING)

# Retrieve a copy of the current directory's `COMPILE_OPTIONS`
get_directory_property(kratos_root_compile_options COMPILE_OPTIONS)

# Disable warnings (needed by centos. We should all love centos, it clearly needs some affection)
add_compile_options(-w)

FetchContent_Declare(
googlebenchmark
URL https://github.com/google/benchmark/archive/v1.9.0.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
set(CMAKE_INSTALL_LIBDIR "libs") # In Linux default dir is lib
set(CMAKE_INSTALL_BINDIR "libs") # In Win default dir is bin
FetchContent_MakeAvailable(googlebenchmark)

# Restore the current directory's old `COMPILE_OPTIONS`
set_directory_properties(PROPERTIES COMPILE_OPTIONS "${kratos_root_compile_options}")
endif(KRATOS_BUILD_BENCHMARK MATCHES ON)

################### PYBIND11

# Try to use python executable from env variable
Expand Down
13 changes: 13 additions & 0 deletions cmake_modules/KratosGBenchmark.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This function automatically configures a given application to build its benchmarks
macro(kratos_add_benchmarks)
set(options USE_MPI USE_CUSTOM_MAIN)
set(oneValueArgs TARGET WORKING_DIRECTORY)
set(multiValueArgs SOURCES)

cmake_parse_arguments(KRATOS_ADD_BENCHMARK "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if(KRATOS_ADD_BENCHMARK_SOURCES)
include(GoogleBenchmark)
endif(KRATOS_ADD_BENCHMARK_SOURCES)

endmacro(kratos_add_benchmarks)
15 changes: 15 additions & 0 deletions kratos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@ if(${KRATOS_BUILD_TESTING} MATCHES ON)
gtest_discover_tests(KratosCoreTest DISCOVERY_MODE PRE_TEST)
endif(${KRATOS_BUILD_TESTING} MATCHES ON)

## Kratos benchmark sources. Disabled by default
if(${KRATOS_BUILD_BENCHMARK} MATCHES ON)
file(GLOB_RECURSE KRATOS_BENCHMARK_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/*.cpp
)

foreach(file ${KRATOS_BENCHMARK_SOURCES})
get_filename_component(filename ${file} NAME_WE)
add_executable(${filename} ${file})
target_link_libraries(${filename} PUBLIC KratosCore benchmark::benchmark)
set_target_properties(${filename} PROPERTIES COMPILE_DEFINITIONS "KRATOS_BENCHMARK=IMPORT,API")
install(TARGETS ${filename} DESTINATION benchmark)
endforeach(file ${KRATOS_BENCHMARK_SOURCES})
endif(${KRATOS_BUILD_BENCHMARK} MATCHES ON)

## Define KratosVersion object
add_library(KratosVersion OBJECT ${KRATOS_VERSION_SOURCES})
set_target_properties(KratosVersion PROPERTIES COMPILE_DEFINITIONS "KRATOS_VERSION=IMPORT,API")
Expand Down
46 changes: 46 additions & 0 deletions kratos/benchmarks/example_benchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// | / |
// ' / __| _` | __| _ \ __|
// . \ | ( | | ( |\__ `
// _|\_\_| \__,_|\__|\___/ ____/
// Multi-Physics
//
// License: BSD License
// Kratos default license: kratos/license.txt
//
// Main authors: Vicente Mataix Ferrandiz
//

// System includes

// External includes
#include <benchmark/benchmark.h>

// Project includes
#include "geometries/point.h"
#include "geometries/triangle_3d_3.h"
#include "utilities/geometry_utilities/nearest_point_utilities.h"

namespace Kratos
{

// Sample data for benchmarking
Point::Pointer p_point_1(make_shared<Point>( 0.0, 0.0, 0.0));
Point::Pointer p_point_2(make_shared<Point>( 1.0, 0.0, 0.0));
Point::Pointer p_point_3(make_shared<Point>( 0.0, 1.0, 0.0));

Triangle3D3<Point> triangle(p_point_1, p_point_3, p_point_2);
Point nearest_point(0.0, 0.0, 0.0);
Point inside_point(0.2, 0.1, 0.00);

static void BM_TriangleNearestPoint(benchmark::State& state) {
for (auto _ : state) {
NearestPointUtilities::TriangleNearestPoint(inside_point, triangle, nearest_point);
}
}

// Register the function as a benchmark
BENCHMARK(BM_TriangleNearestPoint);

} // namespace Kratos

BENCHMARK_MAIN();
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import json
import pandas as pd
import matplotlib.pyplot as plt
import argparse

def main(filenames):
"""
Main function to generate a combined plot from multiple Google Benchmark JSON outputs.

Args:
filenames (list of str): List of paths to the JSON files containing benchmark results.

The function performs the following steps:
1. Loads the JSON files specified in the filenames list.
2. Combines the 'benchmarks' section of all JSON data into a single pandas DataFrame.
3. Plots the 'cpu_time' and 'real_time' for each benchmark with bars grouped by input filename.

The resulting plot displays:
- X-axis: Benchmark names (with labels based on input filenames)
- Y-axis: Time in nanoseconds
- Bars grouped by CPU Time and Real Time for each file

NOTE: The JSON files must be generated using Google Benchmark with:
./benchmark_name --benchmark_format=json --benchmark_out=filename.json
"""
combined_data = []

# Process each JSON file
for filename in filenames:
with open(filename) as f:
data = json.load(f)

# Extract benchmark information and add filename as a source
benchmarks = data["benchmarks"]
for benchmark in benchmarks:
benchmark["source"] = filename
combined_data.extend(benchmarks)

# Convert combined data to a pandas DataFrame
benchmark_df = pd.DataFrame(combined_data)

# Plot the results
plt.figure(figsize=(12, 8))
bar_width = 0.35
x_labels = benchmark_df["name"].unique()
x = range(len(x_labels))
offset = 0

# Plot for each input file
for filename in filenames:
subset = benchmark_df[benchmark_df["source"] == filename]
plt.bar(
[pos + offset for pos in x],
subset["real_time"],
bar_width,
label=f"{filename} - Real Time",
alpha=0.7
)
plt.bar(
[pos + offset for pos in x],
subset["cpu_time"],
bar_width,
label=f"{filename} - CPU Time",
alpha=0.7
)
offset += bar_width

# Customize the plot
plt.title("Benchmark Performance Across Files")
plt.xlabel("Benchmark Name")
plt.ylabel("Time (ns)")
plt.xticks([pos + bar_width for pos in x], x_labels, rotation=45, ha="right")
plt.legend()
plt.tight_layout()

# Show the plot
plt.show()

if __name__ == "__main__":
"""
This script can be run from the command line to generate a combined plot from multiple Google Benchmark JSON outputs.
Example usage:
python generate_plot_google_benchmark.py --filenames filename1.json filename2.json
"""
# Parse command line arguments
parser = argparse.ArgumentParser(description='Generate a combined plot from multiple Google Benchmark JSON results.')
parser.add_argument('--filenames', nargs='+', type=str, help='The list of JSON files containing benchmark results')
args = parser.parse_args()
main(args.filenames)
Loading