statprof.test 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. ;;;; statprof.test --- test suite for Guile's profiler -*- scheme -*-
  2. ;;;; Copyright (C) 2017 Free Software Foundation, Inc.
  3. ;; Copyright (C) 2004, 2009, 2010, 2014 Andy Wingo <wingo at pobox dot com>
  4. ;; Copyright (C) 2001 Rob Browning <rlb at defaultvalue dot org>
  5. ;; This library is free software; you can redistribute it and/or
  6. ;; modify it under the terms of the GNU Lesser General Public
  7. ;; License as published by the Free Software Foundation; either
  8. ;; version 2.1 of the License, or (at your option) any later version.
  9. ;;
  10. ;; This library is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. ;; Lesser General Public License for more details.
  14. ;;
  15. ;; You should have received a copy of the GNU Lesser General Public
  16. ;; License along with this program; if not, contact:
  17. ;;
  18. ;; Free Software Foundation Voice: +1-617-542-5942
  19. ;; 59 Temple Place - Suite 330 Fax: +1-617-542-2652
  20. ;; Boston, MA 02111-1307, USA gnu@gnu.org
  21. ;;; Commentary:
  22. ;;
  23. ;; Unit tests for (debugging statprof).
  24. ;;
  25. ;;; Code:
  26. (define-module (test-suite test-statprof)
  27. #:use-module (test-suite lib)
  28. #:use-module (system base compile)
  29. #:use-module (srfi srfi-1)
  30. #:use-module (statprof))
  31. ;; Throw `unresolved' upon ENOSYS or EINVAL. This is used to skip tests
  32. ;; on platforms such as GNU/Hurd or Cygwin where `ITIMER_PROF' is is
  33. ;; currently unimplemented.
  34. (define-syntax-rule (when-implemented body ...)
  35. (catch 'system-error
  36. (lambda ()
  37. body ...)
  38. (lambda args
  39. (let ((errno (system-error-errno args)))
  40. (false-if-exception (statprof-stop))
  41. (if (or (= errno ENOSYS) (= errno EINVAL))
  42. (throw 'unresolved)
  43. (apply throw args))))))
  44. (pass-if-equal "return values"
  45. '(42 77)
  46. (when-implemented
  47. (call-with-values
  48. (lambda ()
  49. (with-output-to-port (%make-void-port "w")
  50. (lambda ()
  51. (statprof
  52. (lambda ()
  53. (let loop ((i 10000))
  54. (if (zero? i)
  55. (values 42 77)
  56. (loop (1- i)))))))))
  57. list)))
  58. (pass-if "statistical sample counts within expected range"
  59. (when-implemented
  60. ;; test to see that if we call 3 identical functions equally, they
  61. ;; show up equally in the call count, +/- 30%. it's a big range, and
  62. ;; I tried to do something more statistically valid, but failed (for
  63. ;; the moment).
  64. ;; make sure these are compiled so we're not swamped in `eval'
  65. (define (make-func)
  66. ;; Disable partial evaluation so that `(+ i i)' doesn't get
  67. ;; stripped.
  68. (compile '(lambda (n)
  69. (do ((i 0 (+ i 1))) ((= 200 i)) (+ i i)))
  70. #:opts '(#:partial-eval? #f)))
  71. (define run-test
  72. (compile '(lambda (num-calls funcs)
  73. (let loop ((x num-calls) (funcs funcs))
  74. (cond
  75. ((positive? x)
  76. ((car funcs) x)
  77. (loop (- x 1) (cdr funcs))))))))
  78. (let ((num-calls 200000)
  79. (funcs (circular-list (make-func) (make-func) (make-func))))
  80. ;; Run test. 20000 us == 200 Hz.
  81. (statprof-reset 0 20000 #f #f)
  82. (statprof-start)
  83. (run-test num-calls funcs)
  84. (statprof-stop)
  85. (let ((a-data (statprof-proc-call-data (car funcs)))
  86. (b-data (statprof-proc-call-data (cadr funcs)))
  87. (c-data (statprof-proc-call-data (caddr funcs))))
  88. (if (and a-data b-data c-data)
  89. (let* ((samples (map statprof-call-data-cum-samples
  90. (list a-data b-data c-data)))
  91. (expected (/ (apply + samples) 3.0))
  92. (diffs (map (lambda (x) (abs (- x expected)))
  93. samples))
  94. (max-diff (apply max diffs)))
  95. (or (< max-diff (sqrt expected))
  96. ;; don't stop the test suite for what statistically is
  97. ;; bound to happen.
  98. (begin
  99. (format (current-warning-port)
  100. ";;; warning: max diff ~a > (sqrt ~a)\n"
  101. max-diff expected)
  102. (throw 'unresolved))))
  103. ;; Samples were not collected for at least one of the
  104. ;; functions, possibly because NUM-CALLS is too low compared
  105. ;; to the CPU speed.
  106. (throw 'unresolved (pk (list a-data b-data c-data))))))))
  107. (pass-if "accurate call counting"
  108. (when-implemented
  109. ;; Test to see that if we call a function N times while the profiler
  110. ;; is active, it shows up N times.
  111. (let ((num-calls 200))
  112. (define do-nothing
  113. (compile '(lambda (n)
  114. (simple-format #f "FOO ~A\n" (+ n n)))))
  115. ;; Run test.
  116. (statprof-reset 0 50000 #t #f)
  117. (statprof-start)
  118. (let loop ((x num-calls))
  119. (cond
  120. ((positive? x)
  121. (do-nothing x)
  122. (loop (- x 1))
  123. #t)))
  124. (statprof-stop)
  125. ;; Check result.
  126. (let ((proc-data (statprof-proc-call-data do-nothing)))
  127. (and proc-data
  128. (= (statprof-call-data-calls proc-data)
  129. num-calls))))))