autoconf-patches
[Top][All Lists]
Advanced

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

Re: AC_DEFUN_ONCE semantics


From: Eric Blake
Subject: Re: AC_DEFUN_ONCE semantics
Date: Thu, 29 Jan 2009 06:40:28 -0700
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.19) Gecko/20081209 Thunderbird/2.0.0.19 Mnenhy/0.7.5.666

According to Paolo Bonzini on 1/29/2009 1:13 AM:
>> More and more, I get the impression that my m4sugar code looks like black 
>> magic 
>> to the casual onlooker.  Apologies to those who think I don't comment my 
>> code 
>> enough for all the tricks I pull off.
> 
> This one definitely does, usually I can follow you though.
> 
> What was wrong with the simpler definition used for gnulib? :-)  Did you
> measure any actual performance change?

Yes, there is a slight difference; it will be more pronounced the more
defun_once macros you encounter.  The version in gnulib unconditionally
goes through two defun'd macro, and the overhead of
_m4_defun_pro/_m4_defun_epi is sizable (computing diversion numbers with
_m4_divert, manipulating lots of temporary variables, ...).  Also, the
gnulib version exploits the fact that it only has to work with older
autoconf that did not warn; if I use the gnulib approach of two defun's in
autoconf.git, I have to add magic to bypass the new expand-before-require
warning.  The version in autoconf.git bypasses as much as possible, by
deciding on one of three possible calls:

Top-level call, where we've cut from two defun down to one:
_m4_defun_pro([$1])m4_unquote([$2[]m4_provide([$1])])_m4_defun_epi([$1])

Direct expansion inside a defun, where we've avoided a defun, and bypassed
the m4_require overhead by directly using _m4_require_call:
_m4_require_call([$1], [$2[]m4_provide([$1])], _m4_divert_dump)

Require inside a defun, where we exploit that we are already in the middle
of _m4_require_call and only need to provide the body:
m4_unquote([$2[]m4_provide([$1])])

But storing three copies of $2 in the definition of $1 is expensive
(looking through autoconf.m4f shows several defun_once'd macros which
occupy more than 1000 bytes with only a single copy of $2; this would
become 3000 bytes without factoring), which is why I added _m4_defun_once;
the definition of $1 includes m4_if which computes the last two arguments
of the helper macro.

Now, for timing numbers.  Using autoconf.git on coreutils, I see 13.015s,
but with the patch below based on gnulib's implementation (but with
m4_require instead of AC_REQUIRE, and with the necessary tweaks to pass
the autoconf testsuite regarding no spurious newlines), I see 13.191s, for
about a 1% slowdown.  Gnulib is okay with spurious newlines, since it will
only penalize people using older autoconf, and since gnulib intentionally
does not try as hard as autoconf to avoid blank lines.

diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 55dc644..2fd7700 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -1942,6 +1942,12 @@ m4_define([m4_defun_init],
 # current defun'd macro.  Use a helper macro so that EXPANSION need
 # only occur once in the definition of NAME, since it might be large.
 m4_define([m4_defun_once],
+[m4_defun([$1], [m4_pushdef([$1])m4_provide([$1])m4_set_remove(
+  [_m4_provide], [$1])m4_require([_m4_defun_once([$1])], [m4_indir(
+  [_m4_defun_once([$1])])]m4_ifdef([_m4_diverting([$1])], [[dnl]]))])]dnl
+[m4_defun([_m4_defun_once([$1])], [$2])])
+
+m4_ignore(
 [m4_define([m4_location($1)], m4_location)]dnl
 [m4_define([$1], [_m4_defun_once([$1], [$2], m4_if(_m4_divert_dump, [],
   [[_m4_defun_pro([$1])m4_unquote(], [)_m4_defun_epi([$1])]],

-- 
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

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