ref: 9c70e61a54066bf48e9c93178e66442b527762d1
parent: 893f3f9233875f696ca5dd48f18ca670af4fa6e4
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Mar 20 17:56:21 EDT 2017
Add hysteresis around big allocations. We don't need anything fancy, just a fixed size chunk of recently allocated blocks. This should make big allocations blindingly fast for repeated allocations of a known size.
--- a/lib/std/bytealloc.myr
+++ b/lib/std/bytealloc.myr
@@ -36,6 +36,7 @@
var buckets : bucket[32] /* excessive */
var trace : bool
var tracefd : std.fd
+var cache : cacheelt[32]
type bucket = struct
sz : size /* aligned size */
@@ -57,6 +58,11 @@
next : chunk# /* the next chunk in the free list */
;;
+type cacheelt = struct
+ sz : std.size
+ p : byte#
+;;
+
const __init__ = {
for var i = 0; i < buckets.len && (Align << i) <= Bktmax; i++
bktinit(&buckets[i], Align << i)
@@ -116,16 +122,13 @@
const bytealloc = {sz
var bkt, p
- if (sz <= Bktmax)
+ if sz <= Bktmax
bkt = &buckets[bktnum(sz)]
lock(memlck)
p = bktalloc(bkt)
unlock(memlck)
else
- p = getmem(sz)
- if p == Failmem
- die("could not get memory\n")
- ;;
+ p = bigalloc(sz)
;;
if trace
lock(memlck)
@@ -151,7 +154,67 @@
bktfree(bkt, p)
unlock(memlck)
else
- freemem(p, sz)
+ bigfree(p, sz)
+ ;;
+}
+
+const bigalloc = {sz
+ var p
+
+ p = Failmem
+ sz = align(sz, Align)
+
+ /* check our cache */
+ lock(memlck)
+ for var i = 0; i < cache.len; i++
+ if sz > cache[i].sz
+ continue
+ ;;
+ p = cache[i].p
+ if cache[i].sz - sz >= Bktmax
+ cache[i].sz -= sz
+ cache[i].p = ((p : intptr) + (sz : intptr) : byte#)
+ ;;
+ break
+ ;;
+ unlock(memlck)
+ if p != Failmem
+ -> p
+ ;;
+
+ /* ok, lets give up and get memory from the os */
+ p = getmem(sz)
+ if p != Failmem
+ -> p
+ ;;
+ die("could not get memory\n")
+}
+
+const bigfree = {p, sz
+ var minsz, minp, minidx
+
+ minsz = sz
+ minp = p
+ minidx = -1
+ lock(memlck)
+ for var i = 0; i < cache.len; i++
+ if cache[i].sz < minsz
+ minsz = cache[i].sz
+ minp = cache[i].p
+ minidx = i
+ ;;
+ ;;
+ unlock(memlck)
+
+ /* size of 0 means we found a slot. */
+ if minsz == 0
+ -> void
+ ;;
+
+ freemem(minp, minsz)
+ if minidx >= 0
+ cache[minidx].p = p
+ cache[minidx].sz = sz
;;
}