prof.scm 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. ;; chartprof -- a graphical tree frontend to statprof
  2. ;; Copyright (C) 2009 Andy Wingo <wingo@pobox.com>
  3. ;; This program is free software: you can redistribute it and/or modify
  4. ;; it under the terms of the GNU Lesser General Public License as
  5. ;; published by the Free Software Foundation, either version 3 of the
  6. ;; License, or (at your option) any later version.
  7. ;;
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU Lesser General Public License for more details.
  12. ;;
  13. ;; You should have received a copy of the GNU Lesser General Public
  14. ;; License along with this program. If not, see
  15. ;; <http://www.gnu.org/licenses/>.
  16. (define-module (charting prof)
  17. #:use-module (srfi srfi-1)
  18. #:use-module (ice-9 format)
  19. #:use-module (ice-9 receive)
  20. #:use-module (statprof)
  21. #:use-module (cairo)
  22. #:use-module (charting util)
  23. #:use-module (charting draw)
  24. #:export (chartprof))
  25. (define *width* 8)
  26. (define *right-text-width* 100)
  27. (define *unit-height* 8)
  28. (define *spacing* 4)
  29. (define *unit-height-with-spacing* (+ *unit-height* *spacing*))
  30. (define *margin* 16)
  31. (define (show-object cr object x y justification)
  32. (let* ((text (with-output-to-string (lambda () (display object))))
  33. (width (cairo-text-extents:width (cairo-text-extents cr text))))
  34. (cairo-move-to
  35. cr
  36. (+ (case justification
  37. ((left) 0)
  38. ((right) (- width))
  39. ((center) (- (/ width 2)))
  40. (else
  41. (error "unknown justification" justification)))
  42. x)
  43. y)
  44. (cairo-show-text cr text)))
  45. (define (annotate-node cr tree)
  46. (define (fmt val)
  47. (format #f "~,2f" (* 100.0 (/ val (cadr tree)))))
  48. (define (node-pre tree x-y)
  49. (let ((imgwidth (cairo-image-surface-get-width (cairo-get-target cr)))
  50. (terminal (fold (lambda (x y) (- y (cadr x)))
  51. (cadr tree)
  52. (cddr tree))))
  53. (if (or (null? (cddr tree))
  54. (not (null? (cdddr tree))))
  55. (begin
  56. (cairo-save cr)
  57. (cairo-set-source-rgba cr 0.7 0.7 0.7 1)
  58. (cairo-set-line-width cr 1)
  59. (cairo-move-to cr (+ (* 2 (car x-y) *width*) *margin*)
  60. (+ (cdr x-y) *unit-height* 1 (- *margin*)))
  61. (cairo-line-to cr (- imgwidth *margin*)
  62. (+ (cdr x-y) *unit-height* 1 (- *margin*)))
  63. (cairo-stroke cr)
  64. (cairo-restore cr)))
  65. (if (> terminal 0)
  66. (show-object cr (fmt terminal) (+ (* 2 (car x-y) *width*) *margin*)
  67. (+ (cdr x-y) *unit-height* (- *margin*))
  68. 'left))
  69. (if (< terminal (cadr tree))
  70. (show-object cr (fmt (- (cadr tree) terminal))
  71. (+ (- (* 2 (car x-y) *width*) *width*) *margin*)
  72. (+ (cdr x-y) *unit-height* (- *margin*))
  73. 'right))
  74. (show-object cr (car tree) (- imgwidth *margin*)
  75. (+ (cdr x-y) *unit-height* (- *margin*))
  76. 'right)
  77. (cons (car x-y) (+ (cdr x-y) (* terminal *unit-height*)))))
  78. (define (subnode subtree x-y)
  79. (draw-fold subtree node-pre subnode node-post
  80. (cons (1+ (car x-y)) (+ (cdr x-y) *unit-height-with-spacing*))))
  81. (define (node-post tree x-y)
  82. (cons (1- (car x-y)) (cdr x-y)))
  83. (cairo-set-source-rgba cr 0 0 0 1)
  84. (cairo-select-font-face cr "Monospace" 'normal 'normal)
  85. (cairo-set-font-size cr 10.0)
  86. (draw-fold tree node-pre subnode node-post (cons 1 *margin*)))
  87. (define (draw-node cr tree)
  88. (define (node-pre tree swoosh-y)
  89. (let ((terminal (fold (lambda (x y) (- y (cadr x)))
  90. (cadr tree)
  91. (cddr tree))))
  92. (cairo-rel-line-to cr *width* 0)
  93. (cairo-rel-line-to cr 0 (* terminal *unit-height*))
  94. (+ swoosh-y (* terminal *unit-height*))))
  95. (define (subnode subtree swoosh-y)
  96. (receive (current-x current-y) (cairo-get-current-point cr)
  97. (let* ((swoosh-y (+ *unit-height-with-spacing* swoosh-y))
  98. (y-offset (- swoosh-y current-y)))
  99. (cairo-rel-curve-to cr *width* 0 0 y-offset *width* y-offset)
  100. (let ((swoosh-y (draw-fold subtree node-pre subnode node-post swoosh-y)))
  101. (cairo-rel-curve-to cr (- *width*) 0 0 (- y-offset)
  102. (- *width*) (- y-offset))
  103. swoosh-y))))
  104. (define (node-post tree swoosh-y)
  105. (cairo-rel-line-to cr (- *width*) 0)
  106. swoosh-y)
  107. (cairo-move-to cr 0 0)
  108. (draw-fold tree node-pre subnode node-post 0)
  109. (cairo-close-path cr)
  110. (cairo-set-source-rgba cr 1 0.5 0.5 1.0)
  111. (cairo-fill-preserve cr)
  112. (cairo-stroke cr))
  113. (define (draw-fold tree node-pre subnode node-post seed)
  114. (node-post tree (fold subnode (node-pre tree seed) (cddr tree))))
  115. (define (count-nodes tree)
  116. (fold (lambda (x y) (+ (count-nodes x) y))
  117. 1
  118. (cddr tree)))
  119. (define (depth tree)
  120. (+ 1 (fold (lambda (x y) (max (depth x) y))
  121. 0
  122. (cddr tree))))
  123. (define (chartprof filename)
  124. (let ((tree (statprof-fetch-call-tree)))
  125. (if (null? tree)
  126. (format #t "No stacks collected. Did you run statprof with #:full-stacks #t?")
  127. (let* ((width (+ (* 2 (depth tree) *width*) (* 2 *margin*) *right-text-width*))
  128. (height (+ (* (count-nodes tree) *unit-height-with-spacing*)
  129. (* (cadr tree) *unit-height*)))
  130. (surface (cairo-image-surface-create 'rgb24
  131. (+ width (* 2 *margin*))
  132. (+ height (* 2 *margin*))))
  133. (cr (cairo-create surface)))
  134. (cairo-translate cr *margin* *margin*)
  135. (draw-background cr)
  136. (draw-node cr tree)
  137. (cairo-translate cr (- *margin*) 0)
  138. (annotate-node cr tree)
  139. (cairo-surface-write-to-png surface filename)))))