profile.scm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Profiling
  3. ; NOTE: the sampling rate is set at the beginning of each run. Different
  4. ; machines and loadings will produce different tick rates.
  5. (define (profile command)
  6. (let ((thunk (if (eq? (car command) 'run)
  7. (evaluate `(lambda () ,(cadr command))
  8. (environment-for-commands))
  9. (lambda () (execute-command command)))))
  10. (call-with-values
  11. (lambda () (run-with-profiling thunk (command-output)))
  12. (lambda (results hits running on-stack)
  13. (let ((port (command-output)))
  14. (display hits port)
  15. (display " samples" port)
  16. (newline port)
  17. (display "Running:" port)
  18. (newline port)
  19. (display-counts running hits - port)
  20. (display "Waiting:" port)
  21. (newline port)
  22. (display-counts on-stack hits (lambda (total next) next) port)
  23. (set-command-results! results))))))
  24. (define-command-syntax 'profile "<command>" "profile execution"
  25. '(command))
  26. (define (display-counts counts hits combine port)
  27. (let ((limit (quotient hits 10)))
  28. (do ((counts counts (cdr counts))
  29. (total hits (combine total (cdar counts))))
  30. ((or (<= total limit)
  31. (null? counts)
  32. (<= (cdar counts) 1)))
  33. (display " " port)
  34. (display (cdar counts) port)
  35. (display " " port)
  36. (display (caar counts) port)
  37. (newline port))))
  38. ; Strategy:
  39. ; Request periodic interrupts.
  40. ; At each interrupt save the current (raw) continuation.
  41. ; Either at the end of the run or every so many interrupts, stop the
  42. ; timer interrupts and walk the continuations adding the templates to
  43. ; a table, with a count of how many times each has been seen.
  44. (define (run-with-profiling thunk port)
  45. (calculate-tick-rate! port)
  46. (call-with-values
  47. (lambda ()
  48. (dynamic-wind
  49. (lambda ()
  50. (vector-set! interrupt-handlers
  51. (enum interrupt alarm)
  52. handle-timer-interrupt)
  53. (start-periodic-interrupts!))
  54. (lambda ()
  55. (primitive-cwcc
  56. (lambda (top)
  57. (set! *top-continuation* (continuation-cont top))
  58. (set! *hits* 0)
  59. (set! *conts* '())
  60. (set! *templates* '())
  61. (set! *template-counts* (make-template-table))
  62. (set! *cont-counts* (make-template-table))
  63. (set! *cont-count* cont-limit)
  64. (thunk))))
  65. reset-timer-interrupts!))
  66. (lambda results
  67. (for-each add-cont-data! *conts*)
  68. (let ((templates (gather-template-table-data *template-counts*))
  69. (conts (gather-template-table-data *cont-counts*)))
  70. (set! *top-continuation* #f) ; drop pointer
  71. (set! *conts* '())
  72. (values results *hits* templates conts)))))
  73. (define *quantum-mantissa* #f)
  74. (define *quantum-exponent* #f)
  75. ; For checking how fast the machine is.
  76. (define (fib x)
  77. (if (< x 2)
  78. 1
  79. (+ (fib (- x 1)) (fib (- x 2)))))
  80. (define (calculate-tick-rate! port)
  81. (let ((start-time (run-time)))
  82. (fib 17) ; chosen more or less at random.
  83. (let ((end-time (run-time)))
  84. (set! *quantum-mantissa* (quotient (- end-time start-time) 4))
  85. (set! *quantum-exponent* (tick-exponent))
  86. (display (round (/ (* *quantum-mantissa* (expt 10 *quantum-exponent*)))) port)
  87. (display " ticks per second" port)
  88. (newline port))))
  89. (define (start-periodic-interrupts!)
  90. (schedule-interrupt *quantum-mantissa* *quantum-exponent* #t))
  91. (define (stop-periodic-interrupts!)
  92. (schedule-interrupt 0 0 #f))
  93. (define cont-limit 100)
  94. (define *cont-count* cont-limit)
  95. (define (handle-timer-interrupt template ei)
  96. (set! *cont-count* (- *cont-count* 1))
  97. (if (= 0 *cont-count*)
  98. (begin
  99. (stop-periodic-interrupts!)
  100. (for-each add-template-data! *templates*)
  101. (for-each add-cont-data! *conts*)
  102. (set! *cont-count* cont-limit)
  103. (set! *templates* '())
  104. (set! *conts* '())
  105. (start-periodic-interrupts!)))
  106. (set! *templates* (cons template *templates*))
  107. (set! *hits* (+ *hits* 1))
  108. (primitive-cwcc (lambda (cont)
  109. (set! *conts* (cons cont *conts*)))))
  110. (define *top-continuation* #f)
  111. (define *conts* '())
  112. (define *templates* '())
  113. (define *hits* 0)
  114. (define make-template-table (make-table-maker eq? template-id))
  115. (define *template-counts* (make-template-table))
  116. (define *cont-counts* (make-template-table))
  117. (define (okay-cont? cont)
  118. (and cont (not (eq? cont *top-continuation*))))
  119. (define (add-template-data! template)
  120. (let ((p (table-ref *template-counts* template)))
  121. (if (not p)
  122. (table-set! *template-counts*
  123. template
  124. (cons 1 '()))
  125. (set-car! p (+ (car p) 1)))))
  126. (define (add-cont-data! cont)
  127. (let loop ((cont (continuation-cont cont)))
  128. (if (and (okay-cont? cont)
  129. (okay-cont? (continuation-cont cont)))
  130. (let* ((template (continuation-template cont))
  131. (p (table-ref *cont-counts* template)))
  132. (if (not p)
  133. (table-set! *cont-counts*
  134. template
  135. (cons 1 '()))
  136. (set-car! p (+ (car p) 1)))
  137. (loop (continuation-cont cont))))))
  138. (define (gather-template-table-data table)
  139. (let ((counts '()))
  140. (table-walk (lambda (template p)
  141. (set! counts
  142. (cons (cons (debug-data-names
  143. (template-debug-data template))
  144. (car p))
  145. counts)))
  146. table)
  147. (sort-list counts
  148. (lambda (p1 p2)
  149. (>= (cdr p1) (cdr p2))))))