Subject: Re: bug#22114: 24.5; [PATCH] Allow profiler.el to display reports after stopping

From: Vasilij Schneidermann <[email-masked]>
Date: Mon, 14 Dec 2015 09:28:36 +0100

> Your testing was too superficial.  IIRC The problem to which the comments
> refer can only show up if you modify the hash-table.
> 
> The problem is corner-case, but real.  And there's no reason not to plug
> that hole.

I see, I can trigger this by removing a key from the log.  I haven't
thought about that possibility yet, because, why would you do that?
Nevertheless, if I'd want to fix this, I'd just need to use
`copy-hash-table` on the log and return its result?

> E.g. I don't think you need to the C-side changes to get the Elisp
> side to provide the functionality you're looking for.

I've initially provided an elisp-only patch that works around the
profiler resetting the log with an extra level of indirection:  Before
stopping the profiler or accessing the log while it's still running, the
log is saved to a variable, the other code just accesses that variable
instead of retrieving the log directly.  I'm not really happy with it
though as it does need more code than the other variant and does only
fix the UI aspect of viewing a report after the profiler has been
stopped.  In case you haven't seen it yet, I'll attach it to this
message.
>From 3464446b83151ad894ff4ee7f62ed1cb7852b1b6 Mon Sep 17 00:00:00 2001
From: Vasilij Schneidermann <[email-masked]>
Date: Tue, 8 Dec 2015 09:01:15 +0100
Subject: [PATCH] Allow for retrieving profiler logs after stopping

---
 lisp/profiler.el | 59 +++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 35 insertions(+), 24 deletions(-)

diff --git a/lisp/profiler.el b/lisp/profiler.el
index f28bbfe..10cdcfb 100644
--- a/lisp/profiler.el
+++ b/lisp/profiler.el
@@ -214,21 +214,23 @@ Optional argument MODE means only check for the specified mode (cpu or mem)."
         (t (or (profiler-running-p 'cpu)
                (profiler-running-p 'mem)))))
 
+(defvar profiler-cpu-log nil)
+
+(defvar profiler-memory-log nil)
+
 (defun profiler-cpu-profile ()
   "Return CPU profile."
-  (when (profiler-running-p 'cpu)
-    (profiler-make-profile
-     :type 'cpu
-     :timestamp (current-time)
-     :log (profiler-cpu-log))))
+  (profiler-make-profile
+   :type 'cpu
+   :timestamp (current-time)
+   :log profiler-cpu-log))
 
 (defun profiler-memory-profile ()
   "Return memory profile."
-  (when (profiler-memory-running-p)
-    (profiler-make-profile
-     :type 'memory
-     :timestamp (current-time)
-     :log (profiler-memory-log))))
+  (profiler-make-profile
+   :type 'memory
+   :timestamp (current-time)
+   :log profiler-memory-log))
 
 
 ;;; Calltrees
@@ -828,7 +830,11 @@ Also, if MODE is `mem' or `cpu+mem', then memory profiler will be started."
 (defun profiler-stop ()
   "Stop started profilers.  Profiler logs will be kept."
   (interactive)
-  (let ((cpu (if (fboundp 'profiler-cpu-stop) (profiler-cpu-stop)))
+  (when (and (fboundp 'profiler-cpu-running-p) (profiler-cpu-running-p))
+    (setq profiler-cpu-log (profiler-cpu-log)))
+  (when (profiler-memory-running-p)
+    (setq profiler-memory-log (profiler-memory-log)))
+  (let ((cpu (when (fboundp 'profiler-cpu-stop) (profiler-cpu-stop)))
         (mem (profiler-memory-stop)))
     (message "%s profiler stopped"
              (cond ((and mem cpu) "CPU and memory")
@@ -839,26 +845,31 @@ Also, if MODE is `mem' or `cpu+mem', then memory profiler will be started."
 (defun profiler-reset ()
   "Reset profiler logs."
   (interactive)
-  (when (fboundp 'profiler-cpu-log)
-    (ignore (profiler-cpu-log)))
-  (ignore (profiler-memory-log))
-  t)
+  (when (and (fboundp 'profiler-cpu-running-p) (profiler-cpu-running-p))
+    (profiler-cpu-stop))
+  (when (profiler-memory-running-p)
+    (profiler-memory-stop))
+  (setq profiler-cpu-log nil
+        profiler-memory-log nil))
 
 (defun profiler-report-cpu ()
-  (let ((profile (profiler-cpu-profile)))
-    (when profile
-      (profiler-report-profile-other-window profile))))
+  (when profiler-cpu-log
+    (profiler-report-profile-other-window (profiler-cpu-profile))))
 
 (defun profiler-report-memory ()
-  (let ((profile (profiler-memory-profile)))
-    (when profile
-      (profiler-report-profile-other-window profile))))
+  (when profiler-memory-log
+    (profiler-report-profile-other-window (profiler-memory-profile))))
 
 (defun profiler-report ()
   "Report profiling results."
-  (interactive)
-  (profiler-report-cpu)
-  (profiler-report-memory))
+  (when (and (fboundp 'profiler-cpu-running-p) (profiler-cpu-running-p))
+    (setq profiler-cpu-log (profiler-cpu-log)))
+  (when (profiler-memory-running-p)
+    (setq profiler-memory-log (profiler-memory-log)))
+  (if (and (not profiler-cpu-log) (not profiler-memory-log))
+      (user-error "No profiler run recorded")
+    (profiler-report-cpu)
+    (profiler-report-memory)))
 
 ;;;###autoload
 (defun profiler-find-profile (filename)
-- 
2.6.2