From 3fd49cc1753c81766e596866bb09cc3a43631f55 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Thu, 13 May 2021 20:55:23 -0400 Subject: [PATCH 1/4] Improve OutBuffer's allocation strategy --- src/dmd/backend/outbuf.d | 73 ++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/src/dmd/backend/outbuf.d b/src/dmd/backend/outbuf.d index 99f3814d2272..534a2ae32ea0 100644 --- a/src/dmd/backend/outbuf.d +++ b/src/dmd/backend/outbuf.d @@ -28,9 +28,9 @@ struct Outbuffer { @safe: - ubyte *buf; // the buffer itself - ubyte *pend; // pointer past the end of the buffer - private ubyte *p; // current position in buffer + ubyte *buf; // the buffer itself + private ubyte *pend; // pointer past the end of the buffer + private ubyte *p; // current position in buffer nothrow: this(size_t initialSize) @@ -43,8 +43,8 @@ struct Outbuffer @trusted void dtor() { - if (auto slice = this.extractSlice()) - free(slice.ptr); + free(buf); + buf = p = pend = null; } void reset() @@ -52,8 +52,7 @@ struct Outbuffer p = buf; } - // Returns: A slice to the data written so far - extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout + private extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout @trusted pure nothrow @nogc { assert(this.buf, "Attempt to dereference a null pointer"); @@ -62,10 +61,10 @@ struct Outbuffer return this.buf[from .. to]; } - /// Ditto + // Returns: A slice to the data written so far extern(D) inout(ubyte)[] opSlice() inout @trusted pure nothrow @nogc { - return this.buf[0 .. this.p - this.buf]; + return this.buf[0 .. length]; } extern(D) ubyte[] extractSlice() @safe pure nothrow @nogc @@ -90,31 +89,41 @@ struct Outbuffer // Reserve nbytes in buffer @trusted - void enlarge(size_t nbytes) + private void enlarge(size_t nbytes) { pragma(inline, false); // do not inline slow path - const size_t oldlen = pend - buf; - const size_t used = p - buf; - size_t len = used + nbytes; - // No need to reallocate - if (nbytes < (pend - p)) - return; + debug assert(nbytes > pend - p, "You should call this function from reserve() only."); - const size_t newlen = oldlen + (oldlen >> 1); // oldlen * 1.5 - if (len < newlen) - len = newlen; - len = (len + 15) & ~15; + if (buf is null) + { + // Special-case the overwhelmingly most frequent situation + if (nbytes < 64) nbytes = 64; + p = buf = cast(ubyte*) malloc(nbytes); + pend = buf + nbytes; + } + else + { + const size_t used = p - buf; + const size_t oldlen = pend - buf; + // Ensure exponential growth, oldlen * 2 for small sizes, oldlen * 1.5 for big sizes + const size_t minlen = oldlen + (oldlen >> (oldlen > 1024 * 64)); - buf = cast(ubyte*) realloc(buf,len); + size_t len = used + nbytes; + if (len < minlen) + len = minlen; + // Round up to cache line size + len = (len + 63) & ~63; + + buf = cast(ubyte*) realloc(buf, len); + + pend = buf + len; + p = buf + used; + } if (!buf) err_nomem(); - - pend = buf + len; - p = buf + used; } - // Write n zeros; return pointer to start of zeros @trusted void *writezeros(size_t n) @@ -207,7 +216,7 @@ struct Outbuffer * Writes a 32 bit int, no reserve check. */ @trusted - void write32n(int v) + private void write32n(int v) { *cast(int *)p = v; p += 4; @@ -226,7 +235,7 @@ struct Outbuffer * Writes a 64 bit long, no reserve check */ @trusted - void write64n(long v) + private void write64n(long v) { *cast(long *)p = v; p += 8; @@ -245,7 +254,7 @@ struct Outbuffer * Writes a 32 bit float. */ @trusted - void writeFloat(float v) + private void writeFloat(float v) { reserve(float.sizeof); *cast(float *)p = v; @@ -256,7 +265,7 @@ struct Outbuffer * Writes a 64 bit double. */ @trusted - void writeDouble(double v) + private void writeDouble(double v) { reserve(double.sizeof); *cast(double *)p = v; @@ -298,7 +307,7 @@ struct Outbuffer * Inserts string at beginning of buffer. */ @trusted - void prependBytes(const(char)* s) + private void prependBytes(const(char)* s) { prepend(s, strlen(s)); } @@ -307,7 +316,7 @@ struct Outbuffer * Inserts bytes at beginning of buffer. */ @trusted - void prepend(const(void)* b, size_t len) + private void prepend(const(void)* b, size_t len) { reserve(len); memmove(buf + len,buf,p - buf); @@ -319,7 +328,7 @@ struct Outbuffer * Bracket buffer contents with c1 and c2. */ @trusted - void bracket(char c1,char c2) + private void bracket(char c1,char c2) { reserve(2); memmove(buf + 1,buf,p - buf); From b9faefddf7f040718a0de0007af897956d952bd3 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Fri, 14 May 2021 11:15:57 -0400 Subject: [PATCH 2/4] Remove cruft --- src/dmd/backend/outbuf.d | 86 +++------------------------------------- 1 file changed, 6 insertions(+), 80 deletions(-) diff --git a/src/dmd/backend/outbuf.d b/src/dmd/backend/outbuf.d index 534a2ae32ea0..d0f29dca9a14 100644 --- a/src/dmd/backend/outbuf.d +++ b/src/dmd/backend/outbuf.d @@ -212,64 +212,24 @@ struct Outbuffer write16n(v); } - /** - * Writes a 32 bit int, no reserve check. - */ - @trusted - private void write32n(int v) - { - *cast(int *)p = v; - p += 4; - } - /** * Writes a 32 bit int. */ - void write32(int v) + @trusted void write32(int v) { reserve(4); - write32n(v); - } - - /** - * Writes a 64 bit long, no reserve check - */ - @trusted - private void write64n(long v) - { - *cast(long *)p = v; - p += 8; + *cast(int *)p = v; + p += 4; } /** * Writes a 64 bit long. */ - void write64(long v) + @trusted void write64(long v) { reserve(8); - write64n(v); - } - - /** - * Writes a 32 bit float. - */ - @trusted - private void writeFloat(float v) - { - reserve(float.sizeof); - *cast(float *)p = v; - p += float.sizeof; - } - - /** - * Writes a 64 bit double. - */ - @trusted - private void writeDouble(double v) - { - reserve(double.sizeof); - *cast(double *)p = v; - p += double.sizeof; + *cast(long *)p = v; + p += 8; } /** @@ -303,40 +263,6 @@ struct Outbuffer writeString(cast(const(char)[])(s)); } - /** - * Inserts string at beginning of buffer. - */ - @trusted - private void prependBytes(const(char)* s) - { - prepend(s, strlen(s)); - } - - /** - * Inserts bytes at beginning of buffer. - */ - @trusted - private void prepend(const(void)* b, size_t len) - { - reserve(len); - memmove(buf + len,buf,p - buf); - memcpy(buf,b,len); - p += len; - } - - /** - * Bracket buffer contents with c1 and c2. - */ - @trusted - private void bracket(char c1,char c2) - { - reserve(2); - memmove(buf + 1,buf,p - buf); - buf[0] = c1; - p[1] = c2; - p += 2; - } - /** * Returns the number of bytes written. */ From bd158a3ba404be8fce0421f7a9b4749ff779f112 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Fri, 14 May 2021 12:44:28 -0400 Subject: [PATCH 3/4] Make enlarge a local function inside reserve --- src/dmd/backend/outbuf.d | 68 +++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/dmd/backend/outbuf.d b/src/dmd/backend/outbuf.d index d0f29dca9a14..8e933bdd7533 100644 --- a/src/dmd/backend/outbuf.d +++ b/src/dmd/backend/outbuf.d @@ -82,46 +82,44 @@ struct Outbuffer */ void reserve(size_t nbytes) { - // Keep small so it is inlined - if (pend - p < nbytes) - enlarge(nbytes); - } - - // Reserve nbytes in buffer - @trusted - private void enlarge(size_t nbytes) - { - pragma(inline, false); // do not inline slow path - - debug assert(nbytes > pend - p, "You should call this function from reserve() only."); - - if (buf is null) - { - // Special-case the overwhelmingly most frequent situation - if (nbytes < 64) nbytes = 64; - p = buf = cast(ubyte*) malloc(nbytes); - pend = buf + nbytes; - } - else + // non-inline function for the heavy/infrequent reallocation case + @trusted static void enlarge(ref Outbuffer b, size_t nbytes) { - const size_t used = p - buf; - const size_t oldlen = pend - buf; - // Ensure exponential growth, oldlen * 2 for small sizes, oldlen * 1.5 for big sizes - const size_t minlen = oldlen + (oldlen >> (oldlen > 1024 * 64)); + pragma(inline, false); // do not inline slow path + + if (b.buf is null) + { + // Special-case the overwhelmingly most frequent situation + if (nbytes < 64) + nbytes = 64; + b.p = b.buf = cast(ubyte*) malloc(nbytes); + b.pend = b.buf + nbytes; + } + else + { + const size_t used = b.p - b.buf; + const size_t oldlen = b.pend - b.buf; + // Ensure exponential growth, oldlen * 2 for small sizes, oldlen * 1.5 for big sizes + const size_t minlen = oldlen + (oldlen >> (oldlen > 1024 * 64)); - size_t len = used + nbytes; - if (len < minlen) - len = minlen; - // Round up to cache line size - len = (len + 63) & ~63; + size_t len = used + nbytes; + if (len < minlen) + len = minlen; + // Round up to cache line size + len = (len + 63) & ~63; - buf = cast(ubyte*) realloc(buf, len); + b.buf = cast(ubyte*) realloc(b.buf, len); - pend = buf + len; - p = buf + used; + b.pend = b.buf + len; + b.p = b.buf + used; + } + if (!b.buf) + err_nomem(); } - if (!buf) - err_nomem(); + + // Keep small so it is inlined + if (pend - p < nbytes) + enlarge(this, nbytes); } // Write n zeros; return pointer to start of zeros From b873969261704d3262945071d65cbfd2d5284d13 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Sun, 16 May 2021 15:34:11 -0400 Subject: [PATCH 4/4] Re-add prependBytes, prepend, bracket --- src/dmd/backend/outbuf.d | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/dmd/backend/outbuf.d b/src/dmd/backend/outbuf.d index 8e933bdd7533..443fd3562a2a 100644 --- a/src/dmd/backend/outbuf.d +++ b/src/dmd/backend/outbuf.d @@ -261,6 +261,40 @@ struct Outbuffer writeString(cast(const(char)[])(s)); } + /** + * Inserts string at beginning of buffer. + */ + @trusted + void prependBytes(const(char)* s) + { + prepend(s, strlen(s)); + } + + /** + * Inserts bytes at beginning of buffer. + */ + @trusted + void prepend(const(void)* b, size_t len) + { + reserve(len); + memmove(buf + len,buf,p - buf); + memcpy(buf,b,len); + p += len; + } + + /** + * Bracket buffer contents with c1 and c2. + */ + @trusted + void bracket(char c1,char c2) + { + reserve(2); + memmove(buf + 1,buf,p - buf); + buf[0] = c1; + p[1] = c2; + p += 2; + } + /** * Returns the number of bytes written. */