- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
当人们试图在各种库中执行严格的基准测试时,我有时会看到这样的代码:
auto std_start = std::chrono::steady_clock::now();
for (int i = 0; i < 10000; ++i)
for (int j = 0; j < 10000; ++j)
volatile const auto __attribute__((unused)) c = std_set.count(i + j);
auto std_stop = std::chrono::steady_clock::now();
这里使用volatile
来防止优化器注意到被测代码的结果被丢弃,然后丢弃整个计算。
当被测代码没有返回值时,说它是void do_something(int)
,然后有时我会看到这样的代码:
auto std_start = std::chrono::steady_clock::now();
for (int i = 0; i < 10000; ++i)
for (int j = 0; j < 10000; ++j)
static_cast<volatile void> (do_something(i + j));
auto std_stop = std::chrono::steady_clock::now();
volatile
的用法是否正确?什么是 volatile void
?从编译器和标准的角度来看,这意味着什么?
在 [dcl.type.cv]
的标准 (N4296) 中说:
7 [ Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. Furthermore, for some implementations, volatile might indicate that special hardware instructions are required to access the object. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same in C ++ as they are in C. — end note ]
在 1.9 节中,它指定了很多关于执行模型的指导,但就 volatile 而言,它是关于“访问一个 volatile
对象”。我不清楚执行已转换为 volatile void
的语句意味着什么,假设我正确理解代码,以及如果产生任何优化障碍究竟会怎样。
最佳答案
static_cast<volatile void> (foo())
不能要求编译器实际计算 foo()
在任何 gcc/clang/MSVC/ICC 中,启用优化。
#include <bitset>
void foo() {
for (int i = 0; i < 10000; ++i)
for (int j = 0; j < 10000; ++j) {
std::bitset<64> std_set(i + j);
//volatile const auto c = std_set.count(); // real work happens
static_cast<volatile void> (std_set.count()); // optimizes away
}
}
编译为 ret
所有 4 个主要的 x86 编译器。 (MSVC 为 std::bitset::count()
或其他东西的独立定义发出 asm,但向下滚动以获得其对 foo()
的琐碎定义。
(此示例和下一个示例的来源 + asm 输出 Matt Godbolt's compiler explorer )
也许有一些编译器在哪里static_cast<volatile void>()
确实做了一些事情,在这种情况下,它可能是一种更轻量级的方式来编写一个重复循环,它不花费指令将结果存储到内存中,只计算它。 (这有时可能是您在微基准测试中想要的)。
用 tmp += foo()
累加结果(或 tmp |=
)并从 main()
返回它或用 printf
打印也很有用,而不是存储到 volatile
中多变的。或者各种特定于编译器的东西,比如使用空内联 asm
语句来破坏编译器的优化能力,而无需实际添加任何指令。
参见 Chandler Carruth's CppCon2015 talk on using perf
to investigate compiler optimizations ,他在那里展示了一个 optimizer-escape function for GNU C .但是他的escape()
函数被编写为要求值在内存中(将 asm a void*
传递给它,带有 "memory"
破坏)。我们不需要那个,我们只需要编译器将值保存在寄存器或内存中,甚至是一个立即常量。 (它不太可能完全展开我们的循环,因为它不知道 asm 语句是零指令。)
此代码在 gcc 上编译为 只是 popcnt,没有任何额外存储。
// just force the value to be in memory, register, or even immediate
// instead of empty inline asm, use the operand in a comment so we can see what the compiler chose. Absolutely no effect on optimization.
static void escape_integer(int a) {
asm volatile("# value = %0" : : "g"(a));
}
// simplified with just one inner loop
void test1() {
for (int i = 0; i < 10000; ++i) {
std::bitset<64> std_set(i);
int count = std_set.count();
escape_integer(count);
}
}
#gcc8.0 20171110 nightly -O3 -march=nehalem (for popcnt instruction):
test1():
# value = 0 # it peels the first iteration with an immediate 0 for the inline asm.
mov eax, 1
.L4:
popcnt rdx, rax
# value = edx # the inline-asm comment has the %0 filled in to show where gcc put the value
add rax, 1
cmp rax, 10000
jne .L4
ret
Clang 选择将值放在内存中以满足 "g"
约束,这很愚蠢。但是当你给它一个包含内存作为选项的内联汇编约束时,clang 确实倾向于这样做。所以它并不比钱德勒的escape
好。功能。
# clang5.0 -O3 -march=nehalem
test1():
xor eax, eax
#DEBUG_VALUE: i <- 0
.LBB1_1: # =>This Inner Loop Header: Depth=1
popcnt rcx, rax
mov dword ptr [rsp - 4], ecx
# value = -4(%rsp) # inline asm gets a value in memory
inc rax
cmp rax, 10000
jne .LBB1_1
ret
ICC18 -march=haswell
这样做:
test1():
xor eax, eax #30.16
..B2.2: # Preds ..B2.2 ..B2.1
# optimization report
# %s was not vectorized: ASM code cannot be vectorized
xor rdx, rdx # breaks popcnt's false dep on the destination
popcnt rdx, rax #475.16
inc rax #30.34
# value = edx
cmp rax, 10000 #30.25
jl ..B2.2 # Prob 99% #30.25
ret #35.1
这很奇怪,ICC 使用了 xor rdx,rdx
而不是 xor eax,eax
.这浪费了 REX 前缀,并且不被认为是对 Silvermont/KNL 的依赖性破坏。
关于c++ - `static_cast<volatile void>` 对优化器意味着什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47253655/
我在 OS X 中构建菜单栏项时找到了一些示例代码。它使用了单个 |我不确定它的实际含义。 (我想做的是在菜单项左键单击时调用一个函数,但在右键单击时显示菜单) 这是我的代码 //Get refere
为什么它在第 23 行抛出编译错误。'a' 是 Apple 类的对象,col 是包含 Apple 对象的列表,但它仍然是抛出下面提到的编译错误: 类型 Collection 中的方法 add(capt
我有一个类A,它扩展了抽象类B。 让B有一个 protected 字段值 我想在 A 中使用这个字段。如果 A 没有 value,我可以编写 this.value 从 B 获取它。 与super.va
DBLint 用于检查数据库状态。有46条规则。在 www.dblint.org 上对每条规则都有一些简单的解释,但对规则 31 的描述如下: 定义的主键不是最小键:主键是最小的 super 键。如果
var aa: (()?) = (john.residence?.address = someAddress) var bb: ()? = john.residence?.printNumberOfR
我对 jquery 的可重用插件有点陌生。我已经多次遇到这段代码,但无法弄清楚究竟发生了什么。 (function( $ ){ ... })( jQuery ); 谁能帮我解答一下吗? 最佳答案
这个问题已经有答案了: int foo (int argc, ...) vs int foo() vs int foo(void) in C (4 个回答) 已关闭 9 年前。 所以我最近在 Hack
typedef struct Element { struct Element *next; void *data; } Element; 在 pop 函数中,(!(elem = *s
数据加载两次...意味着 AsyncTask onPostExecute 加载相同的数据两次?我的 AsyncTask onPostExecute 运行两次它加载相同的数据...我正在运行异步任务以从
运行“yomeanjs”时,我无限期地挂起“这可能需要几分钟”。当我尝试运行 grunt 时,它失败了,与 npm start 相同。 我使用的是 Win 8.1,并安装了最新的 Node 和 Mon
我正在看 big nerd ranch 的“Android Programming”中的这个页面,我对下面的句子感到困惑。它声明“当 Activity 被隐藏时, Activity 对象不存在”。这让
是否 const vector意味着它的元素是const也一样? 在下面的代码中, v[0].set (1234);在 void g ( const vector & v )产生编译器错误 const
我是 xml 相关事物的新手 我无法理解: SelectNodes(@"//Form/*[. = 'on']"); 注:SelectNodes是 XmlNode 的函数.(与 XmlDocument
我想方便地控制命令行参数。因此我想使用 ShellLib。 我的代码是这样的: ... #include ... EFI_STATUS EFIAPI UefiMain ( EFI_HANDL
着眼于更正 Debian 上/etc/init.d/hostapd 中的一个问题。但是,我不知道这行代码是做什么的,也不知道它是如何工作的 [ -n "$DAEMON_CONF" ] || exit
有没有人遇到过类似我下图所示的情况? 我有一个变量 landingBools.didSlowPast40Knots(正如您从调试打印输出中看到的那样)为假,但出于某种原因,if 语句评估为真。 知道为
我设法使用 flexbox 和一些非常基本的 JavaScript 为自己构建了三个下拉菜单。 因为我不太了解,所以我使用了一个简单的函数三次,而不是使用参数、变量和其他东西。我将其称为丑陋的“蛮力”
这周刚开始学习 javascript。我有一个非常菜鸟的问题。 exports.displayName = (undefined: ?string); 在 React Native 中意味着什么? 这
我正在阅读有关 NaN here 的内容它说: A comparison with a NaN always returns an unordered result even when compari
编码格式:引入*表示“从头开始重复”。例子。输入-{a,b,a,b,c,a,b,a,b,c,d}可以写成{a,b,*,c,*,d}。输出:5;例如2:ABCABCE,输出- 5。 这里*表示从头开始重
我是一名优秀的程序员,十分优秀!