#!/usr/bin/env bash # Synor Profiling Script # Generates flamegraphs and performance profiles for critical paths set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" PROFILE_DIR="$PROJECT_ROOT/target/profiles" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color info() { echo -e "${BLUE}[INFO]${NC} $1"; } success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } # Check dependencies check_deps() { info "Checking profiling dependencies..." # Check for cargo-flamegraph if ! command -v cargo-flamegraph &> /dev/null; then warn "cargo-flamegraph not found. Installing..." cargo install flamegraph fi # Check for samply (alternative profiler) if ! command -v samply &> /dev/null; then warn "samply not found. Install with: cargo install samply" fi # macOS: check for dtrace access if [[ "$OSTYPE" == "darwin"* ]]; then if ! csrutil status 2>/dev/null | grep -q "disabled"; then warn "On macOS, you may need to disable SIP for dtrace-based profiling" warn "Alternative: use 'samply' which uses the Instruments profiler" fi fi success "Dependencies checked" } # Build with profiling symbols build_profile() { info "Building with profiling profile..." cd "$PROJECT_ROOT" cargo build --profile profiling --workspace success "Build complete" } # Profile kHeavyHash mining profile_mining() { info "Profiling kHeavyHash mining..." mkdir -p "$PROFILE_DIR/mining" cd "$PROJECT_ROOT" # Run mining benchmark with flamegraph if command -v cargo-flamegraph &> /dev/null; then CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \ --bench mining_bench \ -p synor-mining \ --output "$PROFILE_DIR/mining/flamegraph.svg" \ -- --bench "kheavyhash" success "Mining flamegraph saved to $PROFILE_DIR/mining/flamegraph.svg" else # Fallback to regular benchmark with timing cargo bench -p synor-mining --bench mining_bench -- --verbose fi } # Profile GHOSTDAG consensus profile_ghostdag() { info "Profiling GHOSTDAG consensus..." mkdir -p "$PROFILE_DIR/ghostdag" cd "$PROJECT_ROOT" if command -v cargo-flamegraph &> /dev/null; then CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \ --bench ghostdag_bench \ -p synor-dag \ --output "$PROFILE_DIR/ghostdag/flamegraph.svg" \ -- --bench success "GHOSTDAG flamegraph saved to $PROFILE_DIR/ghostdag/flamegraph.svg" else cargo bench -p synor-dag --bench ghostdag_bench -- --verbose fi } # Profile storage operations profile_storage() { info "Profiling storage operations..." mkdir -p "$PROFILE_DIR/storage" cd "$PROJECT_ROOT" if command -v cargo-flamegraph &> /dev/null; then CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \ --bench storage_bench \ -p synor-storage \ --output "$PROFILE_DIR/storage/flamegraph.svg" \ -- --bench success "Storage flamegraph saved to $PROFILE_DIR/storage/flamegraph.svg" else cargo bench -p synor-storage --bench storage_bench -- --verbose fi } # Profile crypto operations profile_crypto() { info "Profiling crypto operations..." mkdir -p "$PROFILE_DIR/crypto" cd "$PROJECT_ROOT" if command -v cargo-flamegraph &> /dev/null; then CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \ --bench crypto_bench \ -p synor-crypto \ --output "$PROFILE_DIR/crypto/flamegraph.svg" \ -- --bench success "Crypto flamegraph saved to $PROFILE_DIR/crypto/flamegraph.svg" else cargo bench -p synor-crypto --bench crypto_bench -- --verbose fi } # Profile consensus validation profile_consensus() { info "Profiling consensus validation..." mkdir -p "$PROFILE_DIR/consensus" cd "$PROJECT_ROOT" if command -v cargo-flamegraph &> /dev/null; then CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph \ --bench consensus_bench \ -p synor-consensus \ --output "$PROFILE_DIR/consensus/flamegraph.svg" \ -- --bench success "Consensus flamegraph saved to $PROFILE_DIR/consensus/flamegraph.svg" else cargo bench -p synor-consensus --bench consensus_bench -- --verbose fi } # Run all benchmarks and compare run_all_benchmarks() { info "Running all benchmarks..." cd "$PROJECT_ROOT" # Create baseline if it doesn't exist if [[ ! -d "$PROFILE_DIR/baseline" ]]; then info "Creating baseline benchmark results..." cargo bench --workspace -- --save-baseline baseline success "Baseline saved" else info "Comparing against baseline..." cargo bench --workspace -- --baseline baseline fi } # Profile with samply (macOS-friendly) profile_with_samply() { local target="$1" if ! command -v samply &> /dev/null; then error "samply not installed. Run: cargo install samply" fi info "Profiling $target with samply..." mkdir -p "$PROFILE_DIR/samply" cd "$PROJECT_ROOT" case "$target" in mining) samply record -- cargo bench -p synor-mining --bench mining_bench ;; ghostdag) samply record -- cargo bench -p synor-dag --bench ghostdag_bench ;; storage) samply record -- cargo bench -p synor-storage --bench storage_bench ;; crypto) samply record -- cargo bench -p synor-crypto --bench crypto_bench ;; consensus) samply record -- cargo bench -p synor-consensus --bench consensus_bench ;; *) error "Unknown target: $target" ;; esac } # Generate summary report generate_report() { info "Generating profiling report..." local report="$PROFILE_DIR/PROFILING_REPORT.md" cat > "$report" << 'EOF' # Synor Profiling Report Generated: $(date) ## Critical Paths Analyzed ### 1. kHeavyHash Mining - Matrix initialization time - Hash computation throughput - Memory allocation patterns ### 2. GHOSTDAG Consensus - Block ordering performance - Blue score calculation - Merge set computation ### 3. Storage Operations - RocksDB read/write latency - Batch operation efficiency - Cache hit rates ### 4. Cryptography - Ed25519 signing/verification - Dilithium3 operations - Hybrid signature performance ## Flamegraphs See SVG files in subdirectories: - `mining/flamegraph.svg` - `ghostdag/flamegraph.svg` - `storage/flamegraph.svg` - `crypto/flamegraph.svg` - `consensus/flamegraph.svg` ## Optimization Opportunities 1. **Hot paths** - Look for wide bars at the top of flamegraphs 2. **Allocation pressure** - Search for `alloc` or `malloc` patterns 3. **Lock contention** - Look for mutex/rwlock wait times 4. **Serialization overhead** - Check borsh/serde time ## Running Profiles ```bash # Profile specific component ./scripts/profile.sh mining ./scripts/profile.sh ghostdag ./scripts/profile.sh storage # Run all benchmarks with comparison ./scripts/profile.sh all # Use samply on macOS ./scripts/profile.sh samply mining ``` EOF success "Report generated at $report" } # Print usage usage() { cat << EOF Usage: $0 [options] Commands: check Check profiling dependencies build Build with profiling symbols mining Profile kHeavyHash mining ghostdag Profile GHOSTDAG consensus storage Profile storage operations crypto Profile cryptographic operations consensus Profile consensus validation all Run all benchmarks samply Profile with samply (macOS-friendly) report Generate profiling report Options: -h, --help Show this help message Examples: $0 check # Check dependencies $0 mining # Profile mining $0 samply ghostdag # Profile GHOSTDAG with samply $0 all # Run all benchmarks EOF } # Main entry point main() { case "${1:-}" in check) check_deps ;; build) build_profile ;; mining) check_deps profile_mining ;; ghostdag) check_deps profile_ghostdag ;; storage) check_deps profile_storage ;; crypto) check_deps profile_crypto ;; consensus) check_deps profile_consensus ;; all) check_deps run_all_benchmarks ;; samply) profile_with_samply "${2:-}" ;; report) generate_report ;; -h|--help|"") usage ;; *) error "Unknown command: $1" ;; esac } main "$@"