時間を計る

今,scratch buffer をヴァージョン管理するという誰得な拡張を作っているんですが,その一部に汎用化できそうな部分があったんで,抜き出してご紹介.

stopwatch.el

zip
repository

Features

以下の関数を使って時間を比較できるようになります.扱える時間のフォーマットは (high low microsec),または (high low) です.

stopwatch (time1 &optional time2)

TIME1 と TIME2 の差分を計算します.返り値は high low microsec をつなぎあわせた数字になります.TIME2 を省略した場合は current-time() との比較になります.

stopwatch-by-UNIT (time1 &optional time2 integer)

stopwatch() と同様に差分を計算しますが,返り値は UNIT で表される単位に変換された値(小数)です.INTEGER が non-nil の場合,結果は整数(小数点以下切り捨て)になります.UNIT にはデフォルトで小さい方から ms, sec, min, hour, day が当てはまります.マクロ stopwatch-define-unit-fn() を使って関数を自分で定義することもできます.

また,時間をメッセージで出力するマクロも定義しています.

with-stopwatch (message &rest body)

BODY を囲む形で使います.MESSAGE は文字列,あるいは文字列を返す式です.メッセージを表示しながら BODY を評価し,最後にかかった時間をミリ秒で表示します.返り値は BODY の返り値と同じになります.

Usage

これだけじゃ何が便利だかわからないと思うので,いくつか例を.

  • Emacsの起動にかかった時間をミリ秒で出す.
(stopwatch-by-ms before-init-time after-init-time) ; => 1613.221
  • Emacsを起動させてからの経過時間を分で出す.
(stopwatch-by-min after-init-time nil t) ; => 13
  • ファイル hoge の最終更新時刻から現在までの日数を出す.
(stopwatch-by-day (nth 5 (file-attributes hoge))) nil t) ; => 291

Emacs Lisp を編集しているときにちょっとしたデバッグのために,式と式の間に message() を仕込んだりすることがあります.それと同様のことを時間表示付きで行うことが出来ます.

;; auto-complete.el 内の ac-symbol-candidates() の定義より抜粋.
(or ac-symbols-cache
    (setq ac-symbols-cache
          ;; loop について調査
          (with-stopwatch "TEST: loop for ac-symbols-cache"
            (loop for x being the symbols
                  if (or (fboundp x)
                         (boundp x)
                         (symbol-plist x))
                  collect (symbol-name x)))))

上の式を評価すると,*Messages* buffer に返り値と共に次のように表示され,loop 処理が中断なく実行されていることと,おおよその実行時間がわかります.

Running TEST: loop for ac-symbols-cache...done [36.923 ms]
("yas/check-commit-snippet" "yas/use-menu" "find-library-name" "Buffer-menu" "menu-bar-update-buffers" "vc-mtn-admin-dir" "desktop-clear" "egg-status-popup-delta-menu" "ac-l-prefix-in-paren" "popup-menu-show-quick-help" "auto-install-emacswiki-base-url" "mm-ucs-to-char" ...)

更新情報

version 0.2: stopwatch-define-unit-fn を定義.関数の使い方を統一.