#include "utils/commons.h"
#include "mm_stack.h"
#define MM_STACK_INITIAL_SEGMENTS 10
#define MM_STACK_INITIAL_MALLOC_REQUESTS 10
#define MM_STACK_INITIAL_STATES 10
typedef struct {
uint64_t segment_idx;
uint64_t segment_used;
uint64_t num_malloc_requests;
} mm_stack_state_t;
typedef struct {
uint64_t size; void* memory; uint64_t used; } mm_stack_segment_t;
mm_stack_segment_t* mm_stack_segment_new(
mm_stack_t* const mm_stack) {
mm_stack_segment_t* const segment = (mm_stack_segment_t*) malloc(sizeof(mm_stack_segment_t));
segment->size = mm_stack->segment_size;
segment->memory = malloc(mm_stack->segment_size);
segment->used = 0;
vector_insert(mm_stack->segments,segment,mm_stack_segment_t*);
return segment;
}
void mm_stack_segment_clear(
mm_stack_segment_t* const segment) {
segment->used = 0;
}
void mm_stack_segment_delete(
mm_stack_segment_t* const segment) {
free(segment->memory);
free(segment);
}
mm_stack_t* mm_stack_new(
const uint64_t segment_size) {
mm_stack_t* const mm_stack = (mm_stack_t*) malloc(sizeof(mm_stack_t));
mm_stack->segments = vector_new(MM_STACK_INITIAL_SEGMENTS,mm_stack_segment_t*);
mm_stack->segment_size = segment_size;
#ifndef MM_STACK_FORCE_MALLOC
mm_stack_segment_new(mm_stack);
#endif
mm_stack->current_segment_idx = 0;
mm_stack->malloc_requests = vector_new(MM_STACK_INITIAL_MALLOC_REQUESTS,void*);
mm_stack->states = vector_new(MM_STACK_INITIAL_STATES,mm_stack_state_t);
return mm_stack;
}
void mm_stack_clear(
mm_stack_t* const mm_stack) {
mm_stack_segment_t* const segment = *vector_get_elm(mm_stack->segments,0,mm_stack_segment_t*);
mm_stack_segment_clear(segment);
mm_stack->current_segment_idx = 0;
VECTOR_ITERATE(mm_stack->malloc_requests,mem_ptr,m,void*) {
free(*mem_ptr);
}
vector_clear(mm_stack->malloc_requests);
vector_clear(mm_stack->states);
}
void mm_stack_delete(
mm_stack_t* const mm_stack) {
VECTOR_ITERATE(mm_stack->segments,segment_ptr,p,mm_stack_segment_t*) {
mm_stack_segment_delete(*segment_ptr);
}
vector_delete(mm_stack->segments);
VECTOR_ITERATE(mm_stack->malloc_requests,mem_ptr,m,void*) {
free(*mem_ptr);
}
vector_delete(mm_stack->malloc_requests);
vector_delete(mm_stack->states);
free(mm_stack);
}
mm_stack_segment_t* mm_stack_fetch_segment(
mm_stack_t* const mm_stack,
const uint64_t num_bytes) {
mm_stack_segment_t* const curr_segment =
*vector_get_elm(mm_stack->segments,mm_stack->current_segment_idx,mm_stack_segment_t*);
if (curr_segment->used + num_bytes <= curr_segment->size) {
return curr_segment;
}
if (num_bytes > curr_segment->size) {
return NULL; }
const uint64_t num_segments = vector_get_used(mm_stack->segments);
++(mm_stack->current_segment_idx);
if (mm_stack->current_segment_idx < num_segments) {
mm_stack_segment_t* const segment =
*vector_get_elm(mm_stack->segments,mm_stack->current_segment_idx,mm_stack_segment_t*);
mm_stack_segment_clear(segment);
return segment;
}
return mm_stack_segment_new(mm_stack);
}
void* mm_stack_allocate(
mm_stack_t* const mm_stack,
const uint64_t num_bytes,
const bool zero_mem,
const uint64_t align_bytes) {
if (num_bytes == 0) {
fprintf(stderr,"MMStack error. Zero bytes requested\n");
exit(1);
}
const uint64_t num_bytes_allocated = num_bytes + align_bytes;
#ifdef MM_STACK_FORCE_MALLOC
mm_stack_segment_t* const segment = NULL; #else
mm_stack_segment_t* const segment = mm_stack_fetch_segment(mm_stack,num_bytes_allocated);
#endif
void* memory_base ;
if (segment != NULL) {
memory_base = segment->memory + segment->used;
if (zero_mem) memset(memory_base,0,num_bytes_allocated); segment->used += num_bytes_allocated; } else {
memory_base = malloc(num_bytes_allocated);
if (zero_mem) memset(memory_base,0,num_bytes_allocated); vector_insert(mm_stack->malloc_requests,memory_base,void*);
}
if (align_bytes == 0) return memory_base;
void* memory_aligned = memory_base + align_bytes;
memory_aligned = memory_aligned - ((uintptr_t)memory_aligned % align_bytes);
return memory_aligned;
}
void mm_stack_push(
mm_stack_t* const mm_stack) {
mm_stack_state_t* stack_state;
vector_alloc_new(mm_stack->states,mm_stack_state_t,stack_state);
mm_stack_segment_t* const current_segment =
*vector_get_elm(mm_stack->segments,mm_stack->current_segment_idx,mm_stack_segment_t*);
stack_state->segment_idx = mm_stack->current_segment_idx;
stack_state->segment_used = current_segment->used;
stack_state->num_malloc_requests = vector_get_used(mm_stack->malloc_requests);
}
void mm_stack_pop(
mm_stack_t* const mm_stack) {
mm_stack_state_t* const stack_state = vector_get_last_elm(mm_stack->states,mm_stack_state_t);
vector_dec_used(mm_stack->states);
mm_stack->current_segment_idx = stack_state->segment_idx;
mm_stack_segment_t* const current_segment =
*(vector_get_elm(mm_stack->segments,stack_state->segment_idx,mm_stack_segment_t*));
current_segment->used = stack_state->segment_used;
const uint64_t total_malloc_requests = vector_get_used(mm_stack->malloc_requests);
void** const malloc_requests = vector_get_mem(mm_stack->malloc_requests,void*);
uint64_t i;
for (i=stack_state->num_malloc_requests;i<total_malloc_requests;++i) {
free(*(malloc_requests+i)); }
vector_set_used(mm_stack->malloc_requests,stack_state->num_malloc_requests);
}
void mm_stack_print(
FILE* const stream,
mm_stack_t* const mm_stack) {
fprintf(stream,"MMStack.report\n");
const uint64_t num_segments = vector_get_used(mm_stack->segments);
const uint64_t segment_size = mm_stack->segment_size;
fprintf(stream," => Segments.allocated %" PRIu64 "\n",num_segments);
fprintf(stream," => Segments.size %" PRIu64 " MB\n",segment_size/(1024*1024));
fprintf(stream," => Memory.available %" PRIu64 " MB\n",num_segments*(segment_size/(1024*1024)));
}