help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Identifying sources of allocations in a toy Mandelbrot package


From: Psionic K
Subject: Re: Identifying sources of allocations in a toy Mandelbrot package
Date: Sat, 20 Jan 2024 12:14:53 +0900

> Any temporary Lisp objects will allocate memory. Their references will be
on the stack, but the objects themselves will be on the heap.

I had presumed at a minimum that the compiler can re-use heap locations
when it decides there's no risk.  While the values will be in the heap, is
there a way to destructively re-use heap locations so that we are not
burning through all of the heap during iteration?  Do function calls re-use
any heap space?  Does anything besides GC?   As it is, I can guess that
every call to even + or * is creating a unique float that now exists on the
heap until GC'd.

The vector would have a bounded size of about 50-100MB.  To avoid us
focusing on it, I have removed it.  No material impact.

> have you tried eliminating cl-lib?

No change.  After getting rid of cl-return, I'm doing worse, at around
16.0s and however much memory I provide.

> use let instead of setf and setq, everywhere

Without using recursion to change the iteration structure to one that never
uses setq, I obtained a version that is consistent with all of the GC
tradeoffs I've seen so far, requiring between 10 and 20 seconds depending
on how much memory I allow.  Should I consider further modifications?

    ;;; mandelbrot.el --- Mandelbrot -*- lexical-binding: t; -*-

    ;;; Commentary:

    ;; Render's Mandelbrot set.

    ;;; Code:

    ;;;###autoload
    (defun mandelbrot ()
      "Render a Mandelbrot."
      (declare (speed 3))
      (interactive)
      (pop-to-buffer (get-buffer-create "*Mandelbrot*"))
      (fundamental-mode)
      (erase-buffer)
      (set-buffer-multibyte nil)
      (let ((gc-cons-threshold (* 800000 1024))
            (gc-cons-percentage 0.6)
            (inhibit-modification-hooks t)
            (w 1600) (h 1200) (d 256) (dd 256.0)
            (x0 -2.5) (y0 -1.5) (dx 4.0) (dy 3.0))
        (insert (format "P6\n%d %d\n255\n" w h))
        (let* ((dxp (/ dx w))
               (dyp (/ dy h)))
          (dotimes (y h)
            (message "Row: %d" y)       ; removal prevents GC
            (let ((cy (+ y0 (* dyp y))))
              (dotimes (x w)
                (let ((cx (+ x0 (* dxp x)))
                      (zr 0) (zi 0)
                      (v 0) (not-escaped t))
                  (while (and not-escaped
                              (< v d))
                    (if (> (+ (expt zr 2.0) (expt zi 2.0)) 4)
                        (setq not-escaped nil)
                      (let ((zrt (+ (* zr zr) (- (* zi zi)) cx)))
                        (setq zi (+ (* (* zr zi) 2.0) cy))
                        (setq zr zrt))
                      (setq v (1+ v))))
                  ;; samples that hit 256 wrap in the graphic to display as
zero
                  ;; exponential 0.8 enhances contrast a bit
                  (let ((out (floor (* 256 (/ v dd)))))
                    (insert out out out))))))
          (image-mode))))

    (provide 'mandelbrot)
    ;;; mandelbrot.el ends here.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]