#include #include #include #include #include #include #include #include #include "gc.h" #include "builtin.h" #include "interp.h" static void test_builtins(void); static void test_weak_boxes_and_wills(void); static void test_garbage_collection(bool keep_going); static void print_value(value_t v); static void print_gc_stats(void); static inline void comma(void) { fputs(", ", stdout); } static inline void nl(void) { putchar('\n'); } void out_of_memory(void) { fprintf(stderr, "Out of memory!\n\n"); print_gc_stats(); abort(); } int main(int argc, char **argv) { srand((unsigned int)time(NULL)); gc_init(1024, 256*1024*1024); builtin_init(); interpreter_init(); test_builtins(); test_weak_boxes_and_wills(); test_garbage_collection(argc > 1); return 0; } static void test_builtins(void) { print_value(lookup_builtin(BI_STRUCTURE)); nl(); nl(); print_value(lookup_builtin(BI_TEMPLATE)); nl(); nl(); print_value(lookup_builtin(BI_LAMBDA)); nl(); nl(); } static void print_weak_box_results(value_t box) { value_t v, f; print_value(box); comma(); get_next_finalizer(&v, &f); print_value(v); comma(); print_value(f); nl(); } static void test_weak_boxes_and_wills(void) { gc_root_t box_root, tmp_root; register_gc_root(&box_root, NIL); register_gc_root(&tmp_root, NIL); tmp_root.value = cons(make_fixnum(1), cons(make_fixnum(2), NIL)); box_root.value = make_weak_box(tmp_root.value); register_finalizer(tmp_root.value, make_fixnum(10)); print_weak_box_results(box_root.value); collect_garbage(0); print_weak_box_results(box_root.value); tmp_root.value = NIL; print_weak_box_results(box_root.value); collect_garbage(0); print_weak_box_results(box_root.value); collect_garbage(0); print_weak_box_results(box_root.value); unregister_gc_root(&box_root); unregister_gc_root(&tmp_root); } static void test_garbage_collection(bool keep_going) { gc_root_t root; int count = 0; register_gc_root(&root, NIL); while (1) { int r = rand() & 0xffff; if (r == 0) root.value = make_fixnum(rand()); else { switch (r & 7) { case 0: root.value = cons(make_fixnum(rand()), root.value); break; case 1: root.value = cons(root.value, make_byte_string(256, '\0')); break; case 2: root.value = make_box(root.value); break; case 3: root.value = cons(root.value, cons(make_fixnum(-1), NIL)); get_pair(get_pair(root.value)->cdr)->cdr = root.value; break; case 4: case 5: case 6: case 7: { value_t s = make_struct(NIL, 4); _get_struct(s)->slots[r & 3] = root.value; root.value = s; } break; } } if (++count >= 50000000) { nl(); print_gc_stats(); gc_stats.collections = 0; gc_stats.total_ns = 0; gc_stats.total_freed = 0; gc_stats.high_water = 0; gc_stats.max_ns = 0; count = 0; if (!keep_going) break; } } unregister_gc_root(&root); } static bool all_print(const char *s, size_t len) { for (size_t i = 0; i < len; ++i) { if (s[i] == '"' || !isprint(s[i])) return false; } return true; } static void print_value(value_t v) { if (v == NIL) { fputs("nil", stdout); } else if (v == FALSE_VALUE) { fputs("#f", stdout); } else if (v == TRUE_VALUE) { fputs("#t", stdout); } else if (is_fixnum(v)) { printf("%d", (int)get_fixnum(v)); } else if (is_box(v)) { fputs("#&", stdout); print_value(_get_box(v)->value); } else if (is_pair(v)) { putchar('('); print_value(_get_pair(v)->car); v = _get_pair(v)->cdr; while (is_pair(v)) { putchar(' '); print_value(_get_pair(v)->car); v = _get_pair(v)->cdr; } if (v != NIL) { fputs(" . ", stdout); print_value(v); } putchar(')'); } else if (is_vector(v)) { fputs("#(", stdout); for (size_t i = 0; i < _get_vector(v)->size; ++i) { if (i != 0) putchar(' '); print_value(_get_vector(v)->elements[i]); } putchar(')'); } else if (is_byte_string(v)) { byte_string_t *str = _get_byte_string(v); if (all_print(str->bytes, str->size)) { putchar('"'); fwrite(str->bytes, str->size, 1, stdout); putchar('"'); } else { fputs("#B(", stdout); for (size_t i = 0; i < str->size; ++i) { if (i != 0) putchar(' '); printf("%d", (int)str->bytes[i]); } putchar(')'); } } else if (is_struct(v)) { struct_t *meta = get_struct(_get_struct(v)->type); byte_string_t *str = get_byte_string(meta->slots[0]); fputs("#S(", stdout); fwrite(str->bytes, str->size, 1, stdout); for (size_t i = 0; i < _get_struct(v)->nslots; ++i) { putchar(' '); print_value(_get_struct(v)->slots[i]); } putchar(')'); } else if (is_weak_box(v)) { fputs("#W&", stdout); print_value(_get_weak_box(v)->value); } else { fputs("#", stdout); } } static void print_gc_stats(void) { const double total_time = gc_stats.total_ns / 1.0e9; const double max_time = gc_stats.max_ns / 1.0e9; fprintf(stderr, "%lld bytes freed in %0.6f sec => %0.3f MB/sec. (%d GCs.)\n", gc_stats.total_freed, total_time, (gc_stats.total_freed / total_time) / (1024*1024), gc_stats.collections); fprintf(stderr, "Max GC time was %0.6f sec, avg. %0.6f sec; peak heap size was %d bytes.\n", max_time, (total_time / gc_stats.collections), gc_stats.high_water); } /* vim:set sw=2 expandtab: */