On 05.09.2015 02:53, Branko Čibej wrote:
> On 04.09.2015 21:17, stef...@apache.org wrote:
>> Author: stefan2
>> Date: Fri Sep  4 19:17:44 2015
>> New Revision: 1701317
>>
>> URL: http://svn.apache.org/r1701317
>> Log:
>> Finally, make svn_ra_svn__list_t actually a fully typed, ra_svn-specific
>> object.  Update the creation functions; everything else already "just fits".
> How is this code different from using APR arrays, except that the latter
> needs a typecast on array item access? As far as I can see, you've
> completely duplicated the APR array allocation strategy, including using
> two allocations to create the array.
>
> The only significant difference is that capacity is being tracked
> outside the svn_ra_svn__list_t structure during the construction of the
> list.
>
> Call me dense ... but can you please explain how exactly is this
> better/faster than using APR arrays? (I'm not going to mention 'safer'
> because it clearly isn't.) Code like this that is apparently meant be an
> optimisation of something(?) really should have a bit of an explanatory
> comment, IMO.

I played around with the apr_array_make implementation a bit and did
some performance measurements with small array allocation and usage,
with the following pattern:

  * in 60% of cases, the array does not get resized
  * in 30% it gets resized once
  * in 10% it gets resized twice

If I change apr_array_make to allocate the initial number of elements in
the same block as the array header, I get a 15% speedup on this test
case, compared to the default implementation. If I change it further to
never set the element values to 0 in apr_array_make, I get an additional
10% speedup, for a total of 23%. So I'm guessing this is the number you
were actually seeing.

We can certainly change APR to get that extra 15% in, but we can't
remove the memset(0) because it's part of the existing API semantics.
However we can add (in apr-1.6 and 2.0) a new constructor, e.g.
apr_array_make_uninitialized, that would not clear the element values.
This wouldn't help with apr_array_push, but note that there's already a
private function called apr_array_push_noclear that's used with apr_table_t

Obviously I'd much rather make these enhancements in APR than have yet
another custom allocation hack in Subversion.

-- Brane

#include <stdlib.h>

#include "apr_pools.h"
#include "apr_tables.h"

static void
test_array_alloc(apr_pool_t *pool)
{
    int i, j, k;
    for (i = 0; i < 50000; ++i)
    {
        apr_pool_clear(pool);
        for (j = 0; j < 10000; ++j)
        {
            const int nelts = ((j % 10 == 0) ? 11
                               : (j % 10 < 7) ? 3 : 7);
            apr_array_header_t *a = apr_array_make(pool, 4, 1);
            for (k = 0; k < nelts; ++k)
                APR_ARRAY_PUSH(a, char) = '\0';
        }
    }
}

int main(void)
{
    apr_pool_t *pool = NULL;

    if (apr_initialize())
        exit(1);
    atexit(apr_terminate);

    apr_pool_create(&pool, NULL);
    test_array_alloc(pool);
    return 0;
}

Reply via email to