From b501664ec88b92ddd24e1c62dd7a89439cdb5339 Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Tue, 2 Sep 2025 14:12:40 -0700 Subject: [PATCH 1/2] PerfTests: go --- .../benchmarks/go/README.md | 44 ++ .../go/benchmark/benchmark_tests.go | 453 ++++++++++++++++++ .../benchmarks/go/benchmark/config.go | 59 +++ .../benchmarks/go/benchmark/esdk_benchmark.go | 116 +++++ .../benchmarks/go/benchmark/results.go | 117 +++++ esdk-performance-testing/benchmarks/go/go.mod | 48 ++ esdk-performance-testing/benchmarks/go/go.sum | 103 ++++ .../benchmarks/go/main.go | 66 +++ 8 files changed, 1006 insertions(+) create mode 100644 esdk-performance-testing/benchmarks/go/README.md create mode 100644 esdk-performance-testing/benchmarks/go/benchmark/benchmark_tests.go create mode 100644 esdk-performance-testing/benchmarks/go/benchmark/config.go create mode 100644 esdk-performance-testing/benchmarks/go/benchmark/esdk_benchmark.go create mode 100644 esdk-performance-testing/benchmarks/go/benchmark/results.go create mode 100644 esdk-performance-testing/benchmarks/go/go.mod create mode 100644 esdk-performance-testing/benchmarks/go/go.sum create mode 100644 esdk-performance-testing/benchmarks/go/main.go diff --git a/esdk-performance-testing/benchmarks/go/README.md b/esdk-performance-testing/benchmarks/go/README.md new file mode 100644 index 000000000..379204159 --- /dev/null +++ b/esdk-performance-testing/benchmarks/go/README.md @@ -0,0 +1,44 @@ +# ESDK Go Benchmark + +Performance benchmark suite for the AWS Encryption SDK (ESDK) Go implementation. + +## Quick Start + +```bash +# Run quick benchmark +go run . --config ../../config/test-scenarios.yaml --quick + +# Run full benchmark +go run . --config ../../config/test-scenarios.yaml +``` + +## Build + +```bash +# Build release binary +go build -o esdk-benchmark . + +# Run built binary +./esdk-benchmark --quick +``` + +## Configuration + +The benchmark uses YAML configuration files. See `../../config/test-scenarios.yaml` for the full configuration format. + +### Quick Mode + +Quick mode runs a subset of tests with reduced iterations: +- Only runs test types specified in `quick_config.test_types` +- Uses smaller data sizes from `quick_config.data_sizes.small` +- Fewer iterations: `quick_config.iterations.measurement` + +## Test Types + +- **throughput**: Measures operations per second and latency +- **memory**: Measures peak memory usage during operations +- **concurrency**: Tests performance under concurrent load + +## Output + +Results are saved to JSON format in `../../results/raw-data/go_results.json` by default. \ No newline at end of file diff --git a/esdk-performance-testing/benchmarks/go/benchmark/benchmark_tests.go b/esdk-performance-testing/benchmarks/go/benchmark/benchmark_tests.go new file mode 100644 index 000000000..59a2889b0 --- /dev/null +++ b/esdk-performance-testing/benchmarks/go/benchmark/benchmark_tests.go @@ -0,0 +1,453 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package benchmark + +import ( + "bytes" + "context" + "fmt" + "log" + "runtime" + "runtime/metrics" + "sort" + "sync" + "time" + + esdktypes "github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk/awscryptographyencryptionsdksmithygeneratedtypes" + "github.com/schollz/progressbar/v3" +) + +// === Helper Functions === + +// runEncryptDecryptCycle performs a single encrypt-decrypt cycle and measures performance +func (b *ESDKBenchmark) runEncryptDecryptCycle(data []byte) (float64, float64, error) { + ctx := context.Background() + + encryptionContext := map[string]string{ + "purpose": "performance-test", + "size": fmt.Sprintf("%d", len(data)), + } + + encryptInput := esdktypes.EncryptInput{ + Plaintext: data, + Keyring: b.Keyring, + EncryptionContext: encryptionContext, + } + + // Encrypt + encryptStart := time.Now() + encryptOutput, err := b.EsdkClient.Encrypt(ctx, encryptInput) + if err != nil { + return 0, 0, fmt.Errorf("encryption failed: %w", err) + } + encryptDuration := time.Since(encryptStart).Seconds() * 1000 + + // Decrypt + decryptInput := esdktypes.DecryptInput{ + Ciphertext: encryptOutput.Ciphertext, + Keyring: b.Keyring, + } + + decryptStart := time.Now() + decryptOutput, err := b.EsdkClient.Decrypt(ctx, decryptInput) + if err != nil { + return 0, 0, fmt.Errorf("decryption failed: %w", err) + } + decryptDuration := time.Since(decryptStart).Seconds() * 1000 + + // Verify integrity + if !bytes.Equal(data, decryptOutput.Plaintext) { + return 0, 0, fmt.Errorf("data integrity check failed") + } + + return encryptDuration, decryptDuration, nil +} + +// shouldRunTestType checks if a test type should be run based on quick config +func (b *ESDKBenchmark) shouldRunTestType(testType string) bool { + if b.Config.QuickConfig == nil || len(b.Config.QuickConfig.TestTypes) == 0 { + return true + } + + for _, allowedType := range b.Config.QuickConfig.TestTypes { + if allowedType == testType { + return true + } + } + return false +} + +// === Throughput Test Implementation === + +// runThroughputTest runs throughput benchmark test +func (b *ESDKBenchmark) runThroughputTest(dataSize int, iterations int) (*BenchmarkResult, error) { + log.Printf("Running throughput test - Size: %d bytes, Iterations: %d", dataSize, iterations) + + testData := b.GenerateTestData(dataSize) + + // Warmup + for i := 0; i < b.Config.Iterations.Warmup; i++ { + if _, _, err := b.runEncryptDecryptCycle(testData); err != nil { + return nil, fmt.Errorf("warmup iteration %d failed: %w", i, err) + } + } + + // Measurement runs + var encryptLatencies, decryptLatencies, endToEndLatencies []float64 + var totalBytes int64 + + bar := progressbar.NewOptions(iterations, + progressbar.OptionSetDescription("Throughput test"), + progressbar.OptionShowCount(), + progressbar.OptionSetWidth(50), + ) + + startTime := time.Now() + for i := 0; i < iterations; i++ { + iterationStart := time.Now() + encryptMs, decryptMs, err := b.runEncryptDecryptCycle(testData) + if err != nil { + return nil, fmt.Errorf("measurement iteration %d failed: %w", i, err) + } + iterationDuration := time.Since(iterationStart).Seconds() * 1000 + + encryptLatencies = append(encryptLatencies, encryptMs) + decryptLatencies = append(decryptLatencies, decryptMs) + endToEndLatencies = append(endToEndLatencies, iterationDuration) + totalBytes += int64(dataSize) + + bar.Add(1) + } + totalDuration := time.Since(startTime).Seconds() + + // Calculate metrics + sort.Float64s(endToEndLatencies) + result := &BenchmarkResult{ + TestName: "throughput", + Language: "go", + DataSize: dataSize, + Concurrency: 1, + EncryptLatencyMs: Average(encryptLatencies), + DecryptLatencyMs: Average(decryptLatencies), + EndToEndLatencyMs: Average(endToEndLatencies), + OpsPerSecond: float64(iterations) / totalDuration, + BytesPerSecond: float64(totalBytes) / totalDuration, + P50Latency: Percentile(endToEndLatencies, 0.50), + P95Latency: Percentile(endToEndLatencies, 0.95), + P99Latency: Percentile(endToEndLatencies, 0.99), + Timestamp: time.Now().Format("2006-01-02 15:04:05"), + GoVersion: runtime.Version(), + CPUCount: b.CPUCount, + TotalMemoryGB: b.TotalMemoryGB, + } + + log.Printf("Throughput test completed - Ops/sec: %.2f, MB/sec: %.2f", + result.OpsPerSecond, result.BytesPerSecond/(1024*1024)) + + return result, nil +} + +// === Memory Test Implementation === + +// sampleMemoryContinuously runs continuous memory sampling during operation +func (b *ESDKBenchmark) sampleMemoryContinuously(beforeHeap, beforeAllocs uint64, stopChan chan bool) []MemorySample { + var samples []MemorySample + ticker := time.NewTicker(SamplingIntervalMs * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-stopChan: + return samples + case <-ticker.C: + var currentSamples [2]metrics.Sample + currentSamples[0].Name = "/memory/classes/heap/objects:bytes" + currentSamples[1].Name = "/gc/heap/allocs:bytes" + metrics.Read(currentSamples[:]) + + var heapDelta, allocsDelta uint64 + if currentSamples[0].Value.Uint64() > beforeHeap { + heapDelta = currentSamples[0].Value.Uint64() - beforeHeap + } + if currentSamples[1].Value.Uint64() > beforeAllocs { + allocsDelta = currentSamples[1].Value.Uint64() - beforeAllocs + } + + sample := MemorySample{ + Timestamp: time.Now(), + HeapMB: float64(heapDelta) / (1024 * 1024), + MetricsAllocsMB: float64(allocsDelta) / (1024 * 1024), + MemStatsAllocsMB: 0, + } + samples = append(samples, sample) + } + } +} + +// runMemoryTest runs memory benchmark with continuous sampling +func (b *ESDKBenchmark) runMemoryTest(dataSize int) (*BenchmarkResult, error) { + log.Printf("Running memory test - Size: %d bytes (%d iterations, continuous sampling)", dataSize, MemoryTestIterations) + + data := b.GenerateTestData(dataSize) + + // Setup runtime/metrics tracking + samples := make([]metrics.Sample, 2) + samples[0].Name = "/memory/classes/heap/objects:bytes" + samples[1].Name = "/gc/heap/allocs:bytes" + + var peakHeap, peakAllocations float64 + var avgHeapValues []float64 + + // Run iterations + for i := 0; i < MemoryTestIterations; i++ { + runtime.GC() + time.Sleep(GCSettleTimeMs * time.Millisecond) + + // Get baseline + metrics.Read(samples) + beforeHeap := samples[0].Value.Uint64() + beforeAllocs := samples[1].Value.Uint64() + + // Start continuous sampling + stopSampling := make(chan bool) + var continuousSamples []MemorySample + var samplingMutex sync.Mutex + + go func() { + sampledData := b.sampleMemoryContinuously(beforeHeap, beforeAllocs, stopSampling) + samplingMutex.Lock() + continuousSamples = sampledData + samplingMutex.Unlock() + }() + + // Run operation + operationStart := time.Now() + _, _, err := b.runEncryptDecryptCycle(data) + operationDuration := time.Since(operationStart) + + close(stopSampling) + time.Sleep(FinalSampleWaitMs * time.Millisecond) + + if err != nil { + log.Printf("Iteration %d failed: %v", i+1, err) + continue + } + + // Analyze samples + samplingMutex.Lock() + var iterPeakHeap, iterTotalAllocs, iterAvgHeap float64 + if len(continuousSamples) > 0 { + var heapSum float64 + for _, s := range continuousSamples { + if s.HeapMB > iterPeakHeap { + iterPeakHeap = s.HeapMB + } + if s.MetricsAllocsMB > iterTotalAllocs { + iterTotalAllocs = s.MetricsAllocsMB + } + heapSum += s.HeapMB + } + iterAvgHeap = heapSum / float64(len(continuousSamples)) + } + samplingMutex.Unlock() + + // Update global metrics + if iterPeakHeap > peakHeap { + peakHeap = iterPeakHeap + } + if iterTotalAllocs > peakAllocations { + peakAllocations = iterTotalAllocs + } + avgHeapValues = append(avgHeapValues, iterAvgHeap) + + log.Printf("=== Iteration %d === Peak Heap: %.2f MB, Total Allocs: %.2f MB, Avg Heap: %.2f MB (%v, %d samples)", + i+1, iterPeakHeap, iterTotalAllocs, iterAvgHeap, operationDuration, len(continuousSamples)) + } + + if len(avgHeapValues) == 0 { + return nil, fmt.Errorf("all memory test iterations failed") + } + + overallAvgHeap := Average(avgHeapValues) + memoryEfficiency := float64(dataSize) / (overallAvgHeap * 1024 * 1024) + if overallAvgHeap == 0 { + memoryEfficiency = 0 + } + + log.Printf("\nMemory Summary:") + log.Printf("- Absolute Peak Heap: %.2f MB (across all runs)", peakHeap) + log.Printf("- Average Heap: %.2f MB (across all runs)", overallAvgHeap) + log.Printf("- Total Allocations: %.2f MB (max across all runs)", peakAllocations) + + result := &BenchmarkResult{ + TestName: "memory", + Language: "go", + DataSize: dataSize, + Concurrency: 1, + PeakMemoryMB: peakHeap, + MemoryEfficiency: memoryEfficiency, + Timestamp: time.Now().Format("2006-01-02 15:04:05"), + GoVersion: runtime.Version(), + CPUCount: b.CPUCount, + TotalMemoryGB: b.TotalMemoryGB, + } + + return result, nil +} + +// === Concurrent Test Implementation === + +// runConcurrentTest runs concurrent operations benchmark test +func (b *ESDKBenchmark) runConcurrentTest(dataSize int, concurrency int, iterationsPerWorker int) (*BenchmarkResult, error) { + log.Printf("Running concurrent test - Size: %d bytes, Concurrency: %d", dataSize, concurrency) + + data := b.GenerateTestData(dataSize) + var allTimes []float64 + var timesMutex sync.Mutex + var wg sync.WaitGroup + + errorChan := make(chan error, concurrency) + startTime := time.Now() + + // Launch workers + for i := 0; i < concurrency; i++ { + wg.Add(1) + go func(workerID int) { + defer wg.Done() + + var workerTimes []float64 + for j := 0; j < iterationsPerWorker; j++ { + iterStart := time.Now() + _, _, err := b.runEncryptDecryptCycle(data) + if err != nil { + errorChan <- fmt.Errorf("worker %d iteration %d failed: %w", workerID, j, err) + return + } + workerTimes = append(workerTimes, time.Since(iterStart).Seconds()*1000) + } + + timesMutex.Lock() + allTimes = append(allTimes, workerTimes...) + timesMutex.Unlock() + }(i) + } + + wg.Wait() + totalDuration := time.Since(startTime).Seconds() + + // Check for errors + select { + case err := <-errorChan: + return nil, err + default: + } + + // Calculate metrics + totalOps := concurrency * iterationsPerWorker + totalBytes := int64(totalOps * dataSize) + + sort.Float64s(allTimes) + result := &BenchmarkResult{ + TestName: "concurrent", + Language: "go", + DataSize: dataSize, + Concurrency: concurrency, + EndToEndLatencyMs: Average(allTimes), + OpsPerSecond: float64(totalOps) / totalDuration, + BytesPerSecond: float64(totalBytes) / totalDuration, + P50Latency: Percentile(allTimes, 0.50), + P95Latency: Percentile(allTimes, 0.95), + P99Latency: Percentile(allTimes, 0.99), + Timestamp: time.Now().Format("2006-01-02 15:04:05"), + GoVersion: runtime.Version(), + CPUCount: b.CPUCount, + TotalMemoryGB: b.TotalMemoryGB, + } + + log.Printf("Concurrent test completed - Ops/sec: %.2f, Avg latency: %.2f ms", + result.OpsPerSecond, result.EndToEndLatencyMs) + + return result, nil +} + +// === Test Orchestration === + +// runThroughputTests executes all throughput tests +func (b *ESDKBenchmark) runThroughputTests(dataSizes []int, iterations int) { + log.Println("Running throughput tests...") + for _, dataSize := range dataSizes { + result, err := b.runThroughputTest(dataSize, iterations) + if err != nil { + log.Printf("Throughput test failed: %v", err) + continue + } + b.Results = append(b.Results, *result) + log.Printf("Throughput test completed: %.2f ops/sec", result.OpsPerSecond) + } +} + +// runMemoryTests executes all memory tests +func (b *ESDKBenchmark) runMemoryTests(dataSizes []int) { + log.Println("Running memory tests...") + for _, dataSize := range dataSizes { + result, err := b.runMemoryTest(dataSize) + if err != nil { + log.Printf("Memory test failed: %v", err) + continue + } + b.Results = append(b.Results, *result) + log.Printf("Memory test completed: %.2f MB peak", result.PeakMemoryMB) + } +} + +// runConcurrencyTests executes all concurrency tests +func (b *ESDKBenchmark) runConcurrencyTests(dataSizes []int, concurrencyLevels []int) { + log.Println("Running concurrency tests...") + for _, dataSize := range dataSizes { + for _, concurrency := range concurrencyLevels { + if concurrency > 1 { // Skip single-threaded + result, err := b.runConcurrentTest(dataSize, concurrency, 5) + if err != nil { + log.Printf("Concurrent test failed: %v", err) + continue + } + b.Results = append(b.Results, *result) + log.Printf("Concurrent test completed: %.2f ops/sec @ %d threads", result.OpsPerSecond, concurrency) + } + } + } +} + +// RunAllBenchmarks runs all configured benchmark tests +func (b *ESDKBenchmark) RunAllBenchmarks() error { + log.Println("Starting comprehensive ESDK benchmark suite") + + // Combine all data sizes + var dataSizes []int + for _, sizes := range [][]int{b.Config.DataSizes.Small, b.Config.DataSizes.Medium, b.Config.DataSizes.Large} { + dataSizes = append(dataSizes, sizes...) + } + + // Run test suites + if b.shouldRunTestType("throughput") { + b.runThroughputTests(dataSizes, b.Config.Iterations.Measurement) + } else { + log.Println("Skipping throughput tests (not in test_types)") + } + + if b.shouldRunTestType("memory") { + b.runMemoryTests(dataSizes) + } else { + log.Println("Skipping memory tests (not in test_types)") + } + + if b.shouldRunTestType("concurrency") { + b.runConcurrencyTests(dataSizes, b.Config.ConcurrencyLevels) + } else { + log.Println("Skipping concurrency tests (not in test_types)") + } + + log.Printf("Benchmark suite completed. Total results: %d", len(b.Results)) + return nil +} diff --git a/esdk-performance-testing/benchmarks/go/benchmark/config.go b/esdk-performance-testing/benchmarks/go/benchmark/config.go new file mode 100644 index 000000000..9d216f7ab --- /dev/null +++ b/esdk-performance-testing/benchmarks/go/benchmark/config.go @@ -0,0 +1,59 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package benchmark + +import ( + "fmt" + "os" + + "gopkg.in/yaml.v3" +) + +// TestConfig represents the configuration for benchmark tests +type TestConfig struct { + DataSizes struct { + Small []int `yaml:"small"` + Medium []int `yaml:"medium"` + Large []int `yaml:"large"` + } `yaml:"data_sizes"` + Iterations struct { + Warmup int `yaml:"warmup"` + Measurement int `yaml:"measurement"` + } `yaml:"iterations"` + ConcurrencyLevels []int `yaml:"concurrency_levels"` + QuickConfig *QuickConfig `yaml:"quick_config"` +} + +// QuickConfig represents the quick test configuration +type QuickConfig struct { + DataSizes struct { + Small []int `yaml:"small"` + } `yaml:"data_sizes"` + Iterations struct { + Warmup int `yaml:"warmup"` + Measurement int `yaml:"measurement"` + } `yaml:"iterations"` + ConcurrencyLevels []int `yaml:"concurrency_levels"` + TestTypes []string `yaml:"test_types"` +} + +// LoadConfig loads the test configuration from YAML file +func LoadConfig(configPath string) (TestConfig, error) { + var config TestConfig + + if _, err := os.Stat(configPath); os.IsNotExist(err) { + return config, fmt.Errorf("config file not found: %s", configPath) + } + + data, err := os.ReadFile(configPath) + if err != nil { + return config, fmt.Errorf("failed to read config file: %w", err) + } + + if err := yaml.Unmarshal(data, &config); err != nil { + return config, fmt.Errorf("failed to parse config file: %w", err) + } + + return config, nil +} diff --git a/esdk-performance-testing/benchmarks/go/benchmark/esdk_benchmark.go b/esdk-performance-testing/benchmarks/go/benchmark/esdk_benchmark.go new file mode 100644 index 000000000..800c6869f --- /dev/null +++ b/esdk-performance-testing/benchmarks/go/benchmark/esdk_benchmark.go @@ -0,0 +1,116 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package benchmark + +import ( + "context" + "crypto/rand" + "fmt" + "log" + "runtime" + + mplsmithygenerated "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygenerated" + mpltypes "github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl/awscryptographymaterialproviderssmithygeneratedtypes" + esdksmithygenerated "github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk/awscryptographyencryptionsdksmithygenerated" + esdktypes "github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk/awscryptographyencryptionsdksmithygeneratedtypes" + "github.com/shirou/gopsutil/v3/mem" +) + +// Constants for memory testing +const ( + MemoryTestIterations = 5 + SamplingIntervalMs = 1 + GCSettleTimeMs = 5 + FinalSampleWaitMs = 2 +) + +// ESDKBenchmark is the main benchmark struct +type ESDKBenchmark struct { + Config TestConfig + EsdkClient *esdksmithygenerated.Client + Keyring mpltypes.IKeyring + Results []BenchmarkResult + CPUCount int + TotalMemoryGB float64 +} + +// New creates a new benchmark instance +func New(configPath string) (*ESDKBenchmark, error) { + benchmark := &ESDKBenchmark{ + CPUCount: runtime.NumCPU(), + } + + // Get system memory + if vmStat, err := mem.VirtualMemory(); err == nil { + benchmark.TotalMemoryGB = float64(vmStat.Total) / (1024 * 1024 * 1024) + } + + // Load configuration + config, err := LoadConfig(configPath) + if err != nil { + return nil, fmt.Errorf("failed to load config: %w", err) + } + benchmark.Config = config + + // Setup ESDK + if err := benchmark.setupESDK(); err != nil { + return nil, fmt.Errorf("failed to setup ESDK: %w", err) + } + + log.Printf("Initialized ESDK Benchmark - CPU cores: %d, Memory: %.1fGB", + benchmark.CPUCount, benchmark.TotalMemoryGB) + + return benchmark, nil +} + +// setupESDK initializes the ESDK client and creates a default keyring +func (b *ESDKBenchmark) setupESDK() error { + // Initialize the material providers client + matProvConfig := mpltypes.MaterialProvidersConfig{} + matProv, err := mplsmithygenerated.NewClient(matProvConfig) + if err != nil { + return fmt.Errorf("failed to create material providers client: %w", err) + } + + // Create default AES-256 keyring + key := make([]byte, 32) // 256-bit key + if _, err := rand.Read(key); err != nil { + return fmt.Errorf("failed to generate AES-256 key: %w", err) + } + + keyringInput := mpltypes.CreateRawAesKeyringInput{ + KeyName: "test-aes-256-key", + KeyNamespace: "esdk-performance-test", + WrappingKey: key, + WrappingAlg: mpltypes.AesWrappingAlgAlgAes256GcmIv12Tag16, + } + + keyring, err := matProv.CreateRawAesKeyring(context.Background(), keyringInput) + if err != nil { + return fmt.Errorf("failed to create keyring: %w", err) + } + b.Keyring = keyring + + // Create ESDK client with proper commitment policy + commitmentPolicy := mpltypes.ESDKCommitmentPolicyRequireEncryptRequireDecrypt + esdkConfig := esdktypes.AwsEncryptionSdkConfig{ + CommitmentPolicy: &commitmentPolicy, + } + + esdkClient, err := esdksmithygenerated.NewClient(esdkConfig) + if err != nil { + return fmt.Errorf("failed to create ESDK client: %w", err) + } + b.EsdkClient = esdkClient + + log.Println("ESDK client initialized successfully") + return nil +} + +// GenerateTestData creates test data of specified size +func (b *ESDKBenchmark) GenerateTestData(size int) []byte { + data := make([]byte, size) + rand.Read(data) + return data +} diff --git a/esdk-performance-testing/benchmarks/go/benchmark/results.go b/esdk-performance-testing/benchmarks/go/benchmark/results.go new file mode 100644 index 000000000..696fb0c16 --- /dev/null +++ b/esdk-performance-testing/benchmarks/go/benchmark/results.go @@ -0,0 +1,117 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package benchmark + +import ( + "encoding/json" + "fmt" + "math" + "os" + "path/filepath" + "runtime" + "time" +) + +// BenchmarkResult represents the results of a single benchmark test +type BenchmarkResult struct { + TestName string `json:"test_name"` + Language string `json:"language"` + DataSize int `json:"data_size"` + Concurrency int `json:"concurrency"` + EncryptLatencyMs float64 `json:"encrypt_latency_ms"` + DecryptLatencyMs float64 `json:"decrypt_latency_ms"` + EndToEndLatencyMs float64 `json:"end_to_end_latency_ms"` + OpsPerSecond float64 `json:"ops_per_second"` + BytesPerSecond float64 `json:"bytes_per_second"` + PeakMemoryMB float64 `json:"peak_memory_mb"` + MemoryEfficiency float64 `json:"memory_efficiency_ratio"` + P50Latency float64 `json:"p50_latency"` + P95Latency float64 `json:"p95_latency"` + P99Latency float64 `json:"p99_latency"` + Timestamp string `json:"timestamp"` + GoVersion string `json:"go_version"` + CPUCount int `json:"cpu_count"` + TotalMemoryGB float64 `json:"total_memory_gb"` +} + +// MemorySample represents a single memory measurement +type MemorySample struct { + Timestamp time.Time + HeapMB float64 + MetricsAllocsMB float64 + MemStatsAllocsMB float64 +} + +// === Utility Functions === + +// Average calculates the average of a slice of float64 values +func Average(values []float64) float64 { + if len(values) == 0 { + return 0 + } + sum := 0.0 + for _, v := range values { + sum += v + } + return sum / float64(len(values)) +} + +// Percentile calculates the percentile of sorted values +func Percentile(sortedValues []float64, p float64) float64 { + if len(sortedValues) == 0 { + return 0 + } + if p <= 0 { + return sortedValues[0] + } + if p >= 100 { + return sortedValues[len(sortedValues)-1] + } + + index := (p / 100.0) * float64(len(sortedValues)-1) + lower := int(math.Floor(index)) + upper := int(math.Ceil(index)) + + if lower == upper { + return sortedValues[lower] + } + + weight := index - float64(lower) + return sortedValues[lower]*(1-weight) + sortedValues[upper]*weight +} + +// === Results Saving === + +// SaveResults saves benchmark results to JSON file +func (b *ESDKBenchmark) SaveResults(outputPath string) error { + if err := os.MkdirAll(filepath.Dir(outputPath), 0755); err != nil { + return fmt.Errorf("failed to create output directory: %w", err) + } + + resultsData := map[string]interface{}{ + "metadata": map[string]interface{}{ + "language": "go", + "timestamp": time.Now().Format("2006-01-02 15:04:05"), + "go_version": runtime.Version(), + "cpu_count": b.CPUCount, + "total_memory_gb": b.TotalMemoryGB, + "total_tests": len(b.Results), + }, + "results": b.Results, + } + + file, err := os.Create(outputPath) + if err != nil { + return fmt.Errorf("failed to create output file: %w", err) + } + defer file.Close() + + encoder := json.NewEncoder(file) + encoder.SetIndent("", " ") + if err := encoder.Encode(resultsData); err != nil { + return fmt.Errorf("failed to encode results to JSON: %w", err) + } + + return nil +} diff --git a/esdk-performance-testing/benchmarks/go/go.mod b/esdk-performance-testing/benchmarks/go/go.mod new file mode 100644 index 000000000..68ec4e971 --- /dev/null +++ b/esdk-performance-testing/benchmarks/go/go.mod @@ -0,0 +1,48 @@ +module github.com/aws/aws-encryption-sdk/esdk-performance-testing/benchmarks/go + +go 1.23.0 + +replace github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk => ../../../AwsEncryptionSDK/runtimes/go/ImplementationFromDafny-go + +require ( + github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl v0.2.2 + github.com/aws/aws-encryption-sdk/releases/go/encryption-sdk v0.0.0-00010101000000-000000000000 + github.com/schollz/progressbar/v3 v3.14.1 + github.com/shirou/gopsutil/v3 v3.23.12 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/aws/aws-cryptographic-material-providers-library/releases/go/dynamodb v0.2.2 // indirect + github.com/aws/aws-cryptographic-material-providers-library/releases/go/kms v0.2.2 // indirect + github.com/aws/aws-cryptographic-material-providers-library/releases/go/primitives v0.2.2 // indirect + github.com/aws/aws-cryptographic-material-providers-library/releases/go/smithy-dafny-standard-library v0.2.2 // indirect + github.com/aws/aws-sdk-go-v2 v1.38.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.31.2 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.6 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.49.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.44.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 // indirect + github.com/aws/smithy-go v1.22.5 // indirect + github.com/dafny-lang/DafnyRuntimeGo/v4 v4.11.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.14.0 // indirect +) diff --git a/esdk-performance-testing/benchmarks/go/go.sum b/esdk-performance-testing/benchmarks/go/go.sum new file mode 100644 index 000000000..5c23c6894 --- /dev/null +++ b/esdk-performance-testing/benchmarks/go/go.sum @@ -0,0 +1,103 @@ +github.com/aws/aws-cryptographic-material-providers-library/releases/go/dynamodb v0.2.2 h1:1CYvKblXRaPB9B0cdN/xWVOXvii2AQHgdcbTlI5F8Oc= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/dynamodb v0.2.2/go.mod h1:vb/jlzf5XQSD5O3Po50VX6j6JyzcWs3wPoV7foewmJs= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/kms v0.2.2 h1:0x9qTjQeW8fkP+/kuRw2drLDZM617rr8h6kcUetBjKE= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/kms v0.2.2/go.mod h1:2wGHS+a/Dg21W3cnFDYbOu33d6eQUS52Ff/uAE2vIu8= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl v0.2.2 h1:gXYtIJfwt+5gOmo7zg/TDb0l1cz5XgnWR0/opB0OyyA= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/mpl v0.2.2/go.mod h1:9yccmncslXtxhE4vyg1ZKaTWEe5xyNljrt3glFtMN4g= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/primitives v0.2.2 h1:tBPXcmQVmf0ILx5eY++l64+yp04AFlHeKqpli0YDQBc= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/primitives v0.2.2/go.mod h1:mSUejB7V5Wo23naCw2ORAJ+5ZJkyaSvB6hQbKPVXNuA= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/smithy-dafny-standard-library v0.2.2 h1:k/OqY+NJcTlFByY1WcM6dF5ZC4kIZtZ8b3A9kRVAj8Y= +github.com/aws/aws-cryptographic-material-providers-library/releases/go/smithy-dafny-standard-library v0.2.2/go.mod h1:j4QF5oVY9L1yNZrzoDu3l3d8TRh53uBw3FLZCL7xCTk= +github.com/aws/aws-sdk-go-v2 v1.38.1 h1:j7sc33amE74Rz0M/PoCpsZQ6OunLqys/m5antM0J+Z8= +github.com/aws/aws-sdk-go-v2 v1.38.1/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2/config v1.31.2 h1:NOaSZpVGEH2Np/c1toSeW0jooNl+9ALmsUTZ8YvkJR0= +github.com/aws/aws-sdk-go-v2/config v1.31.2/go.mod h1:17ft42Yb2lF6OigqSYiDAiUcX4RIkEMY6XxEMJsrAes= +github.com/aws/aws-sdk-go-v2/credentials v1.18.6 h1:AmmvNEYrru7sYNJnp3pf57lGbiarX4T9qU/6AZ9SucU= +github.com/aws/aws-sdk-go-v2/credentials v1.18.6/go.mod h1:/jdQkh1iVPa01xndfECInp1v1Wnp70v3K4MvtlLGVEc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 h1:lpdMwTzmuDLkgW7086jE94HweHCqG+uOJwHf3LZs7T0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 h1:IdCLsiiIj5YJ3AFevsewURCPV+YWUlOW8JiPhoAy8vg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 h1:j7vjtr1YIssWQOMeOWRbh3z8g2oY/xPjnZH2gLY4sGw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.49.1 h1:0RqS5X7EodJzOenoY4V3LUSp9PirELO2ZOpOZbMldco= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.49.1/go.mod h1:VRp/OeQolnQD9GfNgdSf3kU5vbg708PF6oPHh2bq3hc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.4 h1:upi++G3fQCAUBXQe58TbjXmdVPwrqMnRQMThOAIz7KM= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.4/go.mod h1:swb+GqWXTZMOyVV9rVePAUu5L80+X5a+Lui1RNOyUFo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= +github.com/aws/aws-sdk-go-v2/service/kms v1.44.2 h1:yTtMSIGWk8KzPDX2pS9k7wNCPKiNWpiJ9DdB2mCAMzo= +github.com/aws/aws-sdk-go-v2/service/kms v1.44.2/go.mod h1:zgkQ8ige7qtxldA4cGtiXdbql3dBo4TfsP6uQyHwq0E= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 h1:ve9dYBB8CfJGTFqcQ3ZLAAb/KXWgYlgu/2R2TZL2Ko0= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 h1:pd9G9HQaM6UZAZh19pYOkpKSQkyQQ9ftnl/LttQOcGI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2/go.mod h1:eknndR9rU8UpE/OmFpqU78V1EcXPKFTTm5l/buZYgvM= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 h1:iV1Ko4Em/lkJIsoKyGfc0nQySi+v0Udxr6Igq+y9JZc= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0/go.mod h1:bEPcjW7IbolPfK67G1nilqWyoxYMSPrDiIQ3RdIdKgo= +github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= +github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/dafny-lang/DafnyRuntimeGo/v4 v4.11.0 h1:wJhHuhD9thOc0GXojfW8DJ/n7G8prW+1nUL5O3lvzs0= +github.com/dafny-lang/DafnyRuntimeGo/v4 v4.11.0/go.mod h1:l2Tm4N2DKuq3ljONC2vOATeM9PUpXbIc8SgXdwwqEto= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/schollz/progressbar/v3 v3.14.1 h1:VD+MJPCr4s3wdhTc7OEJ/Z3dAeBzJ7yKH/P4lC5yRTI= +github.com/schollz/progressbar/v3 v3.14.1/go.mod h1:Zc9xXneTzWXF81TGoqL71u0sBPjULtEHYtj/WVgVy8E= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/esdk-performance-testing/benchmarks/go/main.go b/esdk-performance-testing/benchmarks/go/main.go new file mode 100644 index 000000000..9e15c0fa0 --- /dev/null +++ b/esdk-performance-testing/benchmarks/go/main.go @@ -0,0 +1,66 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "flag" + "fmt" + "log" + + "github.com/aws/aws-encryption-sdk/esdk-performance-testing/benchmarks/go/benchmark" +) + +func main() { + // Parse command line arguments + configPath := flag.String("config", "../../config/test-scenarios.yaml", "Path to test configuration file") + outputPath := flag.String("output", "../../results/raw-data/go_results.json", "Path to output results file") + quick := flag.Bool("quick", false, "Run quick test with reduced iterations") + flag.Parse() + + // Initialize benchmark + bench, err := benchmark.New(*configPath) + if err != nil { + log.Fatalf("Failed to initialize benchmark: %v", err) + } + + // Adjust config for quick test + if *quick { + if bench.Config.QuickConfig == nil { + log.Fatalf("Quick mode requested but no quick_config found in config file") + } + bench.Config.Iterations.Measurement = bench.Config.QuickConfig.Iterations.Measurement + bench.Config.Iterations.Warmup = bench.Config.QuickConfig.Iterations.Warmup + bench.Config.DataSizes.Small = bench.Config.QuickConfig.DataSizes.Small + bench.Config.DataSizes.Medium = []int{} + bench.Config.DataSizes.Large = []int{} + bench.Config.ConcurrencyLevels = bench.Config.QuickConfig.ConcurrencyLevels + } + + // Run benchmarks + if err := bench.RunAllBenchmarks(); err != nil { + log.Fatalf("Benchmark failed: %v", err) + } + + // Save results + if err := bench.SaveResults(*outputPath); err != nil { + log.Fatalf("Failed to save results: %v", err) + } + + // Print summary + fmt.Printf("\n=== ESDK Go Benchmark Summary ===\n") + fmt.Printf("Total tests completed: %d\n", len(bench.Results)) + fmt.Printf("Results saved to: %s\n", *outputPath) + + if len(bench.Results) > 0 { + var maxThroughput float64 + for _, result := range bench.Results { + if result.TestName == "throughput" && result.OpsPerSecond > maxThroughput { + maxThroughput = result.OpsPerSecond + } + } + if maxThroughput > 0 { + fmt.Printf("Maximum throughput: %.2f ops/sec\n", maxThroughput) + } + } +} From 1a59dfa67c65c107b82d46c54aad9c667bb8291d Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Tue, 2 Sep 2025 16:15:59 -0700 Subject: [PATCH 2/2] fix: formatting --- esdk-performance-testing/benchmarks/go/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esdk-performance-testing/benchmarks/go/README.md b/esdk-performance-testing/benchmarks/go/README.md index 379204159..0d69f41d8 100644 --- a/esdk-performance-testing/benchmarks/go/README.md +++ b/esdk-performance-testing/benchmarks/go/README.md @@ -29,6 +29,7 @@ The benchmark uses YAML configuration files. See `../../config/test-scenarios.ya ### Quick Mode Quick mode runs a subset of tests with reduced iterations: + - Only runs test types specified in `quick_config.test_types` - Uses smaller data sizes from `quick_config.data_sizes.small` - Fewer iterations: `quick_config.iterations.measurement` @@ -41,4 +42,4 @@ Quick mode runs a subset of tests with reduced iterations: ## Output -Results are saved to JSON format in `../../results/raw-data/go_results.json` by default. \ No newline at end of file +Results are saved to JSON format in `../../results/raw-data/go_results.json` by default.