|
|
@@ -1,742 +0,0 @@ |
|
|
|
;;; symon.el --- tiny graphical system monitor |
|
|
|
|
|
|
|
;; Copyright (C) 2015 zk_phi |
|
|
|
|
|
|
|
;; This program is free software; you can redistribute it and/or modify |
|
|
|
;; it under the terms of the GNU General Public License as published by |
|
|
|
;; the Free Software Foundation; either version 2 of the License, or |
|
|
|
;; (at your option) any later version. |
|
|
|
;; |
|
|
|
;; This program is distributed in the hope that it will be useful, |
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
;; GNU General Public License for more details. |
|
|
|
;; |
|
|
|
;; You should have received a copy of the GNU General Public License |
|
|
|
;; along with this program; if not, write to the Free Software |
|
|
|
;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
|
|
|
|
|
|
;; Author: zk_phi |
|
|
|
;; URL: http://hins11.yu-yake.com/ |
|
|
|
;; Version: 1.2.0 |
|
|
|
|
|
|
|
;;; Commentary: |
|
|
|
|
|
|
|
;; Load this script |
|
|
|
;; |
|
|
|
;; (require 'symon) |
|
|
|
;; |
|
|
|
;; and turn on `symon-mode'. |
|
|
|
;; |
|
|
|
;; (symon-mode) |
|
|
|
;; |
|
|
|
;; then a tiny system monitor is displayed in minibuffer, during idle. |
|
|
|
|
|
|
|
;;; Change Log: |
|
|
|
|
|
|
|
;; 1.0.0 first release |
|
|
|
;; 1.1.0 add option symon-sparkline-thickness |
|
|
|
;; 1.1.1 add symon-windows-page-file-monitor |
|
|
|
;; 1.1.2 add darwin support (mac os x) |
|
|
|
;; 1.2.0 add paging feature |
|
|
|
|
|
|
|
;;; Code: |
|
|
|
|
|
|
|
(require 'battery) |
|
|
|
(require 'ring) |
|
|
|
|
|
|
|
(defconst symon-version "1.2.0") |
|
|
|
|
|
|
|
(defgroup symon nil |
|
|
|
"tiny graphical system monitor" |
|
|
|
:group 'emacs) |
|
|
|
|
|
|
|
;; + customs |
|
|
|
|
|
|
|
;; core |
|
|
|
|
|
|
|
(defcustom symon-refresh-rate 4 |
|
|
|
"refresh rate of symon display. *set this option BEFORE |
|
|
|
enabling `symon-mode'.*" |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-delay 2 |
|
|
|
"delay in seconds until symon is displayed. *set this option |
|
|
|
BEFORE enabling `symon-mode'.*" |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-history-size 50 |
|
|
|
"number of old values to keep. sparklines grow faster when set |
|
|
|
smaller. *set this option BEFORE enabling `symon-mode'.*" |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-monitors |
|
|
|
(cond ((memq system-type '(gnu/linux cygwin)) |
|
|
|
'(symon-linux-memory-monitor |
|
|
|
symon-linux-cpu-monitor |
|
|
|
symon-linux-network-rx-monitor |
|
|
|
symon-linux-network-tx-monitor |
|
|
|
symon-linux-battery-monitor)) |
|
|
|
((memq system-type '(darwin)) |
|
|
|
'(symon-darwin-memory-monitor |
|
|
|
symon-darwin-cpu-monitor |
|
|
|
symon-darwin-network-rx-monitor |
|
|
|
symon-darwin-network-tx-monitor)) |
|
|
|
((memq system-type '(windows-nt)) |
|
|
|
'(symon-windows-memory-monitor |
|
|
|
symon-windows-cpu-monitor |
|
|
|
symon-windows-network-rx-monitor |
|
|
|
symon-windows-network-tx-monitor))) |
|
|
|
"List of monitors used to read system statuses. This variable |
|
|
|
also can be a list of lists from version 1.2, that case |
|
|
|
monitors are displayed in multiple pages. *set this option |
|
|
|
BEFORE enabling `symon-mode'.*") |
|
|
|
|
|
|
|
;; sparkline |
|
|
|
|
|
|
|
(defcustom symon-sparkline-height 11 |
|
|
|
"height of sparklines." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-sparkline-width 80 |
|
|
|
"width of sparklines." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-sparkline-ascent 100 |
|
|
|
"`:ascent' property for sparklines." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-sparkline-thickness 2 |
|
|
|
"line width of sparklines." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-sparkline-type 'gridded |
|
|
|
"type of sparklines." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
;; some darwin builds cannot render xbm images (foreground color is |
|
|
|
;; always black), so convert to xpm before rendering. |
|
|
|
(defcustom symon-sparkline-use-xpm (eq system-type 'darwin) |
|
|
|
"when non-nil, convert sparklines to xpm from xbm before |
|
|
|
rendering." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
;; network monitor |
|
|
|
|
|
|
|
(defcustom symon-network-rx-upper-bound 300 |
|
|
|
"upper-bound of sparkline for network RX status." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-network-tx-upper-bound 100 |
|
|
|
"upper-bound of sparkline for network TX status." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-network-rx-lower-bound 0 |
|
|
|
"lower-bound of sparkline for network RX status." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
(defcustom symon-network-tx-lower-bound 0 |
|
|
|
"lower-bound of sparkline for network TX status." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
;; page-file monitor |
|
|
|
|
|
|
|
(defcustom symon-windows-page-file-upper-bound 2000 |
|
|
|
"upper-bound of sparkline for page file usage." |
|
|
|
:group 'symon) |
|
|
|
|
|
|
|
;; + utilities |
|
|
|
;; + general |
|
|
|
|
|
|
|
(defun symon--flatten (lst) |
|
|
|
"flatten LST" |
|
|
|
(if (consp lst) |
|
|
|
(apply 'nconc (mapcar 'symon--flatten lst)) |
|
|
|
(list lst))) |
|
|
|
|
|
|
|
;; + sparkline generator |
|
|
|
|
|
|
|
;; sparkline-types are internally a symbol with property |
|
|
|
;; 'symon-sparkline-type associated to a function that generates a |
|
|
|
;; 2d-bool-vector. |
|
|
|
|
|
|
|
(defvar symon--sparkline-base-cache |
|
|
|
[nil symon-sparkline-width symon-sparkline-height nil]) |
|
|
|
(defun symon--get-sparkline-base () |
|
|
|
(unless (and (eq (aref symon--sparkline-base-cache 0) symon-sparkline-type) |
|
|
|
(= (aref symon--sparkline-base-cache 1) symon-sparkline-width) |
|
|
|
(= (aref symon--sparkline-base-cache 2) symon-sparkline-height)) |
|
|
|
(aset symon--sparkline-base-cache 0 symon-sparkline-type) |
|
|
|
(aset symon--sparkline-base-cache 1 symon-sparkline-width) |
|
|
|
(aset symon--sparkline-base-cache 2 symon-sparkline-height) |
|
|
|
(aset symon--sparkline-base-cache 3 |
|
|
|
(funcall (get symon-sparkline-type 'symon-sparkline-type)))) |
|
|
|
(copy-sequence (aref symon--sparkline-base-cache 3))) |
|
|
|
|
|
|
|
(defun symon--make-sparkline (list &optional minimum maximum) |
|
|
|
"make sparkline image from LIST." |
|
|
|
(let ((num-samples (length list))) |
|
|
|
(unless (zerop num-samples) |
|
|
|
(let* ((image-data (symon--get-sparkline-base)) |
|
|
|
(maximum (if maximum (float maximum) 100.0)) |
|
|
|
(minimum (if minimum (float minimum) 0.0)) |
|
|
|
(topmargin (1- symon-sparkline-thickness)) |
|
|
|
(height (- symon-sparkline-height topmargin)) |
|
|
|
(height-per-point (/ height (1+ (- maximum minimum)))) |
|
|
|
(width-per-sample (/ symon-sparkline-width (float num-samples))) |
|
|
|
(samples (apply 'vector list)) |
|
|
|
sample y ix) |
|
|
|
(dotimes (x symon-sparkline-width) |
|
|
|
(setq sample (aref samples (floor (/ x width-per-sample)))) |
|
|
|
(when (numberp sample) |
|
|
|
(setq y (floor (* (- sample minimum) height-per-point))) |
|
|
|
(when (and (<= 0 y) (< y height)) |
|
|
|
(dotimes (dy symon-sparkline-thickness) |
|
|
|
(aset image-data |
|
|
|
(+ (* (- symon-sparkline-height (+ y dy) 1) symon-sparkline-width) x) |
|
|
|
t))))) |
|
|
|
`(image :type xbm :data ,image-data :ascent ,symon-sparkline-ascent |
|
|
|
:height ,symon-sparkline-height :width ,symon-sparkline-width))))) |
|
|
|
|
|
|
|
(defun symon--convert-sparkline-to-xpm (sparkline) |
|
|
|
"convert sparkline to an xpm image." |
|
|
|
(let ((data (plist-get (cdr sparkline) :data))) |
|
|
|
(with-temp-buffer |
|
|
|
(insert (format "/* XPM */ |
|
|
|
static char * sparkline_xpm[] = { \"%d %d 2 1\", \"@ c %s\", \". c none\"" |
|
|
|
symon-sparkline-width symon-sparkline-height |
|
|
|
(face-foreground 'default))) |
|
|
|
(let ((ix 0)) |
|
|
|
(dotimes (x symon-sparkline-height) |
|
|
|
(insert ",\n\"") |
|
|
|
(dotimes (y symon-sparkline-width) |
|
|
|
(insert (if (aref data ix) ?@ ?.)) |
|
|
|
(setq ix (1+ ix))) |
|
|
|
(insert "\""))) |
|
|
|
(insert "};") |
|
|
|
`(image :type xpm :data ,(buffer-string) :ascent ,symon-sparkline-ascent |
|
|
|
:height ,symon-sparkline-height :width ,symon-sparkline-width)))) |
|
|
|
|
|
|
|
;; + symon monitor generator |
|
|
|
|
|
|
|
;; a symon monitor is internally a symbol with property 'symon-monitor |
|
|
|
;; associated to a vector of 3 functions: [SETUP-FN CLEANUP-FN |
|
|
|
;; DISPLAY-FN]. SETUP-FN is called on activation of `symon-mode', and |
|
|
|
;; expected to setup Emacs to fetch status values in a specific |
|
|
|
;; interval. CLEANUP-FN is called on deactivation and expected to tell |
|
|
|
;; Emacs to stop fetching. DISPLAY-FN is called just before displaying |
|
|
|
;; monitor, and must return display string for the monitor. |
|
|
|
|
|
|
|
(defun symon--make-history-ring () |
|
|
|
"like `(make-ring symon-history-size)' but filled with `nil'." |
|
|
|
(cons 0 (cons symon-history-size (make-vector symon-history-size nil)))) |
|
|
|
|
|
|
|
(defmacro define-symon-monitor (name &rest plist) |
|
|
|
"define a new symon monitor NAME. following keywords are |
|
|
|
supoprted in PLIST: |
|
|
|
|
|
|
|
:setup (default: nil) |
|
|
|
|
|
|
|
an expression evaluated when activating symon-mode, and |
|
|
|
expected to do some preparation. |
|
|
|
|
|
|
|
:cleanup (default: nil) |
|
|
|
|
|
|
|
an expression evaluated when deactivating symon-mode, and |
|
|
|
expected to do some cleanup. |
|
|
|
|
|
|
|
:fetch (default: nil) |
|
|
|
|
|
|
|
an expression that evaluates to the latest status value. the |
|
|
|
value must be a number (otherwise `N/A' is displayed as the |
|
|
|
value). |
|
|
|
|
|
|
|
:interval (default: symon-refresh-rate) |
|
|
|
|
|
|
|
fetch interval in seconds. |
|
|
|
|
|
|
|
:index (default: \"\") |
|
|
|
|
|
|
|
string prepended to the status value (\"MEM:\" for memory |
|
|
|
monitor, for example). |
|
|
|
|
|
|
|
:unit (default: \"\") |
|
|
|
|
|
|
|
string appended to the status value (\"%\" for memory |
|
|
|
monitor, for example). |
|
|
|
|
|
|
|
:annotation (default: nil) |
|
|
|
|
|
|
|
an expression that evaluates to the annotation string for the |
|
|
|
metrics (\"xxxKB Swapped\" for memory monitor, for |
|
|
|
example). if this expression returns a non-nil value, it is |
|
|
|
surrounded with parentheses and appended to the status value. |
|
|
|
|
|
|
|
:display (default: nil) |
|
|
|
|
|
|
|
an expression evaluated before updating symon display. when |
|
|
|
this expression evaluates to a non-nil value, it will be |
|
|
|
displayed instead of standard symon display format. |
|
|
|
|
|
|
|
:sparkline (default: nil) |
|
|
|
|
|
|
|
when non-nil, sparklines are rendered. |
|
|
|
|
|
|
|
:lower-bound (default: 100.0) |
|
|
|
|
|
|
|
upper bound of sparkline. |
|
|
|
|
|
|
|
:upper-bound (default: 0.0) |
|
|
|
|
|
|
|
lower bound of sparkline." |
|
|
|
(let* ((cell (make-vector 2 nil)) |
|
|
|
(sparkline (plist-get plist :sparkline)) |
|
|
|
(interval (or (plist-get plist :interval) 'symon-refresh-rate)) |
|
|
|
(display (plist-get plist :display)) |
|
|
|
(update-fn |
|
|
|
`(lambda () |
|
|
|
(ring-insert (aref ,cell 0) ,(plist-get plist :fetch)))) |
|
|
|
(setup-fn |
|
|
|
`(lambda () |
|
|
|
(aset ,cell 0 (symon--make-history-ring)) |
|
|
|
(aset ,cell 1 (run-with-timer 0 ,interval ,update-fn)) |
|
|
|
,(plist-get plist :setup) |
|
|
|
(funcall ,update-fn))) |
|
|
|
(cleanup-fn |
|
|
|
`(lambda () |
|
|
|
(cancel-timer (aref ,cell 1)) |
|
|
|
,(plist-get plist :cleanup))) |
|
|
|
(display-fn |
|
|
|
(if display `(lambda () (concat ,display " ")) |
|
|
|
`(lambda () |
|
|
|
(let* ((lst (ring-elements (aref ,cell 0))) |
|
|
|
(val (car lst))) |
|
|
|
(concat ,(plist-get plist :index) |
|
|
|
(if (not (numberp val)) "N/A " |
|
|
|
(concat (format "%d%s " val ,(or (plist-get plist :unit) "")) |
|
|
|
(let ((annot ,(plist-get plist :annotation))) |
|
|
|
(when annot (concat "(" annot ") "))))) |
|
|
|
,(when sparkline |
|
|
|
`(when (window-system) |
|
|
|
(let ((sparkline (symon--make-sparkline |
|
|
|
lst |
|
|
|
,(plist-get plist :lower-bound) |
|
|
|
,(plist-get plist :upper-bound)))) |
|
|
|
(when symon-sparkline-use-xpm |
|
|
|
(setq sparkline |
|
|
|
(symon--convert-sparkline-to-xpm sparkline))) |
|
|
|
(concat (propertize " " 'display sparkline) " ")))))))))) |
|
|
|
`(put ',name 'symon-monitor (vector ,setup-fn ,cleanup-fn ,display-fn)))) |
|
|
|
|
|
|
|
;; + process management |
|
|
|
|
|
|
|
(defvar symon--process-buffer-name " *symon-process*") |
|
|
|
(defvar symon--process-reference-count 0) |
|
|
|
|
|
|
|
(defun symon--read-value-from-process-buffer (index) |
|
|
|
"Read a value from a specific buffer" |
|
|
|
(when (get-buffer symon--process-buffer-name) |
|
|
|
(with-current-buffer symon--process-buffer-name |
|
|
|
(when (save-excursion |
|
|
|
(search-backward-regexp (concat index ":\\([0-9]+\\)\\>") nil t)) |
|
|
|
(read (match-string 1)))))) |
|
|
|
|
|
|
|
(defun symon--maybe-start-process (cmd) |
|
|
|
(setq symon--process-reference-count |
|
|
|
(1+ symon--process-reference-count)) |
|
|
|
(unless (get-buffer symon--process-buffer-name) |
|
|
|
(let ((proc (start-process-shell-command |
|
|
|
"symon-process" symon--process-buffer-name cmd)) |
|
|
|
(filter (lambda (proc str) |
|
|
|
(when (get-buffer symon--process-buffer-name) |
|
|
|
(with-current-buffer symon--process-buffer-name |
|
|
|
(when (and (string-match "-" str) (search-backward "----" nil t)) |
|
|
|
(delete-region 1 (point))) |
|
|
|
(goto-char (1+ (buffer-size))) |
|
|
|
(insert str)))))) |
|
|
|
(set-process-query-on-exit-flag proc nil) |
|
|
|
(set-process-filter proc filter)))) |
|
|
|
|
|
|
|
(defun symon--maybe-kill-process () |
|
|
|
(setq symon--process-reference-count |
|
|
|
(1- symon--process-reference-count)) |
|
|
|
(when (and (zerop symon--process-reference-count) |
|
|
|
(get-buffer symon--process-buffer-name)) |
|
|
|
(kill-buffer symon--process-buffer-name))) |
|
|
|
|
|
|
|
;; + predefined monitors |
|
|
|
;; + linux monitors |
|
|
|
|
|
|
|
(defun symon-linux--read-lines (file reader indices) |
|
|
|
(with-temp-buffer |
|
|
|
(insert-file-contents file) |
|
|
|
(goto-char 1) |
|
|
|
(mapcar (lambda (index) |
|
|
|
(save-excursion |
|
|
|
(when (search-forward-regexp (concat "^" index "\\(.*\\)$") nil t) |
|
|
|
(if reader |
|
|
|
(funcall reader (match-string 1)) |
|
|
|
(match-string 1))))) |
|
|
|
indices))) |
|
|
|
|
|
|
|
(defvar symon-linux--last-cpu-ticks nil) |
|
|
|
|
|
|
|
(define-symon-monitor symon-linux-cpu-monitor |
|
|
|
:index "CPU:" :unit "%" :sparkline t |
|
|
|
:setup (setq symon-linux--last-cpu-ticks nil) |
|
|
|
:fetch (cl-destructuring-bind (cpu) |
|
|
|
(symon-linux--read-lines |
|
|
|
"/proc/stat" (lambda (str) (mapcar 'read (split-string str nil t))) '("cpu")) |
|
|
|
(let ((total (apply '+ cpu)) (idle (nth 3 cpu))) |
|
|
|
(prog1 (when symon-linux--last-cpu-ticks |
|
|
|
(let ((total-diff (- total (car symon-linux--last-cpu-ticks))) |
|
|
|
(idle-diff (- idle (cdr symon-linux--last-cpu-ticks)))) |
|
|
|
(/ (* (- total-diff idle-diff) 100) total-diff))) |
|
|
|
(setq symon-linux--last-cpu-ticks (cons total idle)))))) |
|
|
|
|
|
|
|
(define-symon-monitor symon-linux-memory-monitor |
|
|
|
:index "MEM:" :unit "%" :sparkline t |
|
|
|
:fetch (cl-destructuring-bind (memtotal memavailable memfree buffers cached) |
|
|
|
(symon-linux--read-lines |
|
|
|
"/proc/meminfo" (lambda (str) (and str (read str))) |
|
|
|
'("MemTotal:" "MemAvailable:" "MemFree:" "Buffers:" "Cached:")) |
|
|
|
(if memavailable |
|
|
|
(/ (* (- memtotal memavailable) 100) memtotal) |
|
|
|
(/ (* (- memtotal (+ memfree buffers cached)) 100) memtotal))) |
|
|
|
:annotation (cl-destructuring-bind (swaptotal swapfree) |
|
|
|
(symon-linux--read-lines |
|
|
|
"/proc/meminfo" 'read '("SwapTotal:" "SwapFree:")) |
|
|
|
(let ((swapped (/ (- swaptotal swapfree) 1000))) |
|
|
|
(unless (zerop swapped) (format "%dMB Swapped" swapped))))) |
|
|
|
|
|
|
|
(define-symon-monitor symon-linux-battery-monitor |
|
|
|
:index "BAT:" :unit "%" :sparkline t |
|
|
|
:fetch (when battery-status-function |
|
|
|
(read (cdr (assoc ?p (funcall battery-status-function)))))) |
|
|
|
|
|
|
|
(defvar symon-linux--last-network-rx nil) |
|
|
|
|
|
|
|
(define-symon-monitor symon-linux-network-rx-monitor |
|
|
|
:index "RX:" :unit "KB/s" :sparkline t |
|
|
|
:upper-bound symon-network-rx-upper-bound |
|
|
|
:lower-bound symon-network-rx-lower-bound |
|
|
|
:setup (setq symon-linux--last-network-rx nil) |
|
|
|
:fetch (with-temp-buffer |
|
|
|
(insert-file-contents "/proc/net/dev") |
|
|
|
(goto-char 1) |
|
|
|
(let ((rx 0)) |
|
|
|
(while (search-forward-regexp "^[\s\t]*\\(.*\\):" nil t) |
|
|
|
(unless (string= (match-string 1) "lo") |
|
|
|
(setq rx (+ rx (read (current-buffer)))))) |
|
|
|
(prog1 (when symon-linux--last-network-rx |
|
|
|
(/ (- rx symon-linux--last-network-rx) symon-refresh-rate 1000)) |
|
|
|
(setq symon-linux--last-network-rx rx))))) |
|
|
|
|
|
|
|
(defvar symon-linux--last-network-tx nil) |
|
|
|
|
|
|
|
(define-symon-monitor symon-linux-network-tx-monitor |
|
|
|
:index "TX:" :unit "KB/s" :sparkline t |
|
|
|
:upper-bound symon-network-tx-upper-bound |
|
|
|
:lower-bound symon-network-tx-lower-bound |
|
|
|
:setup (setq symon-linux--last-network-tx nil) |
|
|
|
:fetch (with-temp-buffer |
|
|
|
(insert-file-contents "/proc/net/dev") |
|
|
|
(goto-char 1) |
|
|
|
(let ((tx 0)) |
|
|
|
(while (search-forward-regexp "^[\s\t]*\\(.*\\):" nil t) |
|
|
|
(unless (string= (match-string 1) "lo") |
|
|
|
(forward-word 8) |
|
|
|
(setq tx (+ tx (read (current-buffer)))))) |
|
|
|
(prog1 (when symon-linux--last-network-tx |
|
|
|
(/ (- tx symon-linux--last-network-tx) symon-refresh-rate 1000)) |
|
|
|
(setq symon-linux--last-network-tx tx))))) |
|
|
|
|
|
|
|
;; + darwin monitors |
|
|
|
|
|
|
|
(defun symon-darwin--maybe-start-process () |
|
|
|
(symon--maybe-start-process (format " |
|
|
|
while true; do |
|
|
|
echo \"----\" |
|
|
|
|
|
|
|
interface=`route get 0.0.0.0 | grep interface | awk '{print $2}'` |
|
|
|
s=`netstat -bi -I $interface | tail -1`; |
|
|
|
echo $s | awk '{print \"rx:\"$7}' |
|
|
|
echo $s | awk '{print \"tx:\"$8}' |
|
|
|
|
|
|
|
s=`hostinfo | grep 'Load average' | awk '{print \"cpu:\"$3}' | sed 's/,//'` |
|
|
|
echo $s |
|
|
|
|
|
|
|
m1=`sysctl hw.memsize | sed 's/.*:\s*//'` |
|
|
|
m_active=`vm_stat | grep 'Pages active' | sed 's/.*: *//'` |
|
|
|
m_wired=`vm_stat | grep 'Pages wired' | sed 's/.*: *//'` |
|
|
|
|
|
|
|
s=`echo \"scale=2; (($m_active+$m_wired)*4096*100 / $m1)\"| bc -l` |
|
|
|
echo \"mem:$s\" |
|
|
|
|
|
|
|
sleep %d |
|
|
|
done" symon-refresh-rate))) |
|
|
|
|
|
|
|
(define-symon-monitor symon-darwin-cpu-monitor |
|
|
|
:index "CPU:" :unit "%" :sparkline t |
|
|
|
:setup (symon-darwin--maybe-start-process) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (symon--read-value-from-process-buffer "cpu")) |
|
|
|
|
|
|
|
(define-symon-monitor symon-darwin-memory-monitor |
|
|
|
:index "MEM:" :unit "%" :sparkline t |
|
|
|
:setup (symon-darwin--maybe-start-process) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (symon--read-value-from-process-buffer "mem")) |
|
|
|
|
|
|
|
(defvar symon-darwin--last-network-rx nil) |
|
|
|
|
|
|
|
(define-symon-monitor symon-darwin-network-rx-monitor |
|
|
|
:index "RX:" :unit "KB/s" :sparkline t |
|
|
|
:upper-bound symon-network-rx-upper-bound |
|
|
|
:lower-bound symon-network-rx-lower-bound |
|
|
|
:setup (progn |
|
|
|
(symon-darwin--maybe-start-process) |
|
|
|
(setq symon-darwin--last-network-rx nil)) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (let ((rx (symon--read-value-from-process-buffer "rx"))) |
|
|
|
(prog1 (when symon-darwin--last-network-rx |
|
|
|
(/ (- rx symon-darwin--last-network-rx) symon-refresh-rate 1000)) |
|
|
|
(setq symon-darwin--last-network-rx rx)))) |
|
|
|
|
|
|
|
(defvar symon-darwin--last-network-tx nil) |
|
|
|
|
|
|
|
(define-symon-monitor symon-darwin-network-tx-monitor |
|
|
|
:index "TX:" :unit "KB/s" :sparkline t |
|
|
|
:upper-bound symon-network-tx-upper-bound |
|
|
|
:lower-bound symon-network-tx-lower-bound |
|
|
|
:setup (progn |
|
|
|
(symon-darwin--maybe-start-process) |
|
|
|
(setq symon-darwin--last-network-tx nil)) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (let ((tx (symon--read-value-from-process-buffer "tx"))) |
|
|
|
(prog1 (when symon-darwin--last-network-tx |
|
|
|
(/ (- tx symon-darwin--last-network-tx) symon-refresh-rate 1000)) |
|
|
|
(setq symon-darwin--last-network-tx tx)))) |
|
|
|
|
|
|
|
(define-symon-monitor symon-darwin-battery-monitor |
|
|
|
:index "BAT:" :unit "%" :sparkline t |
|
|
|
:fetch (when battery-status-function |
|
|
|
(read (cdr (assoc ?p (funcall battery-status-function)))))) |
|
|
|
|
|
|
|
;; + windows monitors |
|
|
|
|
|
|
|
(defun symon-windows--maybe-start-wmi-process () |
|
|
|
(symon--maybe-start-process (format "powershell -command \ |
|
|
|
$last = 0; \ |
|
|
|
while(1) \ |
|
|
|
{ \ |
|
|
|
echo ----; \ |
|
|
|
\ |
|
|
|
$t = (gwmi Win32_ComputerSystem).TotalPhysicalMemory / 1000; \ |
|
|
|
$f = (gwmi Win32_OperatingSystem).FreePhysicalMemory; \ |
|
|
|
echo mem:$(($t - $f) * 100 / $t); \ |
|
|
|
\ |
|
|
|
echo swap:$((gwmi Win32_PageFileUsage).CurrentUsage); \ |
|
|
|
\ |
|
|
|
echo bat:$((gwmi Win32_Battery).EstimatedChargeRemaining); \ |
|
|
|
\ |
|
|
|
$r = 0; \ |
|
|
|
$t = 0; \ |
|
|
|
$w = gwmi Win32_PerfRawData_Tcpip_NetworkInterface; \ |
|
|
|
foreach($x in $w){ \ |
|
|
|
$r = $r + $x.BytesReceivedPersec; \ |
|
|
|
$t = $t + $x.BytesSentPersec \ |
|
|
|
} \ |
|
|
|
echo rx:$($r / 1000); \ |
|
|
|
echo tx:$($t / 1000); \ |
|
|
|
\ |
|
|
|
$p = (gwmi Win32_PerfRawData_Counters_ProcessorInformation)[0]; \ |
|
|
|
if($last) \ |
|
|
|
{ \ |
|
|
|
$dt = $p.Timestamp_Sys100NS - $last.Timestamp_Sys100NS; \ |
|
|
|
$dp = $p.PercentProcessorTime - $last.PercentProcessorTime; \ |
|
|
|
echo cpu:$((1 - ($dp / $dt)) * 100); \ |
|
|
|
} \ |
|
|
|
$last = $p; \ |
|
|
|
\ |
|
|
|
sleep %d \ |
|
|
|
}" symon-refresh-rate))) |
|
|
|
|
|
|
|
(define-symon-monitor symon-windows-cpu-monitor |
|
|
|
:index "CPU:" :unit "%" :sparkline t |
|
|
|
:setup (symon-windows--maybe-start-wmi-process) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (symon--read-value-from-process-buffer "cpu")) |
|
|
|
|
|
|
|
(define-symon-monitor symon-windows-memory-monitor |
|
|
|
:index "MEM:" :unit "%" :sparkline t |
|
|
|
:setup (symon-windows--maybe-start-wmi-process) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (symon--read-value-from-process-buffer "mem")) |
|
|
|
|
|
|
|
(define-symon-monitor symon-windows-page-file-monitor |
|
|
|
:index "PF:" :unit "MB" :sparkline t |
|
|
|
:upper-bound symon-windows-page-file-upper-bound |
|
|
|
:setup (symon-windows--maybe-start-wmi-process) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (symon--read-value-from-process-buffer "swap")) |
|
|
|
|
|
|
|
(define-symon-monitor symon-windows-battery-monitor |
|
|
|
:index "BAT:" :unit "%" :sparkline t |
|
|
|
:setup (symon-windows--maybe-start-wmi-process) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (symon--read-value-from-process-buffer "bat")) |
|
|
|
|
|
|
|
(defvar symon-windows--last-network-rx nil) |
|
|
|
|
|
|
|
(define-symon-monitor symon-windows-network-rx-monitor |
|
|
|
:index "RX:" :unit "KB/s" :sparkline t |
|
|
|
:upper-bound symon-network-rx-upper-bound |
|
|
|
:lower-bound symon-network-rx-lower-bound |
|
|
|
:setup (progn |
|
|
|
(symon-windows--maybe-start-wmi-process) |
|
|
|
(setq symon-windows--last-network-rx nil)) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (let ((rx (symon--read-value-from-process-buffer "rx"))) |
|
|
|
(prog1 (when symon-windows--last-network-rx |
|
|
|
(/ (- rx symon-windows--last-network-rx) symon-refresh-rate)) |
|
|
|
(setq symon-windows--last-network-rx rx)))) |
|
|
|
|
|
|
|
(defvar symon-windows--last-network-tx nil) |
|
|
|
|
|
|
|
(define-symon-monitor symon-windows-network-tx-monitor |
|
|
|
:index "TX:" :unit "KB/s" :sparkline t |
|
|
|
:upper-bound symon-network-tx-upper-bound |
|
|
|
:lower-bound symon-network-tx-lower-bound |
|
|
|
:setup (progn |
|
|
|
(symon-windows--maybe-start-wmi-process) |
|
|
|
(setq symon-windows--last-network-tx nil)) |
|
|
|
:cleanup (symon--maybe-kill-process) |
|
|
|
:fetch (let ((tx (symon--read-value-from-process-buffer "tx"))) |
|
|
|
(prog1 (when symon-windows--last-network-tx |
|
|
|
(/ (- tx symon-windows--last-network-tx) symon-refresh-rate)) |
|
|
|
(setq symon-windows--last-network-tx tx)))) |
|
|
|
|
|
|
|
;; + misc monitors |
|
|
|
|
|
|
|
(define-symon-monitor symon-current-time-monitor |
|
|
|
:display (format-time-string "%H:%M")) |
|
|
|
|
|
|
|
;; + predefined sparkline types |
|
|
|
|
|
|
|
(defun symon--sparkline-draw-horizontal-grid (vec y) |
|
|
|
(dotimes (x/2 (/ symon-sparkline-width 2)) |
|
|
|
(aset vec (+ (* y symon-sparkline-width) (* x/2 2)) t))) |
|
|
|
|
|
|
|
(defun symon--sparkline-draw-vertical-grid (vec x) |
|
|
|
(dotimes (y/2 (/ symon-sparkline-height 2)) |
|
|
|
(aset vec (+ (* (* y/2 2) symon-sparkline-width) x) t))) |
|
|
|
|
|
|
|
(defun symon--make-plain-sparkline () |
|
|
|
(make-bool-vector (* symon-sparkline-height symon-sparkline-width) nil)) |
|
|
|
|
|
|
|
(defun symon--make-bounded-sparkline () |
|
|
|
(let ((vec (symon--make-plain-sparkline))) |
|
|
|
(symon--sparkline-draw-horizontal-grid vec 0) |
|
|
|
(symon--sparkline-draw-horizontal-grid vec (1- symon-sparkline-height)) |
|
|
|
vec)) |
|
|
|
|
|
|
|
(defun symon--make-boxed-sparkline () |
|
|
|
(let ((vec (symon--make-bounded-sparkline))) |
|
|
|
(symon--sparkline-draw-vertical-grid vec 0) |
|
|
|
(symon--sparkline-draw-vertical-grid vec (1- symon-sparkline-width)) |
|
|
|
vec)) |
|
|
|
|
|
|
|
(defun symon--make-gridded-sparkline () |
|
|
|
(let ((vec (symon--make-boxed-sparkline))) |
|
|
|
(symon--sparkline-draw-horizontal-grid vec (/ symon-sparkline-height 2)) |
|
|
|
(symon--sparkline-draw-vertical-grid vec (/ symon-sparkline-width 4)) |
|
|
|
(symon--sparkline-draw-vertical-grid vec (/ symon-sparkline-width 2)) |
|
|
|
(symon--sparkline-draw-vertical-grid vec (/ (* symon-sparkline-width 3) 4)) |
|
|
|
vec)) |
|
|
|
|
|
|
|
(put 'plain 'symon-sparkline-type 'symon--make-plain-sparkline) |
|
|
|
(put 'bounded 'symon-sparkline-type 'symon--make-bounded-sparkline) |
|
|
|
(put 'boxed 'symon-sparkline-type 'symon--make-boxed-sparkline) |
|
|
|
(put 'gridded 'symon-sparkline-type 'symon--make-gridded-sparkline) |
|
|
|
|
|
|
|
;; + symon core |
|
|
|
|
|
|
|
(defvar symon--cleanup-fns nil) ; List[Fn] |
|
|
|
(defvar symon--display-fns nil) ; List[List[Fn]] |
|
|
|
(defvar symon--display-active nil) |
|
|
|
(defvar symon--active-page nil) |
|
|
|
(defvar symon--total-page-num nil) |
|
|
|
(defvar symon--timer-objects nil) |
|
|
|
|
|
|
|
(defun symon--initialize () |
|
|
|
(unless symon-monitors |
|
|
|
(message "Warning: `symon-monitors' is empty.")) |
|
|
|
(let* ((symon-monitors ; for backward-compatibility |
|
|
|
(if (symbolp (car symon-monitors)) |
|
|
|
(list symon-monitors) |
|
|
|
symon-monitors)) |
|
|
|
(monitors |
|
|
|
(mapcar (lambda (lst) |
|
|
|
(mapcar (lambda (s) (get s 'symon-monitor)) lst)) |
|
|
|
symon-monitors)) |
|
|
|
(monitors-flattened |
|
|
|
(symon--flatten monitors))) |
|
|
|
(mapc (lambda (m) (funcall (aref m 0))) monitors-flattened) ; setup-fns |
|
|
|
(setq symon--cleanup-fns (mapcar (lambda (m) (aref m 1)) monitors-flattened) |
|
|
|
symon--display-fns (mapcar (lambda (l) (mapcar (lambda (m) (aref m 2)) l)) monitors) |
|
|
|
symon--display-active nil |
|
|
|
symon--total-page-num (length symon-monitors) |
|
|
|
symon--timer-objects |
|
|
|
(list (run-with-timer 0 symon-refresh-rate 'symon--redisplay) |
|
|
|
(run-with-idle-timer symon-delay t 'symon-display))) |
|
|
|
(add-hook 'pre-command-hook 'symon--display-end) |
|
|
|
(add-hook 'kill-emacs-hook 'symon--cleanup))) |
|
|
|
|
|
|
|
(defun symon--cleanup () |
|
|
|
(remove-hook 'kill-emacs-hook 'symon--cleanup) |
|
|
|
(remove-hook 'pre-command-hook 'symon--display-end) |
|
|
|
(mapc 'cancel-timer symon--timer-objects) |
|
|
|
(mapc 'funcall symon--cleanup-fns)) |
|
|
|
|
|
|
|
(defun symon--display-update () |
|
|
|
"update symon display" |
|
|
|
(unless (or cursor-in-echo-area (active-minibuffer-window)) |
|
|
|
(let ((message-log-max nil) ; do not insert to *Messages* buffer |
|
|
|
(display-string nil) |
|
|
|
(page 0)) |
|
|
|
(dolist (lst symon--display-fns) |
|
|
|
(if (= page symon--active-page) |
|
|
|
(message "%s" (apply 'concat (mapcar 'funcall lst))) |
|
|
|
(mapc 'funcall lst)) |
|
|
|
(setq page (1+ page)))) |
|
|
|
(setq symon--display-active t))) |
|
|
|
|
|
|
|
(defun symon-display () |
|
|
|
"activate symon display." |
|
|
|
(interactive) |
|
|
|
(setq symon--active-page 0) |
|
|
|
(symon--display-update)) |
|
|
|
|
|
|
|
(defun symon--redisplay () |
|
|
|
"update symon display." |
|
|
|
(when symon--display-active |
|
|
|
(setq symon--active-page (% (1+ symon--active-page) symon--total-page-num)) |
|
|
|
(symon--display-update))) |
|
|
|
|
|
|
|
(defun symon--display-end () |
|
|
|
"deactivate symon display." |
|
|
|
(setq symon--display-active nil)) |
|
|
|
|
|
|
|
;;;###autoload |
|
|
|
(define-minor-mode symon-mode |
|
|
|
"tiny graphical system monitor" |
|
|
|
:init-value nil |
|
|
|
:global t |
|
|
|
(if symon-mode (symon--initialize) (symon--cleanup))) |
|
|
|
|
|
|
|
;; + provide |
|
|
|
|
|
|
|
(provide 'symon) |
|
|
|
|
|
|
|
;;; symon.el ends here |