Skip to content

Commit

Permalink
stdlib/timer: better resolution control
Browse files Browse the repository at this point in the history
- added a final `erlang:time_unit()` argument to `tc/[1,2,3]`

Tackles erlang#3264. Primarily for systems with worse resolution than a microsecond.
  • Loading branch information
jdamanalo committed Nov 24, 2022
1 parent d713e27 commit 2206cce
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 19 deletions.
41 changes: 32 additions & 9 deletions lib/stdlib/doc/src/timer.xml
Expand Up @@ -319,33 +319,56 @@

<func>
<name name="tc" arity="1" since="OTP R14B03"/>
<name name="tc" arity="2" since="OTP R14B"/>
<name name="tc" arity="3" since=""/>
<name name="tc" arity="2" clause_i="1" since="OTP R14B"/>
<name name="tc" arity="3" clause_i="1" since=""/>
<fsummary>Measure the real time it takes to evaluate <c>Fun</c>.</fsummary>
<desc>
<taglist>
<tag><c>tc/3</c></tag>
<item>
<p>Calls function <c>timer:tc(Module, Function, Arguments, microsecond)</c>.</p>
</item>
<tag><c>tc/2</c></tag>
<item>
<p>Calls function <c>timer:tc(Fun, Arguments, microsecond)</c>.</p>
</item>
<tag><c>tc/1</c></tag>
<item>
<p>Calls function <c>timer:tc(Fun, microsecond)</c>.</p>
</item>
</taglist>
</desc>
</func>

<func>
<name name="tc" arity="2" clause_i="2" since=""/>
<name name="tc" arity="3" clause_i="2" since=""/>
<name name="tc" arity="4" since=""/>
<fsummary>Measure the real time it takes to evaluate <c>apply(Module,
Function, Arguments)</c> or <c>apply(Fun, Arguments)</c>.</fsummary>
<type_desc variable="Time">In microseconds</type_desc>
<type_desc variable="Time">In the specified <c>TimeUnit</c></type_desc>
<desc>
<taglist>
<tag><c>tc/3</c></tag>
<tag><c>tc/4</c></tag>
<item>
<p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>,
<anno>Arguments</anno>)</c> and measures the elapsed real time as
reported by <seemfa marker="erts:erlang#monotonic_time/0">
<c>erlang:monotonic_time/0</c></seemfa>.</p>
<p>Returns <c>{<anno>Time</anno>, <anno>Value</anno>}</c>, where
<c><anno>Time</anno></c> is the elapsed real time in
<em>microseconds</em>, and <c><anno>Value</anno></c> is what is
the specified <c>TimeUnit</c>, and <c><anno>Value</anno></c> is what is
returned from the apply.</p>
</item>
<tag><c>tc/2</c></tag>
<tag><c>tc/3</c></tag>
<item>
<p>Evaluates <c>apply(<anno>Fun</anno>, <anno>Arguments</anno>)</c>.
Otherwise the same as <c>tc/3</c>.</p>
Otherwise the same as <c>tc/4</c>.</p>
</item>
<tag><c>tc/1</c></tag>
<tag><c>tc/2</c></tag>
<item>
<p>Evaluates <c><anno>Fun</anno>()</c>. Otherwise the same as
<c>tc/2</c>.</p>
<c>tc/3</c>.</p>
</item>
</taglist>
</desc>
Expand Down
50 changes: 40 additions & 10 deletions lib/stdlib/src/timer.erl
Expand Up @@ -24,7 +24,7 @@
exit_after/3, exit_after/2, kill_after/2, kill_after/1,
apply_interval/4, apply_repeatedly/4,
send_interval/3, send_interval/2,
cancel/1, sleep/1, tc/1, tc/2, tc/3, now_diff/2,
cancel/1, sleep/1, tc/1, tc/2, tc/3, tc/4, now_diff/2,
seconds/1, minutes/1, hours/1, hms/3]).

-export([start_link/0, start/0,
Expand Down Expand Up @@ -247,41 +247,71 @@ sleep(T) ->
Time :: integer(),
Value :: term().
tc(F) ->
tc(F, microsecond).

%%
%% Measure the execution time (in microseconds) for Fun(Args)
%% or the exeuction time (in TimeUnit) for Fun().
%%
-spec tc(Fun, Arguments) -> {Time, Value}
when Fun :: function(),
Arguments :: [term()],
Time :: integer(),
Value :: term();
(Fun, TimeUnit) -> {Time, Value}
when Fun :: function(),
TimeUnit :: erlang:time_unit(),
Time :: integer(),
Value :: term().
tc(F, A) when is_list(A) ->
tc(F, A, microsecond);
tc(F, TimeUnit) ->
T1 = erlang:monotonic_time(),
Val = F(),
T2 = erlang:monotonic_time(),
Time = erlang:convert_time_unit(T2 - T1, native, microsecond),
Time = erlang:convert_time_unit(T2 - T1, native, TimeUnit),
{Time, Val}.

%%
%% Measure the execution time (in microseconds) for Fun(Args).
%% Measure the execution time (in microseconds) for an MFA
%% or the execution time (in TimeUnit) for Fun(Args).
%%
-spec tc(Fun, Arguments) -> {Time, Value}
-spec tc(Module, Function, Arguments) -> {Time, Value}
when Module :: module(),
Function :: atom(),
Arguments :: [term()],
Time :: integer(),
Value :: term();
(Fun, Arguments, TimeUnit) -> {Time, Value}
when Fun :: function(),
Arguments :: [term()],
TimeUnit :: erlang:time_unit(),
Time :: integer(),
Value :: term().
tc(F, A) ->
tc(M, F, A) when is_list(A) ->
tc(M, F, A, microsecond);
tc(F, A, TimeUnit) ->
T1 = erlang:monotonic_time(),
Val = apply(F, A),
T2 = erlang:monotonic_time(),
Time = erlang:convert_time_unit(T2 - T1, native, microsecond),
Time = erlang:convert_time_unit(T2 - T1, native, TimeUnit),
{Time, Val}.

%%
%% Measure the execution time (in microseconds) for an MFA.
%% Measure the exeuction time (in TimeUnit) for an MFA.
%%
-spec tc(Module, Function, Arguments) -> {Time, Value}
-spec tc(Module, Function, Arguments, TimeUnit) -> {Time, Value}
when Module :: module(),
Function :: atom(),
Arguments :: [term()],
TimeUnit :: erlang:time_unit(),
Time :: integer(),
Value :: term().
tc(M, F, A) ->
tc(M, F, A, TimeUnit) ->
T1 = erlang:monotonic_time(),
Val = apply(M, F, A),
T2 = erlang:monotonic_time(),
Time = erlang:convert_time_unit(T2 - T1, native, microsecond),
Time = erlang:convert_time_unit(T2 - T1, native, TimeUnit),
{Time, Val}.

%%
Expand Down
13 changes: 13 additions & 0 deletions lib/stdlib/test/timer_simple_SUITE.erl
Expand Up @@ -731,7 +731,19 @@ tc(Config) when is_list(Config) ->
true -> ok
end,

%% tc/4
{Res4, ok} = timer:tc(timer, sleep, [500], millisecond),
ok = if
Res4 < 500 -> {too_early, Res4};
Res4 > 800 -> {too_late, Res4};
true -> ok
end,

%% Check that timer:tc don't catch errors
ok = try timer:tc(erlang, exit, [foo], second)
catch exit:foo -> ok
end,

ok = try timer:tc(erlang, exit, [foo])
catch exit:foo -> ok
end,
Expand All @@ -746,6 +758,7 @@ tc(Config) when is_list(Config) ->

%% Check that return values are propageted
Self = self(),
{_, Self} = timer:tc(erlang, self, [], second),
{_, Self} = timer:tc(erlang, self, []),
{_, Self} = timer:tc(fun(P) -> P end, [self()]),
{_, Self} = timer:tc(fun() -> self() end),
Expand Down

0 comments on commit 2206cce

Please sign in to comment.