Skip to content

Commit c696c4d

Browse files
committed
Add Phase 0: Microarchitectural Baseline Profiling Infrastructure
This commit implements the complete Phase 0 infrastructure for performance profiling and validation as outlined in the PRTree Comprehensive Improvement Plan. ## What's Added ### Build System (CMakeLists.txt) - Profiling infrastructure with ENABLE_PROFILING option - Mandatory sanitizer support (TSan, ASan, UBSan) - Benchmark build targets ### Benchmarks (benchmarks/) - benchmark_construction: Tree construction performance - benchmark_query: Query operation performance - benchmark_parallel: Thread scaling analysis - stress_test_concurrent: Concurrency stress testing - workloads.h: Standard workload definitions - benchmark_utils.h: Timing and reporting utilities ### Profiling Automation (scripts/) - profile_all_workloads.sh: Automated perf/cachegrind profiling - analyze_baseline.py: Results analysis and report generation ### Documentation (docs/baseline/) - README.md: Phase 0 guide and requirements - BASELINE_SUMMARY.md: Template for results documentation ### CI/CD (.github/workflows/sanitizers.yml) - Mandatory ThreadSanitizer checks (BLOCKING) - AddressSanitizer checks (BLOCKING) - UBSanitizer checks (BLOCKING) - Performance baseline tracking - Long-running stress tests ### Project Documentation - PHASE0_IMPLEMENTATION.md: Complete implementation guide - QUICKSTART_PHASE0.md: Quick start instructions ## Key Features 1. **Empirical Validation**: Hardware counter-based profiling 2. **Thread Safety**: Mandatory TSan validation 3. **Representative Workloads**: 5 workloads covering real usage 4. **Automated Profiling**: Scripts for consistent measurements 5. **Regression Detection**: CI integration for future validation ## Testing All benchmarks build and run successfully: - Construction benchmark: ✓ - Query benchmark: ✓ - Parallel benchmark: ✓ - Stress test: ✓ (all tests pass) ## Next Steps 1. Run: ./scripts/profile_all_workloads.sh 2. Complete: docs/baseline/BASELINE_SUMMARY.md 3. Get tech lead approval 4. Proceed to Phase 1 This is a critical checkpoint - ALL subsequent phases depend on this baseline for performance validation. Related: #48 (test coverage), #47 (query optimizations)
1 parent 08d7f5d commit c696c4d

14 files changed

+3031
-0
lines changed

.github/workflows/sanitizers.yml

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
name: Sanitizer and Performance Checks
2+
3+
# Phase 0: Mandatory sanitizer builds (TSan, ASan, UBSan)
4+
# These checks are REQUIRED and will block merges if they fail
5+
6+
on:
7+
push:
8+
branches:
9+
- main
10+
- 'claude/**' # Claude's working branches
11+
pull_request:
12+
branches:
13+
- main
14+
15+
jobs:
16+
thread_sanitizer:
17+
name: ThreadSanitizer (MANDATORY)
18+
runs-on: ubuntu-latest
19+
timeout-minutes: 30
20+
21+
steps:
22+
- uses: actions/checkout@v4
23+
with:
24+
submodules: recursive
25+
26+
- name: Install dependencies
27+
run: |
28+
sudo apt-get update
29+
sudo apt-get install -y cmake build-essential clang
30+
31+
- name: Build with TSan
32+
run: |
33+
mkdir -p build_tsan
34+
cd build_tsan
35+
cmake -DCMAKE_CXX_COMPILER=clang++ \
36+
-DCMAKE_C_COMPILER=clang \
37+
-DENABLE_TSAN=ON \
38+
-DBUILD_BENCHMARKS=ON \
39+
..
40+
make -j$(nproc)
41+
42+
- name: Run stress tests with TSan
43+
run: |
44+
cd build_tsan
45+
./stress_test_concurrent
46+
env:
47+
TSAN_OPTIONS: "halt_on_error=1 history_size=7"
48+
49+
- name: Check for TSan warnings
50+
if: failure()
51+
run: |
52+
echo "❌ ThreadSanitizer detected data races!"
53+
echo "This is a MANDATORY check - fix all data races before merging."
54+
exit 1
55+
56+
address_sanitizer:
57+
name: AddressSanitizer (MANDATORY)
58+
runs-on: ubuntu-latest
59+
timeout-minutes: 30
60+
61+
steps:
62+
- uses: actions/checkout@v4
63+
with:
64+
submodules: recursive
65+
66+
- name: Install dependencies
67+
run: |
68+
sudo apt-get update
69+
sudo apt-get install -y cmake build-essential clang
70+
71+
- name: Build with ASan
72+
run: |
73+
mkdir -p build_asan
74+
cd build_asan
75+
cmake -DCMAKE_CXX_COMPILER=clang++ \
76+
-DCMAKE_C_COMPILER=clang \
77+
-DENABLE_ASAN=ON \
78+
-DBUILD_BENCHMARKS=ON \
79+
..
80+
make -j$(nproc)
81+
82+
- name: Run benchmarks with ASan
83+
run: |
84+
cd build_asan
85+
./benchmark_construction small_uniform
86+
./benchmark_query small_uniform
87+
env:
88+
ASAN_OPTIONS: "halt_on_error=1 detect_leaks=1"
89+
90+
- name: Run stress tests with ASan
91+
run: |
92+
cd build_asan
93+
timeout 60 ./stress_test_concurrent
94+
env:
95+
ASAN_OPTIONS: "halt_on_error=1 detect_leaks=1"
96+
97+
undefined_behavior_sanitizer:
98+
name: UndefinedBehaviorSanitizer (MANDATORY)
99+
runs-on: ubuntu-latest
100+
timeout-minutes: 30
101+
102+
steps:
103+
- uses: actions/checkout@v4
104+
with:
105+
submodules: recursive
106+
107+
- name: Install dependencies
108+
run: |
109+
sudo apt-get update
110+
sudo apt-get install -y cmake build-essential clang
111+
112+
- name: Build with UBSan
113+
run: |
114+
mkdir -p build_ubsan
115+
cd build_ubsan
116+
cmake -DCMAKE_CXX_COMPILER=clang++ \
117+
-DCMAKE_C_COMPILER=clang \
118+
-DENABLE_UBSAN=ON \
119+
-DBUILD_BENCHMARKS=ON \
120+
..
121+
make -j$(nproc)
122+
123+
- name: Run benchmarks with UBSan
124+
run: |
125+
cd build_ubsan
126+
./benchmark_construction small_uniform
127+
./benchmark_query small_uniform
128+
env:
129+
UBSAN_OPTIONS: "halt_on_error=1 print_stacktrace=1"
130+
131+
benchmark_baseline:
132+
name: Performance Baseline Check
133+
runs-on: ubuntu-latest
134+
timeout-minutes: 45
135+
136+
steps:
137+
- uses: actions/checkout@v4
138+
with:
139+
submodules: recursive
140+
141+
- name: Install dependencies
142+
run: |
143+
sudo apt-get update
144+
sudo apt-get install -y cmake build-essential
145+
146+
- name: Build benchmarks
147+
run: |
148+
mkdir -p build_benchmark
149+
cd build_benchmark
150+
cmake -DCMAKE_BUILD_TYPE=Release \
151+
-DENABLE_PROFILING=ON \
152+
-DBUILD_BENCHMARKS=ON \
153+
..
154+
make -j$(nproc)
155+
156+
- name: Run benchmarks
157+
run: |
158+
cd build_benchmark
159+
./benchmark_construction small_uniform > construction_results.txt
160+
./benchmark_query small_uniform > query_results.txt
161+
162+
- name: Upload benchmark results
163+
uses: actions/upload-artifact@v4
164+
with:
165+
name: benchmark-results-${{ github.sha }}
166+
path: |
167+
build_benchmark/construction_results.txt
168+
build_benchmark/query_results.txt
169+
build_benchmark/*.csv
170+
171+
- name: Check for performance regressions
172+
run: |
173+
# Placeholder for future regression checking
174+
# Will compare against Phase 0 baseline once established
175+
echo "✓ Benchmarks completed successfully"
176+
echo "TODO: Compare against Phase 0 baseline"
177+
178+
concurrent_stress_long:
179+
name: Long-Running Stress Test (10 min)
180+
runs-on: ubuntu-latest
181+
timeout-minutes: 15
182+
# Only run on main branch and manual triggers to save CI time
183+
if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
184+
185+
steps:
186+
- uses: actions/checkout@v4
187+
with:
188+
submodules: recursive
189+
190+
- name: Install dependencies
191+
run: |
192+
sudo apt-get update
193+
sudo apt-get install -y cmake build-essential clang
194+
195+
- name: Build with TSan
196+
run: |
197+
mkdir -p build_tsan_long
198+
cd build_tsan_long
199+
cmake -DCMAKE_CXX_COMPILER=clang++ \
200+
-DCMAKE_C_COMPILER=clang \
201+
-DENABLE_TSAN=ON \
202+
-DBUILD_BENCHMARKS=ON \
203+
..
204+
make -j$(nproc)
205+
206+
- name: Run 10-minute torture test
207+
run: |
208+
cd build_tsan_long
209+
# Run for 10 minutes (600 seconds)
210+
timeout 600 ./stress_test_concurrent || {
211+
if [ $? -eq 124 ]; then
212+
echo "✓ Stress test ran for full 10 minutes"
213+
exit 0
214+
else
215+
echo "❌ Stress test failed before timeout"
216+
exit 1
217+
fi
218+
}
219+
env:
220+
TSAN_OPTIONS: "halt_on_error=1 history_size=7"
221+
222+
build_status_summary:
223+
name: Build Status Summary
224+
runs-on: ubuntu-latest
225+
needs: [thread_sanitizer, address_sanitizer, undefined_behavior_sanitizer, benchmark_baseline]
226+
if: always()
227+
228+
steps:
229+
- name: Check build status
230+
run: |
231+
echo "==================================="
232+
echo " Sanitizer Build Status Summary "
233+
echo "==================================="
234+
echo ""
235+
echo "ThreadSanitizer: ${{ needs.thread_sanitizer.result }}"
236+
echo "AddressSanitizer: ${{ needs.address_sanitizer.result }}"
237+
echo "UBSanitizer: ${{ needs.undefined_behavior_sanitizer.result }}"
238+
echo "Benchmarks: ${{ needs.benchmark_baseline.result }}"
239+
echo ""
240+
241+
# Fail if any mandatory check failed
242+
if [ "${{ needs.thread_sanitizer.result }}" != "success" ] || \
243+
[ "${{ needs.address_sanitizer.result }}" != "success" ] || \
244+
[ "${{ needs.undefined_behavior_sanitizer.result }}" != "success" ]; then
245+
echo "❌ MANDATORY SANITIZER CHECKS FAILED"
246+
echo "All sanitizer checks must pass before merging."
247+
exit 1
248+
fi
249+
250+
echo "✓ All mandatory checks passed"

CMakeLists.txt

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
cmake_minimum_required(VERSION 3.5)
22

3+
# Phase 0: Profiling and Sanitizer Infrastructure
4+
option(ENABLE_PROFILING "Build with profiling symbols and frame pointers" OFF)
5+
option(CI_MODE "CI environment - enables mandatory sanitizers" OFF)
6+
option(ENABLE_ASAN "Build with AddressSanitizer" OFF)
7+
option(ENABLE_TSAN "Build with ThreadSanitizer" OFF)
8+
option(ENABLE_UBSAN "Build with UndefinedBehaviorSanitizer" OFF)
9+
310
if(WIN32)
411
set(CMAKE_CXX_FLAGS "/O2 /EHsc")
512
elseif(APPLE)
@@ -9,6 +16,30 @@ else()
916
set(CMAKE_CXX_FLAGS "-O3 -pthread")
1017
endif()
1118

19+
# Profiling support
20+
if(ENABLE_PROFILING)
21+
message(STATUS "Building with profiling support")
22+
add_compile_options(-g -fno-omit-frame-pointer)
23+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
24+
add_compile_options(-fno-inline-functions)
25+
endif()
26+
endif()
27+
28+
# Sanitizer support (mandatory in CI mode)
29+
if(CI_MODE OR ENABLE_TSAN)
30+
message(STATUS "ThreadSanitizer enabled")
31+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -g")
32+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
33+
elseif(ENABLE_ASAN)
34+
message(STATUS "AddressSanitizer enabled")
35+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g")
36+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
37+
elseif(ENABLE_UBSAN)
38+
message(STATUS "UndefinedBehaviorSanitizer enabled")
39+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -g")
40+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
41+
endif()
42+
1243
project(PRTree)
1344
file(GLOB MYCPP ${CMAKE_CURRENT_SOURCE_DIR}/cpp/*)
1445

@@ -20,6 +51,7 @@ option(SKIP_PERFORMANCE_COMPARISON "" ON)
2051
option(BUILD_TESTS "" OFF)
2152
option(BUILD_SANDBOX "" OFF)
2253
option(BUILD_DOC "" OFF)
54+
option(BUILD_BENCHMARKS "Build performance benchmarks" OFF)
2355

2456
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third/pybind11/)
2557
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third/cereal/)
@@ -55,3 +87,48 @@ set_target_properties(PRTree PROPERTIES
5587
ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG}"
5688
ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE}"
5789
)
90+
91+
# Phase 0: Benchmark targets
92+
if(BUILD_BENCHMARKS)
93+
message(STATUS "Building performance benchmarks")
94+
95+
# Construction benchmark
96+
add_executable(benchmark_construction benchmarks/benchmark_construction.cpp)
97+
target_include_directories(benchmark_construction PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cpp)
98+
target_link_libraries(benchmark_construction PRIVATE cereal snappy)
99+
set_target_properties(benchmark_construction PROPERTIES
100+
CXX_STANDARD 17
101+
CXX_STANDARD_REQUIRED TRUE
102+
CXX_EXTENSIONS FALSE
103+
)
104+
105+
# Query benchmark
106+
add_executable(benchmark_query benchmarks/benchmark_query.cpp)
107+
target_include_directories(benchmark_query PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cpp)
108+
target_link_libraries(benchmark_query PRIVATE cereal snappy)
109+
set_target_properties(benchmark_query PROPERTIES
110+
CXX_STANDARD 17
111+
CXX_STANDARD_REQUIRED TRUE
112+
CXX_EXTENSIONS FALSE
113+
)
114+
115+
# Multithreaded benchmark
116+
add_executable(benchmark_parallel benchmarks/benchmark_parallel.cpp)
117+
target_include_directories(benchmark_parallel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cpp)
118+
target_link_libraries(benchmark_parallel PRIVATE cereal snappy)
119+
set_target_properties(benchmark_parallel PROPERTIES
120+
CXX_STANDARD 17
121+
CXX_STANDARD_REQUIRED TRUE
122+
CXX_EXTENSIONS FALSE
123+
)
124+
125+
# Stress test
126+
add_executable(stress_test_concurrent benchmarks/stress_test_concurrent.cpp)
127+
target_include_directories(stress_test_concurrent PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cpp)
128+
target_link_libraries(stress_test_concurrent PRIVATE cereal snappy pthread)
129+
set_target_properties(stress_test_concurrent PROPERTIES
130+
CXX_STANDARD 17
131+
CXX_STANDARD_REQUIRED TRUE
132+
CXX_EXTENSIONS FALSE
133+
)
134+
endif()

0 commit comments

Comments
 (0)