Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #979 from schveiguy/issue13410
Browse files Browse the repository at this point in the history
issue 13410 -- Performance problem with associative array byKey/byValue
  • Loading branch information
MartinNowak committed Oct 10, 2014
2 parents b51b752 + 5b3c9c4 commit 7cb7307
Showing 1 changed file with 46 additions and 10 deletions.
56 changes: 46 additions & 10 deletions src/rt/aaA.d
Expand Up @@ -69,11 +69,30 @@ struct Impl
{
Entry*[] buckets;
size_t nodes; // total number of entries
size_t firstUsedBucket; // starting index for first used bucket.
TypeInfo _keyti;
Entry*[4] binit; // initial value of buckets[]

@property const(TypeInfo) keyti() const @safe pure nothrow @nogc
{ return _keyti; }

// helper function to determine first used bucket, and update implementation's cache for it
// NOTE: will not work with immutable AA in ROM, but that doesn't exist yet.
size_t firstUsedBucketCache() @safe pure nothrow @nogc
in
{
assert(firstUsedBucket < buckets.length);
foreach(i; 0 .. firstUsedBucket)
assert(buckets[i] is null);
}
body
{
size_t i;
for(i = firstUsedBucket; i < buckets.length; ++i)
if(buckets[i] !is null)
break;
return firstUsedBucket = i;
}
}

/* This is the type actually seen by the programmer, although
Expand Down Expand Up @@ -162,6 +181,7 @@ body
if (aa.impl is null)
{ aa.impl = new Impl();
aa.impl.buckets = aa.impl.binit[];
aa.impl.firstUsedBucket = aa.impl.buckets.length;
}
//printf("aa = %p\n", aa);
//printf("aa.a = %p\n", aa.a);
Expand Down Expand Up @@ -200,6 +220,11 @@ body
//printf("rehash\n");
_aaRehash(aa,keyti);
}
else
{
// update cache if necessary
if (i < aa.impl.firstUsedBucket) aa.impl.firstUsedBucket = i;
}
}

Lret:
Expand Down Expand Up @@ -304,7 +329,9 @@ bool _aaDelX(AA aa, in TypeInfo keyti, in void* pkey)
if (keyti.equals(pkey, e + 1))
{
*pe = e.next;
aa.impl.nodes--;
if(!(--aa.impl.nodes))
// reset cache, we know there are no nodes in the aa.
aa.impl.firstUsedBucket = aa.impl.buckets.length;
GC.free(e);
return true;
}
Expand Down Expand Up @@ -332,7 +359,7 @@ inout(ArrayRet_t) _aaValues(inout AA aa, in size_t keysize, in size_t valuesize)
a.ptr = cast(byte*) GC.malloc(a.length * valuesize,
valuesize < (void*).sizeof ? GC.BlkAttr.NO_SCAN : 0);
resi = 0;
foreach (inout(Entry)* e; aa.impl.buckets)
foreach (inout(Entry)* e; aa.impl.buckets[aa.impl.firstUsedBucket..$])
{
while (e)
{
Expand Down Expand Up @@ -380,15 +407,18 @@ body
}
len = prime_list[i];
newImpl.buckets = newBuckets(len);
newImpl.firstUsedBucket = newImpl.buckets.length;

foreach (e; oldImpl.buckets)
foreach (e; oldImpl.buckets[oldImpl.firstUsedBucket..$])
{
while (e)
{ auto enext = e.next;
const j = e.hash % len;
e.next = newImpl.buckets[j];
newImpl.buckets[j] = e;
e = enext;
if(j < newImpl.firstUsedBucket)
newImpl.firstUsedBucket = j;
}
}
if (oldImpl.buckets.ptr == oldImpl.binit.ptr)
Expand All @@ -406,9 +436,10 @@ body
if (paa.impl.buckets.ptr != paa.impl.binit.ptr)
GC.free(paa.impl.buckets.ptr);
paa.impl.buckets = paa.impl.binit[];
paa.impl.firstUsedBucket = paa.impl.buckets.length; // start out with the cache at the end
}
}
return (*paa).impl;
return paa.impl;
}

/********************************************
Expand All @@ -424,7 +455,8 @@ inout(ArrayRet_t) _aaKeys(inout AA aa, in size_t keysize) pure nothrow
auto res = (cast(byte*) GC.malloc(len * keysize, blkAttr))[0 .. len * keysize];

size_t resi = 0;
foreach (inout(Entry)* e; aa.impl.buckets)
// note, can't use firstUsedBucketCache here, aa is inout
foreach (inout(Entry)* e; aa.impl.buckets[aa.impl.firstUsedBucket..$])
{
while (e)
{
Expand Down Expand Up @@ -513,7 +545,7 @@ int _aaApply(AA aa, in size_t keysize, dg_t dg)
immutable alignsize = aligntsize(keysize);
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.impl, keysize, dg);

foreach (e; aa.impl.buckets)
foreach (e; aa.impl.buckets[aa.impl.firstUsedBucketCache .. $])
{
while (e)
{
Expand All @@ -540,7 +572,7 @@ int _aaApply2(AA aa, in size_t keysize, dg2_t dg)

immutable alignsize = aligntsize(keysize);

foreach (e; aa.impl.buckets)
foreach (e; aa.impl.buckets[aa.impl.firstUsedBucketCache..$])
{
while (e)
{
Expand Down Expand Up @@ -586,6 +618,7 @@ Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, vo
}
auto len = prime_list[i];
result.buckets = newBuckets(len);
result.firstUsedBucket = result.buckets.length;

size_t keytsize = aligntsize(keysize);

Expand All @@ -597,6 +630,7 @@ Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, vo
auto key_hash = keyti.getHash(pkey);
//printf("hash = %d\n", key_hash);
i = key_hash % len;
if (i < result.firstUsedBucket) result.firstUsedBucket = i;
auto pe = &result.buckets[i];
while (1)
{
Expand Down Expand Up @@ -740,7 +774,8 @@ int _aaEqual(in TypeInfo tiRaw, in AA e1, in AA e2)
return 1; // this subtree matches
}

foreach (e; e1.impl.buckets)
// note, cannot use firstUsedBucketCache here, e1 is const
foreach (e; e1.impl.buckets[e1.impl.firstUsedBucket..$])
{
if (e)
{ if (_aaKeys_x(e) == 0)
Expand Down Expand Up @@ -770,7 +805,8 @@ hash_t _aaGetHash(in AA* aa, in TypeInfo tiRaw) nothrow
const valueti = ti.next;
const keysize = aligntsize(keyti.tsize);

foreach (const(Entry)* e; aa.impl.buckets)
// note, can't use firstUsedBucketCache here, aa is const
foreach (const(Entry)* e; aa.impl.buckets[aa.impl.firstUsedBucket..$])
{
while (e)
{
Expand Down Expand Up @@ -864,7 +900,7 @@ Range _aaRange(AA aa) pure nothrow @nogc
return res;

res.impl = aa.impl;
foreach (entry; aa.impl.buckets)
foreach (entry; aa.impl.buckets[aa.impl.firstUsedBucketCache .. $] )
{
if (entry !is null)
{
Expand Down

0 comments on commit 7cb7307

Please sign in to comment.