0Pricing
R Academy · レッスン

microbenchmark でベンチマークを行う

microbenchmark() を使って、複数の実装を統計的に比較します。

「microbenchmark でベンチマークを行う」はCoddyKit上の無料R Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはR Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 R Academyコースには全4レッスンが含まれています。

microbenchmarkを使う理由

system.time()の分解能はミリ秒であり、高速な処理の計測には信頼できません。microbenchmarkパッケージは式を数百回実行し、ウォームアップを処理したうえで、ナノ秒分解能の統計情報を報告します。そのため、似た実装を比較するのに適したツールです。

microbenchmarkの基本的な使い方

名前付きの式をmicrobenchmark()に渡します。各引数名が出力のラベルになります。times引数で、各式を評価する回数を指定します。

# library(microbenchmark)
# x <- 1:10000
#
# microbenchmark(
#   loop = {
#     s <- 0
#     for (v in x) s <- s + v
#   },
#   vectorized = sum(x),
#   times = 200L
# )

times引数の選び方

反復回数を増やすと推定値は安定しますが、時間がかかります。一般的な目安は次のとおりです。

  • 高速な式(マイクロ秒):times = 1000L以上
  • 中程度の式(ミリ秒):times = 100L
  • 低速な式(秒):times = 10L以下

デフォルトはtimes = 100Lで、開始点として適しています。

# library(microbenchmark)
# microbenchmark(
#   fast_op = sqrt(2),
#   times = 10000L   # many reps for a nanosecond-scale operation
# )
# microbenchmark(
#   slow_op = sort(rnorm(1e6)),
#   times = 10L      # fewer reps for second-scale operation
# )

unit引数の指定

結果を読みやすい単位で表示するには、unit引数を使用します。

  • 'ns' — ナノ秒(非常に高速な処理向け)
  • 'us' — マイクロ秒
  • 'ms' — ミリ秒
  • 's' — 秒
  • 'relative' — 最速の式に対する比率
# library(microbenchmark)
# x <- runif(1000)
#
# microbenchmark(
#   sapply_sqrt = sapply(x, sqrt),
#   vectorized  = sqrt(x),
#   times = 500L,
#   unit = 'us'   # display in microseconds
# )

サマリー出力の読み方

microbenchmarkは、次の列を含むサマリーテーブルを出力します。

  • min — 1回の実行における最短時間
  • lq / mean / median / uq — 第1四分位数、平均値、中央値、第3四分位数
  • max — 1回の実行における最長時間
  • neval — 評価回数

比較の主な指標にはmedianを使用してください。たまに発生するGCの停止によってmaxやmeanが大きくなる場合でも、medianはその影響を受けにくいためです。

# Example summary output (unit: microseconds):
#
#         expr    min     lq   mean  median    uq    max neval
#         loop 1203.1 1245.3 1301.7  1262.4 1310.1 2100.8   100
#   vectorized    2.1    2.3    2.9     2.4    2.6   18.3   100
#
# => vectorized is ~525x faster at median
cat('Always compare medians, not means, for microbenchmark results
')

microbenchmarkオブジェクトに対するsummary()

保存したmicrobenchmarkの結果に対してsummary(mb)を呼び出すと、プログラムから調べられるデータフレームが返されます。summaryの呼び出しでunitを変更することもできます。

# library(microbenchmark)
# x <- rnorm(5000)
# mb <- microbenchmark(
#   vapply_abs  = vapply(x, abs, numeric(1)),
#   base_abs    = abs(x),
#   times = 200L
# )
# s <- summary(mb, unit = 'ms')
# print(s[, c('expr', 'min', 'median', 'max')])

視覚的な比較のためのautoplot()

autoplot(mb)はggplot2を使用して、式ごとの計測時間の分布をバイオリンプロットまたは箱ひげ図として描画します。これにより、中央値の差だけでなく、選択肢間のばらつきや重なりも簡単に確認できます。

# library(microbenchmark)
# library(ggplot2)
#
# x <- 1:50000
# mb <- microbenchmark(
#   loop   = { s <- 0; for (v in x) s <- s + v },
#   vapply = vapply(x, identity, numeric(1)),
#   vec    = sum(x),
#   times  = 100L
# )
# autoplot(mb)  # opens ggplot2 violin chart

Loopとvapplyとsapplyの比較

典型的なベンチマークとして、forループ、sapply()、vapply()を使って要素ごとに関数を適用する処理を比較します。vapply()は結果ベクトルを事前に確保するため、sapply()より高速です。ただし、どちらも完全にベクトル化されたコードよりは低速です。

# library(microbenchmark)
# x <- runif(5000, 1, 100)
#
# mb <- microbenchmark(
#   for_loop = {
#     r <- numeric(length(x))
#     for (i in seq_along(x)) r[i] <- log(x[i])
#   },
#   sapply_log  = sapply(x, log),
#   vapply_log  = vapply(x, log, numeric(1)),
#   vec_log     = log(x),
#   times = 200L, unit = 'us'
# )
# print(mb)

まず正しさを確認する

ベンチマークを実行する前に、すべての式が同一の結果を返すことを確認してください。高速でも正しくない実装には意味がありません。出力の比較にはidentical()またはall.equal()を使用します。

# x <- runif(1000)
# r1 <- sapply(x, sqrt)
# r2 <- sqrt(x)
# r3 <- vapply(x, sqrt, numeric(1))
#
# stopifnot(isTRUE(all.equal(r1, r2)))
# stopifnot(isTRUE(all.equal(r1, r3)))
# cat('All three produce identical results -- safe to benchmark
')
cat('Always verify correctness before comparing speed
')

setup引数を使ったベンチマーク

計測対象の式を実行する前にコードを1回実行するには、setup引数を使用します。データの作成時間を計測する目的でない場合に、ベンチマークへデータ作成時間が含まれるのを避けられます。

# library(microbenchmark)
#
# microbenchmark(
#   sort_base  = sort(x),
#   sort_order = x[order(x)],
#   setup = { x <- rnorm(10000) },
#   times = 100L
# )
# Each iteration refreshes x via setup, then times sort_base and sort_order

分析でベンチマーク結果を報告する

ベンチマーク結果を共有するときは、必ず次の情報を報告してください。

  • Rのバージョンとプラットフォーム
  • パッケージのバージョン
  • 使用したtimesの値
  • ベンチマークで使用したデータサイズ

計測時間はマシンによって異なるため、実装を比較する場合は絶対値ではなく比率を報告してください。

cat('R version    :', R.version$version.string, '
')
cat('Platform     :', R.version$platform, '
')
cat('Logical cores:', parallel::detectCores(), '
')

クイックチェック:microbenchmarkの指標

2つの実装を比較するとき、microbenchmarkの出力に含まれるどのサマリー統計量が最も信頼できますか。

microbenchmarkのおさらい

microbenchmarkは、Rで厳密なマイクロベンチマークを行うための標準的なツールです。

  • 名前付きの式を渡し、timesを設定して反復回数を指定します
  • 読みやすい出力にはunit = 'us'または'ms'を使用します
  • 中央値を比較します。GCによる外れ値の影響を受けにくいためです
  • autoplot()を使って計測時間の分布を可視化します
  • ベンチマークの前にall.equal()で正しさを確認します

よくある質問

「microbenchmark でベンチマークを行う」レッスンは無料ですか?

はい。「microbenchmark でベンチマークを行う」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、R Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 R Academyコースには全4レッスンが含まれています。

「microbenchmark でベンチマークを行う」で何を学びますか?

microbenchmark() を使って、複数の実装を統計的に比較します。 ブラウザで直接実行するハンズオンコードでR Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

R Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのR Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「microbenchmark でベンチマークを行う」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このR Academyレッスンでコードを書いて実行できますか?

はい。すべてのR Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. system.time() と proc.time()
  2. Rprof と profvis でコードをプロファイリングする
  3. 高速化のためのベクトル化
  4. microbenchmark でベンチマークを行う
← R Academyに戻る