Function: display-call-tree

display-call-tree is an autoloaded, interactive and byte-compiled function defined in bytecomp.el.gz.

Signature

(display-call-tree &optional FILENAME)

Documentation

Display a call graph of a specified file.

This lists which functions have been called, what functions called them, and what functions they call. The list includes all functions whose definitions have been compiled in this Emacs session, as well as all functions called by those functions.

The call graph does not include macros, inline functions, or primitives that the byte-code interpreter knows about directly
(eq, cons, etc.).

The call tree also lists those functions which are not known to be called
(that is, to which no calls have been compiled), and which cannot be
invoked interactively.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/emacs-lisp/bytecomp.el.gz
;; Renamed from byte-compile-report-call-tree
;; to avoid interfering with completion of byte-compile-file.
;;;###autoload
(defun display-call-tree (&optional filename)
  "Display a call graph of a specified file.
This lists which functions have been called, what functions called
them, and what functions they call.  The list includes all functions
whose definitions have been compiled in this Emacs session, as well as
all functions called by those functions.

The call graph does not include macros, inline functions, or
primitives that the byte-code interpreter knows about directly
\(`eq', `cons', etc.).

The call tree also lists those functions which are not known to be called
\(that is, to which no calls have been compiled), and which cannot be
invoked interactively."
  (interactive)
  (message "Generating call tree...")
  (with-output-to-temp-buffer "*Call-Tree*"
    (set-buffer "*Call-Tree*")
    (erase-buffer)
    (message "Generating call tree... (sorting on %s)"
	     (remove-pos-from-symbol byte-compile-call-tree-sort))
    (insert "Call tree for "
	    (cond ((null byte-compile-current-file) (or filename "???"))
		  ((stringp byte-compile-current-file)
		   byte-compile-current-file)
		  (t (buffer-name byte-compile-current-file)))
	    " sorted on "
	    (prin1-to-string (remove-pos-from-symbol
                              byte-compile-call-tree-sort))
	    ":\n\n")
    (if byte-compile-call-tree-sort
	(setq byte-compile-call-tree
	      (sort byte-compile-call-tree
		    (pcase byte-compile-call-tree-sort
                      ('callers
                       (lambda (x y) (< (length (nth 1 x))
                                        (length (nth 1 y)))))
                      ('calls
                       (lambda (x y) (< (length (nth 2 x))
                                        (length (nth 2 y)))))
                      ('calls+callers
                       (lambda (x y) (< (+ (length (nth 1 x))
                                           (length (nth 2 x)))
                                        (+ (length (nth 1 y))
                                           (length (nth 2 y))))))
                      ('name
                       (lambda (x y) (string< (car x) (car y))))
                      (_ (error "`byte-compile-call-tree-sort': `%s' - unknown sort mode"
                                (remove-pos-from-symbol
                                 byte-compile-call-tree-sort)))))))
    (message "Generating call tree...")
    (let ((rest byte-compile-call-tree)
	  (b (current-buffer))
	  f p
	  callers calls)
      (while rest
	(prin1 (car (car rest)) b)
	(setq callers (nth 1 (car rest))
	      calls (nth 2 (car rest)))
	(insert "\t"
	  (cond ((not (fboundp (setq f (car (car rest)))))
		 (if (null f)
		     " <top level>";; shouldn't insert nil then, actually -sk
		   " <not defined>"))
		((symbolp (setq f (symbol-function f))) ;; An alias.
		 (format " ==> %s" f))
		((not (consp f))
		 (format " <%s>" (type-of f)))
		((eq 'macro (car f))
		 (if (compiled-function-p (cdr f))
		     " <compiled macro>"
		   " <macro>"))
		((eq 'lambda (car f))
		 "<function>")
		(t "???"))
	  (format " (%d callers + %d calls = %d)"
		  ;; Does the optimizer eliminate common subexpressions?-sk
		  (length callers)
		  (length calls)
		  (+ (length callers) (length calls)))
	  "\n")
	(if callers
	    (progn
	      (insert "  called by:\n")
	      (setq p (point))
	      (insert "    " (if (car callers)
				 (mapconcat 'symbol-name callers ", ")
			       "<top level>"))
	      (let ((fill-prefix "    "))
		(fill-region-as-paragraph p (point)))
              (unless (= 0 (current-column))
                (insert "\n"))))
	(if calls
	    (progn
	      (insert "  calls:\n")
	      (setq p (point))
	      (insert "    " (mapconcat 'symbol-name calls ", "))
	      (let ((fill-prefix "    "))
		(fill-region-as-paragraph p (point)))
              (unless (= 0 (current-column))
                (insert "\n"))))
	(setq rest (cdr rest)))

      (message "Generating call tree...(finding uncalled functions...)")
      (setq rest byte-compile-call-tree)
      (let (uncalled def)
	(while rest
	  (or (nth 1 (car rest))
	      (null (setq f (caar rest)))
	      (progn
		(setq def (byte-compile-fdefinition f t))
		(and (eq (car-safe def) 'macro)
		     (eq (car-safe (cdr-safe def)) 'lambda)
		     (setq def (cdr def)))
		(functionp def))
	      (progn
		(setq def (byte-compile-fdefinition f nil))
		(and (eq (car-safe def) 'macro)
		     (eq (car-safe (cdr-safe def)) 'lambda)
		     (setq def (cdr def)))
		(commandp def))
	      (setq uncalled (cons f uncalled)))
	  (setq rest (cdr rest)))
	(if uncalled
	    (let ((fill-prefix "  "))
	      (insert "Noninteractive functions not known to be called:\n  ")
	      (setq p (point))
	      (insert (mapconcat 'symbol-name (nreverse uncalled) ", "))
	      (fill-region-as-paragraph p (point))))))
    (message "Generating call tree...done.")))