#!/bin/bash # # Flame Graph Generation Script for Performance Profiling # # This script generates flame graphs for the Foxhunt HFT system to visualize # where CPU time is spent during benchmark execution. Useful for identifying # performance bottlenecks and optimization opportunities. # # Usage: # ./scripts/generate_flame_graphs.sh [benchmark-name] [duration-seconds] # # Examples: # ./scripts/generate_flame_graphs.sh # All benchmarks, 30s each # ./scripts/generate_flame_graphs.sh ml_prediction 60 # Specific benchmark, 60s # # Requirements: # - cargo-flamegraph (install with: cargo install flamegraph) # - perf (Linux kernel profiler) # - Linux system (perf required) set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration BENCHMARK_NAME="${1:-all}" PROFILE_DURATION="${2:-30}" OUTPUT_DIR="flame_graphs" TIMESTAMP=$(date +%Y%m%d_%H%M%S) echo -e "${BLUE}=================================================${NC}" echo -e "${BLUE}Flame Graph Generation for Performance Profiling${NC}" echo -e "${BLUE}=================================================${NC}" echo "" echo -e "${GREEN}Benchmark:${NC} $BENCHMARK_NAME" echo -e "${GREEN}Duration:${NC} ${PROFILE_DURATION}s" echo -e "${GREEN}Output:${NC} $OUTPUT_DIR" echo "" # Check if running on Linux if [[ "$OSTYPE" != "linux-gnu"* ]]; then echo -e "${RED}Error: Flame graphs require Linux (perf tool)${NC}" echo -e "${YELLOW}Alternatives:${NC}" echo " - Run in Docker: docker run -v \$(pwd):/workspace rust:latest bash" echo " - Use Instruments on macOS" echo " - Use other profiling tools (valgrind, etc.)" exit 1 fi # Check if cargo-flamegraph is installed if ! command -v cargo-flamegraph &> /dev/null; then echo -e "${YELLOW}Installing cargo-flamegraph...${NC}" if ! cargo install flamegraph; then echo -e "${RED}Failed to install cargo-flamegraph${NC}" exit 1 fi echo -e "${GREEN}✓ cargo-flamegraph installed${NC}" fi # Check if perf is available if ! command -v perf &> /dev/null; then echo -e "${YELLOW}perf not found. Attempting to install...${NC}" if sudo apt-get install -y linux-tools-common linux-tools-generic linux-tools-$(uname -r) 2>/dev/null; then echo -e "${GREEN}✓ perf installed${NC}" else echo -e "${RED}Failed to install perf. Please install manually:${NC}" echo " sudo apt-get install linux-tools-\$(uname -r)" exit 1 fi fi # Set perf permissions (may require sudo) echo -e "${YELLOW}Configuring perf permissions...${NC}" if [ -f /proc/sys/kernel/perf_event_paranoid ]; then CURRENT_PARANOID=$(cat /proc/sys/kernel/perf_event_paranoid) if [ "$CURRENT_PARANOID" -gt 1 ]; then echo -e "${YELLOW}Note: perf_event_paranoid is $CURRENT_PARANOID (restrictive)${NC}" echo -e "${YELLOW}For better profiling, set to -1 (requires sudo):${NC}" echo " sudo sysctl kernel.perf_event_paranoid=-1" echo "" read -p "Attempt to set now? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then sudo sysctl kernel.perf_event_paranoid=-1 fi fi fi # Create output directory mkdir -p "$OUTPUT_DIR" # Function to generate flame graph for specific benchmark generate_flamegraph() { local bench_name="$1" local output_file="$OUTPUT_DIR/flamegraph_${bench_name}_${TIMESTAMP}.svg" echo "" echo -e "${YELLOW}Generating flame graph: $bench_name${NC}" echo -e "${BLUE}Duration: ${PROFILE_DURATION}s${NC}" echo "" # Run cargo-flamegraph on the benchmark if cargo flamegraph \ --bench performance_regression \ --output "$output_file" \ -- --bench "$bench_name" --profile-time "$PROFILE_DURATION"; then echo -e "${GREEN}✓ Flame graph generated: $output_file${NC}" # Get file size local file_size=$(du -h "$output_file" | cut -f1) echo -e "${BLUE} Size: $file_size${NC}" return 0 else echo -e "${RED}✗ Failed to generate flame graph for $bench_name${NC}" return 1 fi } # Main execution main() { if [ "$BENCHMARK_NAME" = "all" ]; then echo -e "${YELLOW}Generating flame graphs for all benchmarks...${NC}" echo -e "${BLUE}This will take approximately $((PROFILE_DURATION * 8)) seconds${NC}" echo "" # List of all benchmarks in performance_regression.rs BENCHMARKS=( "ml_prediction_latency" "hot_swap_latency" "database_writes" "backtest_performance" "order_processing" "risk_validation" "memory_allocation" "concurrent_access" ) local success_count=0 local total_count=${#BENCHMARKS[@]} for bench in "${BENCHMARKS[@]}"; do if generate_flamegraph "$bench"; then ((success_count++)) fi done echo "" echo -e "${GREEN}=================================================${NC}" echo -e "${GREEN}Flame Graph Generation Complete${NC}" echo -e "${GREEN}=================================================${NC}" echo -e "${GREEN}Success: $success_count / $total_count${NC}" echo "" else generate_flamegraph "$BENCHMARK_NAME" fi # Generate summary HTML echo "" echo -e "${YELLOW}Generating summary page...${NC}" cat > "$OUTPUT_DIR/index.html" <<'EOFHTML' Foxhunt Performance Flame Graphs

Foxhunt HFT Performance Flame Graphs

Generated: TIMESTAMP_PLACEHOLDER
Profile Duration: DURATION_PLACEHOLDER seconds per benchmark

How to Read Flame Graphs

Tip: Click on any frame to zoom in. Look for wide frames at the top for optimization opportunities.

EOFHTML # Add each flame graph to the HTML for svg_file in "$OUTPUT_DIR"/flamegraph_*.svg; do if [ -f "$svg_file" ]; then local bench_name=$(basename "$svg_file" | sed 's/flamegraph_//;s/_[0-9]*\.svg$//') local svg_filename=$(basename "$svg_file") cat >> "$OUTPUT_DIR/index.html" <

$bench_name

EOFBENCH fi done cat >> "$OUTPUT_DIR/index.html" <<'EOFFOOTER' EOFFOOTER # Replace placeholders sed -i "s/TIMESTAMP_PLACEHOLDER/$(date)/" "$OUTPUT_DIR/index.html" sed -i "s/DURATION_PLACEHOLDER/$PROFILE_DURATION/" "$OUTPUT_DIR/index.html" echo -e "${GREEN}✓ Summary page generated: $OUTPUT_DIR/index.html${NC}" # Show results echo "" echo -e "${GREEN}=================================================${NC}" echo -e "${GREEN}Flame Graphs Generated Successfully${NC}" echo -e "${GREEN}=================================================${NC}" echo "" echo -e "${BLUE}View results:${NC}" echo -e " ${YELLOW}open $OUTPUT_DIR/index.html${NC}" echo "" echo -e "${BLUE}Individual flame graphs:${NC}" for svg_file in "$OUTPUT_DIR"/flamegraph_*.svg; do if [ -f "$svg_file" ]; then echo -e " - $(basename "$svg_file")" fi done echo "" echo -e "${BLUE}Analysis tips:${NC}" echo " 1. Look for wide horizontal bars (high CPU time)" echo " 2. Deep stacks indicate complex call chains" echo " 3. Optimize functions with widest frames" echo " 4. Compare flame graphs before/after optimization" echo "" } # Run main function main "$@"