initial benchmarking
This commit is contained in:
56
benchmarks/CMakeLists.txt
Normal file
56
benchmarks/CMakeLists.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
# Benchmarks CMakeLists.txt
|
||||
include(FetchContent)
|
||||
|
||||
# Download and configure Google Benchmark
|
||||
FetchContent_Declare(
|
||||
googlebenchmark
|
||||
URL https://github.com/google/benchmark/archive/v1.8.3.zip
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
)
|
||||
|
||||
# Prevent overriding the parent project's compiler/linker settings
|
||||
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Suppressing benchmark's tests" FORCE)
|
||||
set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "Suppressing benchmark's gtest tests" FORCE)
|
||||
|
||||
# Suppress warnings in Google Benchmark build
|
||||
set(BENCHMARK_ENABLE_WERROR OFF CACHE BOOL "Disable -Werror in benchmark build" FORCE)
|
||||
|
||||
# Make Google Benchmark available
|
||||
FetchContent_MakeAvailable(googlebenchmark)
|
||||
|
||||
# Get the benchmark target and suppress warnings
|
||||
if(TARGET benchmark)
|
||||
target_compile_options(benchmark PRIVATE
|
||||
-Wno-conversion
|
||||
-Wno-sign-conversion
|
||||
)
|
||||
endif()
|
||||
|
||||
if(TARGET benchmark_main)
|
||||
target_compile_options(benchmark_main PRIVATE
|
||||
-Wno-conversion
|
||||
-Wno-sign-conversion
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create benchmark executable
|
||||
add_executable(benchmarks
|
||||
main.cpp
|
||||
core/battle_simulation_bench.cpp
|
||||
core/pokemon_creation_bench.cpp
|
||||
)
|
||||
|
||||
# Link with Google Benchmark and our library
|
||||
target_link_libraries(benchmarks
|
||||
PRIVATE
|
||||
benchmark::benchmark
|
||||
benchmark::benchmark_main
|
||||
PokemonSim::pokemon_battle_sim
|
||||
)
|
||||
|
||||
# Include directories
|
||||
target_include_directories(benchmarks
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
)
|
||||
@@ -1,40 +1,92 @@
|
||||
# Benchmarks Directory (`benchmarks/`)
|
||||
|
||||
This directory contains performance benchmarks and profiling tools for the Pokemon battle simulator.
|
||||
This directory contains performance benchmarks and profiling tools for the Pokemon battle simulator using Google Benchmark.
|
||||
|
||||
## Planned Structure
|
||||
## Quick Start
|
||||
|
||||
```
|
||||
benchmarks/
|
||||
├── core/ # Core system benchmarks
|
||||
│ ├── battle_speed.cpp # Battle simulation speed
|
||||
│ ├── pokemon_creation.cpp # Pokemon instantiation
|
||||
│ ├── move_calculation.cpp # Move damage calculations
|
||||
│ └── type_lookup.cpp # Type effectiveness lookups
|
||||
├── data/ # Data loading benchmarks
|
||||
│ ├── json_parsing.cpp # JSON data parsing speed
|
||||
│ └── data_caching.cpp # Cache performance
|
||||
├── ai/ # AI performance benchmarks
|
||||
│ ├── ai_decision_time.cpp # AI move selection speed
|
||||
│ └── minimax_depth.cpp # Minimax algorithm scaling
|
||||
├── memory/ # Memory usage benchmarks
|
||||
│ ├── memory_usage.cpp # Memory footprint analysis
|
||||
│ └── allocation_speed.cpp # Dynamic allocation performance
|
||||
├── scenarios/ # Real-world scenario benchmarks
|
||||
│ ├── tournament.cpp # Tournament simulation
|
||||
│ └── monte_carlo.cpp # Monte Carlo battle analysis
|
||||
├── results/ # Benchmark results and reports
|
||||
│ ├── baseline/ # Baseline performance data
|
||||
│ └── reports/ # Generated performance reports
|
||||
└── CMakeLists.txt # Benchmark build configuration
|
||||
To run the benchmarks:
|
||||
|
||||
```bash
|
||||
# Build with benchmarks enabled
|
||||
cmake -DBUILD_BENCHMARKS=ON ..
|
||||
make -j$(nproc)
|
||||
|
||||
# Run benchmarks
|
||||
./benchmarks/benchmarks
|
||||
|
||||
# Run specific benchmark
|
||||
./benchmarks/benchmarks --benchmark_filter=BM_BattleSimulation
|
||||
|
||||
# Save results to JSON
|
||||
./benchmarks/benchmarks --benchmark_out=results.json --benchmark_out_format=json
|
||||
```
|
||||
|
||||
## Benchmarking Framework
|
||||
## Benchmark Examples
|
||||
|
||||
- **Google Benchmark**: Primary benchmarking library
|
||||
- **Automated Regression Detection**: Performance alerts on slowdowns
|
||||
- **Multiple Metrics**: Time, memory, CPU usage, cache misses
|
||||
- **Statistical Analysis**: Multiple runs with confidence intervals
|
||||
### Basic Benchmark
|
||||
```cpp
|
||||
static void BM_SimpleFunction(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// Code to benchmark
|
||||
function_to_test();
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SimpleFunction);
|
||||
```
|
||||
|
||||
### Parameterized Benchmark
|
||||
```cpp
|
||||
static void BM_Parameterized(benchmark::State& state) {
|
||||
int size = state.range(0);
|
||||
for (auto _ : state) {
|
||||
// Code using size parameter
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_Parameterized)->Arg(100)->Arg(1000)->Arg(10000);
|
||||
```
|
||||
|
||||
### Fixture-based Benchmark
|
||||
```cpp
|
||||
class MyFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const benchmark::State& state) override {
|
||||
// Setup code
|
||||
}
|
||||
void TearDown(const benchmark::State& state) override {
|
||||
// Cleanup code
|
||||
}
|
||||
};
|
||||
|
||||
BENCHMARK_F(MyFixture, BM_TestWithFixture)(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// Test code
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Current Benchmarks
|
||||
|
||||
### Core Benchmarks (`core/`)
|
||||
- **Battle Simulation**: Measures battle simulation performance
|
||||
- **Pokemon Creation**: Tests Pokemon instantiation speed
|
||||
- **Bulk Operations**: Performance with multiple Pokemon
|
||||
- **Health Operations**: Getter/setter performance
|
||||
|
||||
## Benchmark Output
|
||||
|
||||
The benchmarks provide detailed timing information including:
|
||||
- **Mean**: Average execution time
|
||||
- **Median**: Middle value of execution times
|
||||
- **StdDev**: Standard deviation of results
|
||||
- **Iterations**: Number of times the benchmark was run
|
||||
|
||||
## Performance Optimization Tips
|
||||
|
||||
1. **Use `benchmark::DoNotOptimize()`** to prevent compiler optimization
|
||||
2. **Use `benchmark::ClobberMemory()`** for memory benchmarks
|
||||
3. **Set appropriate iteration counts** for consistent measurements
|
||||
4. **Use fixtures** for complex setup/teardown scenarios
|
||||
5. **Run multiple repetitions** for statistical significance
|
||||
|
||||
## Key Performance Targets
|
||||
|
||||
|
||||
81
benchmarks/core/battle_simulation_bench.cpp
Normal file
81
benchmarks/core/battle_simulation_bench.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <pokemon_battle_sim.h>
|
||||
|
||||
// Benchmark for battle simulation performance
|
||||
static void BM_BattleSimulation(benchmark::State& state) {
|
||||
// Set up Pokemon for the benchmark
|
||||
PokemonSim::Pokemon pikachu("Pikachu", 100);
|
||||
PokemonSim::Pokemon charizard("Charizard", 150);
|
||||
|
||||
// Run the benchmark
|
||||
for (auto _ : state) {
|
||||
// Simulate a battle between the two Pokemon
|
||||
PokemonSim::simulateBattle(pikachu, charizard);
|
||||
|
||||
// Reset health for next iteration
|
||||
pikachu.setHealth(100);
|
||||
charizard.setHealth(150);
|
||||
}
|
||||
}
|
||||
|
||||
// Register the benchmark with different configurations
|
||||
BENCHMARK(BM_BattleSimulation)
|
||||
->Unit(benchmark::kMicrosecond) // Measure in microseconds
|
||||
->Iterations(1000) // Run 1000 iterations
|
||||
->Repetitions(3); // Repeat the benchmark 3 times for statistical analysis
|
||||
|
||||
// Benchmark with varying Pokemon health values
|
||||
static void BM_BattleSimulationWithHealth(benchmark::State& state) {
|
||||
int health = static_cast<int>(state.range(0));
|
||||
|
||||
PokemonSim::Pokemon pokemon1("Pokemon1", health);
|
||||
PokemonSim::Pokemon pokemon2("Pokemon2", health);
|
||||
|
||||
for (auto _ : state) {
|
||||
PokemonSim::simulateBattle(pokemon1, pokemon2);
|
||||
|
||||
// Reset health
|
||||
pokemon1.setHealth(health);
|
||||
pokemon2.setHealth(health);
|
||||
}
|
||||
}
|
||||
|
||||
// Register benchmark with different health values
|
||||
BENCHMARK(BM_BattleSimulationWithHealth)
|
||||
->Arg(50) // Test with 50 HP
|
||||
->Arg(100) // Test with 100 HP
|
||||
->Arg(200) // Test with 200 HP
|
||||
->Unit(benchmark::kMicrosecond);
|
||||
|
||||
// Benchmark for multiple battle simulations
|
||||
static void BM_MultipleBattles(benchmark::State& state) {
|
||||
int numBattles = static_cast<int>(state.range(0));
|
||||
|
||||
std::vector<PokemonSim::Pokemon> team1;
|
||||
std::vector<PokemonSim::Pokemon> team2;
|
||||
|
||||
// Create teams of Pokemon
|
||||
for (int i = 0; i < numBattles; ++i) {
|
||||
team1.emplace_back("Pikachu" + std::to_string(i), 100);
|
||||
team2.emplace_back("Charizard" + std::to_string(i), 150);
|
||||
}
|
||||
|
||||
for (auto _ : state) {
|
||||
// Simulate multiple battles
|
||||
for (int i = 0; i < numBattles; ++i) {
|
||||
PokemonSim::simulateBattle(team1[static_cast<size_t>(i)], team2[static_cast<size_t>(i)]);
|
||||
}
|
||||
|
||||
// Reset all Pokemon health
|
||||
for (int i = 0; i < numBattles; ++i) {
|
||||
team1[static_cast<size_t>(i)].setHealth(100);
|
||||
team2[static_cast<size_t>(i)].setHealth(150);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_MultipleBattles)
|
||||
->Arg(10) // Test with 10 battles
|
||||
->Arg(50) // Test with 50 battles
|
||||
->Arg(100) // Test with 100 battles
|
||||
->Unit(benchmark::kMillisecond);
|
||||
115
benchmarks/core/pokemon_creation_bench.cpp
Normal file
115
benchmarks/core/pokemon_creation_bench.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <pokemon_battle_sim.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// Benchmark for Pokemon creation performance
|
||||
static void BM_PokemonCreation(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// Create a Pokemon - this is what we're measuring
|
||||
PokemonSim::Pokemon pokemon("Pikachu", 100);
|
||||
|
||||
// Prevent compiler optimization from eliminating the Pokemon
|
||||
benchmark::DoNotOptimize(pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_PokemonCreation)
|
||||
->Unit(benchmark::kNanosecond)
|
||||
->Iterations(10000);
|
||||
|
||||
// Benchmark for Pokemon creation with different names and health values
|
||||
static void BM_PokemonCreationParameterized(benchmark::State& state) {
|
||||
std::string name = "Pokemon" + std::to_string(static_cast<int>(state.range(0)));
|
||||
int health = static_cast<int>(state.range(1));
|
||||
|
||||
for (auto _ : state) {
|
||||
PokemonSim::Pokemon pokemon(name, health);
|
||||
benchmark::DoNotOptimize(pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_PokemonCreationParameterized)
|
||||
->Args({1, 50}) // Pokemon1, 50 HP
|
||||
->Args({2, 100}) // Pokemon2, 100 HP
|
||||
->Args({3, 200}) // Pokemon3, 200 HP
|
||||
->Unit(benchmark::kNanosecond);
|
||||
|
||||
// Benchmark for bulk Pokemon creation
|
||||
static void BM_BulkPokemonCreation(benchmark::State& state) {
|
||||
int numPokemon = static_cast<int>(state.range(0));
|
||||
|
||||
for (auto _ : state) {
|
||||
std::vector<PokemonSim::Pokemon> pokemonList;
|
||||
|
||||
// Create multiple Pokemon
|
||||
for (int i = 0; i < numPokemon; ++i) {
|
||||
pokemonList.emplace_back("Pokemon" + std::to_string(i), 100 + i * 10);
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(pokemonList);
|
||||
benchmark::ClobberMemory(); // Ensure memory operations are not optimized away
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_BulkPokemonCreation)
|
||||
->Arg(10) // Create 10 Pokemon
|
||||
->Arg(100) // Create 100 Pokemon
|
||||
->Arg(1000) // Create 1000 Pokemon
|
||||
->Unit(benchmark::kMicrosecond);
|
||||
|
||||
// Benchmark for Pokemon health modifications
|
||||
static void BM_PokemonHealthOperations(benchmark::State& state) {
|
||||
PokemonSim::Pokemon pokemon("TestPokemon", 100);
|
||||
|
||||
for (auto _ : state) {
|
||||
// Perform various health operations
|
||||
pokemon.setHealth(50);
|
||||
int health = pokemon.getHealth();
|
||||
pokemon.setHealth(health + 25);
|
||||
std::string name = pokemon.getName();
|
||||
|
||||
benchmark::DoNotOptimize(health);
|
||||
benchmark::DoNotOptimize(name);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(BM_PokemonHealthOperations)
|
||||
->Unit(benchmark::kNanosecond)
|
||||
->Iterations(100000);
|
||||
|
||||
// Fixture for benchmarks that need setup/teardown
|
||||
class PokemonFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const benchmark::State& /*state*/) override {
|
||||
// Set up Pokemon for each benchmark iteration
|
||||
pokemon1 = std::make_unique<PokemonSim::Pokemon>("Pikachu", 100);
|
||||
pokemon2 = std::make_unique<PokemonSim::Pokemon>("Charizard", 150);
|
||||
}
|
||||
|
||||
void TearDown(const benchmark::State& /*state*/) override {
|
||||
// Clean up after each benchmark iteration
|
||||
pokemon1.reset();
|
||||
pokemon2.reset();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<PokemonSim::Pokemon> pokemon1;
|
||||
std::unique_ptr<PokemonSim::Pokemon> pokemon2;
|
||||
};
|
||||
|
||||
// Benchmark using fixture
|
||||
BENCHMARK_F(PokemonFixture, BM_BattleWithFixture)(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
PokemonSim::simulateBattle(*pokemon1, *pokemon2);
|
||||
|
||||
// Reset health
|
||||
pokemon1->setHealth(100);
|
||||
pokemon2->setHealth(150);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(PokemonFixture, BM_BattleWithFixture)
|
||||
->Unit(benchmark::kMicrosecond)
|
||||
->Iterations(1000);
|
||||
18
benchmarks/main.cpp
Normal file
18
benchmarks/main.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
// Main function for Google Benchmark
|
||||
// This is automatically provided by benchmark::benchmark_main
|
||||
// but we include it for clarity and potential custom initialization
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// Initialize benchmark
|
||||
::benchmark::Initialize(&argc, argv);
|
||||
|
||||
// Set any global benchmark configuration here
|
||||
// For example, you can set the minimum time per benchmark, etc.
|
||||
|
||||
// Run the benchmarks
|
||||
::benchmark::RunSpecifiedBenchmarks();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user