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;