aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/doc/src/filelib.xml4
-rw-r--r--lib/stdlib/doc/src/filename.xml19
-rw-r--r--lib/stdlib/src/filelib.erl21
-rw-r--r--lib/stdlib/src/lib.erl6
-rw-r--r--lib/stdlib/test/filelib_SUITE.erl35
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE.erl106
6 files changed, 121 insertions, 70 deletions
diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml
index 5e631aac21..3b5be75bc0 100644
--- a/lib/stdlib/doc/src/filelib.xml
+++ b/lib/stdlib/doc/src/filelib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -296,7 +296,7 @@ filelib:wildcard("lib/**/*.{erl,hrl}")</code>
for a file with the extension <c>.beam</c>, the default rule is to
look for a file with a corresponding extension <c>.erl</c> by
replacing the suffix <c>"ebin"</c> of the object directory path with
- <c>"src"</c>.
+ <c>"src"</c> or <c>"src/*"</c>.
The file search is done through <seealso
marker="#find_file/3"><c>find_file/3</c></seealso>. The directory of
the object file is always tried before any other directory specified
diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml
index d2608ad542..ce19f70df0 100644
--- a/lib/stdlib/doc/src/filename.xml
+++ b/lib/stdlib/doc/src/filename.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -399,15 +399,18 @@ true
tuples <c>{<anno>BinSuffix</anno>, <anno>SourceSuffix</anno>}</c> and
is interpreted as follows: if the end of the directory name where the
object is located matches <c><anno>BinSuffix</anno></c>, then the
- source code directory has the same name, but with
- <c><anno>BinSuffix</anno></c> replaced by
- <c><anno>SourceSuffix</anno></c>. <c><anno>Rules</anno></c> defaults
+ name created by replacing <c><anno>BinSuffix</anno></c> with
+ <c><anno>SourceSuffix</anno></c> is expanded by calling
+ <seealso marker="filelib#wildcard/1">
+ <c>filelib:wildcard/1</c></seealso>.
+ If a regular file is found among the matches, the function
+ returns that location together with <c><anno>Options</anno></c>.
+ Otherwise the next rule is tried, and so on.</p>
+ <p><c><anno>Rules</anno></c> defaults
to:</p>
<code type="none">
-[{"", ""}, {"ebin", "src"}, {"ebin", "esrc"}]</code>
- <p>If the source file is found in the resulting directory, the function
- returns that location together with <c><anno>Options</anno></c>.
- Otherwise the next rule is tried, and so on.</p>
+[{"", ""}, {"ebin", "src"}, {"ebin", "esrc"},
+ {"ebin", "src/*"}, {"ebin", "esrc/*"}]</code>
<p>The function returns <c>{<anno>SourceFile</anno>,
<anno>Options</anno>}</c> if it succeeds.
<c><anno>SourceFile</anno></c> is the absolute path to the source
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index 0f90b3fc33..de839be5cf 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -582,17 +582,16 @@ default_search_rules() ->
{"", ".c", c_source_search_rules()},
{"", ".in", basic_source_search_rules()},
%% plain old directory rules, backwards compatible
- {"", ""},
- {"ebin","src"},
- {"ebin","esrc"}
- ].
+ {"", ""}] ++ erl_source_search_rules().
basic_source_search_rules() ->
(erl_source_search_rules()
++ c_source_search_rules()).
erl_source_search_rules() ->
- [{"ebin","src"}, {"ebin","esrc"}].
+ [{"ebin","src"}, {"ebin","esrc"},
+ {"ebin",filename:join("src", "*")},
+ {"ebin",filename:join("esrc", "*")}].
c_source_search_rules() ->
[{"priv","c_src"}, {"priv","src"}, {"bin","c_src"}, {"bin","src"}, {"", "src"}].
@@ -672,8 +671,16 @@ try_dir_rule(Dir, Filename, From, To) ->
Src = filename:join(NewDir, Filename),
case is_regular(Src) of
true -> {ok, Src};
- false -> error
+ false -> find_regular_file(wildcard(Src))
end;
false ->
error
end.
+
+find_regular_file([]) ->
+ error;
+find_regular_file([File|Files]) ->
+ case is_regular(File) of
+ true -> {ok, File};
+ false -> find_regular_file(Files)
+ end.
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
index a7980cc294..51e0c3f77e 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -551,7 +551,7 @@ format_stacktrace1(S0, Stack0, PF, SF, Enc) ->
format_stacktrace2(S, Stack, 1, PF, Enc).
format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF, Enc) when is_integer(A) ->
- [io_lib:fwrite(<<"~s~s ~ts ~s">>,
+ [io_lib:fwrite(<<"~s~s ~ts ~ts">>,
[sep(N, S), origin(N, M, F, A),
mfa_to_string(M, F, A, Enc),
location(L)])
@@ -573,7 +573,7 @@ location(L) ->
Line = proplists:get_value(line, L),
if
File =/= undefined, Line =/= undefined ->
- io_lib:format("(~s, line ~w)", [File, Line]);
+ io_lib:format("(~ts, line ~w)", [File, Line]);
true ->
""
end.
diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl
index 930cea347f..7403d52881 100644
--- a/lib/stdlib/test/filelib_SUITE.erl
+++ b/lib/stdlib/test/filelib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
wildcard_one/1,wildcard_two/1,wildcard_errors/1,
fold_files/1,otp_5960/1,ensure_dir_eexist/1,ensure_dir_symlink/1,
wildcard_symlink/1, is_file_symlink/1, file_props_symlink/1,
- find_source/1]).
+ find_source/1, find_source_subdir/1]).
-import(lists, [foreach/2]).
@@ -49,7 +49,7 @@ all() ->
[wildcard_one, wildcard_two, wildcard_errors,
fold_files, otp_5960, ensure_dir_eexist, ensure_dir_symlink,
wildcard_symlink, is_file_symlink, file_props_symlink,
- find_source].
+ find_source, find_source_subdir].
groups() ->
[].
@@ -567,16 +567,18 @@ find_source(Config) when is_list(Config) ->
[{".erl",".yrl",[{"",""}]}]),
{ok, ParserErl} = filelib:find_source(code:which(core_parse)),
+ ParserErlName = filename:basename(ParserErl),
+ ParserErlDir = filename:dirname(ParserErl),
{ok, ParserYrl} = filelib:find_source(ParserErl),
"lry." ++ _ = lists:reverse(ParserYrl),
- {ok, ParserYrl} = filelib:find_source(ParserErl,
+ {ok, ParserYrl} = filelib:find_source(ParserErlName, ParserErlDir,
[{".beam",".erl",[{"ebin","src"}]},
{".erl",".yrl",[{"",""}]}]),
%% find_source automatically checks the local directory regardless of rules
{ok, ParserYrl} = filelib:find_source(ParserErl),
- {ok, ParserYrl} = filelib:find_source(ParserErl,
- [{".beam",".erl",[{"ebin","src"}]}]),
+ {ok, ParserYrl} = filelib:find_source(ParserErlName, ParserErlDir,
+ [{".erl",".yrl",[{"ebin","src"}]}]),
%% find_file does not check the local directory unless in the rules
ParserYrlName = filename:basename(ParserYrl),
@@ -590,3 +592,24 @@ find_source(Config) when is_list(Config) ->
{ok, ParserYrl} = filelib:find_file(ParserYrlName, ParserYrlDir),
{ok, ParserYrl} = filelib:find_file(ParserYrlName, ParserYrlDir, []),
ok.
+
+find_source_subdir(Config) when is_list(Config) ->
+ BeamFile = code:which(inets), % Located in lib/inets/src/inets_app/
+ BeamName = filename:basename(BeamFile),
+ BeamDir = filename:dirname(BeamFile),
+ SrcName = filename:basename(BeamFile, ".beam") ++ ".erl",
+
+ {ok, SrcFile} = filelib:find_source(BeamName, BeamDir),
+ SrcName = filename:basename(SrcFile),
+
+ {error, not_found} =
+ filelib:find_source(BeamName, BeamDir,
+ [{".beam",".erl",[{"ebin","src"}]}]),
+ {ok, SrcFile} =
+ filelib:find_source(BeamName, BeamDir,
+ [{".beam",".erl",
+ [{"ebin",filename:join("src", "*")}]}]),
+
+ {ok, SrcFile} = filelib:find_file(SrcName, BeamDir),
+
+ ok.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE.erl b/lib/stdlib/test/stdlib_bench_SUITE.erl
index cc7e070dbd..9ad4bae2f5 100644
--- a/lib/stdlib/test/stdlib_bench_SUITE.erl
+++ b/lib/stdlib/test/stdlib_bench_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -281,7 +281,7 @@ comparison(Kind) ->
SimpleTimerMon = norm(SimpleTimerMon0, Simple0),
Generic = norm(Generic0, Simple0),
GenericTimer = norm(GenericTimer0, Simple0),
- {Parallelism, _N, Message} = bench_params(Kind),
+ {Parallelism, Message} = bench_params(Kind),
Wordsize = erlang:system_info(wordsize),
MSize = Wordsize * erts_debug:flat_size(Message),
What = io_lib:format("#parallel gen_server instances: ~.4w, "
@@ -296,79 +296,78 @@ comparison(Kind) ->
{comment, C}.
norm(T, Ref) ->
- io_lib:format("~.2f", [T/Ref]).
+ io_lib:format("~.2f", [Ref/T]).
+
+-define(MAX_TIME_SECS, 3). % s
+-define(MAX_TIME, 1000 * ?MAX_TIME_SECS). % ms
+-define(CALLS_PER_LOOP, 5).
do_tests(Test, ParamSet) ->
{Client, ServerMod} = bench(Test),
- {Parallelism, N, Message} = bench_params(ParamSet),
- Fun = create_clients(N, Message, ServerMod, Client, Parallelism),
- Time = run_test(Fun),
- TimesPerTest = 5,
- PerSecond = Parallelism * TimesPerTest * round((1000 * N) / Time),
+ {Parallelism, Message} = bench_params(ParamSet),
+ Fun = create_clients(Message, ServerMod, Client, Parallelism),
+ {TotalLoops, AllPidTime} = run_test(Fun),
+ PerSecond = ?CALLS_PER_LOOP * round((1000 * TotalLoops) / AllPidTime),
ct_event:notify(#event{name = benchmark_data,
data = [{suite,"stdlib_gen_server"},
{value,PerSecond}]}),
- Time.
+ PerSecond.
+
+-define(COUNTER, n).
-simple_client(0, _, _P) ->
- ok;
simple_client(N, M, P) ->
+ put(?COUNTER, N),
_ = simple_server:reply(P, M),
_ = simple_server:reply(P, M),
_ = simple_server:reply(P, M),
_ = simple_server:reply(P, M),
_ = simple_server:reply(P, M),
- simple_client(N-1, M, P).
+ simple_client(N+1, M, P).
-simple_client_timer(0, _, _P) ->
- ok;
simple_client_timer(N, M, P) ->
+ put(?COUNTER, N),
_ = simple_server_timer:reply(P, M),
_ = simple_server_timer:reply(P, M),
_ = simple_server_timer:reply(P, M),
_ = simple_server_timer:reply(P, M),
_ = simple_server_timer:reply(P, M),
- simple_client_timer(N-1, M, P).
+ simple_client_timer(N+1, M, P).
-simple_client_mon(0, _, _P) ->
- ok;
simple_client_mon(N, M, P) ->
+ put(?COUNTER, N),
_ = simple_server_mon:reply(P, M),
_ = simple_server_mon:reply(P, M),
_ = simple_server_mon:reply(P, M),
_ = simple_server_mon:reply(P, M),
_ = simple_server_mon:reply(P, M),
- simple_client_mon(N-1, M, P).
+ simple_client_mon(N+1, M, P).
-simple_client_timer_mon(0, _, _P) ->
- ok;
simple_client_timer_mon(N, M, P) ->
+ put(?COUNTER, N),
_ = simple_server_timer_mon:reply(P, M),
_ = simple_server_timer_mon:reply(P, M),
_ = simple_server_timer_mon:reply(P, M),
_ = simple_server_timer_mon:reply(P, M),
_ = simple_server_timer_mon:reply(P, M),
- simple_client_timer_mon(N-1, M, P).
+ simple_client_timer_mon(N+1, M, P).
-generic_client(0, _, _P) ->
- ok;
generic_client(N, M, P) ->
+ put(?COUNTER, N),
_ = generic_server:reply(P, M),
_ = generic_server:reply(P, M),
_ = generic_server:reply(P, M),
_ = generic_server:reply(P, M),
_ = generic_server:reply(P, M),
- generic_client(N-1, M, P).
+ generic_client(N+1, M, P).
-generic_timer_client(0, _, _P) ->
- ok;
generic_timer_client(N, M, P) ->
+ put(?COUNTER, N),
_ = generic_server_timer:reply(P, M),
_ = generic_server_timer:reply(P, M),
_ = generic_server_timer:reply(P, M),
_ = generic_server_timer:reply(P, M),
_ = generic_server_timer:reply(P, M),
- generic_timer_client(N-1, M, P).
+ generic_timer_client(N+1, M, P).
bench(simple) ->
{fun simple_client/3, simple_server};
@@ -383,16 +382,16 @@ bench(generic) ->
bench(generic_timer) ->
{fun generic_timer_client/3, generic_server_timer}.
-%% -> {Parallelism, NumberOfMessages, MessageTerm}
-bench_params(single_small) -> {1, 700000, small()};
-bench_params(single_medium) -> {1, 350000, medium()};
-bench_params(single_big) -> {1, 70000, big()};
-bench_params(sched_small) -> {parallelism(), 200000, small()};
-bench_params(sched_medium) -> {parallelism(), 100000, medium()};
-bench_params(sched_big) -> {parallelism(), 20000, big()};
-bench_params(multi_small) -> {400, 2000, small()};
-bench_params(multi_medium) -> {400, 1000, medium()};
-bench_params(multi_big) -> {400, 200, big()}.
+%% -> {Parallelism, MessageTerm}
+bench_params(single_small) -> {1, small()};
+bench_params(single_medium) -> {1, medium()};
+bench_params(single_big) -> {1, big()};
+bench_params(sched_small) -> {parallelism(), small()};
+bench_params(sched_medium) -> {parallelism(), medium()};
+bench_params(sched_big) -> {parallelism(), big()};
+bench_params(multi_small) -> {400, small()};
+bench_params(multi_medium) -> {400, medium()};
+bench_params(multi_big) -> {400, big()}.
small() ->
small.
@@ -409,19 +408,38 @@ parallelism() ->
_ -> 1
end.
-create_clients(N, M, ServerMod, Client, Parallel) ->
+create_clients(M, ServerMod, Client, Parallel) ->
fun() ->
State = term,
ServerPid = ServerMod:start(State),
- PidRefs = [spawn_monitor(fun() -> Client(N, M, ServerPid) end) ||
+ PidRefs = [spawn_monitor(fun() -> Client(0, M, ServerPid) end) ||
_ <- lists:seq(1, Parallel)],
- _ = [receive {'DOWN', Ref, _, _, _} -> ok end ||
- {_Pid, Ref} <- PidRefs],
- ok = ServerMod:stop(ServerPid)
+ timer:sleep(?MAX_TIME),
+ try
+ AllPidsN = collect(PidRefs, []),
+ TotalLoops = lists:sum(AllPidsN),
+ TotalLoops
+ after
+ ok = ServerMod:stop(ServerPid)
+ end
end.
+collect([], Result) ->
+ Result;
+collect([{Pid, Ref}|PidRefs], Result) ->
+ N = case erlang:process_info(Pid, dictionary) of
+ {dictionary, Dict} ->
+ {?COUNTER, N0} = lists:keyfind(?COUNTER, 1, Dict),
+ N0;
+ undefined -> % Process did not start in ?MAX_TIME_SECS.
+ 0
+ end,
+ exit(Pid, kill),
+ receive {'DOWN', Ref, _, _, _} -> ok end,
+ collect(PidRefs, [N|Result]).
+
run_test(Test) ->
{T1, _} = statistics(runtime),
- Test(),
+ Result = Test(),
{T2, _} = statistics(runtime),
- T2 - T1.
+ {Result, T2 - T1}.