EC2 AMD CPU 的 SEV-SNP 指令集的开启方法与性能测试

本文介绍在 Amazon EC2 的共享租户(shared tenancy)上开启 AMD SEV-SNP 的方法,并以 ffmpeg 视频转码为负载,对比开启与未开启该特性的 EC2 实例的性能差异。

本文介绍了什么是 AMD SEV-SNP 指令集,以及使用条件、使用场景等。本人给出了 Amazon EC2 的共享租户(shared tenancy)上开启 AMD SEV-SNP 的方法,并以 ffmpeg 视频转码为负载,对比开启与未开启该特性的 EC2 实例的性能差异。

一、背景

1、什么是 AMD SEV-SNP

AMD SEV-SNP,全称是 AMD Secure Encrypted Virtualization-Secure Nested Paging,是 AMD EPYC 处理器提供的机密计算(Confidential Computing)特性。在云环境中,虚拟机运行在云厂商的虚拟化层(Hypervisor)之上,传统模型默认信任 Hypervisor 及主机上的特权软件。机密计算要解决的问题是:在不信任主机特权软件的前提下,保证虚拟机内存中的数据不被读取或篡改,并且能够向第三方证明当前运行的是哪一份代码、运行在真实的 AMD 硬件上。

AMD 的这一能力经历了三代演进:

  • SEV(Secure Encrypted Virtualization):由处理器内置的 AMD 安全处理器(AMD Secure Processor)为每台虚拟机管理独立的内存加密密钥,Hypervisor 读到的只是密文。
  • SEV-ES(Encrypted State):在 SEV 基础上,虚拟机退出到 Hypervisor 时 CPU 寄存器状态也被加密,Hypervisor 无法读取或修改寄存器。
  • SEV-SNP(Secure Nested Paging):在前两者基础上增加内存完整性保护。处理器维护一张 RMP(Reverse Map Table,反向映射表),记录每个物理页归属哪台虚拟机、映射到哪个客户机物理地址。Hypervisor 即使能够写内存,也无法把页重新映射、重放旧数据或篡改受保护虚拟机的页,违反 RMP 规则的访问会被硬件拒绝。

需要区分两个容易混淆的概念。AWS 文档说明,自 AMD EPYC(Milan)、AWS Graviton2 和 Intel Xeon Scalable(Ice Lake)起,EC2 实例内存始终加密,这一能力无需开启 SEV-SNP 即可获得。两者的区别在于加密密钥与访问控制归谁管理:默认的内存加密防护的是物理层面的内存窃取,对 Hypervisor 透明;SEV-SNP 则把虚拟机的密钥交给 AMD 安全处理器管理,并通过 RMP 在硬件层面阻止 Hypervisor 访问或篡改虚拟机内存。因此,在 AWS 上开启 SEV-SNP 带来的增量价值主要是两点:

  • 证明(Attestation):实例可以向 CPU 请求一份签名的证明报告(attestation report),其中包含启动度量(launch measurement),即实例初始内存内容与初始 vCPU 状态的哈希。共享租户上报告由 VLEK(Versioned Loaded Endorsement Key,AMD 为 AWS 签发的版本化签名密钥)签名,Dedicated Host 上由 VCEK(Versioned Chip Endorsement Key,每颗芯片唯一的签名密钥)签名,二者都可以追溯到 AMD 根证书。
  • 由硬件强制的虚拟机隔离:内存访问控制不依赖 Hypervisor 的正确性,适用于对“云厂商运维人员与主机软件也不可见”有合规要求的场景。

本文的重点是开启方法与性能影响,不展开远程证明流程。远程证明可参考 AWS 文档中基于 snpguest 工具的步骤,见另外的文档。

2、在 AWS 云上支持的机型

AMD SEV-SNP 只在第三代 AMD EPYC(Milan,型号 7R13)的部分机型上提供。共享租户与 Dedicated Host 支持的机型相同,区别在于区域和计费方式。

机型系列 支持的规格
通用型 M6a m6a.large、m6a.xlarge、m6a.2xlarge、m6a.4xlarge、m6a.8xlarge
计算优化型 C6a c6a.large、c6a.xlarge、c6a.2xlarge、c6a.4xlarge、c6a.8xlarge、c6a.12xlarge、c6a.16xlarge
内存优化型 R6a r6a.large、r6a.xlarge、r6a.2xlarge、r6a.4xlarge

M6a 与 R6a 的更大规格、以及 M7a、C7a 等第四代 EPYC(Genoa)机型,当前不支持 SEV-SNP。

两种租户方式的对比如下:

对比 共享租户 Dedicated Host
支持区域 仅美国东部(俄亥俄,us-east-2)和欧洲(爱尔兰,eu-west-1) 所有提供 AMD 实例的商业区域(2026 年 7 月发布)
SEV-SNP 费用 额外收取按需单价 10% 的小时费用 不额外收费,但需按整台主机付费
证明报告签名密钥 VLEK(Versioned Loaded Endorsement Key) VCEK(Versioned Chip Endorsement Key)
主机固件 由 AWS 管理 分配主机时更新到最新固件,更新需重新分配主机
维护事件 提前 14 天通知,需要手动停止再启动实例以迁移到新主机 与其他 Dedicated Host 维护事件相同

共享租户的附加费用按所选机型的按需(On-Demand)单价的 10% 计算,作为一项独立的 EC2 费用出现在账单中。预留实例(Reserved Instances)、Savings Plans 和操作系统许可费都不影响这项费用。Spot 实例开启 SEV-SNP 时,附加费同样按按需单价的 10% 计算,而不是按 Spot 价格计算,因此 Spot 折扣越大,附加费占比越高。

使用 SEV-SNP 还有以下限制:

  • 只能在启动实例时开启,开启后在实例整个生命周期内无法关闭。
  • 只能更改为同样支持 SEV-SNP 的实例类型。
  • 不支持休眠(Hibernation),也不能与 AWS Nitro Enclaves 同时使用。
  • AMI 的启动模式必须为 uefi 或 uefi-preferred,操作系统需支持 SEV-SNP。AWS 文档列出的系统为 Amazon Linux 2023、RHEL 9.3、SLES 15 SP4 以及 Ubuntu 23.04 及以上版本。
  • EC2 控制台不显示实例是否开启了 SEV-SNP,需通过 AWS CLI 或 CloudTrail 确认。

3、本项目实验环境

本项目最初计划使用东京区域。由于东京区域只能通过 Dedicated Host 使用 SEV-SNP,而本项目为控制成本选择共享租户,因此测试区域改为美国东部(俄亥俄,us-east-2)。在东京以共享租户方式启动会被 API 直接拒绝,详见第二章第 1 节。

实验共使用两台 EC2 实例,一台开启 SEV-SNP,一台未开启,配置如下:

项目 实验组 sev-snp-on 对比组 sev-snp-off
用途 开启 SEV-SNP 的测试机 未开启 SEV-SNP 的对比机
实例 ID i-0c43016da15a0c159 i-0a0445cf92ef9017d
可用区 us-east-2a(use2-az1) us-east-2b(use2-az2)
机型 c6a.2xlarge(8 vCPU,16 GiB) c6a.2xlarge
处理器 AMD EPYC 7R13 AMD EPYC 7R13
SEV-SNP 开启 未开启

两台实例的共同配置如下:

  • 区域:美国东部(俄亥俄,us-east-2),默认 VPC。
  • AMI:Amazon Linux 2023,al2023-ami-2023.12.20261102.0-kernel-6.18-x86_64(ami-02dae70ab25064279),启动模式 uefi-preferred,内核 6.18.56-125.164.amzn2023.x86_64。
  • 存储:30 GiB gp3 根卷。
  • 访问方式:AWS Systems Manager(SSM)Run Command,实例只附加 AmazonSSMManagedInstanceCore 权限,安全组不开放任何入站端口。
  • 测试软件:ffmpeg 7.0.2 静态构建(两台实例的二进制 MD5 一致),测试片源为 Blender 基金会发布的开源影片 Big Buck Bunny 1080p 30fps。

本文用到的脚本保存在项目的 performace-test-script/ 目录下。下面转向创建实例。

二、创建支持 AMD SEV-SNP 的 EC2

1、确认区域与机型支持

首先查询区域内支持 SEV-SNP 的实例类型。执行如下命令:

aws ec2 describe-instance-types --region us-east-2 \
  --filters Name=processor-info.supported-features,Values=amd-sev-snp \
  --query 'InstanceTypes[].InstanceType' --output text

返回结果如下:

c6a.8xlarge	c6a.large	c6a.xlarge	c6a.2xlarge	c6a.4xlarge	c6a.12xlarge	c6a.16xlarge
m6a.xlarge	m6a.4xlarge	m6a.2xlarge	m6a.8xlarge	m6a.large
r6a.large	r6a.2xlarge	r6a.4xlarge	r6a.xlarge

需要注意,这条命令在东京区域(ap-northeast-1)返回同样的机型列表,但这只说明该机型的处理器具备 SEV-SNP 能力,不代表该区域支持共享租户方式。用 --dry-run 在东京区域以共享租户方式试启动,可以直接验证。执行如下命令:

aws ec2 run-instances --region ap-northeast-1 --dry-run \
  --image-id ami-0c051224e18c11f2e \
  --instance-type c6a.xlarge \
  --cpu-options AmdSevSnp=enabled

返回结果如下:

aws: [ERROR]: An error occurred (UnsupportedOperation) when calling the RunInstances operation: AMD SEV-SNP is not supported in this Region. Either launch the instance in a supported Region or do not specify a value for AmdSevSnp in CpuOptions.

因此,判断某区域能否以共享租户方式使用 SEV-SNP,应以 AWS 文档列出的区域或 --dry-run 结果为准,不能只看 describe-instance-types。

2、准备 AMI、安全组与实例角色

获取最新的 Amazon Linux 2023 AMI,并确认其启动模式。执行如下命令:

AMI=$(aws ssm get-parameter --region us-east-2 \
  --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 \
  --query Parameter.Value --output text)
aws ec2 describe-images --region us-east-2 --image-ids $AMI \
  --query 'Images[0].[ImageId,Name,BootMode]' --output text

返回结果如下:

ami-02dae70ab25064279	al2023-ami-2023.12.20261102.0-kernel-6.18-x86_64	uefi-preferred

BootMode 为 uefi-preferred,满足 SEV-SNP 的启动模式要求。如果使用自定义 AMI,启动模式为 legacy-bios 时无法开启 SEV-SNP。

接下来创建一个只允许出站、不开放入站的安全组,供 SSM Agent 访问 SSM 服务端点和下载测试软件。执行如下命令:

aws ec2 create-security-group --region us-east-2 \
  --vpc-id <your-vpc-id> \
  --group-name sev-snp-test-sg \
  --description "SEV-SNP benchmark, egress only" \
  --tag-specifications 'ResourceType=security-group,Tags=[{Key=Project,Value=AMD-SEV-SNP}]' \
  --query GroupId --output text

返回结果如下:

sg-06e01c759161da241

新建的安全组默认允许全部出站流量,没有入站规则。实例角色使用已附加 AmazonSSMManagedInstanceCore 托管策略的实例配置文件,本文使用的是 Systems Manager 快速设置创建的 AmazonSSMRoleForInstancesQuickSetup。不需要创建密钥对,也不需要开放 22 端口。

3、启动开启 AMD SEV-SNP 的实例

开启 SEV-SNP 只需在 run-instances 中增加 --cpu-options AmdSevSnp=enabled 参数。实验组放在 us-east-2a。执行如下命令:

aws ec2 run-instances --region us-east-2 \
  --image-id ami-02dae70ab25064279 \
  --instance-type c6a.2xlarge \
  --cpu-options AmdSevSnp=enabled \
  --subnet-id <subnet-id-of-us-east-2a> \
  --security-group-ids sg-06e01c759161da241 \
  --iam-instance-profile Name=AmazonSSMRoleForInstancesQuickSetup \
  --block-device-mappings 'DeviceName=/dev/xvda,Ebs={VolumeSize=30,VolumeType=gp3}' \
  --metadata-options HttpTokens=required \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=sev-snp-on},{Key=Project,Value=AMD-SEV-SNP}]' \
  --query 'Instances[0].[InstanceId,Placement.AvailabilityZone,CpuOptions]' --output json

返回结果如下:

[
    "i-0c43016da15a0c159",
    "us-east-2a",
    {
        "CoreCount": 4,
        "ThreadsPerCore": 2,
        "AmdSevSnp": "enabled"
    }
]

返回的 CpuOptions 中出现 "AmdSevSnp": "enabled",说明请求已被接受。AWS 文档对共享租户只给出了 AWS CLI 与 PowerShell 的开启方法,本文全部使用 AWS CLI 操作。

注意:该参数只能在启动时设置。开启后无法关闭,也无法对已有实例补开。如果业务需要 SEV-SNP,应在启动模板(Launch Template)中固定该参数,避免 Auto Scaling 扩容出未开启的实例。

4、确认 AMD SEV-SNP 已开启

从 EC2 API 侧确认实例状态。执行如下命令:

aws ec2 describe-instances --region us-east-2 \
  --instance-ids i-0c43016da15a0c159 \
  --query 'Reservations[].Instances[].CpuOptions'

返回结果如下:

[
    {
        "CoreCount": 4,
        "ThreadsPerCore": 2,
        "AmdSevSnp": "enabled"
    }
]

如果返回中没有 AmdSevSnp 字段,说明该实例未开启 SEV-SNP。

仅看 API 还不够,还需要在操作系统内确认客户机内核实际启用了 SEV-SNP。实例启动约一分钟后 SSM Agent 变为 Online,即可下发命令。本文使用 performace-test-script/sysinfo.sh 采集系统信息,核心命令如下:

uname -r
lscpu | grep -E 'Model name|^CPU\(s\)|Thread|Core\(s\)|L3'
free -h | head -2
dmesg | grep -i -E 'sev|memory encryption'
ls -l /dev/sev-guest

脚本通过 SSM Run Command 下发。由于脚本含引号、管道等字符,直接用 --parameters "commands=..." 简写形式容易被 AWS CLI 按逗号拆分而报错,本文使用 performace-test-script/ssm_send.py 把整个脚本作为一个字符串写入请求 JSON,再以 --cli-input-json 提交。执行如下命令:

cd performace-test-script
python3 ssm_send.py us-east-2 sysinfo.sh i-0c43016da15a0c159

返回结果为 SSM 命令 ID,随后用 performace-test-script/ssm_get.sh 逐字段读取执行结果。执行如下命令:

zsh ssm_get.sh us-east-2 <command-id> i-0c43016da15a0c159

返回结果如下:

Status: Success
ResponseCode: 0
--- stdout
--- kernel
6.18.56-125.164.amzn2023.x86_64
--- cpu
CPU(s):                                  8
Model name:                              AMD EPYC 7R13 Processor
BIOS Model name:                         AMD EPYC 7R13 Processor
Thread(s) per core:                      2
Core(s) per socket:                      4
L3 cache:                                16 MiB (1 instance)
--- memory
               total        used        free      shared  buff/cache   available
Mem:            14Gi       226Mi        13Gi       0.0Ki       281Mi        13Gi
--- dmesg sev
[    1.128073] Memory Encryption Features active: AMD SEV SEV-ES SEV-SNP
[    1.128085] SEV: Status: SEV SEV-ES SEV-SNP 
[    1.257181] SEV: APIC: wakeup_secondary_cpu() replaced with wakeup_cpu_via_vmgexit()
[    1.472607] SEV: Using SNP CPUID table, 38 entries present.
[    1.472607] SEV: SNP running at VMPL0.
[    1.785651] SEV: SNP guest platform devices initialized.
[    1.867660] software IO TLB: Memory encryption is active and system is using DMA bounce buffers
[    5.365673] sev-guest sev-guest: Initialized SEV guest driver (using VMPCK0 communication key)
--- sev-guest device
crw-------. 1 root root 10, 259 Nov  2 09:47 /dev/sev-guest

各行输出的含义如下:

  • Memory Encryption Features active: AMD SEV SEV-ES SEV-SNP:客户机内核检测到 SEV、SEV-ES、SEV-SNP 三项特性均已激活。
  • SNP running at VMPL0:客户机运行在最高的虚拟机特权级 VMPL0(Virtual Machine Privilege Level 0)。
  • system is using DMA bounce buffers:由于客户机私有内存对设备不可见,网卡和 NVMe 磁盘的 DMA(Direct Memory Access)数据需要经过一块共享的 SWIOTLB(Software I/O Translation Lookaside Buffer)缓冲区中转。
  • /dev/sev-guest:SEV 客户机驱动已加载,远程证明工具 snpguest 通过该设备向 AMD 安全处理器请求证明报告。

还有一个容易忽略的差异:开启 SEV-SNP 的实例可用内存显示为 14 GiB,而未开启的同规格实例为 15 GiB。继续用 performace-test-script/diag.sh 查看内存与 SWIOTLB 信息,开启 SEV-SNP 的实例返回结果如下:

--- meminfo
MemTotal:       14773208 kB
--- swiotlb
[    0.000124] software IO TLB: SWIOTLB bounce buffer size adjusted to 946MB
[    0.074372] software IO TLB: area num 8.
[    0.074374] software IO TLB: SWIOTLB bounce buffer size roundup to 1024MB

未开启 SEV-SNP 的实例返回结果如下:

--- meminfo
MemTotal:       15993208 kB
--- swiotlb
[    0.016086] software IO TLB: area num 8.
[    0.316707] software IO TLB: mapped [mem 0x00000000b4482000-0x00000000b8482000] (64MB)

开启 SEV-SNP 后,内核把 SWIOTLB 中转缓冲区从默认的 64 MB 调整到 1024 MB,MemTotal 相应减少约 1.16 GiB,占未开启时 MemTotal 的约 7.6%。对 c6a.large(4 GiB)这类小规格实例,这部分内存占用的比例更高,容量规划时需要预留。

至此实验组实例创建完成。下面转向性能测试。

三、开启 AMD SEV-SNP 后的性能测试

1、测试方法

业内常用的 ffmpeg 基准测试是 Phoronix Test Suite 的 pts/ffmpeg,它使用 libx264 和 libx265 两种编码器,按 Live(直播)、Upload(上传)、Platform(平台转码)、Video On Demand(点播)等场景分别测试,以每秒处理帧数(fps)为指标。本文参照这一思路,并按 FFmpeg 官方 H.264、H.265 编码指南中的常用参数,设计了五个场景:

场景 负载说明 ffmpeg 关键参数 特征
T1 解码 H.264 1080p 解码,输出到空设备 -f null - 多线程,帧处理速度最快,内存吞吐密集
T2 H.264 点播 1080p 转码为 H.264 -c:v libx264 -preset medium -crf 23 多线程,计算密集
T3 H.265 点播 1080p 转码为 H.265 -c:v libx265 -preset medium -crf 28 多线程,计算更密集
T4 直播转码 1080p 缩放到 720p,固定码率 3 Mbps -vf scale=1280:720 -c:v libx264 -preset veryfast -b:v 3M 多线程,帧速快,线程间交接频繁
T5 单线程 与 T2 相同但限制为 1 个线程 -threads 1 单核计算性能

为保证结果可比,测试遵循以下原则:

  • 所有实例使用同一份 ffmpeg 静态构建和同一份测试片段,并用 MD5 校验确认一致,避免发行版软件包或编译选项不同带来的差异。
  • 测试片段从 Big Buck Bunny 1080p 30fps 原片第 60 秒处开始截取约 30 秒,以流复制方式生成,不重新编码,实际处理 902 帧。片段体积较小,首次运行后即驻留在页缓存中,磁盘读取对结果的影响可以忽略。
  • 每个场景连续运行 3 次,取 -benchmark 输出的 rtime(墙钟时间)中位数,fps 为帧数除以中位数时间。
  • 同一轮中的两台实例同时开始测试,并重复两轮,确认结果稳定。

2、准备 ffmpeg 与测试片源

Amazon Linux 2023 的软件源不包含 ffmpeg,本文使用 johnvansickle.com 发布的 ffmpeg 静态构建。Blender 基金会官网现以 zip 包形式提供 Big Buck Bunny 片源,直接下载 .mp4 地址会返回 404,需要下载 .mp4.zip 后解压。准备脚本 performace-test-script/prepare.sh 内容如下:

#!/bin/bash
# 准备 ffmpeg 静态构建与 Big Buck Bunny 1080p 测试片源
export HOME=/root
set -euo pipefail

mkdir -p /opt/bench && cd /opt/bench
dnf install -y -q xz tar unzip

# 1. 下载 ffmpeg 静态构建(两台实例使用同一份二进制,避免编译差异)
curl -sSfLO https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
tar xf ffmpeg-release-amd64-static.tar.xz
cp ffmpeg-*-amd64-static/ffmpeg ffmpeg-*-amd64-static/ffprobe /usr/local/bin/

# 2. 下载 Big Buck Bunny 1080p 30fps 片源,截取第 60 秒起 30 秒,去掉音轨
curl -sSfLO https://download.blender.org/demo/movies/BBB/bbb_sunflower_1080p_30fps_normal.mp4.zip
unzip -o -q bbb_sunflower_1080p_30fps_normal.mp4.zip
/usr/local/bin/ffmpeg -hide_banner -nostdin -loglevel error -y \
  -ss 60 -i bbb_sunflower_1080p_30fps_normal.mp4 -t 30 -c copy -an bbb_1080p_30s.mp4

# 3. 输出版本与校验值,确认两台实例的测试条件一致
/usr/local/bin/ffmpeg -hide_banner -version | head -1
md5sum /usr/local/bin/ffmpeg bbb_1080p_30s.mp4
/usr/local/bin/ffprobe -v error -select_streams v:0 -count_packets \
  -show_entries stream=codec_name,width,height,r_frame_rate,nb_read_packets \
  -of default=noprint_wrappers=1 bbb_1080p_30s.mp4

脚本首行设置 HOME=/root,因为 SSM Run Command 以 root 身份执行,但不保证设置了 HOME 环境变量。执行如下命令下发脚本:

python3 ssm_send.py us-east-2 prepare.sh i-0c43016da15a0c159

约一分钟后读取结果,返回结果如下:

Status: Success
ResponseCode: 0
--- stdout
ffmpeg version 7.0.2-static https://johnvansickle.com/ffmpeg/  Copyright (c) 2000-2024 the FFmpeg developers
d5c698e0e98e5cf7de03fe14bd1cda6a  /usr/local/bin/ffmpeg
88779f8ac07afa321e53313b34f1ddee  bbb_1080p_30s.mp4
codec_name=h264
width=1920
height=1080
r_frame_rate=30/1
nb_read_packets=1138

nb_read_packets=1138 大于 30 秒乘以 30 fps 的 900 帧,原因是流复制只能从关键帧处切分,片段中包含了起点之前的关键帧及其后续帧,播放时由 MP4 编辑列表(edit list)跳过。ffmpeg 转码时实际输出 902 帧,测试脚本以实际输出帧数计算 fps。

3、执行测试脚本

测试脚本 performace-test-script/bench.sh 内容如下:

#!/bin/bash
# ffmpeg 转码性能测试:每个场景运行 3 次,记录 -benchmark 输出的 rtime(墙钟时间)
export HOME=/root
set -uo pipefail
cd /opt/bench
FF=/usr/local/bin/ffmpeg
IN=bbb_1080p_30s.mp4
RUNS=3
mkdir -p out

run() {
  local name=$1; shift
  local list=() log t frames
  for i in $(seq 1 $RUNS); do
    log=$($FF -hide_banner -nostdin -y -benchmark "$@" 2>&1 | tr '\r' '\n')
    t=$(echo "$log" | grep -o 'rtime=[0-9.]*s' | tr -dc '0-9.')
    # 取 ffmpeg 最后一行进度中的实际输出帧数
    frames=$(echo "$log" | grep -o 'frame= *[0-9]*' | tail -1 | tr -dc '0-9')
    list+=("$t")
  done
  local med fps
  med=$(printf '%s\n' "${list[@]}" | sort -n | sed -n '2p')
  fps=$(awk -v f="$frames" -v t="$med" 'BEGIN{printf "%.2f", f/t}')
  printf '%-18s frames=%s runs=%s median=%ss fps=%s\n' "$name" "$frames" "$(IFS=,; echo "${list[*]}")" "$med" "$fps"
}

echo "host=$(hostname) nproc=$(nproc) start=$(date -u +%FT%TZ)"
# T1 解码:H.264 1080p 解码到空输出
run T1_decode_h264   -i "$IN" -f null -
# T2 点播转码:libx264 preset medium CRF 23
run T2_x264_medium   -i "$IN" -c:v libx264 -preset medium -crf 23 out/t2.mp4
# T3 点播转码:libx265 preset medium CRF 28
run T3_x265_medium   -i "$IN" -c:v libx265 -preset medium -crf 28 -x265-params log-level=error out/t3.mp4
# T4 直播转码:缩放到 720p,libx264 preset veryfast,固定码率 3 Mbps
run T4_x264_720p_live -i "$IN" -vf scale=1280:720 -c:v libx264 -preset veryfast -b:v 3M -maxrate 3M -bufsize 6M out/t4.mp4
# T5 单线程:libx264 preset medium,限制 1 个线程,观察单核性能
run T5_x264_1thread  -i "$IN" -c:v libx264 -preset medium -crf 23 -threads 1 out/t5.mp4

完整一轮测试约需 6 分钟,超过本地终端工具的单次等待时间,因此下发后需要分次查询状态,直到 Status 变为 Success。执行如下命令:

python3 ssm_send.py us-east-2 bench.sh i-0c43016da15a0c159
aws ssm get-command-invocation --region us-east-2 \
  --command-id <command-id> --instance-id i-0c43016da15a0c159 \
  --query Status --output text

实验组 sev-snp-on 第一轮返回结果如下:

host=ip-172-31-8-159.us-east-2.compute.internal nproc=8 start=2026-11-02T09:51:43Z
T1_decode_h264     frames=902 runs=1.624,1.620,1.672 median=1.624s fps=555.42
T2_x264_medium     frames=902 runs=13.531,13.269,13.306 median=13.306s fps=67.79
T3_x265_medium     frames=902 runs=26.207,26.020,26.250 median=26.207s fps=34.42
T4_x264_720p_live  frames=902 runs=7.151,7.023,6.937 median=7.023s fps=128.44
T5_x264_1thread    frames=902 runs=51.619,52.632,52.068 median=52.068s fps=17.32

第一轮开始约 8 分钟后进行第二轮测试,返回结果如下:

host=ip-172-31-8-159.us-east-2.compute.internal nproc=8 start=2026-11-02T10:00:02Z
T1_decode_h264     frames=902 runs=1.641,1.636,1.616 median=1.636s fps=551.34
T2_x264_medium     frames=902 runs=13.167,13.274,13.315 median=13.274s fps=67.95
T3_x265_medium     frames=902 runs=25.920,25.821,26.072 median=25.920s fps=34.80
T4_x264_720p_live  frames=902 runs=7.108,6.866,6.784 median=6.866s fps=131.37
T5_x264_1thread    frames=902 runs=53.087,51.968,52.028 median=52.028s fps=17.34

两轮结果的差异在 2.3% 以内,每轮 3 次运行之间的波动也在 5% 以内,数据稳定可用。单独看这组数据无法判断 SEV-SNP 的影响,请看下一章节的对比。

四、对比未开启 AMD SEV-SNP 的机型

1、创建对比组实例

对比组同样使用 c6a.2xlarge 和同一个 AMI,按要求换一个可用区,放在 us-east-2b,并且不指定 --cpu-options AmdSevSnp=enabled。执行如下命令:

aws ec2 run-instances --region us-east-2 \
  --image-id ami-02dae70ab25064279 \
  --instance-type c6a.2xlarge \
  --subnet-id <subnet-id-of-us-east-2b> \
  --security-group-ids sg-06e01c759161da241 \
  --iam-instance-profile Name=AmazonSSMRoleForInstancesQuickSetup \
  --block-device-mappings 'DeviceName=/dev/xvda,Ebs={VolumeSize=30,VolumeType=gp3}' \
  --metadata-options HttpTokens=required \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=sev-snp-off},{Key=Project,Value=AMD-SEV-SNP}]' \
  --query 'Instances[0].[InstanceId,Placement.AvailabilityZone,CpuOptions]' --output json

返回结果如下:

[
    "i-0a0445cf92ef9017d",
    "us-east-2b",
    {
        "CoreCount": 4,
        "ThreadsPerCore": 2
    }
]

CpuOptions 中没有 AmdSevSnp 字段,说明未开启 SEV-SNP。在操作系统内执行 performace-test-script/sysinfo.sh,返回结果如下:

--- kernel
6.18.56-125.164.amzn2023.x86_64
--- cpu
CPU(s):                                  8
Model name:                              AMD EPYC 7R13 Processor
BIOS Model name:                         AMD EPYC 7R13 Processor
Thread(s) per core:                      2
Core(s) per socket:                      4
L3 cache:                                16 MiB (1 instance)
--- memory
               total        used        free      shared  buff/cache   available
Mem:            15Gi       236Mi        14Gi       0.0Ki       281Mi        14Gi
--- dmesg sev
--- sev-guest device
ls: cannot access '/dev/sev-guest': No such file or directory

处理器型号、核数、三级缓存、内核版本与实验组完全一致,dmesg 中没有 SEV 相关信息,也不存在 /dev/sev-guest 设备。两组实例的 ffmpeg 二进制和测试片段 MD5 也相同(d5c698e0… 与 88779f8a…)。

2、执行相同测试

按第三章第 2 节和第 3 节的步骤,在对比组上运行 prepare.sh 和 bench.sh,与实验组同时开始。对比组 sev-snp-off 第一轮返回结果如下:

host=ip-172-31-19-32.us-east-2.compute.internal nproc=8 start=2026-11-02T09:51:43Z
T1_decode_h264     frames=902 runs=1.176,1.162,1.170 median=1.170s fps=770.94
T2_x264_medium     frames=902 runs=11.737,11.753,11.748 median=11.748s fps=76.78
T3_x265_medium     frames=902 runs=22.234,22.294,22.223 median=22.234s fps=40.57
T4_x264_720p_live  frames=902 runs=3.889,3.906,3.908 median=3.906s fps=230.93
T5_x264_1thread    frames=902 runs=48.705,48.229,49.049 median=48.705s fps=18.52

第二轮返回结果如下:

host=ip-172-31-19-32.us-east-2.compute.internal nproc=8 start=2026-11-02T10:00:01Z
T1_decode_h264     frames=902 runs=1.169,1.160,1.163 median=1.163s fps=775.58
T2_x264_medium     frames=902 runs=11.787,11.737,11.805 median=11.787s fps=76.52
T3_x265_medium     frames=902 runs=22.066,22.284,22.228 median=22.228s fps=40.58
T4_x264_720p_live  frames=902 runs=3.913,3.943,3.899 median=3.913s fps=230.51
T5_x264_1thread    frames=902 runs=48.423,49.252,48.340 median=48.423s fps=18.63

3、结果对比

下表的 fps 为两轮结果的平均值,变化率以对比组为基准:

场景 对比组 sev-snp-off(fps) 实验组 sev-snp-on(fps) 性能变化
T1 H.264 解码 773.26 553.38 -28.4%
T2 H.264 点播转码 76.65 67.87 -11.5%
T3 H.265 点播转码 40.58 34.61 -14.7%
T4 720p 直播转码 230.72 129.91 -43.7%
T5 单线程 H.264 18.57 17.33 -6.7%

开启 SEV-SNP 后,五个场景全部变慢,降幅从单线程的 6.7% 到直播转码的 43.7% 不等。这一结果高于“机密计算开销通常在个位数百分比”的一般印象。两台实例的处理器型号、内核版本、ffmpeg 二进制与测试片段均一致,每台实例两轮结果之间的差异在 2.3% 以内,远小于两台实例之间的差距,因此下面从用户态、内核态时间与中断计数的角度分析原因。

4、差异原因分析

为定位开销来源,本文用 performace-test-script/profile.sh 对四个场景各运行一次,记录 -benchmark 输出的用户态时间 utime、内核态时间 stime,以及运行期间系统的上下文切换次数(/proc/stat 的 ctxt)和核间中断次数(/proc/interrupts 的 RES 重调度中断与 CAL 函数调用中断)。

python3 ssm_send.py us-east-2 profile.sh i-0c43016da15a0c159 i-0a0445cf92ef9017d

实验组 sev-snp-on 返回结果如下:

T1_decode_h264     bench: utime=7.260s stime=1.805s rtime=1.620s ctxt=36958 RES=1266 CAL=13469
T2_x264_medium     bench: utime=87.739s stime=4.458s rtime=13.232s ctxt=94757 RES=9109 CAL=20704
T4_x264_720p_live  bench: utime=26.436s stime=7.225s rtime=6.773s ctxt=147645 RES=5629 CAL=53022
T5_x264_1thread    bench: utime=58.007s stime=1.274s rtime=52.335s ctxt=22333 RES=271 CAL=11266

对比组 sev-snp-off 返回结果如下:

T1_decode_h264     bench: utime=6.945s stime=0.261s rtime=1.155s ctxt=40423 RES=1560 CAL=13960
T2_x264_medium     bench: utime=82.645s stime=0.668s rtime=11.795s ctxt=95535 RES=9145 CAL=19796
T4_x264_720p_live  bench: utime=26.222s stime=0.722s rtime=3.927s ctxt=105837 RES=10207 CAL=19002
T5_x264_1thread    bench: utime=54.007s stime=0.260s rtime=48.647s ctxt=25775 RES=340 CAL=11980

以对比组为基准整理如下:

场景 实验组用户态时间 utime 变化 实验组内核态时间 stime 倍数
T1 H.264 解码 +4.5% 6.9 倍
T2 H.264 点播转码 +6.2% 6.7 倍
T4 720p 直播转码 +0.8% 10.0 倍
T5 单线程 H.264 +7.4% 4.9 倍

从数据可以得出两个结论:

  • 用户态计算本身变慢约 1% 至 7%。ffmpeg 的用户态代码在两组实例上完全相同,utime 增加说明同样的指令执行得更慢。SEV-SNP 下处理器在地址转换时需要额外检查 RMP 表项,访问内存的代价随之增加。T5 单线程场景几乎只有这部分开销,因此降幅最小(6.7%)。
  • 内核态时间增加约 5 至 10 倍,是多线程场景降幅偏大的主要原因。T4 的内核态时间从 0.72 秒增加到 7.2 秒,同期 CAL 核间中断次数从约 1.9 万次增加到约 5.3 万次,上下文切换从约 10.6 万次增加到约 14.8 万次。在 SEV-ES 和 SEV-SNP 客户机中,Hypervisor 不能直接读写客户机寄存器,客户机内核发送核间中断、访问部分 MSR 等需要 Hypervisor 介入的操作,都要先触发 #VC(VMM Communication Exception)异常,再通过 GHCB(Guest-Hypervisor Communication Block)共享页与 Hypervisor 交换数据,代价高于普通虚拟机的同类操作。dmesg 中的 wakeup_secondary_cpu() replaced with wakeup_cpu_via_vmgexit() 即是一例,表示连唤醒辅助 CPU 这一操作也改为通过 VMGEXIT 指令请求 Hypervisor 完成。ffmpeg 多线程编解码以帧或切片为单位在线程之间交接任务,帧处理越快,单位时间内的线程唤醒与核间中断越多,这部分开销占比越高。这与 T4(veryfast 预设加缩放滤镜,线程交接最频繁)降幅最大、T1(解码速度最快)次之的结果一致。

注意:上述原因分析基于 utime、stime 和中断计数推断,本文未使用 perf 等工具做指令级剖析,也未单独测试磁盘与网络 I/O。由于开启 SEV-SNP 后所有 DMA 数据都经 SWIOTLB 中转(第二章第 4 节),可以预期 I/O 密集型负载也会产生额外开销,生产选型前应使用实际业务负载复测。

5、清理测试资源

测试完成后,终止两台实例并删除安全组,避免持续计费。执行如下命令:

aws ec2 terminate-instances --region us-east-2 \
  --instance-ids i-0c43016da15a0c159 i-0a0445cf92ef9017d
aws ec2 wait instance-terminated --region us-east-2 \
  --instance-ids i-0c43016da15a0c159 i-0a0445cf92ef9017d
aws ec2 delete-security-group --region us-east-2 --group-id sg-06e01c759161da241

wait instance-terminated 需要实例全部终止后才返回,安全组必须在实例终止后才能删除,否则会返回 DependencyViolation。下面对全文进行总结。

五、小结

在 EC2 上开启 AMD SEV-SNP 的操作本身很简单,只需在启动实例时增加 --cpu-options AmdSevSnp=enabled 参数。但它对区域、机型、AMI 和计费都有限制。共享租户只能用于俄亥俄和爱尔兰两个区域,机型限于 M6a、C6a、R6a 的部分规格,开启后无法关闭。在东京等其他区域只能通过 Dedicated Host 使用。本次在俄亥俄以 c6a.2xlarge 实测,ffmpeg 负载在开启 SEV-SNP 后性能下降约 7% 至 44%:单线程转码约下降 7%,多线程 H.264 和 H.265 点播转码约下降 12% 至 15%,解码约下降 28%,720p 直播转码约下降 44%。从内核态时间与核间中断计数推断,开销主要来自客户机内核与 Hypervisor 交互代价的上升,多线程、高帧速的负载受影响最大。

性能下降叠加 10% 的附加费后,单位吞吐成本上升更多。以 c6a.2xlarge 为例,开启后每小时费用为 0.3366 USD,是对比组的 1.1 倍,而吞吐量只有对比组的 0.56 至 0.93 倍,折算后完成相同转码量的成本约为对比组的 1.18 倍(单线程)、1.24 至 1.29 倍(点播转码)、1.54 倍(解码)和 1.95 倍(直播转码)。

使用该方案时需注意以下事项:

  • 开启前确认区域:describe-instance-types 会在不支持共享租户的区域列出同样的机型,应以 AWS 文档或 run-instances --dry-run 的结果为准。
  • 预留内存:开启后约 1 GiB 内存被 SWIOTLB 中转缓冲区占用,小规格实例需要相应放大。
  • 维护事件需人工处理:共享租户的主机维护提前 14 天通知,必须手动停止再启动实例,应在运维流程中订阅 EC2 计划事件并安排窗口。
  • 功能互斥:不能与 AWS Nitro Enclaves、休眠同时使用,实例类型只能在支持 SEV-SNP 的机型之间更改。
  • 机型较旧:当前只支持第三代 EPYC(Milan),无法使用 M7a、C7a 等更新机型的性能提升,这部分差距需要计入成本评估。
  • 证明需要自行集成:SEV-SNP 只提供签名的证明报告,验证报告、比对启动度量,并据此决定是否下发密钥,需要业务方自行开发或集成密钥管理服务。如果不使用证明报告,开启 SEV-SNP 的收益会大打折扣。

是否选择这一方案,可以按以下场景判断:

  • 适合选择 SEV-SNP 的场景:合规或合同明确要求“云厂商主机软件不可访问客户机内存”并要求硬件级远程证明;处理密钥、个人隐私数据或模型权重等高敏感数据,且可以接受本文实测量级的性能下降与单位吞吐成本上升;部署区域可以放在俄亥俄、爱尔兰,或者业务规模足以独占 Dedicated Host。
  • 不适合选择 SEV-SNP 的场景:以视频转码为代表的高并发、多线程、对吞吐和成本敏感的计算型业务;只需要满足“内存加密”或“静态数据加密”要求的业务,因为 AWS 的 Milan 及更新平台默认已经始终加密内存;业务必须部署在东京等区域又不希望购买 Dedicated Host 的场景。
  • 组合方案:只把处理敏感数据的组件(例如密钥解封、数据脱敏)部署在开启 SEV-SNP 的实例上,大批量转码等计算任务仍放在普通实例上,以控制性能与成本代价。如果只需要可证明的启动链,也可以评估 NitroTPM 与 AWS Nitro Enclaves 等方案。

六、参考文档

AMD SEV-SNP for Amazon EC2 instances(概念、要求、限制与计费)

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sev-snp.html

Enable AMD SEV-SNP for an EC2 instance(共享租户与 Dedicated Host 的开启方法及状态检查)

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/snp-work-launch.html

Find EC2 instance types that support AMD SEV-SNP

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/snp-find-instance-types.html

Attest an Amazon EC2 instance with AMD SEV-SNP(使用 snpguest 获取并验证证明报告)

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/snp-attestation.html

What’s New:Amazon EC2 now supports AMD SEV-SNP(2023 年 4 月,共享租户首发于俄亥俄和爱尔兰)

https://aws.amazon.com/about-aws/whats-new/2023/04/amazon-ec2-amd-sev-snp/

What’s New:Amazon EC2 Dedicated Hosts now support AMD SEV-SNP(2026 年 7 月)

https://aws.amazon.com/about-aws/whats-new/2026/07/ec2-amd-sev-snp-dedicated-hosts/

Amazon EC2 按需实例定价

https://aws.amazon.com/ec2/pricing/on-demand/

AMD 白皮书:AMD SEV-SNP: Strengthening VM Isolation with Integrity Protection and More

https://www.amd.com/content/dam/amd/en/documents/epyc-business-docs/white-papers/SEV-SNP-strengthening-vm-isolation-with-integrity-protection-and-more.pdf

Linux 内核文档:AMD Memory Encryption(SEV-SNP、RMP 与 VMPL 说明)

https://docs.kernel.org/arch/x86/amd-memory-encryption.html

snpguest 证明工具代码仓库

https://github.com/virtee/snpguest

Phoronix Test Suite:FFmpeg 测试(pts/ffmpeg)

https://openbenchmarking.org/test/pts/ffmpeg

FFmpeg 官方编码指南:H.264 与 H.265

https://trac.ffmpeg.org/wiki/Encode/H.264

https://trac.ffmpeg.org/wiki/Encode/H.265

FFmpeg 静态构建下载

https://johnvansickle.com/ffmpeg/

Big Buck Bunny 开源影片

https://peach.blender.org/


最后修改于 2026-11-03