Add scripts to measure cold start performance (#604)

I added two shell scripts under `scripts/lambda-performance` to help
measure Lambda cold and warm start time.

Co-authored-by: Sebastien Stormacq <stormacq@amazon.lu>
This commit is contained in:
Sébastien Stormacq
2025-11-19 20:36:51 +01:00
committed by GitHub
parent 85bd29e4de
commit 0305cb31b8
5 changed files with 910 additions and 0 deletions
+470
View File
@@ -0,0 +1,470 @@
# AWS Lambda Startup Time Measurement Scripts
A set of simple bash scripts to measure AWS Lambda cold start and warm start times. These scripts deploy a Lambda function, invoke it multiple times, retrieve execution metrics from CloudWatch Logs (the authoritative source), and output statistical results.
## Overview
This toolkit provides two measurement scripts:
- **measure-cold-start.sh** - Measures cold start times by forcing a new execution environment between invocations
- **measure-warm-start.sh** - Measures warm start times by reusing the same execution environment
Both scripts follow the KISS (Keep It Simple, Stupid) principle with minimal dependencies and straightforward implementations.
**Note:** Lambda functions are deployed with arm64 architecture by default.
## Purpose
Understanding Lambda startup performance is critical for optimizing serverless applications. These scripts help you:
- Measure cold start initialization times when Lambda creates a new execution environment
- Measure warm start execution times when Lambda reuses an existing environment
- Gather statistically valid datasets through multiple iterations
- Compare performance across different runtimes, configurations, or code changes
## Dependencies
The following tools must be installed and available in your PATH:
- **AWS CLI v2** - For Lambda and CloudWatch Logs operations
- Installation: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
- Must be configured with valid credentials (`aws configure`)
- **jq** - For JSON parsing
- Installation: `brew install jq` (macOS) or `apt-get install jq` (Linux)
- **bc** - For floating-point arithmetic in statistics calculations
- Usually pre-installed on most systems
- Installation: `brew install bc` (macOS) or `apt-get install bc` (Linux)
- **grep** with Perl regex support - For log parsing
- Usually pre-installed on most systems
## Prerequisites
Before running the scripts, ensure you have:
1. **AWS Credentials** - Configured via `aws configure` or environment variables
2. **IAM Role** - An IAM role with Lambda execution permissions (ARN required)
3. **Lambda Deployment Package** - A ZIP file containing your Lambda function code
4. **Permissions** - Your AWS credentials must have permissions to:
- Create/update Lambda functions
- Invoke Lambda functions
- Read CloudWatch Logs
## Command-Line Parameters
### Required Parameters
Both scripts require these parameters:
| Parameter | Description | Example |
|-----------|-------------|---------|
| `--zip-file <path>` | Path to Lambda deployment package (ZIP file) | `--zip-file ./my-function.zip` |
| `--role-arn <arn>` | IAM role ARN for Lambda execution | `--role-arn arn:aws:iam::123456789012:role/lambda-role` |
### Optional Parameters
| Parameter | Description | Default Value |
|-----------|-------------|---------------|
| `--runtime <runtime>` | Lambda runtime environment | `provided.al2023` |
| `--iterations <n>` | Number of measurements to collect | `10` |
| `--event-file <path>` | Path to JSON event payload file | Simple string: "Performance test" |
| `--function-name <name>` | Lambda function name | `lambda-perf-test` |
| `--handler <handler>` | Lambda handler | `bootstrap` |
### Default Values
- **Runtime**: `provided.al2023` - AWS Lambda custom runtime
- **Iterations**: `10` - Provides a reasonable sample size for statistical analysis
- **Function Name**: `lambda-perf-test` - Automatically generated name
- **Handler**: `bootstrap` - Default for custom runtimes
- **Event Payload**: `"Performance test"` - Simple string payload
## Usage Examples
### Basic Cold Start Measurement
Measure cold start times with default settings (10 iterations):
```bash
./measure-cold-start.sh \
--zip-file ./my-function.zip \
--role-arn arn:aws:iam::123456789012:role/lambda-role
```
### Cold Start with Custom Configuration
Measure cold start times with custom runtime and more iterations:
```bash
./measure-cold-start.sh \
--zip-file ./my-function.zip \
--role-arn arn:aws:iam::123456789012:role/lambda-role \
--runtime provided.al2023 \
--iterations 15 \
--function-name my-perf-test
```
### Cold Start with Custom Event Payload
Use a JSON file for the invocation payload:
```bash
./measure-cold-start.sh \
--zip-file ./my-function.zip \
--role-arn arn:aws:iam::123456789012:role/lambda-role \
--event-file ./example-event.json \
--iterations 20
```
### Basic Warm Start Measurement
Measure warm start times with default settings:
```bash
./measure-warm-start.sh \
--zip-file ./my-function.zip \
--role-arn arn:aws:iam::123456789012:role/lambda-role
```
### Warm Start with Custom Configuration
Measure warm start times with more iterations:
```bash
./measure-warm-start.sh \
--zip-file ./my-function.zip \
--role-arn arn:aws:iam::123456789012:role/lambda-role \
--runtime provided.al2023 \
--iterations 25 \
--event-file ./custom-event.json
```
### Comparing Cold vs Warm Starts
Run both scripts with the same configuration to compare:
```bash
# Measure cold starts
./measure-cold-start.sh \
--zip-file ./my-function.zip \
--role-arn arn:aws:iam::123456789012:role/lambda-role \
--iterations 10
# Measure warm starts
./measure-warm-start.sh \
--zip-file ./my-function.zip \
--role-arn arn:aws:iam::123456789012:role/lambda-role \
--iterations 10
```
## Example Output
### Cold Start Measurement Output
```
=== Cold Start Measurement Configuration ===
Function Name: lambda-perf-test
ZIP File: ./my-function.zip
Runtime: provided.al2023
Handler: bootstrap
Iterations: 10
Role ARN: arn:aws:iam::123456789012:role/lambda-role
Deploying function: lambda-perf-test
Function exists, updating code...
Waiting for function to be active...
Function deployed successfully
=== Starting Cold Start Measurements ===
Iteration 1/10
Request ID: abc-123-def-456
Duration: 245.67ms
Forcing cold start...
Iteration 2/10
Request ID: ghi-789-jkl-012
Duration: 198.34ms
Forcing cold start...
Iteration 3/10
Request ID: mno-345-pqr-678
Duration: 223.45ms
Forcing cold start...
...
=== Cold Start Measurement Results ===
Individual measurements:
Measurement 1: 245.67ms
Measurement 2: 198.34ms
Measurement 3: 223.45ms
Measurement 4: 267.89ms
Measurement 5: 201.23ms
Measurement 6: 234.56ms
Measurement 7: 189.12ms
Measurement 8: 256.78ms
Measurement 9: 212.34ms
Measurement 10: 225.67ms
=== Statistics ===
Count: 10
Average: 225.51ms
Min: 189.12ms
Max: 267.89ms
```
### Warm Start Measurement Output
```
=== Warm Start Measurement Configuration ===
Function Name: lambda-perf-test
ZIP File: ./my-function.zip
Runtime: provided.al2023
Handler: bootstrap
Iterations: 10
Role ARN: arn:aws:iam::123456789012:role/lambda-role
Deploying function: lambda-perf-test
Function exists, updating code...
Waiting for function to be active...
Function deployed successfully
=== Starting Warm Start Measurements ===
Iteration 1/10
Request ID: stu-901-vwx-234
Duration: 12.45ms
Iteration 2/10
Request ID: yza-567-bcd-890
Duration: 8.23ms
Iteration 3/10
Request ID: efg-123-hij-456
Duration: 9.67ms
...
=== Warm Start Measurement Results ===
Individual measurements:
Measurement 1: 12.45ms
Measurement 2: 8.23ms
Measurement 3: 9.67ms
Measurement 4: 11.34ms
Measurement 5: 7.89ms
Measurement 6: 10.12ms
Measurement 7: 8.56ms
Measurement 8: 9.23ms
Measurement 9: 10.78ms
Measurement 10: 8.91ms
=== Statistics ===
Count: 10
Average: 9.72ms
Min: 7.89ms
Max: 12.45ms
```
## How It Works
### Cold Start Measurement Process
1. **Deploy Function** - Creates or updates the Lambda function with your ZIP file (using arm64 architecture)
2. **Invoke Function** - Calls the Lambda function via AWS CLI
3. **Capture Invocation ID** - Extracts the request ID from the invocation response
4. **Retrieve Metrics** - Queries CloudWatch Logs using the invocation ID
5. **Parse Duration** - Extracts the duration from the REPORT log line
6. **Force Cold Start** - Updates an environment variable to force a new execution environment
7. **Repeat** - Continues for the specified number of iterations
8. **Calculate Statistics** - Computes average, min, and max from all measurements
### Warm Start Measurement Process
1. **Deploy Function** - Creates or updates the Lambda function with your ZIP file (using arm64 architecture)
2. **Invoke Function** - Calls the Lambda function via AWS CLI
3. **Capture Invocation ID** - Extracts the request ID from the invocation response
4. **Retrieve Metrics** - Queries CloudWatch Logs using the invocation ID
5. **Parse Duration** - Extracts the duration from the REPORT log line
6. **Repeat** - Continues for the specified number of iterations (without forcing cold starts)
7. **Calculate Statistics** - Computes average, min, and max from all measurements
### CloudWatch Logs as Source of Truth
The scripts use CloudWatch Logs as the authoritative source for execution times because:
- CloudWatch Logs contain the official AWS-recorded execution duration
- The REPORT log line includes precise timing information
- Invocation IDs ensure correct correlation between invocations and log entries
- This approach is more reliable than client-side timing
### Cold Start Forcing Mechanism
The cold start script forces new execution environments by:
1. Updating the Lambda function's environment variables with a timestamp
2. Waiting for the configuration update to complete
3. Adding a 2-second delay to ensure the environment is recycled
4. The next invocation will use a fresh execution environment (cold start)
## Performance Expectations
### Typical Execution Times
- **Cold Start Measurement** (10 iterations): ~60-100 seconds
- Each iteration: ~6-10 seconds (invocation + log retrieval + cold start forcing)
- **Warm Start Measurement** (10 iterations): ~30-50 seconds
- Each iteration: ~3-5 seconds (invocation + log retrieval)
### CloudWatch Logs Latency
- Logs typically appear in CloudWatch within 1-3 seconds
- The scripts implement retry logic (up to 10 attempts with 1-second delays)
- Initial 2-second wait before querying logs
## Event Payload
### Using the Default Payload
If no `--event-file` is specified, the scripts use a simple string payload: `"Performance test"`
### Using a Custom Event File
Create a JSON file with your desired payload structure:
```json
{
"message": "Hello World",
"timestamp": "2024-01-01T00:00:00Z",
"userId": "user-123",
"data": {
"key": "value"
}
}
```
Then reference it with `--event-file`:
```bash
./measure-cold-start.sh \
--zip-file ./my-function.zip \
--role-arn arn:aws:iam::123456789012:role/lambda-role \
--event-file ./my-event.json
```
### Example Event File
An `example-event.json` file is provided as a template:
```json
{
"_comment": "Example event payload for Lambda function invocation",
"_usage": "Use this file with --event-file parameter or modify for your specific Lambda function",
"message": "Hello World",
"timestamp": "2024-01-01T00:00:00Z"
}
```
## File Structure
```
lambda-measurement/
├── measure-cold-start.sh # Cold start measurement script
├── measure-warm-start.sh # Warm start measurement script
├── shared-utils.sh # Shared utility functions
├── example-event.json # Example event payload
├── README.md # This documentation
└── test/ # Test directory (optional)
├── test_statistics.bats # Unit tests
└── test_properties.py # Property-based tests
```
## Troubleshooting
### AWS CLI Not Found
**Error**: `ERROR: AWS CLI is not installed or not in PATH`
**Solution**: Install AWS CLI v2 from https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
### Missing Dependencies
**Error**: `ERROR: jq is not installed or not in PATH` or `ERROR: bc is not installed or not in PATH`
**Solution**: Install the missing tool:
- macOS: `brew install jq bc`
- Linux: `apt-get install jq bc` or `yum install jq bc`
### ZIP File Not Found
**Error**: `ERROR: ZIP file not found: ./my-function.zip`
**Solution**: Verify the path to your ZIP file is correct and the file exists
### IAM Role Permissions
**Error**: Function deployment fails with permission errors
**Solution**: Ensure your IAM role has the following permissions:
- `lambda:CreateFunction`
- `lambda:UpdateFunctionCode`
- `lambda:UpdateFunctionConfiguration`
- `lambda:InvokeFunction`
- `lambda:GetFunction`
- `logs:FilterLogEvents`
### CloudWatch Logs Not Available
**Error**: `ERROR: Could not retrieve logs for request <id>`
**Solution**:
- Logs may take longer than expected to appear
- Check that your Lambda function has CloudWatch Logs permissions
- Verify the log group `/aws/lambda/<function-name>` exists
- Increase the retry attempts in `get_duration_from_logs()` if needed
### Failed Invocations
**Warning**: `WARNING: Failed to get duration for iteration N, skipping`
**Solution**:
- Check Lambda function logs for errors
- Verify your function code is working correctly
- Ensure the event payload is compatible with your function
## Best Practices
1. **Run Multiple Iterations** - Use at least 10 iterations for statistically valid results
2. **Consistent Configuration** - Use the same parameters when comparing measurements
3. **Warm Up First** - For warm start measurements, the first invocation may be slower
4. **Clean Environment** - Delete test functions after measurements to avoid costs
5. **Monitor Costs** - Lambda invocations and CloudWatch Logs queries incur AWS charges
6. **Test Realistic Payloads** - Use event payloads that match your production workload
## Limitations
- **Minimal Error Handling** - Scripts follow the KISS principle with basic error handling
- **Sequential Execution** - Measurements are performed sequentially, not in parallel
- **CloudWatch Latency** - Log retrieval adds 2-3 seconds per measurement
- **Environment Variable Limit** - Cold start forcing via environment variables has AWS limits
- **No Concurrent Invocations** - Scripts don't test concurrent execution scenarios
## Contributing
These scripts are designed to be simple and easy to modify. Feel free to:
- Adjust retry logic in `get_duration_from_logs()`
- Modify default values in `parse_arguments()`
- Add additional statistics calculations
- Implement alternative cold start forcing mechanisms
## License
This project is provided as-is for measuring AWS Lambda performance.
## Additional Resources
- [AWS Lambda Documentation](https://docs.aws.amazon.com/lambda/)
- [AWS Lambda Cold Starts](https://aws.amazon.com/blogs/compute/operating-lambda-performance-optimization-part-1/)
- [CloudWatch Logs Documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/)
+90
View File
@@ -0,0 +1,90 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright SwiftAWSLambdaRuntime project authors
## Copyright (c) Amazon.com, Inc. or its affiliates.
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
set -e
# Cold Start Measurement Script
# Measures Lambda cold start times (Init Duration) by forcing new execution environments
# Source shared utility functions
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=scripts/lambda-performance/shared-utils.sh
source "$SCRIPT_DIR/shared-utils.sh"
# Parse command-line arguments
parse_arguments "$@"
# Validate required parameters and dependencies
if ! validate_parameters; then
echo ""
echo "Usage: $0 --zip-file <path> --role-arn <arn> [options]"
echo ""
echo "Required:"
echo " --zip-file <path> Path to Lambda deployment package (ZIP file)"
echo " --role-arn <arn> IAM role ARN for Lambda execution"
echo ""
echo "Optional:"
echo " --runtime <runtime> Lambda runtime (default: provided.al2023)"
echo " --iterations <n> Number of measurements (default: 10)"
echo " --event-file <path> Path to JSON event payload file"
echo " --function-name <name> Lambda function name (default: lambda-perf-test)"
echo " --handler <handler> Lambda handler (default: bootstrap)"
echo ""
exit 1
fi
echo "=== Cold Start Measurement ==="
echo "Function: $FUNCTION_NAME"
echo "Runtime: $RUNTIME"
echo "Iterations: $ITERATIONS"
echo ""
# Deploy Lambda function
deploy_function "$FUNCTION_NAME" "$ZIP_FILE" "$RUNTIME" "$HANDLER" "$ROLE_ARN"
echo ""
echo "=== Starting Measurements ==="
echo ""
# Array to store measurements
measurements=()
# Measurement loop for N iterations
for i in $(seq 1 "$ITERATIONS"); do
echo "Iteration $i/$ITERATIONS"
# Invoke function with metric_type="cold" to get Init Duration
duration=$(invoke_and_get_duration "$FUNCTION_NAME" "$EVENT_PAYLOAD" "cold")
if [ "$duration" == "0" ] || [ -z "$duration" ]; then
echo " WARNING: Failed to get Init Duration, skipping measurement" >&2
else
echo " Init Duration: ${duration}ms"
measurements+=("$duration")
fi
# Force cold start for next iteration (except on last iteration)
if [ "$i" -lt "$ITERATIONS" ]; then
echo " Forcing cold start..."
force_cold_start "$FUNCTION_NAME"
fi
echo ""
done
# Calculate and display statistics
echo "=== Cold Start Results ==="
calculate_statistics "${measurements[@]}"
+97
View File
@@ -0,0 +1,97 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright SwiftAWSLambdaRuntime project authors
## Copyright (c) Amazon.com, Inc. or its affiliates.
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
set -e
# Warm Start Measurement Script
# Measures Lambda warm start times (Duration) by reusing the same execution environment
# Source shared utility functions
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=scripts/lambda-performance/shared-utils.sh
source "$SCRIPT_DIR/shared-utils.sh"
# Parse command-line arguments
parse_arguments "$@"
# Validate required parameters and dependencies
if ! validate_parameters; then
echo ""
echo "Usage: $0 --zip-file <path> --role-arn <arn> [options]"
echo ""
echo "Required:"
echo " --zip-file <path> Path to Lambda deployment package (ZIP file)"
echo " --role-arn <arn> IAM role ARN for Lambda execution"
echo ""
echo "Optional:"
echo " --runtime <runtime> Lambda runtime (default: provided.al2023)"
echo " --iterations <n> Number of measurements (default: 10)"
echo " --event-file <path> Path to JSON event payload file"
echo " --function-name <name> Lambda function name (default: lambda-perf-test)"
echo " --handler <handler> Lambda handler (default: bootstrap)"
echo ""
exit 1
fi
echo "=== Warm Start Measurement ==="
echo "Function: $FUNCTION_NAME"
echo "Runtime: $RUNTIME"
echo "Iterations: $ITERATIONS"
echo ""
# Deploy Lambda function
deploy_function "$FUNCTION_NAME" "$ZIP_FILE" "$RUNTIME" "$HANDLER" "$ROLE_ARN"
echo ""
echo "=== Warming Up Function ==="
echo "Making initial invocation to warm up execution environment..."
echo ""
# Make initial warm-up call (this will be a cold start, so we discard it)
warmup_duration=$(invoke_and_get_duration "$FUNCTION_NAME" "$EVENT_PAYLOAD" "warm")
if [ "$warmup_duration" != "0" ] && [ -n "$warmup_duration" ]; then
echo "Warm-up complete (Duration: ${warmup_duration}ms)"
else
echo "WARNING: Warm-up invocation completed but duration not captured"
fi
echo ""
echo "=== Starting Measurements ==="
echo ""
# Array to store measurements
measurements=()
# Measurement loop for N iterations (all should be warm starts now)
for i in $(seq 1 "$ITERATIONS"); do
echo "Iteration $i/$ITERATIONS"
# Invoke function with metric_type="warm" to get Duration (no cold start forcing)
duration=$(invoke_and_get_duration "$FUNCTION_NAME" "$EVENT_PAYLOAD" "warm")
if [ "$duration" == "0" ] || [ -z "$duration" ]; then
echo " WARNING: Failed to get Duration, skipping measurement" >&2
else
echo " Duration: ${duration}ms"
measurements+=("$duration")
fi
echo ""
done
# Calculate and display statistics
echo "=== Warm Start Results ==="
calculate_statistics "${measurements[@]}"
+253
View File
@@ -0,0 +1,253 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftAWSLambdaRuntime open source project
##
## Copyright SwiftAWSLambdaRuntime project authors
## Copyright (c) Amazon.com, Inc. or its affiliates.
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
# Shared utility functions for Lambda measurement scripts
# Deploy or update a Lambda function
# Arguments: function_name, zip_file, runtime, handler, role_arn
deploy_function() {
local function_name=$1
local zip_file=$2
local runtime=$3
local handler=$4
local role_arn=$5
echo "Deploying function: $function_name"
# Check if function exists
if aws lambda get-function --function-name "$function_name" &>/dev/null; then
echo "Function exists, updating code..."
# Update existing function
aws lambda update-function-code \
--function-name "$function_name" \
--zip-file "fileb://$zip_file" \
> /dev/null
else
echo "Function does not exist, creating..."
# Create new function with arm64 architecture
aws lambda create-function \
--function-name "$function_name" \
--runtime "$runtime" \
--role "$role_arn" \
--handler "$handler" \
--architectures arm64 \
--zip-file "fileb://$zip_file" \
> /dev/null
fi
# Wait for function to be active
echo "Waiting for function to be active..."
aws lambda wait function-active --function-name "$function_name"
echo "Function deployed successfully"
}
# Invoke Lambda function and extract duration from LogResult
# Arguments: function_name, event_payload, metric_type ("cold" or "warm")
# Returns: duration in milliseconds
invoke_and_get_duration() {
local function_name=$1
local event_payload=$2
local metric_type=$3 # "cold" or "warm"
local output_file="/tmp/lambda-response-$.json"
# Invoke function with --log-type Tail to get logs in response
local encoded_payload
encoded_payload=$(echo "$event_payload" | base64)
aws lambda invoke \
--function-name "$function_name" \
--payload "$encoded_payload" \
--log-type Tail \
"$output_file" > /tmp/invoke-response-$.json 2>/dev/null
# Extract and decode LogResult (base64-encoded logs)
local log_result
log_result=$(jq -r '.LogResult // empty' /tmp/invoke-response-$.json 2>/dev/null | base64 -d 2>/dev/null)
# Parse the REPORT line to extract timing using sed (BSD-compatible)
local duration=""
if [ "$metric_type" == "cold" ]; then
# Extract Init Duration for cold starts
duration=$(echo "$log_result" | grep "^REPORT" | sed -n 's/.*Init Duration: \([0-9.]*\) ms.*/\1/p' | head -1)
else
# Extract Duration for warm starts (match first Duration, not Init Duration)
duration=$(echo "$log_result" | grep "^REPORT" | sed -n 's/.*Duration: \([0-9.]*\) ms.*/\1/p' | head -1)
fi
# Clean up temp files
rm -f "$output_file" /tmp/invoke-response-$.json
# Return duration or 0 if not found
if [ -z "$duration" ]; then
echo "0"
else
echo "$duration"
fi
}
# Force a cold start by updating environment variable
# Arguments: function_name
force_cold_start() {
local function_name=$1
local timestamp
timestamp=$(date +%s)
# Update environment variable to force new execution environment
aws lambda update-function-configuration \
--function-name "$function_name" \
--environment "Variables={FORCE_COLD_START=$timestamp}" \
> /dev/null 2>&1
# Wait for update to complete
aws lambda wait function-updated --function-name "$function_name"
# Additional wait to ensure environment is recycled
sleep 2
}
# Calculate and display statistics for measurements
# Arguments: array of duration measurements
calculate_statistics() {
local measurements=("$@")
local count=${#measurements[@]}
if [ "$count" -eq 0 ]; then
echo "No measurements to calculate"
return
fi
local sum=0
local min=${measurements[0]}
local max=${measurements[0]}
for duration in "${measurements[@]}"; do
sum=$(echo "$sum + $duration" | bc)
if (( $(echo "$duration < $min" | bc -l) )); then
min=$duration
fi
if (( $(echo "$duration > $max" | bc -l) )); then
max=$duration
fi
done
local avg
avg=$(echo "scale=2; $sum / $count" | bc)
echo ""
echo "=== Statistics ==="
echo " Count: $count"
echo " Average: ${avg}ms"
echo " Min: ${min}ms"
echo " Max: ${max}ms"
}
# Parse command-line arguments
# Sets global variables for script configuration
parse_arguments() {
# Default values
RUNTIME="${RUNTIME:-provided.al2023}"
ITERATIONS="${ITERATIONS:-10}"
FUNCTION_NAME="${FUNCTION_NAME:-lambda-perf-test}"
HANDLER="${HANDLER:-bootstrap}"
# a simple String payload to use with the HelloWorld function
EVENT_PAYLOAD="${EVENT_PAYLOAD:-\"Performance test\"}"
while [[ $# -gt 0 ]]; do
case $1 in
--zip-file)
ZIP_FILE="$2"
shift 2
;;
--runtime)
RUNTIME="$2"
shift 2
;;
--iterations)
ITERATIONS="$2"
shift 2
;;
--event-file)
EVENT_FILE="$2"
shift 2
;;
--function-name)
FUNCTION_NAME="$2"
shift 2
;;
--handler)
HANDLER="$2"
shift 2
;;
--role-arn)
ROLE_ARN="$2"
shift 2
;;
*)
echo "Unknown option: $1" >&2
return 1
;;
esac
done
}
# Validate required parameters and dependencies
validate_parameters() {
local errors=0
# Check required parameters
if [ -z "$ZIP_FILE" ]; then
echo "ERROR: --zip-file is required" >&2
errors=$((errors + 1))
fi
if [ -z "$ROLE_ARN" ]; then
echo "ERROR: --role-arn is required" >&2
errors=$((errors + 1))
fi
# Validate ZIP file exists
if [ -n "$ZIP_FILE" ] && [ ! -f "$ZIP_FILE" ]; then
echo "ERROR: ZIP file not found: $ZIP_FILE" >&2
errors=$((errors + 1))
fi
# Handle event payload from file or use default
if [ -n "$EVENT_FILE" ]; then
if [ ! -f "$EVENT_FILE" ]; then
echo "ERROR: Event file not found: $EVENT_FILE" >&2
errors=$((errors + 1))
else
EVENT_PAYLOAD=$(cat "$EVENT_FILE")
fi
fi
# Check for required tools
if ! command -v aws &> /dev/null; then
echo "ERROR: AWS CLI is not installed or not in PATH" >&2
errors=$((errors + 1))
fi
if ! command -v jq &> /dev/null; then
echo "ERROR: jq is not installed or not in PATH" >&2
errors=$((errors + 1))
fi
if ! command -v bc &> /dev/null; then
echo "ERROR: bc is not installed or not in PATH" >&2
errors=$((errors + 1))
fi
return $errors
}