New GLib string routines



I'm about to add two new macros to GLib, g_strdup_a, and g_strconcat_a. 
By using alloca, they benchmark significantly faster than g_strdup and
g_strconcat.

Timing test results, strconcat test program, and patch are attached.

g_strconcat especially is used a great deal in gnome-libs and
gnome-core.  Maybe 50% or more of those probably can be replaced with
its _a counterpart.  In my slash&replace earlier today, I saw a lot of
code that looked like

	tmp = g_strconcat(s1, s2, NULL);
	call_some_function(tmp);
	g_free(tmp);

Code like that is ripe for speedup using these alloca macros.

The patch is close to commit-able, but a few issues/questions remain.

- code bombs if you don't have alloca.  should we include an
implementation of alloca in GLib, for those few systems that lack it? 
The only replacement implementation of alloca() I've seen requires the
app to call alloca(0) every so often, to do garbage collection.  Even
so, we should probably rename any included implementation to _g_alloca
or similar.

- The _a macros take an additional first arg, ie. new=g_strdup(old)
becomes g_strdup_a(new,old).  This is because of G_STMT_END
requirements.

	Jeff
g_strdup test:
[jgarzik@dog tmp]$ time ./testalloca-reg 
86.90user 0.01system 1:27.07elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (75major+16minor)pagefaults 0swaps

g_strdup_a test:
[jgarzik@dog tmp]$ time ./testalloca
53.87user 0.01system 0:53.99elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (71major+15minor)pagefaults 0swaps


g_strconcat test:
[jgarzik@dog tmp]$ time ./testalloca
71.46user 0.00system 1:11.54elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (85major+16minor)pagefaults 0swaps

g_strconcat_a test:
[jgarzik@dog tmp]$ time ./testalloca
33.98user 0.01system 0:34.01elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (70major+15minor)pagefaults 0swaps

#include <stdio.h>
#include <string.h>
#include <glib.h>

#define ITER 10000000L
#define TEST_STR	"desert planet "
#define FINAL_STR	"12345678lanet " TEST_STR TEST_STR

#ifdef TEST_REG

void run_test (void)
{
  gchar *s;

  s = g_strconcat(TEST_STR, TEST_STR, TEST_STR);
  strncpy(s, "123456789", 8);
  g_assert(strcmp(s, FINAL_STR) == 0);
  g_free(s);
}

#else

void run_test (void)
{
  gchar *s;

  g_strconcat_a(s, TEST_STR, TEST_STR, TEST_STR);
  strncpy(s, "123456789", 8);
  g_assert(strcmp(s, FINAL_STR) == 0);
}

#endif


int main()
{
  unsigned long i;

  for (i = 0; i < ITER; i++)
    run_test();

  return 0;
}

Index: configure.in
===================================================================
RCS file: /debian/home/gnomecvs/glib/configure.in,v
retrieving revision 1.52
diff -u -r1.52 configure.in
--- configure.in	1998/12/31 02:21:50	1.52
+++ configure.in	1998/12/31 03:03:47
@@ -168,6 +168,12 @@
 
 # Checks for library functions.
 AC_FUNC_VPRINTF
+AC_FUNC_ALLOCA
+if test "x$ac_cv_func_alloca_works" = xyes; then
+	glib_have_alloca=yes
+else
+	glib_have_alloca=no
+fi
 
 AC_CHECK_FUNCS(atexit on_exit)
 
@@ -245,6 +251,7 @@
 AC_CHECK_HEADERS(sys/times.h, AC_DEFINE(HAVE_SYS_TIMES_H))
 AC_CHECK_HEADERS(unistd.h, AC_DEFINE(HAVE_UNISTD_H))
 AC_CHECK_HEADERS(values.h, AC_DEFINE(HAVE_VALUES_H))
+AC_CHECK_HEADER(alloca.h, glib_have_alloca_h=yes, glib_have_alloca_h=no)
 
 # Check for some functions
 AC_CHECK_FUNCS(lstat strerror strsignal memmove vsnprintf strcasecmp strncasecmp poll)
@@ -866,6 +873,7 @@
 	cat >>$outfile <<_______EOF
 $glib_atexit
 $glib_memmove
+$glib_alloca
 $glib_defines
 
 $glib_vacopy
@@ -1127,6 +1135,43 @@
 if test x$glib_working_wctype = xno; then
   glib_wc="\$glib_wc
 #define G_HAVE_BROKEN_WCTYPE 1"
+fi
+
+if test x$glib_have_alloca = xyes; then
+  glib_alloca="
+
+/* alloca support */"
+
+  if test x$glib_have_alloca_h = xyes; then
+    glib_alloca='
+#define G_HAVE_ALLOCA_H 1'
+  fi
+
+  glib_alloca="\$glib_alloca
+#define G_HAVE_ALLOCA 1
+
+/* BEGIN autoconf 2.13 alloca incantation
+   	 NOTE: Do not un-indent the #pragma below. */
+/* AIX requires this to be the first thing in the file.  */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# if G_HAVE_ALLOCA_H
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+/* END autoconf 2.13 alloca incantation */
+
+
+"
 fi
 
 case x$enable_threads in
Index: glib.h
===================================================================
RCS file: /debian/home/gnomecvs/glib/glib.h,v
retrieving revision 1.99
diff -u -r1.99 glib.h
--- glib.h	1998/12/30 22:53:37	1.99
+++ glib.h	1998/12/31 03:03:53
@@ -1455,6 +1455,37 @@
 gpointer g_memdup		(gconstpointer mem,
 				 guint	       byte_size);
 
+/* Macros for dynamic strings via fast stack allocation
+ * All macros take a special first argument: the target gchar* string
+ */
+#if G_HAVE_ALLOCA
+
+#  define g_strdup_a(newstr,str) G_STMT_START { \
+	  const char *__old = (str);		\
+	  char *__new;				\
+	  size_t __len = strlen (__old) + 1;	\
+	  __new = alloca (__len);		\
+	  memcpy (__new, __old, __len);		\
+	  (newstr) = __new;			\
+   } G_STMT_END
+
+#  define g_strconcat_a(newstr,str1,str2,str3) G_STMT_START { \
+	  size_t __len1 = ((str1) == (gchar*)NULL) ? 0 : strlen((str1)); \
+	  size_t __len2 = ((str2) == (gchar*)NULL) ? 0 : strlen((str2)); \
+	  size_t __len3 = ((str3) == (gchar*)NULL) ? 0 : strlen((str3)); \
+	  char *__sptr, *__new = \
+	  	alloca (__len1 + __len2 + __len3 + 1); \
+	  __sptr = __new; \
+	  if (__len1){memcpy (__sptr, (str1), __len1); __sptr += __len1;} \
+	  if (__len2){memcpy (__sptr, (str2), __len2); __sptr += __len2;} \
+	  if (__len3){memcpy (__sptr, (str3), __len3); __sptr += __len3;} \
+	  *__sptr = '\0'; \
+	  (newstr) = __new; \
+   } G_STMT_END
+
+#endif /* G_HAVE_ALLOCA */
+
+
 /* NULL terminated string arrays.
  * g_strsplit() splits up string into max_tokens tokens at delim and
  * returns a newly allocated string array.
Index: testglib.c
===================================================================
RCS file: /debian/home/gnomecvs/glib/testglib.c,v
retrieving revision 1.16
diff -u -r1.16 testglib.c
--- testglib.c	1998/11/13 20:50:41	1.16
+++ testglib.c	1998/12/31 03:03:55
@@ -280,7 +280,7 @@
   gint morenums[10] = { 8, 9, 7, 0, 3, 2, 5, 1, 4, 6};
   gchar *string;
 
-  gchar *mem[10000], *tmp_string, *tmp_string_2;
+  gchar *mem[10000], *tmp_string = NULL, *tmp_string_2;
   gint i, j;
   GArray *garray;
   GPtrArray *gparray;


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