This guide explains how to profile the UTF Strings benchmarks and analyze performance using perf and flame graphs.
./run_bench.sh./profile_bench.shThe profile_bench.sh script automatically:
- Builds the release version
- Installs perf if needed (handles kernel version mismatches)
- Records performance data with detailed call graphs
- Generates initial reports
./profile_bench.shOutput files created:
perf.data- Raw performance data (binary format)perf.script- Flame graph ready data (text format)
After running the profiling script, you can view detailed reports:
# Interactive report browser (recommended)
/usr/lib/linux-tools/6.8.0-87-generic/perf report
# Text-based report
/usr/lib/linux-tools/6.8.0-87-generic/perf report --stdio
# Focus on specific functions
/usr/lib/linux-tools/6.8.0-87-generic/perf report --stdio --symbol=BM_Length_Mixed
# Show assembly code with performance annotations
/usr/lib/linux-tools/6.8.0-87-generic/perf annotate BM_Length_MixedFlame graphs provide excellent visual representation of where CPU time is spent.
git clone https://github.com/brendangregg/FlameGraph.git# Generate flame graph from the perf.script file
cat perf.script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg
# Open in web browser
firefox flamegraph.svg
# or
google-chrome flamegraph.svg
# or
xdg-open flamegraph.svg# CPU flame graph (default)
cat perf.script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > cpu-flamegraph.svg
# Reverse flame graph (callees first)
cat perf.script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl --reverse > reverse-flamegraph.svg
# Differential flame graph (compare two profiles)
# First run: ./profile_bench.sh && mv perf.script perf1.script
# After changes: ./profile_bench.sh && mv perf.script perf2.script
FlameGraph/difffolded.pl perf1.script perf2.script | FlameGraph/flamegraph.pl > diff-flamegraph.svg# Profile specific hardware events
/usr/lib/linux-tools/6.8.0-87-generic/perf stat -e cycles,instructions,cache-misses,branch-misses ./build/Release/utf_strings-bench
# Detailed cache analysis
/usr/lib/linux-tools/6.8.0-87-generic/perf stat -e L1-dcache-loads,L1-dcache-load-misses,LLC-loads,LLC-load-misses ./build/Release/utf_strings-bench
# Branch prediction analysis
/usr/lib/linux-tools/6.8.0-87-generic/perf stat -e branches,branch-misses,branch-loads,branch-load-misses ./build/Release/utf_strings-bench# Record memory access patterns
/usr/lib/linux-tools/6.8.0-87-generic/perf record -e cache-misses -g ./build/Release/utf_strings-bench
# Memory bandwidth analysis
/usr/lib/linux-tools/6.8.0-87-generic/perf stat -e cpu/mem-loads/,cpu/mem-stores/ ./build/Release/utf_strings-bench# Profile only specific functions
/usr/lib/linux-tools/6.8.0-87-generic/perf record -e cycles -g --call-graph dwarf ./build/Release/utf_strings-bench
# View function-level hotspots
/usr/lib/linux-tools/6.8.0-87-generic/perf report --sort=symbol
# Top functions by CPU usage
/usr/lib/linux-tools/6.8.0-87-generic/perf report --stdio --sort=overhead- task-clock: CPU time used by the benchmark
- cycles: Number of CPU cycles consumed
- instructions: Number of instructions executed
- IPC (Instructions Per Cycle): Higher is better (>1.0 is good)
- branch-misses: Branch mispredictions (lower % is better)
- cache-misses: Memory cache misses (lower is better)
- Width: Proportional to time spent in function
- Height: Call stack depth
- Color: Random (not meaningful for CPU graphs)
- Hotspots: Wide bars indicate performance bottlenecks
If you see warnings about kernel version mismatch, the script automatically handles this by finding the correct perf binary. No action needed.
If you encounter permission errors:
# Temporarily allow perf without sudo (session only)
echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid
# Or add your user to the perf_users group (if exists)
sudo usermod -a -G perf_users $USERThe script automatically installs required dependencies, but if you encounter issues:
# Manual installation
sudo apt update
sudo apt install linux-tools-generic
# For specific kernel
sudo apt install linux-tools-$(uname -r)# Configure for debug
cmake -S . -B build/Debug -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -DUTF_STRINGS_WITH_GPERFTOOLS=ON
# Build debug version
cmake --build build/Debug
# Profile debug build
/usr/lib/linux-tools/6.8.0-87-generic/perf record -g ./build/Debug/utf_strings-bench# Configure with specific optimization
cmake -S . -B build/Custom -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -march=native" -DUTF_STRINGS_WITH_GPERFTOOLS=ONAfter profiling, you'll have these files:
perf.data- Raw perf data (binary)perf.script- Text format for flame graphsflamegraph.svg- Visual flame graph (after generation)FlameGraph/- Flame graph tools directory
- Disable CPU scaling:
sudo cpupower frequency-set --governor performance - Close other applications: Reduce system noise
- Run multiple times: Results can vary between runs
- Profile different scenarios: Various input sizes and patterns
- Compare before/after: Use differential flame graphs for optimizations
# 1. Run profiling
./profile_bench.sh
# 2. Generate flame graph
git clone https://github.com/brendangregg/FlameGraph.git
cat perf.script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg
# 3. View results
firefox flamegraph.svg
/usr/lib/linux-tools/6.8.0-87-generic/perf report
# 4. Make code changes...
# 5. Profile again and compare
./profile_bench.sh
cat perf.script | FlameGraph/stackcollapse-perf.pl > after.folded
# Compare with previous: FlameGraph/difffolded.pl before.folded after.folded | FlameGraph/flamegraph.pl > diff.svg# Run all tests with various sanitizer configurations
./test_all_sanitizers.shThis script runs:
- Debug build with AddressSanitizer + UndefinedBehaviorSanitizer
- Debug build with ThreadSanitizer (if Clang available)
- Release build (clean, no sanitizers)
- Extended fuzz testing (if Clang available)
cmake -S . -B build/Debug_Sanitized \
-DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DUTF_STRINGS_ENABLE_SANITIZERS=ON
cmake --build build/Debug_Sanitized
build/Debug_Sanitized/utf_strings-testscmake -S . -B build/Debug_TSan \
-DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_COMPILER=clang++ \
-DUTF_STRINGS_ENABLE_THREAD_SANITIZER=ON
cmake --build build/Debug_TSan
build/Debug_TSan/utf_strings-tests# Run all fuzz tests for 60 seconds each
./run_fuzz_tests.sh
# Run specific encoding for 30 seconds
./run_fuzz_tests.sh --encoding utf8 --time 30
# Available encodings: utf8, utf16_be, utf16_le, utf32_be, utf32_le, all# Build fuzz targets
cmake -S . -B build/Fuzz \
-DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_COMPILER=clang++ \
-DUTF_STRINGS_BUILD_FUZZ_TESTS=ON
cmake --build build/Fuzz
# Run individual fuzz tests
build/Fuzz/fuzz_utf8 -max_total_time=300 -print_final_stats=1
build/Fuzz/fuzz_utf16_be -max_total_time=300 -print_final_stats=1
build/Fuzz/fuzz_utf16_le -max_total_time=300 -print_final_stats=1
build/Fuzz/fuzz_utf32_be -max_total_time=300 -print_final_stats=1
build/Fuzz/fuzz_utf32_le -max_total_time=300 -print_final_stats=1The fuzz tests include:
- UTF-8: Invalid sequences, overlong encodings, truncated multi-byte sequences
- UTF-16 BE/LE: Invalid surrogate pairs, truncated surrogates, endianness handling
- UTF-32 BE/LE: Invalid code points, surrogate range values, endianness handling
- All encodings: Boundary conditions, consistency checks, round-trip validation
Built-in sanitizers detect:
- Buffer overflows and underflows
- Use-after-free and double-free
- Memory leaks
- Undefined behavior
- Integer overflows
- Null pointer dereferences