Skip to content

Instantly share code, notes, and snippets.

@alphapapa
Last active August 17, 2019 06:47
Show Gist options
  • Save alphapapa/43b7ba264ca13e51c8e8583869fe3ffd to your computer and use it in GitHub Desktop.
Save alphapapa/43b7ba264ca13e51c8e8583869fe3ffd to your computer and use it in GitHub Desktop.
Emacs: Benchmarking sequence shuffling

Benchmarking sequence shuffling

See melpa/melpa#6191 (comment)

(defun key-quiz--shuffle-list (list)
  "Shuffles LIST randomly, modying it in-place."
  (dolist (i (reverse (number-sequence 1 (1- (length list)))))
    (let ((j (random (1+ i)))
	  (tmp (elt list i)))
      (setf (elt list i) (elt list j))
      (setf (elt list j) tmp)))
  list)

(defun key-quiz--shuffle-list-nreverse (list)
  "Shuffles LIST randomly, modying it in-place."
  (dolist (i (nreverse (number-sequence 1 (1- (length list)))))
    (let ((j (random (1+ i)))
	  (tmp (elt list i)))
      (setf (elt list i) (elt list j))
      (setf (elt list j) tmp)))
  list)

(defun elfeed--shuffle (seq)
  "Destructively shuffle SEQ."
  (let ((n (length seq)))
    (prog1 seq                  ; don't use dotimes result (bug#16206)
      (dotimes (i n)
        (cl-rotatef (elt seq i) (elt seq (+ i (random (- n i)))))))))

(defun faster-seq-sort-by (function pred sequence)
  "Sort SEQUENCE using PRED as a comparison function.
Elements of SEQUENCE are transformed by FUNCTION before being
sorted.  FUNCTION must be a function of one argument."
  ;; This version is modified to avoid calling "random" twice every time the predicate is called.
  (seq-map 'cdr
           (sort (seq-map (lambda (x) (cons (funcall function x) x)) sequence)
                 (lambda (a b)
                   (funcall pred (car a) (car b))))))

(defun seq-sort-by--shuffle (seq)
  (seq-sort-by (lambda (_) (random)) #'<= seq))

(defun faster-seq-sort-by--shuffle (seq)
  (faster-seq-sort-by (lambda (_) (random)) #'<= seq))

Lists

(let ((big-list (seq-into (seq-take obarray 5000) 'list)))
  (bench-multi-lexical :times 100
    :forms (("key-quiz--shuffle-list" (key-quiz--shuffle-list big-list))
            ("key-quiz--shuffle-list-nreverse" (key-quiz--shuffle-list-nreverse big-list))
            ("elfeed--shuffle" (elfeed--shuffle big-list))
            ("seq-sort-by--shuffle" (seq-sort-by--shuffle big-list))
            ("faster-seq-sort-by--shuffle" (faster-seq-sort-by--shuffle big-list)))))
Formx faster than nextTotal runtime# of GCsTotal GC runtime
faster-seq-sort-by–shuffle1.381.72503700
seq-sort-by–shuffle15.012.37823400
key-quiz–shuffle-list-nreverse1.0335.7033162717.892723
key-quiz–shuffle-list1.2436.6303202818.768216
elfeed–shuffleslowest45.4394053221.130538

Vectors

(let ((big-list (seq-into (seq-take obarray 5000) 'vector)))
  (bench-multi-lexical :times 100
    :forms (("key-quiz--shuffle-list" (key-quiz--shuffle-list big-list))
            ("key-quiz--shuffle-list-nreverse" (key-quiz--shuffle-list-nreverse big-list))
            ("elfeed--shuffle" (elfeed--shuffle big-list))
            ("seq-sort-by--shuffle" (seq-sort-by--shuffle big-list))
            ("faster-seq-sort-by--shuffle" (faster-seq-sort-by--shuffle big-list)))))
Formx faster than nextTotal runtime# of GCsTotal GC runtime
faster-seq-sort-by–shuffle1.391.71899000
seq-sort-by–shuffle10.422.39086000
key-quiz–shuffle-list-nreverse1.0224.9187742717.971779
key-quiz–shuffle-list1.1025.4526652818.487015
elfeed–shuffleslowest27.9913053221.215224
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment