Skip to content

Commit 3698269

Browse files
committed
Improve OutBuffer's allocation strategy
1 parent 86b117b commit 3698269

1 file changed

Lines changed: 41 additions & 32 deletions

File tree

src/dmd/backend/outbuf.d

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ struct Outbuffer
2828
{
2929
@safe:
3030

31-
ubyte *buf; // the buffer itself
32-
ubyte *pend; // pointer past the end of the buffer
33-
private ubyte *p; // current position in buffer
31+
ubyte *buf; // the buffer itself
32+
private ubyte *pend; // pointer past the end of the buffer
33+
private ubyte *p; // current position in buffer
3434

3535
nothrow:
3636
this(size_t initialSize)
@@ -43,17 +43,16 @@ struct Outbuffer
4343
@trusted
4444
void dtor()
4545
{
46-
if (auto slice = this.extractSlice())
47-
free(slice.ptr);
46+
free(buf);
47+
buf = p = pend = null;
4848
}
4949

5050
void reset()
5151
{
5252
p = buf;
5353
}
5454

55-
// Returns: A slice to the data written so far
56-
extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout
55+
private extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout
5756
@trusted pure nothrow @nogc
5857
{
5958
assert(this.buf, "Attempt to dereference a null pointer");
@@ -62,10 +61,10 @@ struct Outbuffer
6261
return this.buf[from .. to];
6362
}
6463

65-
/// Ditto
64+
// Returns: A slice to the data written so far
6665
extern(D) inout(ubyte)[] opSlice() inout @trusted pure nothrow @nogc
6766
{
68-
return this.buf[0 .. this.p - this.buf];
67+
return this.buf[0 .. length];
6968
}
7069

7170
extern(D) ubyte[] extractSlice() @safe pure nothrow @nogc
@@ -90,31 +89,41 @@ struct Outbuffer
9089

9190
// Reserve nbytes in buffer
9291
@trusted
93-
void enlarge(size_t nbytes)
92+
private void enlarge(size_t nbytes)
9493
{
9594
pragma(inline, false); // do not inline slow path
96-
const size_t oldlen = pend - buf;
97-
const size_t used = p - buf;
9895

99-
size_t len = used + nbytes;
100-
// No need to reallocate
101-
if (nbytes < (pend - p))
102-
return;
96+
debug assert(nbytes > pend - p, "You should call this function from reserve() only.");
10397

104-
const size_t newlen = oldlen + (oldlen >> 1); // oldlen * 1.5
105-
if (len < newlen)
106-
len = newlen;
107-
len = (len + 15) & ~15;
98+
if (buf is null)
99+
{
100+
// Special-case the overwhelmingly most frequent situation
101+
if (nbytes < 64) nbytes = 64;
102+
p = buf = cast(ubyte*) malloc(nbytes);
103+
pend = buf + nbytes;
104+
}
105+
else
106+
{
107+
const size_t used = p - buf;
108+
const size_t oldlen = pend - buf;
109+
// Ensure exponential growth, oldlen * 2 for small sizes, oldlen * 1.5 for big sizes
110+
const size_t minlen = oldlen + (oldlen >> (oldlen > 1024 * 64));
108111

109-
buf = cast(ubyte*) realloc(buf,len);
112+
size_t len = used + nbytes;
113+
if (len < minlen)
114+
len = minlen;
115+
// Round up to cache line size
116+
len = (len + 63) & ~63;
117+
118+
buf = cast(ubyte*) realloc(buf, len);
119+
120+
pend = buf + len;
121+
p = buf + used;
122+
}
110123
if (!buf)
111124
err_nomem();
112-
113-
pend = buf + len;
114-
p = buf + used;
115125
}
116126

117-
118127
// Write n zeros; return pointer to start of zeros
119128
@trusted
120129
void *writezeros(size_t n)
@@ -207,7 +216,7 @@ struct Outbuffer
207216
* Writes a 32 bit int, no reserve check.
208217
*/
209218
@trusted
210-
void write32n(int v)
219+
private void write32n(int v)
211220
{
212221
*cast(int *)p = v;
213222
p += 4;
@@ -226,7 +235,7 @@ struct Outbuffer
226235
* Writes a 64 bit long, no reserve check
227236
*/
228237
@trusted
229-
void write64n(long v)
238+
private void write64n(long v)
230239
{
231240
*cast(long *)p = v;
232241
p += 8;
@@ -245,7 +254,7 @@ struct Outbuffer
245254
* Writes a 32 bit float.
246255
*/
247256
@trusted
248-
void writeFloat(float v)
257+
private void writeFloat(float v)
249258
{
250259
reserve(float.sizeof);
251260
*cast(float *)p = v;
@@ -256,7 +265,7 @@ struct Outbuffer
256265
* Writes a 64 bit double.
257266
*/
258267
@trusted
259-
void writeDouble(double v)
268+
private void writeDouble(double v)
260269
{
261270
reserve(double.sizeof);
262271
*cast(double *)p = v;
@@ -298,7 +307,7 @@ struct Outbuffer
298307
* Inserts string at beginning of buffer.
299308
*/
300309
@trusted
301-
void prependBytes(const(char)* s)
310+
private void prependBytes(const(char)* s)
302311
{
303312
prepend(s, strlen(s));
304313
}
@@ -307,7 +316,7 @@ struct Outbuffer
307316
* Inserts bytes at beginning of buffer.
308317
*/
309318
@trusted
310-
void prepend(const(void)* b, size_t len)
319+
private void prepend(const(void)* b, size_t len)
311320
{
312321
reserve(len);
313322
memmove(buf + len,buf,p - buf);
@@ -319,7 +328,7 @@ struct Outbuffer
319328
* Bracket buffer contents with c1 and c2.
320329
*/
321330
@trusted
322-
void bracket(char c1,char c2)
331+
private void bracket(char c1,char c2)
323332
{
324333
reserve(2);
325334
memmove(buf + 1,buf,p - buf);

0 commit comments

Comments
 (0)