Skip to content

Commit 074939d

Browse files
authored
Merge pull request #12519 from andralex/outbuffer
Improve OutBuffer's allocation strategy
2 parents 749632d + b873969 commit 074939d

File tree

1 file changed

+50
-83
lines changed

1 file changed

+50
-83
lines changed

src/dmd/backend/outbuf.d

Lines changed: 50 additions & 83 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
@@ -83,38 +82,46 @@ struct Outbuffer
8382
*/
8483
void reserve(size_t nbytes)
8584
{
85+
// non-inline function for the heavy/infrequent reallocation case
86+
@trusted static void enlarge(ref Outbuffer b, size_t nbytes)
87+
{
88+
pragma(inline, false); // do not inline slow path
89+
90+
if (b.buf is null)
91+
{
92+
// Special-case the overwhelmingly most frequent situation
93+
if (nbytes < 64)
94+
nbytes = 64;
95+
b.p = b.buf = cast(ubyte*) malloc(nbytes);
96+
b.pend = b.buf + nbytes;
97+
}
98+
else
99+
{
100+
const size_t used = b.p - b.buf;
101+
const size_t oldlen = b.pend - b.buf;
102+
// Ensure exponential growth, oldlen * 2 for small sizes, oldlen * 1.5 for big sizes
103+
const size_t minlen = oldlen + (oldlen >> (oldlen > 1024 * 64));
104+
105+
size_t len = used + nbytes;
106+
if (len < minlen)
107+
len = minlen;
108+
// Round up to cache line size
109+
len = (len + 63) & ~63;
110+
111+
b.buf = cast(ubyte*) realloc(b.buf, len);
112+
113+
b.pend = b.buf + len;
114+
b.p = b.buf + used;
115+
}
116+
if (!b.buf)
117+
err_nomem();
118+
}
119+
86120
// Keep small so it is inlined
87121
if (pend - p < nbytes)
88-
enlarge(nbytes);
122+
enlarge(this, nbytes);
89123
}
90124

91-
// Reserve nbytes in buffer
92-
@trusted
93-
void enlarge(size_t nbytes)
94-
{
95-
pragma(inline, false); // do not inline slow path
96-
const size_t oldlen = pend - buf;
97-
const size_t used = p - buf;
98-
99-
size_t len = used + nbytes;
100-
// No need to reallocate
101-
if (nbytes < (pend - p))
102-
return;
103-
104-
const size_t newlen = oldlen + (oldlen >> 1); // oldlen * 1.5
105-
if (len < newlen)
106-
len = newlen;
107-
len = (len + 15) & ~15;
108-
109-
buf = cast(ubyte*) realloc(buf,len);
110-
if (!buf)
111-
err_nomem();
112-
113-
pend = buf + len;
114-
p = buf + used;
115-
}
116-
117-
118125
// Write n zeros; return pointer to start of zeros
119126
@trusted
120127
void *writezeros(size_t n)
@@ -203,64 +210,24 @@ struct Outbuffer
203210
write16n(v);
204211
}
205212

206-
/**
207-
* Writes a 32 bit int, no reserve check.
208-
*/
209-
@trusted
210-
void write32n(int v)
211-
{
212-
*cast(int *)p = v;
213-
p += 4;
214-
}
215-
216213
/**
217214
* Writes a 32 bit int.
218215
*/
219-
void write32(int v)
216+
@trusted void write32(int v)
220217
{
221218
reserve(4);
222-
write32n(v);
223-
}
224-
225-
/**
226-
* Writes a 64 bit long, no reserve check
227-
*/
228-
@trusted
229-
void write64n(long v)
230-
{
231-
*cast(long *)p = v;
232-
p += 8;
219+
*cast(int *)p = v;
220+
p += 4;
233221
}
234222

235223
/**
236224
* Writes a 64 bit long.
237225
*/
238-
void write64(long v)
226+
@trusted void write64(long v)
239227
{
240228
reserve(8);
241-
write64n(v);
242-
}
243-
244-
/**
245-
* Writes a 32 bit float.
246-
*/
247-
@trusted
248-
void writeFloat(float v)
249-
{
250-
reserve(float.sizeof);
251-
*cast(float *)p = v;
252-
p += float.sizeof;
253-
}
254-
255-
/**
256-
* Writes a 64 bit double.
257-
*/
258-
@trusted
259-
void writeDouble(double v)
260-
{
261-
reserve(double.sizeof);
262-
*cast(double *)p = v;
263-
p += double.sizeof;
229+
*cast(long *)p = v;
230+
p += 8;
264231
}
265232

266233
/**

0 commit comments

Comments
 (0)