Skip to content

Commit 77b0681

Browse files
authored
Refactor benchmarks (#363)
1 parent 1bd2a0f commit 77b0681

21 files changed

+938
-367
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: "CI: Benchmark Release"
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
jobs:
10+
benchmark_release:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Install dependencies
18+
run: |
19+
sudo apt update
20+
sudo apt install -y build-essential cmake libhwloc-dev
21+
22+
- name: Build in Release mode with benchmarks
23+
working-directory: ${{ github.workspace }}
24+
run: |
25+
mkdir -p build
26+
cd build
27+
cmake .. -DCMAKE_BUILD_TYPE=Release -DDSF_BENCHMARKS=ON -DCMAKE_INSTALL_PREFIX=${GITHUB_WORKSPACE}/install
28+
cmake --build . -j$(nproc) --config Release
29+
30+
- name: Run benchmarks
31+
working-directory: ${{ github.workspace }}/benchmark
32+
run: |
33+
for bench in *.out; do
34+
echo "Running $bench"
35+
./$bench
36+
done

.github/workflows/cmake_tests.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
if: matrix.os == 'ubuntu-latest'
2323
run: |
2424
sudo apt update
25-
sudo apt install -y lcov gcovr build-essential cmake libtbb-dev libsimdjson-dev libhwloc-dev
25+
sudo apt install -y lcov gcovr build-essential cmake libhwloc-dev
2626
2727
- name: Install dependencies on macOS
2828
if: matrix.os == 'macos-latest'
@@ -37,7 +37,6 @@ jobs:
3737
git clone https://github.com/microsoft/vcpkg.git vcpkg
3838
cd vcpkg
3939
.\bootstrap-vcpkg.bat
40-
.\vcpkg install tbb:x64-windows simdjson:x64-windows
4140
echo "VCPKG_ROOT=$env:GITHUB_WORKSPACE\vcpkg" >> $env:GITHUB_ENV
4241
echo "VCPKG_INSTALLED=$env:GITHUB_WORKSPACE\vcpkg\installed\x64-windows" >> $env:GITHUB_ENV
4342

.gitmodules

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
[submodule "extern/benchmark"]
2-
path = extern/benchmark
3-
url = https://github.com/sbaldu/benchmark.git
4-
51
[submodule "extern/doxygen-awesome"]
62
path = extern/doxygen-awesome
73
url = https://github.com/jothepro/doxygen-awesome-css.git

CMakeLists.txt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,17 @@ project(
1919

2020
option(DSF_TESTS "Build DSF tests" OFF)
2121
option(DSF_EXAMPLES "Build DSF examples" OFF)
22+
option(DSF_BENCHMARKS "Build DSF benchmarks" OFF)
2223
option(DSF_BUILD_PIC "Build DSF with position-independent code" OFF)
2324
option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF)
2425

2526
# If CMAKE_BUILD_TYPE not set, default to Debug
2627
if(NOT CMAKE_BUILD_TYPE)
27-
if(BUILD_PYTHON_BINDINGS)
28+
if(BUILD_PYTHON_BINDINGS OR DSF_BENCHMARKS)
2829
set(CMAKE_BUILD_TYPE
2930
"Release"
3031
CACHE STRING
31-
"Build type (default: Release when building Python bindings)"
32+
"Build type (default: Release when building Python bindings or benchmarks)"
3233
FORCE)
3334
else()
3435
set(CMAKE_BUILD_TYPE
@@ -52,6 +53,10 @@ if(CMAKE_BUILD_TYPE MATCHES "Release")
5253
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
5354
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2")
5455
endif()
56+
elseif(CMAKE_BUILD_TYPE MATCHES "Profile")
57+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
58+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Ofast -march=native -flto=auto -pg")
59+
endif()
5560
elseif(CMAKE_BUILD_TYPE MATCHES "Coverage")
5661
set(DSF_TESTS ON)
5762
message(STATUS "Enable code coverage")
@@ -272,3 +277,10 @@ if(DSF_EXAMPLES)
272277
set(CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX};${CMAKE_PREFIX_PATH}")
273278
add_subdirectory(examples)
274279
endif()
280+
281+
# Benchmarks
282+
message(STATUS "Build DSF benchmarks: ${DSF_BENCHMARKS}")
283+
if(DSF_BENCHMARKS)
284+
set(CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX};${CMAKE_PREFIX_PATH}")
285+
add_subdirectory(benchmark)
286+
endif()

benchmark/Bench_Agent.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#include "dsf/mobility/Agent.hpp"
2+
3+
#include <benchmark/benchmark.h>
4+
#include <memory>
5+
6+
static void BM_Agent_ConstructionWithItineraryId(benchmark::State& state) {
7+
std::time_t spawnTime = 0;
8+
for (auto _ : state) {
9+
dsf::mobility::Agent agent(spawnTime++, 1, 0);
10+
benchmark::DoNotOptimize(agent);
11+
}
12+
}
13+
14+
static void BM_Agent_ConstructionWithTrip(benchmark::State& state) {
15+
std::time_t spawnTime = 0;
16+
std::vector<dsf::Id> trip = {1, 2, 3};
17+
for (auto _ : state) {
18+
dsf::mobility::Agent agent(spawnTime++, trip, 0);
19+
benchmark::DoNotOptimize(agent);
20+
}
21+
}
22+
23+
static void BM_Agent_ConstructionRandom(benchmark::State& state) {
24+
std::time_t spawnTime = 0;
25+
for (auto _ : state) {
26+
dsf::mobility::Agent agent(spawnTime++);
27+
benchmark::DoNotOptimize(agent);
28+
}
29+
}
30+
31+
static void BM_Agent_SetSrcNodeId(benchmark::State& state) {
32+
dsf::mobility::Agent agent(0, 1, 0);
33+
for (auto _ : state) {
34+
agent.setSrcNodeId(5);
35+
}
36+
}
37+
38+
static void BM_Agent_SetStreetId(benchmark::State& state) {
39+
dsf::mobility::Agent agent(0, 1, 0);
40+
for (auto _ : state) {
41+
agent.setStreetId(10);
42+
}
43+
}
44+
45+
static void BM_Agent_SetNextStreetId(benchmark::State& state) {
46+
dsf::mobility::Agent agent(0, 1, 0);
47+
for (auto _ : state) {
48+
agent.setNextStreetId(15);
49+
}
50+
}
51+
52+
static void BM_Agent_SetSpeed(benchmark::State& state) {
53+
dsf::mobility::Agent agent(0, 1, 0);
54+
for (auto _ : state) {
55+
agent.setSpeed(50.0);
56+
}
57+
}
58+
59+
static void BM_Agent_SetFreeTime(benchmark::State& state) {
60+
dsf::mobility::Agent agent(0, 1, 0);
61+
std::time_t freeTime = 100;
62+
for (auto _ : state) {
63+
agent.setFreeTime(freeTime++);
64+
}
65+
}
66+
67+
static void BM_Agent_IncrementDistance(benchmark::State& state) {
68+
dsf::mobility::Agent agent(0, 1, 0);
69+
for (auto _ : state) {
70+
agent.incrementDistance(10.0);
71+
}
72+
}
73+
74+
static void BM_Agent_UpdateItinerary(benchmark::State& state) {
75+
std::vector<dsf::Id> trip = {1, 2, 3, 4, 5};
76+
dsf::mobility::Agent agent(0, trip, 0);
77+
for (auto _ : state) {
78+
agent.updateItinerary();
79+
}
80+
}
81+
82+
static void BM_Agent_Reset(benchmark::State& state) {
83+
dsf::mobility::Agent agent(0, 1, 0);
84+
agent.setSpeed(50.0);
85+
agent.setStreetId(10);
86+
std::time_t spawnTime = 1000;
87+
for (auto _ : state) {
88+
agent.reset(spawnTime++);
89+
}
90+
}
91+
92+
// Getter benchmarks - these are inline so very fast
93+
static void BM_Agent_Getters(benchmark::State& state) {
94+
dsf::mobility::Agent agent(0, 1, 0);
95+
agent.setSpeed(50.0);
96+
agent.setStreetId(10);
97+
for (auto _ : state) {
98+
auto spawnTime = agent.spawnTime();
99+
auto freeTime = agent.freeTime();
100+
auto id = agent.id();
101+
auto streetId = agent.streetId();
102+
auto srcNodeId = agent.srcNodeId();
103+
auto nextStreetId = agent.nextStreetId();
104+
auto speed = agent.speed();
105+
auto distance = agent.distance();
106+
auto isRandom = agent.isRandom();
107+
benchmark::DoNotOptimize(spawnTime);
108+
benchmark::DoNotOptimize(freeTime);
109+
benchmark::DoNotOptimize(id);
110+
benchmark::DoNotOptimize(streetId);
111+
benchmark::DoNotOptimize(srcNodeId);
112+
benchmark::DoNotOptimize(nextStreetId);
113+
benchmark::DoNotOptimize(speed);
114+
benchmark::DoNotOptimize(distance);
115+
benchmark::DoNotOptimize(isRandom);
116+
}
117+
}
118+
119+
static void BM_Agent_ItineraryId(benchmark::State& state) {
120+
dsf::mobility::Agent agent(0, 1, 0);
121+
for (auto _ : state) {
122+
auto itineraryId = agent.itineraryId();
123+
benchmark::DoNotOptimize(itineraryId);
124+
}
125+
}
126+
127+
static void BM_Agent_Trip(benchmark::State& state) {
128+
dsf::mobility::Agent agent(0, {1, 2, 3}, 0);
129+
for (auto _ : state) {
130+
auto trip = agent.trip();
131+
benchmark::DoNotOptimize(trip);
132+
}
133+
}
134+
135+
BENCHMARK(BM_Agent_ConstructionWithItineraryId);
136+
BENCHMARK(BM_Agent_ConstructionWithTrip);
137+
BENCHMARK(BM_Agent_ConstructionRandom);
138+
BENCHMARK(BM_Agent_SetSrcNodeId);
139+
BENCHMARK(BM_Agent_SetStreetId);
140+
BENCHMARK(BM_Agent_SetNextStreetId);
141+
BENCHMARK(BM_Agent_SetSpeed);
142+
BENCHMARK(BM_Agent_SetFreeTime);
143+
BENCHMARK(BM_Agent_IncrementDistance);
144+
BENCHMARK(BM_Agent_UpdateItinerary);
145+
BENCHMARK(BM_Agent_Reset);
146+
BENCHMARK(BM_Agent_Getters);
147+
BENCHMARK(BM_Agent_ItineraryId);
148+
BENCHMARK(BM_Agent_Trip);
149+
150+
BENCHMARK_MAIN();

benchmark/Bench_Dynamics.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include "dsf/mobility/FirstOrderDynamics.hpp"
2+
3+
#include <filesystem>
4+
5+
#include <benchmark/benchmark.h>
6+
7+
static const auto DATA_FOLDER =
8+
std::filesystem::path(__FILE__).parent_path().parent_path() / "test/data";
9+
10+
static void BM_FirstOrderDynamics_Empty_Evolve(benchmark::State& state) {
11+
dsf::mobility::RoadNetwork network;
12+
network.importEdges((DATA_FOLDER / "forlì_edges.csv").string());
13+
network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string());
14+
dsf::mobility::FirstOrderDynamics dynamics(network);
15+
for (auto _ : state) {
16+
dynamics.evolve();
17+
}
18+
}
19+
20+
BENCHMARK(BM_FirstOrderDynamics_Empty_Evolve);
21+
22+
BENCHMARK_MAIN();

benchmark/Bench_Intersection.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#include "dsf/mobility/Intersection.hpp"
2+
#include "dsf/geometry/Point.hpp"
3+
4+
#include <benchmark/benchmark.h>
5+
#include <memory>
6+
7+
static void BM_Intersection_Construction(benchmark::State& state) {
8+
for (auto _ : state) {
9+
dsf::mobility::Intersection intersection(0);
10+
benchmark::DoNotOptimize(intersection);
11+
}
12+
}
13+
14+
static void BM_Intersection_ConstructionWithPoint(benchmark::State& state) {
15+
dsf::geometry::Point point{0.0, 0.0};
16+
for (auto _ : state) {
17+
dsf::mobility::Intersection intersection(0, point);
18+
benchmark::DoNotOptimize(intersection);
19+
}
20+
}
21+
22+
static void BM_Intersection_AddAgentWithAngle(benchmark::State& state) {
23+
std::time_t spawnTime = 0;
24+
for (auto _ : state) {
25+
dsf::mobility::Intersection intersection(0);
26+
intersection.setCapacity(100);
27+
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
28+
intersection.addAgent(0.0, std::move(agent));
29+
}
30+
}
31+
32+
static void BM_Intersection_AddAgentWithoutAngle(benchmark::State& state) {
33+
std::time_t spawnTime = 0;
34+
for (auto _ : state) {
35+
dsf::mobility::Intersection intersection(0);
36+
intersection.setCapacity(100);
37+
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
38+
intersection.addAgent(std::move(agent));
39+
}
40+
}
41+
42+
static void BM_Intersection_nAgents(benchmark::State& state) {
43+
dsf::mobility::Intersection intersection(0);
44+
intersection.setCapacity(1000);
45+
std::time_t spawnTime = 0;
46+
for (int i = 0; i < 100; ++i) {
47+
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
48+
intersection.addAgent(std::move(agent));
49+
}
50+
for (auto _ : state) {
51+
dsf::Size n = intersection.nAgents();
52+
benchmark::DoNotOptimize(n);
53+
}
54+
}
55+
56+
static void BM_Intersection_Density(benchmark::State& state) {
57+
dsf::mobility::Intersection intersection(0);
58+
intersection.setCapacity(1000);
59+
std::time_t spawnTime = 0;
60+
for (int i = 0; i < 100; ++i) {
61+
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
62+
intersection.addAgent(std::move(agent));
63+
}
64+
for (auto _ : state) {
65+
double d = intersection.density();
66+
benchmark::DoNotOptimize(d);
67+
}
68+
}
69+
70+
static void BM_Intersection_IsFull(benchmark::State& state) {
71+
dsf::mobility::Intersection intersection(0);
72+
intersection.setCapacity(1000);
73+
std::time_t spawnTime = 0;
74+
for (int i = 0; i < 100; ++i) {
75+
auto agent = std::make_unique<dsf::mobility::Agent>(spawnTime++, 1, 0);
76+
intersection.addAgent(std::move(agent));
77+
}
78+
for (auto _ : state) {
79+
bool full = intersection.isFull();
80+
benchmark::DoNotOptimize(full);
81+
}
82+
}
83+
84+
static void BM_Intersection_SetStreetPriorities(benchmark::State& state) {
85+
dsf::mobility::Intersection intersection(0);
86+
std::set<dsf::Id> priorities = {1, 2, 3};
87+
for (auto _ : state) {
88+
intersection.setStreetPriorities(priorities);
89+
}
90+
}
91+
92+
static void BM_Intersection_AddStreetPriority(benchmark::State& state) {
93+
dsf::mobility::Intersection intersection(0);
94+
// Need to add ingoing edges first
95+
intersection.addIngoingEdge(1);
96+
intersection.addIngoingEdge(2);
97+
for (auto _ : state) {
98+
intersection.addStreetPriority(1);
99+
intersection.addStreetPriority(2);
100+
}
101+
}
102+
103+
BENCHMARK(BM_Intersection_Construction);
104+
BENCHMARK(BM_Intersection_ConstructionWithPoint);
105+
BENCHMARK(BM_Intersection_AddAgentWithAngle);
106+
BENCHMARK(BM_Intersection_AddAgentWithoutAngle);
107+
BENCHMARK(BM_Intersection_nAgents);
108+
BENCHMARK(BM_Intersection_Density);
109+
BENCHMARK(BM_Intersection_IsFull);
110+
BENCHMARK(BM_Intersection_SetStreetPriorities);
111+
BENCHMARK(BM_Intersection_AddStreetPriority);
112+
113+
BENCHMARK_MAIN();

0 commit comments

Comments
 (0)