anchor.diff:                   (let ((framebuffer (mezzano.gui.compositor:window-buffer window))
                          (width (- (mezzano.gui.compositor:width window) left right))
                          (height (- (mezzano.gui.compositor:height window) top bottom)))
  -                   ;; FIXME: Should do this in a seperate thread.
  -                   (update-display framebuffer left top width height)
  -                   (mezzano.gui.compositor:damage-window window
  -                                                         left top
  -                                                         width height)
                      (catch 'redraw
  -                     (loop
  -                        (dispatch-event app (mezzano.supervisor:fifo-pop fifo)))))))))))))
  +                     (ecase (mode app)
  +                       (:physical-visualizer
  +                        (update-display framebuffer left top width height)
  +                        (mezzano.gui.compositor:damage-window window
  +                                                              left top
  +                                                              width height)
  +                        (loop
  +                           (dispatch-event app (mezzano.supervisor:fifo-pop fifo))))
  +                       (:graphs
  +                        (graph-main-loop app)))))))))))))
   
   (defun spawn (&optional width height)
     (mezzano.supervisor:make-thread (lambda () (main width height))
  
positive.code:                  (app (make-instance 'memory-monitor
                                       :fifo fifo
                                       :window window
                                       :frame frame)))
              (mezzano.gui.widgets:draw-frame frame)
              (mezzano.gui.compositor:damage-window window
                                                    0 0
  
negative.code:                 (#x100 (mezzano.gui:make-colour-from-octets 121 121 121)) ; other
                  (t (mezzano.gui:make-colour 1 1 1)))))))) ; mixed
  
  (defparameter *graph-background-colour*
    gui:*default-background-colour*)
  
  (defparameter *graph-tracker-colour*
    (gui:make-colour-from-octets 255 0 0))
  
  (defparameter *graph-update-interval* 1/4)
  
  (defun update-sampler (sampler column)
    (let ((history (sampler-history sampler))
          (value (funcall (sampler-function sampler))))
      (setf (aref history column) value)
      (when (eql (sampler-scale sampler) t)
        ;; Update autoscale limits.
        (setf (sampler-autoscale sampler)
              (max 1 (reduce #'max history :key (lambda (n) (or n 0))))))))
  
  (defun draw-sampler-incremental (sampler column fb x y graph-height)
    (let* ((history (sampler-history sampler))
           (scale (case (sampler-scale sampler)
                    ((nil) 1)
                    ((t) (sampler-autoscale sampler))
                    (otherwise (sampler-scale sampler))))
           (raw-value (aref history column))
           (raw-last (or (aref history (mod (1- column) (length history)))
                         raw-value))
           (value (- 1 (min 1 (max 0 (/ (float raw-value) scale)))))
           (last (- 1 (min 1 (max 0 (/ (float raw-last) scale)))))
           (from (truncate (* (min value last) graph-height)))
           (to (truncate (* (max value last) graph-height))))
        (dotimes (i (- to from))
          (setf (gui:surface-pixel fb (+ x column) (+ y from i))
                (sampler-colour sampler)))
        (setf (gui:surface-pixel fb (+ x column) (+ y to))
              (sampler-colour sampler))))
  
  (defun draw-sampler-full (sampler current-column fb x y graph-height)
    (let ((history (sampler-history sampler))
          (scale (case (sampler-scale sampler)
                   ((nil) 1)
                   ((t) (sampler-autoscale sampler))
                   (otherwise (sampler-scale sampler)))))
      (dotimes (column (length (sampler-history sampler)))
        (let ((raw-value (aref history column)))
          (when (not raw-value)
            (return-from draw-sampler-full))
          (let* ((raw-last (or (aref history (mod (1- column) (length history)))
                               raw-value))
                 (value (- 1 (min 1 (max 0 (/ (float raw-value) scale)))))
                 (last (- 1 (min 1 (max 0 (/ (float raw-last) scale)))))
                 (from (truncate (* (min value last) graph-height)))
                 (to (truncate (* (max value last) graph-height))))
            (dotimes (i (- to from))
              (setf (gui:surface-pixel fb (+ x column) (+ y from i))
                    (sampler-colour sampler)))
            (setf (gui:surface-pixel fb (+ x column) (+ y to))
                  (sampler-colour sampler)))))))
  
  (defun graph-main-loop (app)
    (sup:with-timer (timer :relative 0 :name "Memory monitor graph update")
      (multiple-value-bind (left right top bottom)
          (mezzano.gui.widgets:frame-size (frame app))
        (let* ((fb (mezzano.gui.compositor:window-buffer (window app)))
               (width (gui:surface-width fb))
               (height (gui:surface-height fb)))
          (gui:bitset :set (- width left right) (- height top bottom)
                      *graph-background-colour*
                      fb left top)
          (mezzano.gui.compositor:damage-window
           (window app) left top (- width left right) (- height top bottom))
          (dolist (sampler (samplers app))
            (when (and (sampler-history sampler)
                       (eql (length (sampler-history sampler)) (- width left right)))
              (return))
            (setf (graph-column app) 0)
            (setf (sampler-history sampler) (make-array (- width left right) :initial-element nil)))
          (let ((need-full-redraw nil))
            (loop
               (loop
                  (multiple-value-bind (event validp)
                      (sync:mailbox-receive (fifo app) :wait-p nil)
                    (when (not validp) (return))
                    (dispatch-event app event)))
               (when (sup:timer-expired-p timer)
                 (sup:timer-arm *graph-update-interval* timer)
                 (dolist (sampler (samplers app))
                   (update-sampler sampler (graph-column app))
                   (when (not (eql (if (eql (sampler-scale sampler) t)
                                       (sampler-autoscale sampler)
                                       (sampler-scale sampler))
                                   (sampler-last-scale sampler)))
                     (setf need-full-redraw t)))
                 (cond (need-full-redraw
                        (gui:bitset :set (- width left right) (- height top bottom)
                                    *graph-background-colour*
                                    fb left top)
                        (dolist (sampler (samplers app))
                          (setf (sampler-last-scale sampler) (if (eql (sampler-scale sampler) t)
                                                                 (sampler-autoscale sampler)
                                                                 (sampler-scale sampler)))
                          (draw-sampler-full sampler (graph-column app) fb left top (- height top bottom)))
                        (setf need-full-redraw nil))
                       (t
                        (gui:bitset :set 1 (- height top bottom)
                                    *graph-background-colour*
                                    fb (+ left (graph-column app)) top)
                        (dolist (sampler (samplers app))
                          (draw-sampler-incremental sampler (graph-column app) fb left top (- height top bottom)))))
                 (incf (graph-column app))
                 (when (>= (graph-column app) (- width left right))
                   (setf (graph-column app) 0))
                 (gui:bitset :set 1 (- height top bottom)
                             *graph-tracker-colour*
                             fb (+ left (graph-column app))  top)
                 (mezzano.gui.compositor:damage-window
                  (window app) left top (- width left right) (- height top bottom)))
               (sync:wait-for-objects timer (fifo app))))))))
  
  (defun general-area-usage ()
    (let ((bump (+ int::*general-area-old-gen-bump* int::*general-area-young-gen-bump*))
          (limit (+ int::*general-area-old-gen-limit* int::*general-area-young-gen-limit*)))
      (/ (float bump) limit)))
  
  (defun general-area-alloc ()
    (+ int::*general-area-old-gen-bump* int::*general-area-young-gen-bump*))
  
  (defun general-area-commit ()
    (+ int::*general-area-old-gen-limit* int::*general-area-young-gen-limit*))
  
  (defun cons-area-usage ()
    (let ((bump (+ int::*cons-area-old-gen-bump* int::*cons-area-young-gen-bump*))
          (limit (+ int::*cons-area-old-gen-limit* int::*cons-area-young-gen-limit*)))
      (/ (float bump) limit)))
  
  (defun cons-area-alloc ()
    (+ int::*cons-area-old-gen-bump* int::*cons-area-young-gen-bump*))
  
  (defun cons-area-commit ()
    (+ int::*cons-area-old-gen-limit* int::*cons-area-young-gen-limit*))
  
  (defun pinned-area-usage ()
    (multiple-value-bind (allocated-words total-words)
        (int::area-info :pinned)
      (/ (float allocated-words) total-words)))
  
  (defun wired-area-usage ()
    (multiple-value-bind (allocated-words total-words)
        (int::area-info :wired)
      (/ (float allocated-words) total-words)))
  
  (defun function-area-usage ()
    (multiple-value-bind (allocated-words total-words)
        (int::area-info :function)
      (/ (float allocated-words) total-words)))
  
  (defun wired-function-area-usage ()
    (multiple-value-bind (allocated-words total-words)
        (int::area-info :wired-function)
      (/ (float allocated-words) total-words)))
  
  (defun main (open-width open-height)
    (with-simple-restart (abort "Close memory monitor")
      (catch 'quit
  