在库中的 C++17 中强制内联回调 (lambda)
Forcing inlining of callback (lambda) in C++17 in library
我正在构建一个运行时系统,它允许程序员指定在特定点调用的回调。我正在使用clang 7.0.1/-std=c++17
。回调通过将 lambda 存储为std::function
在运行时注册。当运行时稍后调用std::function
回调时,它会传递 6 个参数(考虑到运行时的通用性,这是必要的)。请注意,std::function
是在应用程序中创建的,但由单独编译的静态链接库使用。但是,我使用的是 LTO(通过-flto
和 LLD 7.0.1),所以我希望它仍然能够进行此优化。我是其中一些东西的新手,所以希望这是可能的。
当我使用-O3
进行编译并在调用函数声明上指定__attribute__((flatten))
时,lambda 不是内联的。当我使用 perf 事件运行系统时,我可以看到该函数没有内联:
return _M_invoker(_M_functor, std::forward<_ArgTypes>(__args)...);
mov -0x90(%rbp),%rdi
lea -0x48(%rbp),%rsi
mov %rbx,%rdx
mov %r15,%rbx
callq *0x180(%r15)
...
这个调用花费了不小的时间,它似乎是内联的;总共只有几个调用站点。我以前当然见过内联的 lambda,但我不确定我使用函子(通过std::function
)的方法是否以某种方式取消了内联的资格。
强制内联可能吗?如果这里需要更多信息,请告诉我。
编辑:感谢所有非常有用的信息。我现在意识到,我设置运行时的方式并没有给编译器内联回调的机会。这些评论清楚地说明了为什么会这样。有一些关于替代方法的暗示可能是内联的。鉴于 1) 我控制应用程序和运行时源(以及编程模型/API);2)我正在同时编译库和应用程序(甚至可以使它们成为一个统一的构建过程),我是否可以在这里采取其他方法,可能会允许内联发生?也许模板和 lambda(不是std::functions
)?我是这个领域的新手,如果有人对如何有效地为编译器提供它需要内联的内容有想法,我会全力以赴。最坏的情况是,如果这开辟了任何可能性,我甚至可以为每个应用程序构建库的自定义版本(作为概念证明)......
std::function
的全部意义在于拥有一个通用类型,该类型可以保存某个签名的任意可调用对象,同时允许通过公共接口调用该任意可调用对象,而不管可调用对象实际是哪种类型。因此,如果你考虑一下,std::function
本质上需要某种间接。调用std::function
需要运行哪些代码不仅取决于类型,还取决于std::function
的特定值。这使得std::function
(至少是对存储的可调用对象的调用)本质上不可内联。为调用回调的函数生成的代码必须能够处理您可能抛出的任何std::function
。编译器可能为std::function
提供内联的唯一方法是,如果它以某种方式能够确定调用回调的函数大多数时候只会与std::function
持有特定值的对象一起使用,然后生成调用该特定情况回调的函数的克隆。这要么需要一个几乎不切实际的千里眼编译器才能达到,要么需要很多魔法硬连接到编译器中,只是为了std::function
而专门用于。从理论上讲,这并非完全不可能。但我从未见过任何编译器能够做这样的事情。根据我的经验,优化器只是无法真正看透std::function
。而且我预计这种情况不会很快改变,因为在那里进行任何有意义的优化似乎都需要付出巨大的努力才能获得相当可疑的好处。std::function
一开始只是重型机械。您只需为在那里使用的内容付费。如果你付不起代价,就不要用std::function
...
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 使用带有闭包的 lambda 的回调
- 通过实用程序 fn 将捕获的 lambda 传递给 C 样式回调 - 错误
- C++模板函数中,指定回调函子/lambda 的参数类型,同时仍允许内联?
- 如何成功地将函数对象(或lambda)传递给trackbar回调的第二个参数(void*)
- ROS:在nodehandle.subscribe中使用lambda作为回调
- 如何定义与将 Lambda 与捕获作为回调一起使用兼容的函数指针
- lambda回调中Android Cocos2D-X应用程序上的SEG故障
- 在库中的 C++17 中强制内联回调 (lambda)
- 如何使用C lambda将成员功能指针转换为普通功能指针,以用作回调
- std::函数,带有 SDL 事件回调的 lambda 错误
- 将lambda传递到lambda回调参数
- C lambda/回调弹出窗口
- C lambda回调为触发事件
- 允许 lambda/回调函数的多个签名作为模板参数
- 读取 Lambda 回调后的访问冲突
- 用C++lambda包装C回调,可以使用模板多态性
- 带有lambda的C++回调失败,返回bad_function_call
- 如何将C++lambda传递给需要函数指针和上下文的C回调
- 如何避免在调用异步函数进行 lambda 回调时出现额外的副本