123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- ;; chartprof -- a graphical tree frontend to statprof
- ;; Copyright (C) 2009 Andy Wingo <wingo@pobox.com>
- ;; This program is free software: you can redistribute it and/or modify
- ;; it under the terms of the GNU Lesser General Public License as
- ;; published by the Free Software Foundation, either version 3 of the
- ;; License, or (at your option) any later version.
- ;;
- ;; This program is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU Lesser General Public License for more details.
- ;;
- ;; You should have received a copy of the GNU Lesser General Public
- ;; License along with this program. If not, see
- ;; <http://www.gnu.org/licenses/>.
- (define-module (charting prof)
- #:use-module (srfi srfi-1)
- #:use-module (ice-9 format)
- #:use-module (ice-9 receive)
- #:use-module (statprof)
- #:use-module (cairo)
- #:use-module (charting util)
- #:use-module (charting draw)
- #:export (chartprof))
- (define *width* 8)
- (define *right-text-width* 100)
- (define *unit-height* 8)
- (define *spacing* 4)
- (define *unit-height-with-spacing* (+ *unit-height* *spacing*))
- (define *margin* 16)
- (define (show-object cr object x y justification)
- (let* ((text (with-output-to-string (lambda () (display object))))
- (width (cairo-text-extents:width (cairo-text-extents cr text))))
- (cairo-move-to
- cr
- (+ (case justification
- ((left) 0)
- ((right) (- width))
- ((center) (- (/ width 2)))
- (else
- (error "unknown justification" justification)))
- x)
- y)
- (cairo-show-text cr text)))
- (define (annotate-node cr tree)
- (define (fmt val)
- (format #f "~,2f" (* 100.0 (/ val (cadr tree)))))
- (define (node-pre tree x-y)
- (let ((imgwidth (cairo-image-surface-get-width (cairo-get-target cr)))
- (terminal (fold (lambda (x y) (- y (cadr x)))
- (cadr tree)
- (cddr tree))))
- (if (or (null? (cddr tree))
- (not (null? (cdddr tree))))
- (begin
- (cairo-save cr)
- (cairo-set-source-rgba cr 0.7 0.7 0.7 1)
- (cairo-set-line-width cr 1)
- (cairo-move-to cr (+ (* 2 (car x-y) *width*) *margin*)
- (+ (cdr x-y) *unit-height* 1 (- *margin*)))
- (cairo-line-to cr (- imgwidth *margin*)
- (+ (cdr x-y) *unit-height* 1 (- *margin*)))
- (cairo-stroke cr)
- (cairo-restore cr)))
- (if (> terminal 0)
- (show-object cr (fmt terminal) (+ (* 2 (car x-y) *width*) *margin*)
- (+ (cdr x-y) *unit-height* (- *margin*))
- 'left))
- (if (< terminal (cadr tree))
- (show-object cr (fmt (- (cadr tree) terminal))
- (+ (- (* 2 (car x-y) *width*) *width*) *margin*)
- (+ (cdr x-y) *unit-height* (- *margin*))
- 'right))
- (show-object cr (car tree) (- imgwidth *margin*)
- (+ (cdr x-y) *unit-height* (- *margin*))
- 'right)
- (cons (car x-y) (+ (cdr x-y) (* terminal *unit-height*)))))
- (define (subnode subtree x-y)
- (draw-fold subtree node-pre subnode node-post
- (cons (1+ (car x-y)) (+ (cdr x-y) *unit-height-with-spacing*))))
- (define (node-post tree x-y)
- (cons (1- (car x-y)) (cdr x-y)))
- (cairo-set-source-rgba cr 0 0 0 1)
- (cairo-select-font-face cr "Monospace" 'normal 'normal)
- (cairo-set-font-size cr 10.0)
- (draw-fold tree node-pre subnode node-post (cons 1 *margin*)))
- (define (draw-node cr tree)
- (define (node-pre tree swoosh-y)
- (let ((terminal (fold (lambda (x y) (- y (cadr x)))
- (cadr tree)
- (cddr tree))))
- (cairo-rel-line-to cr *width* 0)
- (cairo-rel-line-to cr 0 (* terminal *unit-height*))
- (+ swoosh-y (* terminal *unit-height*))))
- (define (subnode subtree swoosh-y)
- (receive (current-x current-y) (cairo-get-current-point cr)
- (let* ((swoosh-y (+ *unit-height-with-spacing* swoosh-y))
- (y-offset (- swoosh-y current-y)))
- (cairo-rel-curve-to cr *width* 0 0 y-offset *width* y-offset)
- (let ((swoosh-y (draw-fold subtree node-pre subnode node-post swoosh-y)))
- (cairo-rel-curve-to cr (- *width*) 0 0 (- y-offset)
- (- *width*) (- y-offset))
- swoosh-y))))
- (define (node-post tree swoosh-y)
- (cairo-rel-line-to cr (- *width*) 0)
- swoosh-y)
- (cairo-move-to cr 0 0)
- (draw-fold tree node-pre subnode node-post 0)
- (cairo-close-path cr)
- (cairo-set-source-rgba cr 1 0.5 0.5 1.0)
- (cairo-fill-preserve cr)
- (cairo-stroke cr))
- (define (draw-fold tree node-pre subnode node-post seed)
- (node-post tree (fold subnode (node-pre tree seed) (cddr tree))))
- (define (count-nodes tree)
- (fold (lambda (x y) (+ (count-nodes x) y))
- 1
- (cddr tree)))
- (define (depth tree)
- (+ 1 (fold (lambda (x y) (max (depth x) y))
- 0
- (cddr tree))))
- (define (chartprof filename)
- (let ((tree (statprof-fetch-call-tree)))
- (if (null? tree)
- (format #t "No stacks collected. Did you run statprof with #:full-stacks #t?")
- (let* ((width (+ (* 2 (depth tree) *width*) (* 2 *margin*) *right-text-width*))
- (height (+ (* (count-nodes tree) *unit-height-with-spacing*)
- (* (cadr tree) *unit-height*)))
- (surface (cairo-image-surface-create 'rgb24
- (+ width (* 2 *margin*))
- (+ height (* 2 *margin*))))
- (cr (cairo-create surface)))
- (cairo-translate cr *margin* *margin*)
- (draw-background cr)
- (draw-node cr tree)
- (cairo-translate cr (- *margin*) 0)
- (annotate-node cr tree)
- (cairo-surface-write-to-png surface filename)))))
|