【发布时间】:2020-09-15 10:13:48
【问题描述】:
有一个clang-tidy 选项performance-faster-string-find 可以检测std::basic_string::find 方法(和相关方法)的使用,其中单个字符串文字作为参数。据他们说,使用字符文字更有效。
我想执行一个小基准测试来测试它。因此,我做了这个小程序:
#include <string>
#include <chrono>
#include <iostream>
int main() {
int res = 0;
std::string s(STRING_LITERAL);
auto start = std::chrono::steady_clock::now();
for(int i = 0; i < 10000000; i++) {
#ifdef CHAR_TEST
res += s.find('A');
#else
res += s.find("A");
#endif
}
auto end = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
return res;
}
本程序使用了两个宏:
-
STRING_LITERAL将是std::string的内容,我们将在其上调用find函数。在我的基准测试中,这个宏可以有两个值:一个小字符串,比如"BAB"或一个长字符串,比如"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", -
CHAR_TEST,如果已定义,则运行字符文字的基准测试。如果不是,find会使用单个字符串字面量调用。
结果如下:
> (echo "char with small string" ; g++ -DSTRING_LITERAL=\"BAB\" -DCHAR_TEST -O3 -o toy_exe toy.cpp && ./toy_exe) ; (echo "string literal with small string" ; g++ -DSTRING_LITERAL=\"BAB\" -O3 -o toy_exe toy.cpp && ./toy_exe) ; (echo "char with long string" ; g++ -DSTRING_LITERAL=\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\" -DCHAR_TEST -O3 -o toy_exe toy.cpp && ./toy_exe) ; (echo "string literal with long string" ; g++ -DSTRING_LITERAL=\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\" -O3 -o toy_exe toy.cpp && ./toy_exe)
char with small string
elapsed time: 0.0551678s
string literal with small string
elapsed time: 0.0493302s
char with long string
elapsed time: 0.0599704s
string literal with long string
elapsed time: 0.188888s
我相当丑陋的命令运行了四种可能的宏组合的基准测试,我发现,std::string 很长,使用字符文字作为 find 的参数确实更有效,但它不再小std::string 是这样。我重复了这个实验,我总是发现小std::string 的字符文字的执行时间增加了大约 10%。
同时,我的一位同事对quick-bench.com 进行了一些基准测试,发现以下results:
- 带有字符文字的小
std::string:11 个时间单位 - 小
std::string,带单个字符串字面量:20 个时间单位 - 长
std::string字符字面量:13 个时间单位 - 长
std::string单字符串字面量:22 个时间单位
这些结果与 Clang-tidy 所声称的一致(并且听起来合乎逻辑)。那么,我的基准测试有什么问题?为什么我得到一致的错误结果?
编辑: 该基准测试是在 Debian 上使用 GCC 6.3.0 执行的。我也使用 Clang 8.0.0 运行它以获得类似的结果。
【问题讨论】:
-
你玩过编译器的优化级别吗?
-
@mlc 在我所有的测试中,我使用了
-O3优化级别。在 quick-bench.com 上进行的基准测试也是如此。 -
我假设您也在相同的编译器版本和相同的 c++ 标准中运行它?
-
@mlc 是的,您可以在我的问题中看到命令:
g++ -DSTRING_LITERAL=\"BAB\" -DCHAR_TEST -O3 -o toy_exe toy.cpp。不过,我也用 clang 和-std=c++11做了一些测试,并观察到类似的结果。 -
查看 quick-bench 上的代码,我看到他们使用
benchmark::DoNotOptimize()。似乎编译器为您和 quick-bench 上的代码做了不同的优化。请参阅:github.com/google/benchmark#preventing-optimization。
标签: c++ stdstring microbenchmark