2. 性能度量标准:延迟、吞吐量、抖动、CPU周期计数、如何正确测量性能

做高频交易,说白了就是跟时间赛跑。你写的代码到底快不快,不能靠感觉,得靠数据说话。这一章,我们就来聊聊那几个最核心的性能指标,以及怎么把它们量出来。

2.1 延迟:从事件到响应的距离

延迟,就是一件事从发生到被处理完,中间花了多少时间。在期货高频里,这个“事”通常是行情数据包到达,或者交易信号产生。

关键点:

  • 端到端延迟:从网卡收到数据包,到交易指令发出,整个链条的总耗时。
  • 单向延迟 vs 往返延迟:我们更关心单向延迟。因为行情来了,你只需要发指令出去,不需要等交易所确认再发。
  • 平均延迟 vs 尾延迟:平均延迟好看没用,99.9%甚至99.99%的尾延迟才是杀手。我见过一个系统,平均延迟只有5微秒,但偶尔一次卡到100微秒,直接导致订单没抢到。

核心原则:在高频交易中,我们优化的是尾延迟,而不是平均延迟。

2.2 吞吐量:单位时间能处理多少事

吞吐量,就是系统在单位时间内能处理多少个事件。比如,一秒钟能处理多少笔行情,或者一秒钟能发出多少笔订单。

延迟和吞吐量,有时候是矛盾的。你想想看,为了降低单笔延迟,你可能用了更简单的算法,但这样单位时间处理的事件数就少了。反过来,为了提升吞吐量,你可能用了批处理,但单笔延迟就上去了。

我个人习惯:先保证延迟达标,再考虑吞吐量。因为在高频场景下,错过一笔交易的机会成本,远大于处理慢一点的成本。

2.3 抖动:延迟的稳定性

抖动,就是延迟的波动程度。一个系统,如果延迟忽高忽低,那比延迟高一点更可怕。为什么?因为你的策略没法预测下一次响应什么时候来。

衡量方式:

  • 标准差:延迟数据的标准差越小,抖动越小。
  • 百分位差:比如P99延迟减去P50延迟,这个差值越小,说明系统越稳定。

避坑指南:我曾经遇到过一个系统,平均延迟很低,但抖动特别大。查了半天,发现是垃圾回收(GC)在作祟。所以,用C++做高频,一定要避免动态内存分配,尤其是不要在热路径上new/delete。

2.4 CPU周期计数:最底层的度量

CPU周期,是CPU执行一条指令的最小时间单位。比如,一个3GHz的CPU,一个周期就是0.33纳秒。用CPU周期来度量性能,比用纳秒更精确,因为它不受CPU频率变化的影响。

怎么获取?

在x86平台上,可以用RDTSC指令。但要注意,现代CPU的TSC(时间戳计数器)可能不是恒定的,尤其是在不同核心之间。所以,我建议用__rdtscp,它会序列化指令,保证准确性。

// 获取CPU周期计数
#include <x86intrin.h>

uint64_t start = __rdtscp(&aux);
// ... 你的代码 ...
uint64_t end = __rdtscp(&aux);
uint64_t cycles = end - start;

小技巧:测量极短代码段时,要减去测量本身的开销。可以先测一个空循环的周期数,然后从结果中减去。

2.5 如何正确测量性能

测量性能,比写代码更容易犯错。我见过太多人,测出来的数据根本不准,还拿这个去优化。

测量原则:

  1. 预热:CPU有缓存,有分支预测器。第一次运行和第二次运行,性能可能差很多。所以,先跑几万次“热身”,再开始正式测量。
  2. 隔离:测量时,关掉其他进程,尤其是那些会抢占CPU的。最好绑核,把测量线程固定在一个物理核心上。
  3. 多次测量:单次测量没有意义。至少要测100万次,然后看分布。我习惯用直方图来观察延迟分布。
  4. 避免编译器优化:用volatile或者asm volatile("" ::: "memory")来防止编译器把测量代码优化掉。
// 一个简单的测量框架
void benchmark() {
    // 预热
    for (int i = 0; i < 100000; ++i) {
        do_work();
    }

    // 正式测量
    std::vector<uint64_t> latencies;
    latencies.reserve(1000000);
    for (int i = 0; i < 1000000; ++i) {
        uint64_t start = __rdtscp(&aux);
        do_work();
        uint64_t end = __rdtscp(&aux);
        latencies.push_back(end - start);
    }

    // 分析结果
    // 计算平均、P50、P99、P99.9等
}

2.6 知识体系图

下面这张图,把性能度量的几个维度串起来了。你可以看到,延迟、吞吐量、抖动、CPU周期,它们之间是相互关联的。

性能度量标准 延迟 端到端 / 尾延迟 吞吐量 事件/秒 抖动 延迟稳定性 CPU周期计数 最底层度量 正确测量:预热、隔离、多次、防优化

2.7 总结

性能度量,是优化的前提。没有准确的度量,优化就是瞎忙活。记住,延迟、吞吐量、抖动、CPU周期,这四个指标要一起看,不能只看一个。

嗯,这一章就到这里。下一章,我们会聊聊如何用工具把这些指标抓出来,以及怎么分析它们。


专注资料整理