【发布时间】:2014-10-14 13:36:20
【问题描述】:
这是我正在查看的函数:
template <uint8_t Size>
inline uint64_t parseUnsigned( const char (&buf)[Size] )
{
uint64_t val = 0;
for (uint8_t i = 0; i < Size; ++i)
if (buf[i] != ' ')
val = (val * 10) + (buf[i] - '0');
return val;
}
我有一个测试工具,它通过所有可能的数字,大小为 5,左填充空格。我正在使用 GCC 4.7.2。当我用 -O3 编译后在 callgrind 下运行程序时,我得到:
I refs: 7,154,919
当我使用 -O2 编译时,我得到:
I refs: 9,001,570
好的,所以 -O3 提高了性能(我确认一些改进来自上述功能,而不仅仅是测试工具)。但我不想完全从 -O2 切换到 -O3,我想找出要添加的特定选项。所以我咨询man g++ 以获取它说由-O3 添加的选项列表:
-fgcse-after-reload [enabled]
-finline-functions [enabled]
-fipa-cp-clone [enabled]
-fpredictive-commoning [enabled]
-ftree-loop-distribute-patterns [enabled]
-ftree-vectorize [enabled]
-funswitch-loops [enabled]
所以我再次使用 -O2 编译,然后是上述所有选项。但这给了我比普通 -O2 更差的性能:
I refs: 9,546,017
我发现将 -ftree-vectorize 添加到 -O2 会导致性能下降。但我不知道如何将 -O3 性能与任何选项组合相匹配。我该怎么做?
如果您想自己尝试,这里是测试工具(将上述parseUnsigned() 定义放在#includes 下):
#include <cmath>
#include <stdint.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
template <uint8_t Size>
inline void increment( char (&buf)[Size] )
{
for (uint8_t i = Size - 1; i < 255; --i)
{
if (buf[i] == ' ')
{
buf[i] = '1';
break;
}
++buf[i];
if (buf[i] > '9')
buf[i] -= 10;
else
break;
}
}
int main()
{
char str[5];
memset(str, ' ', sizeof(str));
unsigned max = std::pow(10, sizeof(str));
for (unsigned ii = 0; ii < max; ++ii)
{
uint64_t result = parseUnsigned(str);
if (result != ii)
{
printf("parseUnsigned(%*s) from %u: %lu\n", sizeof(str), str, ii, result);
abort();
}
increment(str);
}
}
【问题讨论】:
-
除了使用 callgrind 之外,你有没有计时?
-
如果你真的想优化这个函数,基于
Size进行dispatch,这样64位算法只在字符串大到足以存储UINT_MAX以上的数字时使用。 -
不要查看手册页,而是尝试使用this command 来判断哪些选项真正被激活。
-
@BenVoigt:我现在做到了。我将
sizeof(str)从 5 更改为 9。然后-O2需要 11 秒,-O3需要 6.8 秒,-O2 -ftree-vectorize需要 13 秒。这是在运行 64 位 Linux 的 2.7 GHz Xeon E5-2697 上。
标签: c++ gcc optimization g++ compiler-optimization