tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Small ld.elf_so speed up



On Thu, 1 Apr 2010 18:04:55 +0200
Joerg Sonnenberger <joerg%britannica.bec.de@localhost> wrote:

> On Thu, Apr 01, 2010 at 04:44:20PM +0100, Sad Clouds wrote:
> > What does contribute to application load time? Is it the number of
> > shared libraries the application is linked to, or the number of
> > symbols exported by those libraries?
> 
> In this case, primary the number of (external) symbols referenced.
> The number of symbols exported by itself doesn't matter. The number of
> shared libraries matters in so far, as more hash steps might be
> needed.
> 
> Joerg

So, if you have an application that is linked to a total of 10 shared
libraries. Each of those libraries exports 50 symbols. The application
references all of those symbols, that is 10 * 50 = 500 symbols. This
then increases load time.

What if the application and the libraries were designed in the
following way:

Each library exports only 2 symbols:

libname_init() and libname_destroy()

All other symbols are declared as 'static' and not visible outside the
compilation unit.

The library init() function initialises pointers to private symbols
(the ones declared 'static'), so that application can access them.

For example:

/* libtest.so */

typedef struct test *test_t;

struct test
{
        void (*function_01)();
        void (*function_02)();
        ...
        void (*function_50)();
};

test_init(test_t *handle)
{
        *handle = malloc(sizeof(struct test));

        (*handle)->function_01 = &function_01_private;
        (*handle)->function_02 = &function_02_private;
        ...
        (*handle)->function_50 = &function_50_private;
}

test_destroy(test_t *handle)
{
        free(*handle);
        *handle = NULL;
}

The application then would use the library in the following way:

/* Application */

#include <libtest.h>
static test_t test;

int main(void)
{
        test_init(&test);

        /* Call library functions */
        test->function_01();
        ...

        test_destroy(&test);
}

I don't know how dynamic linker is implemented, but I've been
developing some of my packages/libraries as described above. I also
added calls to pthread_mutex_lock() to make package init() and
destroy() functions thread-safe.

I don't know how much faster application load time would be with large
sets of symbols, however my motivation for doing this was:

1. Since most symbols are private and declared as 'static', this
removes the chance of name clashes.

2. Library init() and destroy() calls can be coded to transparently use
dlopen interface, to load/unload shared objects on request, without
signficant source code changes. The library design also cuts down on
the number of dlsym() calls.

3. It is probably easier to keep backward compatibility and correctness
when upgrading libraries, because symbol binding is done dynamically,
via pointer assignments. You can add a second argument to init() and
destroy() functions, which provides library version number.


Home | Main Index | Thread Index | Old Index