egra: post rebuild event on minimisation (because minimised windows won't do it)
[iv.d.git] / _obsolete_dont_use / gcarena.d
blob54ab4eac44bfd61867d33d6d562c4e38a1621f61
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.
25 * Like this:
27 * foreach (fname; files) {
28 * auto ar = useCleanArena(); // (1)
29 * auto img = readPng(fname).getAsTrueColorImage();
30 * process(img);
31 * // (2)
32 * }
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:
41 * void testArena () {
42 * auto ar = useCleanArena();
43 * auto s = new ubyte[100]; // allocated in arena
44 * {
45 * auto pause = pauseArena(); // in this scope it's not used
46 * auto t = new ubyte[200]; // allocated in main GC heap
47 * }
48 * auto v = new ubyte[300]; // allocated in arena again
49 * writeln("hi");
50 * // end of scope, stop using arena
51 * }
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*/;
57 import iv.alice;
60 // ////////////////////////////////////////////////////////////////////////// //
61 void setArenaSize (usize totalSize) {
62 gcaData.arena_size = totalSize;
66 struct ArenaHandler {
67 private:
68 bool stopped = false;
70 public:
71 @disable this (this);
72 ~this () @trusted nothrow => stop();
74 void stop () @trusted nothrow {
75 if (stopped) return;
76 gcaData.clearProxy();
77 stopped = true;
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() () {
95 gcaData.clearProxy();
96 struct ArenaPause {
97 @disable this (this);
98 ~this () @trusted nothrow @nogc => gcaData.installProxy();
100 return ArenaPause();
104 // ////////////////////////////////////////////////////////////////////////// //
105 private:
106 import core.memory;
108 alias BlkInfo = GC.BlkInfo;
110 // copied from proxy.d (d runtime)
111 struct Proxy {
112 extern (C):
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 // ////////////////////////////////////////////////////////////////////////// //
145 struct GCAData {
146 Proxy myProxy;
147 Proxy* pOrg; // pointer to original Proxy of runtime
148 Proxy** pproxy;
150 ubyte[] arena_bytes;
151 usize arena_pos = 0;
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;
167 *pproxy = null;
168 arena_bytes = new ubyte[arena_size];
169 *pproxy = oldproxy;
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;
178 arena_pos += size;
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);
188 arena_pos = 0;
191 void installProxy () @trusted nothrow @nogc {
192 version(test_gcarena) {
193 import core.stdc.stdio : printf;
194 printf("using arena now\n");
196 *pproxy = &myProxy;
199 void clearProxy () @trusted nothrow {
200 version(test_gcarena) {
201 import core.stdc.stdio : printf;
202 printf("using GC now\n");
204 *pproxy = null;
209 // ////////////////////////////////////////////////////////////////////////// //
210 extern(C) {
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;
233 BlkInfo b;
234 b.base = gcaData.alloc(sz);
235 b.size = gcaData.arena_pos-pos0;
236 b.attr = ba;
237 return b;
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);
247 memset(p, 0, sz);
248 return p;
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
265 static this () {
266 gcaData.initProxy();
270 // ////////////////////////////////////////////////////////////////////////// //
271 version(test_gcarena)
272 unittest {
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
281 printf("hi\n");
282 // end of scope, stop using arena