- 新增 PprofConfig 配置结构,支持路径和 IP 访问控制 - 实现 PprofHandler 处理器,提供 CPU/heap/goroutine/block/mutex profile - Makefile 新增 build-perf、build-pgo、pgo-collect 目标 - 支持 PGO (Profile-Guided Optimization) 构建 Co-Authored-By: Claude <noreply@anthropic.com>
318 lines
10 KiB
Makefile
318 lines
10 KiB
Makefile
# Makefile - Lolly Build Commands
|
||
|
||
# 版本信息
|
||
APP_NAME := lolly
|
||
VERSION := 0.1.0
|
||
GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
|
||
BUILD_TIME := $(shell date -u '+%Y-%m-%d %H:%M:%S UTC')
|
||
GO_VERSION := $(shell go version | awk '{print $$3}')
|
||
BUILD_PLATFORM := $(shell go env GOOS)/$(shell go env GOARCH)
|
||
BUILD_DIR := bin
|
||
|
||
# 生产构建标志(体积优化)
|
||
LDFLAGS := -ldflags "-s -w \
|
||
-X 'rua.plus/lolly/internal/app.Version=$(VERSION)' \
|
||
-X 'rua.plus/lolly/internal/app.GitCommit=$(GIT_COMMIT)' \
|
||
-X 'rua.plus/lolly/internal/app.GitBranch=$(GIT_BRANCH)' \
|
||
-X 'rua.plus/lolly/internal/app.BuildTime=$(BUILD_TIME)' \
|
||
-X 'rua.plus/lolly/internal/app.GoVersion=$(GO_VERSION)' \
|
||
-X 'rua.plus/lolly/internal/app.BuildPlatform=$(BUILD_PLATFORM)'"
|
||
|
||
# 运行时性能优化标志
|
||
PERF_GCFLAGS := -gcflags="-l=4"
|
||
PERF_ASMFLAGS := -asmflags="-l=4"
|
||
|
||
# Go 文件
|
||
MAIN_PATH := main.go
|
||
|
||
# 默认目标
|
||
.DEFAULT_GOAL := build
|
||
|
||
# ============================================
|
||
# 构建命令
|
||
# ============================================
|
||
|
||
# 本地构建
|
||
build:
|
||
@echo "Building $(APP_NAME)..."
|
||
@mkdir -p $(BUILD_DIR)
|
||
go build $(LDFLAGS) -o $(BUILD_DIR)/$(APP_NAME) $(MAIN_PATH)
|
||
@echo "Built: $(BUILD_DIR)/$(APP_NAME)"
|
||
@echo "Version: $(VERSION) | Commit: $(GIT_COMMIT) | Platform: $(BUILD_PLATFORM)"
|
||
|
||
# 生产构建(体积优化)
|
||
build-prod:
|
||
@echo "Building $(APP_NAME) for production..."
|
||
@mkdir -p $(BUILD_DIR)
|
||
go build $(LDFLAGS) -trimpath -o $(BUILD_DIR)/$(APP_NAME) $(MAIN_PATH)
|
||
@echo "Production build complete: $(BUILD_DIR)/$(APP_NAME)"
|
||
|
||
# 生产构建(最大运行时性能)
|
||
build-perf:
|
||
@echo "Building $(APP_NAME) with max runtime performance..."
|
||
@mkdir -p $(BUILD_DIR)
|
||
go build $(LDFLAGS) $(PERF_GCFLAGS) $(PERF_ASMFLAGS) -trimpath \
|
||
-o $(BUILD_DIR)/$(APP_NAME) $(MAIN_PATH)
|
||
@echo "Performance build complete: $(BUILD_DIR)/$(APP_NAME)"
|
||
|
||
# PGO 构建(需先收集 profile)
|
||
PGO_PROFILE ?= default.pgo
|
||
build-pgo:
|
||
@echo "Building $(APP_NAME) with PGO optimization..."
|
||
@mkdir -p $(BUILD_DIR)
|
||
if [ -f $(PGO_PROFILE) ]; then \
|
||
go build $(LDFLAGS) $(PERF_GCFLAGS) $(PERF_ASMFLAGS) -trimpath \
|
||
-pgo=$(PGO_PROFILE) -o $(BUILD_DIR)/$(APP_NAME) $(MAIN_PATH); \
|
||
echo "PGO build complete using: $(PGO_PROFILE)"; \
|
||
else \
|
||
echo "PGO profile not found: $(PGO_PROFILE)"; \
|
||
echo "Run 'make pgo-collect' first to generate profile"; \
|
||
exit 1; \
|
||
fi
|
||
|
||
# 收集 PGO profile(运行代表性 workload)
|
||
pgo-collect:
|
||
@echo "=== PGO Profile Collection Guide ==="
|
||
@echo ""
|
||
@echo "Step 1: Enable pprof in your config file:"
|
||
@echo " monitoring:"
|
||
@echo " pprof:"
|
||
@echo " enabled: true"
|
||
@echo " path: /debug/pprof"
|
||
@echo " allow: [\"127.0.0.1\"]"
|
||
@echo ""
|
||
@echo "Step 2: Build and run lolly with representative workload:"
|
||
@echo " make build && ./bin/lolly -c configs/lolly.yaml"
|
||
@echo ""
|
||
@echo "Step 3: Collect CPU profile (run during peak load):"
|
||
@echo " curl http://localhost:<port>/debug/pprof/profile?seconds=30 > $(PGO_PROFILE)"
|
||
@echo ""
|
||
@echo "Step 4: Build with PGO optimization:"
|
||
@echo " make build-pgo"
|
||
@echo ""
|
||
@echo "Available pprof endpoints:"
|
||
@echo " /debug/pprof - Index page"
|
||
@echo " /debug/pprof/profile - CPU profile (add ?seconds=N)"
|
||
@echo " /debug/pprof/heap - Memory profile"
|
||
@echo " /debug/pprof/goroutine - Goroutine count"
|
||
@echo ""
|
||
@echo "Tip: Profile during real workload for best PGO results"
|
||
|
||
# 跨平台构建
|
||
build-linux:
|
||
@echo "Building for Linux..."
|
||
@mkdir -p $(BUILD_DIR)
|
||
GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -trimpath -o $(BUILD_DIR)/$(APP_NAME)-linux-amd64 $(MAIN_PATH)
|
||
@echo "Built: $(BUILD_DIR)/$(APP_NAME)-linux-amd64"
|
||
|
||
build-darwin:
|
||
@echo "Building for macOS..."
|
||
@mkdir -p $(BUILD_DIR)
|
||
GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -trimpath -o $(BUILD_DIR)/$(APP_NAME)-darwin-amd64 $(MAIN_PATH)
|
||
GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -trimpath -o $(BUILD_DIR)/$(APP_NAME)-darwin-arm64 $(MAIN_PATH)
|
||
@echo "Built: $(BUILD_DIR)/$(APP_NAME)-darwin-{amd64,arm64}"
|
||
|
||
build-windows:
|
||
@echo "Building for Windows..."
|
||
@mkdir -p $(BUILD_DIR)
|
||
GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -trimpath -o $(BUILD_DIR)/$(APP_NAME)-windows-amd64.exe $(MAIN_PATH)
|
||
@echo "Built: $(BUILD_DIR)/$(APP_NAME)-windows-amd64.exe"
|
||
|
||
# 构建所有平台
|
||
build-all: build-linux build-darwin build-windows
|
||
@echo "All platform builds complete."
|
||
|
||
# ============================================
|
||
# 开发命令
|
||
# ============================================
|
||
|
||
# 运行开发服务器
|
||
run:
|
||
@echo "Running $(APP_NAME) in development mode..."
|
||
go run $(MAIN_PATH) -c configs/lolly.yaml
|
||
|
||
# 测试配置
|
||
test-config:
|
||
@echo "Testing configuration..."
|
||
go run $(MAIN_PATH) -t -c configs/lolly.yaml
|
||
|
||
# 显示版本
|
||
version:
|
||
@echo "$(APP_NAME) version $(VERSION)"
|
||
@echo "Git: $(GIT_COMMIT) ($(GIT_BRANCH))"
|
||
@echo "Built: $(BUILD_TIME)"
|
||
@echo "Go: $(GO_VERSION)"
|
||
|
||
# ============================================
|
||
# 测试命令
|
||
# ============================================
|
||
|
||
# 运行所有测试
|
||
test:
|
||
@echo "Running tests..."
|
||
go test -v ./...
|
||
|
||
# 运行测试(带覆盖率)
|
||
test-cover:
|
||
@echo "Running tests with coverage..."
|
||
go test -v -coverprofile=coverage.out ./...
|
||
go tool cover -html=coverage.out -o coverage.html
|
||
@echo "Coverage report: coverage.html"
|
||
|
||
# 运行基准测试
|
||
bench:
|
||
@echo "Running benchmarks..."
|
||
go test -bench=. -benchmem ./...
|
||
|
||
# 运行基准测试(统计模式,10次采样)
|
||
bench-stat:
|
||
@echo "Running benchmarks with statistical sampling..."
|
||
go test -bench=. -benchmem -count=10 ./... | tee benchmark-current.txt
|
||
|
||
# 对比基准测试结果(需要 benchstat)
|
||
bench-compare:
|
||
@echo "Comparing benchmarks..."
|
||
@if command -v benchstat >/dev/null 2>&1; then \
|
||
if [ -f benchmark-baseline.txt ]; then \
|
||
benchstat benchmark-baseline.txt benchmark-current.txt; \
|
||
else \
|
||
echo "基准线文件 benchmark-baseline.txt 不存在,运行当前基准测试..."; \
|
||
$(MAKE) bench-stat; \
|
||
fi \
|
||
else \
|
||
echo "benchstat 未安装,运行: go install golang.org/x/perf/cmd/benchstat@latest"; \
|
||
exit 1; \
|
||
fi
|
||
|
||
# 保存当前基准结果为基准线
|
||
bench-save:
|
||
@echo "Saving benchmark baseline..."
|
||
@if [ -f benchmark-current.txt ]; then \
|
||
cp benchmark-current.txt benchmark-baseline.txt; \
|
||
echo "基准线已保存到 benchmark-baseline.txt"; \
|
||
else \
|
||
echo "运行基准测试并保存..."; \
|
||
$(MAKE) bench-stat; \
|
||
cp benchmark-current.txt benchmark-baseline.txt; \
|
||
fi
|
||
|
||
# 检查性能回归(需要 Python)
|
||
bench-check:
|
||
@echo "Checking for performance regressions..."
|
||
@if [ -f benchmark-comparison.txt ]; then \
|
||
python scripts/check_regression.py benchmark-comparison.txt; \
|
||
elif command -v benchstat >/dev/null 2>&1 && [ -f benchmark-baseline.txt ] && [ -f benchmark-current.txt ]; then \
|
||
benchstat benchmark-baseline.txt benchmark-current.txt > benchmark-comparison.txt; \
|
||
python scripts/check_regression.py benchmark-comparison.txt; \
|
||
else \
|
||
echo "需要 benchstat 和基准线/当前结果文件"; \
|
||
echo "运行: make bench-save && make bench-stat && make bench-check"; \
|
||
exit 1; \
|
||
fi
|
||
|
||
# ============================================
|
||
# 代码质量
|
||
# ============================================
|
||
|
||
# 格式化代码
|
||
fmt:
|
||
@echo "Formatting code..."
|
||
go fmt ./...
|
||
|
||
# 静态检查
|
||
lint:
|
||
@echo "Running linter..."
|
||
@if command -v golangci-lint >/dev/null 2>&1; then \
|
||
golangci-lint run ./...; \
|
||
else \
|
||
echo "golangci-lint not installed. Run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
|
||
go vet ./...; \
|
||
fi
|
||
|
||
# 代码检查
|
||
check: fmt lint test
|
||
@echo "All checks passed."
|
||
|
||
# ============================================
|
||
# 依赖管理
|
||
# ============================================
|
||
|
||
# 下载依赖
|
||
deps:
|
||
@echo "Downloading dependencies..."
|
||
go mod download
|
||
go mod tidy
|
||
|
||
# 更新依赖
|
||
update-deps:
|
||
@echo "Updating dependencies..."
|
||
go get -u ./...
|
||
go mod tidy
|
||
|
||
# ============================================
|
||
# 安装命令
|
||
# ============================================
|
||
|
||
# 安装到系统
|
||
install:
|
||
@echo "Installing $(APP_NAME)..."
|
||
go install $(LDFLAGS) $(MAIN_PATH)
|
||
@echo "Installed to: $(shell go env GOPATH)/bin/$(APP_NAME)"
|
||
|
||
# ============================================
|
||
# 清理命令
|
||
# ============================================
|
||
|
||
# 清理构建产物
|
||
clean:
|
||
@echo "Cleaning build artifacts..."
|
||
rm -rf $(BUILD_DIR)
|
||
rm -f coverage.out coverage.html
|
||
@echo "Clean complete."
|
||
|
||
# ============================================
|
||
# 帮助
|
||
# ============================================
|
||
|
||
help:
|
||
@echo "$(APP_NAME) Makefile Commands"
|
||
@echo ""
|
||
@echo "Build:"
|
||
@echo " make build - Build for current platform"
|
||
@echo " make build-prod - Production build (size optimized)"
|
||
@echo " make build-perf - Production build (max runtime performance)"
|
||
@echo " make build-pgo - PGO build (needs profile, use PGO_PROFILE=path)"
|
||
@echo " make pgo-collect - Guide for collecting PGO profile"
|
||
@echo " make build-all - Build for all platforms"
|
||
@echo " make build-linux - Build for Linux amd64"
|
||
@echo " make build-darwin - Build for macOS (amd64 + arm64)"
|
||
@echo " make build-windows - Build for Windows amd64"
|
||
@echo ""
|
||
@echo "Development:"
|
||
@echo " make run - Run development server"
|
||
@echo " make test-config - Test configuration file"
|
||
@echo " make version - Show version info"
|
||
@echo ""
|
||
@echo "Testing:"
|
||
@echo " make test - Run all tests"
|
||
@echo " make test-cover - Run tests with coverage"
|
||
@echo " make bench - Run benchmarks"
|
||
@echo " make bench-stat - Run benchmarks with statistical sampling (10x)"
|
||
@echo " make bench-compare - Compare against baseline (needs benchstat)"
|
||
@echo " make bench-save - Save current results as baseline"
|
||
@echo " make bench-check - Check for performance regressions"
|
||
@echo ""
|
||
@echo "Quality:"
|
||
@echo " make fmt - Format code"
|
||
@echo " make lint - Run linter"
|
||
@echo " make check - Format + lint + test"
|
||
@echo ""
|
||
@echo "Dependencies:"
|
||
@echo " make deps - Download dependencies"
|
||
@echo " make update-deps - Update dependencies"
|
||
@echo ""
|
||
@echo "Other:"
|
||
@echo " make install - Install to GOPATH/bin"
|
||
@echo " make clean - Clean build artifacts"
|
||
@echo ""
|