diff --git a/.cargo/config.toml b/.cargo/config.toml index 846bccb9d..5f0bd591a 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,9 +1,11 @@ [alias] xtask = "run --package xtask --" docs = "doc --workspace --all-features --no-deps" -b = "bench --package builder --bench coordinator --" -bs = "bench --package builder --bench coordinator -- --save-baseline" -bc = "bench --package builder --bench coordinator -- --baseline main --save-baseline pr" +bench = "bench --package builder --bench coordinator --" +bench-save = "bench --package builder --bench coordinator -- --save-baseline" +bench-cmp = "bench --package builder --bench coordinator -- --baseline main --save-baseline pr" +prof-build = "build --profile profiling --features jemalloc --bin world-chain" +prof-bench = "bench --profile profiling --package world-chain-builder --bench coordinator" [env] DEBUG = "info,flashblocks=debug,world_chain=info" diff --git a/.github/scripts/build_pgo.sh b/.github/scripts/build_pgo.sh new file mode 100755 index 000000000..601a7547a --- /dev/null +++ b/.github/scripts/build_pgo.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# PGO (Profile-Guided Optimization) build script for world-chain. +# +# This script automates the three-phase PGO workflow: +# 1. Build with PGO instrumentation +# 2. Collect profile data by running benchmarks +# 3. Rebuild with PGO optimization applied +# +# Environment variables: +# FEATURES - Cargo features (default: "jemalloc") +# PGO_DATA_DIR - Directory for raw PGO data (default: /tmp/pgo-data) +# EXTRA_RUSTFLAGS - Additional RUSTFLAGS (default: "") +# SKIP_COLLECT - Skip collection phase, use existing data (default: false) +# STRIP_SYMBOLS - Strip debug symbols from final binary (default: false) +# +# Usage: +# .github/scripts/build_pgo.sh + +set -euo pipefail + +FEATURES="${FEATURES:-jemalloc}" +PGO_DATA_DIR="${PGO_DATA_DIR:-/tmp/pgo-data}" +EXTRA_RUSTFLAGS="${EXTRA_RUSTFLAGS:-}" +SKIP_COLLECT="${SKIP_COLLECT:-false}" +STRIP_SYMBOLS="${STRIP_SYMBOLS:-false}" + +BIN="world-chain" +PROFILE_BUILD="profiling" +PROFILE_FINAL="maxperf" + +# Resolve llvm-profdata from the rustc sysroot +SYSROOT=$(rustc --print sysroot) +HOST_TRIPLE=$(rustc -vV | awk '/^host:/ { print $2 }') +LLVM_PROFDATA="$SYSROOT/lib/rustlib/$HOST_TRIPLE/bin/llvm-profdata" + +if [[ ! -f "$LLVM_PROFDATA" ]]; then + echo "ERROR: llvm-profdata not found. Install llvm-tools-preview:" + echo " rustup component add llvm-tools-preview" + exit 1 +fi + +echo "=== Phase 1: PGO Instrumented Build ===" +mkdir -p "$PGO_DATA_DIR" + +RUSTFLAGS="-Cprofile-generate=$PGO_DATA_DIR -C target-cpu=native $EXTRA_RUSTFLAGS" \ + cargo build --profile "$PROFILE_BUILD" --features "$FEATURES" --bin "$BIN" + +echo "Instrumented binary: target/$PROFILE_BUILD/$BIN" + +if [[ "$SKIP_COLLECT" != "true" ]]; then + echo "" + echo "=== Phase 2: Collect PGO Data ===" + echo "Running benchmarks to collect profile data..." + + RUSTFLAGS="-Cprofile-generate=$PGO_DATA_DIR -C target-cpu=native $EXTRA_RUSTFLAGS" \ + cargo bench --profile "$PROFILE_BUILD" \ + --package world-chain-builder \ + --bench coordinator \ + -- --warm-up-time 3 --measurement-time 20 + + echo "Profile data collected in: $PGO_DATA_DIR" + echo "Files: $(find "$PGO_DATA_DIR" -name '*.profraw' | wc -l) .profraw files" +fi + +echo "" +echo "=== Phase 3: Merge Profile Data ===" +"$LLVM_PROFDATA" merge -o "$PGO_DATA_DIR/merged.profdata" "$PGO_DATA_DIR" +echo "Merged profile: $PGO_DATA_DIR/merged.profdata" + +echo "" +echo "=== Phase 4: PGO Optimized Build ===" +RUSTFLAGS="-Cprofile-use=$PGO_DATA_DIR/merged.profdata -C target-cpu=native $EXTRA_RUSTFLAGS" \ + cargo build --profile "$PROFILE_FINAL" --features "$FEATURES" --bin "$BIN" + +if [[ "$STRIP_SYMBOLS" == "true" ]]; then + echo "Stripping debug symbols..." + strip "target/$PROFILE_FINAL/$BIN" +fi + +echo "" +echo "=== Done ===" +echo "PGO-optimized binary: target/$PROFILE_FINAL/$BIN" +SIZE=$(ls -lh "target/$PROFILE_FINAL/$BIN" | awk '{print $5}') +echo "Binary size: $SIZE" diff --git a/.github/workflows/profiling.yml b/.github/workflows/profiling.yml new file mode 100644 index 000000000..bf75f0ef1 --- /dev/null +++ b/.github/workflows/profiling.yml @@ -0,0 +1,159 @@ +name: Profiling Build + +on: + workflow_dispatch: + inputs: + profile: + description: 'Cargo profile to build with' + required: true + default: 'profiling' + type: choice + options: + - profiling + - maxperf + enable_pgo: + description: 'Enable PGO data collection and optimized rebuild' + required: false + default: false + type: boolean + workflow_call: + inputs: + profile: + required: true + type: string + default: 'profiling' + enable_pgo: + required: false + type: boolean + default: false + +env: + CARGO_TERM_COLOR: always + +permissions: + contents: read + +jobs: + build-profiling: + name: Build (${{ inputs.profile }}) + runs-on: arc-public-8xlarge-amd64-runner + timeout-minutes: 120 + env: + PROFILE: ${{ inputs.profile }} + steps: + - uses: actions/checkout@v6 + + - uses: dtolnay/rust-toolchain@stable + + - name: Cache + uses: actions/cache@v5 + continue-on-error: false + with: + path: | + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: cargo-profiling-${{ hashFiles('**/Cargo.lock') }} + restore-keys: cargo-profiling- + + - name: Build profiling binary + run: | + case "${PROFILE}" in + profiling|maxperf) ;; + *) echo "invalid profile: ${PROFILE}" >&2; exit 1 ;; + esac + + RUSTFLAGS="-C target-cpu=native" \ + cargo build --profile "${PROFILE}" \ + --features jemalloc \ + --bin world-chain + + - name: Upload profiling binary + uses: actions/upload-artifact@v7 + with: + name: world-chain-${{ env.PROFILE }}-x86_64-linux + path: target/${{ env.PROFILE }}/world-chain + retention-days: 7 + + build-pgo: + name: PGO Build + if: ${{ inputs.enable_pgo }} + runs-on: arc-public-8xlarge-amd64-runner + timeout-minutes: 180 + steps: + - uses: actions/checkout@v6 + + - uses: dtolnay/rust-toolchain@stable + with: + components: llvm-tools-preview + + - name: Cache + uses: actions/cache@v5 + continue-on-error: false + with: + path: | + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: cargo-pgo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: cargo-pgo- + + - name: Phase 1 - PGO instrumented build + run: | + just build-pgo-instrumented + + - name: Phase 2 - Collect PGO data via benchmarks + run: | + RUSTFLAGS="-Cprofile-generate=/tmp/pgo-data -C target-cpu=native" \ + cargo bench --profile profiling \ + --package world-chain-builder \ + --bench coordinator \ + -- --warm-up-time 5 --measurement-time 30 + + - name: Phase 3 - Merge PGO profile data + run: | + just merge-pgo + + - name: Phase 4 - PGO optimized build + run: | + just build-pgo-optimized + + - name: Upload PGO-optimized binary + uses: actions/upload-artifact@v7 + with: + name: world-chain-pgo-optimized-x86_64-linux + path: target/maxperf/world-chain + retention-days: 7 + + - name: Upload PGO profile data + uses: actions/upload-artifact@v7 + with: + name: pgo-profile-data + path: /tmp/pgo-data/merged.profdata + retention-days: 1 + + docker-profiling: + name: Docker profiling image + needs: build-profiling + runs-on: arc-public-8xlarge-amd64-runner + timeout-minutes: 90 + steps: + - uses: actions/checkout@v6 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build profiling Docker image + run: | + just docker-profiling + + - name: Save Docker image + run: | + docker save world-chain:profiling | gzip > world-chain-profiling.tar.gz + + - name: Upload Docker image + uses: actions/upload-artifact@v7 + with: + name: world-chain-docker-profiling + path: world-chain-profiling.tar.gz + retention-days: 3 diff --git a/Cargo.toml b/Cargo.toml index 500d47856..1b6455b86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,10 @@ inherits = "dev" [profile.verbose-tracing] inherits = "dev" +[profile.profiling] +inherits = "release" +debug = "full" +strip = "none" [workspace.lints] diff --git a/Justfile b/Justfile index c90c494bd..b38830648 100644 --- a/Justfile +++ b/Justfile @@ -51,3 +51,57 @@ docs: install *args='': cargo install --path bin/world-chain --locked $@ + +# === Profiling === + +# Build with profiling profile (release + debug symbols for perf/samply/flamegraph) +build-profiling features='jemalloc': + RUSTFLAGS="-C target-cpu=native" cargo build --profile profiling --features {{ features }} --bin world-chain + +# Build with maxperf profile + native CPU targeting +build-maxperf features='jemalloc': + RUSTFLAGS="-C target-cpu=native" cargo build --profile maxperf --features {{ features }} --bin world-chain + +# Build release targeting native CPU (without profiling symbols) +build-native features='jemalloc': + RUSTFLAGS="-C target-cpu=native" cargo build --release --features {{ features }} --bin world-chain + +# Run benchmarks with profiling profile +bench-profiling *args='': + RUSTFLAGS="-C target-cpu=native" cargo bench --profile profiling --package world-chain-builder --bench coordinator -- $@ + +# Run playground with profiling build for profile data collection +stress-profile *args='': + RUSTFLAGS="-C target-cpu=native" RUST_LOG="info" cargo run -p xtask --profile profiling -- launch-node --nodes 2 --spam --num-blocks 100 $@ + +# Build Docker image with profiling profile +docker-profiling features='jemalloc': + docker buildx build \ + --build-arg PROFILE=profiling \ + --build-arg FEATURES={{ features }} \ + -t world-chain:profiling . + +# Build Docker image with maxperf profile +docker-maxperf features='jemalloc': + docker buildx build \ + --build-arg PROFILE=maxperf \ + --build-arg FEATURES={{ features }} \ + -t world-chain:maxperf . + +# === PGO (Profile-Guided Optimization) === + +# PGO phase 1: build with instrumentation +build-pgo-instrumented pgo_data_dir='/tmp/pgo-data' features='jemalloc': + mkdir -p {{ pgo_data_dir }} + RUSTFLAGS="-Cprofile-generate={{ pgo_data_dir }} -C target-cpu=native" \ + cargo build --profile profiling --features {{ features }} --bin world-chain + +# Merge PGO profile data files into a single .profdata +merge-pgo pgo_data_dir='/tmp/pgo-data': + $(rustc --print sysroot)/lib/rustlib/$(rustc -vV | awk '/^host:/ { print $2 }')/bin/llvm-profdata \ + merge -o {{ pgo_data_dir }}/merged.profdata {{ pgo_data_dir }} + +# PGO phase 3: build with optimization using collected profile data +build-pgo-optimized pgo_merged='/tmp/pgo-data/merged.profdata' features='jemalloc': + RUSTFLAGS="-Cprofile-use={{ pgo_merged }} -C target-cpu=native" \ + cargo build --profile maxperf --features {{ features }} --bin world-chain