PyXL logo PyXL

🧪 480ns 的 GPIO 环回测试

用硬件跑 Python。480ns GPIO。没有解释器。没有 C。只有 PyXL。

TL;DR

什么是 PyXL?

PyXL 是一个定制的硬件处理器,它可以直接执行 Python —— 没有解释器,没有 JIT,也没有任何花招。 它接受常规的 Python 代码,并在硅片上运行它。 一个定制的工具链将 .py 文件编译成 CPython ByteCode,将其翻译成定制的汇编,并生成一个可以在从头开始构建的流水线处理器上运行的二进制文件。

PyXL 不是什么

它是一个真正的 Python 处理器,专为确定性和速度而构建。

它在哪里运行?

PyXL 运行在 Zynq-7000 FPGA (Arty-Z7-20 开发板) 上。 PyXL 核心以 100MHz 的频率运行。 板上的 ARM CPU 处理设置和内存,但 Python 代码本身完全在硬件中执行。 该工具链是用 Python 编写的,并在使用未修改的 CPython 的标准开发机器上运行。

等等 —— 什么是 GPIO?

GPIO 代表 General Purpose Input/Output (通用输入/输出)。 这是一个简单的硬件引脚,软件可以从中读取或写入数据 —— 一种控制外部世界的方式:LED、按钮、传感器、电机等等。

在 MicroPython (例如在 PyBoard 上) 中,您的 Python 代码与处理底层硬件寄存器的 C 函数进行交互。 它相当快,但仍然需要通过 Python VM 和软件堆栈才能到达引脚。

PyXL 跳过了所有这些。 Python 字节码直接在硬件中执行,并且 GPIO 访问在物理上连接到处理器 —— 没有解释器,没有函数调用,只有原生硬件执行。

现在进行 GPIO 测试。 视频展示了什么?

我用跳线将 Arty 板上的两个引脚连接起来。 然后,我编写了一个 Python 程序,该程序测量从 GPIO 引脚 1 设置为 1 的时间,直到在连接到它的另一个引脚上测量到 1 的时间。 该视频展示了 PyXL 和运行 MicroPython VM 的 PyBoard 之间的比较。让我们重点关注 PyXL 是如何工作的。

程序

from compiler.intrinsics import *

def main():
  pyxl_write_gpio_pin1(0)       # 重置输出引脚
  c1 = pyxl_get_cycle_counter()    # 周期计数器 (100 MHz)
  pyxl_write_gpio_pin1(1)       # 设置输出引脚
  while pyxl_read_gpio_pin2() == 0:  # 等待直到输入引脚设置为 1
    continue
  c2 = pyxl_get_cycle_counter()    # 周期计数器 (100 MHz)
  return (c2 - c1) * 10        # 以纳秒为单位返回结果 (每个周期为 10 纳秒)

正如你所看到的,这是一个常规的 Python 程序,但它也有一些不熟悉的函数调用。 这些函数来源于 compiler.intrinsics 模块。

pyxl_get_cycle_counter()

从 PyXL CPU 获取当前周期计数器。 该计数器在每个时钟周期递增 1。

pyxl_write_gpio_pin1()

将值 (0/1) 写入 GPIO 引脚。 这些是编译器公开的底层内部函数 —— 目前为该测试硬编码,但将演变为更通用的 pyxl_gpio_write(pin, value) API。

pyxl_read_gpio_pin2()

从 Pin2 读取值。 同样的 API 注释也适用于此处。

等等,为什么没有调用 main 函数?

main 函数只是被定义了,但没有被调用。 为什么? 在目前阶段,PyXL 在运行程序时会自动调用 main 函数。 这只是一个方便的功能 (用于开发),将来会改变。

它是如何工作的?

如上所述,该程序被编译为 CPython Bytecode,然后再次编译为 PyXL 汇编。 然后将它们链接在一起,并生成一个二进制文件。 该二进制文件通过网络发送到 Arty 板,在那里 ARM CPU 获取应用程序,将其复制到与 PyXL HW 共享的内存中,并开始运行它。

一个典型的 Python 运行时 (CPython 或 MicroPython,例如 PyBoard 或用于嵌入式的 Python) 具有很大的开销,这是由在基于软件的 VM 上运行 ByteCode 引起的。 在 PyXL 中,没有 VM,硬件完成所有工作。

至于读取和写入 GPIO - GPIO 头直接映射到 FPGA 引脚,并在物理上连接到 PyXL 核心的顶层模块。 可以将其视为 HW 的 main 函数。

在此测试中,所有代码和数据都驻留在可预测的低延迟内存中,从而确保确定性行为 (实时行为)。 这意味着对于相同的输入,它将花费完全相同的时间来运行。

那么这些平台是如何比较的呢?

GPIO 环回延迟 (纳秒)。数值越小越好。

PyXL480ns MicroPython (PyBoard)14,741ns

正如你所看到的,PyXL 比 PyBoard 快 30 倍。

另外,请记住 PyXL 的时钟速度低于 PyBoard。

不以更高的时钟频率运行的原因是 PyXL 在 FPGA 上进行了原型设计,而 PyBoard 具有 ASIC。 但关键是,这并不是 PyXL 的限制,可以实现更高的时钟频率。

由于可以实现更高的时钟频率,我们需要进行同类比较,并对时钟频率进行标准化。 这使得 PyXL 的标准化优势比 PyBoard 高约 50 倍。

为什么两个测试没有运行完全相同的代码?

对于你们中的细心的人来说,你可能已经在视频中注意到,PyBoard 代码和 PyXL 代码并不相同。

两者都是 Python,这是显而易见的,但有两个主要区别:

  1. 用于测量时间和读取/写入 GPIO 引脚的 API 调用。 原因是这不是在主机上运行的 CPython,而是了解底层硬件的系统,它们带来了自己的运行时环境。 每个平台都有自己的硬件访问 API 调用,但常规的 Python 代码仍然可以在平台之间移植 (只要它们支持你想使用的任何 Python 功能)。
  2. PyBoard 在一个紧密的循环中运行测试,以补偿抖动和冷缓存。 在 PyBoard 上运行的 MicroPython 具有运行时抖动。 在我的测试中,结果在 14-25 微秒之间。 因此,我想在充分预热后与 PyBoard 进行比较,以展示即使在这种情况下,PyXL 的性能也优越得多。 相比之下,PyXL 是完全确定性的。 只要跳线已连接,PyXL 每次都会返回一致的 480ns。 这使得 PyXL 适用于实时用例。

有什么大不了的,谁在乎让信号更快一点?

这不仅仅是性能提升 —— 它是一种解锁。 PyXL 带来了 Python 在嵌入式或实时环境中从未有过的响应性和确定性。

Python VM —— 即使是为微控制器设计的那些 —— 仍然是围绕软件解释器构建的。 这在你的代码和硬件之间引入了开销和复杂性。

PyXL 消除了这种障碍。 你的 Python 代码直接在硬件中执行。 GPIO 访问是物理的。 控制流是可预测的。 执行在设计上是紧凑且一致的。

通过这种解锁,PyXL 可以进一步开发并适应以下用例:

使用 PyXL,你可以用 Python 编写一次性能关键的代码,并按原样发布它。

听起来很有趣? 让我们谈谈。

如果你好奇,请联系我们。 好奇吗? 让我们谈谈:runpyxl@proton.me