c++ - 了解 volatile asm 与 volatile 变量
问题描述
我们考虑以下程序,它只是定时循环:
#include <cstdlib>
std::size_t count(std::size_t n)
{
#ifdef VOLATILEVAR
volatile std::size_t i = 0;
#else
std::size_t i = 0;
#endif
while (i < n) {
#ifdef VOLATILEASM
asm volatile("": : :"memory");
#endif
++i;
}
return i;
}
int main(int argc, char* argv[])
{
return count(argc > 1 ? std::atoll(argv[1]) : 1);
}
为了便于阅读,同时具有 volatile 变量和 volatile asm 的版本如下所示:
#include <cstdlib>
std::size_t count(std::size_t n)
{
volatile std::size_t i = 0;
while (i < n) {
asm volatile("": : :"memory");
++i;
}
return i;
}
int main(int argc, char* argv[])
{
return count(argc > 1 ? std::atoll(argv[1]) : 1);
}
g++ 8
with下的编译g++ -Wall -Wextra -g -std=c++11 -O3 loop.cpp -o loop
大致给出了以下时间:
default: 0m0.001s
-DVOLATILEASM: 0m1.171s
-DVOLATILEVAR: 0m5.954s
-DVOLATILEVAR -DVOLATILEASM: 0m5.965s
我的问题是:为什么会这样?默认版本是正常的,因为循环已被编译器优化掉。但是我很难理解为什么-DVOLATILEVAR
比-DVOLATILEASM
两者都应该强制循环运行要长得多。
编译器资源管理器为 提供以下count
功能-DVOLATILEASM
:
count(unsigned long):
mov rax, rdi
test rdi, rdi
je .L2
xor edx, edx
.L3:
add rdx, 1
cmp rax, rdx
jne .L3
.L2:
ret
和对于-DVOLATILEVAR
(和组合-DVOLATILEASM -DVOLATILEVAR
):
count(unsigned long):
mov QWORD PTR [rsp-8], 0
mov rax, QWORD PTR [rsp-8]
cmp rdi, rax
jbe .L2
.L3:
mov rax, QWORD PTR [rsp-8]
add rax, 1
mov QWORD PTR [rsp-8], rax
mov rax, QWORD PTR [rsp-8]
cmp rax, rdi
jb .L3
.L2:
mov rax, QWORD PTR [rsp-8]
ret
为什么会这样呢?为什么volatile
变量的限定会阻止编译器执行与 with 相同的循环asm volatile
?
解决方案
当你让i
volatile
你告诉编译器它不知道的东西可以改变它的值时。这意味着每次使用它时它都被迫加载它的值,并且每次写入它时它都必须存储它。什么时候i
不是volatile
编译器可以优化该同步。
推荐阅读
- sails.js - ReferenceError:list.ejs 上的“postIts.forEach(function(postit)”?postIts 未在 eval 中定义(编译时为 eval
- firebase - Firebase 更新到 8.2.0 后如何修复列出用户的 401 错误
- python - 如何使用掩码在tensorflow中保留k个点
- git - 如何将 Github 远程存储库链接到预先存在的本地存储库?
- html - 如何将文本列表居中,然后在 w3.css 列中对其进行调整
- python - 如何解决 gurobipy.GurobiError:Objective Q not PSD?(用简单的例子)
- python - Python3.7如何连接SQL Server和TLS1.2?
- ruby-on-rails - AASM + Rspec - 如何在测试中忽略/禁用/跳过转换回调?
- android - 如何在 Flutter 中每 5 秒重复一次 Widget?
- c - 实现递归函数的问题