[gambit-list] Profiling for memory usage

Marc Feeley feeley at iro.umontreal.ca
Sat Aug 12 07:41:40 EDT 2023


> On Aug 11, 2023, at 4:03 AM, Sven Hartrumpf <hartrumpf at gmx.net> wrote:
> 
> Hi.
> 
> I profile Gambit-compiled programs for runtime of functions
> by using the "perf" tool.
> 
> But how can I profile programs for memory usage (allocations)
> of functions?
> 
> Greetings
> Sven

There is no standard way to profile a program to discover which procedures do the most memory allocations. The “time” macro can be used to determine how much is allocated for the evaluation of a specific expression, but that is a rather blunt tool. There is a ##get-bytes-allocated! primitive that can be used to measure how much memory has been allocated by the program up to now. A profiling tool can then be built on top of that. For example below is the file prof-space.scm which defines a “define-prof” macro that behaves like “define” but that calculates the amount of memory allocated by the defined procedure. You could modify this code to your specific needs.

Marc


;; file: prof-space.scm

(define ##space-usage (make-table size: 100))

(define ##ba-cell (f64vector 0.0))

(define (##profile-space var thunk)
  (let* ((_ (##get-bytes-allocated! ##ba-cell 0))
         (before (##flonum->fixnum (f64vector-ref ##ba-cell 0)))
         (result (thunk))
         (_ (##get-bytes-allocated! ##ba-cell 0))
         (after (##flonum->fixnum (f64vector-ref ##ba-cell 0)))
         (bytes-allocated (- (- after before) ##profile-space-offset)))
    (if var
        (begin
          (table-set! ##space-usage
                      var
                      (+ bytes-allocated (table-ref ##space-usage var 0)))
          result)
        bytes-allocated)))

(define ##profile-space-offset 0)

(set! ##profile-space-offset (##profile-space #f (##lambda () 42)))

(define (##display-space-usage)
  (for-each
   (lambda (bucket)
     (println (car bucket) " = " (cdr bucket)))
   (list-sort (lambda (x y) (< (cdr x) (cdr y))) (table->list ##space-usage))))

(define-macro (define-prof pattern . rest)

  ;; Note: the name "define-prof" could be replaced by "define" to
  ;; profile all procedure definitions.

  (define (should-profile? var) #t) ;; profile everything

  (define (procedure-definition var lambda-expr)
    `(##define ,var
       ,(if (should-profile? var)
            `(##lambda ,(cadr lambda-expr)
               (##profile-space ',var
                                (##lambda () ,@(cddr lambda-expr))))
            lambda-expr)))

  (cond ((and (symbol? pattern)
              (pair? rest)
              (not (pair? (cdr rest)))
              (pair? (car rest))
              (memq (caar rest) '(lambda ##lambda)))
         (procedure-definition pattern (car rest)))
        ((pair? pattern)
         (procedure-definition (car pattern) `(##lambda ,(cdr pattern) , at rest)))
        (else
         `(##define ,pattern , at rest))))

;; code being profiled

(define-prof (f n) (make-vector n))   ;; allocates an n element vector
(define-prof (g n) (make-u8vector n)) ;; allocates an n element u8vector
(define-prof (h n) (iota n))          ;; allocates n pairs

(f 1000)
(g 1000)
(h 1000)

(##display-space-usage)

;; execution:
;;
;; $ gsc -exe prof-space.scm
;; $ ./prof-space 
;; g = 2016
;; f = 8048
;; h = 48000




More information about the Gambit-list mailing list