Scheme:MOP:ProfiledGeneric
ProfiledGeneric
すでにGaucheにはプロファイラが実装されたわけだけど、 Gauche本とか読むと 自分でみやってみたくなってきた。 特に総称関数回りはいじったことなかったので。
profiled-generic.scm
うーん。 まぁ土台はいいとして、<*-time-counter>の使い方とか 意味とかこれでいいのかしらん。 メソッド名とかも、どうもセンスねーなーって感じる。
残件
- 表示出力をもっとちゃんと整形する。(formatまだまだ使いこなせてない)
;;; ;;; 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の消費時間、引数の型のつもり。