In-place extension of arrays only for certain alignment?
Ali Çehreli
acehreli at yahoo.com
Tue Aug 16 18:11:54 UTC 2022
Related to my DConf 2022 lightning talk, I am noticing that D runtime's
in-place array extension optimization is available only for array data
that are at certain memory alignments.
I used the following program to test it. In addition to repeatedly
adding an element to an array,
- 'version = neither' does not drop any element (this is "good" as well)
- 'version = bad' case drops the front element (a moving window of 1)
- 'version = good' case drops elements only when element data will hit a
certain alignment value.
Is this expected?
import std.stdio;
import std.range;
// PLEASE UNCOMMENT ONLY ONE:
// version = bad; // No in-place extension
// version = good; // In-place extension happens
// version = neither; // In-place extension happens
mixin assertSingleVersionOf!("bad", "good", "neither");
void main() {
struct S {
ubyte[4] data; // Try different reasonable sizes.
// For example, 5 will not work even
// for the "good" case.
}
S[] arr;
foreach (i; 0 .. 100_000) {
const oldCap = arr.capacity;
const oldPtr = arr.ptr;
arr ~= S.init;
if (arr.capacity != oldCap) {
// The array needed to be extended...
if (arr.ptr == oldPtr) {
// ... but the pointer did not change
writefln!"In-place extension -- element: %,s capacity: %,s ->
%,s ptr: %s"(
i, oldCap, arr.capacity, arr.ptr);
}
}
version (neither) {
// Do not remove any element; just extend
}
version (bad) {
// Dropping 1 element inhibits in-place extension
// (Many values other than 1 will inhibit as well.)
arr = arr[1..$];
// Even this does not help
arr.assumeSafeAppend();
}
version (good) {
// Dropping front elements equaling 2048 bytes works.
// (Likely a GC magic constant.)
enum magic = 2048;
enum elementsPerPage = magic / S.sizeof;
if (arr.length == elementsPerPage) {
arr = arr[elementsPerPage..$];
}
}
}
}
// A useful template that has nothing to do with this problem.
mixin template assertSingleVersionOf(args...) {
import std.format : format;
static assert (1 >= {
size_t count = 0;
static foreach (arg; args) {
static assert (is (typeof(arg) == string));
mixin (format!q{
version (%s) {
++count;
}
}(arg));
}
return count;
}(), format!"Please pick only one or none of %(%s, %)"([args]));
}
Ali
More information about the Digitalmars-d-learn
mailing list