Finally got around to verifying this once I got a hand on a Mac, I'll add more details from my own computer later but the gist is this:
Problem
In whatever circumstance that I don't understand :erlang.monotonic_time()only answers in microsecond precision while acting like nanosecond. The impact is that we get measurements that aren't precise enough and as a result are reporting weird measurements/medians of 0ns or what not.
Here you can see the monotonic_time()behaviour changing, between answering in thousands (microseconds) and precise (nanoseconds)
iex(20)> :erlang.monotonic_time()
-576460662355025000
iex(21)> :erlang.monotonic_time()
-576460661060082000
iex(22)> :erlang.monotonic_time()
-576460660057118000
iex(23)> :erlang.monotonic_time()
-576460658439012000
iex(24)> :erlang.monotonic_time()
-576460657486274000
iex(25)> :erlang.monotonic_time()
-576460656358455000
iex(26)>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution
^CJalynas-MacBook-Pro-2:strings_bench tobi$ iex
Erlang/OTP 22 [erts-10.5.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :erlang.monotonic_time()
-576460750092774257
iex(2)> :erlang.monotonic_time()
-576460748033749614
iex(3)> :erlang.monotonic_time()
-576460746882032373
iex(4)> :erlang.monotonic_time()
-576460745953850985
iex(5)> :erlang.monotonic_time()
-576460744563625901
iex(6)>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution
^CJalynas-MacBook-Pro-2:strings_bench tobi$ iex -S mix
Erlang/OTP 22 [erts-10.5.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :erlang.monotonic_time()
-576460749655663000
iex(2)> :erlang.monotonic_time()
-576460748341135000
iex(3)> :erlang.monotonic_time()
-576460746837166000
iex(4)>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution
^CJalynas-MacBook-Pro-2:strings_bench tobi$ iex
Erlang/OTP 22 [erts-10.5.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :erlang.monotonic_time()
-576460748654849000
iex(2)> :erlang.monotonic_time()
-576460747093918000
and yes, the native time unit claims to be :nanosecond (no change when converting native to nanosecond):
iex(7)> :erlang.convert_time_unit(1000, :native, :nanosecond)
1000
iex(8)> :erlang.monotonic_time()
-576460691963568000
iex(9)> :erlang.monotonic_time()
-576460691066966000
as a result our measurements can look like this and produce very odd results:
0
2000
1000
0
1000
1000
1000
1000
1000
0
1000
0
0
1000
0
1000
0
1000
1000
1000
0
1000
0
1000
1000
0
1000
1000
Name ips average deviation median 99th %
iodata 1.56 M 642.21 ns ±330.72% 1000 ns 3000 ns
string 1.39 M 720.55 ns ±1535.92% 0 ns 3000 ns
Comparison:
iodata 1.56 M
string 1.39 M - 1.12x slower +78.34 ns
Background
See this twitter thread, basically I noticed odd looking benchmarking results in this blog post (a median of 0ns). The benchmark can be found here
Further Debugging
After looking into the Erlang Time Correction docs I hoped that the os_monotonic information might be different but apart from the bad time values it seems to be the same between Mac and my linux machine:
# example from my Linux system, but apart from the time Mac results look the same
iex(2)> :erlang.system_info(:os_monotonic_time_source)
[
function: :clock_gettime,
clock_id: :CLOCK_MONOTONIC,
resolution: 1000000000,
extended: :no,
parallel: :yes,
time: 5688955479888
]
I also investigated time_warp_mode but results on the mac didn't change.
Opened an issue at Erlang/OTP: https://bugs.erlang.org/browse/ERL-1067
Possible Solutions
- explicitly don't trust macos and treat it as we'd treat microsecond measurements (repetition and all)
- make the repeated measurement code more intelligent and "doubtful" when it returns multiples of a thousand and then rather retry and see if it ends up divisble by a thousand again
- your idea here
Workarounds possible now
- run benchmarks on linux
- manually integrate repetition to go over a threshold of ~10 microseconds
Environment
Values obtained from a MBP from ~2014/2015 running 10.14.2 Mojave on an i5 processor
Is this a benchee bug?
Yes and No. Yes the results reported in the end aren't accurate, however I'd say that this time reporting with another precision than reported is a bug in the BEAM or maybe MacOS or I dunno what.
We still need to fix it/make it better as lots of people out there are doing benchmarks on MacOS.
Can I help?
If you have a mac you can run the benchmark and post your results: https://github.com/oestrich/strings_bench
If you could run an iex shell and run :erlang.monotonic_time() a couple of times, kill the session and run it again seeing if the precision changes as seen above, that'd be nice. I'd like to see if this happens all the time/for everything or just specific configurations.
Finally got around to verifying this once I got a hand on a Mac, I'll add more details from my own computer later but the gist is this:
Problem
In whatever circumstance that I don't understand
:erlang.monotonic_time()only answers in microsecond precision while acting like nanosecond. The impact is that we get measurements that aren't precise enough and as a result are reporting weird measurements/medians of 0ns or what not.Here you can see the
monotonic_time()behaviour changing, between answering in thousands (microseconds) and precise (nanoseconds)and yes, the native time unit claims to be
:nanosecond(no change when converting native to nanosecond):as a result our measurements can look like this and produce very odd results:
Background
See this twitter thread, basically I noticed odd looking benchmarking results in this blog post (a median of 0ns). The benchmark can be found here
Further Debugging
After looking into the Erlang Time Correction docs I hoped that the os_monotonic information might be different but apart from the bad time values it seems to be the same between Mac and my linux machine:
I also investigated time_warp_mode but results on the mac didn't change.
Opened an issue at Erlang/OTP: https://bugs.erlang.org/browse/ERL-1067
Possible Solutions
Workarounds possible now
Environment
Values obtained from a MBP from ~2014/2015 running 10.14.2 Mojave on an i5 processor
Is this a benchee bug?
Yes and No. Yes the results reported in the end aren't accurate, however I'd say that this time reporting with another precision than reported is a bug in the BEAM or maybe MacOS or I dunno what.
We still need to fix it/make it better as lots of people out there are doing benchmarks on MacOS.
Can I help?
If you have a mac you can run the benchmark and post your results: https://github.com/oestrich/strings_bench
If you could run an
iexshell and run:erlang.monotonic_time()a couple of times, kill the session and run it again seeing if the precision changes as seen above, that'd be nice. I'd like to see if this happens all the time/for everything or just specific configurations.