If you ask about the testing methodology, I would expect that you also include your code, because there may be a slight error in the reference code, which can ruin the result. So I write one and made a Gist so that we can compare the result using the same code. YMMV, especially because I use Linux and timers, is very OS dependent. There are my results:
$ uname -a Linux hynek-notebook 4.1.0-1-amd64 #1 SMP Debian 4.1.3-1 (2015-08-03) x86_64 GNU/Linux $ grep 'model name' /proc/cpuinfo model name : Intel(R) Core(TM) i5 CPU M 520 @ 2.40GHz model name : Intel(R) Core(TM) i5 CPU M 520 @ 2.40GHz model name : Intel(R) Core(TM) i5 CPU M 520 @ 2.40GHz model name : Intel(R) Core(TM) i5 CPU M 520 @ 2.40GHz $ erl Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] Eshell V7.0 (abort with ^G) 1> c(test). {ok,test} 2> test:bench_all(1). [{unique_monotonic_integer,{38341,39804}}, {update_counter,{158248,159319}}, {monotonic_time,{217531,218272}}, {system_time,{224630,226960}}, {os_system_time,{53489,53691}}, {universal_time,{114125,116324}}] 3> test:bench_all(2). [{unique_monotonic_integer,{40109,40238}}, {update_counter,{307393,338993}}, {monotonic_time,{120024,121612}}, {system_time,{123634,124928}}, {os_system_time,{29606,29992}}, {universal_time,{177544,178820}}] 4> test:bench_all(20). [{unique_monotonic_integer,{23796,26364}}, {update_counter,{514835,527087}}, {monotonic_time,{91916,93662}}, {system_time,{94615,96249}}, {os_system_time,{27194,27598}}, {universal_time,{317353,340187}}] 5>
The first thing I should note is that only erlang:unique_integer/0,1 and ets:update_counter/3,4,5 generates a unique value. Even erlang:monotonic_time/0 can generate two identical timestamps! Therefore, if you need a unique number, you have no choice but to use erlang:unique_integer/0,1 . If you want a unique monotone timestamp, you can use {erlang:monotonic_time(), erlang:unique_integer()} , or if you do not need a time part, you can use erlang:unique_integer([monotonic]) . If you do not need monotonous and unique, you can use other options. Therefore, if you need a unique monotonous number, there is only one good option, and it is erlang:unique_integer([monotonic]) .
The second time, I should note that spawning of two processes is not enough to test scalability. As you can see, when I use os:timestamp/0 with 20 processes, they start to catch up with erlang:unique_integer/0,1 . And there is one more problem. We both use HW with only two processors. Too scalable to check. Imagine how the result will look on an HW with 64 or more cores.
Edit : Using {write_concurrency, true} will improve ets:update_counter , but still far beyond erlang:unique_integer/0,1 .
2> test:bench(test:update_counter(),1). {203830,213657} 3> test:bench(test:update_counter(),2). {129148,140627} 4> test:bench(test:update_counter(),20). {471858,501198}