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 version (D_HavePointerMap) 59 bool conservative = false; 60 else 61 bool conservative = true; 62 bool fork = true; 63 bool eager_alloc = true; 64 bool early_collect = false; 65 uint min_free = 5; // percent of the heap (0-100) 66 size_t prealloc_psize = 0; 67 size_t prealloc_npools = 0; 68 } 69 70 package Options options; 71 72 73 debug (PRINTF) 74 void print_options() 75 { 76 int b(bool v) { return v; } 77 with (options) 78 printf("rt.gc.cdgc.opts: verbose=%u, log_file='%s', " 79 "malloc_stats_file='%s', collect_stats_file='%s', sentinel=%d, " 80 "mem_stomp=%d, conservative=%d, fork=%d, eager_alloc=%d, " 81 "early_collect=%d, min_free=%u, prealloc_psize=%lu, " 82 "prealloc_npools=%lu\n", verbose, log_file.ptr, 83 malloc_stats_file.ptr, collect_stats_file.ptr, b(sentinel), 84 b(mem_stomp), b(conservative), b(fork), b(eager_alloc), 85 b(early_collect), min_free, prealloc_psize, prealloc_npools); 86 } 87 88 89 bool cstr_eq(char* s1, char* s2) 90 { 91 return cstring.strcmp(s1, s2) == 0; 92 } 93 94 95 bool parse_bool(char* value) 96 { 97 if (value[0] == '\0') 98 return true; 99 return (cstdlib.atoi(value) != 0); 100 } 101 102 103 void parse_prealloc(char* value) 104 { 105 char* end; 106 cerrno.errno = 0; 107 long size = cstdlib.strtol(value, &end, 10); 108 if (end == value || cerrno.errno) // error parsing 109 return; 110 size *= 1024 * 1024; // size is supposed to be in MiB 111 long npools = 1; 112 if (*end == 'x') { // number of pools specified 113 char* start = end + 1; 114 npools = cstdlib.strtol(start, &end, 10); 115 if (*end != '\0' || end == start || cerrno.errno) // error parsing 116 return; 117 } 118 else if (*end != '\0') { // don't accept trailing garbage 119 return; 120 } 121 if (size > 0 && npools > 0) { 122 options.prealloc_psize = size; 123 options.prealloc_npools = npools; 124 } 125 } 126 127 128 void parse_min_free(char* value) 129 { 130 char* end; 131 long free = cstdlib.strtol(value, &end, 10); 132 if (*end != '\0' || end == value || cerrno.errno || free < 0 || free > 100) 133 return; 134 options.min_free = free; 135 } 136 137 138 void process_option(char* opt_name, char* opt_value) 139 { 140 if (cstr_eq(opt_name, "verbose")) 141 options.verbose = cstdlib.atoi(opt_value); 142 else if (cstr_eq(opt_name, "log_file")) 143 cstring.strcpy(options.log_file.ptr, opt_value); 144 else if (cstr_eq(opt_name, "malloc_stats_file")) 145 cstring.strcpy(options.malloc_stats_file.ptr, opt_value); 146 else if (cstr_eq(opt_name, "collect_stats_file")) 147 cstring.strcpy(options.collect_stats_file.ptr, opt_value); 148 else if (cstr_eq(opt_name, "sentinel")) 149 options.sentinel = parse_bool(opt_value); 150 else if (cstr_eq(opt_name, "mem_stomp")) 151 options.mem_stomp = parse_bool(opt_value); 152 else if (cstr_eq(opt_name, "conservative")) 153 options.conservative = parse_bool(opt_value); 154 else if (cstr_eq(opt_name, "fork")) 155 options.fork = parse_bool(opt_value); 156 else if (cstr_eq(opt_name, "eager_alloc")) 157 options.eager_alloc = parse_bool(opt_value); 158 else if (cstr_eq(opt_name, "early_collect")) 159 options.early_collect = parse_bool(opt_value); 160 else if (cstr_eq(opt_name, "min_free")) 161 parse_min_free(opt_value); 162 else if (cstr_eq(opt_name, "pre_alloc")) 163 parse_prealloc(opt_value); 164 } 165 166 167 package void parse(char* opts_string) 168 { 169 char[MAX_OPT_LEN] opt_name; 170 opt_name[0] = '\0'; 171 char[MAX_OPT_LEN] opt_value; 172 opt_value[0] = '\0'; 173 char* curr = opt_name.ptr; 174 size_t i = 0; 175 if (opts_string is null) { 176 debug (PRINTF) printf("rt.gc.cdgc.opts: no options overriden\n"); 177 return; 178 } 179 for (; *opts_string != '\0'; opts_string++) 180 { 181 char c = *opts_string; 182 if (i == MAX_OPT_LEN) 183 { 184 if (c != ':') 185 continue; 186 else 187 i--; 188 } 189 switch (*opts_string) 190 { 191 case ':': 192 curr[i] = '\0'; 193 process_option(opt_name.ptr, opt_value.ptr); 194 i = 0; 195 opt_name[0] = '\0'; 196 opt_value[0] = '\0'; 197 curr = opt_name.ptr; 198 break; 199 case '=': 200 opt_name[i] = '\0'; 201 curr = opt_value.ptr; 202 i = 0; 203 break; 204 default: 205 curr[i] = c; 206 ++i; 207 } 208 } 209 if (i == MAX_OPT_LEN) 210 i--; 211 curr[i] = '\0'; 212 process_option(opt_name.ptr, opt_value.ptr); 213 debug (PRINTF) print_options(); 214 } 215 216 217 unittest 218 { 219 with (options) { 220 assert (verbose == 0); 221 assert (log_file[0] == '\0'); 222 assert (sentinel == false); 223 assert (mem_stomp == false); 224 assert (conservative == false); 225 assert (fork == true); 226 assert (eager_alloc == true); 227 assert (early_collect == false); 228 assert (prealloc_psize == 0); 229 assert (prealloc_npools == 0); 230 assert (min_free == 5); 231 } 232 parse("mem_stomp"); 233 with (options) { 234 assert (verbose == 0); 235 assert (log_file[0] == '\0'); 236 assert (sentinel == false); 237 assert (mem_stomp == true); 238 assert (conservative == false); 239 assert (fork == true); 240 assert (eager_alloc == true); 241 assert (early_collect == false); 242 assert (prealloc_psize == 0); 243 assert (prealloc_npools == 0); 244 assert (min_free == 5); 245 } 246 parse("mem_stomp=0:verbose=2:conservative:fork=0:eager_alloc=0"); 247 with (options) { 248 assert (verbose == 2); 249 assert (log_file[0] == '\0'); 250 assert (sentinel == false); 251 assert (mem_stomp == false); 252 assert (conservative == true); 253 assert (fork == false); 254 assert (eager_alloc == false); 255 assert (early_collect == false); 256 assert (prealloc_psize == 0); 257 assert (prealloc_npools == 0); 258 assert (min_free == 5); 259 } 260 parse("log_file=12345 67890:verbose=1:sentinel=4:mem_stomp=1"); 261 with (options) { 262 assert (verbose == 1); 263 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 264 assert (sentinel == true); 265 assert (mem_stomp == true); 266 assert (conservative == true); 267 assert (fork == false); 268 assert (eager_alloc == false); 269 assert (early_collect == false); 270 assert (prealloc_psize == 0); 271 assert (prealloc_npools == 0); 272 assert (min_free == 5); 273 } 274 parse("pre_alloc:min_free=30:early_collect"); 275 with (options) { 276 assert (verbose == 1); 277 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 278 assert (sentinel == true); 279 assert (mem_stomp == true); 280 assert (conservative == true); 281 assert (fork == false); 282 assert (eager_alloc == false); 283 assert (early_collect == true); 284 assert (prealloc_psize == 0); 285 assert (prealloc_npools == 0); 286 assert (min_free == 30); 287 } 288 parse("pre_alloc=1:early_collect=0"); 289 with (options) { 290 assert (verbose == 1); 291 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 292 assert (sentinel == true); 293 assert (mem_stomp == true); 294 assert (conservative == true); 295 assert (fork == false); 296 assert (eager_alloc == false); 297 assert (early_collect == false); 298 assert (prealloc_psize == 1 * 1024 * 1024); 299 assert (prealloc_npools == 1); 300 assert (min_free == 30); 301 } 302 parse("pre_alloc=5a:min_free=101"); 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 (early_collect == false); 312 assert (prealloc_psize == 1 * 1024 * 1024); 313 assert (prealloc_npools == 1); 314 assert (min_free == 30); 315 } 316 parse("pre_alloc=5x:min_free=-1"); 317 with (options) { 318 assert (verbose == 1); 319 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 320 assert (sentinel == true); 321 assert (mem_stomp == true); 322 assert (conservative == true); 323 assert (fork == false); 324 assert (eager_alloc == false); 325 assert (early_collect == false); 326 assert (prealloc_psize == 1 * 1024 * 1024); 327 assert (prealloc_npools == 1); 328 assert (min_free == 30); 329 } 330 parse("pre_alloc=09x010:min_free=10a"); 331 with (options) { 332 assert (verbose == 1); 333 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 334 assert (sentinel == true); 335 assert (mem_stomp == true); 336 assert (conservative == true); 337 assert (fork == false); 338 assert (eager_alloc == false); 339 assert (early_collect == false); 340 assert (prealloc_psize == 9 * 1024 * 1024); 341 assert (prealloc_npools == 10); 342 assert (min_free == 30); 343 } 344 parse("pre_alloc=5x2:min_free=1.0"); 345 with (options) { 346 assert (verbose == 1); 347 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 348 assert (sentinel == true); 349 assert (mem_stomp == true); 350 assert (conservative == true); 351 assert (fork == false); 352 assert (eager_alloc == false); 353 assert (early_collect == false); 354 assert (prealloc_psize == 5 * 1024 * 1024); 355 assert (prealloc_npools == 2); 356 assert (min_free == 30); 357 } 358 parse("pre_alloc=9x5x:min_free=-1"); 359 with (options) { 360 assert (verbose == 1); 361 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 362 assert (sentinel == true); 363 assert (mem_stomp == true); 364 assert (conservative == true); 365 assert (fork == false); 366 assert (eager_alloc == false); 367 assert (early_collect == false); 368 assert (prealloc_psize == 5 * 1024 * 1024); 369 assert (prealloc_npools == 2); 370 assert (min_free == 30); 371 } 372 parse("pre_alloc=9x-5:min_free=0"); 373 with (options) { 374 assert (verbose == 1); 375 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 376 assert (sentinel == true); 377 assert (mem_stomp == true); 378 assert (conservative == true); 379 assert (fork == false); 380 assert (eager_alloc == false); 381 assert (early_collect == false); 382 assert (prealloc_psize == 5 * 1024 * 1024); 383 assert (prealloc_npools == 2); 384 assert (min_free == 0); 385 } 386 parse("pre_alloc=0x3x0x4:min_free=100"); 387 with (options) { 388 assert (verbose == 1); 389 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 390 assert (sentinel == true); 391 assert (mem_stomp == true); 392 assert (conservative == true); 393 assert (fork == false); 394 assert (eager_alloc == false); 395 assert (early_collect == false); 396 assert (prealloc_psize == 5 * 1024 * 1024); 397 assert (prealloc_npools == 2); 398 assert (min_free == 100); 399 } 400 parse(null); 401 with (options) { 402 assert (verbose == 1); 403 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 404 assert (sentinel == true); 405 assert (mem_stomp == true); 406 assert (conservative == true); 407 assert (fork == false); 408 assert (eager_alloc == false); 409 assert (early_collect == false); 410 assert (prealloc_psize == 5 * 1024 * 1024); 411 assert (prealloc_npools == 2); 412 assert (min_free == 100); 413 } 414 parse(""); 415 with (options) { 416 assert (verbose == 1); 417 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 418 assert (sentinel == true); 419 assert (mem_stomp == true); 420 assert (conservative == true); 421 assert (fork == false); 422 assert (eager_alloc == false); 423 assert (early_collect == false); 424 assert (prealloc_psize == 5 * 1024 * 1024); 425 assert (prealloc_npools == 2); 426 assert (min_free == 100); 427 } 428 parse(":"); 429 with (options) { 430 assert (verbose == 1); 431 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 432 assert (sentinel == true); 433 assert (mem_stomp == true); 434 assert (conservative == true); 435 assert (fork == false); 436 assert (eager_alloc == false); 437 assert (early_collect == false); 438 assert (prealloc_psize == 5 * 1024 * 1024); 439 assert (prealloc_npools == 2); 440 assert (min_free == 100); 441 } 442 parse("::::"); 443 with (options) { 444 assert (verbose == 1); 445 assert (cstring.strcmp(log_file.ptr, "12345 67890".ptr) == 0); 446 assert (sentinel == true); 447 assert (mem_stomp == true); 448 assert (conservative == true); 449 assert (fork == false); 450 assert (eager_alloc == false); 451 assert (early_collect == false); 452 assert (prealloc_psize == 5 * 1024 * 1024); 453 assert (prealloc_npools == 2); 454 assert (min_free == 100); 455 } 456 } 457 458 459 // vim: set et sw=4 sts=4 :