simstr/bench/comments.txt

352 lines
18 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

- std::string e;
Пустые строки, ничего необычного.
- std::string_view e;
- ssa e;
- stringa e;
- lstringa<20> e;
- lstringa<40> e;
- std::string e = "Test text";
Короткий литерал помещается во внутренний буфер std::string,
время тратится только на копирование 10 байтов.
- std::string_view e = "Test text";
И string_view, и ssa - по сути одно и то же:
указатель на текст и его длина.
- ssa e = "Test text";
- stringa e = "Test text";
stringa при инициализации константным литералом так же
сохраняет только указатель на текст и его длину.
- lstringa<20> e = "Test text";
Внутреннего буфера хватает для размещения символов,
время уходит только на копирование байтов.
- lstringa<40> e = "Test text";
- std::string e = "123456789012345678901234567890";
Вот тут уже литерал не помещается во внутренний буфер,
возникает аллокация и копирование 30-и байтов.
Но как же отстает аллокация под Windows от Linux'а, 20 vs 70 ns...
- std::string_view e = "123456789012345678901234567890";
string_view и ssa по прежнему ничего не делают, кроме
запоминания указателя на текст и его размера.
- ssa e = "123456789012345678901234567890";
- stringa e = "123456789012345678901234567890";
stringa на константных литералах не отстает!
- lstringa<20> e = "123456789012345678901234567890";
lstringa<20> может вместить в себя до 23 символов,
Очевидно, что для 30-и символов уже нужна аллокация.
- lstringa<40> e = "123456789012345678901234567890";
А в lstringa<40> влезает до 47 символов, так что просто
копируется 30 байтов.
- std::string e = "Test text"; auto c{e};
Строка в пределах SSO, так что просто копирует байты.
- std::string_view e = "Test text"; auto c{e};
- ssa e = "Test text"; auto c{e};
ssa и string_view не владеют строкой, копируется
только информация о строке.
- stringa e = "Test text"; auto c{e};
Копирование stringa происходит быстро,
особенно если она инициализирована литералом.
- lstringa<20> e = "Test text"; auto c{e};
В обоих случаях хватает внутреннего буфера.
- lstringa<40> e = "Test text"; auto c{e};
Только копируются байты.
- std::string e = "123456789012345678901234567890"; auto c{e};
Копирования длинной строки вызывает аллокацию,
SSO уже не хватает. И снова как же отстаёт аллокация под Windows...
- std::string_view e = "123456789012345678901234567890"; auto c{e};
- ssa e = "123456789012345678901234567890"; auto c{e};
- stringa e = "123456789012345678901234567890"; auto c{e};
А вот у stringa копирование литерала не зависит от его длины,
сравни с предыдущим бенчмарком.
- lstringa<20> e = "123456789012345678901234567890"; auto c{e};
Не влезает, аллокация.
- lstringa<40> e = "123456789012345678901234567890"; auto c{e};
Уложили во внутренний буфер.
- std::string::find;
Здесь "победила дружба", у всех типов по колонке примерно одинаково.
Однако, Windows и Linux явно в разных весовых категориях.
- std::string_view::find;
- ssa::find;
- stringa::find;
- lstringa<20>::find;
- lstringa<40>::find;
- std::string copy{str_with_len_N};/15
- std::string copy{str_with_len_N};/16
Явно виден скачок, где заканчивается SSO и начинается аллокация.
Обратите внимание, что WASM - 32-битный, и там размер
SSO у std::string меньше, насколько я помню, 11 символов + 0.
- std::string copy{str_with_len_N};/23
Дальше просто добавляется время на копирование байтов.
- std::string copy{str_with_len_N};/24
- std::string copy{str_with_len_N};/32
- std::string copy{str_with_len_N};/64
- std::string copy{str_with_len_N};/128
- std::string copy{str_with_len_N};/256
- std::string copy{str_with_len_N};/512
- std::string copy{str_with_len_N};/1024
- std::string copy{str_with_len_N};/2048
- std::string copy{str_with_len_N};/4096
Чем длиннее строка, тем дольше создаётся копия.
- stringa copy{str_with_len_N};/15
Здесь stringa инициализируется не литералом,
а значит, должна сама хранить символы.
- stringa copy{str_with_len_N};/16
Под WASM SSO у stringa составляет 15 символов. Кроме того,
собиралось без поддержки потоков, поэтому возможно атомарный
инкремент заменён на обычный, судя по времени.
- stringa copy{str_with_len_N};/23
SSO в stringa до 23 символов, и даже 23
копируются быстрее, чем 15 в std::string.
- stringa copy{str_with_len_N};/24
Всё, не влезаем в SSO, а значит, используем shared буфер.
Добавляется время на атомарный инкремент счётчика.
- stringa copy{str_with_len_N};/32
- stringa copy{str_with_len_N};/64
- stringa copy{str_with_len_N};/128
- stringa copy{str_with_len_N};/256
- stringa copy{str_with_len_N};/512
- stringa copy{str_with_len_N};/1024
- stringa copy{str_with_len_N};/2048
- stringa copy{str_with_len_N};/4096
И как видно, кроме инкремента нет накладных расходов,
время копирования не зависит от длины строки.
- lstringa<16> copy{str_with_len_N};/15
lstringa<16> использует SSO до 23 символов.
А в WASM 32-битная архитектура, SSO до 19 символов.
- lstringa<16> copy{str_with_len_N};/16
- lstringa<16> copy{str_with_len_N};/23
- lstringa<16> copy{str_with_len_N};/24
И после начинает вести себя при копировании, как std::string.
- lstringa<16> copy{str_with_len_N};/32
- lstringa<16> copy{str_with_len_N};/64
- lstringa<16> copy{str_with_len_N};/128
- lstringa<16> copy{str_with_len_N};/256
- lstringa<16> copy{str_with_len_N};/512
- lstringa<16> copy{str_with_len_N};/1024
- lstringa<16> copy{str_with_len_N};/2048
- lstringa<16> copy{str_with_len_N};/4096
- lstringa<512> copy{str_with_len_N};/8
А вот lstringa<512> имеет гораздо больший внутренний
буфер и копирует символы без аллокации.
- lstringa<512> copy{str_with_len_N};/16
- lstringa<512> copy{str_with_len_N};/32
- lstringa<512> copy{str_with_len_N};/64
- lstringa<512> copy{str_with_len_N};/128
- lstringa<512> copy{str_with_len_N};/256
- lstringa<512> copy{str_with_len_N};/512
Даже 512 символов копируются быстрее, чем
одна аллокация или атомарный инкремент.
- lstringa<512> copy{str_with_len_N};/1024
А дальше уже как у всех
- lstringa<512> copy{str_with_len_N};/2048
- lstringa<512> copy{str_with_len_N};/4096
- std::string s = "123456789"; int res = std::strtol(s.c_str(), 0, 10);
В simstr для конвертации в число достаточно куска строки,
нет нужды в null терминированности. Ближайший аналог такого
поведения "std::from_chars", но он к сожалению очень ограничен
по возможностям. Здесь я попытался произвести тесты, близкие по
логике к работе std::from_chars
- std::string_view s = "123456789"; std::from_chars(s.data(), s.data() + s.size(), res, 10);
from_chars требует точного указания основания счисления,
не допускает знаков плюс, пробелов, префиксов 0x и т.п.
- stringa s = "123456789"; int res = s.to_int<int, true, 10, false>
Здесь для to_int заданы такие же ограничения - проверять переполнение,
десятичная система, без лидирующих пробелов и знака плюс
- ssa s = "123456789"; int res = s.to_int<int, true, 10, false>
- lstringa<20> s = "123456789"; int res = s.to_int<int, true, 10, false>
- std::string s = "abcDef"; int res = std::strtol(s.c_str(), 0, 16);
Всё то же, только для 16ричной системы
- std::string_view s = "abcDef"; std::from_chars(s.data(), s.data() + s.size(), res, 16);
- stringa s = "abcDef"; int res = s.to_int<int, true, 16, false>
- ssa s = "abcDef"; int res = s.to_int<int, true, 16, false>
- lstringa<20> s = "abcDef"; int res = s.to_int<int, true, 16, false>
- std::string s = " 123456789"; int res = std::strtol(s.c_str(), 0, 0);
А здесь уже парсинг произвольного числа.
- stringa s = " 123456789"; int res = s.to_int<int>; // Check overflow
- ssa s = " 123456789"; int res = s.to_int<int, false>; // No check overflow
- std::stringstream str; ... str << "abbaabbaabbaabba";
- std::string str; ... str += "abbaabbaabbaabba";
- lstringa<8> str; ... str += "abbaabbaabbaabba";
- lstringa<128> str; ... str += "abbaabbaabbaabba";
Чем больше внутренний буфер, тем меньше раз требуется
аллокация, тем быстрее результат.
- lstringa<512> str; ... str += "abbaabbaabbaabba";
- lstringa<1024> str; ... str += "abbaabbaabbaabba";
- std::stringstream str; ... str << str_var << "abbaabbaabbaabba";
- std::string str; ... str += str_var + "abbaabbaabbaabba";
- lstringa<8> str; ... str += str_var + "abbaabbaabbaabba";
- lstringa<128> str; ... str += str_var + "abbaabbaabbaabba";
- lstringa<512> str; ... str += str_var + "abbaabbaabbaabba";
- lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba";
- std::stringstream str; ... str << str_var << "abbaabbaabbaabba";
- std::string str; ... str += str_var + "abbaabbaabbaabba";
- lstringa<8> str; ... str += str_var + "abbaabbaabbaabba";
- lstringa<128> str; ... str += str_var + "abbaabbaabbaabba";
- lstringa<512> str; ... str += str_var + "abbaabbaabbaabba";
- lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba";
- std::stringstream str; ... str << str_var1 << str_var2;
- std::string str; ... str += str_var1 + str_var2;
- lstringa<16> str; ... str += str_var1 + str_var2;
- lstringa<128> str; ... str += str_var1 + str_var2;
- lstringa<512> str; ... str += str_var1 + str_var2;
- lstringa<1024> str; ... str += str_var1 + str_var2;
- std::stringstream str; str << "test = " << k << " times";
- std::string str = "test = " + std::to_string(k) + " times";
- char buf[100]; sprintf(buf, "test = %u times", k); std::string str = buf;
- std::string str = std::format("test = {} times", k);
- lstringa<8> str; str.format("test = {} times", k);
В simstr format с первого раза не помещается в такую строку без аллокации.
- lstringa<32> str; str.format("test = {} times", k);
А в такую помещается. Используйте сразу буфера подходящего размера.
- lstringa<8> str = "test = " + k + " times";
Результат не помещается в SSO, возникает аллокация.
- lstringa<32> str = "test = " + k + " times";
А здесь и ниже - результат укладывается в SSO.
Ещё раз - используйте сразу буфера подходящего размера.
- stringa str = "test = " + k + " times";
Под WASM размер SSO 15 символов, что явно не хватает для размещения
результата, отсюда и такое время.
- std::string::find + substr + std::strtol
- ssa::splitter + ssa::as_int
- Naive (and wrong) replace symbols with std::string find + replace
Это наивная реализация, которая неверно отработает на
таких заменах, как 'a'->'b' и 'b'->'a'. Но если замены не конфликтуют,
то работает быстро.
- replace symbols with std::string find_first_of + replace
Дальше уже правильные реализации, не зависящие от конфликтующих замен.
- replace symbols with std::string_view find_first_of + copy
- replace runtime symbols with string expressions and without remembering all search results
- replace runtime symbols with simstr and memorization of all search results
- replace const symbols with string expressions and without remembering all search results
- replace const symbols with string expressions and memorization of all search results
- Short Naive (and wrong) replace symbols with std::string find + replace
- Short replace symbols with std::string find_first_of + replace
- Short replace symbols with std::string_view find_first_of + copy
- Short replace runtime symbols with string expressions and without remembering all search results
- Short replace runtime symbols with simstr and memorization of all search results
- Short replace const symbols with string expressions and without remembering all search results
- Short replace const symbols with string expressions and memorization of all search results
- replace bb to ---- in 64 std::string
Тут проверяется тяжелый случай - замена подстроки на более
длинную. Обычная реализация несколько раз передвигает хвост.
- replace bb to ---- in 64 lstringa<8>
- replace bb to ---- in 64 str by init stringa
- replace bb to ---- in 256 std::string
- replace bb to ---- in 256 lstringa<8>
- replace bb to ---- in 256 str by init stringa
- replace bb to ---- in 512 std::string
- replace bb to ---- in 512 lstringa<8>
- replace bb to ---- in 512 str by init stringa
- replace bb to ---- in 1024 std::string
- replace bb to ---- in 1024 lstringa<8>
- replace bb to ---- in 1024 str by init stringa
- replace bb to ---- in 2048 std::string
Чем длиннее строка, тем больше замедляется std::string
- replace bb to ---- in 2048 lstringa<8>
- replace bb to ---- in 2048 str by init stringa
- replace bb to -- in 64 std::string
Идеальный случай замены - на подстроку такой же длины
- replace bb to -- in 64 lstringa<8>
- replace bb to -- in 64 by init stringa
- replace bb to -- in 256 std::string
- replace bb to -- in 256 lstringa<8>
- replace bb to -- in 256 by init stringa
- replace bb to -- in 512 std::string
- replace bb to -- in 512 lstringa<8>
- replace bb to -- in 512 by init stringa
- replace bb to -- in 1024 std::string
- replace bb to -- in 1024 lstringa<8>
- replace bb to -- in 1024 by init stringa
- replace bb to -- in 2048 std::string
- replace bb to -- in 2048 lstringa<8>
- replace bb to -- in 2048 by init stringa
- hashStrMapA<size_t> emplace & find stringa;
Вставляем в hashStrMapA 10000 stringa длиной от 30 до 50
символов, а потом ищем их в ней
- std::unordered_map<std::string, size_t> emplace & find std::string;
То же самое c std::string и std::unordered_map
- hashStrMapA<size_t> emplace & find ssa;
Теперь вставляем stringa, а ищем ssa
- std::unordered_map<std::string, size_t> emplace & find std::string_view;
Вставляем std::string, а ищем std::string_view
- Build func full name std::string;
Обыденная задача, подобные часто могут встретится в работе:
По неким данным сгенерировать текст. В этом случае по данным
о неких функциях сформировать их полное имя с типами параметров и
возвращаемого значения. Алгоритм на std::string.
- Build func full name std::string 1;
Почти тот же алгоритм, но несколько последовательных
+= к строке заменены на одно += + + +.
- Build func full name std::stream;
Строим имя функции через std::ostringstream и <<
- Build func full name stringa;
Реализация на simstr строках и строковых выражениях.
Инфа о параметрах добавляется в текущую строку
- Build func full name stringa 1;
Реализация на simstr строках и строковых выражениях.
Инфа о параметрах добавляется во временную строку, а потом
разом добавляется в текущую строку. Позволяет операции в цикле
записать в одну строку, но чуть проигрывает по времени выполнения.
- Пусто