使用计时器测试Erlang函数性能

6 erlang performance timer

我正在使用以下方法在紧密循环(比如5000次迭代)中测试函数的性能timer:tc/3:

{Duration_us, _Result} = timer:tc(M, F, [A])
Run Code Online (Sandbox Code Playgroud)

这将返回持续时间(以微秒为单位)和函数的结果.为了论证,持续时间是N微秒.

然后,我对迭代结果执行简单的平均计算.

如果我把一个timer:sleep(1)函数调用之前timer:tc/3呼吁,为所有迭代的平均时间总是>没有睡眠的平均数:

timer:sleep(1),
timer:tc(M, F, [A]).
Run Code Online (Sandbox Code Playgroud)

这对我来说没有多大意义,因为timer:tc/3函数应该是原子的,而不关心它之前发生的任何事情.

谁能解释这个奇怪的功能?它是否与调度和减少有关?

Mic*_*ael 1

你的意思是这样的:

4> 富:富(10000)。

在哪里:

-module(foo).
-export([foo/1, baz/1]).

foo(N) -> TL = bar(N), {TL,sum(TL)/N} .

bar(0) -> [];
bar(N) ->
    timer:sleep(1),
    {D,_} = timer:tc(?MODULE, baz, [1000]),
    [D|bar(N-1)]
    .

baz(0) -> ok;
baz(N) -> baz(N-1).

sum([]) -> 0;
sum([H|T]) -> H + sum(T).
Run Code Online (Sandbox Code Playgroud)

我尝试过这个,很有趣。使用 sleep 语句,timer:tc/3 返回的平均时间为 19 到 22 微秒,如果注释掉 sleep,平均值会下降到 4 到 6 微秒。相当戏剧化!

我注意到计时中存在人为因素,因此像这样的事件(这些数字是计时器返回的单个微秒计时:tc/3)并不罕见:

---- snip ----
  5,5,5,6,5,5,5,6,5,5,5,6,5,5,5,5,4,5,5,5,5,5,4,5,5,5,5,6,5,5,
  5,6,5,5,5,5,5,6,5,5,5,5,5,6,5,5,5,6,5,5,5,5,5,5,5,5,5,5,4,5,
  5,5,5,6,5,5,5,6,5,5,7,8,7,8,5,6,5,5,5,6,5,5,5,5,4,5,5,5,5,
  14,4,5,5,4,5,5,4,5,4,5,5,5,4,5,5,4,5,5,4,5,4,5,5,5,4,5,5,4,
  5,5,4,5,4,5,5,4,4,5,5,4,5,5,4,4,4,4,4,5,4,5,5,4,5,5,5,4,5,5,
  4,5,5,4,5,4,5,5,5,4,5,5,4,5,5,4,5,4,5,4,5,4,5,5,4,4,4,4,5,4,
  5,5,54,22,26,21,22,22,24,24,32,31,36,31,33,27,25,21,22,21,
  24,21,22,22,24,21,22,21,24,21,22,22,24,21,22,21,24,21,22,21,
  23,27,22,21,24,21,22,21,24,22,22,21,23,22,22,21,24,22,22,21,
  24,21,22,22,24,22,22,21,24,22,22,22,24,22,22,22,24,22,22,22,
  24,22,22,22,24,22,22,21,24,22,22,21,24,21,22,22,24,22,22,21,
  24,21,23,21,24,22,23,21,24,21,22,22,24,21,22,22,24,21,22,22,
  24,22,23,21,24,21,23,21,23,21,21,21,23,21,25,22,24,21,22,21,
  24,21,22,21,24,22,21,24,22,22,21,24,22,23,21,23,21,22,21,23,
  21,22,21,23,21,23,21,24,22,22,22,24,22,22,41,36,30,33,30,35,
  21,23,21,25,21,23,21,24,22,22,21,23,21,22,21,24,22,22,22,24,
  22,22,21,24,22,22,22,24,22,22,21,24,22,22,21,24,22,22,21,24,
  22,22,21,24,21,22,22,27,22,23,21,23,21,21,21,23,21,21,21,24,
  21,22,21,24,21,22,22,24,22,22,22,24,21,22,22,24,21,22,21,24,
  21,23,21,23,21,22,21,23,21,23,22,24,22,22,21,24,21,22,22,24,
  21,23,21,24,21,22,22,24,21,22,22,24,21,22,21,24,21,22,22,24,
  22,22,22,24,22,22,21,24,22,21,21,24,21,22,22,24,21,22,22,24,
  24,23,21,24,21,22,24,21,22,21,23,21,22,21,24,21,22,21,32,31,
  32,21,25,21,22,22,24,46,5,5,5,5,5,4,5,5,5,5,6,5,5,5,5,5,5,4,
  6,5,5,5,6,5,5,5,5,5,5,5,6,5,5,5,5,4,5,4,5,5,5,5,6,5,5,5,5,5,
  5,5,6,5,5,5,5,5,5,5,6,5,5,5,5,4,6,4,6,5,5,5,5,5,5,4,6,5,5,5,
  5,4,5,5,5,5,5,5,6,5,5,5,5,4,5,5,5,5,5,5,6,5,5,5,5,5,5,5,6,5,
  5,5,5,4,5,5,6,5,5,5,6,5,5,5,5,5,5,5,6,5,5,5,6,5,5,5,5,5,5,5,
  6,5,5,5,5,4,5,4,5,5,5,5,6,5,5,5,5,5,5,4,5,4,5,5,5,5,5,6,5,5,
  5,5,4,5,4,5,5,5,5,6,5,5,5,5,5,5,5,6,5,5,5,5,5,5,5,6,5,5,5,5,
---- snip ----
Run Code Online (Sandbox Code Playgroud)

我认为这就是您所指的效果,尽管当您说“ always > N”时,是“ always ”还是“大部分”?无论如何,并不总是适合我。

上述结果摘录是在没有睡眠的情况下进行的。通常,当使用睡眠计时器时:tc/3 在没有睡眠的情况下,大多数时间会返回 4 或 5 等低时间,但有时会返回 22 等大时间,并且在睡眠到位后,通常会返回 22 等大时间,偶尔会出现一批低时间。

为什么会发生这种情况当然并不明显,因为睡眠实际上只是意味着产出。我想知道这一切是否与CPU缓存有关。毕竟,特别是在一台不忙的机器上,人们可能会期望没有睡眠的情况能够一次性执行大部分代码,而无需将其移动到另一个核心,而不需要对核心做太多其他事情,从而充分利用从缓存中...但是当您睡眠并因此屈服并稍后返回时,缓存命中的机会可能会大大减少。