Djz*_*zin 4 assembly qemu arm64
我正在尝试为ARM体系结构生成一些生成的程序集.在这种特定情况下,目标是aarch64-unknown-linux-gnu.我真的想要倒数到个人周期,花几个小时来获得最短的时间并消除差异.
我没有直接访问ARM硬件,所以我试图在QEMU下运行我的代码.
对于x86/x86_64,我使用rdtsc和rdtscp指令返回循环计数.
对于aarch64,我以为我可以使用
let clocks: u64;
asm!("mrs $0, pmccntr_el0" : "=r" (clocks) ::: "volatile");
Run Code Online (Sandbox Code Playgroud)
但是当我跑步的时候
qemu-aarch64 -L /usr/aarch64-linux-gnu myprogram
Run Code Online (Sandbox Code Playgroud)
我正进入(状态
qemu: uncaught target signal 4 (Illegal instruction) - core dumped
Run Code Online (Sandbox Code Playgroud)
我想可能pmcr_el0需要在寄存器中设置一些位,但是甚至可以从中读取
let pmcr: u32;
asm!("mrs $0, pmcr_el0" : "=r" (pmcr) ::: "volatile");
Run Code Online (Sandbox Code Playgroud)
给出了同样的Illegal instruction错误.
这让我感到震惊,好像这些都是需要为我启用的特权指令 - 但我找不到如何使用QEMU执行此操作的文档.
那么有没有办法访问QEMU中的性能硬件?有没有办法以其他方式计算周期?我真的希望它与x86代码尽可能匹配.
似乎你忘了在pmuserenr寄存器中启用一些位.
另外,要使用性能监视器扩展,请遵循ARMv8体系结构参考手册的 D6章节.
请注意,QEMU不适合进行代码分析和优化.
QEMU的第一个目标是仿真速度(> 40 MIPS),它为OS开发提供了一些可靠的架构配置文件.然后QEMU不需要支持准确的ARMv8性能监视器功能,当前的实现是相当抽象和最小的:除了循环计数器PMCCNTR的不准确模型之外什么也没有,并且根本没有性能监视器事件基础结构.
你最好使用普通的物理计数器来产生时间间隔:
mrs x0, cntpct_el0
Run Code Online (Sandbox Code Playgroud)
为了理解为什么QEMU上的循环计算是无用的,请注意,QEMU是一个功能模型,它基于一些假设:
1)所有指令逐个顺序执行,每个指令消耗相等的时间段:
1 guest instruction counter tick = 1 emulated nano second << icount_time_shift
Run Code Online (Sandbox Code Playgroud)
icount_time_shift由"-icount"命令行选项指定,默认为3.然后1个模拟的客户指令是8个模拟纳秒.
指令计数器和纳秒之间的这种严格转换是QEMU动态客户代码转换机制的关键概念,它允许确定性地生成转换块(TB):外围模型,其是纳秒驱动,绑定到TB执行,这是指令计数器驱动.
例如,您将10个访客指令作为TB执行,然后将外设时钟提前到80 ns.外围设备也可以告诉TB执行循环,预计800 ns没有任何访客事件,并且可以将下一个100条指令作为一个TB执行.
2)仿真纳秒级是一个基本时钟单元,在qemu提供时间量,所有其他客户计数器按一些整数因子缩放:
例如,ARM物理系统计数器(CNTPCT)硬编码频率的当前QEMU实现是62MHz.然后
scale_factor = 10^9 / (62 *10^6) = 16, (division is integer)
Run Code Online (Sandbox Code Playgroud)
即QEMU每16个模拟纳秒的增量进行CNTPCT单次增量.基于该规模的ARMv8通用定时器QEMU实现.
此外,QEMU将PMCR实现为具有某种整数范围的计数器.
在QEMU,您可以手动计算访客程序中的指令,将其复数到某个常数,并且我认为它将等于您的访客代码尝试在QEMU上运行时计算的值.
对于在HW上运行的真实代码,结果将毫无意义:您需要使用专有的性能模拟器之一来实现具有缓存模型和管道的目标微架构,或者直接在HW上进行测试.