ホーム / xyzzy関連 / encap.l


encap.l

指定した関数の機能を置きかえる手段を提供します。

使用例

「最近使ったファイル」に小細工

特定ファイルの名前を固定したり、正規表現で表示を抑制したりします。

(defvar *my-sticking-files* '("~/memo"))     ; 固定するファイルのリスト
(defvar *my-recent-files-mask* '("\\.bak$")) ; 表示を抑制するための正規表現のリスト

(encapsulate 'add-file-history-to-menu
             'stick
             '(let* ((history
                      (remove-if #'(lambda (fn)
                                     (or
                                      (member fn (mapcar #'namestring *my-sticking-files*) :test #'string-equal)
                                      (member-if #'(lambda (re)
                                                     (string-matchp re fn))
                                                 *my-recent-files-mask*)))
                                 *minibuffer-file-name-history*))
                     (*minibuffer-file-name-history* (append *my-sticking-files* history)))
               (apply basic-definition argument-list)))

trace/untrace

指定した関数の実行時の引数と戻り値を"*Trace Output*"バッファに出力します。

;;; trace.l

; (trace function1 function2 ...) makes the functions `traced'.
; (trace) returns `traced' functions.
; (untrace function1 function2 ...) makes the functions `untraced'. 
; (untrace) makes all `traced' functions `untraced'.

(require "encap")

(defvar *trace-function-list* nil)
(defvar *trace-depth* 0)

(defun trace-encap (func)
  (unless (encapsulated-p func 'traced-function)
    (encapsulate func 'traced-function
                 `((ed::setup-trace-output-buffer)
                   (setq *trace-depth* (1+ *trace-depth*))
                   (format *error-output* "~ACalling ~S~%" (make-sequence 'string *trace-depth* :initial-element #\SPC) (cons ',func argument-list))
                   (let ((#1=#:result (multiple-value-list (apply basic-definition argument-list))))
                     (format *error-output* "~A~S returned~{ ~A~}~%" (make-sequence 'string *trace-depth* :initial-element #\SPC) ',func #1#)
                     (setq *trace-depth* (1- *trace-depth*))
                     (values-list #1#))))
    (push func *trace-function-list*)
    func))

(defun trace-unencap (func)
  (when (encapsulated-p func 'traced-function)
    (unencapsulate func 'traced-function)
    (setq *trace-function-list* (remove func *trace-function-list* :test #'eq))
    func))

(defmacro trace (&rest args)
  (if (null args)
      '*trace-function-list*
    `(let (lst)
       (dolist (func ',args (reverse lst))
         (when (trace-encap func)
           (setq lst (cons func lst)))))))

(defmacro untrace (&rest args)
  (if (null args)
      '(let (lst)
        (dolist (func *trace-function-list* lst)
          (when (trace-unencap func)
            (setq lst (cons func lst)))))
    `(let (lst)
       (dolist (func ',args (reverse lst))
         (when (trace-unencap func)
           (setq lst (cons func lst)))))))

;;; trace.l ends here.

profile/unprofile

簡単プロファイラです。呼出し回数や実行時間を計測しますが厳密じゃないです。

;;; profile.l

; (profile function1 function2 ...) makes the functions `profiled'.
; (profile) returns `profiled' functions.
; (unprofile function1 function2 ...) makes the functions `unprofiled'.
; (unprofile) makes all `profiled' functions `unprofiled'.
; (profile-clear) clears profile results.
; (profile-results) shows profile results.

(require "encap")

(defvar *profile-function-list* nil)
(defvar *profile-results* nil)
(unless *profile-results*
  (setq *profile-results* (make-hash-table :test #'eq)))

(defun profile-record (func time)
  (let ((result (gethash func *profile-results*)))
    (if result
        (progn
          (setf (car result) (1+ (car result)))
          (setf (cdr result) (+ time (cdr result))))
      (setf (gethash func *profile-results*)
            (cons 1 time)))))

(defun profile-encap (func)
  (unless (encapsulated-p func 'profiled-function)
    (encapsulate func 'profiled-function
                 `(let ((#1=#:begin (get-internal-real-time)))
                    (multiple-value-prog1
                     (apply basic-definition argument-list)
                     (profile-record ',func (- (get-internal-real-time) #1#)))))
    (push func *profile-function-list*)
    func))

(defun profile-unencap (func)
  (when (encapsulated-p func 'profiled-function)
    (unencapsulate func 'profiled-function)
    (remhash func *profile-results*)
    (setq *profile-function-list* (remove func *profile-function-list* :test #'eq))
    func))

(defun profile-results ()
  (let ((max (apply #'max (cons 8 (mapcar #'(lambda (x) (length (format nil "~S" x))) *profile-function-list*)))))
    (insert (format nil (format nil "~~~D@A  Calls   Total time (msec)  Avg time/call~~%" max) "Function"))
    (insert (make-sequence 'string max :initial-element #\=) "  ======  =================  =============" #\LFD)
    (let ((fmt (format nil "~~~D@S  ~~6D  ~~17D  ~~13F~~%" max)))
      (mapc #'(lambda (func)
                (let ((result (gethash func *profile-results*)))
                  (if result
                      (insert (format nil fmt func (car result) (cdr result) (/ (cdr result) (car result))))
                    (insert (format nil fmt func 0 0 0)))))
            (mapcar #'(lambda (x) (car x))
                    (sort (mapcar #'(lambda (x)
                                      (let ((result (gethash x *profile-results*)))
                                        (if result
                                            (cons x (cdr result))
                                          (cons x 0))))
                                  *profile-function-list*)
                          #'>
                          :key #'cdr))))
    t))

(defun profile-clear ()
  (clrhash *profile-results*)
  t)

(defmacro profile (&rest args)
  (if (null args)
      '*profile-function-list*
    `(let (lst)
       (dolist (func ',args (reverse lst))
         (when (profile-encap func)
           (setq lst (cons func lst)))))))

(defmacro unprofile (&rest args)
  (if (null args)
      '(let (lst)
        (dolist (func *profile-function-list* (reverse lst))
          (when (profile-unencap func)
            (setq lst (cons func lst)))))
    `(let (lst)
       (dolist (func ',args (reverse lst))
         (when (profile-unencap func)
           (setq lst (cons func lst)))))))

;;; profile.l ends here.

履歴


ホーム / xyzzy関連 / encap.l