branch: elpa/flamegraph
commit 90efec373228fa504aaa0cd15b8a62962456478f
Author: Dmitry Gutov <[email protected]>
Commit: Dmitry Gutov <[email protected]>
Drop cold callees from describe-buffer snippets
Add flamegraph-call-site-threshold (default 2%): callees whose share of
the described frame's count falls below it are no longer highlighted in
the source snippet, nor are their lines pulled into it.
---
README.md | 1 +
flamegraph.el | 15 +++++++++++++--
test/flamegraph-tests.el | 19 +++++++++++++++++++
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 9d48b1d61c..1853c9d0c3 100644
--- a/README.md
+++ b/README.md
@@ -153,6 +153,7 @@ canonical [CPU Flame Graphs][cpufg] article.
| `flamegraph-frame-border` | Pixel gap between adjacent frame boxes |
| `flamegraph-text-padding` | Pixels between a frame's left edge and its label
|
| `flamegraph-source-directory` | Where to resolve relative paths when
visiting source |
+| `flamegraph-call-site-threshold` | Min sample share for a callee to appear
in the describe-buffer snippet (default: 2%) |
| Face | Purpose |
| --- | --- |
diff --git a/flamegraph.el b/flamegraph.el
index c42410e213..95d3186add 100644
--- a/flamegraph.el
+++ b/flamegraph.el
@@ -84,6 +84,12 @@ FILE:LINE location. If nil, paths are resolved against the
directory of
the data file the graph was loaded from."
:type '(choice (const :tag "Data file's directory" nil) directory))
+(defcustom flamegraph-call-site-threshold 0.02
+ "Minimum share of a frame's samples for a callee to appear in its snippet.
+Callees below this fraction (of the described frame's count) are not
+highlighted in the describe-buffer source."
+ :type 'float)
+
(defface flamegraph-call-site-hot
'((((background light)) :background "#ff9b3d")
(((background dark)) :background "#9c4a1c"))
@@ -683,8 +689,10 @@ in completely unrelated forms (a literal `(if …)'
elsewhere), or
may not exist at all (`dolist' → `while'/`let'). Only real function
matches narrow, which is what preserves structural attribution.
-Each region is (POS-BEG POS-END WEIGHT), WEIGHT being the callee's
-share of NODE's count, for heat styling."
+Callees below `flamegraph-call-site-threshold' of NODE's count are
+dropped along with their subtree. Each region is (POS-BEG POS-END
+WEIGHT), WEIGHT being the callee's share of NODE's count, for heat
+styling."
(let ((total (max 1 (profiler-calltree-count node)))
regions)
(cl-labels
@@ -698,6 +706,9 @@ share of NODE's count, for heat styling."
(skip
;; Special form — transparent descend, no narrowing.
(walk k region))
+ ((< weight flamegraph-call-site-threshold)
+ ;; Too cold to be worth showing — drop it and its subtree.
+ nil)
((flamegraph--callee-name-acceptable-p name)
;; Real function — search in the current region.
;; Each match is highlighted and narrows the search
diff --git a/test/flamegraph-tests.el b/test/flamegraph-tests.el
index 8efadf6f7f..ae3800d6f8 100644
--- a/test/flamegraph-tests.el
+++ b/test/flamegraph-tests.el
@@ -193,6 +193,25 @@ callees outside it must still be found."
outer (point-min) (point-max))))
(should (equal (flamegraph-test--region-texts regions) '("foo"))))))
+(ert-deftest flamegraph-test-walker-below-threshold-dropped ()
+ "Callees below `flamegraph-call-site-threshold' are dropped with subtree.
+hot at 50% is kept; cold at 1% (and its child) are not."
+ (flamegraph-test--with-elisp-source
+ "(defun outer ()
+ (hot (deep))
+ (cold))"
+ (let* ((deep (profiler-make-calltree :entry 'deep :count 1))
+ (hot (profiler-make-calltree :entry 'hot :count 50
+ :children (list deep)))
+ (cold (profiler-make-calltree :entry 'cold :count 1))
+ (outer (profiler-make-calltree :entry 'outer :count 100
+ :children (list hot cold)))
+ (flamegraph-call-site-threshold 0.02)
+ (regions (flamegraph--collect-nested-call-sites
+ outer (point-min) (point-max))))
+ ;; hot (50%) kept; deep is 1% of outer -> dropped; cold (1%) dropped.
+ (should (equal (flamegraph-test--region-texts regions) '("hot"))))))
+
;;; `flamegraph--symbol-location'
(ert-deftest flamegraph-test-symbol-location ()