Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add PerformanceTests #1910

Merged
merged 11 commits into from
Mar 28, 2025
19 changes: 19 additions & 0 deletions PerformanceTests/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// swift-tools-version: 5.9

import PackageDescription

let package = Package(
name: "SDKWorkbench",
platforms: [.macOS(.v12), .iOS(.v15)],
dependencies: [
.package(name: "aws-sdk-swift", path: "../../aws-sdk-swift"),
],
targets: [
.executableTarget(
name: "PerformanceTestScript",
dependencies: [
.product(name: "AWSSTS", package: "aws-sdk-swift"),
]
),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import ClientRuntime

// MARK: - Main Entry Point
@main
struct PerformanceTestRun {
static func main() async throws {
let runner = BenchmarkRunner(iterations: 5)
let commitId = ProcessRunner.getGitCommitId()
let sdkVersion = ProcessRunner.getSdkVersion()

// Add more tests here
let performanceTests = [
AWSSTSGetCallerIdentity()
]

var benchmarks: [BenchmarkResult] = []
for test in performanceTests {
let result = try await runner.runBenchmark(test)
benchmarks.append(result)
}

let report = BenchmarkReport(
productId: "AWS SDK for Swift",
sdkVersion: sdkVersion,
commitId: commitId,
results: benchmarks
)
report.printFormatted()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import AWSSTS
import Foundation

struct AWSSTSGetCallerIdentity: PerformanceTest {
let name = "sts.getcalleridentity.latency"

let description = "The total time between initiating a GetCallerIdentity and reading the last byte of the object."

let unit = "Milliseconds"

let dimensions = [
Dimension(name: "OS", value: OperatingSystem.current.rawValue),
]

let test = getCallerIdentity

static func getCallerIdentity() async throws -> Double {
let start = Date()
let client = try await STSClient()
_ = try await client.getCallerIdentity(input: .init())
return Date().timeIntervalSince(start) * 1000 // Convert seconds to milliseconds
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

struct BenchmarkResult: Codable {
let name: String
let description: String
let unit: String
let date: Int
let measurements: [Double]
let dimensions: [Dimension]?
}

struct Dimension: Codable {
let name: String
let value: String
}

struct BenchmarkReport: Codable {
let productId: String
let sdkVersion: String?
let commitId: String
let results: [BenchmarkResult]
}

struct BenchmarkRunner {

var iterations: Int

/// Executes the given test multiple times
func runBenchmark(
_ perfTest: PerformanceTest
) async throws -> BenchmarkResult {
var measurements: [Double] = []

for _ in 0..<iterations {
measurements.append(try await perfTest.test())
}

let timestamp = Int(Date().timeIntervalSince1970)
return BenchmarkResult(
name: perfTest.name,
description: perfTest.description,
unit: perfTest.unit,
date: timestamp,
measurements: measurements,
dimensions: perfTest.dimensions
)
}
}

extension BenchmarkReport {
func printFormatted() {
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted

if let jsonData = try? jsonEncoder.encode(self),
let jsonString = String(data: jsonData, encoding: .utf8) {
print(jsonString)
} else {
print("Error encoding JSON")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

enum OperatingSystem: String {
case macOS = "macOS"
case Linux = "Linux"
case Unknown = "Unknown"

static var current: OperatingSystem {
#if os(macOS)
return .macOS
#elseif os(Linux)
return .Linux
#else
return .Unknown
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

protocol PerformanceTest {
var name: String { get }
var description: String { get }
var unit: String { get }
var dimensions: [Dimension] { get }
var test: () async throws -> Double { get }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

struct ProcessRunner {
static func runProcess(
executable: String = "/usr/bin/env",
arguments: [String]
) -> String {
let process = Process()
process.executableURL = URL(fileURLWithPath: executable)
process.arguments = arguments

let outputPipe = Pipe()
process.standardOutput = outputPipe
process.standardError = Pipe()

do {
try process.run()
process.waitUntilExit()
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
return String(data: outputData, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
} catch {
print("ProcessRunner Error: \(error.localizedDescription)")
return ""
}
}

/// Retrieves the current Git commit ID.
static func getGitCommitId() -> String {
return ProcessRunner.runProcess(arguments: ["git", "rev-parse", "HEAD"])
}

/// Retrieves the SDK version from a file.
static func getSdkVersion() -> String {
return ProcessRunner.runProcess(arguments: ["cat", "../../aws-sdk-swift/Package.version"])
}
}
Loading