Comments
This commit is contained in:
parent
7105c570d9
commit
87dc0fef2d
6 changed files with 135 additions and 5 deletions
|
|
@ -5,6 +5,13 @@
|
||||||
|
|
||||||
namespace GC
|
namespace GC
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The basic element of what can be stored on
|
||||||
|
* the heap. A chunk contains a start address
|
||||||
|
* on the actual heap, the size of memory that
|
||||||
|
* is allocated at that address and if the
|
||||||
|
* chunk is reachable (marked).
|
||||||
|
*/
|
||||||
struct Chunk
|
struct Chunk
|
||||||
{
|
{
|
||||||
bool m_marked {false};
|
bool m_marked {false};
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@
|
||||||
|
|
||||||
namespace GC
|
namespace GC
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Types of events that can occur on the heap.
|
||||||
|
*/
|
||||||
enum GCEventType
|
enum GCEventType
|
||||||
{
|
{
|
||||||
HeapInit,
|
HeapInit,
|
||||||
|
|
@ -24,6 +26,9 @@ namespace GC
|
||||||
ProfilerDispose
|
ProfilerDispose
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores metadeta about an event on the heap.
|
||||||
|
*/
|
||||||
class GCEvent
|
class GCEvent
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,10 @@
|
||||||
|
|
||||||
namespace GC
|
namespace GC
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Flags for the collect overlead for conditional
|
||||||
|
* collection (mark/sweep/free/all).
|
||||||
|
*/
|
||||||
enum CollectOption {
|
enum CollectOption {
|
||||||
MARK=0x1,
|
MARK=0x1,
|
||||||
SWEEP=0x2,
|
SWEEP=0x2,
|
||||||
|
|
@ -24,9 +27,16 @@ namespace GC
|
||||||
COLLECT_ALL=0x7
|
COLLECT_ALL=0x7
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The heap class to represent the heap for the
|
||||||
|
* garbage collection. The heap is a singleton
|
||||||
|
* instance and can be retrieved by Heap::the()
|
||||||
|
* inside the heap class. The heap is represented
|
||||||
|
* by a char array of size 65536 and can enable
|
||||||
|
* a profiler to track the actions on the heap.
|
||||||
|
*/
|
||||||
class Heap
|
class Heap
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Heap() : m_heap(static_cast<char *>(malloc(HEAP_SIZE))) {}
|
Heap() : m_heap(static_cast<char *>(malloc(HEAP_SIZE))) {}
|
||||||
|
|
||||||
|
|
@ -35,6 +45,14 @@ namespace GC
|
||||||
std::free((char *)m_heap);
|
std::free((char *)m_heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If m_instance is a nullptr (the singleton has not
|
||||||
|
* been initialized yet) initialize the singleton
|
||||||
|
* and return the pointer. Otherwise return the
|
||||||
|
* previously initialized pointer.
|
||||||
|
*
|
||||||
|
* @returns The pointer to the heap singleton.
|
||||||
|
*/
|
||||||
static Heap *the()
|
static Heap *the()
|
||||||
{
|
{
|
||||||
if (m_instance) // if m_instance is not a nullptr
|
if (m_instance) // if m_instance is not a nullptr
|
||||||
|
|
@ -43,6 +61,16 @@ namespace GC
|
||||||
return m_instance;
|
return m_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
static Chunk *get_at(std::vector<Chunk *> &list, size_t n)
|
static Chunk *get_at(std::vector<Chunk *> &list, size_t n)
|
||||||
{
|
{
|
||||||
auto iter = list.begin();
|
auto iter = list.begin();
|
||||||
|
|
@ -52,6 +80,13 @@ namespace GC
|
||||||
return *iter;
|
return *iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bool whether the profiler is enabled
|
||||||
|
* or not.
|
||||||
|
*
|
||||||
|
* @returns True or false if the profiler is enabled
|
||||||
|
* or disabled respectively.
|
||||||
|
*/
|
||||||
inline bool profiler_enabled() {
|
inline bool profiler_enabled() {
|
||||||
auto heap = Heap::the();
|
auto heap = Heap::the();
|
||||||
return heap->m_profiler_enable;
|
return heap->m_profiler_enable;
|
||||||
|
|
@ -60,7 +95,6 @@ namespace GC
|
||||||
char *const m_heap;
|
char *const m_heap;
|
||||||
size_t m_size {0};
|
size_t m_size {0};
|
||||||
inline static Heap *m_instance {nullptr};
|
inline static Heap *m_instance {nullptr};
|
||||||
// size_t m_allocated_size {0};
|
|
||||||
uintptr_t *m_stack_top {nullptr};
|
uintptr_t *m_stack_top {nullptr};
|
||||||
bool m_profiler_enable {false};
|
bool m_profiler_enable {false};
|
||||||
|
|
||||||
|
|
@ -85,6 +119,7 @@ namespace GC
|
||||||
* that the address of the topmost stack frame is
|
* that the address of the topmost stack frame is
|
||||||
* saved as the limit for scanning the stack in collect.
|
* saved as the limit for scanning the stack in collect.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void init();
|
static void init();
|
||||||
static void dispose();
|
static void dispose();
|
||||||
static void *alloc(size_t size);
|
static void *alloc(size_t size);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,15 @@ namespace GC {
|
||||||
delete c;
|
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()
|
static Profiler *the()
|
||||||
{
|
{
|
||||||
if (m_instance)
|
if (m_instance)
|
||||||
|
|
|
||||||
|
|
@ -7,27 +7,54 @@
|
||||||
|
|
||||||
namespace GC
|
namespace GC
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @returns The type of the event
|
||||||
|
*/
|
||||||
GCEventType GCEvent::get_type()
|
GCEventType GCEvent::get_type()
|
||||||
{
|
{
|
||||||
return m_type;
|
return m_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The time the event happened in
|
||||||
|
* the form of time_t.
|
||||||
|
*/
|
||||||
std::time_t GCEvent::get_time_stamp()
|
std::time_t GCEvent::get_time_stamp()
|
||||||
{
|
{
|
||||||
return m_timestamp;
|
return m_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the event is related to a chunk, this
|
||||||
|
* function returns the chunk that it is
|
||||||
|
* related to. If the event is independent
|
||||||
|
* of a chunk, it returns the nullptr.
|
||||||
|
*
|
||||||
|
* @returns A chunk pointer or the nullptr.
|
||||||
|
*/
|
||||||
const Chunk *GCEvent::get_chunk()
|
const Chunk *GCEvent::get_chunk()
|
||||||
{
|
{
|
||||||
return m_chunk;
|
return m_chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the event is an AllocStart event, this
|
||||||
|
* returns the size of the alloc() request.
|
||||||
|
* otherwise this returns 0.
|
||||||
|
*
|
||||||
|
* @returns A number representing the number
|
||||||
|
* of bytes requested to alloc()
|
||||||
|
* or 0 if the event is not an
|
||||||
|
* AllocStart event.
|
||||||
|
*/
|
||||||
size_t GCEvent::get_size()
|
size_t GCEvent::get_size()
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The string conversion of the event type.
|
||||||
|
*/
|
||||||
const char *GCEvent::type_to_string()
|
const char *GCEvent::type_to_string()
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,11 @@
|
||||||
|
|
||||||
namespace GC
|
namespace GC
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Records an event independent of a chunk.
|
||||||
|
*
|
||||||
|
* @param type The type of event to record.
|
||||||
|
*/
|
||||||
void Profiler::record(GCEventType type)
|
void Profiler::record(GCEventType type)
|
||||||
{
|
{
|
||||||
auto event = new GCEvent(type);
|
auto event = new GCEvent(type);
|
||||||
|
|
@ -20,6 +25,14 @@ namespace GC
|
||||||
profiler->m_events.push_back(event);
|
profiler->m_events.push_back(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This overload is only used with an AllocStart
|
||||||
|
* event.
|
||||||
|
*
|
||||||
|
* @param type The type of event to record.
|
||||||
|
*
|
||||||
|
* @param size The size of requested to alloc().
|
||||||
|
*/
|
||||||
void Profiler::record(GCEventType type, size_t size)
|
void Profiler::record(GCEventType type, size_t size)
|
||||||
{
|
{
|
||||||
auto event = new GCEvent(type, size);
|
auto event = new GCEvent(type, size);
|
||||||
|
|
@ -27,6 +40,14 @@ namespace GC
|
||||||
profiler->m_events.push_back(event);
|
profiler->m_events.push_back(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records an event related to a chunk.
|
||||||
|
*
|
||||||
|
* @param type The type of event to record.
|
||||||
|
*
|
||||||
|
* @param chunk The chunk the event is connected
|
||||||
|
* to.
|
||||||
|
*/
|
||||||
void Profiler::record(GCEventType type, Chunk *chunk)
|
void Profiler::record(GCEventType type, Chunk *chunk)
|
||||||
{
|
{
|
||||||
// Create a copy of chunk to store in the profiler
|
// Create a copy of chunk to store in the profiler
|
||||||
|
|
@ -39,6 +60,10 @@ namespace GC
|
||||||
profiler->m_events.push_back(event);
|
profiler->m_events.push_back(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the history of the recorded events
|
||||||
|
* to a log file in the /tests/logs folder.
|
||||||
|
*/
|
||||||
void Profiler::dump_trace()
|
void Profiler::dump_trace()
|
||||||
{
|
{
|
||||||
auto profiler = Profiler::the();
|
auto profiler = Profiler::the();
|
||||||
|
|
@ -85,6 +110,12 @@ namespace GC
|
||||||
fstr << "--------------------------------" << std::endl;
|
fstr << "--------------------------------" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the profiler singleton and all
|
||||||
|
* the events recorded after recording
|
||||||
|
* the ProfilerDispose event and dumping
|
||||||
|
* the history to a log file.
|
||||||
|
*/
|
||||||
void Profiler::dispose()
|
void Profiler::dispose()
|
||||||
{
|
{
|
||||||
Profiler::record(ProfilerDispose);
|
Profiler::record(ProfilerDispose);
|
||||||
|
|
@ -93,6 +124,13 @@ namespace GC
|
||||||
delete profiler;
|
delete profiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a filestream for the future
|
||||||
|
* log file to print the history to in
|
||||||
|
* dump_trace().
|
||||||
|
*
|
||||||
|
* @returns The output stream to the file.
|
||||||
|
*/
|
||||||
std::ofstream Profiler::create_file_stream()
|
std::ofstream Profiler::create_file_stream()
|
||||||
{
|
{
|
||||||
// get current time
|
// get current time
|
||||||
|
|
@ -114,6 +152,15 @@ namespace GC
|
||||||
return fstr;
|
return fstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function retrieves the current path of the
|
||||||
|
* executable to use for log files.
|
||||||
|
*
|
||||||
|
* @returns The path to the logs folder.
|
||||||
|
*
|
||||||
|
* @throws A runtime error if the call
|
||||||
|
* to readlink() fails.
|
||||||
|
*/
|
||||||
std::string Profiler::get_log_folder()
|
std::string Profiler::get_log_folder()
|
||||||
{
|
{
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue