You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add/Change: bench-multi-lexical and changes to bench-multi
bench-multi now produces code compatible with lexical-binding, and
bench-multi-lexical benchmarks code in a byte-compiled file with
lexical-binding enabled.
The fastest method here is to call ~insert~ once with the result of calling ~concat~ once, using ~apply~ to pass all of the strings. With 100 iterations, it's about 6x faster than the next-fastest method, and even with 1 iteration, it's over 2x faster.
185
+
186
+
185
187
*** Libraries :libraries:
186
188
:PROPERTIES:
187
189
:ID: 523aa766-36a3-4827-a114-6babf72edc6b
@@ -1348,24 +1350,26 @@ When called from an Org source block, it gives output like this:
1348
1350
1349
1351
This macro makes comparing multiple forms easy:
1350
1352
1351
-
#+BEGIN_SRC elisp
1353
+
#+BEGIN_SRC elisp :exports code :results silent
1352
1354
(cl-defmacro bench-multi (&key (times 1) forms ensure-equal)
1353
-
"Run FORMS with `benchmark-run-compiled' for TIMES iterations, returning list suitable for Org source block evaluation.
1355
+
"Return Org table as a list with benchmark results for FORMS.
1356
+
Runs FORMS with `benchmark-run-compiled' for TIMES iterations.
1354
1357
1355
-
When ENSURE-EQUAL is non-nil, compare the results of FORMS and
1356
-
ensure they are `equal'. If they aren't, raise an error, and if
1357
-
the results are sequences, show the difference between them using
1358
+
When ENSURE-EQUAL is non-nil, the results of FORMS are compared,
1359
+
and an error is raised if they aren't `equal'. If the results
1360
+
are sequences, the difference between them is shown with
1358
1361
`seq-difference'.
1359
1362
1360
-
If the first element of a form is a string, the string is used as
1361
-
the form's description in the results; otherwise, forms are
1362
-
numbered from 0.
1363
+
If the first element of a form is a string, it's used as the
1364
+
form's description in the bench-multi-results; otherwise, forms
1365
+
are numbered from 0.
1363
1366
1364
-
Before `benchmark-run-compiled' is called for each form,
1365
-
`garbage-collect' is called."
1367
+
Before each form is run, `garbage-collect' is called."
1368
+
;; MAYBE: Since `bench-multi-lexical' byte-compiles the file, I'm not sure if
1369
+
;; `benchmark-run-compiled' is necessary over `benchmark-run', or if it matters.
1366
1370
(declare (indent defun))
1367
-
(let ((results (gensym))
1368
-
(result-times (gensym))
1371
+
(let ((keys (gensym "keys"))
1372
+
(result-times (gensym "result-times"))
1369
1373
(header '(("Form" "x faster than next" "Total runtime" "# of GCs" "Total GC runtime")
1370
1374
hline))
1371
1375
(descriptions (cl-loop for form in forms
@@ -1374,54 +1378,61 @@ This macro makes comparing multiple forms easy:
1374
1378
(prog1 (car form)
1375
1379
(setf (nth i forms) (cadr (nth i forms))))
1376
1380
i))))
1377
-
`(let* ((,results (make-hash-table))
1378
-
(,result-times (sort (list ,@(cl-loop for form in forms
1379
-
for i from 0
1380
-
for description = (nth i descriptions)
1381
-
collect `(progn
1382
-
(garbage-collect)
1383
-
(cons ,description
1384
-
(benchmark-run-compiled ,times
1385
-
,(if ensure-equal
1386
-
`(puthash ,description ,form ,results)
1387
-
form))))))
1388
-
(lambda (a b)
1389
-
(< (second a) (second b))))))
1390
-
,(when ensure-equal
1391
-
`(cl-loop with keys = (hash-table-keys ,results)
1392
-
for i from 0 to (- (length keys) 2)
1393
-
unless (equal (gethash (nth i keys) ,results)
1394
-
(gethash (nth (1+ i) keys) ,results))
1395
-
do (if (sequencep (gethash (car (hash-table-keys ,results)) ,results))
1396
-
(let* ((k1) (k2)
1397
-
;; If the difference in one order is nil, try in other order.
1398
-
(difference (or (setq k1 (nth i keys)
1399
-
k2 (nth (1+ i) keys)
1400
-
difference (seq-difference (gethash k1 ,results)
1401
-
(gethash k2 ,results)))
1402
-
(setq k1 (nth (1+ i) keys)
1403
-
k2 (nth i keys)
1404
-
difference (seq-difference (gethash k1 ,results)
1405
-
(gethash k2 ,results))))))
1406
-
(user-error "Forms' results not equal: difference (%s - %s): %S"
1407
-
k1 k2 difference))
1408
-
;; Not a sequence
1409
-
(user-error "Forms' results not equal: %s:%S %s:%S"
It can also help catch bugs by ensuring that each form returns the same results. For example, the benchmark above contains a subtle bug: because ~case-fold-search~ in the =regexp= form is non-nil, the regexp is compared case-insensitively, so it matches Org headings which start with =Maybe= rather than only ones which start with =MAYBE=. Using the ~:ensure-equal t~ argument to ~bench-multi~ compares the results and raises an error showing the difference between the two sequences the forms evaluate to:
@@ -1480,8 +1490,7 @@ It can also help catch bugs by ensuring that each form returns the same results.
1480
1490
Fixing the error, by setting ~case-fold-search~ to ~nil~, not only makes the forms give the same result but, in this case, doubles the performance of the faster form:
0 commit comments