Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
5.8 KiB

пре 4 година
  1. ;;; swank-sprof.lisp
  2. ;;
  3. ;; Authors: Juho Snellman
  4. ;;
  5. ;; License: MIT
  6. ;;
  7. (in-package :swank)
  8. #+sbcl
  9. (eval-when (:compile-toplevel :load-toplevel :execute)
  10. (require :sb-sprof))
  11. #+sbcl(progn
  12. (defvar *call-graph* nil)
  13. (defvar *node-numbers* nil)
  14. (defvar *number-nodes* nil)
  15. (defun frame-name (name)
  16. (if (consp name)
  17. (case (first name)
  18. ((sb-c::xep sb-c::tl-xep
  19. sb-c::&more-processor
  20. sb-c::top-level-form
  21. sb-c::&optional-processor)
  22. (second name))
  23. (sb-pcl::fast-method
  24. (cdr name))
  25. ((flet labels lambda)
  26. (let* ((in (member :in name)))
  27. (if (stringp (cadr in))
  28. (append (ldiff name in) (cddr in))
  29. name)))
  30. (t
  31. name))
  32. name))
  33. (defun pretty-name (name)
  34. (let ((*package* (find-package :common-lisp-user))
  35. (*print-right-margin* most-positive-fixnum))
  36. (format nil "~S" (frame-name name))))
  37. (defun samples-percent (count)
  38. (sb-sprof::samples-percent *call-graph* count))
  39. (defun node-values (node)
  40. (values (pretty-name (sb-sprof::node-name node))
  41. (samples-percent (sb-sprof::node-count node))
  42. (samples-percent (sb-sprof::node-accrued-count node))))
  43. (defun filter-swank-nodes (nodes)
  44. (let ((swank-packages (load-time-value
  45. (mapcar #'find-package
  46. '(swank swank/rpc swank/mop
  47. swank/match swank/backend)))))
  48. (remove-if (lambda (node)
  49. (let ((name (sb-sprof::node-name node)))
  50. (and (symbolp name)
  51. (member (symbol-package name) swank-packages
  52. :test #'eq))))
  53. nodes)))
  54. (defun serialize-call-graph (&key exclude-swank)
  55. (let ((nodes (sb-sprof::call-graph-flat-nodes *call-graph*)))
  56. (when exclude-swank
  57. (setf nodes (filter-swank-nodes nodes)))
  58. (setf nodes (sort (copy-list nodes) #'>
  59. ;; :key #'sb-sprof::node-count)))
  60. :key #'sb-sprof::node-accrued-count))
  61. (setf *number-nodes* (make-hash-table))
  62. (setf *node-numbers* (make-hash-table))
  63. (loop for node in nodes
  64. for i from 1
  65. with total = 0
  66. collect (multiple-value-bind (name self cumulative)
  67. (node-values node)
  68. (setf (gethash node *node-numbers*) i
  69. (gethash i *number-nodes*) node)
  70. (incf total self)
  71. (list i name self cumulative total)) into list
  72. finally (return
  73. (let ((rest (- 100 total)))
  74. (return (append list
  75. `((nil "Elsewhere" ,rest nil nil)))))))))
  76. (defslimefun swank-sprof-get-call-graph (&key exclude-swank)
  77. (when (setf *call-graph* (sb-sprof:report :type nil))
  78. (serialize-call-graph :exclude-swank exclude-swank)))
  79. (defslimefun swank-sprof-expand-node (index)
  80. (let* ((node (gethash index *number-nodes*)))
  81. (labels ((caller-count (v)
  82. (loop for e in (sb-sprof::vertex-edges v) do
  83. (when (eq (sb-sprof::edge-vertex e) node)
  84. (return-from caller-count (sb-sprof::call-count e))))
  85. 0)
  86. (serialize-node (node count)
  87. (etypecase node
  88. (sb-sprof::cycle
  89. (list (sb-sprof::cycle-index node)
  90. (sb-sprof::cycle-name node)
  91. (samples-percent count)))
  92. (sb-sprof::node
  93. (let ((name (node-values node)))
  94. (list (gethash node *node-numbers*)
  95. name
  96. (samples-percent count)))))))
  97. (list :callers (loop for node in
  98. (sort (copy-list (sb-sprof::node-callers node)) #'>
  99. :key #'caller-count)
  100. collect (serialize-node node
  101. (caller-count node)))
  102. :calls (let ((edges (sort (copy-list (sb-sprof::vertex-edges node))
  103. #'>
  104. :key #'sb-sprof::call-count)))
  105. (loop for edge in edges
  106. collect
  107. (serialize-node (sb-sprof::edge-vertex edge)
  108. (sb-sprof::call-count edge))))))))
  109. (defslimefun swank-sprof-disassemble (index)
  110. (let* ((node (gethash index *number-nodes*))
  111. (debug-info (sb-sprof::node-debug-info node)))
  112. (with-output-to-string (s)
  113. (typecase debug-info
  114. (sb-impl::code-component
  115. (sb-disassem::disassemble-memory (sb-vm::code-instructions debug-info)
  116. (sb-vm::%code-code-size debug-info)
  117. :stream s))
  118. (sb-di::compiled-debug-fun
  119. (let ((component (sb-di::compiled-debug-fun-component debug-info)))
  120. (sb-disassem::disassemble-code-component component :stream s)))
  121. (t `(:error "No disassembly available"))))))
  122. (defslimefun swank-sprof-source-location (index)
  123. (let* ((node (gethash index *number-nodes*))
  124. (debug-info (sb-sprof::node-debug-info node)))
  125. (or (when (typep debug-info 'sb-di::compiled-debug-fun)
  126. (let* ((component (sb-di::compiled-debug-fun-component debug-info))
  127. (function (sb-kernel::%code-entry-points component)))
  128. (when function
  129. (find-source-location function))))
  130. `(:error "No source location available"))))
  131. (defslimefun swank-sprof-start (&key (mode :cpu))
  132. (sb-sprof:start-profiling :mode mode))
  133. (defslimefun swank-sprof-stop ()
  134. (sb-sprof:stop-profiling))
  135. )
  136. (provide :swank-sprof)