diff --git a/src/GC/include/chunk.hpp b/src/GC/include/chunk.hpp index fe44220..2a514e0 100644 --- a/src/GC/include/chunk.hpp +++ b/src/GC/include/chunk.hpp @@ -12,8 +12,8 @@ namespace GC size_t size; // Default constructor - Chunk() - {} + Chunk() {} + Chunk(const Chunk *const c) : marked(c->marked), start(c->start), size(c->size) {} // -- Temporary -- // A copy constructor, keep track of how many times the vectors that hold chunks @@ -21,7 +21,7 @@ namespace GC // Shouldn't be all that relevant if we use vectors with Chunk-pointers. Chunk(const Chunk& c) : marked(c.marked), start(c.start), size(c.size) { - std::cout << "Chunk was copied" << std::endl; + // std::cout << "Chunk was copied" << std::endl; } }; } \ No newline at end of file diff --git a/src/GC/include/event.hpp b/src/GC/include/event.hpp index 26fdf99..6eb38f4 100644 --- a/src/GC/include/event.hpp +++ b/src/GC/include/event.hpp @@ -12,13 +12,16 @@ namespace GC enum GCEventType { + HeapInit, + AllocStart, CollectStart, MarkStart, ChunkMarked, ChunkSwept, ChunkFreed, NewChunk, - ReusedChunk + ReusedChunk, + ProfilerDispose }; class GCEvent @@ -27,22 +30,33 @@ namespace GC // make const GCEventType m_type; std::time_t m_timestamp; - Chunk *m_chunk = nullptr; + Chunk *m_chunk; + size_t m_size; public: GCEvent(GCEventType type) { m_type = type; m_timestamp = std::time(NULL); + m_chunk = nullptr; + m_size = 0; } - GCEvent(GCEventType type, Chunk *chunk) + GCEvent(GCEventType type, Chunk *chunk) : GCEvent(type) { - m_type = type; - m_timestamp = std::time(NULL); m_chunk = chunk; } + GCEvent(GCEventType type, size_t size) : GCEvent(type) + { + m_size = size; + } + + ~GCEvent() { + if (m_chunk != nullptr) + delete m_chunk; + } + GCEventType get_type(); std::time_t get_time_stamp(); Chunk *get_chunk(); diff --git a/src/GC/include/heap.hpp b/src/GC/include/heap.hpp index 0994aa7..1a1175d 100644 --- a/src/GC/include/heap.hpp +++ b/src/GC/include/heap.hpp @@ -56,13 +56,13 @@ namespace GC return *iter; } - inline static bool get_profiler_mode() { + inline bool profiler_enabled() { auto heap = Heap::the(); return heap->m_profiler_enable; } inline static Heap *m_instance = nullptr; - const char *m_heap; + char *m_heap; size_t m_size; size_t m_allocated_size; uintptr_t *m_stack_top = nullptr; @@ -73,7 +73,7 @@ namespace GC void collect(); void sweep(Heap *heap); - uintptr_t *try_recycle_chunks(size_t size); + Chunk *try_recycle_chunks(size_t size); void free(Heap *heap); void free_overlap(Heap *heap); void mark(uintptr_t *start, const uintptr_t *end, std::vector &worklist); diff --git a/src/GC/include/profiler.hpp b/src/GC/include/profiler.hpp index 882293b..23a83b5 100644 --- a/src/GC/include/profiler.hpp +++ b/src/GC/include/profiler.hpp @@ -11,7 +11,10 @@ namespace GC { class Profiler { private: Profiler() { } - ~Profiler() { } + ~Profiler() { + for (GCEvent *c : m_events) + delete c; + } inline static Profiler *the() { if (m_instance) @@ -28,7 +31,9 @@ namespace GC { public: static void record(GCEventType type); + static void record(GCEventType type, size_t size); static void record(GCEventType type, Chunk *chunk); static void dump_trace(); + static void dispose(); }; } \ No newline at end of file diff --git a/src/GC/lib/heap.cpp b/src/GC/lib/heap.cpp index bc4f593..bab2c99 100644 --- a/src/GC/lib/heap.cpp +++ b/src/GC/lib/heap.cpp @@ -7,8 +7,9 @@ #include #include -//#include "../include/heap.hpp" -#include +// #include "../include/heap.hpp" +// #include +#include "heap.hpp" using std::cout, std::endl, std::vector, std::hex, std::dec; @@ -24,6 +25,8 @@ namespace GC void Heap::init() { Heap *heap = Heap::the(); + if (heap->profiler_enabled()) + Profiler::record(HeapInit); heap->m_stack_top = static_cast(__builtin_frame_address(1)); } @@ -33,6 +36,8 @@ namespace GC void Heap::dispose() { Heap *heap = Heap::the(); + if (heap->profiler_enabled()) + Profiler::dispose(); delete heap; } @@ -47,9 +52,12 @@ namespace GC */ void *Heap::alloc(size_t size) { - // Singleton Heap *heap = Heap::the(); + bool profiler_enabled = heap->profiler_enabled(); + + if (profiler_enabled) + Profiler::record(AllocStart, size); if (size < 0) { @@ -65,10 +73,12 @@ namespace GC } // If a chunk was recycled, return the old chunk address - uintptr_t *reused_chunk = heap->try_recycle_chunks(size); + Chunk *reused_chunk = heap->try_recycle_chunks(size); if (reused_chunk != nullptr) { - return static_cast(reused_chunk); + if (profiler_enabled) + Profiler::record(ReusedChunk, reused_chunk); + return static_cast(reused_chunk->start); } // If no free chunks was found (reused_chunk is a nullptr), @@ -81,6 +91,9 @@ namespace GC heap->m_allocated_chunks.push_back(new_chunk); + if (profiler_enabled) + Profiler::record(NewChunk, new_chunk); + // new_chunk should probably be a unique pointer, if that isn't implicit already return new_chunk->start; } @@ -101,7 +114,7 @@ namespace GC * nullptr is returned to signify no * chunks were found. */ - uintptr_t *Heap::try_recycle_chunks(size_t size) + Chunk *Heap::try_recycle_chunks(size_t size) { auto heap = Heap::the(); // Check if there are any freed chunks large enough for current request @@ -124,14 +137,14 @@ namespace GC heap->m_freed_chunks.push_back(chunk_complement); heap->m_allocated_chunks.push_back(chunk); - return chunk->start; + return chunk; } else if (chunk->size == size) { // Reuse the whole chunk heap->m_freed_chunks.erase(iter); heap->m_allocated_chunks.push_back(chunk); - return chunk->start; + return chunk; } } return nullptr; @@ -149,6 +162,9 @@ namespace GC // Get instance auto heap = Heap::the(); + if (heap->profiler_enabled()) + Profiler::record(CollectStart); + // get current stack auto stack_bottom = reinterpret_cast(__builtin_frame_address(0)); @@ -174,10 +190,12 @@ namespace GC * @param end Pointer to the end of the stack frame. * @param worklist The currently allocated chunks, which haven't been marked. */ - void Heap::mark(uintptr_t *start, const uintptr_t *end, vector &worklist) + void Heap::mark(uintptr_t *start, const uintptr_t* const end, vector &worklist) { + Heap *heap = Heap::the(); + bool profiler_enabled = heap->profiler_enabled(); cout << "--- mark() was called ---\n" << endl; - if (Heap::get_profiler_mode()) + if (profiler_enabled) Profiler::record(MarkStart); // To find adresses thats in the worklist for (; start <= end; start++) @@ -185,7 +203,7 @@ namespace GC auto it = worklist.begin(); auto stop = worklist.end(); // for (auto it = worklist.begin(); it != worklist.end();) { - while (it != stop) // while (it != stop) + while (it != stop) { Chunk *chunk = *it; @@ -201,10 +219,9 @@ namespace GC // Check if the stack pointer aligns with the chunk if (c_start <= *start && *start < c_end) { - if (!chunk->marked) { - if (Heap::get_profiler_mode()) + if (profiler_enabled) Profiler::record(ChunkMarked, chunk); chunk->marked = true; cout << "Marked this chunk ^\n" << endl; @@ -238,13 +255,13 @@ namespace GC // gets detected cout << "--- mark_step() was called ---\n" << endl; - for (; start <= end; start += sizeof(uintptr_t)) { - + for (; start <= end; start += sizeof(uintptr_t)) + { auto it = worklist.begin(); auto end = worklist.end(); - while (it != end) { - + while (it != end) + { Chunk *chunk = *it; auto c_start = reinterpret_cast(chunk->start); auto c_size = reinterpret_cast(chunk->size); @@ -254,8 +271,8 @@ namespace GC cout << "Chunk start:\t\t" << hex << c_start << endl; cout << "Chunk end:\t\t" << hex << c_end << "\n" << endl; - if (c_start <= start && start < c_end) { - + if (c_start <= start && start < c_end) + { if (!chunk->marked) { // Mark the chunk and erase it from the worklist chunk->marked = true; @@ -265,11 +282,13 @@ namespace GC //memory_location = c_end; mark_step(c_start, c_end, worklist); } - else { + else + { it++; } } - else { + else + { it++; } } @@ -287,6 +306,7 @@ namespace GC cout << "--- sweep() was called ---" << endl; auto iter = heap->m_allocated_chunks.begin(); auto stop = heap->m_allocated_chunks.end(); + bool profiler_enabled = heap->profiler_enabled(); // This cannot "iter != stop", results in seg fault, since the end gets updated, I think. while (iter != heap->m_allocated_chunks.end()) { @@ -302,7 +322,8 @@ namespace GC { // Add the unmarked chunks to freed chunks and remove from // the list of allocated chunks - Profiler::record(ChunkSwept, chunk); + if (profiler_enabled) + Profiler::record(ChunkSwept, chunk); heap->m_freed_chunks.push_back(chunk); iter = heap->m_allocated_chunks.erase(iter); } @@ -323,12 +344,15 @@ namespace GC cout << "--- free() was called ---" << endl; if (heap->m_freed_chunks.size() > FREE_THRESH) { + bool profiler_enabled = heap->profiler_enabled(); while (heap->m_freed_chunks.size()) { auto chunk = heap->m_freed_chunks.back(); heap->m_freed_chunks.pop_back(); - cout << "Freed chunk was deleted" << endl; + if (profiler_enabled) + Profiler::record(ChunkFreed, chunk); delete chunk; + cout << "Freed chunk was deleted" << endl; } } // if there are chunks but not more than FREE_THRESH @@ -351,7 +375,7 @@ namespace GC * @note Maybe this should be changed to prioritizing * larger chunks. */ - void Heap::free_overlap(Heap *heap) + void Heap::free_overlap(Heap *heap) // borde göra en record(ChunkFreed) på onödiga chunks { std::vector filtered; size_t i = 0; diff --git a/src/GC/lib/profiler.cpp b/src/GC/lib/profiler.cpp index f695fcc..ce6fc0b 100644 --- a/src/GC/lib/profiler.cpp +++ b/src/GC/lib/profiler.cpp @@ -19,9 +19,17 @@ namespace GC profiler->m_events.push_back(event); } + void Profiler::record(GCEventType type, size_t size) + { + auto event = new GCEvent(type, size); + auto profiler = Profiler::the(); + profiler->m_events.push_back(event); + } + void Profiler::record(GCEventType type, Chunk *chunk) { - auto event = new GCEvent(type, chunk); + auto chunk_copy = new Chunk(chunk); + auto event = new GCEvent(type, chunk_copy); auto profiler = Profiler::the(); profiler->m_events.push_back(event); } @@ -49,11 +57,13 @@ namespace GC fstr << "--------------------------------\n" << buffer << "\nEvent:\t" << event->type_to_string(); + + chunk = event->get_chunk(); if (chunk) { - fstr << "\nChunk:\t" << chunk->start + fstr << "\nChunk: " << chunk->start << "\n Size: " << chunk->size << "\n Mark: " << chunk->marked; } @@ -61,6 +71,13 @@ namespace GC } } + void Profiler::dispose() { + Profiler::record(ProfilerDispose); + Profiler::dump_trace(); + auto profiler = Profiler::the(); + delete profiler; + } + std::ofstream Profiler::create_file_stream() { std::time_t tt = std::time(NULL); diff --git a/src/GC/todo.md b/src/GC/todo.md index d8edd62..3fd98c6 100644 --- a/src/GC/todo.md +++ b/src/GC/todo.md @@ -7,6 +7,8 @@ Goal for next week (24/2): ## GC TODO: - Skriva klart profiler + - fixa abs_path i create_file_stream +- delete chunk i free_overlap - Kolla linking med Valter/Victor - Fixa en a-fil/static lib till Samuel - Kolla vektor vs list complexity @@ -16,3 +18,9 @@ då är alla efter varandra i minnet. ## Tests TODO - Write complex datastructures for tests with larger programs +## Profiler grejer +1. [x] Kolla existerande events +2. [x] Nya events för init, dispose i heap.cpp +3. [x] Skriv om try_recycle för att returnera en chunk +4. [x] Copy constructor för chunks (reused chunks) +5. [x] Nya events för try_recycle \ No newline at end of file