Scheme:MOP:ProfiledGeneric

Scheme:MOP:ProfiledGeneric

ProfiledGeneric

すでにGaucheにはプロファイラが実装されたわけだけど、 Gauche本とか読むと 自分でみやってみたくなってきた。 特に総称関数回りはいじったことなかったので。

profiled-generic.scm

うーん。 まぁ土台はいいとして、<*-time-counter>の使い方とか 意味とかこれでいいのかしらん。 メソッド名とかも、どうもセンスねーなーって感じる。

残件

;;;
;;; profiled-generic - MOP sample -
;;;  
;;;   Copyright (c) 2007  Katsutoshi Itoh  <cut-sea@master.email.ne.jp>
;;;   
;;;   Redistribution and use in source and binary forms, with or without
;;;   modification, are permitted provided that the following conditions
;;;   are met:
;;;   
;;;   1. Redistributions of source code must retain the above copyright
;;;      notice, this list of conditions and the following disclaimer.
;;;  
;;;   2. Redistributions in binary form must reproduce the above copyright
;;;      notice, this list of conditions and the following disclaimer in the
;;;      documentation and/or other materials provided with the distribution.
;;;  
;;;   3. Neither the name of the authors nor the names of its contributors
;;;      may be used to endorse or promote products derived from this
;;;      software without specific prior written permission.
;;;  
;;;   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
;;;   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
;;;   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
;;;   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
;;;   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
;;;   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
;;;   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
;;;   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
;;;   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
;;;   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;;;   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;;;  
;;;  $Id$
;;;

(define-module gauche.mop.profiled-generic
  (use srfi-1)
  (use gauche.time)

  (export
   <profiled-generic>
   profile-init!
   profile-on!
   profile-off!
   profile-on?
   get-profile
   )
  )
(select-module gauche.mop.profiled-generic)

(define-class <profiled-data> ()
  ((count     :accessor count-of :init-value 0)
   (real-time :accessor real-time-of :init-form (make <real-time-counter>))
   (sys-time  :accessor sys-time-of  :init-form (make <system-time-counter>))
   (proc-time :accessor proc-time-of :init-form (make <process-time-counter>))
   (user-time :accessor user-time-of :init-form (make <user-time-counter>))))

(define-class <profiled-generic> (<generic>)
  ((enable    :accessor enable-of :init-value #t)
   (hash      :accessor hash-of :init-value (make-hash-table 'equal?))))

(define-method profile-init! ((gf <profiled-generic>))
  (set! (hash-of gf) (make-hash-table 'equal?)))

(define-method profile-on! ((gf <profiled-generic>))
  (set! (enable-of gf) #t))

(define-method profile-off! ((gf <profiled-generic>))
  (set! (enable-of gf) #f))

(define-method profile-on? ((gf <profiled-generic>))
  (enable-of gf))

(define-method apply-generic ((gf <profiled-generic>) args)
  (if (profile-on? gf)
      (let ((h   (hash-of gf))
            (key (map class-of args)))
        (unless (hash-table-exists? h key)
          (hash-table-put! h key (make <profiled-data>)))
        (let1 pd (hash-table-get h key)
          (inc! (count-of pd))
          (with-time-counter (real-time-of pd)
            (with-time-counter (sys-time-of pd)
              (with-time-counter (proc-time-of pd)
                (with-time-counter (user-time-of pd)
                  (next-method)))))))
      (next-method)))

(define-method object-hash ((class <class>))
  (hash (ref class 'name)))

(define-method get-profile ((gf <profiled-generic>))
  (format #t "counts\treal\tsys\tproc\tuser\targuments~%")
  (hash-table-for-each (hash-of gf)
    (lambda (k v)
      (format #t "~d\t~d\t~d\t~d\t~d"
              (count-of v)
              (time-counter-value (real-time-of v))
              (time-counter-value (sys-time-of v))
              (time-counter-value (proc-time-of v))
              (time-counter-value (user-time-of v)))
      (format #t "\t~a~%" (string-join (map (lambda (c) (x->string (ref c 'name))) k) ",")))))

(provide "gauche/mop/prifiled-generic")

使用してみる

モジュールをuseしてからプロファイルしたい総称関数を用意。

(use gauche.mop.profiled-generic)

(define-generic add :class <profiled-generic>)

(define-method add ((n1 <number>) (n2 <number>))
  (+ n1 n2))

(define-method add ((s1 <string>) (s2 <string>))
  (string-append s1 s2))

(define-method add ((l1 <list>) (l2 <list>))
  (append l1 l2))

これでaddを使ってみよう。

gosh> (add (expt 2 100) (sin 0.9))
1.2676506002282294e30
gosh> (add "ABCDEF" "あいうえお")
"ABCDEFあいうえお"
gosh> (add (iota 10) (list <class> <integer>))
(0 1 2 3 4 5 6 7 8 9 #<class <class>> #<class <integer>>)

gosh> (get-profile add)
counts  real    sys     proc    user    arguments
1       1.31e-4 0.0     0.0     0.0     <integer>,<real>
1       1.27e-4 0.0     0.0     0.0     <pair>,<pair>
1       1.32e-4 0.0     0.0     0.0     <string>,<string>
#<undef>
gosh> 

左からcallされた回数、real/system/process/userの消費時間、引数の型のつもり。


Last modified : 2012/02/07 08:28:10 UTC