Scalaでビジーウェイトする関数を作ってみました。
ソースコードと結果は以下になります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 再帰でbusy wait. | |
def busyWait(nanosec: Long): Unit = { | |
@scala.annotation.tailrec | |
def wait(target: Long, now: Long): Unit = { | |
(target < now) match { | |
case true => // 何もしない. | |
case false => wait(target, System.nanoTime) | |
} | |
} | |
val now = System.nanoTime | |
wait(now + nanosec, now) | |
} | |
// ベンチマーク用 | |
// num回 nanosecでbusyWaitを呼び出し、処理に掛かった時間を返す. | |
def run(num: Int, nanosec: Long): Seq[Long] = { | |
def runWait(nanosec: Long): Long = { | |
val start = System.nanoTime | |
busyWait(nanosec) | |
System.nanoTime - start | |
} | |
for(i <- 0 until num) yield {runWait(nanosec)} | |
} | |
// runを実行して平均値を表示. | |
def execBenchmark(num: Int)(nanosec: Long) = { | |
def printMean(list: Seq[Long]) = { | |
println("mean => " + list.sum / list.size) | |
} | |
println("------ " + nanosec + " [ns] ------") | |
printMean(run(num, nanosec)) | |
println | |
} | |
// 繰り返し回数は固定 | |
val exec10000Times = execBenchmark(10000) _ | |
// 適用に実行. | |
List[Long](1000, | |
2000, | |
3000, | |
4000, | |
5000, | |
6000, | |
7000, | |
8000, | |
9000, | |
10000, | |
20000, | |
30000, | |
40000, | |
50000, | |
100000, | |
200000, | |
300000, | |
1000000, | |
2000000, | |
3000000).foreach(exec10000Times) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------ 1000 [ns] ------ | |
mean => 2093 | |
------ 2000 [ns] ------ | |
mean => 3013 | |
------ 3000 [ns] ------ | |
mean => 4025 | |
------ 4000 [ns] ------ | |
mean => 5025 | |
------ 5000 [ns] ------ | |
mean => 6045 | |
------ 6000 [ns] ------ | |
mean => 7027 | |
------ 7000 [ns] ------ | |
mean => 8054 | |
------ 8000 [ns] ------ | |
mean => 9037 | |
------ 9000 [ns] ------ | |
mean => 10089 | |
------ 10000 [ns] ------ | |
mean => 11043 | |
------ 20000 [ns] ------ | |
mean => 21054 | |
------ 30000 [ns] ------ | |
mean => 31049 | |
------ 40000 [ns] ------ | |
mean => 41066 | |
------ 50000 [ns] ------ | |
mean => 51515 | |
------ 100000 [ns] ------ | |
mean => 101324 | |
------ 200000 [ns] ------ | |
mean => 201272 | |
------ 300000 [ns] ------ | |
mean => 301094 | |
------ 1000000 [ns] ------ | |
mean => 1001368 | |
------ 2000000 [ns] ------ | |
mean => 2001425 | |
------ 3000000 [ns] ------ | |
mean => 3001278 | |
何故こんなことをしたのかというと、Sleepよりもう少し精度が欲しかったから。
実行環境にもよりますが、僕のMBAだと100[usec]位の精度でなら使えると思います。
当然ビジーウェイトなので悲しいほどCPUを消費します。
もっとかっこいい実装方法があったら教えて欲しいです。
後で標準偏差とかも取ってみます。
0 件のコメント:
コメントを投稿