C++ c+中std::min(int)的效率+;
我的代码中有一个循环,循环次数为1亿次(模拟模型的1亿次复制需要)。对于1亿次迭代中的每一次,我都通过对名为C++ c+中std::min(int)的效率+;,c++,performance,std,C++,Performance,Std,我的代码中有一个循环,循环次数为1亿次(模拟模型的1亿次复制需要)。对于1亿次迭代中的每一次,我都通过对名为age的整数变量进行索引,从数组(myarray)中检索一个值。由于数组的长度,只能为age=0,…,99索引myarray[age]。然而,age的实际域是0,…,inf 所以,我有下面的函数 int tidx(const int& a) { return std::min(a,99); } 它允许通过myarray[tidx(age)]进行索引 如何才能更有效地执行此
age
的整数变量进行索引,从数组(myarray
)中检索一个值。由于数组的长度,只能为age=0,…,99
索引myarray[age]
。然而,age
的实际域是0,…,inf
所以,我有下面的函数
int tidx(const int& a) {
return std::min(a,99);
}
它允许通过myarray[tidx(age)]
进行索引
如何才能更有效地执行此操作?
[下面的性能输出]
构建源文件的示例演示了我正在使用的编译器标志:
Building file: ../SAR.cpp
Invoking: GCC C++ Compiler
g++ -O3 -Wall -c -fmessage-length=0 -Wno-sign-compare -fopenmp -MMD -MP -MF"SAR.d" -MT"SAR.d" -o"SAR.o" "../SAR.cpp"
Finished building: ../SAR.cpp
从性能记录
,然后是性能报告
:
Samples: 280 of event 'cycles', Event count (approx.): 179855989
24.78% pc2 libc-2.17.so [.] __GI_____strtod_l_internal
11.35% pc2 pc2 [.] samplePSA(int, double, int, NRRan&)
6.67% pc2 libc-2.17.so [.] str_to_mpn.isra.0
6.15% pc2 pc2 [.] simulate4_NEJMdisutilities(Policy&, bool)
5.68% pc2 pc2 [.] (anonymous namespace)::stateTransition(double const&, int const&, int&, double const&, bool const&, bool&, bo
5.25% pc2 pc2 [.] HistogramAges::add(double const&)
3.73% pc2 libstdc++.so.6.0.17 [.] std::istream::getline(char*, long, char)
3.02% pc2 libstdc++.so.6.0.17 [.] std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_
2.49% pc2 [kernel.kallsyms] [k] 0xffffffff81043e6a
2.29% pc2 libc-2.17.so [.] __strlen_sse2
2.00% pc2 libc-2.17.so [.] __mpn_lshift
1.72% pc2 libstdc++.so.6.0.17 [.] __cxxabiv1::__vmi_class_type_info::__do_dyncast(long, __cxxabiv1::__class_type_info::__sub_kind, __cxxabiv1::
1.71% pc2 libc-2.17.so [.] __memcpy_ssse3_back
1.67% pc2 libstdc++.so.6.0.17 [.] std::locale::~locale()
1.65% pc2 libc-2.17.so [.] __mpn_construct_double
1.38% pc2 libc-2.17.so [.] memchr
1.29% pc2 pc2 [.] (anonymous namespace)::readTransitionMatrix(double*, std::string)
1.27% pc2 libstdc++.so.6.0.17 [.] std::string::_M_mutate(unsigned long, unsigned long, unsigned long)
1.15% pc2 libc-2.17.so [.] round_and_return
1.02% pc2 libc-2.17.so [.] __mpn_mul
1.01% pc2 libstdc++.so.6.0.17 [.] std::istream::sentry::sentry(std::istream&, bool)
1.00% pc2 libc-2.17.so [.] __memcpy_sse2
0.85% pc2 libstdc++.so.6.0.17 [.] std::locale::locale(std::locale const&)
0.85% pc2 libstdc++.so.6.0.17 [.] std::string::_M_replace_safe(unsigned long, unsigned long, char const*, unsigned long)
0.83% pc2 libstdc++.so.6.0.17 [.] std::locale::locale()
0.73% pc2 libc-2.17.so [.] __mpn_mul_1
如有任何意见,我将不胜感激。我需要学习如何解释/阅读这些信息,因此任何可能帮助我入门的提示都将不胜感激。为了优化代码,必须首先找出瓶颈所在。要找到瓶颈,必须分析代码。否则的话,很多时间将被浪费在做根本不重要的微优化/错误优化上 我没有在您的最小工作代码示例(您没有提供)上使用探查器,但根据我的经验,我可以告诉您,
tidx()
函数不是瓶颈,在这种情况下,您不应该关心std::min()
的性能。瓶颈更有可能是内存访问和停滞的CPU周期
对于初学者,如果可能的话,尝试展开循环(若编译器并没有为您这样做)。执行25000000次迭代可能比执行100000000次更有效,但在单个循环周期中执行更多。但是在你这样做之前,你必须确保展开循环是有帮助的,而不是有害的。这通常是通过分析来完成的,因此我们回到了这样一个问题:为了优化代码,必须首先找出瓶颈所在。要找到瓶颈。。。哦,等等,我差点进入不定式循环。正在中止。关于分析,已经给出了很好的建议
min(tx,ty)
应等于return(x
作为汇编器,这将成为:
mov x, %eax
cmp y, %eax
cmovg y, %eax
或者类似的东西。如果您在gcc中启用-O2,这三条指令肯定应该内联 需要研究的几个想法
- 检查为函数生成的装配。它可能会也可能不会编译成次优的东西
- 调用该函数的次数减少
- 重写该函数,以使用SSE指令一次计算4(或AVX为8)个值的最小值
- 重新构造函数的调用方式。理想情况下,调用之间的距离不应太远,以至于代码从指令缓存中被逐出
- 不要通过常量引用传递int。这有什么意义?只需传递一个int的副本
- 检查是否存在任何别名或虚假共享可能会降低您在呼叫站点的速度
但实际上,这是一个非常简单的函数。仅仅看一下它的实现并没有什么好处。我的大多数建议涉及如何调用函数、从何处调用函数、何时调用函数以及调用函数的数据。这些可能是您需要查看的内容。记住在启用优化的情况下评测可执行文件。对于性能测试来说,运行未优化的可执行文件是无用的,因为它将具有完全不同的性能特征
然后考虑一下你能做些什么来避免这么多的查找。做更少的工作(算法改进)将花费更少的时间
正如Herb Sutter喜欢说的那样,编写代码时不要“过早的伪化”
定义:过早悲观化是指当您编写的代码速度比需要的慢时,通常是要求进行不必要的额外工作,而相当复杂的代码会更快,并且应该自然地从您的手指中流出
例如,内联可能有帮助,也可能没有帮助,但您可能希望编写代码,以免妨碍内联。稍后,您可以强制或阻止内联,并比较哪些内联更适合您的执行环境。您可能也不想使用对int等小类型的引用。在没有优化的情况下,引用参数可能会使用指针来实现,现在指针通常比int更大、更慢。即使在32位硬件上,引用也不会比int更快
int tidx(int a) {
return std::min(a,99);
}
然后你可以尝试其他一些优化技术;独立任务是否并行运行?您的数据结构是否具有良好的引用特性局部性?如果事情并行运行,您是否受到虚假共享的影响?您可以使用SIMD或其他数据并行化吗?您还可以使用编译器设置或在代码的特定部分启用特定优化。这就是测试性能变得非常重要的地方,因为不同的硬件可以有完全不同的行为。而且,由于大多数这类优化都会混淆代码,因此您不想为很少或没有回报而付出代价。许多人犯的第一个错误是盯着代码看,盯着某个东西看,然后想知道他们是否能更快地完成
第二个错误是在上面运行gprof
,希望找到一个“瓶颈”
gprof
能够可靠地找到的唯一有用的东西是,您的代码是否是CPU绑定的,以及您编译的代码是否是CPU绑定的。
它不善于发现可以解决的函数调用问题。
它不善于发现您不知道自己在做的I/O问题
很多人使用,而且。我认为你不能<代码>标准::分钟
很可能是内联的,因此
int tidx(int a) {
return std::min(a,99);
}