quick_worker_benchmark_test.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package nginx_log
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "runtime"
  8. "testing"
  9. "time"
  10. "github.com/0xJacky/Nginx-UI/internal/nginx_log/indexer"
  11. "github.com/0xJacky/Nginx-UI/internal/nginx_log/parser"
  12. )
  13. // BenchmarkQuickWorkerComparison does a quick comparison of worker configurations
  14. func BenchmarkQuickWorkerComparison(b *testing.B) {
  15. recordCount := 5000 // Smaller dataset for quick testing
  16. // Test configurations
  17. testConfigs := []struct {
  18. name string
  19. workerMultiplier int
  20. }{
  21. {"1x_CPU", 1},
  22. {"2x_CPU_Old", 2},
  23. {"3x_CPU_New", 3},
  24. {"4x_CPU_HighThroughput", 4},
  25. {"6x_CPU_Max", 6},
  26. }
  27. // Generate test data once
  28. tempDir := b.TempDir()
  29. testLogFile := filepath.Join(tempDir, "access.log")
  30. if err := generateQuickTestData(testLogFile, recordCount); err != nil {
  31. b.Fatalf("Failed to generate test data: %v", err)
  32. }
  33. for _, tc := range testConfigs {
  34. b.Run(tc.name, func(b *testing.B) {
  35. workerCount := runtime.GOMAXPROCS(0) * tc.workerMultiplier
  36. b.ResetTimer()
  37. for i := 0; i < b.N; i++ {
  38. indexDir := filepath.Join(tempDir, fmt.Sprintf("index_%s_%d", tc.name, i))
  39. // Create config with specific worker count
  40. config := indexer.DefaultIndexerConfig()
  41. config.IndexPath = indexDir
  42. config.WorkerCount = workerCount
  43. config.EnableMetrics = false
  44. // Run test
  45. start := time.Now()
  46. result := runQuickWorkerTest(b, config, testLogFile)
  47. duration := time.Since(start)
  48. // Report metrics
  49. throughput := float64(result.Processed) / duration.Seconds()
  50. b.ReportMetric(throughput, "records/sec")
  51. b.ReportMetric(float64(workerCount), "workers")
  52. b.ReportMetric(float64(result.Processed), "processed")
  53. if i == 0 {
  54. b.Logf("Workers=%d, Processed=%d, Duration=%v, Throughput=%.0f rec/s",
  55. workerCount, result.Processed, duration, throughput)
  56. }
  57. }
  58. })
  59. }
  60. }
  61. type QuickTestResult struct {
  62. Processed int
  63. Duration time.Duration
  64. }
  65. func runQuickWorkerTest(b *testing.B, config *indexer.Config, logFile string) *QuickTestResult {
  66. ctx := context.Background()
  67. // Simple parser setup
  68. parserConfig := &parser.Config{
  69. MaxLineLength: 4 * 1024,
  70. WorkerCount: config.WorkerCount / 3, // Parser uses 1/3 of indexer workers
  71. BatchSize: 500,
  72. }
  73. optimizedParser := parser.NewOptimizedParser(
  74. parserConfig,
  75. nil, // No UA parser for speed
  76. nil, // No Geo service for speed
  77. )
  78. // Parse only
  79. file, err := os.Open(logFile)
  80. if err != nil {
  81. b.Fatalf("Failed to open log file: %v", err)
  82. }
  83. defer file.Close()
  84. parseResult, err := optimizedParser.OptimizedParseStream(ctx, file)
  85. if err != nil {
  86. b.Fatalf("Parsing failed: %v", err)
  87. }
  88. return &QuickTestResult{
  89. Processed: parseResult.Processed,
  90. Duration: parseResult.Duration,
  91. }
  92. }
  93. func generateQuickTestData(filename string, recordCount int) error {
  94. file, err := os.Create(filename)
  95. if err != nil {
  96. return err
  97. }
  98. defer file.Close()
  99. baseTime := time.Now().Unix()
  100. for i := 0; i < recordCount; i++ {
  101. logLine := fmt.Sprintf(
  102. `192.168.1.%d - - [%s] "GET /api/test%d HTTP/1.1" 200 %d "-" "Test/1.0" 0.001`,
  103. i%256,
  104. time.Unix(baseTime+int64(i), 0).Format("02/Jan/2006:15:04:05 -0700"),
  105. i%100,
  106. 1000+i%1000,
  107. )
  108. fmt.Fprintln(file, logLine)
  109. }
  110. return nil
  111. }