This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[libobjc-branch] Optimize selector allocations
- From: Alexander Malmberg <alexander at malmberg dot org>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 27 Jan 2004 01:05:34 +0100
- Subject: [libobjc-branch] Optimize selector allocations
Hi,
libobjc currently allocates a lot of memory unnecessarily at startup.
This patch helps reduce this in two ways:
* class_add_method_list and __objc_register_selectors_from_class
register selectors through the sel_register_typed_name function, which
assumes that the strings passed to it need to be copied. This is
unnecessary. The patch avoids this copying by using
__sel_register_typed_name instead.
* __sel_register_typed_name allocates thousands of 8(/16)-byte struct
objc_selector:s during startup of an average GNUstep application. This
wastes a fair bit of memory in malloc overhead. Since these structures
are never deallocated, it's easy to pool allocations of them, and the
patch does this.
Together, the changes reduce the amount of memory allocated by libobjc
at startup of a GNUstep application by 120kb-150kb. Startup time should
also improve, but the difference isn't measurable.
Tested on i686-pc-linux-gnu with a 'make check-objc'; no new regressions
(some local patches, though).
ChangeLog entry:
2004-01-27 Alexander Malmberg <alexander@malmberg.org>
* selector.c: Rename register_selectors_from_list to
__objc_register_selectors_from_list. Update caller.
(__objc_register_selectors_from_list): Lock __objc_runtime_mutex
while registering selectors. Use __sel_register_typed_name instead
of sel_register_typed_name. Check for NULL method_name:s.
(pool_alloc_selector): New function.
(__sel_register_typed_name): Use pool_alloc_selector to allocate
selector structures.
* sendmsg.c (class_add_method_list): Use
__objc_register_selectors_from_list.
* objc/runtime.h: Add __objc_register_selectors_from_list.
- Alexander Malmberg
Index: selector.c
===================================================================
RCS file: /cvsroot/gcc/gcc/libobjc/selector.c,v
retrieving revision 1.7
diff -u -r1.7 selector.c
--- selector.c 15 Jan 2004 01:49:41 -0000 1.7
+++ selector.c 26 Jan 2004 23:56:17 -0000
@@ -35,8 +35,6 @@
static struct sarray *__objc_selector_names = 0; /* uid -> name !T:MUTEX */
static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
-static void register_selectors_from_list (MethodList_t);
-
/* Number of selectors stored in each of the above tables */
unsigned int __objc_selector_max_index = 0; /* !T:MUTEX */
@@ -60,7 +58,7 @@
method_list = class->methods;
while (method_list)
{
- register_selectors_from_list (method_list);
+ __objc_register_selectors_from_list (method_list);
method_list = method_list->method_next;
}
}
@@ -70,21 +68,27 @@
the record table. This is the routine that does the actual recording
work.
- This one is only called for Class objects. For categories,
- class_add_method_list is called.
+ The name and type pointers in the method list must be permanent and
+ immutable.
*/
-static void
-register_selectors_from_list (MethodList_t method_list)
+void
+__objc_register_selectors_from_list (MethodList_t method_list)
{
int i = 0;
+
+ objc_mutex_lock (__objc_runtime_mutex);
while (i < method_list->method_count)
{
Method_t method = &method_list->method_list[i];
- method->method_name
- = sel_register_typed_name ((const char *) method->method_name,
- method->method_types);
+ if (method->method_name)
+ {
+ method->method_name
+ = __sel_register_typed_name ((const char *) method->method_name,
+ method->method_types, 0, YES);
+ }
i += 1;
}
+ objc_mutex_unlock (__objc_runtime_mutex);
}
@@ -320,6 +324,35 @@
/* The uninstalled dispatch table */
extern struct sarray *__objc_uninstalled_dtable;
+/* __sel_register_typed_name allocates lots of struct objc_selector:s
+ of 8 (16, if pointers are 64 bits) bytes at startup. To reduce the number
+ of malloc calls and memory lost to malloc overhead, we allocate
+ objc_selector:s in blocks here. This is only called from
+ __sel_register_typed_name, and __sel_register_typed_name may only be
+ called when __objc_runtime_mutex is locked.
+
+ Note that the objc_selector:s allocated from __sel_register_typed_name
+ are never freed.
+
+ 62 because 62 * sizeof (struct objc_selector) = 496 (992). This should
+ let malloc add some overhead and use a nice, round 512 (1024) byte chunk.
+ */
+#define SELECTOR_POOL_SIZE 62
+static struct objc_selector *selector_pool;
+static int selector_pool_left;
+
+static struct objc_selector *
+pool_alloc_selector(void)
+{
+ if (!selector_pool_left)
+ {
+ selector_pool = objc_malloc (sizeof (struct objc_selector)
+ * SELECTOR_POOL_SIZE);
+ selector_pool_left = SELECTOR_POOL_SIZE;
+ }
+ return &selector_pool[--selector_pool_left];
+}
+
/* Store the passed selector name in the selector record and return its
selector value (value returned by sel_get_uid).
Assumes that the calling function has locked down __objc_runtime_mutex. */
@@ -369,7 +402,7 @@
if (orig)
j = orig;
else
- j = objc_malloc (sizeof (struct objc_selector));
+ j = pool_alloc_selector ();
j->sel_id = (void *) i;
/* Can we use the pointer or must copy types? Don't copy if NULL */
@@ -388,7 +421,7 @@
if (orig)
j = orig;
else
- j = objc_malloc (sizeof (struct objc_selector));
+ j = pool_alloc_selector ();
j->sel_id = (void *) i;
/* Can we use the pointer or must copy types? Don't copy if NULL */
@@ -446,7 +479,7 @@
sel_register_typed_name (const char *name, const char *type)
{
SEL ret;
-
+
objc_mutex_lock (__objc_runtime_mutex);
/* Assume that name and type are not constant static memory and need to
be copied before put into a runtime structure. is_const == NO */
Index: sendmsg.c
===================================================================
RCS file: /cvsroot/gcc/gcc/libobjc/sendmsg.c,v
retrieving revision 1.12.14.1
diff -u -r1.12.14.1 sendmsg.c
--- sendmsg.c 25 Jan 2004 19:11:44 -0000 1.12.14.1
+++ sendmsg.c 26 Jan 2004 23:56:18 -0000
@@ -465,28 +465,14 @@
This one is only called for categories. Class objects have their
methods installed right away, and their selectors are made into
- SEL's by the function __objc_register_selectors_from_class. */
+ SEL's by the function __objc_register_selectors_from_class. */
void
class_add_method_list (Class class, MethodList_t list)
{
- int i;
-
/* Passing of a linked list is not allowed. Do multiple calls. */
assert (! list->method_next);
- /* Check for duplicates. */
- for (i = 0; i < list->method_count; ++i)
- {
- Method_t method = &list->method_list[i];
-
- if (method->method_name) /* Sometimes these are NULL */
- {
- /* This is where selector names are transmogrified to SEL's */
- method->method_name =
- sel_register_typed_name ((const char *) method->method_name,
- method->method_types);
- }
- }
+ __objc_register_selectors_from_list(list);
/* Add the methods to the class's method list. */
list->method_next = class->methods;
Index: objc/runtime.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libobjc/objc/runtime.h,v
retrieving revision 1.4
diff -u -r1.4 runtime.h
--- objc/runtime.h 23 May 2003 20:04:58 -0000 1.4
+++ objc/runtime.h 26 Jan 2004 23:56:18 -0000
@@ -49,6 +49,7 @@
extern void __objc_install_premature_dtable(Class); /* (objc-dispatch.c) */
extern void __objc_resolve_class_links(void); /* (objc-class.c) */
extern void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */
+extern void __objc_register_selectors_from_list (MethodList_t);
extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */
extern int __objc_init_thread_system(void); /* thread.c */