c++ - `static` 的使用如何影响我的代码速度?
问题描述
我正在在线解决一个练习,有一次我需要从字符串的开头和结尾删除“”。这是我的代码:
void static inline process_value(std::string &value) {
if (value.back() !='>') {
value = value.substr(1, value.size()-2);
}
}
从此基准循环调用:
static void UsingStatic(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
std::string valor("\"Hola\"");
process_valueS(valor);
// Make sure the variable is not optimized away by compiler
benchmark::DoNotOptimize(valor);
}
}
只是出于好奇,我做了一个基准测试。
- 编译器: Clang-9.0
- 标准: c++20
- 优化: O3
- STL: libstdc++(GNU)
当我这样做时,我决定static
从中删除process_value
,void inline process_value
否则它是一样的。令我惊讶的是,它变慢了。
我认为静态仅意味着该函数仅适用于文件。但是这里它说“'静态'意味着函数应该由编译器内联,如果可能的话”。但是在那种情况下,当我删除静态时,我认为结果不应该改变。现在我很困惑,除了将函数分隔为单个之外,静态还有什么其他作用.cpp
,这对性能有何影响?
QuickBench 上的反汇编显示NoUsingStatic
循环实际上是调用process_value
而不是内联它,尽管inline
关键字使编译器这样做是合法的。但UsingStatic
确实内联调用process_valueS
. 编译器决策的差异大概解释了性能上的差异,但是为什么 clang 会选择不内联一个简单的函数声明void inline process_value(std::string &value){ ... }
呢?
编辑:因为问题不够清楚,所以问题已关闭,我删除了与问题无关的部分。但如果我错过了一些信息,请在评论中告诉我
解决方案
Clang 使用基于成本的决定是否内联函数。这个成本受很多事情的影响。它受static
.
幸运的是,clang 有一个输出,我们可以在其中观察到这一点。看看这个神螺栓链接:
void call();
inline void a() {
call();
}
static inline void b() {
call();
}
void foo() {
a();
b();
}
在这个小例子中,a()
和b()
都是一样的,唯一的例外就是b()
静态的。
如果您将鼠标移到调用a()
或b()
Godbolt 上(在OptViewer
窗口中),您可以阅读:
a()
:成本=0,阈值=487
b()
:成本=-15000,阈值=487
(如果成本低于阈值,clang 将内联调用。)
clangb()
的成本要低得多,因为它是静态的。似乎clang只会为静态函数提供一次-15000的成本降低。如果b()
被多次调用,所有b()
s 的成本将为零,除了一个。
这是您的案例的数字,链接:
process_value():
cost=400, threshold=325 -> 刚好高于阈值,不会被内联
process_valueS():
:成本=-14600,阈值=325 -> 可以内联
所以,显然,static
如果它只被调用一次,就会产生很大的影响。这是有道理的,因为内联静态函数一次不会增加代码大小。
提示:如果你想强制 clang 内联一个函数,使用__attribute__((always_inline))
它。
推荐阅读
- excel - 我的 vba 代码中的 Elseif 函数不起作用
- graphics - 安装 intel-linux-graphics-installer 依赖不满足:libpackagekit-glib2-16 (>= 0.8.10)
- javascript - 如何通过最新的firestore反转时间戳以订购文档
- javascript - ./node_modules/react-bootstrap/esm/Modal.js 找不到模块
- solana - 如何获取在与@solana/web3.js 的交易中转移的自定义令牌数量?
- google-cloud-platform - Big Query 中的表未分区
- azure-ad-b2c - 带有“继续”条件的 Azure B2C 自我断言屏幕
- php - Laravel-检查与您的 MariaDB 服务器版本相对应的手册,以在第 1 行的 ') < Now()' 附近使用正确的语法
- javascript - 如何在 Joi 中获得兄弟值?
- maven - POM 无效,传递依赖项(如果有)将不可用,启用调试日志以获取更多详细信息