diff --git a/src/GC/Makefile b/src/GC/Makefile index 6b33ca8..1c2690a 100644 --- a/src/GC/Makefile +++ b/src/GC/Makefile @@ -18,7 +18,7 @@ file: heap: $(CC) $(WFLAGS) $(STDFLAGS) $(LIB_INCL) lib/heap.cpp -h_test: +h_test: static_lib rm -f tests/h_test.out # $(CC) $(WFLAGS) $(STDFLAGS) $(LIB_INCL) tests/h_test.cpp lib/heap.cpp lib/profiler.cpp lib/event.cpp -o tests/h_test.out $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -O3 -g -o tests/h_test.out tests/h_test.cpp lib/gcoll.a @@ -43,10 +43,10 @@ game: wrapper_test: rm -f lib/event.o lib/profiler.o lib/heap.o lib/coll.a tests/wrapper_test.out # compile object files - $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -O3 -g -c -o lib/event.o lib/event.cpp -fPIC - $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -O3 -g -c -o lib/profiler.o lib/profiler.cpp -fPIC - $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -O3 -g -c -o lib/heap.o lib/heap.cpp -fPIC - $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -O3 -g -c -o lib/cheap.o lib/cheap.cpp -fPIC + $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -g -c -o lib/event.o lib/event.cpp -fPIC + $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -g -c -o lib/profiler.o lib/profiler.cpp -fPIC + $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -g -c -o lib/heap.o lib/heap.cpp -fPIC + $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -g -c -o lib/cheap.o lib/cheap.cpp -fPIC # compile object files into library ar rcs lib/gcoll.a lib/event.o lib/profiler.o lib/heap.o lib/cheap.o clang -stdlib=libc++ $(WFLAGS) $(LIB_INCL) -o tests/wrapper_test.out tests/wrapper_test.c lib/gcoll.a -lstdc++ @@ -76,6 +76,12 @@ static_lib: static_lib_test: static_lib $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -o tests/extern_lib.out tests/extern_lib.cpp lib/gcoll.a +alloc_free_list: static_lib + $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -o tests/alloc_fl.out tests/alloc_free_list.cpp lib/gcoll.a + +linked_list_test: static_lib + $(CC) $(STDFLAGS) $(WFLAGS) $(LIB_INCL) -o tests/linkedlist.out tests/linkedlist.cpp lib/gcoll.a + wrapper: # remove old files rm -f lib/event.o lib/profiler.o lib/heap.o lib/coll.a tests/wrapper.out diff --git a/src/GC/include/cheap.h b/src/GC/include/cheap.h index 0f880e8..84f5971 100644 --- a/src/GC/include/cheap.h +++ b/src/GC/include/cheap.h @@ -8,8 +8,9 @@ extern "C" { #endif #define DEBUG +#define WRAPPER_DEBUG -#ifdef DEBUG +#ifdef WRAPPER_DEBUG typedef struct cheap { void *obj; @@ -19,11 +20,15 @@ struct cheap; typedef struct cheap cheap_t; #endif +#define FuncCallsOnly 0x1E +#define ChunkOpsOnly 0x3E0 + cheap_t *cheap_the(); void cheap_init(); void cheap_dispose(); void *cheap_alloc(unsigned long size); void cheap_set_profiler(cheap_t *cheap, bool mode); +void cheap_profiler_log_options(cheap_t *cheap, unsigned long flag); #ifdef __cplusplus } diff --git a/src/GC/include/event.hpp b/src/GC/include/event.hpp index 298ccab..c18b1ce 100644 --- a/src/GC/include/event.hpp +++ b/src/GC/include/event.hpp @@ -1,9 +1,6 @@ #pragma once #include -#include -#include -#include #include "chunk.hpp" @@ -14,16 +11,18 @@ namespace GC */ enum GCEventType { - HeapInit, - AllocStart, - CollectStart, - MarkStart, - ChunkMarked, - ChunkSwept, - ChunkFreed, - NewChunk, - ReusedChunk, - ProfilerDispose + HeapInit = 1 << 0, + AllocStart = 1 << 1, + CollectStart = 1 << 2, + MarkStart = 1 << 3, + SweepStart = 1 << 4, + ChunkMarked = 1 << 5, + ChunkSwept = 1 << 6, + ChunkFreed = 1 << 7, + NewChunk = 1 << 8, + ReusedChunk = 1 << 9, + ProfilerDispose = 1 << 10, + FreeStart = 1 << 11 }; /** diff --git a/src/GC/include/heap.hpp b/src/GC/include/heap.hpp index f877667..bd13af2 100644 --- a/src/GC/include/heap.hpp +++ b/src/GC/include/heap.hpp @@ -1,8 +1,6 @@ #pragma once -#include -#include -#include +#include #include #include #include @@ -10,9 +8,9 @@ #include "chunk.hpp" #include "profiler.hpp" -#define HEAP_SIZE 2097152 //256 //65536 //2097152 -#define FREE_THRESH (uint) 100000 //1000 -#define DEBUG +#define HEAP_SIZE 65536 +#define FREE_THRESH (uint) 100 +#define HEAP_DEBUG namespace GC { @@ -21,12 +19,12 @@ namespace GC * collection (mark/sweep/free/all). */ enum CollectOption { - MARK=0x1, - SWEEP=0x2, - MARK_SWEEP = 0x3, - FREE=0x4, - COLLECT_ALL=0x7 - }; + MARK = 1 << 0, + SWEEP = 1 << 1, + MARK_SWEEP = 1 << 2, + FREE = 1 << 3, + COLLECT_ALL = 0b1111 // all flags above + }; /** * The heap class to represent the heap for the @@ -48,13 +46,13 @@ 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::list m_free_list; std::unordered_map m_chunk_table; static bool profiler_enabled(); @@ -74,7 +72,6 @@ namespace GC // Temporary Chunk *try_recycle_chunks_new(size_t size); void free_overlap_new(Heap &heap); - public: /** * These are the only five functions which are exposed @@ -89,12 +86,13 @@ namespace GC static void dispose(); static void *alloc(size_t size); void set_profiler(bool mode); + void set_profiler_log_options(RecordOption flags); // Stop the compiler from generating copy-methods Heap(Heap const&) = delete; Heap& operator=(Heap const&) = delete; -#ifdef DEBUG +#ifdef HEAP_DEBUG void collect(CollectOption flags); // conditional collection void check_init(); // print dummy things void print_contents(); // print dummy things diff --git a/src/GC/include/profiler.hpp b/src/GC/include/profiler.hpp index ccdf463..f70ca3b 100644 --- a/src/GC/include/profiler.hpp +++ b/src/GC/include/profiler.hpp @@ -1,12 +1,32 @@ #pragma once +#include #include +#include #include "chunk.hpp" #include "event.hpp" +// #define FunctionCallTypes +// #define ChunkOpsTypes + namespace GC { + enum RecordOption + { + FunctionCalls = (GC::AllocStart | GC::CollectStart | GC::MarkStart | GC::SweepStart), + ChunkOps = (GC::ChunkMarked | GC::ChunkSwept | GC::ChunkFreed | GC::NewChunk | GC::ReusedChunk), + AllOps = 0xFFFFFF + }; + + struct ProfilerEvent + { + uint m_n {1}; + const GCEventType m_type; + + ProfilerEvent(GCEventType type) : m_type(type) {} + }; + class Profiler { private: Profiler() {} @@ -16,34 +36,36 @@ namespace GC { delete c; } - /** - * Returns the instance of the Profiler singleton. - * If m_instance is the nullptr and the profiler - * is not initialized yet, initialize it and return - * the pointer to it. Otherwise return the previously - * initialized pointer. - * - * @returns The pointer to the profiler singleton. - */ - static Profiler *the() - { - if (m_instance) - return m_instance; - m_instance = new Profiler(); - return m_instance; - } - + static Profiler &the(); inline static Profiler *m_instance {nullptr}; std::vector m_events; + ProfilerEvent *m_last_prof_event {new ProfilerEvent(HeapInit)}; + std::vector m_prof_events; + RecordOption flags; + std::chrono::microseconds alloc_time {0}; + // size_t alloc_counts {0}; + std::chrono::microseconds collect_time {0}; + // size_t collect_counts {0}; + + static void record_data(GCEvent *type); std::ofstream create_file_stream(); std::string get_log_folder(); static void dump_trace(); + static void dump_prof_trace(); + static void dump_chunk_trace(); + // static void dump_trace_short(); + // static void dump_trace_full(); + static void print_chunk_event(GCEvent *event, char buffer[22]); + static const char *type_to_string(GCEventType type); public: + static RecordOption log_options(); + static void set_log_options(RecordOption flags); static void record(GCEventType type); static void record(GCEventType type, size_t size); static void record(GCEventType type, Chunk *chunk); + static void record(GCEventType type, std::chrono::microseconds time); static void dispose(); }; } \ No newline at end of file diff --git a/src/GC/lib/cheap.cpp b/src/GC/lib/cheap.cpp index 29a0b10..42179b6 100644 --- a/src/GC/lib/cheap.cpp +++ b/src/GC/lib/cheap.cpp @@ -1,10 +1,10 @@ #include -#include +#include #include "heap.hpp" #include "cheap.h" -#ifndef DEBUG +#ifndef WRAPPER_DEBUG struct cheap { void *obj; @@ -45,4 +45,19 @@ void cheap_set_profiler(cheap_t *cheap, bool mode) GC::Heap *heap = static_cast(cheap->obj); heap->set_profiler(mode); +} + +void cheap_profiler_log_options(cheap_t *cheap, unsigned long flags) +{ + GC::Heap *heap = static_cast(cheap->obj); + + GC::RecordOption cast_flag; + if (flags == FuncCallsOnly) + cast_flag = GC::FunctionCalls; + else if (flags == ChunkOpsOnly) + cast_flag = GC::ChunkOps; + else + cast_flag = GC::AllOps; + + heap->set_profiler_log_options(cast_flag); } \ No newline at end of file diff --git a/src/GC/lib/event.cpp b/src/GC/lib/event.cpp index 185c613..89a2a71 100644 --- a/src/GC/lib/event.cpp +++ b/src/GC/lib/event.cpp @@ -1,7 +1,3 @@ -// #include -// #include -// #include - #include "chunk.hpp" #include "event.hpp" diff --git a/src/GC/lib/heap.cpp b/src/GC/lib/heap.cpp index d10ac90..565b425 100644 --- a/src/GC/lib/heap.cpp +++ b/src/GC/lib/heap.cpp @@ -1,16 +1,15 @@ -#include -#include -#include -#include #include -#include #include #include #include #include +#include #include "heap.hpp" +#define time_now std::chrono::high_resolution_clock::now() +#define to_us std::chrono::duration_cast + using std::cout, std::endl, std::vector, std::hex, std::dec, std::unordered_map; namespace GC @@ -42,6 +41,12 @@ namespace GC // clang complains because arg for __b_f_a is not 0 which is "unsafe" #pragma clang diagnostic ignored "-Wframe-address" heap.m_stack_top = static_cast(__builtin_frame_address(1)); + heap.m_heap_top = heap.m_heap; + } + + void Heap::set_profiler_log_options(RecordOption flags) + { + Profiler::set_log_options(flags); } /** @@ -67,6 +72,7 @@ namespace GC */ void *Heap::alloc(size_t size) { + auto a_start = time_now; // Singleton Heap &heap = Heap::the(); bool profiler_enabled = heap.profiler_enabled(); @@ -82,6 +88,8 @@ namespace GC if (heap.m_size + size > HEAP_SIZE) { + // auto a_ms = to_us(c_start - a_start); + // Profiler::record(AllocStart, a_ms); heap.collect(); // If memory is not enough after collect, crash with OOM error if (heap.m_size > HEAP_SIZE) @@ -90,6 +98,13 @@ namespace GC } //throw std::runtime_error(std::string("Error: Heap out of memory")); } + if (heap.m_size + size > HEAP_SIZE) + { + if (profiler_enabled) + Profiler::dispose(); + throw std::runtime_error(std::string("Error: Heap out of memory")); + } + } // If a chunk was recycled, return the old chunk address Chunk *reused_chunk = heap.try_recycle_chunks(size); @@ -97,6 +112,9 @@ namespace GC { if (profiler_enabled) Profiler::record(ReusedChunk, reused_chunk); + auto a_end = time_now; + auto a_ms = to_us(a_end - a_start); + Profiler::record(AllocStart, a_ms); return static_cast(reused_chunk->m_start); } @@ -111,6 +129,9 @@ namespace GC if (profiler_enabled) Profiler::record(NewChunk, new_chunk); + auto a_end = time_now; + auto a_ms = to_us(a_end - a_start); + Profiler::record(AllocStart, a_ms); return new_chunk->m_start; } @@ -166,25 +187,6 @@ namespace GC return nullptr; } - /** - * Advances an iterator and returns an element - * at position `n`. - * - * @param list The list to retrieve an element from. - * - * @param n The position to retrieve an element at. - * - * @returns The pointer to the chunk at position n in list. - */ - // Chunk *Heap::get_at(std::vector &list, size_t n) - // { - // auto iter = list.begin(); - // if (!n) - // return *iter; - // std::advance(iter, n); - // return *iter; - // } - /** * Returns a bool whether the profiler is enabled * or not. @@ -206,6 +208,8 @@ namespace GC */ void Heap::collect() { + auto c_start = time_now; + Heap &heap = Heap::the(); if (heap.profiler_enabled()) @@ -229,6 +233,10 @@ namespace GC sweep(heap); free(heap); + + auto c_end = time_now; + + Profiler::record(CollectStart, to_us(c_end - c_start)); } /** @@ -336,8 +344,10 @@ namespace GC */ void Heap::sweep(Heap &heap) { - auto iter = heap.m_allocated_chunks.begin(); bool profiler_enabled = heap.m_profiler_enable; + if (profiler_enabled) + Profiler::record(SweepStart); + auto iter = heap.m_allocated_chunks.begin(); // This cannot "iter != stop", results in seg fault, since the end gets updated, I think. while (iter != heap.m_allocated_chunks.end()) { @@ -357,6 +367,7 @@ namespace GC Profiler::record(ChunkSwept, chunk); heap.m_freed_chunks.push_back(chunk); iter = heap.m_allocated_chunks.erase(iter); + heap.m_size -= chunk->m_size; } } } @@ -376,6 +387,9 @@ namespace GC */ void Heap::free(Heap &heap) { + bool profiler_enabled = heap.m_profiler_enable; + if (profiler_enabled) + Profiler::record(FreeStart); if (heap.m_freed_chunks.size() > FREE_THRESH) { bool profiler_enabled = heap.profiler_enabled(); @@ -458,7 +472,13 @@ namespace GC } } -#ifdef DEBUG + void Heap::set_profiler(bool mode) + { + Heap &heap = Heap::the(); + heap.m_profiler_enable = mode; + } + +#ifdef HEAP_DEBUG /** * Prints the result of Heap::init() and a dummy value * for the current stack frame for reference. @@ -609,12 +629,6 @@ namespace GC } } - void Heap::set_profiler(bool mode) - { - Heap &heap = Heap::the(); - heap.m_profiler_enable = mode; - } - void Heap::print_allocated_chunks(Heap *heap) { cout << "--- Allocated Chunks ---\n" << endl; for (auto chunk : heap->m_allocated_chunks) { diff --git a/src/GC/lib/profiler.cpp b/src/GC/lib/profiler.cpp index d2e3246..78a0b8e 100644 --- a/src/GC/lib/profiler.cpp +++ b/src/GC/lib/profiler.cpp @@ -15,6 +15,38 @@ namespace GC { + Profiler& Profiler::the() + { + static Profiler instance; + return instance; + } + + RecordOption Profiler::log_options() + { + Profiler &prof = Profiler::the(); + return prof.flags; + } + + void Profiler::set_log_options(RecordOption flags) + { + Profiler &prof = Profiler::the(); + prof.flags = flags; + } + + void Profiler::record_data(GCEvent *event) + { + Profiler &prof = Profiler::the(); + prof.m_events.push_back(event); + + if (prof.m_last_prof_event->m_type == event->get_type()) + prof.m_last_prof_event->m_n++; + else + { + prof.m_prof_events.push_back(prof.m_last_prof_event); + prof.m_last_prof_event = new ProfilerEvent(event->get_type()); + } + } + /** * Records an event independent of a chunk. * @@ -22,9 +54,12 @@ namespace GC */ void Profiler::record(GCEventType type) { - auto event = new GCEvent(type); - auto profiler = Profiler::the(); - profiler->m_events.push_back(event); + Profiler &prof = Profiler::the(); + if (prof.flags & type) + Profiler::record_data(new GCEvent(type)); + // auto event = new GCEvent(type); + // auto profiler = Profiler::the(); + // profiler.m_events.push_back(event); } /** @@ -37,9 +72,21 @@ namespace GC */ void Profiler::record(GCEventType type, size_t size) { - auto event = new GCEvent(type, size); - auto profiler = Profiler::the(); - profiler->m_events.push_back(event); + Profiler &prof = Profiler::the(); + if (prof.flags & type) + Profiler::record_data(new GCEvent(type, size)); + // auto event = new GCEvent(type, size); + // auto profiler = Profiler::the(); + // profiler.m_events.push_back(event); + } + + void Profiler::dump_trace() + { + Profiler &prof = Profiler::the(); + if (prof.flags & FunctionCalls) + dump_prof_trace(); + else + dump_chunk_trace(); } /** @@ -56,60 +103,114 @@ namespace GC // because in free() chunks are deleted and cannot // be referenced by the profiler. These copied // chunks are deleted by the profiler on dispose(). - auto chunk_copy = new Chunk(chunk); - auto event = new GCEvent(type, chunk_copy); - auto profiler = Profiler::the(); - profiler->m_events.push_back(event); + Profiler &prof = Profiler::the(); + if (prof.flags & type) + { + auto chunk_copy = new Chunk(chunk); + auto event = new GCEvent(type, chunk_copy); + Profiler::record_data(event); + } + // auto profiler = Profiler::the(); + // profiler.m_events.push_back(event); + } + + void Profiler::record(GCEventType type, std::chrono::microseconds time) + { + Profiler &prof = Profiler::the(); + if (type == AllocStart) + { + prof.alloc_time += time; + } + else if (type == CollectStart) + { + prof.collect_time += time; + } + } + + void Profiler::dump_prof_trace() + { + Profiler &prof = Profiler::the(); + prof.m_prof_events.push_back(prof.m_last_prof_event); + auto start = prof.m_prof_events.begin(); + auto end = prof.m_prof_events.end(); + int allocs = 0, collects = 0; + + char buffer[22]; + std::ofstream fstr = prof.create_file_stream(); + + while (start != end) + { + auto event = *start++; + + if (event->m_type == AllocStart) + allocs += event->m_n; + else if (event->m_type == CollectStart) + collects += event->m_n; + + fstr << "\n--------------------------------\n" + << Profiler::type_to_string(event->m_type) << " " + << event->m_n << " times:"; + } + fstr << "\n--------------------------------"; + + fstr << "\n\nTime spent on allocations:\t" << prof.alloc_time.count() << " microseconds" + << "\nAllocation cycles:\t" << allocs + << "\nTime spent on collections:\t" << prof.collect_time.count() << " microseconds" + << "\nCollection cycles:\t" << collects + << "\n--------------------------------"; } /** * Prints the history of the recorded events * to a log file in the /tests/logs folder. */ - void Profiler::dump_trace() + void Profiler::dump_chunk_trace() { - auto profiler = Profiler::the(); - auto start = profiler->m_events.begin(); - auto end = profiler->m_events.end(); + Profiler &prof = Profiler::the(); + auto start = prof.m_events.begin(); + auto end = prof.m_events.end(); - // File output stream - std::ofstream fstr = profiler->create_file_stream(); // Buffer for timestamp char buffer[22]; - // Time variables - std::tm *btm; - std::time_t tt; - const Chunk *chunk; while (start != end) { auto event = *start++; + auto e_type = event->get_type(); - tt = event->get_time_stamp(); - btm = std::localtime(&tt); - std::strftime(buffer, 22, "%a %T", btm); - - fstr << "--------------------------------\n" - << buffer - << "\nEvent:\t" << event->type_to_string(); - - - - chunk = event->get_chunk(); - - if (event->get_type() == AllocStart) - { - fstr << "\nSize: " << event->get_size(); - } - else if (chunk) - { - fstr << "\nChunk: " << chunk->m_start - << "\n Size: " << chunk->m_size - << "\n Mark: " << chunk->m_marked; - } - fstr << "\n"; + prof.print_chunk_event(event, buffer); } - fstr << "--------------------------------" << std::endl; + } + + void Profiler::print_chunk_event(GCEvent *event, char buffer[22]) + { + Profiler &prof = Profiler::the(); + // File output stream + std::ofstream fstr = prof.create_file_stream(); + std::time_t tt = event->get_time_stamp(); + std::tm *btm = std::localtime(&tt); + std::strftime(buffer, 22, "%a %T", btm); + + fstr << "--------------------------------\n" + << buffer + << "\nEvent:\t" << Profiler::type_to_string(event->get_type()); + // event->type_to_string(); + + + + const Chunk *chunk = event->get_chunk(); + + if (event->get_type() == AllocStart) + { + fstr << "\nSize: " << event->get_size(); + } + else if (chunk) + { + fstr << "\nChunk: " << chunk->m_start + << "\n Size: " << chunk->m_size + << "\n Mark: " << chunk->m_marked; + } + fstr << "\n"; } /** @@ -122,8 +223,6 @@ namespace GC { Profiler::record(ProfilerDispose); Profiler::dump_trace(); - auto profiler = Profiler::the(); - delete profiler; } /** @@ -189,4 +288,24 @@ namespace GC #endif return folder + "/logs"; } + + const char *Profiler::type_to_string(GCEventType type) + { + switch (type) + { + case HeapInit: return "HeapInit"; + case AllocStart: return "AllocStart"; + case CollectStart: return "CollectStart"; + case MarkStart: return "MarkStart"; + case ChunkMarked: return "ChunkMarked"; + case ChunkSwept: return "ChunkSwept"; + case ChunkFreed: return "ChunkFreed"; + case NewChunk: return "NewChunk"; + case ReusedChunk: return "ReusedChunk"; + case ProfilerDispose: return "ProfilerDispose"; + case SweepStart: return "SweepStart"; + case FreeStart: return "FreeStart"; + default: return "[Unknown]"; + } + } } \ No newline at end of file diff --git a/src/GC/tests/advance.cpp b/src/GC/tests/advance.cpp index 92ce506..89dca71 100644 --- a/src/GC/tests/advance.cpp +++ b/src/GC/tests/advance.cpp @@ -5,40 +5,79 @@ #include #include -int main() { - using namespace std; - using TimeStamp = std::chrono::_V2::system_clock::time_point; +// void time_test() +// { +// using TimeStamp = std::chrono::_V2::system_clock::time_point; - list l; - char c = 'a'; - for (int i = 1; i <= 5; i++) { - l.push_back(c++); - } +// std::list l; +// char c = 'a'; +// for (int i = 1; i <= 5; i++) { +// l.push_back(c++); +// } - auto iter = l.begin(); - auto stop = l.end(); +// auto iter = l.begin(); +// auto stop = l.end(); - while (iter != stop) { - cout << *iter << " "; +// while (iter != stop) { +// std::cout << *iter << " "; +// iter++; +// } +// std::cout << std::endl; +// iter = l.begin(); +// while (*iter != *stop) { +// std::cout << *iter << " "; +// iter++; +// } +// std::cout << std::endl; + +// std::cout << "rebased" << std::endl; +// std::cout << "iter: " << *iter << "\nstop: " << *stop << std::endl; + +// TimeStamp ts = std::chrono::system_clock::now(); +// std::time_t tt = std::chrono::system_clock::to_time_t(ts); +// std::string tstr = std::ctime(&tt); +// tstr.resize(tstr.size()-1); +// std::cout << tstr << std::endl; +// } + +void iter_test() +{ + std::list list; + list.push_back(1); + list.push_back(2); + list.push_back(4); + list.push_back(5); + + auto iter = list.begin(); + + while (iter != list.end()) + { + if (*iter == 4) + { + iter = list.erase(iter); + std::cout << *iter << "\n"; + list.insert(iter, 3); + // list.insert(iter, 3); + // std::cout << "n: " << *(++iter) << "\n"; + // iter = list.erase(++iter); + } iter++; } - cout << endl; - iter = l.begin(); - while (*iter != *stop) { - cout << *iter << " "; - iter++; + + for (int i : list) + { + std::cout << i << " "; } - cout << endl; + std::cout << std::endl; +} - cout << "rebased" << endl; - cout << "iter: " << *iter << "\nstop: " << *stop << endl; - TimeStamp ts = std::chrono::system_clock::now(); - std::time_t tt = std::chrono::system_clock::to_time_t(ts); - std::string tstr = std::ctime(&tt); - tstr.resize(tstr.size()-1); - std::cout << tstr << std::endl; + +int main() { + std::cout << "hello" << std::endl; + + iter_test(); return 0; } \ No newline at end of file diff --git a/src/GC/tests/alloc_free_list.cpp b/src/GC/tests/alloc_free_list.cpp new file mode 100644 index 0000000..a0d1a27 --- /dev/null +++ b/src/GC/tests/alloc_free_list.cpp @@ -0,0 +1,250 @@ +#include +#include + +#include "heap.hpp" + +using GC::Chunk; + +void alloc_test(); +void add_to_free_list(Chunk *chunk); +void merge_free_list(Chunk *chunk, bool do_merge); +void do_merge_list(); +void print_free_list(); + +std::list m_free_list; + +int main() +{ + alloc_test(); + + // std::list test; + + // test.push_back(1); + // test.push_back(2); + // test.push_back(3); + // test.push_back(4); + // test.push_back(5); + + // auto iter = test.begin(); + + // std::cout << "First? " << *(iter++) << "\n"; + // std::cout << "Second? " << *(iter--) << "\n"; + // std::cout << "First? " << *iter << std::endl; + + // auto i = test.begin(); + // while (i != test.end()) + // { + // std::cout << *i << " "; + // ++i; + // } + + // if (i == test.end()) + // std::cout << "great success!"; + + // std::cout << std::endl; + + return 0; +} + +void alloc_test() +{ + auto tmp = static_cast(__builtin_frame_address(0)); + + auto c1 = new Chunk((size_t)(8), tmp); + auto c2 = new Chunk((size_t)(4), c1->m_start + (size_t)(8)); + auto c3 = new Chunk((size_t)(16), c2->m_start + (size_t)(4)); + auto c4 = new Chunk((size_t)(4), c3->m_start + (size_t)(16)); + auto c5 = new Chunk((size_t)(32), c4->m_start + (size_t)(4)); + + // std::cout << "test: " << (uintptr_t *)(tmp + (size_t)(2)) << std::endl; + + std::cout << "tmp: " << tmp << "\ntmp: " << (tmp + (size_t)(28)) << std::endl; + + // add_to_free_list(c1); + // add_to_free_list(c2); + // add_to_free_list(c3); + // add_to_free_list(c4); + // add_to_free_list(c5); + + merge_free_list(c1, false); + merge_free_list(c2, false); + merge_free_list(c3, false); + merge_free_list(c4, false); + merge_free_list(c5, false); + + std::cout << "----- BEFORE MERGE ----------------------"; + // print_free_list(); + + do_merge_list(); + + std::cout << "----- AFTER MERGE -----------------------"; + // print_free_list(); +} + +void add_to_free_list(Chunk *chunk) +{ + Chunk *curr; + auto iter = m_free_list.begin(); + uintptr_t *prev_start = nullptr; + uintptr_t *prev_end = nullptr; + + if (m_free_list.size() == 0) + { + m_free_list.push_back(chunk); + return; + } + + while (iter != m_free_list.end()) + { + curr = *iter; + + // If the curr chunk is aligned before param + if (curr->m_start + curr->m_size == chunk->m_start) + { + Chunk *merged = new Chunk( + curr->m_size + chunk->m_size, + curr->m_start); + iter = m_free_list.erase(iter); + m_free_list.insert(iter, merged); + return; + } + + // If the curr chunk is aligned after param + if (chunk->m_start + chunk->m_size == curr->m_start) + { + Chunk *merged = new Chunk( + curr->m_size + chunk->m_size, + chunk->m_start); + iter = m_free_list.erase(iter); + m_free_list.insert(iter, merged); + return; + } + + // If the first chunk starts after param + if (prev_start == nullptr && curr->m_start > chunk->m_start) + { + m_free_list.insert(iter, chunk); + return; + } + + if (prev_end < chunk->m_start && (chunk->m_start + chunk->m_size) < curr->m_start) + { + m_free_list.insert(iter, chunk); + return; + } + + prev_start = curr->m_start; + prev_end = prev_start + curr->m_size; + iter++; + } + + // This is only reachable if the chunk is at the end + m_free_list.push_back(chunk); +} + +void merge_free_list(Chunk *chunk, bool do_merge) +{ + auto i = m_free_list.begin(); + uintptr_t *prev_start = nullptr, *prev_end; + bool chunk_inserted = false; + + while (i != m_free_list.end()) + { + + // if chunk is left-aligned + if ((*i)->m_start + (*i)->m_size == chunk->m_start) + { + m_free_list.insert(++i, chunk); + chunk_inserted = true; + break; + } + + // if chunk is right-aligned + if (chunk->m_start + chunk->m_size == (*i)->m_start) + { + m_free_list.insert(i, chunk); + chunk_inserted = true; + break; + } + + // is new first + if (prev_start == nullptr && (*i)->m_start > chunk->m_start) + { + m_free_list.insert(i, chunk); + chunk_inserted = true; + break; + } + + // if between chunks + if (prev_end < chunk->m_start && (chunk->m_start + chunk->m_size) < (*i)->m_start) + { + m_free_list.insert(i, chunk); + chunk_inserted = true; + break; + } + + prev_start = (*i)->m_start; + prev_end = (*i)->m_start + (*i)->m_size; + i++; + } + + // is new last + if (!chunk_inserted && i == m_free_list.end()) + m_free_list.push_back(chunk); + + if (do_merge) + do_merge_list(); +} + +void do_merge_list() +{ + std::cout << "DO MERGE" << std::endl; + auto i = m_free_list.begin(); + Chunk *prev = *(i++), *curr; + print_free_list(); + + while (i != m_free_list.end()) + { + curr = *i; + + if ((prev->m_start + prev->m_size) == curr->m_start) + { + Chunk *merged = new Chunk( + prev->m_size + curr->m_size, + prev->m_start + ); + + // replace current and previous with merged + i = m_free_list.erase(i); + i = m_free_list.erase(--i); + m_free_list.insert(i, merged); + + prev = merged; + } + else + { + prev = curr; + i++; + } + print_free_list(); + } + print_free_list(); +} + +void print_free_list() +{ + std::cout << "free-list count: " << m_free_list.size() << "\n"; + + auto iter = m_free_list.begin(); + size_t cnt = 1; + + while (iter != m_free_list.end()) + { + std::cout << "C" << cnt << ":\n\tstart: " << (*iter)->m_start + << "\n\tsize: " << (*iter)->m_size << "\n"; + iter++; + cnt++; + } + + std::cout << std::endl; +} \ No newline at end of file diff --git a/src/GC/tests/events.cpp b/src/GC/tests/events.cpp deleted file mode 100644 index e517092..0000000 --- a/src/GC/tests/events.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -using namespace std; -// broken :( -// [event_source(native)] -class ESource { -public: - __event void TestEvent(int eValue); -}; - -// [event_receiver(native)] -class EReceiver { -public: - void Handler1(int eValue) { - cout << "Handler1 with: " << eValue << endl; - } - - void Handler2(int eValue) { - cout << "Handler2 with: " << eValue << endl; - } - - void hookEvent(ESource *eSource) { - __hook(&ESource::TestEvent, eSource, &EReceiver::Handler1); - __hook(&ESource::TestEvent, eSource, &EReceiver::Handler2); - } - - void unhookEvent(ESource *eSource) { - __unhook(&ESource::TestEvent, eSource, &EReceiver::Handler1); - __unhook(&ESource::TestEvent, eSource, &EReceiver::Handler2); - } -}; - -int main() { - - ESource src; - EReceiver rcv; - - rcv.hookEvent(&src); - __raise src.TestEvent(12); - rcv.unhookEvent(&src); - - return 0; -} \ No newline at end of file diff --git a/src/GC/tests/h_test.cpp b/src/GC/tests/h_test.cpp index 3e0a00b..6ce727e 100644 --- a/src/GC/tests/h_test.cpp +++ b/src/GC/tests/h_test.cpp @@ -80,6 +80,7 @@ int main() { GC::Heap::init(); GC::Heap &gc = GC::Heap::the(); gc.set_profiler(true); + GC::Profiler::set_log_options(GC::FunctionCalls); gc.check_init(); auto stack_start = reinterpret_cast(__builtin_frame_address(0)); diff --git a/src/GC/tests/linkedlist.cpp b/src/GC/tests/linkedlist.cpp new file mode 100644 index 0000000..61ab3c4 --- /dev/null +++ b/src/GC/tests/linkedlist.cpp @@ -0,0 +1,74 @@ +#include +#include + +#include "heap.hpp" + +#define allocNode static_cast(GC::Heap::alloc(sizeof(Node))) + +using std::cout, std::endl; + +struct Node // sizeof(Node) = 16 +{ + int value; + Node *next {nullptr}; +}; + +Node *create_list(size_t length) +{ + Node *head = allocNode; + head->value = 0; + + Node *prev = head; + + for (size_t i = 1; i < length; i++) + { + Node *next = allocNode; + next->value = i; + prev->next = next; + prev = next; + } + + return head; +} + +void print_list(Node* head) +{ + cout << "\nPrinting list...\n"; + while (head != nullptr) + { + cout << head->value << " "; + head = head->next; + } + cout << endl; +} + +void clear_list(Node *head) +{ + while (head != nullptr) + { + Node *tmp = head->next; + head->next = nullptr; + head = tmp; + } +} + +void run_list_test() +{ + Node *list = create_list(10); + print_list(list); +} + +int main() +{ + GC::Heap::init(); + GC::Heap &heap = GC::Heap::the(); + heap.set_profiler(true); + GC::Profiler::set_log_options(GC::FunctionCalls); + + for (int i = 0; i < 10; i++) + run_list_test(); + + GC::Heap::dispose(); + + return 0; +} \ No newline at end of file diff --git a/src/GC/tests/linker.cpp b/src/GC/tests/linker.cpp index 36717c5..fb5b979 100644 --- a/src/GC/tests/linker.cpp +++ b/src/GC/tests/linker.cpp @@ -9,22 +9,8 @@ struct Obj { }; int main() { - auto heap = GC::Heap::debug_the(); - - std::cout << "heap:\t" << heap << std::endl; - auto obj = static_cast(GC::Heap::alloc(sizeof(Obj))); - - std::cout << "obj: \t" << obj << std::endl; - - obj->a = 3; - obj->b = 4; - obj->c = 5; - - std::cout << obj->a << ", " << obj->b << ", " << obj->c << std::endl; - - heap->print_contents(); - //delete heap; + return 0; } \ No newline at end of file diff --git a/src/GC/tests/wrapper.c b/src/GC/tests/wrapper.c index bcd4859..d6f042c 100644 --- a/src/GC/tests/wrapper.c +++ b/src/GC/tests/wrapper.c @@ -21,23 +21,23 @@ void test_init() /* Uncomment ONLY if run with DEBUG defined in cheap.h */ -// cheap_t *test_the() -// { -// printf("----- IN TEST_THE -----------------------------\n"); +cheap_t *test_the() +{ + printf("----- IN TEST_THE -----------------------------\n"); -// cheap_t *fst_heap = cheap_the(); + cheap_t *fst_heap = cheap_the(); -// printf("Heap 1:\t%p\n", fst_heap->obj); + printf("Heap 1:\t%p\n", fst_heap->obj); -// cheap_t *snd_heap = cheap_the(); + cheap_t *snd_heap = cheap_the(); -// printf("Heap 2:\t%p\n", snd_heap->obj); + printf("Heap 2:\t%p\n", snd_heap->obj); -// printf("----- EXIT TEST_THE ---------------------------\n"); + printf("----- EXIT TEST_THE ---------------------------\n"); -// free(snd_heap); -// return fst_heap; -// } + free(snd_heap); + return fst_heap; +} void test_profiler(cheap_t *heap) { @@ -45,6 +45,7 @@ void test_profiler(cheap_t *heap) cheap_set_profiler(heap, false); cheap_set_profiler(heap, true); + cheap_profiler_log_options(heap, FuncCallsOnly); printf("----- EXIT TEST_PROFILER ----------------------\n"); } @@ -79,8 +80,8 @@ int main() test_init(); /* Uncomment ONLY if run with DEBUG defined in cheap.h */ - // cheap_t *heap = test_the(); - // test_profiler(heap); + cheap_t *heap = test_the(); + test_profiler(heap); Object *o = test_alloc(); printf("Object size: %lu\n", sizeof(Object));