Skip to content
Merged
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
7 changes: 0 additions & 7 deletions .github/workflows/library_rust_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,6 @@ jobs:
CORES=$(node -e 'console.log(os.cpus().length)')
make transpile_rust CORES=$CORES

- name: Test Linter for Rust examples and implementation_from_dafny.rs
working-directory: ${{ matrix.library }}/runtimes/rust
shell: bash
run: |
cargo clippy
cargo clippy --example main

- name: Test Rust
working-directory: ${{ matrix.library }}
shell: bash
Expand Down
34 changes: 18 additions & 16 deletions esdk-performance-testing/benchmarks/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,60 +1,62 @@
[package]
name = "esdk-benchmark"
version = "0.1.0"
edition = "2021"
edition = "2024"

[[bin]]
name = "esdk_benchmark"
path = "src/main.rs"

[dependencies]
# AWS Encryption SDK
# aws-esdk = { path = "/Users/ajewell/esdk_rust/esdk" }
aws-esdk = { path = "../../../AwsEncryptionSDK/runtimes/rust" }

# Async runtime
tokio = { version = "1.0", features = ["full"] }
tokio = { version = "1.47", features = ["full"] }

# Serialization
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"

# CLI and progress
clap = { version = "4.0", features = ["derive"] }
indicatif = "0.17"
clap = { version = "4.5", features = ["derive"] }
indicatif = "0.18"

# Statistics and benchmarking
hdrhistogram = "7.5"
rand = "0.8"
rand = "0.9"

# System info
sysinfo = "0.30"
sysinfo = "0.37"

# Error handling
anyhow = "1.0"
thiserror = "1.0"
thiserror = "2.0"

# Logging
log = "0.4"
env_logger = "0.10"
env_logger = "0.11"

# Time
chrono = { version = "0.4", features = ["serde"] }

# Memory profiling
memory-stats = "1.0"
memory-stats = "1.2"
stats_alloc = "0.1"

# Async utilities
futures = "0.3"

aws-config = "1.8.6"
aws-sdk-dynamodb = "1.73.0"
aws-sdk-kms = "1.67.0"
aws-sdk-sso = "1.69.0"
aws-sdk-ssooidc = "1.69.0"
aws-sdk-sts = "1.69.0"
aws-smithy-types = "1.2"
aws-sdk-dynamodb = "1.92.0"
aws-sdk-kms = "1.86.0"
aws-sdk-sso = "1.83.0"
aws-sdk-ssooidc = "1.84.0"
aws-sdk-sts = "1.85.0"
aws-smithy-types = "1.3"
cpu-time = "1.0.0"

[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
criterion = { version = "0.7", features = ["html_reports"] }
12 changes: 8 additions & 4 deletions esdk-performance-testing/benchmarks/rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,22 @@ Rust implementation of the AWS Encryption SDK performance benchmark suite.

## Prerequisites

- Rust 1.85.0+ ([rustup.rs](https://rustup.rs/))
- Rust 1.86.0+ ([rustup.rs](https://rustup.rs/))
- Build tools (Xcode CLI Tools on macOS, build-essential on Linux)

## Quick Start

```bash
# If necessary, build the ESDK and return here
cd ../../../AwsEncryptionSDK/
make polymorph_rust transpile_rust
cd ../esdk-performance-testing/benchmarks/rust/

# Build and run
cargo build --release
./target/release/esdk_benchmark --config ../../config/test-scenarios.yaml
cargo run --release -- --config ../../config/test-scenarios.yaml

# Quick test (requires quick_config in YAML)
./target/release/esdk_benchmark --quick
cargo run --release -- --quick
```

## Configuration
Expand Down
116 changes: 116 additions & 0 deletions esdk-performance-testing/benchmarks/rust/src/alloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use serde::Serialize;
use std::sync::atomic::AtomicIsize;
use std::sync::atomic::Ordering;

pub struct ResourceTracker {
pub count: isize,
pub total: isize,
pub net_total: isize,
pub net_count: isize,
}

#[derive(Debug, Default, Clone, Serialize)]
pub struct ResourceResults {
pub count_k: isize,
pub total_m: isize,
pub max_bytes_m: isize,
pub net_count: isize,
pub net_total: isize,
}

impl ResourceTracker {
pub fn new() -> Self {
clear_max();
Self {
count: get_counter(),
total: get_total(),
net_total: get_net_total(),
net_count: get_net_counter(),
}
}
pub fn get_results(&self) -> ResourceResults {
ResourceResults {
count_k: (get_counter() - self.count) / 1000,
total_m: (get_total() - self.total) / 1_000_000,
max_bytes_m: (get_max_total() - self.net_total) / 1_000_000,
net_count: get_net_counter() - self.net_count,
net_total: (get_net_total() - self.net_total) / 1_000_000,
}
}
}

// total number of allocations made over the life of the program
static COUNTER: AtomicIsize = AtomicIsize::new(0);

// total number of bytes allocated over the life of the program
static TOTAL: AtomicIsize = AtomicIsize::new(0);

// number allocations not yet deallocated
static NET_COUNTER: AtomicIsize = AtomicIsize::new(0);

// number bytes not yet deallocated
static NET_TOTAL: AtomicIsize = AtomicIsize::new(0);

// the peak value reached by NET_TOTAL
// This is reset whenever a ResourceTracker is created
// so it gives the right answer for a single operation
// but it does not handle nested ResourceTrackers correctly.
static MAX_NET_TOTAL: AtomicIsize = AtomicIsize::new(0);

fn add_to_counter(inc: isize) {
COUNTER.fetch_add(1, Ordering::SeqCst);
TOTAL.fetch_add(inc, Ordering::SeqCst);
NET_COUNTER.fetch_add(1, Ordering::SeqCst);
NET_TOTAL.fetch_add(inc, Ordering::SeqCst);
MAX_NET_TOTAL.fetch_max(NET_TOTAL.load(Ordering::SeqCst), Ordering::SeqCst);
}

fn subtract_from_counter(inc: isize) {
NET_COUNTER.fetch_sub(1, Ordering::SeqCst);
NET_TOTAL.fetch_sub(inc, Ordering::SeqCst);
}

fn get_counter() -> isize {
COUNTER.load(Ordering::SeqCst)
}

fn get_total() -> isize {
TOTAL.load(Ordering::SeqCst)
}

fn get_net_counter() -> isize {
NET_COUNTER.load(Ordering::SeqCst)
}

fn get_net_total() -> isize {
NET_TOTAL.load(Ordering::SeqCst)
}

fn clear_max() {
MAX_NET_TOTAL.store(0, Ordering::SeqCst)
}

fn get_max_total() -> isize {
MAX_NET_TOTAL.load(Ordering::SeqCst)
}

use std::alloc::{GlobalAlloc, Layout, System};

struct MyAllocator;

unsafe impl GlobalAlloc for MyAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
add_to_counter(layout.size() as isize);
unsafe { System.alloc(layout) }
}

unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
subtract_from_counter(layout.size() as isize);
unsafe { System.dealloc(ptr, layout) }
}
}

#[global_allocator]
static GLOBAL: MyAllocator = MyAllocator;
6 changes: 3 additions & 3 deletions esdk-performance-testing/benchmarks/rust/src/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
use anyhow::{Context, Result};
use aws_esdk::client as esdk_client;
use aws_esdk::material_providers::client as mpl_client;
use aws_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
use aws_esdk::material_providers::types::AesWrappingAlg;
use aws_esdk::material_providers::types::EsdkCommitmentPolicy;
use aws_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
use aws_esdk::types::aws_encryption_sdk_config::AwsEncryptionSdkConfig;
use log::info;
use rand::Rng;
use sysinfo::System;

use crate::config::{load_config, TestConfig};
use crate::config::{TestConfig, load_config};
use crate::results::BenchmarkResult;

// Constants for memory testing
Expand Down Expand Up @@ -72,7 +72,7 @@ impl EsdkBenchmark {

// Create default AES-256 keyring
let mut key = [0u8; 32]; // 256-bit key
rand::thread_rng().fill(&mut key);
rand::rng().fill(&mut key);

let raw_keyring = mpl_client
.create_raw_aes_keyring()
Expand Down
16 changes: 9 additions & 7 deletions esdk-performance-testing/benchmarks/rust/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

#![allow(clippy::collapsible_if)]

mod alloc;
mod benchmark;
mod config;
mod results;
Expand All @@ -18,10 +21,8 @@ fn main() -> Result<()> {
.thread_stack_size(8 * 1024 * 1024) // 8MB stack size
.enable_all()
.build()?;

rt.block_on(async {
run_benchmark().await
})

rt.block_on(async { run_benchmark().await })
}

async fn run_benchmark() -> Result<()> {
Expand Down Expand Up @@ -63,9 +64,10 @@ async fn run_benchmark() -> Result<()> {

// Adjust config for quick test
if quick {
let quick_config = bench.config.quick_config.as_ref()
.ok_or_else(|| anyhow::anyhow!("Quick mode requested but no quick_config found in config file"))?;

let quick_config = bench.config.quick_config.as_ref().ok_or_else(|| {
anyhow::anyhow!("Quick mode requested but no quick_config found in config file")
})?;

bench.config.iterations.measurement = quick_config.iterations.measurement;
bench.config.iterations.warmup = quick_config.iterations.warmup;
bench.config.data_sizes.small = quick_config.data_sizes.small.clone();
Expand Down
2 changes: 2 additions & 0 deletions esdk-performance-testing/benchmarks/rust/src/results.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use crate::alloc;
use anyhow::Result;
use chrono::Utc;
use serde::Serialize;
Expand Down Expand Up @@ -28,6 +29,7 @@ pub struct BenchmarkResult {
pub rust_version: String,
pub cpu_count: usize,
pub total_memory_gb: f64,
pub alloc: alloc::ResourceResults,
}

#[derive(Debug, Serialize)]
Expand Down
Loading
Loading