1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * A tiny hack to redirect all GC allocations to a fixed size arena.
20 * Say, you've got an operation that actively allocates in GC'ed heap but
21 * after it's complete you don't need anything it allocated. And you need
22 * to do it in a loop many times, potentially allocating lots of memory.
23 * Just add one line in the beginning of loop's scope and each iteration
24 * will reuse the same fixed size buffer.
27 * foreach (fname; files) {
28 * auto ar = useCleanArena(); // (1)
29 * auto img = readPng(fname).getAsTrueColorImage();
34 * Between points (1) and (2) all GC allocations will happen inside
35 * an arena which will be reused on each iteration. No GC will happen,
36 * no garbage accumulated.
38 * If you need some data created inbetween, you can temporarily pause
39 * using the arena and allocate something on main GC heap:
42 * auto ar = useCleanArena();
43 * auto s = new ubyte[100]; // allocated in arena
45 * auto pause = pauseArena(); // in this scope it's not used
46 * auto t = new ubyte[200]; // allocated in main GC heap
48 * auto v = new ubyte[300]; // allocated in arena again
50 * // end of scope, stop using arena
53 * You can set size for arena by calling setArenaSize() before its first use.
54 * Default size is 64 MB.
56 module iv
.gcarena
/*is aliced*/;
60 // ////////////////////////////////////////////////////////////////////////// //
61 void setArenaSize (usize totalSize
) {
62 gcaData
.arena_size
= totalSize
;
72 ~this () @trusted nothrow => stop();
74 void stop () @trusted nothrow {
80 @property usize
allocated () const @trusted nothrow @nogc => gcaData
.arena_pos
;
81 @property isStopped () pure const @safe nothrow @nogc => stopped
;
85 // use template to autodeduce attributes
86 auto useCleanArena() () {
87 gcaData
.arena_pos
= 0;
88 gcaData
.installProxy();
89 return ArenaHandler();
93 // use template to autodeduce attributes
94 auto pauseArena() () {
98 ~this () @trusted nothrow @nogc => gcaData
.installProxy();
104 // ////////////////////////////////////////////////////////////////////////// //
108 alias BlkInfo
= GC
.BlkInfo
;
110 // copied from proxy.d (d runtime)
113 void function () @trusted nothrow gc_enable
;
114 void function () @trusted nothrow gc_disable
;
115 void function () @trusted nothrow gc_collect
;
116 void function () @trusted nothrow gc_minimize
;
118 uint function (void*) @trusted nothrow gc_getAttr
;
119 uint function (void*, uint) @trusted nothrow gc_setAttr
;
120 uint function (void*, uint) @trusted nothrow gc_clrAttr
;
122 void* function (usize
, uint, const TypeInfo
) @trusted nothrow gc_malloc
;
123 BlkInfo
function (usize
, uint, const TypeInfo
) @trusted nothrow gc_qalloc
;
124 void* function (usize
, uint, const TypeInfo
) @trusted nothrow gc_calloc
;
125 void* function (void*, usize
, uint ba
, const TypeInfo
) @trusted nothrow gc_realloc
;
126 usize
function (void*, usize
, usize
, const TypeInfo
) @trusted nothrow gc_extend
;
127 usize
function (usize
) @trusted nothrow gc_reserve
;
128 void function (void*) @trusted nothrow gc_free
;
130 void* function (void*) @trusted nothrow gc_addrOf
;
131 usize
function (void*) @trusted nothrow gc_sizeOf
;
133 BlkInfo
function (void*) @trusted nothrow gc_query
;
135 void function (void*) @trusted nothrow gc_addRoot
;
136 void function (void*, usize
, const TypeInfo
) @trusted nothrow gc_addRange
;
138 void function (void*) @trusted nothrow gc_removeRoot
;
139 void function (void*) @trusted nothrow gc_removeRange
;
140 void function (in void[]) @trusted nothrow gc_runFinalizers
;
144 // ////////////////////////////////////////////////////////////////////////// //
147 Proxy
* pOrg
; // pointer to original Proxy of runtime
152 usize arena_size
= 64*1024*1024;
154 void initProxy () @trusted nothrow @nogc {
155 pOrg
= gc_getProxy();
156 pproxy
= cast(Proxy
**)(cast(byte*)pOrg
+Proxy
.sizeof
);
157 foreach (/*auto*/ funname
; __traits(allMembers
, Proxy
)) __traits(getMember
, myProxy
, funname
) = &genCall
!funname
;
158 myProxy
.gc_malloc
= &gca_malloc
;
159 myProxy
.gc_qalloc
= &gca_qalloc
;
160 myProxy
.gc_calloc
= &gca_calloc
;
163 void* alloc (usize size
) @trusted nothrow {
164 { import core
.stdc
.stdio
: printf
; printf("!!!\n"); }
165 if (arena_bytes
.length
== 0) {
166 auto oldproxy
= *pproxy
;
168 arena_bytes
= new ubyte[arena_size
];
171 if (arena_pos
+size
> arena_bytes
.length
) {
172 import core
.stdc
.stdio
: stderr
, fprintf
;
173 import core
.exception
: onOutOfMemoryError
;
174 stderr
.fprintf("Arena too small! arena=%u, asked for %u, need %u", cast(uint)arena_bytes
.length
, cast(uint)size
, cast(uint)(arena_pos
+size
));
175 onOutOfMemoryError();
177 auto pos
= arena_pos
;
179 arena_pos
= (arena_pos
+15)&~15;
180 return &arena_bytes
[pos
];
183 void clearArena () @trusted nothrow @nogc {
184 version(test_gcarena
) {
185 import core
.stdc
.stdio
: printf
;
186 printf("clearArena: allocated %u\n", cast(uint)arena_pos
);
191 void installProxy () @trusted nothrow @nogc {
192 version(test_gcarena
) {
193 import core
.stdc
.stdio
: printf
;
194 printf("using arena now\n");
199 void clearProxy () @trusted nothrow {
200 version(test_gcarena
) {
201 import core
.stdc
.stdio
: printf
;
202 printf("using GC now\n");
209 // ////////////////////////////////////////////////////////////////////////// //
211 Proxy
* gc_getProxy () @trusted nothrow @nogc;
213 auto genCall(string funname
) (FunArgsTypes
!funname args
) {
214 *gcaData
.pproxy
= null;
215 scope(exit
) *gcaData
.pproxy
= &gcaData
.myProxy
;
216 return __traits(getMember
, *gcaData
.pOrg
, funname
)(args
);
219 void* gca_malloc (usize sz
, uint ba
, const TypeInfo ti
) @trusted nothrow {
220 version(test_gcarena
) {
221 import core
.stdc
.stdio
: printf
;
222 printf("gca_malloc %u\n", cast(uint)sz
);
224 return gcaData
.alloc(sz
);
227 BlkInfo
gca_qalloc (usize sz
, uint ba
, const TypeInfo ti
) @trusted nothrow {
228 version(test_gcarena
) {
229 import core
.stdc
.stdio
: printf
;
230 printf("gca_qalloc %u\n", cast(uint)sz
);
232 auto pos0
= gcaData
.arena_pos
;
234 b
.base
= gcaData
.alloc(sz
);
235 b
.size
= gcaData
.arena_pos
-pos0
;
240 void* gca_calloc (usize sz
, uint ba
, const TypeInfo ti
) @trusted nothrow {
241 import core
.stdc
.string
: memset
;
242 version(test_gcarena
) {
243 import core
.stdc
.stdio
: printf
;
244 printf("gca_calloc %u\n", cast(uint)sz
);
246 void* p
= gcaData
.alloc(sz
);
253 // ////////////////////////////////////////////////////////////////////////// //
254 template FunArgsTypes(string funname
) {
255 import std
.traits
: ParameterTypeTuple
;
256 alias FunType
= typeof(*__traits(getMember
, gcaData
.myProxy
, funname
));
257 alias FunArgsTypes
= ParameterTypeTuple
!FunType
;
261 // ////////////////////////////////////////////////////////////////////////// //
262 GCAData gcaData
; // thread local
270 // ////////////////////////////////////////////////////////////////////////// //
271 version(test_gcarena
)
273 import core
.stdc
.stdio
: printf
;
274 auto ar
= useCleanArena();
275 auto s
= new ubyte[100]; // allocated in arena
277 auto pause
= pauseArena(); // in this scope it's not used
278 auto t
= new ubyte[200]; // allocated in main GC heap
280 auto v
= new ubyte[300]; // allocated in arena again
282 // end of scope, stop using arena