GNU bug report logs - #17147
Performance regression by 3000000% for evaluating "and" form

Previous Next

Package: guile;

Reported by: David Kastrup <dak <at> gnu.org>

Date: Mon, 31 Mar 2014 09:59:02 UTC

Severity: wishlist

Done: Mark H Weaver <mhw <at> netris.org>

Bug is archived. No further changes may be made.

Full log


Message #19 received at 17147 <at> debbugs.gnu.org (full text, mbox):

From: David Kastrup <dak <at> gnu.org>
To: Mark H Weaver <mhw <at> netris.org>
Cc: 17147 <at> debbugs.gnu.org
Subject: Re: bug#17147: Performance regression by 3000000% for evaluating
 "and" form
Date: Tue, 01 Apr 2014 08:17:01 +0200
[Message part 1 (text/plain, inline)]
Mark H Weaver <mhw <at> netris.org> writes:

> Okay, good point.  Indeed, the expansion time of our 'and' and 'or'
> macros is quadratic in the number of operands.  They are implemented in
> boot-9.scm as follows:
>
>   (define-syntax and
>     (syntax-rules ()
>       ((_) #t)
>       ((_ x) x)
>       ((_ x y ...) (if x (and y ...) #f))))
>   
>   (define-syntax or
>     (syntax-rules ()
>       ((_) #f)
>       ((_ x) x)
>       ((_ x y ...) (let ((t x)) (if t t (or y ...))))))
>
> The problem is that the "y ..." pattern has to iterate down the entire
> list to verify that it's a proper list, and this is done for each
> operand.

Why would it have to do that?  It cannot be anything valid else if it is
a pair.

Note that the compiler does not bother to do this for other cases: if I
write

[zorpo.scm (text/plain, inline)]
(use-modules (srfi srfi-19) (srfi srfi-1))
(define start-time (current-time))
(primitive-eval (cons '+ (circular-list 0)))
(display (time-difference (current-time) start-time))
[Message part 3 (text/plain, inline)]
then I get
dak <at> lola:/usr/local/tmp/guile$ meta/guile /tmp/zorpo.scm 
;;; note: source file /tmp/zorpo.scm
;;;       newer than compiled /usr/local/tmp/guile/cache/guile/ccache/2.2-LE-4-3.4/tmp/zorpo.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /tmp/zorpo.scm
;;; compiled /usr/local/tmp/guile/cache/guile/ccache/2.2-LE-4-3.4/tmp/zorpo.scm.go
Warning: Unwind-only `stack-overflow' exception; skipping pre-unwind handler.
Warning: Unwind-only `stack-overflow' exception; skipping pre-unwind handler.

and what of it?  If you really, really must, do one recursive top-level
check of everything before starting.  But re-verifying structural
integraty after applying every single rule is madness.  Actually,
replacing '+ by 'and in that example will lead to the same bomb-out.  So
it does not look like structural integrity verification is happening
anyway.

> The simplest solution would be to replace all occurrences of "y ..."
> with ". y" in the two macros above, but that has the slight downside
> of making the error message much less comprehensible if you use a
> dotted tail in an 'and' or 'or' form.  Maybe that's not worth worrying
> about though.

If you care about nice error messages, do a single upfront check.

> Alternatively, we could use procedural macros here, but we'd have to
> limit ourselves to very primitive forms in the code because this is so
> early in the bootstrap.

I don't think it's worth it just for and/or (the form generated by or
actually seems more prone to buildup and churn).  But for syntax
replacements in general?  Sure.  You don't want quadratic behavior in
bare-bones replacements like these.

-- 
David Kastrup

This bug report was last modified 11 years and 41 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.