Skip to content
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
36 changes: 36 additions & 0 deletions .github/workflows/benchmark_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: "CI: Benchmark Release"

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
benchmark_release:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt update
sudo apt install -y build-essential cmake libhwloc-dev

- name: Build in Release mode with benchmarks
working-directory: ${{ github.workspace }}
run: |
mkdir -p build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DDSF_BENCHMARKS=ON -DCMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/install
cmake --build . -j$(nproc) --config Release

- name: Run benchmarks
working-directory: ${{ github.workspace }}/benchmark
run: |
for bench in *.out; do
echo "Running $bench"
./$bench
done
3 changes: 1 addition & 2 deletions .github/workflows/cmake_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt update
sudo apt install -y lcov gcovr build-essential cmake libtbb-dev libsimdjson-dev libhwloc-dev
sudo apt install -y lcov gcovr build-essential cmake libhwloc-dev

- name: Install dependencies on macOS
if: matrix.os == 'macos-latest'
Expand All @@ -37,7 +37,6 @@ jobs:
git clone https://github.com/microsoft/vcpkg.git vcpkg
cd vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg install tbb:x64-windows simdjson:x64-windows
echo "VCPKG_ROOT=$env:GITHUB_WORKSPACE\vcpkg" >> $env:GITHUB_ENV
echo "VCPKG_INSTALLED=$env:GITHUB_WORKSPACE\vcpkg\installed\x64-windows" >> $env:GITHUB_ENV

Expand Down
4 changes: 0 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
[submodule "extern/benchmark"]
path = extern/benchmark
url = https://github.com/sbaldu/benchmark.git

[submodule "extern/doxygen-awesome"]
path = extern/doxygen-awesome
url = https://github.com/jothepro/doxygen-awesome-css.git
16 changes: 14 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ project(

option(DSF_TESTS "Build DSF tests" OFF)
option(DSF_EXAMPLES "Build DSF examples" OFF)
option(DSF_BENCHMARKS "Build DSF benchmarks" OFF)
option(DSF_BUILD_PIC "Build DSF with position-independent code" OFF)
option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF)

# If CMAKE_BUILD_TYPE not set, default to Debug
if(NOT CMAKE_BUILD_TYPE)
if(BUILD_PYTHON_BINDINGS)
if(BUILD_PYTHON_BINDINGS OR DSF_BENCHMARKS)
set(CMAKE_BUILD_TYPE
"Release"
CACHE STRING
"Build type (default: Release when building Python bindings)"
"Build type (default: Release when building Python bindings or benchmarks)"
FORCE)
else()
set(CMAKE_BUILD_TYPE
Expand All @@ -52,6 +53,10 @@ if(CMAKE_BUILD_TYPE MATCHES "Release")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2")
endif()
elseif(CMAKE_BUILD_TYPE MATCHES "Profile")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Ofast -march=native -flto=auto -pg")
endif()
Comment on lines +56 to +59
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

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

The Profile build type uses -march=native which creates binaries optimized for the build machine's CPU architecture. This can cause portability issues if binaries are distributed. Consider documenting this limitation or using a separate option to enable -march=native for profiling.

Copilot uses AI. Check for mistakes.
elseif(CMAKE_BUILD_TYPE MATCHES "Coverage")
set(DSF_TESTS ON)
message(STATUS "Enable code coverage")
Expand Down Expand Up @@ -272,3 +277,10 @@ if(DSF_EXAMPLES)
set(CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX};${CMAKE_PREFIX_PATH}")
add_subdirectory(examples)
endif()

# Benchmarks
message(STATUS "Build DSF benchmarks: ${DSF_BENCHMARKS}")
if(DSF_BENCHMARKS)
set(CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX};${CMAKE_PREFIX_PATH}")
add_subdirectory(benchmark)
endif()
150 changes: 150 additions & 0 deletions benchmark/Bench_Agent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#include "dsf/mobility/Agent.hpp"

#include <benchmark/benchmark.h>
#include <memory>

static void BM_Agent_ConstructionWithItineraryId(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
std::time_t spawnTime = 0;
for (auto _ : state) {
dsf::mobility::Agent agent(spawnTime++, 1, 0);
benchmark::DoNotOptimize(agent);
}
}

static void BM_Agent_ConstructionWithTrip(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
std::time_t spawnTime = 0;
std::vector<dsf::Id> trip = {1, 2, 3};
for (auto _ : state) {
dsf::mobility::Agent agent(spawnTime++, trip, 0);
benchmark::DoNotOptimize(agent);
}
}

static void BM_Agent_ConstructionRandom(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
std::time_t spawnTime = 0;
for (auto _ : state) {
dsf::mobility::Agent agent(spawnTime++);
benchmark::DoNotOptimize(agent);
}
}

static void BM_Agent_SetSrcNodeId(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
for (auto _ : state) {
agent.setSrcNodeId(5);
}
}

static void BM_Agent_SetStreetId(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
for (auto _ : state) {
agent.setStreetId(10);
}
}

static void BM_Agent_SetNextStreetId(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
for (auto _ : state) {
agent.setNextStreetId(15);
}
}

static void BM_Agent_SetSpeed(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
for (auto _ : state) {
agent.setSpeed(50.0);
}
}

static void BM_Agent_SetFreeTime(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
std::time_t freeTime = 100;
for (auto _ : state) {
agent.setFreeTime(freeTime++);
}
}

static void BM_Agent_IncrementDistance(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
for (auto _ : state) {
agent.incrementDistance(10.0);
}
}

static void BM_Agent_UpdateItinerary(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
std::vector<dsf::Id> trip = {1, 2, 3, 4, 5};
dsf::mobility::Agent agent(0, trip, 0);
for (auto _ : state) {
agent.updateItinerary();
}
}

static void BM_Agent_Reset(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
agent.setSpeed(50.0);
agent.setStreetId(10);
std::time_t spawnTime = 1000;
for (auto _ : state) {
agent.reset(spawnTime++);
}
}

// Getter benchmarks - these are inline so very fast
static void BM_Agent_Getters(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
agent.setSpeed(50.0);
agent.setStreetId(10);
for (auto _ : state) {
auto spawnTime = agent.spawnTime();
auto freeTime = agent.freeTime();
auto id = agent.id();
auto streetId = agent.streetId();
auto srcNodeId = agent.srcNodeId();
auto nextStreetId = agent.nextStreetId();
auto speed = agent.speed();
auto distance = agent.distance();
auto isRandom = agent.isRandom();
benchmark::DoNotOptimize(spawnTime);
benchmark::DoNotOptimize(freeTime);
benchmark::DoNotOptimize(id);
benchmark::DoNotOptimize(streetId);
benchmark::DoNotOptimize(srcNodeId);
benchmark::DoNotOptimize(nextStreetId);
benchmark::DoNotOptimize(speed);
benchmark::DoNotOptimize(distance);
benchmark::DoNotOptimize(isRandom);
}
}

static void BM_Agent_ItineraryId(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, 1, 0);
for (auto _ : state) {
auto itineraryId = agent.itineraryId();
benchmark::DoNotOptimize(itineraryId);
}
}

static void BM_Agent_Trip(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Agent agent(0, {1, 2, 3}, 0);

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note test

MISRA 12.3 rule
for (auto _ : state) {
auto trip = agent.trip();
benchmark::DoNotOptimize(trip);
}
}

BENCHMARK(BM_Agent_ConstructionWithItineraryId);
BENCHMARK(BM_Agent_ConstructionWithTrip);
BENCHMARK(BM_Agent_ConstructionRandom);
BENCHMARK(BM_Agent_SetSrcNodeId);
BENCHMARK(BM_Agent_SetStreetId);
BENCHMARK(BM_Agent_SetNextStreetId);
BENCHMARK(BM_Agent_SetSpeed);
BENCHMARK(BM_Agent_SetFreeTime);
BENCHMARK(BM_Agent_IncrementDistance);
BENCHMARK(BM_Agent_UpdateItinerary);
BENCHMARK(BM_Agent_Reset);
BENCHMARK(BM_Agent_Getters);
BENCHMARK(BM_Agent_ItineraryId);
BENCHMARK(BM_Agent_Trip);

BENCHMARK_MAIN();
22 changes: 22 additions & 0 deletions benchmark/Bench_Dynamics.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "dsf/mobility/FirstOrderDynamics.hpp"

#include <filesystem>

#include <benchmark/benchmark.h>

static const auto DATA_FOLDER =
std::filesystem::path(__FILE__).parent_path().parent_path() / "test/data";

static void BM_FirstOrderDynamics_Empty_Evolve(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::RoadNetwork network;
network.importEdges((DATA_FOLDER / "forlì_edges.csv").string());
network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string());
dsf::mobility::FirstOrderDynamics dynamics(network);
for (auto _ : state) {
dynamics.evolve();
}
}

BENCHMARK(BM_FirstOrderDynamics_Empty_Evolve);

BENCHMARK_MAIN();
113 changes: 113 additions & 0 deletions benchmark/Bench_Intersection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include "dsf/mobility/Intersection.hpp"
#include "dsf/geometry/Point.hpp"

#include <benchmark/benchmark.h>
#include <memory>

static void BM_Intersection_Construction(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
for (auto _ : state) {
dsf::mobility::Intersection intersection(0);
benchmark::DoNotOptimize(intersection);
}
}

static void BM_Intersection_ConstructionWithPoint(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::geometry::Point point{0.0, 0.0};
for (auto _ : state) {
dsf::mobility::Intersection intersection(0, point);
benchmark::DoNotOptimize(intersection);
}
}

static void BM_Intersection_AddAgentWithAngle(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
std::time_t spawnTime = 0;
for (auto _ : state) {
dsf::mobility::Intersection intersection(0);
intersection.setCapacity(100);
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
intersection.addAgent(0.0, std::move(agent));
}
}

static void BM_Intersection_AddAgentWithoutAngle(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
std::time_t spawnTime = 0;
for (auto _ : state) {
dsf::mobility::Intersection intersection(0);
intersection.setCapacity(100);
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
intersection.addAgent(std::move(agent));
}
}

static void BM_Intersection_nAgents(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Intersection intersection(0);
intersection.setCapacity(1000);
std::time_t spawnTime = 0;
for (int i = 0; i < 100; ++i) {
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
intersection.addAgent(std::move(agent));
}
for (auto _ : state) {
dsf::Size n = intersection.nAgents();
benchmark::DoNotOptimize(n);
}
}

static void BM_Intersection_Density(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Intersection intersection(0);
intersection.setCapacity(1000);
std::time_t spawnTime = 0;
for (int i = 0; i < 100; ++i) {
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
intersection.addAgent(std::move(agent));
}
for (auto _ : state) {
double d = intersection.density();
benchmark::DoNotOptimize(d);
}
}

static void BM_Intersection_IsFull(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Intersection intersection(0);
intersection.setCapacity(1000);
std::time_t spawnTime = 0;
for (int i = 0; i < 100; ++i) {
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
intersection.addAgent(std::move(agent));
}
for (auto _ : state) {
bool full = intersection.isFull();
benchmark::DoNotOptimize(full);
}
}

static void BM_Intersection_SetStreetPriorities(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Intersection intersection(0);
std::set<dsf::Id> priorities = {1, 2, 3};
for (auto _ : state) {
intersection.setStreetPriorities(priorities);
}
}

static void BM_Intersection_AddStreetPriority(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::Intersection intersection(0);
// Need to add ingoing edges first
intersection.addIngoingEdge(1);
intersection.addIngoingEdge(2);
for (auto _ : state) {
intersection.addStreetPriority(1);
intersection.addStreetPriority(2);
}
}

BENCHMARK(BM_Intersection_Construction);
BENCHMARK(BM_Intersection_ConstructionWithPoint);
BENCHMARK(BM_Intersection_AddAgentWithAngle);
BENCHMARK(BM_Intersection_AddAgentWithoutAngle);
BENCHMARK(BM_Intersection_nAgents);
BENCHMARK(BM_Intersection_Density);
BENCHMARK(BM_Intersection_IsFull);
BENCHMARK(BM_Intersection_SetStreetPriorities);
BENCHMARK(BM_Intersection_AddStreetPriority);

BENCHMARK_MAIN();
Loading
Loading