g3/scripts/pgo/example_run.sh
WaterWhisperer ef761d9e58
Some checks are pending
CodeCoverage / lib unit test (push) Waiting to run
CodeCoverage / g3mkcert test (push) Waiting to run
CodeCoverage / g3keymess test (push) Waiting to run
CodeCoverage / g3proxy test (push) Waiting to run
CodeCoverage / g3bench test (push) Waiting to run
CodeCoverage / g3statsd test (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (java-kotlin) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
CodeQL Advanced / Analyze (rust) (push) Waiting to run
CrossCompiling / Build (push) Waiting to run
CrossCompiling / Build-1 (push) Waiting to run
CrossCompiling / Build-2 (push) Waiting to run
CrossCompiling / Build-3 (push) Waiting to run
CrossCompiling / Build-4 (push) Waiting to run
CrossCompiling / Build-5 (push) Waiting to run
CrossCompiling / Build-6 (push) Waiting to run
CrossCompiling / Build-7 (push) Waiting to run
CrossCompiling / Build-8 (push) Waiting to run
CrossCompiling / Build-9 (push) Waiting to run
Linux-CI / Clippy (push) Waiting to run
Linux-CI / Build (push) Waiting to run
Linux-CI / Build-1 (push) Waiting to run
Linux-CI / Build-2 (push) Waiting to run
Linux-CI / Build-3 (push) Waiting to run
Linux-CI / Build vendored (push) Waiting to run
Linux-CI / Build vendored-1 (push) Waiting to run
Linux-CI / Build vendored-2 (push) Waiting to run
Linux-CI / Build vendored-3 (push) Waiting to run
Linux-CI / Build vendored-4 (push) Waiting to run
Linux-CI / Build vendored-5 (push) Waiting to run
Linux-CI / Build vendored-6 (push) Waiting to run
Linux-CI / Build vendored-7 (push) Waiting to run
Linux-CI / Build vendored-8 (push) Waiting to run
Linux-CI / Build vendored-9 (push) Waiting to run
Linux-CI / Build vendored-10 (push) Waiting to run
Linux-CI / Build vendored-11 (push) Waiting to run
Linux-CI / Build vendored-12 (push) Waiting to run
Linux-CI / Build vendored-13 (push) Waiting to run
Linux-CI / Build vendored-14 (push) Waiting to run
Linux-CI / Build vendored-15 (push) Waiting to run
Linux-CI / Build vendored-16 (push) Waiting to run
Linux-CI / Build vendored-17 (push) Waiting to run
Linux-CI / Build vendored-18 (push) Waiting to run
Linux-CI / Build vendored-19 (push) Waiting to run
Linux-CI / Build vendored-20 (push) Waiting to run
Linux-CI / Build vendored-21 (push) Waiting to run
Linux-CI / Build vendored-22 (push) Waiting to run
Linux-CI / Build vendored-23 (push) Waiting to run
Linux-CI / Build vendored-24 (push) Waiting to run
Linux-CI / Build vendored-25 (push) Waiting to run
Linux-CI / Build vendored-26 (push) Waiting to run
Linux-CI / Build vendored-27 (push) Waiting to run
Linux-CI / Build vendored-28 (push) Waiting to run
Linux-CI / Build vendored-29 (push) Waiting to run
Linux-CI / Build vendored-30 (push) Waiting to run
Linux-CI / Build with OpenSSL Async Job (push) Waiting to run
Linux-CI / Build with OpenSSL Async Job-1 (push) Waiting to run
MacOS-CI / Build vendored (push) Waiting to run
StaticLinking / musl (push) Waiting to run
StaticLinking / musl-1 (push) Waiting to run
StaticLinking / msvc (push) Waiting to run
StaticLinking / msvc-1 (push) Waiting to run
StaticLinking / msvc-2 (push) Waiting to run
StaticLinking / msvc-3 (push) Waiting to run
MacOS-CI / Build (push) Waiting to run
MacOS-CI / Build vendored-1 (push) Waiting to run
MacOS-CI / Build vendored-2 (push) Waiting to run
MacOS-CI / Build vendored-3 (push) Waiting to run
MacOS-CI / Build vendored-4 (push) Waiting to run
MacOS-CI / Build vendored-5 (push) Waiting to run
MacOS-CI / Build vendored-6 (push) Waiting to run
MacOS-CI / Build vendored-7 (push) Waiting to run
MacOS-CI / Build vendored-8 (push) Waiting to run
MacOS-CI / Build vendored-9 (push) Waiting to run
MacOS-CI / Build vendored-10 (push) Waiting to run
MacOS-CI / Build vendored-11 (push) Waiting to run
MacOS-CI / Build vendored-12 (push) Waiting to run
MacOS-CI / Build vendored-13 (push) Waiting to run
MacOS-CI / Build vendored-14 (push) Waiting to run
MacOS-CI / Build vendored-15 (push) Waiting to run
MacOS-CI / Build vendored-16 (push) Waiting to run
MacOS-CI / Build vendored-17 (push) Waiting to run
MacOS-CI / Build vendored-18 (push) Waiting to run
MacOS-CI / Build vendored-19 (push) Waiting to run
MacOS-CI / Build vendored-20 (push) Waiting to run
MacOS-CI / Build vendored-21 (push) Waiting to run
MacOS-CI / Build vendored-22 (push) Waiting to run
MacOS-CI / Build vendored-23 (push) Waiting to run
MacOS-CI / Build vendored-24 (push) Waiting to run
Windows-CI / Build (push) Waiting to run
Windows-CI / Build vendored (push) Waiting to run
Windows-CI / Build vendored-1 (push) Waiting to run
Windows-CI / Build vendored-2 (push) Waiting to run
Windows-CI / Build vendored-3 (push) Waiting to run
Windows-CI / Build vendored-4 (push) Waiting to run
Windows-CI / Build vendored-5 (push) Waiting to run
Windows-CI / Build vendored-6 (push) Waiting to run
Windows-CI / Build vendored-7 (push) Waiting to run
Windows-CI / Build vendored-8 (push) Waiting to run
Windows-CI / Build vendored-9 (push) Waiting to run
Windows-CI / Build vendored-10 (push) Waiting to run
Windows-CI / Build vendored-11 (push) Waiting to run
Windows-CI / Build vendored-12 (push) Waiting to run
Windows-CI / Build vendored-13 (push) Waiting to run
Windows-CI / Build vendored-14 (push) Waiting to run
Windows-CI / Build vendored-15 (push) Waiting to run
Windows-CI / Build vendored-16 (push) Waiting to run
Windows-CI / Build vendored-17 (push) Waiting to run
Windows-CI / Build vendored-18 (push) Waiting to run
Windows-CI / Build vendored-19 (push) Waiting to run
Windows-CI / Build vendored-20 (push) Waiting to run
Windows-CI / Build vendored-21 (push) Waiting to run
Windows-CI / Build vendored-22 (push) Waiting to run
Windows-CI / Build vendored-23 (push) Waiting to run
feat: enable Profile-Guided Optimization (PGO) for rust code
2025-09-26 13:55:16 +08:00

507 lines
No EOL
22 KiB
Bash
Executable file

#!/bin/bash
# PGO Build Script for Rust Code
# This script implements Profile-Guided Optimization for g3 Rust components
set -e
SCRIPTS_DIR=$(dirname "$0")
PROJECT_DIR=$(realpath "${SCRIPTS_DIR}/../..")
PGO_DIR="${SCRIPTS_DIR}"
PROFILE_DIR="${PGO_DIR}/profile"
BENCHMARK_DIR="${PGO_DIR}/benchmark"
BUILD_DIR="${PROJECT_DIR}/target"
PGO_DATA_DIR="/tmp/pgo-data"
# Default components for PGO (memory-efficient choices)
DEFAULT_COMPONENTS=("g3mkcert")
# All available components
ALL_COMPONENTS=("g3mkcert" "g3proxy" "g3bench" "g3fcgen" "g3iploc" "g3keymess" "g3statsd" "g3tiles")
# Components to build with PGO (set by command line args)
declare -a PGO_COMPONENTS
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Check prerequisites
check_prerequisites() {
log_info "Checking Rust PGO prerequisites..."
# Check Rust and Cargo
if ! command -v cargo >/dev/null 2>&1; then
log_error "Cargo not found. Please install Rust."
exit 1
fi
# Check cargo-binutils for profdata
if ! cargo profdata --help >/dev/null 2>&1; then
log_warn "cargo profdata not found. Please install cargo-binutils: cargo install cargo-binutils && cargo binutils setup"
fi
log_info "Prerequisites check passed"
}
# Clean previous builds and profile data
TEMP_DIRS=()
cleanup_temp_dirs() {
log_info "Cleaning up temporary directories..."
for dir in "${TEMP_DIRS[@]}"; do
rm -rf "$dir" 2>/dev/null || true
done
rm -rf "${PGO_DATA_DIR}"
}
clean_previous() {
log_info "Cleaning previous builds and profile data..."
cargo clean
cleanup_temp_dirs
mkdir -p "${PGO_DATA_DIR}"
}
# Build instrumented binaries for profile generation
build_instrumented() {
log_info "Building instrumented binaries for profile generation..."
log_info "Target components: ${PGO_COMPONENTS[*]}"
cd "${PROJECT_DIR}"
for component in "${PGO_COMPONENTS[@]}"; do
log_info "Building instrumented binary for $component ..."
RUSTFLAGS="-Cprofile-generate=${PGO_DATA_DIR}" cargo build --release -p "$component"
done
log_info "Instrumented binaries built successfully"
}
get_binary_path() {
local binary_name="$1"
echo "./target/release/${binary_name}"
}
# Run comprehensive g3mkcert workload based on coverage scripts
run_g3mkcert_comprehensive_workload() {
local g3mkcert_bin="$1"
local temp_dir="/tmp/pgo-g3mkcert-$$"
local original_dir="$(pwd)"
TEMP_DIRS+=("$temp_dir")
echo "Running comprehensive g3mkcert workload based on coverage scripts..."
mkdir -p "$temp_dir"
cd "$temp_dir"
# Convert relative path to absolute path
if [[ "$g3mkcert_bin" != /* ]]; then
g3mkcert_bin="${original_dir}/${g3mkcert_bin}"
fi
# Basic operations first
"$g3mkcert_bin" --version || echo "g3mkcert --version failed"
"$g3mkcert_bin" --help || echo "g3mkcert --help failed"
# Root CA certificates with different algorithms and key sizes
echo "Generating Root CA certificates..."
"$g3mkcert_bin" --root --common-name "G3 Test CA" --rsa 2048 --output-cert rootCA-rsa.crt --output-key rootCA-rsa.key || echo "Root CA RSA generation failed"
"$g3mkcert_bin" --root --common-name "G3 Test CA" --ec256 --output-cert rootCA-ec256.crt --output-key rootCA-ec256.key || echo "Root CA EC256 generation failed"
"$g3mkcert_bin" --root --common-name "G3 Test CA" --ed25519 --output-cert rootCA-ed25519.crt --output-key rootCA-ed25519.key || echo "Root CA Ed25519 generation failed"
# Intermediate CA certificates
echo "Generating Intermediate CA certificates..."
"$g3mkcert_bin" --intermediate --common-name "G3 Intermediate CA" --rsa 2048 --output-cert intermediateCA-rsa.crt --output-key intermediateCA-rsa.key --ca-cert rootCA-rsa.crt --ca-key rootCA-rsa.key || echo "Intermediate CA RSA generation failed"
"$g3mkcert_bin" --intermediate --common-name "G3 Intermediate CA" --ec384 --output-cert intermediateCA-ec384.crt --output-key intermediateCA-ec384.key --ca-cert rootCA-ec256.crt --ca-key rootCA-ec256.key || echo "Intermediate CA EC384 generation failed"
"$g3mkcert_bin" --intermediate --common-name "G3 Intermediate CA" --ed25519 --output-cert intermediateCA-ed25519.crt --output-key intermediateCA-ed25519.key --ca-cert rootCA-ed25519.crt --ca-key rootCA-ed25519.key || echo "Intermediate CA Ed25519 generation failed"
# TLS Server certificates with different algorithms and hosts
echo "Generating TLS Server certificates..."
"$g3mkcert_bin" --tls-server --host "www.example.com" --host "*.example.net" --rsa 2048 --output-cert tls-server-rsa.crt --output-key tls-server-rsa.key --ca-cert rootCA-rsa.crt --ca-key rootCA-rsa.key || echo "TLS Server RSA generation failed"
"$g3mkcert_bin" --tls-server --host "www.example.com" --host "*.example.net" --ec256 --output-cert tls-server-ec256.crt --output-key tls-server-ec256.key --ca-cert intermediateCA-rsa.crt --ca-key intermediateCA-rsa.key || echo "TLS Server EC256 generation failed"
"$g3mkcert_bin" --tls-server --host "www.example.com" --host "*.example.net" --ed25519 --output-cert tls-server-ed25519.crt --output-key tls-server-ed25519.key --ca-cert rootCA-rsa.crt --ca-key rootCA-rsa.key || echo "TLS Server Ed25519 generation failed"
# TLS Client certificates
echo "Generating TLS Client certificates..."
"$g3mkcert_bin" --tls-client --host "www.example.com" --rsa 4096 --output-cert tls-client-rsa.crt --output-key tls-client-rsa.key --ca-cert intermediateCA-ec384.crt --ca-key intermediateCA-ec384.key || echo "TLS Client RSA generation failed"
"$g3mkcert_bin" --tls-client --host "www.example.com" --ec256 --output-cert tls-client-ec256.crt --output-key tls-client-ec256.key --ca-cert rootCA-ec256.crt --ca-key rootCA-ec256.key || echo "TLS Client EC256 generation failed"
"$g3mkcert_bin" --tls-client --host "www.example.com" --ed25519 --output-cert tls-client-ed25519.crt --output-key tls-client-ed25519.key --ca-cert intermediateCA-ed25519.crt --ca-key intermediateCA-ed25519.key || echo "TLS Client Ed25519 generation failed"
cd "$original_dir"
echo "Comprehensive g3mkcert workload completed"
}
# Run profile generation workloads
generate_profiles() {
# Use unified directory for both compiler generated and runtime (LLVM_PROFILE_FILE) output
local profile_data_dir="${PGO_DATA_DIR}"
echo "Generating PGO profiles..."
mkdir -p "${PGO_DATA_DIR}"
# Pattern ensures per-process/profile separation
export LLVM_PROFILE_FILE="${PGO_DATA_DIR}/cargo-pgo-%p-%m.profraw"
export TEST_NAME="rust-pgo"
echo "Environment variables:"
echo " LLVM_PROFILE_FILE=${LLVM_PROFILE_FILE}"
echo " TEST_NAME=${TEST_NAME}"
echo " RUSTFLAGS=${RUSTFLAGS}"
# Run workloads based on available components
for component in "${PGO_COMPONENTS[@]}"; do
case $component in
g3mkcert)
local g3mkcert_bin=$(get_binary_path "g3mkcert")
run_g3mkcert_comprehensive_workload "$g3mkcert_bin"
;;
g3proxy)
echo "Running g3proxy workload..."
local g3proxy_bin=$(get_binary_path "g3proxy")
"$g3proxy_bin" --help || echo "g3proxy help failed"
"$g3proxy_bin" --version || echo "g3proxy version failed"
;;
g3bench)
echo "Running g3bench workload..."
local g3bench_bin=$(get_binary_path "g3bench")
"$g3bench_bin" help || echo "g3bench help command failed"
"$g3bench_bin" version || echo "g3bench version command failed"
;;
g3fcgen)
echo "Running g3fcgen workload..."
local g3fcgen_bin=$(get_binary_path "g3fcgen")
"$g3fcgen_bin" --help || echo "g3fcgen help failed"
"$g3fcgen_bin" --version || echo "g3fcgen version failed"
;;
g3iploc)
echo "Running g3iploc workload..."
local g3iploc_bin=$(get_binary_path "g3iploc")
"$g3iploc_bin" --help || echo "g3iploc help failed"
"$g3iploc_bin" --version || echo "g3iploc version failed"
;;
g3keymess)
echo "Running g3keymess workload..."
local g3keymess_bin=$(get_binary_path "g3keymess")
"$g3keymess_bin" --help || echo "g3keymess help failed"
"$g3keymess_bin" --version || echo "g3keymess version failed"
;;
g3statsd)
echo "Running g3statsd workload..."
local g3statsd_bin=$(get_binary_path "g3statsd")
"$g3statsd_bin" --help || echo "g3statsd help failed"
"$g3statsd_bin" --version || echo "g3statsd version failed"
;;
g3tiles)
echo "Running g3tiles workload..."
local g3tiles_bin=$(get_binary_path "g3tiles")
"$g3tiles_bin" --help || echo "g3tiles help failed"
"$g3tiles_bin" --version || echo "g3tiles version failed"
;;
*)
echo "Running workload for ${component}..."
local component_bin=$(get_binary_path "${component}")
if [ -f "$component_bin" ]; then
"$component_bin" --help 2>/dev/null || echo "${component} help failed"
"$component_bin" --version 2>/dev/null || echo "${component} version failed"
fi
;;
esac
done
echo "Running unit tests to generate profiles..."
# Run tests to generate more profile data
cargo test --release --package g3-types || echo "g3-types tests failed, continuing..."
# Check if any profile files were generated
local profile_count=$(find "${profile_data_dir}" -name "*.profraw" 2>/dev/null | wc -l)
echo "Generated ${profile_count} profile files in ${profile_data_dir}"
if [ "${profile_count}" -eq 0 ]; then
echo "Warning: No profile files generated"
ls -la "${profile_data_dir}" || echo "Profile directory doesn't exist"
echo "Checking if instrumented binaries have profile capabilities..."
local g3mkcert_bin=$(get_binary_path "g3mkcert")
if [ -f "$g3mkcert_bin" ]; then
ldd "$g3mkcert_bin" | grep -i profile || echo "No profile libraries found"
fi
return 1
fi
echo "Profile generation completed successfully!"
return 0
}
# Build optimized binary using profile data
build_optimized() {
log_info "Merging profile data..."
shopt -s nullglob
local profraw_files=("${PGO_DATA_DIR}"/*.profraw)
if [ ${#profraw_files[@]} -eq 0 ]; then
log_error "No .profraw files found in ${PGO_DATA_DIR}; skip optimized build."
shopt -u nullglob
return 1
fi
local count=${#profraw_files[@]}
log_info "Found ${count} raw profile files"
cargo profdata -- merge -o "${PGO_DATA_DIR}/merged.profdata" "${profraw_files[@]}"
shopt -u nullglob
log_info "Building optimized binaries using profile data..."
cd "${PROJECT_DIR}"
for component in "${PGO_COMPONENTS[@]}"; do
log_info "Building optimized binary for $component ..."
RUSTFLAGS="-Cprofile-use=${PGO_DATA_DIR}/merged.profdata" cargo build --release -p "$component"
done
log_info "Optimized binaries built successfully"
}
# Check if hyperfine is available for more precise benchmarking
check_benchmark_tool() {
if command -v hyperfine >/dev/null 2>&1; then
echo "hyperfine"
else
echo "time"
fi
}
run_performance_benchmark() {
log_info "Running performance benchmark to measure PGO effectiveness"
local benchmark_tool=$(check_benchmark_tool)
if [ "$benchmark_tool" = "time" ]; then
log_warn "Using 'time' for basic benchmarking. For more precise results, install 'hyperfine': cargo install hyperfine"
else
log_info "Using 'hyperfine' for precise benchmarking"
fi
# Preserve current (PGO optimized) binaries before building baseline which would overwrite them
log_info "Preserving PGO optimized binaries..."
for component in "${PGO_COMPONENTS[@]}"; do
local pgo_bin="${BUILD_DIR}/release/${component}"
if [ -x "$pgo_bin" ]; then
cp "$pgo_bin" "/tmp/${component}-pgo" || log_warn "Failed to preserve PGO binary for ${component}"
else
log_warn "Expected optimized binary not found for ${component}: $pgo_bin"
fi
done
log_info "PGO binaries saved to /tmp/<component>-pgo"
# First test with regular build for comparison
log_info "Building baseline (non-PGO) version for comparison..."
(cd "${PROJECT_DIR}" && cargo build --release >/dev/null 2>&1)
echo ""
log_info "=== Baseline Performance (without PGO) ==="
for component in "${PGO_COMPONENTS[@]}"; do
case "$component" in
"g3mkcert")
echo "Testing g3mkcert operations..."
local g3mkcert_bin=$(get_binary_path "g3mkcert")
local cert_out="/tmp/rootCA-bench-baseline.crt"
local key_out="/tmp/rootCA-bench-baseline.key"
if [ "$benchmark_tool" = "hyperfine" ]; then
# Save baseline for hyperfine comparison
cp "$g3mkcert_bin" "/tmp/g3mkcert-baseline"
echo "Baseline saved for comparison"
else
time "$g3mkcert_bin" --root --common-name "G3 Test CA" --rsa 2048 --output-cert "$cert_out" --output-key "$key_out" >/dev/null 2>&1 || echo "Baseline test completed"
fi
;;
"g3proxy"|"g3bench"|"g3fcgen"|"g3iploc"|"g3keymess"|"g3statsd"|"g3tiles")
echo "Testing ${component} basic operations..."
local component_bin=$(get_binary_path "${component}")
if [ "$benchmark_tool" = "hyperfine" ]; then
# Save baseline for hyperfine comparison
cp "$component_bin" "/tmp/${component}-baseline"
echo "Baseline saved for comparison"
else
time (for i in {1..20}; do "$component_bin" --help >/dev/null 2>&1; done) 2>/dev/null || echo "${component} baseline test completed"
fi
;;
*)
echo "Testing ${component} basic operations..."
local component_bin=$(get_binary_path "${component}")
if [ "$benchmark_tool" = "time" ]; then
time (for i in {1..20}; do "$component_bin" --help >/dev/null 2>&1; done) 2>/dev/null || echo "${component} baseline test completed"
fi
;;
esac
done
echo ""
log_info "=== PGO-Optimized Performance ==="
for component in "${PGO_COMPONENTS[@]}"; do
case "$component" in
"g3mkcert")
echo "Testing PGO-optimized g3mkcert operations..."
local cert_out="/tmp/rootCA-bench-pgo.crt"
local key_out="/tmp/rootCA-bench-pgo.key"
if [ "$benchmark_tool" = "hyperfine" ]; then
echo "Comparing baseline vs PGO-optimized g3mkcert (root CA generation)..."
hyperfine --shell=none --warmup 3 --runs 15 "/tmp/g3mkcert-baseline --root --common-name 'G3 Test CA' --rsa 2048 --output-cert /tmp/rootCA-bench-baseline.crt --output-key /tmp/rootCA-bench-baseline.key" "/tmp/g3mkcert-pgo --root --common-name 'G3 Test CA' --rsa 2048 --output-cert /tmp/rootCA-bench-pgo.crt --output-key /tmp/rootCA-bench-pgo.key"
else
time "/tmp/g3mkcert-pgo" --root --common-name "G3 Test CA" --rsa 2048 --output-cert "$cert_out" --output-key "$key_out" >/dev/null 2>&1 || echo "PGO test completed"
fi
rm -f /tmp/rootCA-bench-baseline.crt /tmp/rootCA-bench-baseline.key /tmp/rootCA-bench-pgo.crt /tmp/rootCA-bench-pgo.key
;;
"g3proxy"|"g3bench"|"g3fcgen"|"g3iploc"|"g3keymess"|"g3statsd"|"g3tiles")
echo "Testing PGO-optimized ${component} basic operations..."
if [ "$benchmark_tool" = "hyperfine" ]; then
echo "Comparing baseline vs PGO-optimized ${component} (help output)..."
hyperfine --shell=none --warmup 3 --runs 15 "/tmp/${component}-baseline --help" "/tmp/${component}-pgo --help"
else
time (for i in {1..20}; do "/tmp/${component}-pgo" --help >/dev/null 2>&1; done) 2>/dev/null || echo "${component} PGO test completed"
fi
;;
*)
echo "Testing PGO-optimized ${component} basic operations..."
if [ "$benchmark_tool" = "time" ]; then
time (for i in {1..20}; do "/tmp/${component}-pgo" --help >/dev/null 2>&1; done) 2>/dev/null || echo "${component} PGO test completed"
fi
;;
esac
done
echo ""
log_info "Performance benchmark completed!"
if [ "$benchmark_tool" = "time" ]; then
log_info "Compare the 'real' times above to see PGO optimization effect"
log_info "For more precise measurements, install hyperfine: cargo install hyperfine"
else
log_info "Hyperfine results show statistical comparison with confidence intervals"
fi
for component in "${PGO_COMPONENTS[@]}"; do
if [ -f "/tmp/${component}-pgo" ]; then
cp "/tmp/${component}-pgo" "${BUILD_DIR}/release/${component}" 2>/dev/null || true
fi
done
log_info "Restored PGO binaries to ${BUILD_DIR}/release/ after benchmarking"
}
# Parse component arguments
parse_components() {
if [ ${#PGO_COMPONENTS[@]} -eq 0 ]; then
# No components specified, use defaults
PGO_COMPONENTS=("${DEFAULT_COMPONENTS[@]}")
log_info "No components specified, using defaults: ${PGO_COMPONENTS[*]}"
else
# Validate specified components
for component in "${PGO_COMPONENTS[@]}"; do
if [[ ! " ${ALL_COMPONENTS[*]} " =~ " ${component} " ]]; then
log_error "Invalid component: $component"
log_info "Available components: ${ALL_COMPONENTS[*]}"
exit 1
fi
done
log_info "Using specified components: ${PGO_COMPONENTS[*]}"
fi
}
# Main function
main() {
log_info "Starting Rust PGO optimization process..."
log_info "Project directory: ${PROJECT_DIR}"
log_info "PGO scripts directory: ${PGO_DIR}"
# Parse and validate components
parse_components
# Check prerequisites
check_prerequisites
# Step 1: Clean previous builds
clean_previous
# Step 2: Build instrumented binary
build_instrumented
# Step 3: Generate profiles
generate_profiles
# Step 4: Build optimized binary
build_optimized
# Step 5: Run benchmark (optional)
if [ "${RUN_BENCHMARK}" = "true" ]; then
run_performance_benchmark
fi
log_info "PGO optimization completed successfully!"
log_info "Components optimized: ${PGO_COMPONENTS[*]}"
log_info "Optimized binaries are available in: ${BUILD_DIR}/release/"
# Show profile data location
if [ -d "${PGO_DATA_DIR}" ]; then
profile_count=$(find "${PGO_DATA_DIR}" -name "*.profraw" -o -name "*.profdata" | wc -l)
log_info "Profile data files generated: ${profile_count}"
log_info "Profile data location: ${PGO_DATA_DIR}"
fi
if [ "${RUN_BENCHMARK}" != "true" ]; then
echo ""
log_info "To verify optimization effectiveness, run:"
echo " $0 --benchmark"
echo "or manually test optimized binaries in: ${BUILD_DIR}/release/"
fi
}
# Parse command line arguments
RUN_BENCHMARK=false
while [[ $# -gt 0 ]]; do
case $1 in
--components|-c)
shift
# Parse comma-separated component list
IFS=',' read -ra PGO_COMPONENTS <<< "$1"
shift
;;
--all|-a)
PGO_COMPONENTS=("${ALL_COMPONENTS[@]}")
shift
;;
--benchmark|-b)
RUN_BENCHMARK=true
shift
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -c, --components LIST Comma-separated list of components to optimize"
echo " Default: ${DEFAULT_COMPONENTS[*]}"
echo " -a, --all Optimize all available components"
echo " -b, --benchmark Run performance benchmark after optimization"
echo " -h, --help Show this help message"
echo ""
echo "Available components:"
echo " ${ALL_COMPONENTS[*]}"
echo ""
echo "Examples:"
echo " $0 # Use default components"
echo " $0 --components g3mkcert,g3proxy # Optimize specific components"
echo " $0 --all --benchmark # Optimize all and run benchmark"
echo ""
echo "This script performs Profile-Guided Optimization (PGO) for g3 Rust components:"
echo " 1. Builds instrumented binaries"
echo " 2. Runs representative workloads to collect profile data"
echo " 3. Builds optimized binaries using the profile data"
echo " 4. Optionally runs benchmarks to measure performance improvement"
exit 0
;;
*)
log_error "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done
trap 'cleanup_temp_dirs; exit 1' INT TERM
main