Author: stefan2
Date: Thu May 16 10:19:18 2013
New Revision: 1483292

URL: http://svn.apache.org/r1483292
Log:
Daring another no-no: provide our own, optimized implementation
of a string to unsigned int conversion.  Use it to simplify & speed up
svn_revnum_parse.

Background: In my 'svn log -g' tests, I found that >50% of the runtime
is spent parsing mergeinfo and ~20% in strtol alone.

* subversion/include/private/svn_string_private.h
  (svn__strtoff): declare new private API

* subversion/libsvn_subr/string.c
  (svn__strtoff): implement it

* subversion/libsvn_subr/types.c
  (svn_revnum_parse): use it

Modified:
    subversion/trunk/subversion/include/private/svn_string_private.h
    subversion/trunk/subversion/libsvn_subr/string.c
    subversion/trunk/subversion/libsvn_subr/types.c

Modified: subversion/trunk/subversion/include/private/svn_string_private.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_string_private.h?rev=1483292&r1=1483291&r2=1483292&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_string_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_string_private.h Thu May 16 
10:19:18 2013
@@ -136,6 +136,12 @@ svn_stringbuf__morph_into_string(svn_str
 apr_status_t
 svn__strtoff(apr_off_t *offset, const char *buf, char **end, int base);
 
+/** Like strtoul but with a fixed base of 10.  This allows the compiler to
+ * generate massively faster (4x on 64bit LINUX) code.
+ */
+unsigned long
+svn__strtoul(const char *buffer, char **end);
+
 /** Number of chars needed to represent signed (19 places + sign + NUL) or
  * unsigned (20 places + NUL) integers as strings.
  */

Modified: subversion/trunk/subversion/libsvn_subr/string.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/string.c?rev=1483292&r1=1483291&r2=1483292&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/string.c (original)
+++ subversion/trunk/subversion/libsvn_subr/string.c Thu May 16 10:19:18 2013
@@ -1027,6 +1027,36 @@ svn__strtoff(apr_off_t *offset, const ch
 #endif
 }
 
+unsigned long
+svn__strtoul(const char *buffer, char **end)
+{
+  unsigned long result = 0;
+
+  /* this loop will execute in just 2 CPU cycles, confirmed by measurement:
+     7 macro-ops (max 4 / cycle => 2 cycles)
+       1 load (max 1 / cycle)
+       1 jumps (compare + conditional jump == 1 macro op; max 1 / cycle)
+       2 arithmetic ops (subtract, increment; max 3 / cycle)
+       2 scale-and-add AGU ops (max 3 / cycle)
+       1 compiler-generated move operation
+     dependency chain: temp = result * 4 + result; result = temp * 2 + c
+                       (2 ops with latency 1 => 2 cycles)
+   */
+  while (1)
+    {
+      unsigned long c = *buffer - '0';
+      if (c > 9)
+        break;
+
+      result = result * 10 + c;
+      ++buffer;
+    }
+
+  *end = (char *)buffer;
+  return result;
+}
+
+
 /* "Precalculated" itoa values for 2 places (including leading zeros).
  * For maximum performance, make sure all table entries are word-aligned.
  */

Modified: subversion/trunk/subversion/libsvn_subr/types.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/types.c?rev=1483292&r1=1483291&r2=1483292&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/types.c (original)
+++ subversion/trunk/subversion/libsvn_subr/types.c Thu May 16 10:19:18 2013
@@ -30,6 +30,7 @@
 #include "svn_string.h"
 #include "svn_props.h"
 #include "svn_private_config.h"
+#include "private/svn_string_private.h"
 
 svn_error_t *
 svn_revnum_parse(svn_revnum_t *rev,
@@ -38,28 +39,17 @@ svn_revnum_parse(svn_revnum_t *rev,
 {
   char *end;
 
-  svn_revnum_t result = strtol(str, &end, 10);
+  svn_revnum_t result = (svn_revnum_t)svn__strtoul(str, &end);
 
   if (endptr)
     *endptr = end;
 
   if (str == end)
-    return svn_error_createf(SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
-                             _("Invalid revision number found parsing '%s'"),
-                             str);
-
-  if (result < 0)
-    {
-      /* The end pointer from strtol() is valid, but a negative revision
-         number is invalid, so move the end pointer back to the
-         beginning of the string. */
-      if (endptr)
-        *endptr = str;
-
-      return svn_error_createf(SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
-                               _("Negative revision number found parsing 
'%s'"),
-                               str);
-    }
+    return svn_error_createf
+              (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
+               *str == '-' ? _("Negative revision number found parsing '%s'")
+                           : _("Invalid revision number found parsing '%s'"),
+               str);
 
   *rev = result;
 


Reply via email to