dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

sly-profiler.el (5482B)


      1 ;;; -*- coding: utf-8; lexical-binding: t -*-
      2 ;;;
      3 ;;; sly-profiler.el -- a navigable dialog of inspectable timing entries
      4 ;;;
      5 (eval-and-compile
      6   (require 'sly)
      7   (require 'sly-parse "lib/sly-parse"))
      8 
      9 (define-sly-contrib sly-profiler
     10   "Provide an interfactive timing dialog buffer for managing and
     11 inspecting details of timing functions. Invoke this dialog with C-c Y."
     12   (:authors "João Távora <joaotavora@gmail.com>")
     13   (:license "GPL")
     14   (:slynk-dependencies slynk/profiler)
     15   (:on-load (add-hook 'sly-mode-hook 'sly-profiler-enable))
     16   (:on-unload (remove-hook 'sly-mode-hook 'sly-profiler-enable)))
     17 
     18 
     19 ;;;; Modes and mode maps
     20 ;;;
     21 (defvar sly-profiler-mode-map
     22   (let ((map (make-sparse-keymap)))
     23     (define-key map (kbd "G") 'sly-profiler-fetch-timings)
     24     (define-key map (kbd "C-k") 'sly-profiler-clear-fetched-timings)
     25     (define-key map (kbd "g") 'sly-profiler-fetch-status)
     26     (define-key map (kbd "q") 'quit-window)
     27     map))
     28 
     29 (define-derived-mode sly-profiler-mode fundamental-mode
     30   "SLY Timing Dialog" "Mode for controlling SLY's Timing Dialog"
     31   (set-syntax-table lisp-mode-syntax-table)
     32   (read-only-mode 1))
     33 
     34 (defvar sly-profiler-shortcut-mode-map
     35   (let ((map (make-sparse-keymap)))
     36     (define-key map (kbd "C-c Y") 'sly-profiler)
     37     (define-key map (kbd "C-c C-y") 'sly-profiler-toggle-timing)
     38     map))
     39 
     40 (define-minor-mode sly-profiler-shortcut-mode
     41   "Add keybindings for accessing SLY's Profiler.")
     42 
     43 (defun sly-profiler-enable () (sly-profiler-shortcut-mode 1))
     44 
     45 
     46 ;;;; Helpers
     47 ;;;
     48 (defun sly-profiler--get-buffer ()
     49   (let* ((name (format "*profiler for %s*"
     50                        (sly-connection-name sly-default-connection)))
     51          (existing (get-buffer name)))
     52     (cond ((and existing
     53                 (buffer-live-p existing)
     54                 (with-current-buffer existing
     55                   (memq sly-buffer-connection sly-net-processes)))
     56            existing)
     57           (t
     58            (if existing (kill-buffer existing))
     59            (with-current-buffer (get-buffer-create name)
     60              (sly-profiler-mode)
     61              (setq sly-buffer-connection sly-default-connection)
     62              (pop-to-buffer (current-buffer)))))))
     63 
     64 (defun sly-profiler--clear-local-tree ()
     65   (erase-buffer)
     66   (insert "Cleared timings!"))
     67 
     68 (defun sly-profiler--render-timings (timing-specs)
     69   (let ((inhibit-read-only t))
     70     (erase-buffer)
     71     (let ((standard-output (current-buffer)))
     72       (cl-loop for spec in timing-specs
     73                do (princ spec) (terpri)))))
     74 
     75 ;;;; Interactive functions
     76 ;;;
     77 ;; (defun sly-profiler-fetch-specs ()
     78 ;;   "Refresh just list of timing specs."
     79 ;;   (interactive)
     80 ;;   (sly-eval-async `(slynk-profiler:report-specs)
     81 ;;     #'sly-profiler--open-specs))
     82 
     83 (defun sly-profiler-clear-fetched-timings (&optional interactive)
     84   "Clear local and remote timings collected so far"
     85   (interactive "p")
     86   (when (or (not interactive)
     87             (y-or-n-p "Clear all collected and fetched timings?"))
     88     (sly-eval-async
     89         '(slynk-profiler:clear-timing-tree)
     90       #'sly-profiler--clear-local-tree)))
     91 
     92 (defun sly-profiler-fetch-timings ()
     93   (interactive)
     94   (sly-eval-async `(slynk-profiler:report-latest-timings)
     95     #'sly-profiler--render-timings))
     96 
     97 (defun sly-profiler-fetch-status ()
     98   (interactive)
     99   (sly-profiler-fetch-timings))
    100 
    101 (defun sly-profiler-toggle-timing (&optional using-context-p)
    102   "Toggle the dialog-timing of the spec at point.
    103 
    104 When USING-CONTEXT-P, attempt to decipher lambdas. methods and
    105 other complicated function specs."
    106   (interactive "P")
    107   ;; Notice the use of "spec strings" here as opposed to the
    108   ;; proper cons specs we use on the slynk side.
    109   ;;
    110   ;; Notice the conditional use of `sly-trace-query' found in
    111   ;; slynk-fancy-trace.el
    112   ;;
    113   (let* ((spec-string (if using-context-p
    114                           (sly-extract-context)
    115                         (sly-symbol-at-point)))
    116          (spec-string (read-from-minibuffer "(Un)time: " (format "%s" spec-string))))
    117     (message "%s" (sly-eval `(slynk-profiler:toggle-timing
    118                                 (slynk::from-string ,spec-string))))))
    119 
    120 (defun sly-profiler (&optional refresh)
    121   "Show timing dialog and refresh timing collection status.
    122 
    123 With optional CLEAR-AND-FETCH prefix arg, clear the current tree
    124 and fetch a first batch of timings."
    125   (interactive "P")
    126   (sly-with-popup-buffer ((sly-buffer-name :profiler :connection sly-default-connection)
    127                           :mode 'sly-profiler-mode
    128                           :select t)
    129     (when refresh (sly-profiler-fetch-timings))))
    130 
    131 
    132 ;;;; Menu
    133 ;;;
    134 (easy-menu-define sly-profiler--shortcut-menu nil
    135   "Menu setting traces from anywhere in SLY."
    136   (let* ((in-dialog '(eq major-mode 'sly-profiler-mode))
    137          (_dialog-live `(and ,in-dialog
    138                              (memq sly-buffer-connection sly-net-processes)))
    139          (connected '(sly-connected-p)))
    140     `("Profiling"
    141       ["(Un)Profile definition" sly-profiler-toggle-timing ,connected]
    142       ["Open Profiler Dialog" sly-profiler (and ,connected (not ,in-dialog))])))
    143 
    144 (easy-menu-add-item sly-menu nil sly-profiler--shortcut-menu "Documentation")
    145 
    146 (defvar sly-profiler--easy-menu
    147   (let ((condition '(memq sly-buffer-connection sly-net-processes)))
    148     `("Timing"
    149       [ "Clear fetched timings" sly-profiler-clear-fetched-timings ,condition]
    150       [ "Fetch timings" sly-profiler-fetch-timings ,condition])))
    151 
    152 (easy-menu-define my-menu sly-profiler-mode-map "Timing"
    153   sly-profiler--easy-menu)
    154 
    155 (provide 'sly-profiler)