diff --git a/src/GC/include/cheap.h b/src/GC/include/cheap.h index d2c649d..0f880e8 100644 --- a/src/GC/include/cheap.h +++ b/src/GC/include/cheap.h @@ -7,7 +7,7 @@ extern "C" { #endif -// #define DEBUG +#define DEBUG #ifdef DEBUG typedef struct cheap diff --git a/src/GC/include/heap.hpp b/src/GC/include/heap.hpp index 365a838..f877667 100644 --- a/src/GC/include/heap.hpp +++ b/src/GC/include/heap.hpp @@ -5,12 +5,13 @@ #include #include #include +#include #include "chunk.hpp" #include "profiler.hpp" -#define HEAP_SIZE 2097152 //65536 -#define FREE_THRESH (uint) 100000 +#define HEAP_SIZE 2097152 //256 //65536 //2097152 +#define FREE_THRESH (uint) 100000 //1000 #define DEBUG namespace GC @@ -47,12 +48,14 @@ namespace GC char *const m_heap; size_t m_size {0}; + size_t m_total_size {0}; // static Heap *m_instance {nullptr}; uintptr_t *m_stack_top {nullptr}; bool m_profiler_enable {false}; std::vector m_allocated_chunks; std::vector m_freed_chunks; + std::unordered_map m_chunk_table; static bool profiler_enabled(); // static Chunk *get_at(std::vector &list, size_t n); @@ -62,6 +65,8 @@ namespace GC void free(Heap &heap); void free_overlap(Heap &heap); void mark(uintptr_t *start, const uintptr_t *end, std::vector &worklist); + void mark_hash(uintptr_t *start, const uintptr_t *end); + void create_table(); void print_line(Chunk *chunk); void print_worklist(std::vector &list); void mark_step(uintptr_t start, uintptr_t end, std::vector &worklist); diff --git a/src/GC/lib/heap.cpp b/src/GC/lib/heap.cpp index 579f421..d10ac90 100644 --- a/src/GC/lib/heap.cpp +++ b/src/GC/lib/heap.cpp @@ -7,10 +7,11 @@ #include #include #include +#include #include "heap.hpp" -using std::cout, std::endl, std::vector, std::hex, std::dec; +using std::cout, std::endl, std::vector, std::hex, std::dec, std::unordered_map; namespace GC { @@ -83,7 +84,11 @@ namespace GC { heap.collect(); // If memory is not enough after collect, crash with OOM error - throw std::runtime_error(std::string("Error: Heap out of memory")); + if (heap.m_size > HEAP_SIZE) + { + throw std::runtime_error(std::string("Error: Heap out of memory")); + } + //throw std::runtime_error(std::string("Error: Heap out of memory")); } // If a chunk was recycled, return the old chunk address @@ -100,6 +105,7 @@ namespace GC auto new_chunk = new Chunk(size, (uintptr_t *)(heap.m_heap + heap.m_size)); heap.m_size += size; + heap.m_total_size += size; heap.m_allocated_chunks.push_back(new_chunk); if (profiler_enabled) @@ -133,7 +139,8 @@ namespace GC //auto chunk = Heap::get_at(heap.m_freed_chunks, i); auto chunk = heap.m_freed_chunks[i]; auto iter = heap.m_freed_chunks.begin(); - advance(iter, i); + i++; + //advance(iter, i); if (chunk->m_size > size) { // Split the chunk, use one part and add the remaining part to @@ -212,8 +219,12 @@ namespace GC uintptr_t *stack_top = heap.m_stack_top; - auto work_list = heap.m_allocated_chunks; - mark(stack_bottom, stack_top, work_list); + //auto work_list = heap.m_allocated_chunks; + //mark(stack_bottom, stack_top, work_list); + + // Testing mark_hash, previous woking implementation above + create_table(); + mark_hash(stack_bottom, stack_top); sweep(heap); @@ -281,6 +292,37 @@ namespace GC } } + void Heap::create_table() + { + Heap &heap = Heap::the(); + unordered_map chunk_table; + for (auto chunk : heap.m_allocated_chunks) { + auto pair = std::make_pair(reinterpret_cast(chunk->m_start), chunk); + heap.m_chunk_table.insert(pair); + } + } + + void Heap::mark_hash(uintptr_t *start, const uintptr_t* const end) + { + Heap &heap = Heap::the(); + for (; start <= end; start++) + { + auto search = heap.m_chunk_table.find(*start); + if (search != heap.m_chunk_table.end()) + { + Chunk *chunk = search->second; + auto c_start = reinterpret_cast(chunk->m_start); + auto c_size = reinterpret_cast(chunk->m_size); + auto c_end = reinterpret_cast(c_start + c_size); + if (!chunk->m_marked) + { + chunk->m_marked = true; + mark_hash(chunk->m_start, c_end); + } + } + } + } + /** * Sweeps the heap, unmarks the marked chunks for the next cycle, @@ -343,6 +385,7 @@ namespace GC heap.m_freed_chunks.pop_back(); if (profiler_enabled) Profiler::record(ChunkFreed, chunk); + heap.m_size -= chunk->m_size; delete chunk; } } @@ -405,6 +448,7 @@ namespace GC { if (profiler_enabled) Profiler::record(ChunkFreed, chunk); + heap.m_size -= chunk->m_size; delete chunk; } else diff --git a/src/GC/lib/profiler.cpp b/src/GC/lib/profiler.cpp index 29abad4..d2e3246 100644 --- a/src/GC/lib/profiler.cpp +++ b/src/GC/lib/profiler.cpp @@ -11,7 +11,7 @@ #include "event.hpp" #include "profiler.hpp" -// #define MAC_OS +#define MAC_OS namespace GC { diff --git a/src/GC/tests/h_test.cpp b/src/GC/tests/h_test.cpp index c871721..3e0a00b 100644 --- a/src/GC/tests/h_test.cpp +++ b/src/GC/tests/h_test.cpp @@ -11,7 +11,7 @@ struct Node { }; Node *create_chain(int depth) { - cout << "entering create_chain"; + cout << "entering create_chain" << endl; std::vector nodes; if (depth > 0) { Node *last_node = static_cast(GC::Heap::alloc(sizeof(Node))); @@ -36,14 +36,14 @@ void create_array(size_t size) { } void detach_pointer(long **ptr) { - cout << "entering detach_pointer"; + cout << "entering detach_pointer" << endl; long *dummy_ptr = nullptr; *ptr = dummy_ptr; cout << "\nexiting detach_pointer" << endl; } Node *test_chain(int depth, bool detach) { - cout << "entering test_chain"; + cout << "entering test_chain" << endl; auto stack_start = reinterpret_cast(__builtin_frame_address(0)); Node *node_chain = create_chain(depth); @@ -85,9 +85,8 @@ int main() { Node *root1 = static_cast(gc.alloc(sizeof(Node))); Node *root2 = static_cast(gc.alloc(sizeof(Node))); - root1 = test_chain(58000, false); - root2 = test_chain(58000, false); - + root1 = test_chain(100000, false); + //root2 = test_chain(58000, false); gc.collect(GC::COLLECT_ALL); auto end = std::chrono::high_resolution_clock::now(); diff --git a/src/GC/tests/h_test.out.dSYM/Contents/Info.plist b/src/GC/tests/h_test.out.dSYM/Contents/Info.plist new file mode 100644 index 0000000..3db2218 --- /dev/null +++ b/src/GC/tests/h_test.out.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.h_test.out + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/src/GC/tests/h_test.out.dSYM/Contents/Resources/DWARF/h_test.out b/src/GC/tests/h_test.out.dSYM/Contents/Resources/DWARF/h_test.out new file mode 100644 index 0000000..0d4c74f Binary files /dev/null and b/src/GC/tests/h_test.out.dSYM/Contents/Resources/DWARF/h_test.out differ diff --git a/src/GC/tests/wrapper_test.c b/src/GC/tests/wrapper_test.c index 729cf69..2055b8c 100644 --- a/src/GC/tests/wrapper_test.c +++ b/src/GC/tests/wrapper_test.c @@ -12,17 +12,7 @@ typedef struct node { Node *HEAD = NULL; Node *CURRENT = NULL; -// Creates a linked list of length depth. Global head "HEAD" is updated. -void *create_linked_list(int depth) { - HEAD = (Node*)(cheap_alloc(sizeof(Node))); - HEAD->id = 0; - // Purposely omitting adding a child to "last_node", since its the last node - for (int i = 1; i < depth - 1; i++) { - insert_first(i); - } -} - -void *insert_first(int node_id) { +void insert_first(int node_id) { Node *new_head; new_head = (Node*)(cheap_alloc(sizeof(Node))); new_head->id = node_id; @@ -31,15 +21,33 @@ void *insert_first(int node_id) { HEAD = new_head; } -void test_linked_list(int list_length){ +// Creates a linked list of length depth. Global head "HEAD" is updated. +Node *create_linked_list(int depth) { + HEAD = (Node*)(cheap_alloc(sizeof(Node))); + HEAD->id = 0; + // Purposely omitting adding a child to "last_node", since its the last node + for (int i = 1; i < depth - 1; i++) { + insert_first(i); + } + return HEAD; +} + +void create_garbage(int amount) { + for (int i = 0; i < amount; i++) { + long *garbage = (long*)(cheap_alloc(sizeof(long))); + } +} + +int main () { cheap_init(); cheap_t *heap = cheap_the(); cheap_set_profiler(heap, true); - create_linked_list(list_length); - cheap_dispose(); - free(heap); -} -int main (int argc, char **argv) { - test_linked_list(30); + // Every node in this list should be marked + Node *head = create_linked_list(5); + // Everything create here should be swept + create_garbage(30); + + cheap_dispose(); + return 0; } \ No newline at end of file