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
Afficher les réponses par date
On Aug 11, 2023, at 4:03 AM, Sven Hartrumpf hartrumpf@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) ,@rest))) (else `(##define ,pattern ,@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
Thanks Marc for the code and the explanations! Maybe this can be integrated into the distribution somehow at some point in the future? Anyway, this will help me now to investigate which functions are problematic in my Scheme code.
Greetings Sven
On Aug 12, 2023, at 3:55 PM, Sven Hartrumpf hartrumpf@gmx.net wrote:
Thanks Marc for the code and the explanations! Maybe this can be integrated into the distribution somehow at some point in the future? Anyway, this will help me now to investigate which functions are problematic in my Scheme code.
Sven: There is an intermittent bug that reports negative bytes allocated when the “time” macro is used. If you happen to hit a similar situation with this more granular method of measuring allocation, please file a bug report with the details. Brad