Skip to content

Commit 66a37ea

Browse files
committed
resolve all review comments
Principally, this PR: - makes security_group and ssh_key configurable via env variables - generates them automatically if unspecified - adds some checks and comments - adds x86 instances.
1 parent c51145c commit 66a37ea

File tree

2 files changed

+167
-32
lines changed

2 files changed

+167
-32
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ outputs
66
tags
77
compile_commands.json
88
.cache
9+
*.log
910
**/__pycache__

scripts/aws_tests.bash

Lines changed: 166 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,150 @@
11
#!/bin/bash
22

3-
# Preliminary setup
4-
# - Install AWS CLI v2 (perhaps it works on v1, untested):
5-
# - on Arch Linux: paru -S aws-cli-v2
6-
# - Configure AWS Credentials: aws configure
3+
# This script launches EC2 instances to benchmark your project.
4+
#
5+
# Requirements:
6+
# - The programs `git`, `ssh`, `rsync`, and `aws` must be installed.
7+
# - AWS CLI v2 installed and configured (`aws configure`)
8+
# - An EC2-compatible SSH key must exist in AWS, or the script will generate one (and save locally).
9+
#
10+
# Required AWS IAM permissions:
11+
# - ec2:RunInstances
12+
# - ec2:TerminateInstances
13+
# - ec2:DescribeInstances
14+
# - ec2:DescribeVpcs
15+
# - ec2:CreateSecurityGroup
16+
# - ec2:DeleteSecurityGroup
17+
# - ec2:AuthorizeSecurityGroupIngress
18+
#
19+
# Optional environment variables:
20+
# AWS_KEY_NAME use an existing key pair instead of creating one
21+
# AWS_SECURITY_GROUP use an existing SG instead of creating one
22+
23+
set -euo pipefail
24+
25+
# --------------------
26+
# User-configurable variables
27+
# --------------------
28+
29+
# Ubuntu 24.04 AMI IDs for x86_64 and aarch64 architectures
30+
declare -A AMI_MAP=(
31+
["x86_64"]="ami-020cba7c55df1f615"
32+
["aarch64"]="ami-07041441b708acbd6"
33+
)
34+
35+
# We need biggest (metal) instances to access perf events on x86
36+
INSTANCES_x86_64=(
37+
"c5n.metal" # Skylake
38+
"c6i.metal" # Ice Lake
39+
"c7i.metal-24xl" # Sapphire Rapids
40+
"c5a.24xlarge" # EPYC Zen 2
41+
"c6a.metal" # EPYC Zen 3
42+
"c7a.metal-48xl" # EPYC Zen 4
43+
)
44+
INSTANCES_aarch64=(
45+
"c6g.medium" # Graviton 2 - Neoverse N1
46+
"c7g.medium" # Graviton 3 - Neoverse V1
47+
"c8g.medium" # Graviton 4 - Neoverse V2
48+
)
749

8-
set -e # Exit script on first error
50+
VOLUME_SIZE=10 # in GB
951

10-
AMI_ID_x86_64="ami-020cba7c55df1f615"
11-
AMI_ID_aarch64="ami-07041441b708acbd6"
52+
KEY_NAME="${AWS_KEY_NAME:-aws_auto}" # Key path is assumed to be ~/.ssh/${KEY_NAME}.pem
53+
SECURITY_GROUP="${AWS_SECURITY_GROUP:-}"
1254

13-
INSTANCES_x86_64=()
14-
INSTANCES_aarch64=("c6g.medium" "c7g.medium" "c8g.medium")
55+
# --------------------
56+
# Internal variables (do not modify)
57+
# --------------------
1558

16-
KEY_NAME="openssh"
17-
KEY_PATH="~/.ssh/openssh.pem"
59+
KEY_PATH="$HOME/.ssh/${KEY_NAME}.pem"
1860
SSH_COMMAND="ssh -i ${KEY_PATH} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
19-
SECURITY_GROUP="sg-0315466a0d7fc99e1"
20-
VOLUME_SIZE=10 # in GB
2161

22-
PROJECT_DIR=$(basename $(pwd))
62+
PROJECT_DIR=$(basename "$(git rev-parse --show-toplevel)")
63+
CREATED_SECURITY_GROUP=""
64+
65+
# Cleanup function to delete created security group on exit
66+
cleanup() {
67+
if [ -n "${CREATED_SECURITY_GROUP}" ]; then
68+
echo "Cleaning up security group: ${CREATED_SECURITY_GROUP}"
69+
aws ec2 delete-security-group --group-id "${CREATED_SECURITY_GROUP}" || true
70+
fi
71+
}
72+
73+
check_prerequisites() {
74+
if ((BASH_VERSINFO[0] < 4)); then
75+
echo "Error: This script requires Bash version 4 or higher." >&2
76+
exit 1
77+
fi
78+
79+
for cmd in git ssh rsync aws; do
80+
if ! command -v "$cmd" >/dev/null 2>&1; then
81+
echo "Error: Required command '$cmd' is not installed." >&2
82+
exit 1
83+
fi
84+
done
85+
86+
if ! git rev-parse --show-toplevel >/dev/null 2>&1; then
87+
echo "Error: This script must be run from within a Git repository." >&2
88+
exit 1
89+
fi
90+
91+
if ! aws sts get-caller-identity >/dev/null 2>&1; then
92+
echo "Error: AWS credentials not configured. Run 'aws configure'." >&2
93+
exit 1
94+
fi
95+
}
96+
97+
create_key_pair() {
98+
if aws ec2 describe-key-pairs --key-names "${KEY_NAME}" >/dev/null 2>&1; then
99+
echo "Using existing AWS key pair: ${KEY_NAME}"
100+
return
101+
fi
102+
103+
echo "Creating new AWS key pair named ${KEY_NAME}"
104+
mkdir -p ~/.ssh
105+
aws ec2 create-key-pair --key-name "$KEY_NAME" \
106+
--query 'KeyMaterial' --output text > "$KEY_PATH"
107+
chmod 400 "$KEY_PATH"
108+
echo "Created and saved key pair private key to $KEY_PATH"
109+
}
110+
111+
create_security_group() {
112+
if [ -n "${SECURITY_GROUP}" ]; then
113+
echo "Using existing security group: ${SECURITY_GROUP}"
114+
return
115+
fi
116+
117+
echo "Creating a new security group for SSH access..."
118+
VPC_ID=$(aws ec2 describe-vpcs \
119+
--filters Name=isDefault,Values=true \
120+
--query "Vpcs[0].VpcId" \
121+
--output text)
122+
123+
CREATED_SECURITY_GROUP=$(aws ec2 create-security-group \
124+
--group-name ssh-public-access \
125+
--description "Allow SSH access from anywhere (0.0.0.0/0)" \
126+
--vpc-id "${VPC_ID}" \
127+
--query "GroupId" \
128+
--output text)
129+
130+
aws ec2 authorize-security-group-ingress \
131+
--group-id "${CREATED_SECURITY_GROUP}" \
132+
--protocol tcp \
133+
--port 22 \
134+
--cidr 0.0.0.0/0
135+
136+
SECURITY_GROUP="${CREATED_SECURITY_GROUP}"
137+
echo "Created security group: ${SECURITY_GROUP}"
138+
}
139+
140+
get_arch() {
141+
local instance_name="$1"
142+
if printf '%s\n' "${INSTANCES_aarch64[@]}" | grep -qx "$instance_name"; then
143+
echo "aarch64"
144+
else
145+
echo "x86_64"
146+
fi
147+
}
23148

24149
process_instance() {
25150
INSTANCE_NAME=$1
@@ -41,8 +166,7 @@ process_instance() {
41166

42167
PUBLIC_IP=$(aws ec2 describe-instances \
43168
--instance-ids ${INSTANCE_ID} \
44-
--query "Reservations[0].Instances[0].PublicIpAddress" \
45-
--output text)
169+
--query "Reservations[0].Instances[0].PublicIpAddress" --output text)
46170
echo "Instance ${INSTANCE_ID} public IP: ${PUBLIC_IP}"
47171

48172
git ls-files -z | rsync -avz --partial --progress --from0 --files-from=- -e "${SSH_COMMAND}" \
@@ -53,10 +177,12 @@ process_instance() {
53177
54178
echo "Updating and installing dependencies on ${INSTANCE_NAME}..."
55179
sudo apt update
56-
sudo DEBIAN_FRONTEND=noninteractive \
57-
apt install -y linux-tools-common linux-tools-generic \
58-
g++ clang cmake python3
59-
echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
180+
sudo DEBIAN_FRONTEND=noninteractive apt install -y \
181+
linux-tools-common linux-tools-generic g++ clang cmake python3
182+
183+
# Enable access to perf events for benchmarking
184+
# Must use `sudo tee` since shell redirection (`>`) is not affected by sudo
185+
echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid > /dev/null
60186
61187
echo "Saving some info about the environment..."
62188
mkdir -p outputs
@@ -84,17 +210,25 @@ EOF
84210
echo "Terminated instance: ${INSTANCE_ID}"
85211
}
86212

87-
echo "Launching ${#INSTANCES_aarch64[@]} aarch64 instances and ${#INSTANCES_x86_64[@]} x86_64 instances in parallel..."
88-
for INSTANCE_NAME in "${INSTANCES_x86_64[@]}" "${INSTANCES_aarch64[@]}"; do
89-
if printf '%s\n' "${INSTANCES_aarch64[@]}" | grep -qx "${INSTANCE_NAME}"; then
90-
AMI_ID=${AMI_ID_aarch64}
91-
else
92-
AMI_ID=${AMI_ID_x86_64}
93-
fi
213+
main () {
214+
trap cleanup EXIT
215+
check_prerequisites
216+
create_key_pair
217+
create_security_group
94218

95-
process_instance "${INSTANCE_NAME}" "${AMI_ID}" 2>&1 | tee "${INSTANCE_NAME}.log" &
96-
done
219+
echo "Launching ${#INSTANCES_aarch64[@]} aarch64 instances and ${#INSTANCES_x86_64[@]} x86_64 instances in parallel..."
220+
for INSTANCE_NAME in "${INSTANCES_x86_64[@]}" "${INSTANCES_aarch64[@]}"; do
221+
ARCH=$(get_arch "$INSTANCE_NAME")
222+
AMI_ID="${AMI_MAP[$ARCH]}"
223+
224+
process_instance "${INSTANCE_NAME}" "${AMI_ID}" 2>&1 | tee "${INSTANCE_NAME}.log" &
225+
done
226+
227+
# Wait for all background jobs to finish
228+
wait
229+
echo "All instances completed."
230+
}
97231

98-
# Wait for all background jobs to finish
99-
wait
100-
echo "All instances completed."
232+
if [ "$0" = "$BASH_SOURCE" ] ; then
233+
main
234+
fi

0 commit comments

Comments
 (0)