mirror of https://github.com/orefkov/simstr.git
1914 lines
69 KiB
C++
1914 lines
69 KiB
C++
/*
|
||
* (c) Проект "SimStr", Александр Орефков orefkov@gmail.com
|
||
* Бенчмарки
|
||
*/
|
||
|
||
#include "bench.h"
|
||
#include <sstream>
|
||
#include <string>
|
||
#include <charconv>
|
||
|
||
using namespace simstr;
|
||
using namespace std::literals;
|
||
|
||
#define TEST_TEXT "Test text"
|
||
#define LONG_TEXT "123456789012345678901234567890"
|
||
#define TEXT_16 "abbaabbaabbaabba"
|
||
|
||
#define CHECK_RESULT
|
||
|
||
void __(benchmark::State& state) { for (auto _: state) {} }
|
||
|
||
template<typename T>
|
||
void CreateEmpty(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}
|
||
BENCHMARK(__)->Name("----- Create Empty Str ---------")->Repetitions(1);
|
||
BENCHMARK(CreateEmpty<std::string>) ->Name("std::string e;");
|
||
BENCHMARK(CreateEmpty<std::string_view>) ->Name("std::string_view e;");
|
||
BENCHMARK(CreateEmpty<ssa>) ->Name("ssa e;");
|
||
BENCHMARK(CreateEmpty<stringa>) ->Name("stringa e;");
|
||
BENCHMARK(CreateEmpty<lstringa<20>>) ->Name("lstringa<20> e;");
|
||
BENCHMARK(CreateEmpty<lstringa<40>>) ->Name("lstringa<40> e;");
|
||
|
||
template<typename T>
|
||
void CreateShortLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string = TEST_TEXT;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}
|
||
BENCHMARK(__)->Name("----- Create Str from short literal (9 symbols) --------")->Repetitions(1);
|
||
BENCHMARK(CreateShortLiteral<std::string>) ->Name("std::string e = \"Test text\";");
|
||
BENCHMARK(CreateShortLiteral<std::string_view>) ->Name("std::string_view e = \"Test text\";");
|
||
BENCHMARK(CreateShortLiteral<ssa>) ->Name("ssa e = \"Test text\";");
|
||
BENCHMARK(CreateShortLiteral<stringa>) ->Name("stringa e = \"Test text\";");
|
||
BENCHMARK(CreateShortLiteral<lstringa<20>>) ->Name("lstringa<20> e = \"Test text\";");
|
||
BENCHMARK(CreateShortLiteral<lstringa<40>>) ->Name("lstringa<40> e = \"Test text\";");
|
||
|
||
template<typename T>
|
||
void CreateLongLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string{LONG_TEXT};
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}
|
||
BENCHMARK(__)->Name("----- Create Str from long literal (30 symbols) ---------")->Repetitions(1);
|
||
BENCHMARK(CreateLongLiteral<std::string>) ->Name("std::string e = \"123456789012345678901234567890\";");
|
||
BENCHMARK(CreateLongLiteral<std::string_view>) ->Name("std::string_view e = \"123456789012345678901234567890\";");
|
||
BENCHMARK(CreateLongLiteral<ssa>) ->Name("ssa e = \"123456789012345678901234567890\";");
|
||
BENCHMARK(CreateLongLiteral<stringa>) ->Name("stringa e = \"123456789012345678901234567890\";");
|
||
BENCHMARK(CreateLongLiteral<lstringa<20>>) ->Name("lstringa<20> e = \"123456789012345678901234567890\";");
|
||
BENCHMARK(CreateLongLiteral<lstringa<40>>) ->Name("lstringa<40> e = \"123456789012345678901234567890\";");
|
||
|
||
template<typename T>
|
||
void CopyShortString(benchmark::State& state) {
|
||
T x{TEST_TEXT};
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}
|
||
BENCHMARK(__)->Name("----- Create copy of Str with 9 symbols ---------")->Repetitions(1);
|
||
BENCHMARK(CopyShortString<std::string>) ->Name("std::string e = \"Test text\"; auto c{e};");
|
||
BENCHMARK(CopyShortString<std::string_view>) ->Name("std::string_view e = \"Test text\"; auto c{e};");
|
||
BENCHMARK(CopyShortString<ssa>) ->Name("ssa e = \"Test text\"; auto c{e};");
|
||
BENCHMARK(CopyShortString<stringa>) ->Name("stringa e = \"Test text\"; auto c{e};");
|
||
BENCHMARK(CopyShortString<lstringa<20>>) ->Name("lstringa<20> e = \"Test text\"; auto c{e};");
|
||
BENCHMARK(CopyShortString<lstringa<40>>) ->Name("lstringa<40> e = \"Test text\"; auto c{e};");
|
||
|
||
template<typename T>
|
||
void CopyLongString(benchmark::State& state) {
|
||
T x = LONG_TEXT;
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("----- Create copy of Str with 30 symbols ---------")->Repetitions(1);
|
||
BENCHMARK(CopyLongString<std::string>) ->Name("std::string e = \"123456789012345678901234567890\"; auto c{e};");
|
||
BENCHMARK(CopyLongString<std::string_view>) ->Name("std::string_view e = \"123456789012345678901234567890\"; auto c{e};");
|
||
BENCHMARK(CopyLongString<ssa>) ->Name("ssa e = \"123456789012345678901234567890\"; auto c{e};");
|
||
BENCHMARK(CopyLongString<stringa>) ->Name("stringa e = \"123456789012345678901234567890\"; auto c{e};");
|
||
BENCHMARK(CopyLongString<lstringa<20>>) ->Name("lstringa<20> e = \"123456789012345678901234567890\"; auto c{e};");
|
||
BENCHMARK(CopyLongString<lstringa<40>>) ->Name("lstringa<40> e = \"123456789012345678901234567890\"; auto c{e};");
|
||
|
||
template<typename T>
|
||
void Find(benchmark::State& state) {
|
||
T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT};
|
||
for (auto _: state) {
|
||
int i = (int)x.find(TEST_TEXT);
|
||
#ifdef CHECK_RESULT
|
||
if (i != 90) {
|
||
state.SkipWithError("not find?");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(i);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}
|
||
BENCHMARK(__)->Name("----- Find 9 symbols text in end of 99 symbols text ---------")->Repetitions(1);
|
||
BENCHMARK(Find<std::string>) ->Name("std::string::find;");
|
||
BENCHMARK(Find<std::string_view>) ->Name("std::string_view::find;");
|
||
BENCHMARK(Find<ssa>) ->Name("ssa::find;");
|
||
BENCHMARK(Find<stringa>) ->Name("stringa::find;");
|
||
BENCHMARK(Find<lstringa<20>>) ->Name("lstringa<20>::find;");
|
||
BENCHMARK(Find<lstringa<40>>) ->Name("lstringa<40>::find;");
|
||
|
||
template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}
|
||
BENCHMARK(__)->Name("------- Copy not literal Str with N symbols ---------")->Repetitions(1);
|
||
BENCHMARK(CopyDynString<std::string>) ->Name("std::string copy{str_with_len_N};")->Arg(15)->Arg(16)->Arg(23)->Arg(24)->RangeMultiplier(2)->Range(32, 4096);
|
||
BENCHMARK(CopyDynString<stringa>) ->Name("stringa copy{str_with_len_N};")->Arg(15)->Arg(16)->Arg(23)->Arg(24)->RangeMultiplier(2)->Range(32, 4096);
|
||
BENCHMARK(CopyDynString<lstringa<16>>) ->Name("lstringa<16> copy{str_with_len_N};")->Arg(15)->Arg(16)->Arg(23)->Arg(24)->RangeMultiplier(2)->Range(32, 4096);
|
||
BENCHMARK(CopyDynString<lstringa<512>>) ->Name("lstringa<512> copy{str_with_len_N};")->Arg(15)->Arg(16)->Arg(23)->Arg(24)->RangeMultiplier(2)->Range(32, 4096);
|
||
|
||
void ToIntStr10(benchmark::State& state, const std::string& s, int c) {
|
||
for (auto _: state) {
|
||
int res = std::strtol(s.c_str(), nullptr, 10);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
|
||
void ToIntStr16(benchmark::State& state, const std::string& s, int c) {
|
||
for (auto _: state) {
|
||
int res = std::strtol(s.c_str(), nullptr, 16);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
|
||
void ToIntStr0(benchmark::State& state, const std::string& s, int c) {
|
||
for (auto _: state) {
|
||
int res = std::strtol(s.c_str(), nullptr, 0);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
|
||
void ToIntFromChars10(benchmark::State& state, const std::string_view& s, int c) {
|
||
//#ifdef __EMSCRIPTEN__
|
||
//state.SkipWithError("not implemented");
|
||
//#else
|
||
for (auto _: state) {
|
||
int res = 0;
|
||
std::from_chars(s.data(), s.data() + s.size(), res, 10);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
//#endif
|
||
}
|
||
|
||
void ToIntFromChars16(benchmark::State& state, const std::string_view& s, int c) {
|
||
//#ifdef __EMSCRIPTEN__
|
||
// state.SkipWithError("not implemented");
|
||
//#else
|
||
for (auto _: state) {
|
||
int res = 0;
|
||
std::from_chars(s.data(), s.data() + s.size(), res, 16);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
//#endif
|
||
}
|
||
|
||
template<typename T>
|
||
void ToIntSimStr10(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = std::get<0>(t. template to_int<int, true, 10, false, false>());
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}
|
||
|
||
template<typename T>
|
||
void ToIntSimStr16(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = std::get<0>(t. template to_int<int, true, 16, false, false>());
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}
|
||
|
||
template<typename T>
|
||
void ToIntSimStr0(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = std::get<0>(t. template to_int<int>());
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}
|
||
|
||
void ToIntNoOverflow(benchmark::State& state, ssa t, int c) {
|
||
for (auto _: state) {
|
||
int res = std::get<0>(t.to_int<int, false>());
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("----- Convert to int '1234567' ---------")->Repetitions(1);
|
||
BENCHMARK_CAPTURE(ToIntStr10, , std::string{"123456789"}, 123456789) ->Name("std::string s = \"123456789\"; int res = std::strtol(s.c_str(), 0, 10);");
|
||
BENCHMARK_CAPTURE(ToIntFromChars10, , std::string_view{"123456789"}, 123456789) ->Name("std::string_view s = \"123456789\"; std::from_chars(s.data(), s.data() + s.size(), res, 10);");
|
||
BENCHMARK_CAPTURE(ToIntSimStr10, , stringa{"123456789"}, 123456789) ->Name("stringa s = \"123456789\"; int res = s.to_int<int, true, 10, false>");
|
||
BENCHMARK_CAPTURE(ToIntSimStr10, , ssa{"123456789"}, 123456789) ->Name("ssa s = \"123456789\"; int res = s.to_int<int, true, 10, false>");
|
||
BENCHMARK_CAPTURE(ToIntSimStr10, , lstringa<20>{"123456789"}, 123456789) ->Name("lstringa<20> s = \"123456789\"; int res = s.to_int<int, true, 10, false>");
|
||
BENCHMARK(__)->Name("----- Convert to unsigned 'abcDef' ---------")->Repetitions(1);
|
||
BENCHMARK_CAPTURE(ToIntStr16, , std::string{"abcDef"}, 0xabcDef) ->Name("std::string s = \"abcDef\"; int res = std::strtol(s.c_str(), 0, 16);");
|
||
BENCHMARK_CAPTURE(ToIntFromChars16, , std::string_view{"abcDef"}, 0xabcDef) ->Name("std::string_view s = \"abcDef\"; std::from_chars(s.data(), s.data() + s.size(), res, 16);");
|
||
BENCHMARK_CAPTURE(ToIntSimStr16, , stringa{"abcDef"}, 0xabcDef) ->Name("stringa s = \"abcDef\"; int res = s.to_int<int, true, 16, false>");
|
||
BENCHMARK_CAPTURE(ToIntSimStr16, , ssa{"abcDef"}, 0xabcDef) ->Name("ssa s = \"abcDef\"; int res = s.to_int<int, true, 16, false>");
|
||
BENCHMARK_CAPTURE(ToIntSimStr16, >, lstringa<20>{"abcDef"}, 0xabcDef) ->Name("lstringa<20> s = \"abcDef\"; int res = s.to_int<int, true, 16, false>");
|
||
BENCHMARK(__)->Name("----- Convert to int ' 1234567' ---------")->Repetitions(1);
|
||
BENCHMARK_CAPTURE(ToIntStr0, , std::string{" 123456789"}, 123456789) ->Name("std::string s = \" 123456789\"; int res = std::strtol(s.c_str(), 0, 0);");
|
||
BENCHMARK_CAPTURE(ToIntSimStr0, , stringa{" 123456789"}, 123456789) ->Name("stringa s = \" 123456789\"; int res = s.to_int<int>; // Check overflow");
|
||
BENCHMARK_CAPTURE(ToIntNoOverflow, , ssa{" 123456789"}, 123456789) ->Name("ssa s = \" 123456789\"; int res = s.to_int<int, false>; // No check overflow");
|
||
|
||
void AppendStreamConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
std::string result;
|
||
std::stringstream str;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
str << TEXT_16;
|
||
}
|
||
result = str.str();
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(str);
|
||
}
|
||
}
|
||
|
||
void AppendStdStringConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
std::string result;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
result += TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
}
|
||
}
|
||
|
||
template<unsigned N>
|
||
void AppendLstringConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
result += TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("-- Append const literal of 16 bytes 64 times, 1024 total length --")->Repetitions(1);
|
||
BENCHMARK(AppendStreamConstLiteral) ->Name("std::stringstream str; ... str << \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendStdStringConstLiteral) ->Name("std::string str; ... str += \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendLstringConstLiteral<8>) ->Name("lstringa<8> str; ... str += \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendLstringConstLiteral<128>) ->Name("lstringa<128> str; ... str += \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendLstringConstLiteral<512>) ->Name("lstringa<512> str; ... str += \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendLstringConstLiteral<1024>)->Name("lstringa<1024> str; ... str += \"abbaabbaabbaabba\";");
|
||
|
||
void AppendStreamStrConstLiteral(benchmark::State& state) {
|
||
std::string s1 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
std::stringstream s;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
s << s1 << TEXT_16;
|
||
}
|
||
result = s.str();
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
}
|
||
}
|
||
|
||
void AppendStdStrStrConstLiteral(benchmark::State& state) {
|
||
std::string p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}
|
||
|
||
template<unsigned N>
|
||
void AppendLstringStrConstLiteral(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("-- Append string of 16 bytes and const literal of 16 bytes 32 times, 1024 total length --")->Repetitions(1);
|
||
BENCHMARK(AppendStreamStrConstLiteral) ->Name("std::stringstream str; ... str << str_var << \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendStdStrStrConstLiteral) ->Name("std::string str; ... str += str_var + \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendLstringStrConstLiteral<8>) ->Name("lstringa<8> str; ... str += str_var + \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendLstringStrConstLiteral<128>) ->Name("lstringa<128> str; ... str += str_var + \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendLstringStrConstLiteral<512>) ->Name("lstringa<512> str; ... str += str_var + \"abbaabbaabbaabba\";");
|
||
BENCHMARK(AppendLstringStrConstLiteral<1024>) ->Name("lstringa<1024> str; ... str += str_var + \"abbaabbaabbaabba\";");
|
||
|
||
|
||
void AppendStreamStrConstLiteralBig(benchmark::State& state) {
|
||
std::string s1 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
std::stringstream s;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
s << s1 << TEXT_16;
|
||
}
|
||
result = s.str();
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
}
|
||
}
|
||
|
||
void AppendStdStrStrConstLiteralBig(benchmark::State& state) {
|
||
std::string p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}
|
||
|
||
template<unsigned N>
|
||
void AppendLstringStrConstLiteralBig(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("-- Append string of 16 bytes and const literal of 16 bytes 2048 times, 65536 total length --")->Repetitions(1);
|
||
BENCHMARK(AppendStreamStrConstLiteralBig) ->Name("std::stringstream str; ... str << str_var << \"abbaabbaabbaabba\"; 2048 times");
|
||
BENCHMARK(AppendStdStrStrConstLiteralBig) ->Name("std::string str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times");
|
||
BENCHMARK(AppendLstringStrConstLiteralBig<8>) ->Name("lstringa<8> str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times");
|
||
BENCHMARK(AppendLstringStrConstLiteralBig<128>) ->Name("lstringa<128> str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times");
|
||
BENCHMARK(AppendLstringStrConstLiteralBig<512>) ->Name("lstringa<512> str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times");
|
||
BENCHMARK(AppendLstringStrConstLiteralBig<1024>) ->Name("lstringa<1024> str; ... str += str_var + \"abbaabbaabbaabba\"; 2048 times");
|
||
|
||
void AppendStream2String(benchmark::State& state) {
|
||
std::string s1 = TEXT_16;
|
||
std::string s2 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
std::stringstream s;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
s << s1 << s2;
|
||
}
|
||
result = s.str();
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}
|
||
|
||
void AppendStdStr2String(benchmark::State& state) {
|
||
std::string s1 = TEXT_16;
|
||
std::string s2 = TEXT_16;
|
||
|
||
for (auto _: state) {
|
||
std::string result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += s1 + s2;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}
|
||
|
||
template<unsigned N>
|
||
void AppendLstring2String(benchmark::State& state) {
|
||
stra s1 = TEXT_16;
|
||
stra s2 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += s1 + s2;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("-- Append 2 string of 16 bytes 32 times, 1024 total length --")->Repetitions(1);
|
||
BENCHMARK(AppendStream2String) ->Name("std::stringstream str; ... str << str_var1 << str_var2;");
|
||
BENCHMARK(AppendStdStr2String) ->Name("std::string str; ... str += str_var1 + str_var2;");
|
||
BENCHMARK(AppendLstring2String<8>) ->Name("lstringa<16> str; ... str += str_var1 + str_var2;");
|
||
BENCHMARK(AppendLstring2String<128>) ->Name("lstringa<128> str; ... str += str_var1 + str_var2;");
|
||
BENCHMARK(AppendLstring2String<512>) ->Name("lstringa<512> str; ... str += str_var1 + str_var2;");
|
||
BENCHMARK(AppendLstring2String<1024>) ->Name("lstringa<1024> str; ... str += str_var1 + str_var2;");
|
||
|
||
void AppendStreamStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
std::stringstream t;
|
||
t << "test = " << k << " times";
|
||
std::string result = t.str();
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}
|
||
|
||
void AppendStdStringStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
std::string result = "test = " + std::to_string(k) + " times";
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}
|
||
|
||
void AppendSprintfStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
char buf[100];
|
||
std::sprintf(buf, "test = %u times", k);
|
||
std::string result = buf;
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}
|
||
|
||
void AppendFormatStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
std::string result = std::format("test = {} times", k);
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}
|
||
|
||
template<typename T>
|
||
void AppendSimStrStrNumStrF(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
T result;
|
||
result.format("test = {} times", k);
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}
|
||
|
||
template<typename T>
|
||
void AppendSimStrStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
T result = "test = "_ss + k + " times";
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("-- Append text, number, text --")->Repetitions(1);
|
||
BENCHMARK(AppendStreamStrNumStr) ->Name("std::stringstream str; str << \"test = \" << k << \" times\";");
|
||
BENCHMARK(AppendStdStringStrNumStr) ->Name("std::string str = \"test = \" + std::to_string(k) + \" times\";");
|
||
BENCHMARK(AppendSprintfStrNumStr) ->Name("char buf[100]; sprintf(buf, \"test = %u times\", k); std::string str = buf;");
|
||
BENCHMARK(AppendFormatStrNumStr) ->Name("std::string str = std::format(\"test = {} times\", k);");
|
||
BENCHMARK(AppendSimStrStrNumStrF<lstringa<8>>) ->Name("lstringa<8> str; str.format(\"test = {} times\", k);");
|
||
BENCHMARK(AppendSimStrStrNumStrF<lstringa<32>>)->Name("lstringa<32> str; str.format(\"test = {} times\", k);");
|
||
BENCHMARK(AppendSimStrStrNumStr<lstringa<8>>) ->Name("lstringa<8> str = \"test = \" + k + \" times\";");
|
||
BENCHMARK(AppendSimStrStrNumStr<lstringa<32>>) ->Name("lstringa<32> str = \"test = \" + k + \" times\";");
|
||
BENCHMARK(AppendSimStrStrNumStr<stringa>) ->Name("stringa str = \"test = \" + k + \" times\";");
|
||
|
||
const char NUMBER_LIST[] = "1-!- 2-!- 3-!- 4 -!- 5-!- 6 -!- 7-!- -8-!- 0xaF-!- 15-!- 010"; // 218
|
||
|
||
void SplitConvertIntStdString(benchmark::State& state) {
|
||
std::string numbers = NUMBER_LIST;
|
||
for (auto _: state) {
|
||
int total = 0;
|
||
for (size_t start = 0; start < numbers.length(); ) {
|
||
int delim = numbers.find("-!-", start);
|
||
if (delim == std::string::npos) {
|
||
delim = numbers.size();
|
||
}
|
||
std::string part = numbers.substr(start, delim - start);
|
||
total += std::strtol(part.c_str(), nullptr, 0);
|
||
start = delim + 3;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (total != 218) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(total);
|
||
benchmark::DoNotOptimize(numbers);
|
||
}
|
||
}
|
||
|
||
void SplitConvertIntSimStr(benchmark::State& state) {
|
||
stra numbers = NUMBER_LIST;
|
||
for (auto _: state) {
|
||
int total = 0;
|
||
for (auto splitter = numbers.splitter("-!-"); !splitter.is_done();) {
|
||
total += splitter.next().as_int<int>();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (total != 218) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(total);
|
||
benchmark::DoNotOptimize(numbers);
|
||
}
|
||
}
|
||
void SplitConvertIntSplitf(benchmark::State& state) {
|
||
stra numbers = NUMBER_LIST;
|
||
for (auto _: state) {
|
||
int total = 0;
|
||
numbers.splitf<void>("-!-", [&](ssa& part){total += part.as_int<int>();});
|
||
#ifdef CHECK_RESULT
|
||
if (total != 218) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(total);
|
||
benchmark::DoNotOptimize(numbers);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("-- Split text and convert to int --")->Repetitions(1);
|
||
BENCHMARK(SplitConvertIntStdString) ->Name("std::string::find + substr + std::strtol");
|
||
BENCHMARK(SplitConvertIntSimStr) ->Name("ssa::splitter + ssa::as_int");
|
||
BENCHMARK(SplitConvertIntSplitf) ->Name("ssa::splitf + functor");
|
||
|
||
void ReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
std::vector<std::pair<u8s, std::string_view>> repl = {
|
||
{'&', "&"},
|
||
{'-', ""},
|
||
{'<', "<"},
|
||
{'>', ">"},
|
||
{'\'', "'"},
|
||
{'\"', """}
|
||
};
|
||
|
||
auto repl_all = [](std::string& str, char s, std::string_view repl) {
|
||
size_t start_pos = 0;
|
||
while((start_pos = str.find(s, start_pos)) != std::string::npos) {
|
||
str.replace(start_pos, 1, repl);
|
||
start_pos += repl.length();
|
||
}
|
||
};
|
||
for (auto _: state) {
|
||
std::string result{source};
|
||
for (const auto& r : repl) {
|
||
repl_all(result, r.first, r.second);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
void ReplaceSymbolsStdStringNaiveRight(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
std::vector<std::pair<u8s, std::string_view>> repl = {
|
||
{'-', ""},
|
||
{'<', "<"},
|
||
{'>', ">"},
|
||
{'\'', "'"},
|
||
{'\"', """},
|
||
{'&', "&"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
std::string result{source};
|
||
std::string pattern;
|
||
for (const auto& r : repl) {
|
||
pattern += r.first;
|
||
}
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find_first_of(pattern, start_pos)) != std::string::npos) {
|
||
size_t idx = pattern.find(result[start_pos]);
|
||
result.replace(start_pos, 1, repl[idx].second);
|
||
start_pos += repl[idx].second.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
void ReplaceSymbolsStdString(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
|
||
const std::string_view repl_from = "-<>'\"&";
|
||
const std::string_view repl_to[] = {"", "<", ">", "'", """, "&"};
|
||
|
||
for (auto _: state) {
|
||
std::string result;
|
||
|
||
for (size_t start = 0; start < source.size();) {
|
||
size_t idx = source.find_first_of(repl_from, start);
|
||
if (idx == std::string::npos) {
|
||
result += source.substr(start);
|
||
break;
|
||
}
|
||
if (idx > start) {
|
||
result += source.substr(start, idx - start);
|
||
}
|
||
size_t what = repl_from.find(source[idx]);
|
||
result += repl_to[what];
|
||
|
||
start = idx + 1;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}
|
||
|
||
template<bool UseVector>
|
||
void ReplaceSymbolsDynPatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
|
||
std::vector<std::pair<u8s, ssa>> repl = {
|
||
{'-', ""},
|
||
{'<', "<"},
|
||
{'>', ">"},
|
||
{'\'', "'"},
|
||
{'\"', """},
|
||
{'&', "&"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
stringa result = expr_replace_symbols<u8s, UseVector>{source, repl};
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
template<bool UseVector>
|
||
void ReplaceSymbolsCons2PatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl_const_symbols<UseVector>(source,
|
||
'-', "",
|
||
'<', "<",
|
||
'>', ">",
|
||
'\'', "'",
|
||
'\"', """,
|
||
'&', "&"
|
||
);
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjdfksjd "dkjfsjkhdf dfj ' kdkd "dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("-- Replace symbols in text ~400 symbols --")->Repetitions(1);
|
||
BENCHMARK(ReplaceSymbolsStdStringNaiveWrong) ->Name("Naive (and wrong) replace symbols with std::string find + replace");
|
||
BENCHMARK(ReplaceSymbolsStdStringNaiveRight) ->Name("replace symbols with std::string find_first_of + replace");
|
||
BENCHMARK(ReplaceSymbolsStdString) ->Name("replace symbols with std::string_view find_first_of + copy");
|
||
BENCHMARK(ReplaceSymbolsDynPatternSimStr<false>) ->Name("replace runtime symbols with string expressions and without remembering all search results");
|
||
BENCHMARK(ReplaceSymbolsDynPatternSimStr<true>) ->Name("replace runtime symbols with simstr and memorization of all search results");
|
||
BENCHMARK(ReplaceSymbolsCons2PatternSimStr<false>) ->Name("replace const symbols with string expressions and without remembering all search results");
|
||
BENCHMARK(ReplaceSymbolsCons2PatternSimStr<true>) ->Name("replace const symbols with string expressions and memorization of all search results");
|
||
|
||
|
||
void ShortReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
std::vector<std::pair<u8s, std::string_view>> repl = {
|
||
{'&', "&"},
|
||
{'-', ""},
|
||
{'<', "<"},
|
||
{'>', ">"},
|
||
{'\'', "'"},
|
||
{'\"', """}
|
||
};
|
||
|
||
auto repl_all = [](std::string& str, char s, std::string_view repl) {
|
||
size_t start_pos = 0;
|
||
while((start_pos = str.find(s, start_pos)) != std::string::npos) {
|
||
str.replace(start_pos, 1, repl);
|
||
start_pos += repl.length();
|
||
}
|
||
};
|
||
for (auto _: state) {
|
||
std::string result{source};
|
||
for (const auto& r : repl) {
|
||
repl_all(result, r.first, r.second);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
void ShortReplaceSymbolsStdStringNaiveRight(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
std::vector<std::pair<u8s, std::string_view>> repl = {
|
||
{'-', ""},
|
||
{'<', "<"},
|
||
{'>', ">"},
|
||
{'\'', "'"},
|
||
{'\"', """},
|
||
{'&', "&"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
std::string result{source};
|
||
std::string pattern;
|
||
for (const auto& r : repl) {
|
||
pattern += r.first;
|
||
}
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find_first_of(pattern, start_pos)) != std::string::npos) {
|
||
size_t idx = pattern.find(result[start_pos]);
|
||
result.replace(start_pos, 1, repl[idx].second);
|
||
start_pos += repl[idx].second.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
void ShortReplaceSymbolsStdString(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
|
||
const std::string_view repl_from = "-<>'\"&";
|
||
const std::string_view repl_to[] = {"", "<", ">", "'", """, "&"};
|
||
|
||
for (auto _: state) {
|
||
std::string result;
|
||
|
||
for (size_t start = 0; start < source.size();) {
|
||
size_t idx = source.find_first_of(repl_from, start);
|
||
if (idx == std::string::npos) {
|
||
result += source.substr(start);
|
||
break;
|
||
}
|
||
if (idx > start) {
|
||
result += source.substr(start, idx - start);
|
||
}
|
||
size_t what = repl_from.find_first_of(source[idx]);
|
||
result += repl_to[what];
|
||
|
||
start = idx + 1;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}
|
||
|
||
template<bool UseVector>
|
||
void ShortReplaceSymbolsDynPatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
|
||
std::vector<std::pair<u8s, ssa>> repl = {
|
||
{'-', ""},
|
||
{'<', "<"},
|
||
{'>', ">"},
|
||
{'\'', "'"},
|
||
{'\"', """},
|
||
{'&', "&"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
stringa result = expr_replace_symbols<u8s, UseVector>{source, repl};
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
template<bool UseVector>
|
||
void ShortReplaceSymbolsCons2PatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl_const_symbols<UseVector>(source,
|
||
'-', "",
|
||
'<', "<",
|
||
'>', ">",
|
||
'\'', "'",
|
||
'\"', """,
|
||
'&', "&"
|
||
);
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("-- Replace symbols in text ~40 symbols --")->Repetitions(1);
|
||
BENCHMARK(ShortReplaceSymbolsStdStringNaiveWrong) ->Name("Short Naive (and wrong) replace symbols with std::string find + replace");
|
||
BENCHMARK(ShortReplaceSymbolsStdStringNaiveRight) ->Name("Short replace symbols with std::string find_first_of + replace");
|
||
BENCHMARK(ShortReplaceSymbolsStdString) ->Name("Short replace symbols with std::string_view find_first_of + copy");
|
||
BENCHMARK(ShortReplaceSymbolsDynPatternSimStr<false>) ->Name("Short replace runtime symbols with string expressions and without remembering all search results");
|
||
BENCHMARK(ShortReplaceSymbolsDynPatternSimStr<true>) ->Name("Short replace runtime symbols with simstr and memorization of all search results");
|
||
BENCHMARK(ShortReplaceSymbolsCons2PatternSimStr<false>) ->Name("Short replace const symbols with string expressions and without remembering all search results");
|
||
BENCHMARK(ShortReplaceSymbolsCons2PatternSimStr<true>) ->Name("Short replace const symbols with string expressions and memorization of all search results");
|
||
|
||
template<size_t Long>
|
||
void ReplaceAllLongerStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "----";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
template<size_t N, size_t Count>
|
||
void ReplaceAllLongerSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}
|
||
|
||
template<size_t Count>
|
||
void ReplaceAllLongerSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}
|
||
|
||
template<size_t Long>
|
||
void ReplaceAllEqualStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "--";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
template<size_t N, size_t Long>
|
||
void ReplaceAllEqualSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
lstringa<2048> big_source{Long, source}, big_sample{Long, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}
|
||
|
||
template<size_t Count>
|
||
void ReplaceAllEqualSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
ssa pattern = "bb";
|
||
ssa repl = "--";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("----- Replace All Str To Longer Size ---------")->Repetitions(1);
|
||
BENCHMARK(ReplaceAllLongerStdString<1>) ->Name("replace bb to ---- in std::string|64");
|
||
BENCHMARK(ReplaceAllLongerStdString<4>) ->Name("replace bb to ---- in std::string|256");
|
||
BENCHMARK(ReplaceAllLongerStdString<8>) ->Name("replace bb to ---- in std::string|512");
|
||
BENCHMARK(ReplaceAllLongerStdString<16>) ->Name("replace bb to ---- in std::string|1024");
|
||
BENCHMARK(ReplaceAllLongerStdString<32>) ->Name("replace bb to ---- in std::string|2048");
|
||
BENCHMARK(ReplaceAllLongerSimString<8, 1>) ->Name("replace bb to ---- in lstringa<8>|64");
|
||
BENCHMARK(ReplaceAllLongerSimString<8, 4>) ->Name("replace bb to ---- in lstringa<8>|256");
|
||
BENCHMARK(ReplaceAllLongerSimString<8, 8>) ->Name("replace bb to ---- in lstringa<8>|512");
|
||
BENCHMARK(ReplaceAllLongerSimString<8, 16>) ->Name("replace bb to ---- in lstringa<8>|1024");
|
||
BENCHMARK(ReplaceAllLongerSimString<8, 32>) ->Name("replace bb to ---- in lstringa<8>|2048");
|
||
BENCHMARK(ReplaceAllLongerSimStringExpr<1>) ->Name("replace bb to ---- by init stringa|64");
|
||
BENCHMARK(ReplaceAllLongerSimStringExpr<4>) ->Name("replace bb to ---- by init stringa|256");
|
||
BENCHMARK(ReplaceAllLongerSimStringExpr<8>) ->Name("replace bb to ---- by init stringa|512");
|
||
BENCHMARK(ReplaceAllLongerSimStringExpr<16>) ->Name("replace bb to ---- by init stringa|1024");
|
||
BENCHMARK(ReplaceAllLongerSimStringExpr<32>) ->Name("replace bb to ---- by init stringa|2048");
|
||
|
||
BENCHMARK(__)->Name("----- Replace All Str To Same Size ---------")->Repetitions(1);
|
||
BENCHMARK(ReplaceAllEqualStdString<1>) ->Name("replace bb to -- in std::string|64");
|
||
BENCHMARK(ReplaceAllEqualStdString<4>) ->Name("replace bb to -- in std::string|256");
|
||
BENCHMARK(ReplaceAllEqualStdString<8>) ->Name("replace bb to -- in std::string|512");
|
||
BENCHMARK(ReplaceAllEqualStdString<16>) ->Name("replace bb to -- in std::string|1024");
|
||
BENCHMARK(ReplaceAllEqualStdString<32>) ->Name("replace bb to -- in std::string|2048");
|
||
BENCHMARK(ReplaceAllEqualSimString<8, 1>) ->Name("replace bb to -- in lstringa<8>|64");
|
||
BENCHMARK(ReplaceAllEqualSimString<8, 4>) ->Name("replace bb to -- in lstringa<8>|256");
|
||
BENCHMARK(ReplaceAllEqualSimString<8, 8>) ->Name("replace bb to -- in lstringa<8>|512");
|
||
BENCHMARK(ReplaceAllEqualSimString<8, 16>) ->Name("replace bb to -- in lstringa<8>|1024");
|
||
BENCHMARK(ReplaceAllEqualSimString<8, 32>) ->Name("replace bb to -- in lstringa<8>|2048");
|
||
BENCHMARK(ReplaceAllEqualSimStringExpr<1>) ->Name("replace bb to -- by init stringa|64");
|
||
BENCHMARK(ReplaceAllEqualSimStringExpr<4>) ->Name("replace bb to -- by init stringa|256");
|
||
BENCHMARK(ReplaceAllEqualSimStringExpr<8>) ->Name("replace bb to -- by init stringa|512");
|
||
BENCHMARK(ReplaceAllEqualSimStringExpr<16>) ->Name("replace bb to -- by init stringa|1024");
|
||
BENCHMARK(ReplaceAllEqualSimStringExpr<32>) ->Name("replace bb to -- by init stringa|2048");
|
||
|
||
std::vector<stringa> prepareTestStrings(size_t length, size_t delta, size_t count) {
|
||
std::vector<stringa> result;
|
||
result.reserve(count);
|
||
|
||
struct expr_rand {
|
||
using symb_type = u8s;
|
||
size_t len;
|
||
size_t length() const noexcept {
|
||
return len;
|
||
}
|
||
char* place(char* ptr) const {
|
||
for (size_t idx = len; idx > 0; idx--) {
|
||
*ptr++ = char(' ' + std::rand() % 200);
|
||
}
|
||
return ptr;
|
||
}
|
||
};
|
||
|
||
for (size_t idx = 0; idx < count; idx++) {
|
||
result.emplace_back(expr_rand{length + std::rand() % delta});
|
||
}
|
||
return result;
|
||
}
|
||
|
||
std::vector<stringa> bs_sim = prepareTestStrings(30, 20, 10'000);
|
||
|
||
std::vector<std::string> prepareTestStdStrings() {
|
||
std::vector<std::string> result;
|
||
result.reserve(bs_sim.size());
|
||
for (const auto& s: bs_sim) {
|
||
result.emplace_back(s.to_string());
|
||
}
|
||
return result;
|
||
}
|
||
|
||
std::vector<std::string> bs_std = prepareTestStdStrings();
|
||
|
||
void HashMapSimStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
hashStrMapA<size_t> store;
|
||
for (size_t idx = 0; idx < bs_sim.size(); idx++) {
|
||
store.try_emplace(bs_sim[idx], idx);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (store.size() != bs_sim.size()) {
|
||
state.SkipWithError("bad inserts");
|
||
}
|
||
#endif
|
||
for (size_t idx = 0; idx < bs_sim.size(); idx++) {
|
||
auto find = store.find(bs_sim[idx]);
|
||
size_t res = find->second;
|
||
#ifdef CHECK_RESULT
|
||
if (res != idx) {
|
||
state.SkipWithError("bad find");
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
}
|
||
|
||
void HashMapStdStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
std::unordered_map<std::string, size_t> store;
|
||
for (size_t idx = 0; idx < bs_std.size(); idx++) {
|
||
store.try_emplace(bs_std[idx], idx);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (store.size() != bs_std.size()) {
|
||
state.SkipWithError("bad inserts");
|
||
}
|
||
#endif
|
||
for (size_t idx = 0; idx < bs_std.size(); idx++) {
|
||
auto find = store.find(bs_std[idx]);
|
||
size_t res = find->second;
|
||
#ifdef CHECK_RESULT
|
||
if (res != idx) {
|
||
state.SkipWithError("bad find");
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
}
|
||
|
||
void HashMapSimSsa(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
hashStrMapA<size_t> store;
|
||
for (size_t idx = 0; idx < bs_sim.size(); idx++) {
|
||
store.emplace(bs_sim[idx], idx);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (store.size() != bs_sim.size()) {
|
||
state.SkipWithError("bad inserts");
|
||
}
|
||
#endif
|
||
for (size_t idx = 0; idx < bs_sim.size(); idx++) {
|
||
ssa key = bs_sim[idx];
|
||
auto find = store.find(key);
|
||
size_t res = find->second;
|
||
#ifdef CHECK_RESULT
|
||
if (res != idx) {
|
||
state.SkipWithError("bad find");
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
}
|
||
|
||
void HashMapStdStrView(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
std::unordered_map<std::string, size_t> store;
|
||
for (size_t idx = 0; idx < bs_std.size(); idx++) {
|
||
store.emplace(bs_std[idx], idx);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (store.size() != bs_std.size()) {
|
||
state.SkipWithError("bad inserts");
|
||
}
|
||
#endif
|
||
for (size_t idx = 0; idx < bs_std.size(); idx++) {
|
||
std::string_view key = bs_std[idx];
|
||
auto find = store.find(std::string{key});
|
||
size_t res = find->second;
|
||
#ifdef CHECK_RESULT
|
||
if (res != idx) {
|
||
state.SkipWithError("bad find");
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("----- Hash Map insert and find ---------")->Repetitions(1);
|
||
BENCHMARK(HashMapSimStr)->Name("hashStrMapA<size_t> emplace & find stringa;");
|
||
BENCHMARK(HashMapStdStr)->Name("std::unordered_map<std::string, size_t> emplace & find std::string;");
|
||
BENCHMARK(HashMapSimSsa)->Name("hashStrMapA<size_t> emplace & find ssa;");
|
||
BENCHMARK(HashMapStdStrView)->Name("std::unordered_map<std::string, size_t> emplace & find std::string_view;");
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// Набор тестов, имитирующий довольно типовой сценарий, похож на то, что встречалось в работе
|
||
// По имеющимся данным о неких функциях и их параметрах - построить полное имя функции
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
enum class Types {
|
||
int2,
|
||
int4,
|
||
int8,
|
||
bytea,
|
||
text,
|
||
char_,
|
||
varchar,
|
||
boolean,
|
||
last,
|
||
};
|
||
|
||
const ssa type_names[] = {
|
||
"int2",
|
||
"int4",
|
||
"int8",
|
||
"bytea",
|
||
"text",
|
||
"char",
|
||
"varchar",
|
||
"boolean"
|
||
};
|
||
|
||
const std::string_view type_names_sv[] = {
|
||
"int2",
|
||
"int4",
|
||
"int8",
|
||
"bytea",
|
||
"text",
|
||
"char",
|
||
"varchar",
|
||
"boolean"
|
||
};
|
||
|
||
constexpr bool is_power_of_two_or_zero(uint32_t value) {
|
||
return !(value & (value - 1));
|
||
}
|
||
|
||
struct type_set {
|
||
uint32_t value;
|
||
void to_simstr(mutable_str<u8s> auto& str) const {
|
||
if (!value) {
|
||
str += "{?}";
|
||
} else if (value == 0xFFFFFFFF) {
|
||
str += "any";
|
||
} else {
|
||
if (!is_power_of_two_or_zero(value)) {
|
||
str += "{";
|
||
}
|
||
bool add_comma = false;
|
||
for (unsigned idx = 0; idx < (unsigned)Types::last; idx++) {
|
||
if (value & (1 << idx)) {
|
||
str += e_if(add_comma, ", ") + type_names[idx];
|
||
add_comma = true;
|
||
}
|
||
}
|
||
if (!is_power_of_two_or_zero(value)) {
|
||
str += "}";
|
||
}
|
||
}
|
||
}
|
||
auto get_simstr() const {
|
||
lstringa<128> str;
|
||
if (!value) {
|
||
str = "{?}";
|
||
} else if (value == 0xFFFFFFFF) {
|
||
str = "any";
|
||
} else {
|
||
if (!is_power_of_two_or_zero(value)) {
|
||
str = "{";
|
||
}
|
||
bool add_comma = false;
|
||
for (unsigned idx = 0; idx < (unsigned)Types::last; idx++) {
|
||
if (value & (1 << idx)) {
|
||
str += e_if(add_comma, ", ") + type_names[idx];
|
||
add_comma = true;
|
||
}
|
||
}
|
||
if (!is_power_of_two_or_zero(value)) {
|
||
str += "}";
|
||
}
|
||
}
|
||
return str;
|
||
}
|
||
void to_stdstr(std::string& str) const {
|
||
if (!value) {
|
||
str += "{?}";
|
||
} else if (value == 0xFFFFFFFF) {
|
||
str += "any";
|
||
} else {
|
||
if (!is_power_of_two_or_zero(value)) {
|
||
str += "{";
|
||
}
|
||
bool add_comma = false;
|
||
for (unsigned idx = 0; idx < (unsigned)Types::last; idx++) {
|
||
if (value & (1 << idx)) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
str += type_names_sv[idx];
|
||
add_comma = true;
|
||
}
|
||
}
|
||
if (!is_power_of_two_or_zero(value)) {
|
||
str += "}";
|
||
}
|
||
}
|
||
}
|
||
void to_stream(std::ostream& str) const {
|
||
if (!value) {
|
||
str << "{?}";
|
||
} else if (value == 0xFFFFFFFF) {
|
||
str << "any";
|
||
} else {
|
||
if (!is_power_of_two_or_zero(value)) {
|
||
str << "{";
|
||
}
|
||
bool add_comma = false;
|
||
for (unsigned idx = 0; idx < (unsigned)Types::last; idx++) {
|
||
if (value & (1 << idx)) {
|
||
if (add_comma) {
|
||
str << ", ";
|
||
}
|
||
str << type_names_sv[idx];
|
||
add_comma = true;
|
||
}
|
||
}
|
||
if (!is_power_of_two_or_zero(value)) {
|
||
str << "}";
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
struct param {
|
||
type_set allowed_types;
|
||
bool optional;
|
||
};
|
||
|
||
struct function {
|
||
stringa name;
|
||
std::string std_name;
|
||
std::vector<param> params;
|
||
Types ret_type;
|
||
bool has_ret_type_resolver;
|
||
bool unlim_params;
|
||
// Построение полного имени с помощью simstr строковых объектов и выражений
|
||
stringa build_full_name() const {
|
||
lstringa<512> str = e_choice(has_ret_type_resolver, "any", type_names[(unsigned)ret_type]) + " " + name + "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
str += e_if(add_comma, ", ") + e_if(param.optional, "[");
|
||
param.allowed_types.to_simstr(str);
|
||
if (param.optional) {
|
||
str += "]";
|
||
}
|
||
add_comma = true;
|
||
}
|
||
return str + e_if(unlim_params, e_if(add_comma, ", ") + "...") + ")";
|
||
}
|
||
stringa build_full_name1() const {
|
||
lstringa<512> str = e_choice(has_ret_type_resolver, "any", type_names[(unsigned)ret_type]) + " " + name + "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
str += e_if(add_comma, ", ") + e_if(param.optional, "[") + param.allowed_types.get_simstr() + e_if(param.optional, "]");
|
||
add_comma = true;
|
||
}
|
||
return str + e_if(unlim_params, e_if(add_comma, ", ") + "...") + ")";
|
||
}
|
||
// Построение полного имени с помощью std::string
|
||
std::string build_full_name_std() const {
|
||
std::string str{has_ret_type_resolver ? "any"sv : type_names_sv[(unsigned)ret_type]};
|
||
str += " ";
|
||
str += std_name;
|
||
str += "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
if (param.optional) {
|
||
str += "[";
|
||
}
|
||
param.allowed_types.to_stdstr(str);
|
||
if (param.optional) {
|
||
str += "]";
|
||
}
|
||
add_comma = true;
|
||
}
|
||
if (unlim_params) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
str += "...";
|
||
}
|
||
str += ")";
|
||
//std::cout << "Len=" << str.length() << ", Cap=" << str.capacity() << "\n";
|
||
return str;
|
||
}
|
||
// Построение полного имени с помощью std::string
|
||
std::string build_full_name_std1() const {
|
||
std::string str{has_ret_type_resolver ? "any"sv : type_names_sv[(unsigned)ret_type]};
|
||
str += " " + std_name + "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
if (param.optional) {
|
||
str += "[";
|
||
}
|
||
param.allowed_types.to_stdstr(str);
|
||
if (param.optional) {
|
||
str += "]";
|
||
}
|
||
add_comma = true;
|
||
}
|
||
if (unlim_params) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
str += "...";
|
||
}
|
||
str += ")";
|
||
//std::cout << "Len=" << str.length() << ", Cap=" << str.capacity() << "\n";
|
||
return str;
|
||
}
|
||
// Построение полного имени с помощью std::ostringstream
|
||
std::string build_full_name_stream() const {
|
||
std::ostringstream str;
|
||
if (has_ret_type_resolver) {
|
||
str << "any";
|
||
} else {
|
||
str << type_names_sv[(unsigned)ret_type];
|
||
}
|
||
str << " " << std_name << "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
if (add_comma) {
|
||
str << ", ";
|
||
}
|
||
if (param.optional) {
|
||
str << "[";
|
||
}
|
||
param.allowed_types.to_stream(str);
|
||
if (param.optional) {
|
||
str << "]";
|
||
}
|
||
add_comma = true;
|
||
}
|
||
if (unlim_params) {
|
||
if (add_comma) {
|
||
str << ", ";
|
||
}
|
||
str << "...";
|
||
}
|
||
str << ")";
|
||
return str.str();
|
||
}
|
||
};
|
||
// Тестовые варианты функций
|
||
const struct {
|
||
function f;
|
||
std::string_view check;
|
||
} functions[] = {
|
||
{{"func1", "func1", {}, Types::boolean, true, true}, "any func1(...)"},
|
||
{{"function2", "function2", {{4, false}, {12, true}}, Types::int2, false, false}, "int2 function2(int8, [{int8, bytea}])"},
|
||
{{"func3", "func3", {{16, false}, {7, false}, {32, true}}, Types::char_, false, true}, "char func3(text, {int2, int4, int8}, [char], ...)"},
|
||
{{"function4", "function4", {{10, false}, {64, false}, {31, true}}, Types::char_, true, false}, "any function4({int4, bytea}, varchar, [{int2, int4, int8, bytea, text}])"},
|
||
{{"f5", "f5", {{10, false}, {64, false}, {0xFFFFFFFF, false}}, Types::text, false, true}, "text f5({int4, bytea}, varchar, any, ...)"},
|
||
};
|
||
|
||
// Замеры скорости выполнения разных вариантов
|
||
|
||
//> stringa build_full_name() const {
|
||
void BuildFuncNameSimStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (const auto& f : functions) {
|
||
stringa res = f.f.build_full_name();
|
||
benchmark::DoNotOptimize(res);
|
||
#ifdef CHECK_RESULT
|
||
if (res != stra{f.check}) {
|
||
std::cout << res << "\n";
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
//> stringa build_full_name1() const {
|
||
void BuildFuncNameSimStr1(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (const auto& f : functions) {
|
||
stringa res = f.f.build_full_name1();
|
||
benchmark::DoNotOptimize(res);
|
||
#ifdef CHECK_RESULT
|
||
if (res != stra{f.check}) {
|
||
std::cout << res << "\n";
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
//> std::string build_full_name_std() const {
|
||
void BuildFuncNameStdStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (const auto& f : functions) {
|
||
std::string res = f.f.build_full_name_std();
|
||
benchmark::DoNotOptimize(res);
|
||
#ifdef CHECK_RESULT
|
||
if (res != f.check) {
|
||
std::cout << res << "\n";
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
//> std::string build_full_name_std1() const {
|
||
void BuildFuncNameStdStr1(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (const auto& f : functions) {
|
||
std::string res = f.f.build_full_name_std1();
|
||
benchmark::DoNotOptimize(res);
|
||
#ifdef CHECK_RESULT
|
||
if (res != f.check) {
|
||
std::cout << res << "\n";
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
//> std::string build_full_name_stream() const {
|
||
void BuildFuncNameStream(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (const auto& f : functions) {
|
||
std::string res = f.f.build_full_name_stream();
|
||
benchmark::DoNotOptimize(res);
|
||
#ifdef CHECK_RESULT
|
||
if (res != f.check) {
|
||
std::cout << res << "\n";
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
BENCHMARK(__)->Name("----- Build Full Func Name ---------")->Repetitions(1);
|
||
BENCHMARK(BuildFuncNameStdStr) ->Name("Build func full name std::string;");
|
||
BENCHMARK(BuildFuncNameStdStr1) ->Name("Build func full name std::string 1;");
|
||
BENCHMARK(BuildFuncNameStream) ->Name("Build func full name std::stream;");
|
||
BENCHMARK(BuildFuncNameSimStr) ->Name("Build func full name stringa;");
|
||
BENCHMARK(BuildFuncNameSimStr1) ->Name("Build func full name stringa 1;");
|
||
|
||
int main(int argc, char** argv) {
|
||
char arg1[] = "--benchmark_repetitions=10", arg2[] = "--benchmark_report_aggregates_only=true";
|
||
char* my_params[] = {argv[0], arg1, arg2};
|
||
if (argc < 2) {
|
||
argc = 3;
|
||
argv = my_params;
|
||
}
|
||
::benchmark::Initialize(&argc, argv);
|
||
if (::benchmark::ReportUnrecognizedArguments(argc, argv))
|
||
return 1;
|
||
::benchmark::RunSpecifiedBenchmarks();
|
||
::benchmark::Shutdown();
|
||
return 0;
|
||
}
|