You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中不使用asm!获取原生RDTSC指令以进行性能基准测试?

如何在Rust中不使用asm!获取原生RDTSC指令以进行性能基准测试?

嘿,我来帮你拆解这个问题~

首先,为啥会出现这种“合并再拆分”的无意义操作呢?其实问题出在std::arch::x86_64::_rdtsc()这个内置函数的设计初衷上:它就是专门用来返回合并后的64位时间戳值的,所以它的底层实现必然会生成shl rdx,32 + or rdx,rax这些指令,把RDTSC输出的EAX(低32位)和EDX(高32位)寄存器值合并成一个u64。

当你把这个合并后的u64再拆分成高低位元组时,编译器虽然能看到你做了反向操作,但它没办法“推翻”_rdtsc()的设计逻辑——它会先严格执行这个函数的要求(合并两个寄存器的值),再执行你的拆分代码,这就导致了这种来回折腾的“ping-pong”操作。编译器不会去深挖_rdtsc()的底层指令,只会基于它对外的功能(返回合并后的u64)来做优化。

那有没有办法不用asm!就拿到原生的RDTSC指令呢?

很遗憾,在当前Rust标准库提供的工具里,确实没有完美的解决方案。所有官方提供的RDTSC相关内置函数,都是以返回合并后的u64为目标的,所以编译器必须遵守这个设计,没办法跳过合并步骤。哪怕你用元组返回、加优化提示,编译器还是会先完成合并再拆分,绕不开那些额外的指令。

不过,如果你能稍微松口,其实Rust 1.59之后asm!宏已经是稳定特性了,而且写法非常简单,能直接生成你想要的原生RDTSC指令,完全没有额外开销:

#[inline(always)]
fn tick_count() -> (u32, u32) {
    let lo: u32;
    let hi: u32;
    unsafe {
        core::arch::asm!(
            "rdtsc",
            out("eax") lo,
            out("edx") hi,
            options(nomem, nostack, preserves_flags)
        );
    }
    (lo, hi)
}

这段代码会直接生成rdtsc指令,然后把EAX和EDX寄存器的值分别存入lo和hi变量,没有任何多余的移位或或操作,完全符合你的需求。

如果你铁了心完全不碰asm!,那目前确实没有办法绕过那些额外的指令——毕竟标准库没有提供直接返回两个寄存器原始值的内置函数,编译器只能按现有语义来生成代码。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 07:17:57