assembly for _d_arrayappendcT using the original byte[] copy
text/plain
1932
Comments
Comment #0 by lio+bugzilla — 2008-08-25T10:09:30Z
See original thread.
Appending an element to an array is very slow. There are three reasons:
1) __d_arrayappendcT is used for all types of arrays, resulting in less than optimal performance when sizeof(item) > 1;
2) std.gc.capacity calls sizeOfNoSync which in turn calls findPool. Complexity of this call is O(m+n), n = number of pools, m = size of block;
3) sizeOfNoSync records the last result in a (global) cache to improve the performance of the case "for() ar~=item;" When appending to two arrays, this cache is useless, resulting in the O(m+n) code path described above.
A possible solution to 1) might be to create custom append routines for each array type (similar to the custom routines for the array operations, comparison, hashing, etc.) This way, an array of int[] can simply add an int. Or, the __d_arrayappendcT code should check the size of the item and invoke different code (possibly using mmx/sse when applicable.)
2) might be solved by using the fact that pooltable is always sorted; this would bring the complexity down to O(m + log n). Ideally the size for each allocation is recorded, either in a separate array (per pool) or right before the allocation itself. This would result in a complexity of O(log n) resp. O(1), minimizing the impact of the cache miss as mentioned in 3).
Comment #1 by lio+bugzilla — 2008-08-26T09:41:53Z
Some stats. Using bearophile's test program from the original post in newsgroup, with n = 100_000_000:
dmd v2.018 -O -inline -release
Default Phobos: 10,72 seconds
Commented gc.d line 915: 4,26 seconds
Replaced line 915 with memcpy: 5,63 seconds
Line 915 is:
# x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
where both x and argp are byte[]
Why is byte[] = byte[] slower than memcpy? Perhaps that array assignment should also be part of the run-time library, perhaps just using memcpy?
Comment #2 by lio+bugzilla — 2008-08-26T10:58:33Z
For the record, when changing the loop to..
#int count = 0;
#for(int i; i < n; i++) a[count++] = i;
..it takes 0,43 seconds. (Same flags, n as before.)
Adding std.gc.capacity(a.ptr) to the loop: 2,73 seconds.