密码学 - TFHE-hpu后端 - Zama-Ai

  • zama-ai
  • 发布于 2天前
  • 阅读 43

本文档介绍了TFHE中用于连接HPU加速器的tfhe-hpu-backend代码。它包含一个HpuDevice抽象,可以轻松配置和调度HPU加速器上的TFHE操作。提供了HPU硬件设置、CPU密文克隆到HPU、在HPU上调度操作的示例以及预先构建的示例。

TFHE-hpu-backend

摘要

tfhe-hpu-backend包含了与TFHE的HPU加速器交互的代码。 它包含一个HpuDevice抽象,可以轻松地在HPU加速器上配置和调度TFHE操作。

用户API公开了以下用于硬件设置的函数:

  • HpuDevice::new, HpuDevice::from_config: 从配置文件实例化抽象设备。
  • HpuDevice::init: 配置并上传所需的公共材料。
  • new_var_from: 从 tfhe-rs 密文创建一个HPU密文。

HPU设备也可以在 integer 中使用,借助以下函数:

  • tfhe::integer::hpu::init_device: 使用服务器密钥初始化给定的HPU设备。
  • tfhe::integer::hpu::ciphertext::HpuRadixCiphertext::from_radix_ciphertext: 将CpuRadixCiphertext转换为其HPU对应形式。

通过设置线程局部HPU服务器密钥,也可以从 hl-api 无缝使用HPU设备:

  • tfhe::Config::from_hpu_device: 从HpuDevice提取hl-api配置。
  • tfhe::set_server_key: 在当前线程中注册Hpu服务器密钥。

借助 hw-xfer 功能,还可以从 high-level-api 对象创建HPU变量。 这实现了一个trait,可以在HPU加速器上 clone_onmv_on FheUint 对象,并从它们那里 from 转换回来。

这些对象实现了 std::ops trait,可用于在HPU硬件上调度操作。

后端结构

tfhe-hpu-backend 分为多个模块:

  • entities: 定义由HPU加速器处理的结构。从/到这些对象的转换trait在 tfhe-rs 中实现。
  • asm: 描述了HPU的类似汇编的语言。它实现了抽象的HPU行为,并通过微代码轻松更新它。
  • fw: 帮助微代码设计者的抽象。使用简单的rust程序来描述新的HPU操作。帮助进行寄存器/堆管理。
  • interface:
    • device: 公开用户API的高级结构。
    • backend: 包含HPU模块的内部私有结构
    • variable: 包装HPU密文。它使硬件对象的生命周期可以在 rust 借用检查器中Hook。
    • memory: 处理板载内存分配和同步
    • config: 帮助通过TOML配置文件配置HPU加速器
    • cmd: 将 variable 上的操作转换为具体的HPU命令
    • regmap: 轻松与HPU内部寄存器通信。
    • rtl: 定义从HPU的状态/配置寄存器填充的具体 rust 结构

下面是后端内部结构的概述。 HPU backend structure

这张图描述了 tfhe-hpu-backend 的内部模块,Device是用户的主要入口点。其生命周期如下:

  1. 创建HpuDevice,打开与相关FPGA的链接。配置相关的驱动程序并上传比特流。读取FPGA寄存器以提取支持的配置和功能。构建固件转换表(IOp -> DOps流)。

  2. 在板载内存中分配所需的内存块。上传TFHE计算所需的公共材料。

  3. 创建处理TFHE密文的HPU变量。它使用所需的内部资源包装TFHE密文,并强制执行正确的生命周期管理。此抽象强制在变量生命周期内所有必需的资源都是有效的。

  4. 用户可以从HPU变量触发HPU操作。 Variable抽象强制要求在硬件上正确同步所需的对象,并将每个操作转换为具体的HPU命令。 当硬件确认HPU操作时,将更新相关变量的内部状态。 这种机制支持异步操作,并最大程度地减少主机到/从HW的内存传输量。 这种机制还支持将计算图卸载到HPU,并且仅需要在最终结果上进行同步。

示例

配置文件

HPU配置旋钮收集在TOML配置文件中。该文件描述了目标FPGA及其关联的配置:

[fpga] # FPGA目标
  # FPGA中的寄存器布局
  regmap=["${HPU_BACKEND_DIR}/config_store/${HPU_CONFIG}/hpu_regif_core_cfg_1in3.toml",
          "${HPU_BACKEND_DIR}/config_store/${HPU_CONFIG}/hpu_regif_core_cfg_3in3.toml",
          "${HPU_BACKEND_DIR}/config_store/${HPU_CONFIG}/hpu_regif_core_prc_1in3.toml",
          "${HPU_BACKEND_DIR}/config_store/${HPU_CONFIG}/hpu_regif_core_prc_3in3.toml"]
  polling_us=2
[fpga.ffi.V80] # 硬件属性
  id="${V80_PCIE_DEV}"
  board_sn="${V80_SERIAL_NUMBER}"
  hpu_path="${HPU_BACKEND_DIR}/config_store/v80_archives/psi64.hpu"
  ami_path="${AMI_PATH}/ami.ko"
  qdma_h2c="/dev/qdma${V80_PCIE_DEV}001-MM-0" # QDma 主机到卡设备
  qdma_c2h="/dev/qdma${V80_PCIE_DEV}001-MM-1" # QDma 卡到主机设备

[rtl] # RTL 选项
  bpip_used = true # BPIP/IPIP 模式
  bpip_use_opportunism = false # 使用严格的刷新范例
  bpip_timeout = 100_000 # 时钟周期中的BPIP超时

[board] # 板配置
  ct_mem = 32768 # 分配的密文数量
  ct_pc = [ # 用于密文的内存
    {Hbm= {pc=32}},
    {Hbm= {pc=33}},
  ]
  heap_size = 16384 # 为堆保留的插槽数

  lut_mem = 256 # 分配的LUT表数量
  lut_pc = {Hbm={pc=34}} # 用于LUT的内存

  fw_size= 16777216 # 固件转换表的大小(以字节为单位)
  fw_pc = {Ddr= {offset= 0x3900_0000}} # 用于固件转换表的内存

  bsk_pc = [ # 用于自举密钥的内存
    {Hbm={pc=8}},
    {Hbm={pc=12}},
    {Hbm={pc=24}},
    {Hbm={pc=28}},
    {Hbm={pc=40}},
    {Hbm={pc=44}},
    {Hbm={pc=56}},
    {Hbm={pc=60}}
  ]

  ksk_pc = [ # 用于密钥切换密钥的内存
    {Hbm={pc=0}},
    {Hbm={pc=1}},
    {Hbm={pc=2}},
    {Hbm={pc=3}},
    {Hbm={pc=4}},
    {Hbm={pc=5}},
    {Hbm={pc=6}},
    {Hbm={pc=7}},
    {Hbm={pc=16}},
    {Hbm={pc=17}},
    {Hbm={pc=18}},
    {Hbm={pc=19}},
    {Hbm={pc=20}},
    {Hbm={pc=21}},
    {Hbm={pc=22}},
    {Hbm={pc=23}}
  ]

  trace_pc = {Hbm={pc=35}} # 用于跟踪日志的内存
  trace_depth = 32 # 为跟踪日志分配的内存大小(以MiB为单位)

[firmware] # 固件属性
  implementation = "Llt" # 要使用的固件风格
  integer_w=[4,6,8,10,12,14,16,32,64,128] # 支持的IOp宽度列表
  min_batch_size = 11 # 最大吞吐量的最小批处理大小
  kogge_cfg            = "${HPU_BACKEND_DIR}/config_store/${HPU_CONFIG}/kogge_cfg.toml"
  custom_iop.'IOP[0]'  = "${HPU_BACKEND_DIR}/config_store/${HPU_CONFIG}/custom_iop/cust_0.asm"

## 默认固件配置。可以在每个IOp的基础上进行编辑
[firmware.op_cfg.default]
  fill_batch_fifo = true
  min_batch_size = false
  use_tiers = false
  flush_behaviour = "Patient"
  flush = true

设备设置

以下代码段显示了如何实例化和配置 HpuDevice

    // 以下代码片段使用HighLevelApi抽象
    // 实例化 HpuDevice --------------------------------------------------
    let hpu_device = HpuDevice::from_config(&args.config.expand());

    // 生成密钥 ----------------------------------------------------------
    let config = Config::from_hpu_device(&hpu_device);

    let cks = ClientKey::generate(config);
    let csks = CompressedServerKey::new(&cks);

    // 将 HpuDevice 和密钥注册为线程局部引擎
    set_server_key((hpu_device, csks));

在HPU上克隆CPU密文

以下代码段显示了如何将CPU密文转换为HPU密文:

    // 抽取随机值作为输入
    let a = rand::thread_rng().gen_range(0..u8::MAX);

    // 在Cpu端加密它们
    let a_fhe = FheUint8::encrypt(a, &cks);

    // 克隆一个密文并将它们移动到HpuWorld中
    // NB: 在此阶段,数据不会通过Pcie移动
    //     数据仅在Hpu中排序,并复制到主机内部缓冲区中
    let a_hpu = a_fhe.clone_on(&hpu_device);

在HPU上调度操作

一旦注册为线程局部引擎,HighLevel FheUint将转换为Hpu格式。 以下代码段显示了如何在HPU上启动操作:

  // 求和 -------------------------------------------------------------
  // 生成随机输入值并计算预期结果
  let in_a = rng.gen_range(0..u64::max_value());
  let in_b = rng.gen_range(0..u64::max_value());
  let clear_sum_ab = in_a.wrapping_add(in_b);

  // 加密输入值
  let fhe_a = FheUint64::encrypt(in_a, cks);
  let fhe_b = FheUint64::encrypt(in_b, cks);

  // 通过hl_api触发HPU上的操作
  let fhe_sum_ab = fhe_a+fhe_b;

  // 解密值
  let dec_sum_ab: u64 = fhe_sum_ab.decrypt(cks);

预制示例

tfhe/examples/hpu 中已经有一些示例应用程序可用:

  • hpu_hlapi:描述了通过HighLevelApi使用HPU设备。
  • hpu_bench:描述了通过Integer抽象级别使用HPU设备。

为了在硬件上运行这些应用程序,用户必须从项目根目录(即 tfhe-rs-internal)使用 hpu-v80 功能进行构建:

注意:运行示例需要正确拉取 .hpu 文件。由于这些文件的大小,它们由git-lfs支持,并且默认情况下处于禁用状态。 为了检索它们,请从 TFHE-rs 根文件夹运行以下命令:

make pull_hpu_files
$ cargo build --release --features="hpu-v80" --example hpu_hlapi --example hpu_bench
## 使用 setup_hpu.sh 脚本正确设置环境
$ source setup_hpu.sh --config v80 -p
## 引入 Xilinx 环境(2024 或 2025 版本)
$ source /opt/xilinx/Vivado/2024.2/settings64.sh
$ xsdb -eval "connect;puts [lsort -unique [regex -all -inline {( XFL[A-Z0-9]*)} [targets -target-properties]]]"
****** Xilinx hw_server v2024.2
  **** Build date : Oct 29 2024 at 10:16:47
    ** Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
    ** Copyright 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.

INFO: hw_server application started
INFO: Use Ctrl-C to exit hw_server application

INFO: To connect to this hw_server instance use url: TCP:127.0.0.1:3121

{ XFL12E5XJHWLA}
$ export V80_SERIAL_NUMBER=XFL12E5XJHWL
$ ./target/release/examples/hpu_bench --integer-w 64 --integer-w 32 --iop MUL --iter 10
$ ./target/release/examples/hpu_hlapi

注意:当".hpu"文件没有正确获取时发生的错误可能有点神秘:memory allocation of ... bytes failed 如果遇到此问题,应运行以下命令:

make pull_hpu_files

注意:tfhe-hpu-backend此时只能使用一个V80板,但是如果你的服务器上有多个板,则可以执行

$ . setup_hpu.sh --config v80 -p
getopt: option requires an argument -- 'p'
Please select a device in following list (1st two digits):
24:00.1 Processing accelerators: Xilinx Corporation Device 50b5
61:00.1 Processing accelerators: Xilinx Corporation Device 50b5
$ . setup_hpu.sh --config v80 -p 61
$ source /opt/xilinx/Vivado/2024.2/settings64.sh
# 如果加载了AMI驱动程序并且运行的AMC版本是预期的版本
$ cat /sys/module/ami/drivers/pci\:ami/0000\:61\:00.0/board_serial
XFL1UKRD42KW
# 列出USB JTAG上可用的序列号
$ xsdb -eval "connect;puts [lsort -unique [regex -all -inline {( XFL[A-Z0-9]*)} [targets -target-properties]]]"
...
{ XFL12E5XJHWLA} { XFL1UKRD42KWA}
$ export V80_SERIAL_NUMBER=XFL1UKRD42KW
$ ./target/release/examples/hpu_hlapi

注意:默认情况下,setup_hpu.sh会将AMI_PATH设置为类似/opt/v80/ami/e55d02d的路径,其中e55d02d是AMI驱动程序的git修订版。 为了正确运行,你需要将来自此修订版的已编译的ami.ko放在此目录中,或者将AMI_PATH设置为你的AVED提取:

export AMI_PATH=/home/user/AVED/sw/AMI/driver/

测试框架

tfhe-rs中还支持一组测试。测试在各种整数宽度的测试包中收集。 这些测试有5个子类:

  • alu:运行并检查所有ct x ct IOp
  • alus:运行并检查所有ct x 标量IOp
  • bitwise:运行并检查所有按位IOp
  • cmp:运行并检查所有比较IOp
  • ternary:运行并检查三元运算
  • algo: 运行并检查专用于卸载小型算法的IOp

以下代码段给出了一些可用于测试的命令示例:

## 使用 setup_hpu.sh 脚本正确设置环境
source setup_hpu.sh --config v80 -p

## 运行64b整数宽度的所有子类
cargo test --release --features="hpu-v80" --test hpu -- u64

## 仅运行所有整数宽度IOp 的 `bitwise` 子类
cargo test --release --features="hpu-v80" --test hpu -- bitwise

基准测试框架

HPU完全集成在tfhe基准测试系统中。性能结果可以从HighLevelApi或Integer Api中提取。 可以通过以下Makefile目标启动三个基准测试,以简化操作:

## 不要忘记事先正确设置环境
source setup_hpu.sh --config v80 -p

## 运行 hlapi 基准测试
make test_high_level_api_hpu

## 运行 hlapi erc20 基准测试
make bench_hlapi_erc20_hpu 

## 运行整数级别基准测试
make bench_integer_hpu

渴望在没有真实硬件的情况下启动?

你是否仍在等待你的FPGA板,并对交货时间感到沮丧? 不用担心,你有备份。tfhe-rs中提供了一个专用的仿真基础设施,具有准确的性能估算。 你可以在任何linux/MacOs上使用它来测试HPU在tfhe-rs中的集成,并为HPU目标优化你的应用程序。 只需看一眼 Hpu mockup,然后按照说明操作即可。

  • 原文链接: github.com/zama-ai/tfhe-...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
zama-ai
zama-ai
江湖只有他的大名,没有他的介绍。