mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-13 23:11:41 +00:00
New TLSF, see #15
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
TLSF memory allocator
|
||||
=====================
|
||||
 TLSF
|
||||
=================
|
||||
|
||||
A port of [Matt Conte's implementation](https://github.com/mattconte/tlsf) of the [TLSF](http://www.gii.upv.es/tlsf/) memory allocator to AssemblyScript.
|
||||
An implementation of the [Two Level Segregate Fit](http://www.gii.upv.es/tlsf/main/docs)
|
||||
memory allocator in AssemblyScript.
|
||||
|
||||
Instructions
|
||||
------------
|
||||
|
@ -1,36 +0,0 @@
|
||||
tlsf.ts is based on https://github.com/mattconte/tlsf
|
||||
|
||||
Two Level Segregated Fit memory allocator, version 3.1.
|
||||
Written by Matthew Conte
|
||||
http://tlsf.baisoku.org
|
||||
|
||||
Based on the original documentation by Miguel Masmano:
|
||||
http://www.gii.upv.es/tlsf/main/docs
|
||||
|
||||
This implementation was written to the specification
|
||||
of the document, therefore no GPL restrictions apply.
|
||||
|
||||
Copyright (c) 2006-2016, Matthew Conte
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL MATTHEW CONTE BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
File diff suppressed because it is too large
Load Diff
@ -4,8 +4,8 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "npm run build:untouched && npm run build:optimized",
|
||||
"build:untouched": "asc assembly/tlsf.ts -t tlsf.untouched.wast -b tlsf.untouched.wasm --validate",
|
||||
"build:optimized": "asc -O3 assembly/tlsf.ts -b tlsf.optimized.wasm -t tlsf.optimized.wast --validate --noDebug --noAssert",
|
||||
"build:untouched": "asc assembly/tlsf.ts -t tlsf.untouched.wast -b tlsf.untouched.wasm --validate --sourceMap --measure",
|
||||
"build:optimized": "asc -O3 assembly/tlsf.ts -b tlsf.optimized.wasm -t tlsf.optimized.wast --validate --noDebug --noAssert --sourceMap --measure",
|
||||
"test": "node tests"
|
||||
}
|
||||
}
|
||||
|
@ -1,61 +1,28 @@
|
||||
var fs = require("fs");
|
||||
|
||||
function test(file) {
|
||||
console.log("Testing '" + file + "' ...");
|
||||
var runner = require("./runner");
|
||||
|
||||
var tlsf = new WebAssembly.Instance(WebAssembly.Module(fs.readFileSync(__dirname + "/../" + file)), {
|
||||
function test(file) {
|
||||
console.log("Testing '" + file + "' ...\n");
|
||||
|
||||
var exports = new WebAssembly.Instance(WebAssembly.Module(fs.readFileSync(__dirname + "/../" + file)), {
|
||||
env: {
|
||||
log_i: function(i) { i == -1 ? console.log("---") : console.log("log_i -> " + i); }
|
||||
abort: function(msg, file, line, column) {
|
||||
throw Error("Assertion failed: " + (msg ? "'" + getString(msg) + "' " : "") + "at " + getString(file) + ":" + line + ":" + column);
|
||||
},
|
||||
log: function(ptr) { console.log(getString(ptr)); },
|
||||
logi: function(i) { console.log(i); }
|
||||
}
|
||||
}).exports;
|
||||
|
||||
try {
|
||||
var memSize = 0;
|
||||
var ptr = 0;
|
||||
for (var j = 0; j < 10000; ++j) {
|
||||
if (!j || !((j + 1) % 1000))
|
||||
console.log("run #" + (j + 1));
|
||||
ptr;
|
||||
var ptrs = [];
|
||||
// allocate some blocks of unusual sizes
|
||||
for (var i = 0; i < 2048; ++i) {
|
||||
var size = i * 61;
|
||||
ptr = tlsf.allocate_memory(size);
|
||||
if (tlsf.set_memory)
|
||||
tlsf.set_memory(ptr, ptr % 256, size); // slow
|
||||
// immediately free every 4th
|
||||
if (!(i % 4)) {
|
||||
tlsf.free_memory(ptr);
|
||||
} else {
|
||||
ptrs.push(ptr);
|
||||
// randomly free random blocks (if not the first run that determines max memory)
|
||||
if (j && Math.random() < 0.25) {
|
||||
ptr = ptrs.splice((Math.random() * ptrs.length)|0, 1)[0];
|
||||
tlsf.free_memory(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tlsf.check)
|
||||
tlsf.check();
|
||||
if (tlsf.check_pool)
|
||||
tlsf.check_pool(0);
|
||||
// clean up by randomly freeing all blocks
|
||||
while (ptrs.length) {
|
||||
ptr = ptrs.splice((Math.random() * ptrs.length)|0, 1)[0];
|
||||
tlsf.free_memory(ptr);
|
||||
}
|
||||
if (memSize && memSize != tlsf.memory.buffer.byteLength)
|
||||
throw new Error("memory should not grow multiple times: " + memSize + " != " + tlsf.memory.buffer.byteLength);
|
||||
memSize = tlsf.memory.buffer.byteLength;
|
||||
if (tlsf.check)
|
||||
tlsf.check();
|
||||
if (tlsf.check_pool)
|
||||
tlsf.check_pool(0);
|
||||
}
|
||||
} finally {
|
||||
// mem(tlsf.memory, 0, 4096);
|
||||
console.log("memSize=" + memSize);
|
||||
function getString(ptr) {
|
||||
var len = new Uint32Array(exports.memory.buffer, ptr)[0];
|
||||
var str = new Uint16Array(exports.memory.buffer, ptr + 4).subarray(0, len);
|
||||
return String.fromCharCode.apply(String, str);
|
||||
}
|
||||
|
||||
runner(exports, 10, 20000); // picked so I/O isn't the bottleneck
|
||||
console.log("mem final: " + exports.memory.buffer.byteLength);
|
||||
console.log();
|
||||
}
|
||||
|
||||
|
91
examples/tlsf/tests/runner.js
Normal file
91
examples/tlsf/tests/runner.js
Normal file
@ -0,0 +1,91 @@
|
||||
function runner(tlsf, runs, allocs) {
|
||||
var ptrs = [];
|
||||
|
||||
function randomAlloc(maxSize) {
|
||||
if (!maxSize) maxSize = 8192;
|
||||
var size = ((Math.random() * maxSize) >>> 0) + 1;
|
||||
size = (size + 3) & ~3;
|
||||
var ptr = tlsf.allocate_memory(size);
|
||||
if (!ptr) throw Error();
|
||||
if (ptrs.indexOf(ptr) >= 0) throw Error();
|
||||
if (tlsf.set_memory)
|
||||
tlsf.set_memory(ptr, 0xdc, size);
|
||||
ptrs.push(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function preciseFree(ptr) {
|
||||
var idx = ptrs.indexOf(ptr);
|
||||
if (idx < 0) throw Error();
|
||||
var ptr = ptrs[idx];
|
||||
ptrs.splice(idx, 1);
|
||||
if (typeof ptr !== "number") throw Error();
|
||||
tlsf.free_memory(ptr);
|
||||
}
|
||||
|
||||
function randomFree() {
|
||||
var idx = (Math.random() * ptrs.length) >>> 0;
|
||||
var ptr = ptrs[idx];
|
||||
if (typeof ptr !== "number") throw Error();
|
||||
ptrs.splice(idx, 1);
|
||||
tlsf.free_memory(ptr);
|
||||
}
|
||||
|
||||
// remember the smallest possible memory address
|
||||
var base = tlsf.allocate_memory(64);
|
||||
console.log("base: " + base);
|
||||
tlsf.free_memory(base);
|
||||
console.log("mem initial: " + tlsf.memory.buffer.byteLength);
|
||||
|
||||
for (var j = 0; j < runs; ++j) {
|
||||
console.log("run " + (j + 1) + " (" + allocs + " allocations) ...");
|
||||
for (var i = 0; i < allocs; ++i) {
|
||||
var ptr = randomAlloc();
|
||||
|
||||
// immediately free every 4th
|
||||
if (!(i % 4)) preciseFree(ptr);
|
||||
|
||||
// occasionally free random blocks
|
||||
else if (ptrs.length && Math.random() < 0.33) randomFree();
|
||||
|
||||
// ^ sums up to clearing about half the blocks half-way
|
||||
}
|
||||
// free the rest, randomly
|
||||
while (ptrs.length) randomFree();
|
||||
|
||||
// should now be possible to reuse the entire first page (remember: sl+1)
|
||||
// e.g. with base 3088 (3048 optimized due to static memory):
|
||||
var size = 0x10000 - base - 4 - 1008;
|
||||
// 61436 (1110111111111100b) -> fl = 15, sl = 27
|
||||
// 61437 (61440 aligned, 1111000000000000b) -> fl = 15, sl = 28
|
||||
// NOTE that this calculation will be different if static memory changes
|
||||
var ptr = tlsf.allocate_memory(size);
|
||||
tlsf.set_memory(ptr, 0xac, size);
|
||||
if (ptr !== base) throw Error("expected " + base + " but got " + ptr);
|
||||
tlsf.free_memory(ptr);
|
||||
}
|
||||
|
||||
mem(tlsf.memory, 0, 0x10000); // should end in 02 00 00 00 (tail LEFT_FREE)
|
||||
}
|
||||
|
||||
function mem(memory, offset, count) {
|
||||
if (!offset) offset = 0;
|
||||
if (!count) count = 1024;
|
||||
var mem = new Uint8Array(memory.buffer, offset);
|
||||
var stackTop = new Uint32Array(memory.buffer, 4, 1)[0];
|
||||
var hex = [];
|
||||
for (var i = 0; i < count; ++i) {
|
||||
var o = (offset + i).toString(16);
|
||||
while (o.length < 4) o = "0" + o;
|
||||
if ((i & 15) === 0) {
|
||||
hex.push("\n" + o + ":");
|
||||
}
|
||||
var h = mem[i].toString(16);
|
||||
if (h.length < 2) h = "0" + h;
|
||||
hex.push(h);
|
||||
}
|
||||
console.log(hex.join(" ") + " ...");
|
||||
}
|
||||
|
||||
if (typeof module === "object" && typeof exports === "object")
|
||||
module.exports = runner;
|
Reference in New Issue
Block a user