m4-commit
[Top][All Lists]
Advanced

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

[SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-r


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-readonly-60-g58ffaf1
Date: Sat, 23 Feb 2008 04:28:00 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU M4 source repository".

http://git.sv.gnu.org/gitweb/?p=m4.git;a=commitdiff;h=58ffaf13f5206f8bac8ec4ebad8147e99157263d

The branch, branch-1_4 has been updated
       via  58ffaf13f5206f8bac8ec4ebad8147e99157263d (commit)
      from  10801988a863c045aa0dc06b56575f1cc52bc586 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 58ffaf13f5206f8bac8ec4ebad8147e99157263d
Author: Eric Blake <address@hidden>
Date:   Mon Nov 19 19:40:49 2007 -0700

    Stage 18: try harder to reuse argv in recursion.
    
    * src/macro.c (make_argv_ref_token): Avoid wrapping $@ when
    possible.
    (push_args): Let make_argv_ref_token take care of pending data.
    * doc/m4.texinfo (Improved foreach): Tweak wording to match new
    performance capability.  Add regression tests.
    * NEWS: Document the speedup.
    * src/m4.c (AUTHORS): Claim credit for my rewrite.
    
    (cherry picked from commit 58d580eeca1f75ddd2ca68d8b93fef6eead14350)
    
    Signed-off-by: Eric Blake <address@hidden>

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog      |   16 +++++++++
 NEWS           |    4 ++-
 doc/m4.texinfo |   96 +++++++++++++++++++++++++++++++++++++++++++++++++------
 src/m4.c       |    2 +-
 src/macro.c    |   80 ++++++++++++++++++++++++++--------------------
 5 files changed, 150 insertions(+), 48 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 62c4ad1..1269290 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2008-02-23  Eric Blake  <address@hidden>
+
+       Stage 18: try harder to reuse argv in recursion.
+       When pushing arguments that contain an existing $@ ref, reuse the
+       ref rather than creating another layer of wrappers.
+       Memory impact: noticeable improvement, due to better $@ reuse.
+       Speed impact: noticeable improvement, due to O(n^2) to O(n)
+       reduction in unboxed recursion.
+       * src/macro.c (make_argv_ref_token): Avoid wrapping $@ when
+       possible.
+       (push_args): Let make_argv_ref_token take care of pending data.
+       * doc/m4.texinfo (Improved foreach): Tweak wording to match new
+       performance capability.  Add regression tests.
+       * NEWS: Document the speedup.
+       * src/m4.c (AUTHORS): Claim credit for my rewrite.
+
 2008-02-22  Eric Blake  <address@hidden>
 
        Stage 17: pass argv through quoted strings.
diff --git a/NEWS b/NEWS
index 31a41c2..8faafcf 100644
--- a/NEWS
+++ b/NEWS
@@ -27,7 +27,9 @@ Version 1.4.11 - ?? ??? 2008, by ????  (git version 1.4.10a-*)
   regular expressions, which speeds up typical Autoconf usage.
 * Enhance the `format' builtin to warn for more suspicious usages, such as
   missing arguments or problems parsing according to the format string.
-* Memory usage is greatly reduced in recursive macros.
+* Enhance the `ifelse' and `shift' builtins so that tail-recursive
+  algorithms based on `$@' operate in linear, rather than quadratic, time
+  and memory.
 * A number of portability improvements inherited from gnulib.
 
 Version 1.4.10 - 09 Jul 2007, by Eric Blake  (CVS version 1.4.9c)
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 2a549dd..92a8eff 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -7195,17 +7195,17 @@ helper method immediately, the 
@samp{defn(address@hidden')} no longer
 contains unexpanded macros.
 
 The astute m4 programmer might notice that the solution above still uses
-more memory, and thus more time, than strictly necessary.  Note that
address@hidden, which contains an arbitrarily long quoted list, is expanded
-and rescanned three times per iteration of @code{_foreachq}.
-Furthermore, every iteration of the algorithm effectively unboxes then
-reboxes the list, which costs a couple of macro invocations.  It is
-possible to rewrite the algorithm for a bit more speed by swapping the
-order of the arguments to @code{_foreachq} in order to operate on an
-unboxed list in the first place, and by using the fixed-length @samp{$#}
-instead of an arbitrary length list as the key to end recursion.  This
-alternative approach is available as
address@hidden@value{VERSION}/@/examples/@/foreach3.m4}:
+more macro invocations than strictly necessary.  Note that @samp{$2},
+which contains an arbitrarily long quoted list, is expanded and
+rescanned three times per iteration of @code{_foreachq}.  Furthermore,
+every iteration of the algorithm effectively unboxes then reboxes the
+list, which costs a couple of macro invocations.  It is possible to
+rewrite the algorithm by swapping the order of the arguments to
address@hidden in order to operate on an unboxed list in the first
+place, and by using the fixed-length @samp{$#} instead of an arbitrary
+length list as the key to end recursion.  The result is eight macro
+invocations per loop, instead of nine.  This alternative approach is
+available as @address@hidden/@/examples/@/foreach3.m4}:
 
 @comment examples
 @example
@@ -7248,6 +7248,20 @@ foreachq(`x', ``1', `2', `3', `4'', `x
 @result{}4
 @end example
 
+Prior to M4 1.4.11, every instance of @samp{$@@} was rescanned as it was
+encountered.  Thus, the @file{foreachq3.m4} alternative used much less
+memory than @file{foreachq2.m4}, and executed as much as 10% faster,
+since each iteration encountered fewer @samp{$@@}.  However, the
+implementation of rescanning every byte in @samp{$@@} was quadratic in
+the number of bytes scanned (for example, making the broken version in
address@hidden cubic, rather than quadratic, in behavior).  Once the
+underlying M4 implementation was improved in 1.4.11 to reuse results of
+previous scans, both styles of @code{foreachq} become linear in the
+number of bytes scanned, and the difference in timing is no longer
+noticeable; in fact, after the change, the @file{foreachq2.m4} version
+uses slightly less memory since it tracks fewer arguments per macro
+invocation.
+
 For yet another approach, the improved version of @code{foreach},
 available in @address@hidden/@/examples/@/foreach2.m4}, simply
 overquotes the arguments to @address@hidden to begin with, using
@@ -7376,6 +7390,66 @@ foreachq(`x', ```active'', ``active''', `<x>
 @result{}<active>
 @end example
 
address@hidden
address@hidden Not worth putting in the manual, but make sure that performance
address@hidden on recursive algorithms is not quadratic.
+
address@hidden boxed recursion
+
address@hidden examples
address@hidden options: -Dlimit=10 -Dverbose
address@hidden
+$ @kbd {m4 -I examples -Dlimit=10 -Dverbose}
+include(`loop.m4')dnl
address@hidden 1 2 3 4 5 6 7 8 9 10
address@hidden example
+
address@hidden examples
address@hidden options: -Dlimit=2500
address@hidden
+$ @kbd {m4 -I examples -Dlimit=2500}
+include(`loop.m4')dnl
address@hidden example
+
address@hidden examples
address@hidden options: -Dlimit=10000
address@hidden
+$ @kbd {m4 -I examples -Dlimit=10000}
+define(`debug', `define(`popdef',`divert`'i')')
address@hidden
+include(`loop.m4')dnl
address@hidden
address@hidden example
+
address@hidden unboxed recursion
+
address@hidden examples
address@hidden options: -Dlimit=10 -Dverbose -Dalt
address@hidden
+$ @kbd {m4 -I examples -Dlimit=10 -Dverbose -Dalt}
+include(`loop.m4')dnl
address@hidden 1 2 3 4 5 6 7 8 9 10
address@hidden example
+
address@hidden examples
address@hidden options: -Dlimit=2500 -Dalt
address@hidden
+$ @kbd {m4 -I examples -Dlimit=2500 -Dalt}
+include(`loop.m4')dnl
address@hidden example
+
address@hidden examples
address@hidden options: -Dlimit=10000 -Dalt
address@hidden
+$ @kbd {m4 -I examples -Dlimit=10000 -Dalt}
+define(`debug', `define(`popdef',`divert`'i')')
address@hidden
+include(`loop.m4')dnl
address@hidden
address@hidden example
+
address@hidden ignore
+
 @node Improved cleardivert
 @section Solution for @code{cleardivert}
 
diff --git a/src/m4.c b/src/m4.c
index af4991f..0ace6dc 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -27,7 +27,7 @@
 
 #include "version-etc.h"
 
-#define AUTHORS "Rene' Seindal"
+#define AUTHORS "Rene' Seindal", "Eric Blake"
 
 static void usage (int);
 
diff --git a/src/macro.c b/src/macro.c
index c0a24c4..32ff62d 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -1285,24 +1285,55 @@ make_argv_ref_token (token_data *token, struct obstack 
*obs, int level,
 {
   token_chain *chain;
 
-  assert (obstack_object_size (obs) == 0);
-  /* TODO support $@ refs when argv array is larger than 1.  */
-  if (argv->wrapper && argv->arraylen == 1)
-    {
-      assert (TOKEN_DATA_TYPE (argv->array[0]) == TOKEN_COMP
-             && argv->array[0]->u.u_c.wrapper);
-      chain = argv->array[0]->u.u_c.chain;
-      assert (!chain->next && chain->type == CHAIN_ARGV
-             && !chain->u.u_a.skip_last);
-      argv = chain->u.u_a.argv;
-      index += chain->u.u_a.index - 1;
-    }
   if (index >= argv->argc)
     return NULL;
+  TOKEN_DATA_TYPE (token) = TOKEN_COMP;
+  token->u.u_c.chain = token->u.u_c.end = NULL;
 
+  /* Cater to the common idiom of $0(`$1',shift(shift($@))), by
+     inlining the first few arguments and reusing the original $@ ref,
+     rather than creating another layer of wrappers.  */
+  while (argv->wrapper)
+    {
+      unsigned int i;
+      for (i = 0; i < argv->arraylen; i++)
+       {
+         if (TOKEN_DATA_TYPE (argv->array[i]) == TOKEN_COMP
+             && argv->array[i]->u.u_c.wrapper)
+           break;
+         if (index == 1)
+           {
+             push_arg_quote (obs, argv, i + 1, quotes);
+             obstack_1grow (obs, ',');
+           }
+         else
+           index--;
+       }
+      assert (i < argv->arraylen);
+      if (i + 1 == argv->arraylen)
+       {
+         assert (TOKEN_DATA_TYPE (argv->array[i]) == TOKEN_COMP
+                 && argv->array[i]->u.u_c.wrapper);
+         chain = argv->array[i]->u.u_c.chain;
+         assert (!chain->next && chain->type == CHAIN_ARGV
+                 && !chain->u.u_a.skip_last);
+         argv = chain->u.u_a.argv;
+         index += chain->u.u_a.index - 1;
+       }
+      else
+       {
+         index += i;
+         break;
+       }
+    }
+
+  make_text_link (obs, &token->u.u_c.chain, &token->u.u_c.end);
   chain = (token_chain *) obstack_alloc (obs, sizeof *chain);
-  TOKEN_DATA_TYPE (token) = TOKEN_COMP;
-  token->u.u_c.chain = token->u.u_c.end = chain;
+  if (token->u.u_c.end)
+    token->u.u_c.end->next = chain;
+  else
+    token->u.u_c.chain = chain;
+  token->u.u_c.end = chain;
   token->u.u_c.wrapper = true;
   token->u.u_c.has_func = argv->has_func;
   chain->next = NULL;
@@ -1416,8 +1447,6 @@ push_args (struct obstack *obs, macro_arguments *argv, 
bool skip, bool quote)
   unsigned int i = skip ? 2 : 1;
   token_data td;
   token_data *token;
-  char *str = NULL;
-  size_t len = obstack_object_size (obs);
 
   if (i >= argv->argc)
     return;
@@ -1428,29 +1457,10 @@ push_args (struct obstack *obs, macro_arguments *argv, 
bool skip, bool quote)
       return;
     }
 
-  /* Since make_argv_ref_token puts data on obs, we must first close
-     any pending data.  The resulting token contents live entirely on
-     obs, so we call push_token with a level of -1.  */
-  if (len)
-    {
-      obstack_1grow (obs, '\0');
-      str = (char *) obstack_finish (obs);
-    }
   /* TODO allow shift, $@, to push builtins without flatten.  */
   token = make_argv_ref_token (&td, obs, -1, argv, i, true,
                               quote ? &curr_quote : NULL);
   assert (token);
-  if (len)
-    {
-      token_chain *chain = (token_chain *) obstack_alloc (obs, sizeof *chain);
-      chain->next = token->u.u_c.chain;
-      token->u.u_c.chain = chain;
-      chain->type = CHAIN_STR;
-      chain->quote_age = 0;
-      chain->u.u_s.str = str;
-      chain->u.u_s.len = len;
-      chain->u.u_s.level = -1;
-    }
   if (push_token (token, -1, argv->inuse))
     arg_mark (argv);
 }


hooks/post-receive
--
GNU M4 source repository




reply via email to

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