已解决,原因是cpuid指令使用不当
分析:看到
https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf 使用cpuid 和rdtsc 配合使用序列化指令,并获取时间。但实际上cpuid 运行后结果会修改rax,rbx,rcx等寄存器数据,再执行rdtsc获取的时间会覆盖cpuid所修改的寄存器,所以两个联合起来使用没有问题,但单独使用则有问题。之所以没添加优化选项没有问题是因为ii值存在栈上,优化后存在rbx上。
--------------------------------------------------
cpuid是序列化CPU指令执行的指令,写了一段测试cpuid执行时间的程序,
加上-O2选项后会死循环,未加优化选项则能正确循环3次后退出。
代码如下。编译命令 gcc -g -O2 -lrt #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <fcntl.h>
#define NS_PER_USEC (1000)
#define NS_PER_SEC (1000000000)
int main(){
long delta_ns;
struct timespec tm_now;
int loop;
int time_internal = 100000;
int ii;
struct timespec tm_interval = {.tv_sec = 0, \
.tv_nsec = 1000000};
for(ii=0; ii<3; ++ii){
printf("(%d) before cpuid %ld s %ld ns\n", ii, tm_now.tv_sec, tm_now.tv_nsec);
__asm__ __volatile__ ("cpuid");
clock_gettime(CLOCK_MONOTONIC, &tm_now);
printf("(%d) after cpuid %ld s %ld ns\n", ii, tm_now.tv_sec, tm_now.tv_nsec);
nanosleep(&tm_interval, NULL);
}
}
正常情况下(无优化选项),代码循环三次,每次输出cpuid指令前后的系统时间。
异常情况下(-O2和-O3优化选项),代码死循环(ii为固定>0的值),系统时间输出也有误。
0x00005555555551a9 <+0>: endbr64
0x00005555555551ad <+4>: push %rbp
0x00005555555551ae <+5>: mov %rsp,%rbp
0x00005555555551b1 <+8>: sub $0x40,%rsp
0x00005555555551b5 <+12>: mov %fs:0x28,%rax
0x00005555555551be <+21>: mov %rax,-0x8(%rbp)
0x00005555555551c2 <+25>: xor %eax,%eax
0x00005555555551c4 <+27>: movl $0x186a0,-0x34(%rbp)
0x00005555555551cb <+34>: movq $0x0,-0x20(%rbp)
0x00005555555551d3 <+42>: movq $0xf4240,-0x18(%rbp)
0x00005555555551db <+50>: movl $0x0,-0x38(%rbp)
0x00005555555551e2 <+57>: jmp 0x555555555248 <main+159>
0x00005555555551e4 <+59>: mov -0x28(%rbp),%rcx
0x00005555555551e8 <+63>: mov -0x30(%rbp),%rdx
0x00005555555551ec <+67>: mov -0x38(%rbp),%eax
0x00005555555551ef <+70>: mov %eax,%esi
0x00005555555551f1 <+72>: lea 0xe10(%rip),%rdi # 0x555555556008
0x00005555555551f8 <+79>: mov $0x0,%eax
0x00005555555551fd <+84>: callq 0x5555555550a0 <printf@plt>
0x0000555555555202 <+89>: cpuid
0x0000555555555204 <+91>: lea -0x30(%rbp),%rax
0x0000555555555208 <+95>: mov %rax,%rsi
0x000055555555520b <+98>: mov $0x1,%edi
0x0000555555555210 <+103>: callq 0x555555555080 <clock_gettime@plt>
0x0000555555555215 <+108>: mov -0x28(%rbp),%rcx
0x0000555555555219 <+112>: mov -0x30(%rbp),%rdx
0x000055555555521d <+116>: mov -0x38(%rbp),%eax
0x0000555555555220 <+119>: mov %eax,%esi
0x0000555555555222 <+121>: lea 0xdff(%rip),%rdi # 0x555555556028
0x0000555555555229 <+128>: mov $0x0,%eax
0x000055555555522e <+133>: callq 0x5555555550a0 <printf@plt>
0x0000555555555233 <+138>: lea -0x20(%rbp),%rax
0x0000555555555237 <+142>: mov $0x0,%esi
0x000055555555523c <+147>: mov %rax,%rdi
0x000055555555523f <+150>: callq 0x5555555550b0 <nanosleep@plt>
0x0000555555555244 <+155>: addl $0x1,-0x38(%rbp)
0x0000555555555248 <+159>: cmpl $0x2,-0x38(%rbp)
0x000055555555524c <+163>: jle 0x5555555551e4 <main+59>
0x000055555555524e <+165>: mov $0x0,%eax
0x0000555555555253 <+170>: mov -0x8(%rbp),%rsi
0x0000555555555257 <+174>: xor %fs:0x28,%rsi
0x0000555555555260 <+183>: je 0x555555555267 <main+190>
0x0000555555555262 <+185>: callq 0x555555555090 <__stack_chk_fail@plt>
0x0000555555555267 <+190>: leaveq
0x0000555555555268 <+191>: retq
从生成的汇编来看,ii 应该是在rbp寄存器中,没有按照ii预期的从0-3变化。
--
修改:lambdago FROM 171.82.232.*
FROM 171.82.232.*