Created
June 13, 2012 15:43
-
-
Save w495/2924882 to your computer and use it in GitHub Desktop.
Тестирование скорости конкатенации
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% | |
%% @file test_concat.erl тестирование скорости конкатенации | |
%% Тестирование проводилось на списках и binary. | |
%% Тестировалось наивная конкатенация через: | |
%% * ++, для списков; | |
%% * <<X/binary,Y/binary>>>, для binary; | |
%% * вложенные списки (правильные и неправильные), cм ниже; | |
%% * конкатенация через lists:append, для списков; | |
%% * конкатенация через string:join, для списков; | |
%% | |
%% Мораль тестирования в том, что, лучше конкатенацию списков | |
%% и binary делать через вложенные списки, | |
%% без дополнительных преобразований. | |
%% Если при этом требуется получить вид результирующей сущности, | |
%% то лучше пользоваться erlang:list_to_binary, а не lists:flatten. | |
%% Если требуется сразу получить результат конкатенации списков, | |
%% то лучше пользоваться наивным ++ или lists:append или string:join, | |
%% в зависимости от нужд. По тестам получилось, что ++ несколько | |
%% быстрее, чем последние два. | |
%% Если требуется сразу получить результат конкатенации binary, | |
%% то лучше пользоваться <<X/binary,Y/binary>>>. | |
%% | |
% ============================================================================ | |
% Erlang R15B (erts-5.9) | |
% [source] | |
% [64-bit] | |
% [smp:2:2] | |
% [async-threads:0] | |
% [hipe] | |
% [kernel-poll:false] | |
% ============================================================================ | |
% | |
% lists | |
% ----------------------------------------------------------------------------------------------------------------- | |
% |time[mks] | memory size in bytes | times | * name | |
% |----------|----------|----------|----------|----------|----------|----------|----------------------------------- | |
% | | total | proc | procu | sys | bin | | | |
% |----------|----------|----------|----------|----------|----------|----------|----------------------------------- | |
% | 3450039 | 10885456 | 1548666 | 1550186 | 9337734 | 667712 | 100000 | * item :: erlang:'++' | |
% | 6823747 | 10892384 | 1548675 | 1550186 | 9343501 | 673272 | 100000 | * item :: ++ erlang:list_to_binary | |
% | 37616 | 10536104 | 1201419 | 1200610 | 9338389 | 668032 | 100000 | * nested list :: [X,Y] | |
% | 36949 | 10536256 | 1201419 | 1200610 | 9338541 | 668184 | 100000 | * deep list :: [X|Y] | |
% | 18128505 | 10880064 | 1541578 | 1541578 | 9338358 | 668336 | 100000 | * nested list :: lists:flatten | |
% | 18011393 | 10880224 | 1541578 | 1541578 | 9338902 | 668496 | 100000 | * deep list :: lists:flatten | |
% | 5035014 | 10469616 | 1123570 | 1122770 | 9339062 | 668656 | 100000 | * nested list :: erlang:list_to_binary | |
% | 5036683 | 10469784 | 1123570 | 1122770 | 9339230 | 668824 | 100000 | * deep list :: erlang:list_to_binary | |
% | 3558985 | 10831464 | 1494642 | 1496162 | 9339142 | 668992 | 100000 | * item :: lists:append | |
% | 3648410 | 10838784 | 1497090 | 1497090 | 9339294 | 669144 | 100000 | * item :: string:join([X ... ], []) | |
% ----------------------------------------------------------------------------------------------------------------- | |
% | |
% binary | |
% ----------------------------------------------------------------------------------------------------------------- | |
% |time[mks] | memory size in bytes | times | * name | |
% |----------|----------|----------|----------|----------|----------|----------|----------------------------------- | |
% | | total | proc | procu | sys | bin | | | |
% |----------|----------|----------|----------|----------|----------|----------|----------------------------------- | |
% | 245128 | 10501824 | 1144267 | 1143458 | 9339853 | 669368 | 100000 | * item :: <<X/binary>> | |
% | 36630 | 10488336 | 1152163 | 1151354 | 9339877 | 669520 | 100000 | * nested list :: [X,Y] | |
% | 36393 | 10488488 | 1152163 | 1151354 | 9340157 | 669672 | 100000 | * deep list :: [X|Y] | |
% | 2397030 | 10571112 | 1234386 | 1234386 | 9340102 | 669824 | 100000 | * nested list :: lists:flatten | |
% | 2421131 | 10571400 | 1234386 | 1234386 | 9340262 | 669984 | 100000 | * deep list :: lists:flatten | |
% | 1220187 | 10508240 | 1157043 | 1156234 | 9337525 | 667168 | 100000 | * nested list :: erlang:list_to_binary | |
% | 1267500 | 10508160 | 1169810 | 1171330 | 9337326 | 667176 | 100000 | * deep list :: erlang:list_to_binary | |
% ----------------------------------------------------------------------------------------------------------------- | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
-module(test_concat). | |
-vsn(2.0). | |
-export([ | |
test/0, | |
test/1 | |
]). | |
-spec test() -> ok. | |
-spec test({ | |
Select ::string(), | |
All ::string(), | |
From ::string(), | |
Btable ::string(), | |
Where ::string(), | |
Id ::string(), | |
Order ::string(), | |
Limit ::string() | |
}) -> ok. | |
test()-> | |
tests:test({ | |
" select ", | |
" * ", | |
" from ", | |
" Btable ", | |
" where ", | |
" id > ? ", | |
" order by id ", | |
" limit 100000 " | |
}), | |
ok. | |
%% | |
%% @spec test_concat({ | |
%% string, string, string, string, string, string, string | |
%% })-> ok. | |
%% | |
test(Params)-> | |
io:format("lists~n"), | |
test_concat(Params, lists), | |
io:format("~nbinary~n"), | |
test_concat( | |
erlang:list_to_tuple([ | |
erlang:list_to_binary(X)||X<-erlang:tuple_to_list(Params) | |
]), | |
binary | |
), | |
io:format("~n"), | |
ok. | |
%% | |
%% @spec test_concat(Params::{ | |
%% string, string, string, string, string, string, string | |
%% }, | |
%% Type::lists | binary | |
%% )-> ok. | |
%% | |
%% @doc Основаня функция тестирования. | |
%% Ключевая особенность --- строки надо передавать как параметры. | |
%% Это нужно для того, чтобы компилятор, не проводил оптимизацию. | |
%% В противном случае тест будет не очень честным. | |
%% В зависимости от параметра Type тестирование проводится для | |
%% списков или binary | |
%% | |
test_concat(Params, Type)-> | |
Times = 100000, | |
%% | |
%% Наивная конкатенация списков и binary | |
%% | |
case Type of | |
lists -> | |
print_speed("item :: erlang:'++' ", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Проверяем скорость формирования списка | |
add_lists({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}) | |
end, Times, Params), | |
print_speed("item :: ++ erlang:list_to_binary ", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Проверяем скорость формирования списка, | |
%% и binary из него | |
List = add_lists({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}), | |
erlang:list_to_binary(List) | |
end, Times, Params); | |
_ -> | |
print_speed("item :: <<X/binary>> ", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Проверяем скорость формирования binary, | |
add_binary({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}) | |
end, Times, Params) | |
end, | |
%% | |
%% Конкатенация на основе вложенных списков | |
%% | |
print_speed("nested list :: [X,Y]", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Правильный список | |
make_nested({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}) | |
end, Times, Params), | |
print_speed("deep list :: [X|Y]", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Неправильный список | |
make_deep({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}) | |
end, Times, Params), | |
%% | |
%% Конкатенация на основе вложенных списков со спрямлением | |
%% через lists:flatten | |
%% | |
print_speed("nested list :: lists:flatten", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Правильный список | |
Nested_list =make_nested({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}), | |
lists:flatten(Nested_list) | |
end, Times, Params), | |
print_speed("deep list :: lists:flatten", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Неправильный список | |
Deep_list = make_deep({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}), | |
lists:flatten(Deep_list) | |
end, Times, Params), | |
%% | |
%% Конкатенация на основе вложенных списков со спрямлением | |
%% через приведение к binary | |
%% | |
print_speed("nested list :: erlang:list_to_binary", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Правильный список | |
Nested_list =make_nested({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}), | |
erlang:list_to_binary(Nested_list) | |
end, Times, Params), | |
print_speed("deep list :: erlang:list_to_binary", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% Неправильный список | |
Deep_list = make_deep({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}), | |
erlang:list_to_binary(Deep_list) | |
end, Times, Params), | |
%% | |
%% Конкатенация на основе сложения списков | |
%% | |
case Type of | |
lists -> | |
print_speed("item :: lists:append ", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% lists:append реадизован через ++ | |
append_lists({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}) | |
end, Times, Params), | |
print_speed(" item :: string:join([X ... ], [])", | |
fun({Select, All, From, Btable, Where, Id, Order, Limit}) -> | |
%% string:join реадизован через ++ | |
join_lists({ | |
Select,All,From,Btable,Where,Id,Order,Limit | |
}) | |
end, Times, Params); | |
_ -> | |
ok | |
end, | |
ok. | |
%% @spec append_lists({ | |
%% string, string, string, string, string, string, string | |
%% })-> string. | |
%% | |
%% @doc Возвращает список полученный путем конкатенации | |
%% списков через lists:append | |
%% | |
append_lists({Select, All, From, Btable, Where, Id, Order, Limit})-> | |
X = lists:append([Select, All, From, Btable, Where, Id, Order, Limit]), | |
Y = lists:append([X,X,X,X]), | |
Z = lists:append([Y,Y,Y,Y]), | |
lists:append([Z,Z,Z,Z,Z]). | |
%% @spec join_lists({ | |
%% string, string, string, string, string, string, string | |
%% })-> string. | |
%% | |
%% @doc Возвращает список полученный путем конкатенации | |
%% списков через string:join | |
%% | |
join_lists({Select, All, From, Btable, Where, Id, Order, Limit})-> | |
X = string:join([Select, All, From, Btable, Where, Id, Order, Limit], []), | |
Y = string:join([X,X,X,X], []), | |
Z = string:join([Y,Y,Y,Y], []), | |
string:join([Z,Z,Z,Z,Z], []). | |
%% @spec add_lists({ | |
%% string, string, string, string, string, string, string | |
%% })-> string. | |
%% | |
%% @doc Возвращает список полученный путем списков через оператор ++ | |
%% | |
add_lists({Select, All, From, Btable, Where, Id, Order, Limit})-> | |
X = Select ++ All ++ From ++ Btable | |
++ Where ++ Id ++ Order ++ Limit, | |
Y = X ++ X ++ X ++ X, | |
Z = Y ++ Y ++ Y ++ Y, | |
Z ++ Z ++ Z ++ Z ++ Z. | |
%% @spec add_binary({ | |
%% binary, binary, binary, binary, binary, binary, binary | |
%% })-> binary. | |
%% | |
%% @doc Возвращает binary полученный путем сложения binary | |
%% | |
add_binary({Select, All, From, Btable, Where, Id, Order, Limit})-> | |
X = <<Select/binary,All/binary,From/binary,Btable/binary, | |
Where/binary, Id/binary, Order/binary, Limit/binary>>, | |
Y = <<X/binary, X/binary,X/binary,X/binary>>, | |
Z = <<Y/binary,Y/binary, Y/binary, Y/binary>>, | |
<<Z/binary, Z/binary,Z/binary,Z/binary,Z/binary>>. | |
%% @spec make_deep({ | |
%% string|binary, | |
%% string|binary, | |
%% string|binary, | |
%% string|binary, | |
%% string|binary, | |
%% string|binary, | |
%% string|binary | |
%% })-> improper_list(string|binary, string|binary) . | |
%% | |
%% @doc Возвращает не правильный вложенный список. | |
%% Каждый новый элемент списка добавляется к хвосту списка, | |
%% а хвост тоже элемент. | |
%% | |
make_deep({Select, All, From, Btable, Where, Id, Order, Limit})-> | |
X = [Select|[All|[From|[Btable|[Where|[Id|[Order|[Limit]]]]]]]], | |
Y = [X|[X|[X|[X]]]], | |
Z = [Y|[Y|[Y|[Y]]]], | |
[Z|[Z|[Z|[Z|[Z]]]]]. | |
%% @spec make_nested({ | |
%% string|binary, | |
%% string|binary, | |
%% string|binary, | |
%% string|binary, | |
%% string|binary, | |
%% string|binary, | |
%% string|binary | |
%% })-> list(string|binary) . | |
%% | |
%% @doc Возвращает правильный вложенный список | |
%% | |
make_nested({Select, All, From, Btable, Where, Id, Order, Limit})-> | |
X = [Select, All, From, Btable, Where, Id, Order, Limit], | |
Y = [X, X, X, X], | |
Z = [Y, Y, Y, Y], | |
[Z, Z, Z, Z, Z]. | |
%% @spec print_speed({ | |
%% string | |
%% (fun(any) -> any), | |
%% integer, | |
%% any, | |
%% })-> ok | |
%% | |
%% @doc Вызывает функцию Fun с параметром Params Times раз. | |
%% Печатает информацию о ее выполнении: | |
%% 1) время выполнения; | |
%% 2) erlang:memory(total), | |
%% 3) erlang:memory('processes'), | |
%% 4) erlang:memory(processes_used), | |
%% 5) erlang:memory(system), | |
%% 6) erlang:memory(binary), | |
%% 7) количество раз (Times) | |
%% 8) имя теста Name | |
%% | |
print_speed(Name, Fun, Times, Params) -> | |
Start = utime(), | |
erlang:garbage_collect(), | |
iter(Times, Fun, Params), | |
Stop = utime(), | |
io:format( | |
%"| TIME | memory | times| name | |
%"| | total | proc | procu | sys | bin | | | |
"| ~8.B | ~8.B | ~8.B | ~8.B | ~8.B | ~8.B | ~8.B | * ~s ~n",[ | |
Stop - Start, | |
erlang:memory(total), | |
erlang:memory('processes'), | |
erlang:memory(processes_used), | |
erlang:memory(system), | |
erlang:memory(binary), | |
Times, Name | |
] | |
). | |
%% @spec iter({ | |
%% integer | |
%% (fun(any) -> any), | |
%% any, | |
%% })-> ok | |
%% @doc Вызывает функцию Fun с параметром Params Times раз. | |
%% | |
iter(0, _, _) -> | |
ok; | |
iter(Times, F, Params) -> | |
erlang:apply(F, [Params]), | |
iter(Times-1, F, Params). | |
%% @spec utime() -> integer | |
%% | |
%% @doc Возвращает текущее количество микросекунд. | |
%% | |
utime() -> | |
{_M,S,Mi} = now(), S*1000000+Mi. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Предыдущая версия передавала строки не через параметры и компилятор оптимизировал конкатенацию. Можно считать результаты предыдущей версии ошибочными.