Files
v-hono/tests/benchmark_compare.go
meiseayoung 05bb2d6c95 feat: cross-platform uSockets support and route cache optimization
1. Cross-platform uSockets configuration
   - Use @VMODROOT for portable library paths
   - Support macOS (arm64/x86_64), Windows, and Linux
   - Auto-detect Homebrew paths for libuv on macOS

2. Route cache optimization (3x performance boost)
   - Replace LRU cache with FastRouteCache for dynamic routes
   - Zero-overhead cache lookup (no TTL check, no LRU reordering)
   - Dynamic route performance: 30k -> 97k RPS

3. New test files
   - Go-based integration tests for picoev and uSockets
   - FastCache optimization validation tests
   - Benchmark comparison tools
2026-01-02 21:44:07 +08:00

252 lines
6.2 KiB
Go

// 高并发基准测试 - 用于对比 v-hono 内外性能
// 参数与外层 benchmark.go 保持一致: 500 并发, 100万请求
//
// 使用方法:
// 1. 启动服务器: v -enable-globals run v-hono/tests/test_picoev_server.v
// 2. 运行测试: go run v-hono/tests/benchmark_compare.go
package main
import (
"fmt"
"io"
"net/http"
"strings"
"sync"
"sync/atomic"
"time"
)
const (
baseURL = "http://127.0.0.1:9999"
connections = 500
requests = 1000000
timeout = 10 * time.Second
)
type Metrics struct {
TotalRequests int64
SuccessRequests int64
FailedRequests int64
TotalBytes int64
MinLatency time.Duration
MaxLatency time.Duration
TotalLatencyNs int64
StartTime time.Time
EndTime time.Time
}
func main() {
fmt.Println("🔥 V-Hono 高并发基准测试")
fmt.Println(strings.Repeat("=", 50))
fmt.Printf("服务器: %s\n", baseURL)
fmt.Printf("并发数: %d\n", connections)
fmt.Printf("请求数: %d\n", requests)
fmt.Printf("超时: %v\n", timeout)
fmt.Println()
// 检查服务器
if !checkServer() {
fmt.Println("❌ 服务器未运行")
fmt.Println(" 请先启动: v -enable-globals run v-hono/tests/test_picoev_server.v")
return
}
fmt.Println("✅ 服务器已就绪")
// 预热
fmt.Println("\n🔥 预热服务器...")
warmup()
fmt.Println("✅ 预热完成")
// 运行测试
testCases := []struct {
name string
path string
}{
{"健康检查", "/health"},
{"根路径", "/"},
{"JSON接口", "/json"},
{"动态路由", "/users/123"},
}
allResults := make(map[string]*Metrics)
for _, tc := range testCases {
fmt.Printf("\n🚀 测试: %s (%s)\n", tc.name, tc.path)
fmt.Println(strings.Repeat("-", 50))
metrics := runBenchmark(tc.path)
allResults[tc.name] = metrics
printMetrics(tc.name, metrics)
time.Sleep(2 * time.Second)
}
// 汇总
printSummary(allResults)
}
func checkServer() bool {
client := &http.Client{Timeout: 2 * time.Second}
for i := 0; i < 3; i++ {
resp, err := client.Get(baseURL + "/health")
if err == nil && resp.StatusCode == 200 {
resp.Body.Close()
return true
}
time.Sleep(500 * time.Millisecond)
}
return false
}
func warmup() {
client := &http.Client{Timeout: 5 * time.Second}
for i := 0; i < 100; i++ {
resp, err := client.Get(baseURL + "/health")
if err == nil {
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}
}
}
func runBenchmark(endpoint string) *Metrics {
url := baseURL + endpoint
metrics := &Metrics{
StartTime: time.Now(),
MinLatency: time.Hour,
}
client := &http.Client{
Timeout: timeout,
Transport: &http.Transport{
MaxIdleConns: connections,
MaxIdleConnsPerHost: connections,
IdleConnTimeout: 30 * time.Second,
},
}
requestsPerWorker := requests / connections
var wg sync.WaitGroup
var latencyMutex sync.Mutex
// 进度显示
done := make(chan bool)
go showProgress(metrics, done)
// 启动工作协程
for i := 0; i < connections; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < requestsPerWorker; j++ {
start := time.Now()
resp, err := client.Get(url)
latency := time.Since(start)
atomic.AddInt64(&metrics.TotalRequests, 1)
atomic.AddInt64(&metrics.TotalLatencyNs, int64(latency))
latencyMutex.Lock()
if latency < metrics.MinLatency {
metrics.MinLatency = latency
}
if latency > metrics.MaxLatency {
metrics.MaxLatency = latency
}
latencyMutex.Unlock()
if err != nil {
atomic.AddInt64(&metrics.FailedRequests, 1)
continue
}
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil || resp.StatusCode >= 400 {
atomic.AddInt64(&metrics.FailedRequests, 1)
} else {
atomic.AddInt64(&metrics.SuccessRequests, 1)
atomic.AddInt64(&metrics.TotalBytes, int64(len(body)))
}
}
}()
}
wg.Wait()
metrics.EndTime = time.Now()
done <- true
return metrics
}
func showProgress(metrics *Metrics, done chan bool) {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-done:
fmt.Println()
return
case <-ticker.C:
current := atomic.LoadInt64(&metrics.TotalRequests)
elapsed := time.Since(metrics.StartTime).Seconds()
rps := float64(current) / elapsed
progress := float64(current) / float64(requests) * 100
fmt.Printf("\r进度: %.1f%% | 完成: %d | RPS: %.0f | 耗时: %.1fs",
progress, current, rps, elapsed)
}
}
}
func printMetrics(name string, m *Metrics) {
duration := m.EndTime.Sub(m.StartTime)
avgLatency := time.Duration(m.TotalLatencyNs / m.TotalRequests)
fmt.Printf("\n📊 %s - 测试结果\n", name)
fmt.Println(strings.Repeat("=", 40))
fmt.Printf("总请求数: %d\n", m.TotalRequests)
fmt.Printf("成功请求: %d\n", m.SuccessRequests)
fmt.Printf("失败请求: %d\n", m.FailedRequests)
fmt.Printf("成功率: %.2f%%\n", float64(m.SuccessRequests)/float64(m.TotalRequests)*100)
fmt.Printf("总耗时: %.2f 秒\n", duration.Seconds())
fmt.Printf("RPS: %.0f 请求/秒\n", float64(m.TotalRequests)/duration.Seconds())
fmt.Printf("最小延迟: %v\n", m.MinLatency)
fmt.Printf("最大延迟: %v\n", m.MaxLatency)
fmt.Printf("平均延迟: %v\n", avgLatency)
if m.TotalBytes > 0 {
throughputMB := float64(m.TotalBytes) / 1024 / 1024 / duration.Seconds()
fmt.Printf("数据传输: %.2f MB\n", float64(m.TotalBytes)/1024/1024)
fmt.Printf("吞吐量: %.2f MB/s\n", throughputMB)
}
}
func printSummary(results map[string]*Metrics) {
fmt.Printf("\n🏆 性能汇总报告\n")
fmt.Println(strings.Repeat("=", 60))
fmt.Printf("%-15s %-12s %-10s %-12s %-10s\n", "接口", "RPS", "成功率", "平均延迟", "吞吐量")
fmt.Println(strings.Repeat("-", 60))
for name, metrics := range results {
duration := metrics.EndTime.Sub(metrics.StartTime)
rps := float64(metrics.TotalRequests) / duration.Seconds()
successRate := float64(metrics.SuccessRequests) / float64(metrics.TotalRequests) * 100
avgLatency := time.Duration(metrics.TotalLatencyNs / metrics.TotalRequests)
throughput := float64(metrics.TotalBytes) / 1024 / 1024 / duration.Seconds()
fmt.Printf("%-15s %-12.0f %-9.1f%% %-12v %-8.1fMB/s\n",
name, rps, successRate, avgLatency, throughput)
}
fmt.Println("\n✅ 测试完成!")
}