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;
}
このプログラムでは2つのマクロが使用されます。
STRING_LITERAL
これは、find
関数を呼び出すstd::string
のコンテンツになります。私のベンチマークでは、このマクロは2つの値を持つことができます:小さな文字列、たとえば"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
私の非常に醜いコマンドは、マクロの4つの可能な組み合わせのベンチマークを実行し、長いstd::string
を使用して、find
の引数として文字リテラルを使用する方が確かに効率的ですが、小さいstd::string
には当てはまりません。実験を繰り返したところ、小さいstd::string
の文字リテラルの実行時間は常に約10%増加しました。
並行して、私の同僚の1人が quick-bench.com でいくつかのベンチマークを作成し、次の results を見つけました:
std::string
:11単位時間std::string
、1文字の文字列リテラル:20単位時間std::string
、文字リテラル:13単位時間std::string
と単一の文字列リテラル:22単位時間これらの結果は、clang-tidy(および論理的に聞こえる)の主張と一致しています。それで、私のベンチマークの何が問題になっていますか?なぜ一貫した間違った結果があるのですか?
EDIT:このベンチマークは、DebianでGCC 6.3.0を使用して実行されました。同様の結果を得るために、Clang 8.0.0を使用して実行しました。
ベンチのマーキングに問題があるとは思いません。 repl.ioプラットフォームでまったく同じコードを実行すると、「クイックベンチ」に一致する結果が得られます。
char with small string .elapsed time:0.402103s
stringリテラルsmall文字列経過時間:0.489828s
char with long文字列経過時間:0.400224s
stringリテラルlong文字列経過時間:0.53304s
頭に浮かぶことが1つあります。あなたのプロファイリングはループ上で行われます。