elispコードのパフォーマンスを測定するにはどうすればよいですか?


26

elispコードのパフォーマンスを測定するにはどうすればよいですか?所要時間を測定するために使用できるツール/外部パッケージは何ですか?

合計時間に加えて、機能ごとにかかった時間を示すプロファイルを表示できますか?メモリ使用量もプロファイルできますか?


1
質問は広すぎます。どんなパフォーマンスですか?どこ?いつ?「Emacsのパフォーマンス」は、あらゆるものを意味します。
ドリュー

@Drew他の多くのプログラミング言語には、一連のベンチマーク(Python:speed.pypy.org、JS:Sunspiderなど)があり、elispインタープリターに同等のものがあることを望んでいました。
ウィルフレッドヒューズ14年

関数benchmarkやプロファイラーによって提供されるようなベンチマークは、Emacsのパフォーマンスを測定しません。特定の式を評価するパフォーマンスを測定します。Emacs 内のパフォーマンスを比較するのに役立ちます。Emacs自体のパフォーマンスを測定するには、Emacs以外のパフォーマンスと比較する必要があります。そして、それがEmacsの幅広さの出番です。これまたはそれについてはEmacs対XYZを測定できますが、Emacsのパフォーマンスを全体として測定するには、このような比較を何度も行う必要があります。
ドリュー

Emacsでパフォーマンスを測定するにはどうすればいいですか?」
ドリュー

2
わかりました、私はemacs.stackexchange.com/q/655/304を開いてEmacsのベンチマークを行い、この質問をelispプログラムのベンチマーク/プロファイリングに関するものと言い換えました。
ウィルフレッドヒューズ14年

回答:


31

基準

最も簡単なオプションは組み込みbenchmarkパッケージです。その使い方は非常に簡単です:

(benchmark 100 (form (to be evaluated)))

自動ロードされるので、それを要求する必要さえありません。

プロファイリング

ベンチマークは全体的なテストには適していますが、パフォーマンスの問題がある場合、どの関数が問題を引き起こしているかはわかりません。そのために、(組み込みの)プロファイラーがあります。

  1. で開始しM-x profiler-startます。
  2. 時間のかかる操作を実行します。
  3. でレポートを取得しM-x profiler-reportます。

関数呼び出しのナビゲーション可能なツリーを備えたバッファに移動する必要があります。
プロファイラーのスクリーンショット


benchmark関数が機能していないようです:開いた.cファイル内で行う(benchmark 100 (c-font-lock-fontify-region 0 17355))と、取得し続けますvoid-function jit-lock-bounds
ハイエンジェル

1
FTR:の代替としてbenchmark機能benchmark-runとがありbenchmark-run-compiledます。私にとっての主な違いは、両方の機能が実際に作品ということでした(。前のページを参照のコメント) Ь:
ハイエンジェル

14

@Malabaraの答えに加えて、カスタムメイドのwith-timerマクロを使用して、コードのさまざまな部分(init.elファイルなど)を永続的に計測する傾向があります。

違いは、benchmarkインストルメントする特定のビットのコードのパフォーマンスを調査できる一方with-timerで、コードのインストルメント化された各部分に費やされる時間を(十分に大きい部分のオーバーヘッドなしで)常に提供することです。どの部分をさらに調査する必要があります。

(defmacro with-timer (title &rest forms)
  "Run the given FORMS, counting the elapsed time.
A message including the given TITLE and the corresponding elapsed
time is displayed."
  (declare (indent 1))
  (let ((nowvar (make-symbol "now"))
        (body   `(progn ,@forms)))
    `(let ((,nowvar (current-time)))
       (message "%s..." ,title)
       (prog1 ,body
         (let ((elapsed
                (float-time (time-subtract (current-time) ,nowvar))))
           (message "%s... done (%.3fs)" ,title elapsed))))))

使用例:

(with-timer "Doing things"
  (form (to (be evaluated))))

*Messages*バッファに次の出力を生成します。

Doing things... done (0.047s)

これは、Jon Wiegleyのuse-package-with-elapsed-timer優れたuse-package拡張機能のマクロに大きな影響を受けていることを言及する必要があります。


init.elを測定している場合は、おそらくemacsスタートアッププロファイラーに興味があるでしょう。
ウィルフレッドヒューズ14年

マクロは素晴らしいです。これはより多くの票に値する。
マラバルバ14年

2
Emacsは合計初期化時間を記録します。コマンドで表示できemacs-init-timeます。
ジョー14年

1
@WilfredHughesはい、私は使用esupしていますし、気に入っています。しかし、繰り返しますが、そのようなものの興味は、with-timer何かを大雑把にプロファイルすることではありません。本当の関心は、あなたが常にプロファイリング情報を持っていることです。emacsを開始するたびに、*Messages*バッファに多くの行があり、どの部分がどれくらい時間がかかったかを教えてくれます。異常を検出した場合、適切なツールを使用して、物事のプロファイルと最適化を行うことができます。
ffevotte

@JoeSはい、emacs-init-time興味深い情報を生成します。ただし、初期化の個々の部分を分解する可能性はなく、包括的経過時間のみを提供します。
ffevotte

3

@Malabarbaの答えに加えて、を使用してコードのコンパイル済み実行時間を測定できることに注意してくださいbenchmark-run-compiled。そのメトリックは、多くの場合、解釈された実行時間よりもはるかに関連性が高くなりM-x benchmarkます。

ELISP> (benchmark-run (cl-loop for i below (* 1000 1000) sum i))
(0.79330082 6 0.2081620540000002)

ELISP> (benchmark-run-compiled (cl-loop for i below (* 1000 1000) sum i))
(0.047896284 0 0.0)

3つの数値は、合計経過時間、GC実行の数、およびGCで費やされた時間です。


1

ベンチマークとは、数値を取得することだけでなく、結果分析に基づいて意思決定を行うことでもあります。

ありbenchstat.elあなたがその機能を取得するために使用することができますMELPAのパッケージbenchstatプログラムを提供しては。

Xパフォーマンスプロパティをに対して検証する比較ベースのベンチマークを実装しYます。

Benchstat関数benchmark-run-compiledは、情報を収集するだけでなく、解釈形式を読みやすくするためのラッパーとして見ることができます。以下が含まれます。

  • Xとの間の経過時間の差分Y
  • 平均時間
  • 配分額

非常に簡単な使用例:

(require 'benchstat)

;; Decide how much repetitions is needed.
;; This is the same as `benchmark-run-compiled` REPETITIONS argument.
(defconst repetitions 1000000)

;; Collect old code profile.
(benchstat-run :old repetitions (list 1 2))
;; Collect new code profile.
(benchstat-run :new repetitions (cons 1 2))

;; Display the results.
;; Can be run interactively by `M-x benchstat-compare'.
(benchstat-compare)

benchstat-compare一時バッファで結果をレンダリングされます:

name   old time/op    new time/op    delta
Emacs    44.2ms ± 6%    25.0ms ±15%  -43.38%  (p=0.000 n=10+10)

name   old allocs/op  new allocs/op  delta
Emacs      23.0 ± 0%      11.4 ± 5%  -50.43%  (p=0.000 n=10+10)

benchstatただし、プログラムバイナリが必要になります。Goプログラミング言語を使用している場合は、おそらくシステムに既に1つあります。それ以外の場合は、ソースからコンパイルするオプションがあります。

linux / amd64用のプリコンパイル済みバイナリは、githubリリースページにあります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.