Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions esdk-performance-testing/benchmarks/net/Benchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using System.Diagnostics;
using System.Runtime;
using System.Text.Json;
using System.Security.Cryptography;
using Microsoft.Extensions.Logging;
using AWS.Cryptography.EncryptionSDK;
using AWS.Cryptography.MaterialProviders;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
using ShellProgressBar;
using Newtonsoft.Json;

namespace EsdkBenchmark;

public partial class ESDKBenchmark
{
private readonly ILogger _logger;
private readonly TestConfig _config;
private readonly int _cpuCount;
private readonly double _totalMemoryGb;
private static readonly Random _random = new();
private readonly List<BenchmarkResult> _results = new();

// Public properties to match Go structure
public TestConfig Config => _config;
public List<BenchmarkResult> Results => _results;

// ESDK components
private MaterialProviders _materialProviders = null!;
private ESDK _encryptionSdk = null!;
private IKeyring _keyring = null!;

// Constants for memory testing
private const int MemoryTestIterations = 5;
private const int SamplingIntervalMs = 1;
private const int GcSettleTimeMs = 5;
private const int FinalSampleWaitMs = 2;

public ESDKBenchmark(string configPath, ILogger logger)
{
_logger = logger;
_config = ConfigLoader.LoadConfig(configPath);

// Get system information
_cpuCount = Environment.ProcessorCount;
_totalMemoryGb = GetTotalMemoryGb();

// Configure GC for performance
GCSettings.LatencyMode = GCLatencyMode.SustainedLowLatency;

// Setup ESDK
var setupError = SetupEsdk();
if (setupError != null)
{
throw new InvalidOperationException($"Failed to setup ESDK: {setupError}");
}

_logger.LogInformation("Initialized ESDK Benchmark - CPU cores: {CpuCount}, Memory: {Memory:F1}GB",
_cpuCount, _totalMemoryGb);
}

private string? SetupEsdk()
{
try
{
_materialProviders = new MaterialProviders(new MaterialProvidersConfig());

// Create 256-bit AES key using .NET crypto
var key = new byte[32];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(key);
}

// Create raw AES keyring
var createKeyringInput = new CreateRawAesKeyringInput
{
KeyNamespace = "esdk-performance-test",
KeyName = "test-aes-256-key",
WrappingKey = new MemoryStream(key),
WrappingAlg = AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16
};
_keyring = _materialProviders.CreateRawAesKeyring(createKeyringInput);

// Create ESDK client with commitment policy
var esdkConfig = new AwsEncryptionSdkConfig
{
CommitmentPolicy = ESDKCommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
};
_encryptionSdk = new ESDK(esdkConfig);

return null;
}
catch (Exception ex)
{
return ex.Message;
}
}

public static double GetTotalMemoryGb()
{
try
{
var gcMemoryInfo = GC.GetGCMemoryInfo();
// Convert from bytes to GB
return gcMemoryInfo.TotalAvailableMemoryBytes / (1024.0 * 1024.0 * 1024.0);
}
catch
{
// Fallback - estimate based on process memory
return Environment.WorkingSet / (1024.0 * 1024.0 * 1024.0) * 4; // Rough estimate
}
}

private byte[] GenerateTestData(int size)
{
var data = new byte[size];
_random.NextBytes(data);
return data;
}



public void RunAllBenchmarks()
{
_results.Clear();
Console.WriteLine("Starting comprehensive ESDK benchmark suite");

// Combine all data sizes
var dataSizes = _config.DataSizes.Small
.Concat(_config.DataSizes.Medium)
.Concat(_config.DataSizes.Large);

// Run test suites
if (ConfigLoader.ShouldRunTestType(_config, "throughput"))
{
RunThroughputTests(dataSizes, _config.Iterations.Measurement);
}
else
{
Console.WriteLine("Skipping throughput tests (not in test_types)");
}

if (ConfigLoader.ShouldRunTestType(_config, "memory"))
{
RunMemoryTests(dataSizes);
}
else
{
Console.WriteLine("Skipping memory tests (not in test_types)");
}

if (ConfigLoader.ShouldRunTestType(_config, "concurrency"))
{
RunConcurrencyTests(dataSizes, _config.ConcurrencyLevels);
}
else
{
Console.WriteLine("Skipping concurrency tests (not in test_types)");
}

Console.WriteLine($"Benchmark suite completed. Total results: {_results.Count}");
}
}
132 changes: 132 additions & 0 deletions esdk-performance-testing/benchmarks/net/Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

namespace EsdkBenchmark;

public class TestConfig
{
[YamlMember(Alias = "data_sizes")]
public DataSizes DataSizes { get; set; } = new();

[YamlMember(Alias = "iterations")]
public IterationConfig Iterations { get; set; } = new();

[YamlMember(Alias = "concurrency_levels")]
public List<int> ConcurrencyLevels { get; set; } = new();

[YamlMember(Alias = "quick_config")]
public QuickConfig? QuickConfig { get; set; }
}

public class DataSizes
{
[YamlMember(Alias = "small")]
public List<int> Small { get; set; } = new();

[YamlMember(Alias = "medium")]
public List<int> Medium { get; set; } = new();

[YamlMember(Alias = "large")]
public List<int> Large { get; set; } = new();
}

public class IterationConfig
{
[YamlMember(Alias = "warmup")]
public int Warmup { get; set; }

[YamlMember(Alias = "measurement")]
public int Measurement { get; set; }
}

public class QuickConfig
{
[YamlMember(Alias = "data_sizes")]
public QuickDataSizes DataSizes { get; set; } = new();

[YamlMember(Alias = "iterations")]
public QuickIterationConfig Iterations { get; set; } = new();

[YamlMember(Alias = "concurrency_levels")]
public List<int> ConcurrencyLevels { get; set; } = new();

[YamlMember(Alias = "test_types")]
public List<string> TestTypes { get; set; } = new();
}

public class QuickDataSizes
{
[YamlMember(Alias = "small")]
public List<int> Small { get; set; } = new();
}

public class QuickIterationConfig
{
[YamlMember(Alias = "warmup")]
public int Warmup { get; set; }

[YamlMember(Alias = "measurement")]
public int Measurement { get; set; }
}

public static class ConfigLoader
{
public static TestConfig LoadConfig(string configPath)
{
if (!File.Exists(configPath))
{
throw new FileNotFoundException($"Config file not found: {configPath}");
}

try
{
var yaml = File.ReadAllText(configPath);
var deserializer = new DeserializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build();

return deserializer.Deserialize<TestConfig>(yaml);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to load config file: {ex.Message}", ex);
}
}

public static void AdjustForQuickTest(TestConfig config)
{
if (config.QuickConfig != null)
{
if (config.QuickConfig.DataSizes != null)
{
config.DataSizes.Small = config.QuickConfig.DataSizes.Small;
config.DataSizes.Medium = new List<int>();
config.DataSizes.Large = new List<int>();
}

if (config.QuickConfig.Iterations != null)
{
config.Iterations.Warmup = config.QuickConfig.Iterations.Warmup;
config.Iterations.Measurement = config.QuickConfig.Iterations.Measurement;
}

if (config.QuickConfig.ConcurrencyLevels.Count > 0)
{
config.ConcurrencyLevels = config.QuickConfig.ConcurrencyLevels;
}
}
}

public static bool ShouldRunTestType(TestConfig config, string testType)
{
if (config.QuickConfig != null && config.QuickConfig.TestTypes.Count > 0)
{
return config.QuickConfig.TestTypes.Contains(testType);
}
return true;
}
}
64 changes: 64 additions & 0 deletions esdk-performance-testing/benchmarks/net/EsdkBenchmark.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>13.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyName>EsdkBenchmark</AssemblyName>
<RootNamespace>Amazon.Esdk.Benchmark</RootNamespace>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<AssemblyTitle>ESDK .NET Performance Benchmark</AssemblyTitle>
<AssemblyDescription>Performance benchmark suite for AWS Encryption SDK .NET runtime</AssemblyDescription>
<AssemblyCompany>Amazon Web Services</AssemblyCompany>
<AssemblyProduct>AWS Encryption SDK</AssemblyProduct>
<Copyright>Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.</Copyright>
<Version>1.0.0</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)'=='Release'">
<Optimize>true</Optimize>
<DebugType>portable</DebugType>
<DebugSymbols>true</DebugSymbols>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<!-- ESDK and Material Providers -->
<ProjectReference Include="../../../AwsEncryptionSDK/runtimes/net/ESDK.csproj" />

<!-- Command line parsing -->
<PackageReference Include="CommandLineParser" Version="2.9.1" />

<!-- Configuration and serialization -->
<PackageReference Include="YamlDotNet" Version="13.7.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

<!-- Progress reporting -->
<PackageReference Include="ShellProgressBar" Version="5.2.0" />

<!-- System information -->
<PackageReference Include="System.Management" Version="6.0.0" />

<!-- Memory profiling -->
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="6.0.0" />

<!-- Logging -->
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />

<!-- Statistics -->
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />

<!-- Async utilities -->
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
</ItemGroup>

<ItemGroup>
<None Include="../../config/test-scenarios.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
Loading
Loading