faster strchr

Eric Blake ebb9@byu.net
Tue Jun 3 18:29:00 GMT 2008


Jeff Johnston <jjohnstn <at> redhat.com> writes:

> >>>       
> >> Yes, go ahead.  I assume you have verified that the function still works 
> >> correctly.
> >>
> > OK for this followon, which changes the generic C code in the same manner 
(also 
> > tested)?
> 
> Yes, thanks.
> 

OK for this followup?  This codifies my regression test into version control, 
rather than just this email thread.  I tested with:

$ cd libc/string
$ gcc -Wall -o strchr -O2 -D_REGRESSION_TEST strchr.c
$ time ./strchr --all    # C implementation

real	0m3.188s
user	0m3.171s
sys	0m0.030s
$ gcc -c -o strchr1.o -Dstrchr=strchr1 ../machine/i386/strchr.S
$ gcc -Wall -o strchr -O2 -D_REGRESSION_TEST -DTEST_STRCHR=strchr1 \
  strchr.c strchr1.o
$ time ./strchr --all    # Assembly implementation

real	0m2.922s
user	0m2.890s
sys	0m0.030s


If this approach is okay, then I will make similar changes for the other 
functions I have touched; am I pre-approved for checking those in too?  Do you 
want me to also try and figure out how to hook this into 'make check'?

2008-05-28  Eric Blake  <ebb9@byu.net>

	Add test for recent changes.
	* libc/string/strchr.c [_REGRESSION_TEST]: New section, which can
	optionally be compiled as a regression test.

Index: libc/string/strchr.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/string/strchr.c,v
retrieving revision 1.3
diff -u -p -r1.3 strchr.c
--- libc/string/strchr.c	22 May 2008 02:31:46 -0000	1.3
+++ libc/string/strchr.c	28 May 2008 15:17:27 -0000
@@ -121,3 +121,101 @@ _DEFUN (strchr, (s1, i),
     return (char *)s;
   return NULL;
 }
+
+/* The remainder of this file can serve as a regression test.  Compile
+   with -D_REGRESSION_TEST, and optionally with
+   -DTEST_STRCHR=strchr_alt when linked with strchr_alt.o, to ensure
+   correct operation and allow timing tests.  */
+#ifdef _REGRESSION_TEST
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <assert.h>
+
+# ifdef TEST_STRCHR
+char *TEST_STRCHR (const char *, int);
+# else
+#  define TEST_STRCHR strchr
+# endif
+
+static void
+test (size_t size, size_t repeat, size_t offset, int goal)
+{
+  char *buf = malloc (size + 1);
+  char *expected;
+  assert (buf);
+  switch (goal)
+    {
+    case 0:
+      expected = buf + size;
+      break;
+    case 1:
+      expected = (size > 1 && offset < size - 1) ? buf + offset : NULL;
+      break;
+    case 2:
+      expected = offset < size ? buf + size - 1 : NULL;
+      break;
+    default:
+      expected = NULL;
+      break;
+    }
+  if (size)
+    {
+      memset (buf, 1, size - 1);
+      buf[size - 1] = 2;
+    }
+  buf[size] = 0;
+  buf += offset;
+  while (repeat--)
+    assert (TEST_STRCHR (buf, goal) == expected);
+  buf -= offset;
+  free (buf);
+}
+
+int
+main (int argc, char **argv)
+{
+  if (argc == 2 && strcmp (argv[1], "--all") == 0)
+    {
+      int i, j, k;
+
+      /* Ensure all alignments for both start and target work.  */
+      for (i = 0; i <= 32; i++)
+        for (j = 0; j < i; j++)
+          for (k = 0; k <= 3; k++)
+            test (i, 1, j, k);
+      /* Multiple runs to make timing easier.  */
+      test (1000000, 1000, 0, 0);
+      test (1000000, 1000, 1, 0);
+      test (1000000, 1000, 0, 1);
+      test (1000000, 1000, 1, 1);
+      test (1000000, 1000, 0, 2);
+      test (1000000, 1000, 1, 2);
+      test (1000000, 1000, 0, 3);
+      test (1000000, 1000, 1, 3);
+      return 0;
+    }
+  if (argc < 5)
+    {
+      printf ("usage: %s --all\n", argv[0]);
+      printf ("   or: %s size repeat offset goal\n", argv[0]);
+      printf ("\t--all - run a canned set of tests\n");
+      printf ("\tsize - buffer size to search in\n");
+      printf ("\trepeat - times to repeat search\n");
+      printf ("\toffset - offset within buf to start search, <= size\n");
+      printf ("\tgoal - 0 for end, 1 for beginning, 2 for next to last, 3 for 
miss\n");
+      return 1;
+    }
+  size_t size = strtol (argv[1], NULL, 0);
+  size_t repeat = strtol (argv[2], NULL, 0);
+  size_t offset = strtol (argv[3], NULL, 0);
+  int goal = strtol (argv[4], NULL, 0);
+  if (!repeat)
+    repeat = 1;
+  if (size < offset)
+    offset = size;
+  test (size, repeat, offset, goal);
+  return 0;
+}
+
+#endif /* _REGRESSION_TEST */





More information about the Newlib mailing list