]> git.llucax.com Git - software/dgc/cdgc.git/blob - rt/gc/cdgc/opts.d
d757bc8d8f3164822e825183342c6ceb2a576126
[software/dgc/cdgc.git] / rt / gc / cdgc / opts.d
1 /**
2  * This module contains the options managemente code of the garbage collector.
3  *
4  * Copyright: Copyright (C) 2010 Leandro Lucarella <http://www.llucax.com.ar/>
5  *            All rights reserved.
6  *
7  * License: Boost Software License - Version 1.0 - August 17th, 2003
8  *
9  * Permission is hereby granted, free of charge, to any person or organization
10  * obtaining a copy of the software and accompanying documentation covered by
11  * this license (the "Software") to use, reproduce, display, distribute,
12  * execute, and transmit the Software, and to prepare derivative works of the
13  * Software, and to permit third-parties to whom the Software is furnished to
14  * do so, all subject to the following:
15  *
16  * The copyright notices in the Software and this entire statement, including
17  * the above license grant, this restriction and the following disclaimer,
18  * must be included in all copies of the Software, in whole or in part, and
19  * all derivative works of the Software, unless such copies or derivative
20  * works are solely in the form of machine-executable object code generated by
21  * a source language processor.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
26  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
27  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
28  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29  * DEALINGS IN THE SOFTWARE.
30  *
31  * Authors: Leandro Lucarella
32  */
33
34 module rt.gc.cdgc.opts;
35
36 //debug = PRINTF;
37
38 import cstdlib = tango.stdc.stdlib;
39 import cstring = tango.stdc.string;
40 import cerrno = tango.stdc.errno;
41 debug (PRINTF) import tango.stdc.stdio: printf;
42
43
44 private:
45
46
47 const MAX_OPT_LEN = 256;
48
49
50 struct Options
51 {
52     uint verbose = 0;
53     char[MAX_OPT_LEN] log_file = "";
54     char[MAX_OPT_LEN] malloc_stats_file = "";
55     char[MAX_OPT_LEN] collect_stats_file = "";
56     bool sentinel = false;
57     bool mem_stomp = false;
58     bool conservative = false;
59     bool fork = true;
60     bool eager_alloc = true;
61     uint min_free = 15; // percent of the heap (0-100)
62     size_t prealloc_psize = 0;
63     size_t prealloc_npools = 0;
64 }
65
66 package Options options;
67
68
69 debug (PRINTF)
70 void print_options()
71 {
72     int b(bool v) { return v; }
73     with (options)
74     printf("rt.gc.cdgc.opts: verbose=%u, log_file='%s', "
75             "malloc_stats_file='%s', collect_stats_file='%s', sentinel=%d, "
76             "mem_stomp=%d, conservative=%d, fork=%d, eager_alloc=%d, "
77             "early_collect=%d, min_free=%u, prealloc_psize=%lu, "
78             "prealloc_npools=%lu\n", verbose, log_file.ptr,
79             malloc_stats_file.ptr, collect_stats_file.ptr, b(sentinel),
80             b(mem_stomp), b(conservative), b(fork), b(eager_alloc),
81             b(early_collect), min_free, prealloc_psize, prealloc_npools);
82 }
83
84
85 bool cstr_eq(char* s1, char* s2)
86 {
87     return cstring.strcmp(s1, s2) == 0;
88 }
89
90
91 bool parse_bool(char* value)
92 {
93     if (value[0] == '\0')
94         return true;
95     return (cstdlib.atoi(value) != 0);
96 }
97
98
99 void parse_prealloc(char* value)
100 {
101     char* end;
102     cerrno.errno = 0;
103     long size = cstdlib.strtol(value, &end, 10);
104     if (end == value || cerrno.errno) // error parsing
105         return;
106     size *= 1024 * 1024; // size is supposed to be in MiB
107     long npools = 1;
108     if (*end == 'x') { // number of pools specified
109         char* start = end + 1;
110         npools = cstdlib.strtol(start, &end, 10);
111         if (*end != '\0' || end == start || cerrno.errno) // error parsing
112             return;
113     }
114     else if (*end != '\0') { // don't accept trailing garbage
115         return;
116     }
117     if (size > 0 && npools > 0) {
118         options.prealloc_psize = size;
119         options.prealloc_npools = npools;
120     }
121 }
122
123
124 void parse_min_free(char* value)
125 {
126     char* end;
127     long free = cstdlib.strtol(value, &end, 10);
128     if (*end != '\0' || end == value || cerrno.errno || free < 0 || free > 100)
129         return;
130     options.min_free = free;
131 }
132
133
134 void process_option(char* opt_name, char* opt_value)
135 {
136     if (cstr_eq(opt_name, "verbose"))
137         options.verbose = cstdlib.atoi(opt_value);
138     else if (cstr_eq(opt_name, "log_file"))
139         cstring.strcpy(options.log_file.ptr, opt_value);
140     else if (cstr_eq(opt_name, "malloc_stats_file"))
141         cstring.strcpy(options.malloc_stats_file.ptr, opt_value);
142     else if (cstr_eq(opt_name, "collect_stats_file"))
143         cstring.strcpy(options.collect_stats_file.ptr, opt_value);
144     else if (cstr_eq(opt_name, "sentinel"))
145         options.sentinel = parse_bool(opt_value);
146     else if (cstr_eq(opt_name, "mem_stomp"))
147         options.mem_stomp = parse_bool(opt_value);
148     else if (cstr_eq(opt_name, "conservative"))
149         options.conservative = parse_bool(opt_value);
150     else if (cstr_eq(opt_name, "fork"))
151         options.fork = parse_bool(opt_value);
152     else if (cstr_eq(opt_name, "eager_alloc"))
153         options.eager_alloc = parse_bool(opt_value);
154     else if (cstr_eq(opt_name, "min_free"))
155         parse_min_free(opt_value);
156     else if (cstr_eq(opt_name, "pre_alloc"))
157         parse_prealloc(opt_value);
158 }
159
160
161 package void parse(char* opts_string)
162 {
163     char[MAX_OPT_LEN] opt_name;
164     opt_name[0] = '\0';
165     char[MAX_OPT_LEN] opt_value;
166     opt_value[0] = '\0';
167     char* curr = opt_name.ptr;
168     size_t i = 0;
169     if (opts_string is null) {
170         debug (PRINTF) printf("rt.gc.cdgc.opts: no options overriden\n");
171         return;
172     }
173     for (; *opts_string != '\0'; opts_string++)
174     {
175         char c = *opts_string;
176         if (i == MAX_OPT_LEN)
177         {
178             if (c != ':')
179                 continue;
180             else
181                 i--;
182         }
183         switch (*opts_string)
184         {
185         case ':':
186             curr[i] = '\0';
187             process_option(opt_name.ptr, opt_value.ptr);
188             i = 0;
189             opt_name[0] = '\0';
190             opt_value[0] = '\0';
191             curr = opt_name.ptr;
192             break;
193         case '=':
194             opt_name[i] = '\0';
195             curr = opt_value.ptr;
196             i = 0;
197             break;
198         default:
199             curr[i] = c;
200             ++i;
201         }
202     }
203     if (i == MAX_OPT_LEN)
204         i--;
205     curr[i] = '\0';
206     process_option(opt_name.ptr, opt_value.ptr);
207     debug (PRINTF) print_options();
208 }
209
210
211 unittest
212 {
213     with (options) {
214         assert (verbose == 0);
215         assert (log_file[0] == '\0');
216         assert (sentinel == false);
217         assert (mem_stomp == false);
218         assert (conservative == false);
219         assert (fork == true);
220         assert (eager_alloc == true);
221         assert (prealloc_psize == 0);
222         assert (prealloc_npools == 0);
223         assert (min_free == 15);
224     }
225     parse("mem_stomp");
226     with (options) {
227         assert (verbose == 0);
228         assert (log_file[0] == '\0');
229         assert (sentinel == false);
230         assert (mem_stomp == true);
231         assert (conservative == false);
232         assert (fork == true);
233         assert (eager_alloc == true);
234         assert (prealloc_psize == 0);
235         assert (prealloc_npools == 0);
236         assert (min_free == 15);
237     }
238     parse("mem_stomp=0:verbose=2:conservative:fork=0:eager_alloc=0");
239     with (options) {
240         assert (verbose == 2);
241         assert (log_file[0] == '\0');
242         assert (sentinel == false);
243         assert (mem_stomp == false);
244         assert (conservative == true);
245         assert (fork == false);
246         assert (eager_alloc == false);
247         assert (prealloc_psize == 0);
248         assert (prealloc_npools == 0);
249         assert (min_free == 15);
250     }
251     parse("log_file=12345 67890:verbose=1:sentinel=4:mem_stomp=1");
252     with (options) {
253         assert (verbose == 1);
254         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
255         assert (sentinel == true);
256         assert (mem_stomp == true);
257         assert (conservative == true);
258         assert (fork == false);
259         assert (eager_alloc == false);
260         assert (prealloc_psize == 0);
261         assert (prealloc_npools == 0);
262     }
263     parse("pre_alloc:min_free=30");
264     with (options) {
265         assert (verbose == 1);
266         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
267         assert (sentinel == true);
268         assert (mem_stomp == true);
269         assert (conservative == true);
270         assert (fork == false);
271         assert (eager_alloc == false);
272         assert (prealloc_psize == 0);
273         assert (prealloc_npools == 0);
274         assert (min_free == 30);
275     }
276     parse("pre_alloc=1");
277     with (options) {
278         assert (verbose == 1);
279         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
280         assert (sentinel == true);
281         assert (mem_stomp == true);
282         assert (conservative == true);
283         assert (fork == false);
284         assert (eager_alloc == false);
285         assert (prealloc_psize == 1 * 1024 * 1024);
286         assert (prealloc_npools == 1);
287         assert (min_free == 30);
288     }
289     parse("pre_alloc=5a:min_free=101");
290     with (options) {
291         assert (verbose == 1);
292         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
293         assert (sentinel == true);
294         assert (mem_stomp == true);
295         assert (conservative == true);
296         assert (fork == false);
297         assert (eager_alloc == false);
298         assert (prealloc_psize == 1 * 1024 * 1024);
299         assert (prealloc_npools == 1);
300         assert (min_free == 30);
301     }
302     parse("pre_alloc=5x:min_free=-1");
303     with (options) {
304         assert (verbose == 1);
305         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
306         assert (sentinel == true);
307         assert (mem_stomp == true);
308         assert (conservative == true);
309         assert (fork == false);
310         assert (eager_alloc == false);
311         assert (prealloc_psize == 1 * 1024 * 1024);
312         assert (prealloc_npools == 1);
313         assert (min_free == 30);
314     }
315     parse("pre_alloc=09x010:min_free=10a");
316     with (options) {
317         assert (verbose == 1);
318         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
319         assert (sentinel == true);
320         assert (mem_stomp == true);
321         assert (conservative == true);
322         assert (fork == false);
323         assert (eager_alloc == false);
324         assert (prealloc_psize == 9 * 1024 * 1024);
325         assert (prealloc_npools == 10);
326         assert (min_free == 30);
327     }
328     parse("pre_alloc=5x2:min_free=1.0");
329     with (options) {
330         assert (verbose == 1);
331         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
332         assert (sentinel == true);
333         assert (mem_stomp == true);
334         assert (conservative == true);
335         assert (fork == false);
336         assert (eager_alloc == false);
337         assert (prealloc_psize == 5 * 1024 * 1024);
338         assert (prealloc_npools == 2);
339         assert (min_free == 30);
340     }
341     parse("pre_alloc=9x5x:min_free=-1");
342     with (options) {
343         assert (verbose == 1);
344         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
345         assert (sentinel == true);
346         assert (mem_stomp == true);
347         assert (conservative == true);
348         assert (fork == false);
349         assert (eager_alloc == false);
350         assert (prealloc_psize == 5 * 1024 * 1024);
351         assert (prealloc_npools == 2);
352         assert (min_free == 30);
353     }
354     parse("pre_alloc=9x-5:min_free=0");
355     with (options) {
356         assert (verbose == 1);
357         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
358         assert (sentinel == true);
359         assert (mem_stomp == true);
360         assert (conservative == true);
361         assert (fork == false);
362         assert (eager_alloc == false);
363         assert (prealloc_psize == 5 * 1024 * 1024);
364         assert (prealloc_npools == 2);
365         assert (min_free == 0);
366     }
367     parse("pre_alloc=0x3x0x4:min_free=100");
368     with (options) {
369         assert (verbose == 1);
370         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
371         assert (sentinel == true);
372         assert (mem_stomp == true);
373         assert (conservative == true);
374         assert (fork == false);
375         assert (eager_alloc == false);
376         assert (prealloc_psize == 5 * 1024 * 1024);
377         assert (prealloc_npools == 2);
378         assert (min_free == 100);
379     }
380     parse(null);
381     with (options) {
382         assert (verbose == 1);
383         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
384         assert (sentinel == true);
385         assert (mem_stomp == true);
386         assert (conservative == true);
387         assert (fork == false);
388         assert (eager_alloc == false);
389         assert (prealloc_psize == 5 * 1024 * 1024);
390         assert (prealloc_npools == 2);
391         assert (min_free == 100);
392     }
393     parse("");
394     with (options) {
395         assert (verbose == 1);
396         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
397         assert (sentinel == true);
398         assert (mem_stomp == true);
399         assert (conservative == true);
400         assert (fork == false);
401         assert (eager_alloc == false);
402         assert (prealloc_psize == 5 * 1024 * 1024);
403         assert (prealloc_npools == 2);
404         assert (min_free == 100);
405     }
406     parse(":");
407     with (options) {
408         assert (verbose == 1);
409         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
410         assert (sentinel == true);
411         assert (mem_stomp == true);
412         assert (conservative == true);
413         assert (fork == false);
414         assert (eager_alloc == false);
415         assert (prealloc_psize == 5 * 1024 * 1024);
416         assert (prealloc_npools == 2);
417         assert (min_free == 100);
418     }
419     parse("::::");
420     with (options) {
421         assert (verbose == 1);
422         assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0);
423         assert (sentinel == true);
424         assert (mem_stomp == true);
425         assert (conservative == true);
426         assert (fork == false);
427         assert (eager_alloc == false);
428         assert (prealloc_psize == 5 * 1024 * 1024);
429         assert (prealloc_npools == 2);
430         assert (min_free == 100);
431     }
432 }
433
434
435 // vim: set et sw=4 sts=4 :