diff options
| author | Paul Buetow <paul@buetow.org> | 2026-07-22 23:52:43 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-07-22 23:52:43 +0300 |
| commit | 17bf7e042496a4afcbf6ee7a583378adb3ec502d (patch) | |
| tree | 380d89c2ca5157a067244857aa4fd5ebf2387915 /benchmarks/dcat_benchmark_test.go | |
| parent | bc2767c87c4090798c4c7d15e101ed066e947301 (diff) | |
build: DTail fork — benchmarks, PGO tooling, Makefile, docker
Squashed development of the build/benchmark/profiling tooling:
- Turbo-vs-normal and per-tool benchmark harnesses under benchmarks/ (with dated
baseline and result artifacts preserved), plus MapReduce/SSH/network suites.
- Profile-Guided Optimization workflow (internal/tools/pgo lives with the code):
Makefile targets (make pgo / pgo-quick / build-pgo), profile generation with
non-zero-sample and representativeness guards.
- Makefile targets for build, test (unit + integration), lint, vet, benchmarking
and profiling; docker config updates.
- .gitignore hardened against pgo profiles and accidental integration-test
debug/output dumps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'benchmarks/dcat_benchmark_test.go')
| -rw-r--r-- | benchmarks/dcat_benchmark_test.go | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/benchmarks/dcat_benchmark_test.go b/benchmarks/dcat_benchmark_test.go new file mode 100644 index 0000000..189cd0b --- /dev/null +++ b/benchmarks/dcat_benchmark_test.go @@ -0,0 +1,320 @@ +package benchmarks + +import ( + "fmt" + "os" + "path/filepath" + "testing" + "time" +) + +// BenchmarkDCatSimple benchmarks simple file reading +func BenchmarkDCatSimple(b *testing.B) { + cleanup := SetupBenchmark(b) + defer cleanup() + + sizes := GetBenchmarkSizes() + + for _, size := range sizes { + b.Run(fmt.Sprintf("Size=%s", size), func(b *testing.B) { + // Generate test file + config := TestDataConfig{ + Size: size, + Format: SimpleLogFormat, + Compression: NoCompression, + LineVariation: 50, + } + + testFile := GenerateTestFile(b, config) + defer os.Remove(testFile) + + fileSize, _ := GetFileSize(testFile) + lineCount, _ := CountFileLines(testFile) + + // Warmup + WarmupCommand(b, "dcat", "--plain", "--cfg", "none", testFile) + + b.ResetTimer() + + // Run benchmark + totalDuration := time.Duration(0) + for i := 0; i < b.N; i++ { + result, err := RunBenchmarkCommand(b, "dcat", "--plain", "--cfg", "none", testFile) + if err != nil { + b.Fatalf("Command failed: %v", err) + } + totalDuration += result.Duration + } + + avgDuration := totalDuration / time.Duration(b.N) + throughput := CalculateThroughput(fileSize, avgDuration) + linesPerSec := CalculateLinesPerSecond(lineCount, avgDuration) + + // Report metrics + b.ReportMetric(throughput, "MB/sec") + b.ReportMetric(linesPerSec, "lines/sec") + + // Save result + benchResult := BenchmarkResult{ + Timestamp: time.Now(), + Tool: "dcat", + Operation: fmt.Sprintf("Simple_%s", size), + FileSize: fileSize, + Duration: avgDuration, + Throughput: throughput, + LinesPerSec: linesPerSec, + } + SaveResults([]BenchmarkResult{benchResult}) + }) + } +} + +// BenchmarkDCatMultipleFiles benchmarks reading multiple files +func BenchmarkDCatMultipleFiles(b *testing.B) { + cleanup := SetupBenchmark(b) + defer cleanup() + + numFiles := []int{10, 50, 100} + fileSize := Small / 10 // 1MB each + + for _, num := range numFiles { + b.Run(fmt.Sprintf("Files=%d", num), func(b *testing.B) { + // Generate test files + var testFiles []string + totalSize := int64(0) + totalLines := 0 + + for i := 0; i < num; i++ { + config := TestDataConfig{ + Size: FileSize(fileSize), + Format: SimpleLogFormat, + Compression: NoCompression, + LineVariation: 50, + } + + testFile := GenerateTestFile(b, config) + testFiles = append(testFiles, testFile) + defer os.Remove(testFile) + + size, _ := GetFileSize(testFile) + lines, _ := CountFileLines(testFile) + totalSize += size + totalLines += lines + } + + // Warmup + args := append([]string{"--plain", "--cfg", "none"}, testFiles...) + WarmupCommand(b, "dcat", args...) + + b.ResetTimer() + + // Run benchmark + totalDuration := time.Duration(0) + for i := 0; i < b.N; i++ { + result, err := RunBenchmarkCommand(b, "dcat", args...) + if err != nil { + b.Fatalf("Command failed: %v", err) + } + totalDuration += result.Duration + } + + avgDuration := totalDuration / time.Duration(b.N) + throughput := CalculateThroughput(totalSize, avgDuration) + linesPerSec := CalculateLinesPerSecond(totalLines, avgDuration) + + // Report metrics + b.ReportMetric(throughput, "MB/sec") + b.ReportMetric(linesPerSec, "lines/sec") + b.ReportMetric(float64(num), "files") + + // Save result + benchResult := BenchmarkResult{ + Timestamp: time.Now(), + Tool: "dcat", + Operation: fmt.Sprintf("MultiFile_%d", num), + FileSize: totalSize, + Duration: avgDuration, + Throughput: throughput, + LinesPerSec: linesPerSec, + } + SaveResults([]BenchmarkResult{benchResult}) + }) + } +} + +// BenchmarkDCatCompressed benchmarks reading compressed files +func BenchmarkDCatCompressed(b *testing.B) { + cleanup := SetupBenchmark(b) + defer cleanup() + + compressions := []struct { + name string + typ CompressionType + }{ + {"none", NoCompression}, + {"gzip", GzipCompression}, + {"zstd", ZstdCompression}, + } + + sizes := GetBenchmarkSizes() + if IsQuickMode() { + sizes = []FileSize{Small} + } + + for _, size := range sizes { + for _, comp := range compressions { + b.Run(fmt.Sprintf("Size=%s/Compression=%s", size, comp.name), func(b *testing.B) { + // Generate test file + config := TestDataConfig{ + Size: size, + Format: SimpleLogFormat, + Compression: comp.typ, + LineVariation: 50, + } + + testFile := GenerateTestFile(b, config) + defer os.Remove(testFile) + + // Get uncompressed size for throughput calculation + uncompressedSize := int64(size) + compressedSize, _ := GetFileSize(testFile) + compressionRatio := float64(uncompressedSize) / float64(compressedSize) + + // Estimate line count (compressed files are harder to count) + approxLineCount := int(size) / 150 + + // Warmup + WarmupCommand(b, "dcat", "--plain", "--cfg", "none", testFile) + + b.ResetTimer() + + // Run benchmark + totalDuration := time.Duration(0) + for i := 0; i < b.N; i++ { + result, err := RunBenchmarkCommand(b, "dcat", "--plain", "--cfg", "none", testFile) + if err != nil { + b.Fatalf("Command failed: %v", err) + } + totalDuration += result.Duration + } + + avgDuration := totalDuration / time.Duration(b.N) + // Throughput based on uncompressed size + throughput := CalculateThroughput(uncompressedSize, avgDuration) + linesPerSec := CalculateLinesPerSecond(approxLineCount, avgDuration) + + // Report metrics + b.ReportMetric(throughput, "MB/sec") + b.ReportMetric(linesPerSec, "lines/sec") + b.ReportMetric(compressionRatio, "compression_ratio") + + // Save result + benchResult := BenchmarkResult{ + Timestamp: time.Now(), + Tool: "dcat", + Operation: fmt.Sprintf("Compressed_%s_%s", comp.name, size), + FileSize: uncompressedSize, + Duration: avgDuration, + Throughput: throughput, + LinesPerSec: linesPerSec, + } + SaveResults([]BenchmarkResult{benchResult}) + }) + } + } +} + +// BenchmarkDCatServerMode benchmarks server mode vs serverless +func BenchmarkDCatServerMode(b *testing.B) { + cleanup := SetupBenchmark(b) + defer cleanup() + + // Skip if dserver binary doesn't exist + dserverPath := filepath.Join("..", "dserver") + if _, err := os.Stat(dserverPath); err != nil { + b.Skip("dserver binary not found, skipping server mode benchmarks") + } + + modes := []struct { + name string + server bool + }{ + {"serverless", false}, + {"server", true}, + } + + sizes := GetBenchmarkSizes() + if IsQuickMode() { + sizes = []FileSize{Small} + } + + for _, size := range sizes { + for _, mode := range modes { + b.Run(fmt.Sprintf("Size=%s/Mode=%s", size, mode.name), func(b *testing.B) { + // Generate test file + config := TestDataConfig{ + Size: size, + Format: SimpleLogFormat, + Compression: NoCompression, + LineVariation: 50, + } + + testFile := GenerateTestFile(b, config) + defer os.Remove(testFile) + + fileSize, _ := GetFileSize(testFile) + lineCount, _ := CountFileLines(testFile) + + var args []string + + if mode.server { + // Start dserver + // Note: In a real implementation, we'd need to: + // 1. Start dserver in background + // 2. Wait for it to be ready + // 3. Run dcat with --servers flag + // 4. Stop dserver after benchmark + // For now, we'll skip the actual server mode implementation + b.Skip("Server mode benchmarking requires additional setup") + } else { + args = []string{"--plain", "--cfg", "none", testFile} + } + + // Warmup + WarmupCommand(b, "dcat", args...) + + b.ResetTimer() + + // Run benchmark + totalDuration := time.Duration(0) + for i := 0; i < b.N; i++ { + result, err := RunBenchmarkCommand(b, "dcat", args...) + if err != nil { + b.Fatalf("Command failed: %v", err) + } + totalDuration += result.Duration + } + + avgDuration := totalDuration / time.Duration(b.N) + throughput := CalculateThroughput(fileSize, avgDuration) + linesPerSec := CalculateLinesPerSecond(lineCount, avgDuration) + + // Report metrics + b.ReportMetric(throughput, "MB/sec") + b.ReportMetric(linesPerSec, "lines/sec") + + // Save result + benchResult := BenchmarkResult{ + Timestamp: time.Now(), + Tool: "dcat", + Operation: fmt.Sprintf("%s_%s", mode.name, size), + FileSize: fileSize, + Duration: avgDuration, + Throughput: throughput, + LinesPerSec: linesPerSec, + } + SaveResults([]BenchmarkResult{benchResult}) + }) + } + } +} |
