Last active
December 27, 2024 23:38
-
-
Save chaitanyagupta/671e3880dc24a2763d1653a9c1ea6b0f to your computer and use it in GitHub Desktop.
Memory usage in a Lisp image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;;; mem-usage.lisp | |
;;; MEM-USAGE returns memory used by Lisp image in a plist. | |
;;; MEM-USED prints memory allocated while running the given forms. | |
;;; Works on SBCL, CMUCL, CCL and CLISP. | |
;;; Relies on internal APIs (the ones that ROOM uses). Can break at any time. | |
(defpackage #:mem-usage | |
(:use #:cl) | |
(:export #:mem-usage #:mem-used)) | |
(in-package #:mem-usage) | |
(defun mem-usage () | |
"Memory used (in bytes) by various memory spaces in a Lisp image. Returns a plist." | |
#+sbcl (list :dynamic (sb-vm::dynamic-usage) | |
:static (sb-kernel::static-space-usage) | |
:immobile (sb-kernel::immobile-space-usage)) | |
#+cmu (list :dynamic (lisp::dynamic-usage) | |
:static (lisp::static-space-usage)) | |
#+ccl (multiple-value-bind (usedbytes static-used staticlib-used frozen-space-size) | |
(ccl::%usedbytes) | |
(list :dynamic usedbytes | |
:static (+ static-used staticlib-used frozen-space-size))) | |
#+clisp (multiple-value-bind (used room static) | |
(sys::%room) | |
(declare (ignore room)) | |
(list :dynamic used | |
:static static))) | |
(defun print-usage (usage stream) | |
"Prints memory usage plist returned by MEM-USAGE in a human-readable format." | |
(format stream "~&~{~{~50<~:(~A~) space usage is:~;~:D bytes.~%~>~}~}" | |
`((:dynamic ,(getf usage :dynamic 0)) | |
(:static ,(getf usage :static 0)) | |
(:immobile ,(getf usage :immobile 0)))) | |
usage) | |
(defun mem-difference (x y) | |
"Difference between two mem-usage records" | |
(loop | |
:for metric in '(:dynamic :static :immobile) | |
:for x-value = (getf x metric) | |
:when x-value | |
:nconc (list metric (- x-value (getf y metric))))) | |
;; Copied from TRIVIAL-GARBAGE | |
(defun run-gc (&key full verbose) | |
"Initiates a garbage collection. @code{full} forces the collection | |
of all generations, when applicable. When @code{verbose} is | |
@em{true}, diagnostic information about the collection is printed | |
if possible." | |
(declare (ignorable verbose full)) | |
#+(or cmu scl) (ext:gc :verbose verbose :full full) | |
#+sbcl (sb-ext:gc :full full) | |
#+allegro (excl:gc (not (null full))) | |
#+(or abcl clisp) (ext:gc) | |
#+ecl (si:gc t) | |
#+openmcl (ccl:gc) | |
#+corman (ccl:gc (if full 3 0)) | |
#+lispworks (hcl:gc-generation (if full t 0))) | |
(defmacro mem-used ((&optional place (stream '*standard-output*)) &body forms) | |
"Prints memory allocated by running FORMS. Memory usage is recorded | |
before and after FORMS are run, and the difference in usage is printed | |
to STREAM. | |
Full GC is run before and after running forms to eliminate as many | |
temporary allocations as possible. Make sure to save a reference to | |
the objects whose memory usage you want to measure. (If the object you | |
want to measure is the last one returned, and you use this form in the | |
REPL, then * and / will refer to these objects, so you don't need to | |
handle this explicitly. | |
Does not work well for small allocations. In that case, predefine a | |
vector of appropriate size, make repeated allocations and insert the | |
newly allocated objects in that vector. | |
Returns the values returned by the last form. | |
If PLACE is non-nil, nothing is printed and instead the raw | |
values (see MEM-USAGE) are saved in PLACE." | |
(let ((start-usage (gensym "START-USAGE-")) | |
(diff (gensym "DIFF-"))) | |
`(progn | |
(run-gc :full t) | |
(let ((,start-usage (mem-usage))) | |
(multiple-value-prog1 | |
(progn ,@forms) | |
(run-gc :full t) | |
(let ((,diff (mem-difference (mem-usage) ,start-usage))) | |
,(if place | |
`(setf ,place ,diff) | |
`(print-usage ,diff ,stream)))))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment