#include "utils/commons.h"
#include "system/mm_allocator.h"
#include "wavefront_slab.h"
#define WF_SLAB_EXPAND_FACTOR 1.5f
#define WF_SLAB_QUEUES_LENGTH_INIT 100
wavefront_slab_t* wavefront_slab_new(
const int init_wf_length,
const bool allocate_backtrace,
const wf_slab_mode_t slab_mode,
mm_allocator_t* const mm_allocator) {
wavefront_slab_t* const wavefront_slab =
mm_allocator_alloc(mm_allocator,wavefront_slab_t);
wavefront_slab->allocate_backtrace = allocate_backtrace;
wavefront_slab->slab_mode = slab_mode;
wavefront_slab->init_wf_length = init_wf_length;
wavefront_slab->current_wf_length = init_wf_length;
wavefront_slab->wavefronts = vector_new(WF_SLAB_QUEUES_LENGTH_INIT,wavefront_t*);
wavefront_slab->wavefronts_free = vector_new(WF_SLAB_QUEUES_LENGTH_INIT,wavefront_t*);
wavefront_slab->memory_used = 0;
wavefront_slab->mm_allocator = mm_allocator;
return wavefront_slab;
}
void wavefront_slab_reap_free(
wavefront_slab_t* const wavefront_slab) {
wavefront_t** const wavefronts = vector_get_mem(wavefront_slab->wavefronts,wavefront_t*);
const int num_wavefronts = vector_get_used(wavefront_slab->wavefronts);
mm_allocator_t* const mm_allocator = wavefront_slab->mm_allocator;
int i, valid_idx = 0;
for (i=0;i<num_wavefronts;++i) {
switch (wavefronts[i]->status) {
case wavefront_status_deallocated:
mm_allocator_free(mm_allocator,wavefronts[i]); break;
case wavefront_status_busy:
wavefronts[valid_idx++] = wavefronts[i]; break;
case wavefront_status_free:
wavefront_free(wavefronts[i],mm_allocator); wavefront_slab->memory_used -= wavefront_get_size(wavefronts[i]);
mm_allocator_free(mm_allocator,wavefronts[i]); break;
}
}
vector_set_used(wavefront_slab->wavefronts,valid_idx);
vector_clear(wavefront_slab->wavefronts_free);
}
void wavefront_slab_reap_repurpose(
wavefront_slab_t* const wavefront_slab) {
const int current_wf_length = wavefront_slab->current_wf_length;
wavefront_t** const wavefronts = vector_get_mem(wavefront_slab->wavefronts,wavefront_t*);
const int num_wavefronts = vector_get_used(wavefront_slab->wavefronts);
mm_allocator_t* const mm_allocator = wavefront_slab->mm_allocator;
vector_reserve(wavefront_slab->wavefronts_free,num_wavefronts,false);
wavefront_t** const wavefronts_free = vector_get_mem(wavefront_slab->wavefronts_free,wavefront_t*);
int i, valid_idx = 0;
for (i=0;i<num_wavefronts;++i) {
switch (wavefronts[i]->status) {
case wavefront_status_deallocated:
mm_allocator_free(mm_allocator,wavefronts[i]); break;
case wavefront_status_busy:
case wavefront_status_free:
if (wavefronts[i]->wf_elements_allocated == current_wf_length) {
wavefronts[i]->status = wavefront_status_free; wavefronts[valid_idx] = wavefronts[i]; wavefronts_free[valid_idx] = wavefronts[i]; valid_idx++;
} else {
wavefront_free(wavefronts[i],mm_allocator); wavefront_slab->memory_used -= wavefront_get_size(wavefronts[i]);
mm_allocator_free(mm_allocator,wavefronts[i]); }
break;
}
}
vector_set_used(wavefront_slab->wavefronts,valid_idx);
vector_set_used(wavefront_slab->wavefronts_free,valid_idx);
}
void wavefront_slab_reap(
wavefront_slab_t* const wavefront_slab) {
wavefront_slab->current_wf_length = wavefront_slab->init_wf_length;
wavefront_slab_reap_repurpose(wavefront_slab); }
void wavefront_slab_clear(
wavefront_slab_t* const wavefront_slab) {
switch (wavefront_slab->slab_mode) {
case wf_slab_reuse:
wavefront_slab_reap_repurpose(wavefront_slab);
break;
case wf_slab_tight:
wavefront_slab->current_wf_length = wavefront_slab->init_wf_length;
wavefront_slab_reap_repurpose(wavefront_slab);
break;
}
}
void wavefront_slab_delete(
wavefront_slab_t* const wavefront_slab) {
mm_allocator_t* const mm_allocator = wavefront_slab->mm_allocator;
vector_delete(wavefront_slab->wavefronts_free);
wavefront_t** const wavefronts =
vector_get_mem(wavefront_slab->wavefronts,wavefront_t*);
const int num_wavefronts = vector_get_used(wavefront_slab->wavefronts);
int i;
for (i=0;i<num_wavefronts;++i) {
if (wavefronts[i]->status == wavefront_status_deallocated) {
mm_allocator_free(mm_allocator,wavefronts[i]); } else {
wavefront_free(wavefronts[i],mm_allocator); mm_allocator_free(mm_allocator,wavefronts[i]); }
}
vector_delete(wavefront_slab->wavefronts);
mm_allocator_free(wavefront_slab->mm_allocator,wavefront_slab);
}
void wavefront_slab_set_mode(
wavefront_slab_t* const wavefront_slab,
const wf_slab_mode_t slab_mode) {
if (slab_mode != wavefront_slab->slab_mode) {
wavefront_slab->slab_mode = slab_mode;
wavefront_slab->current_wf_length = wavefront_slab->init_wf_length;
wavefront_slab_reap_repurpose(wavefront_slab);
}
}
wavefront_t* wavefront_slab_allocate_new(
wavefront_slab_t* const wavefront_slab,
const int wf_length_requested,
const int min_lo,
const int max_hi) {
mm_allocator_t* const mm_allocator = wavefront_slab->mm_allocator;
wavefront_t* const wavefront = mm_allocator_alloc(mm_allocator,wavefront_t);
wavefront_allocate(wavefront,wf_length_requested,wavefront_slab->allocate_backtrace,mm_allocator);
vector_insert(wavefront_slab->wavefronts,wavefront,wavefront_t*);
wavefront_slab->memory_used += wavefront_get_size(wavefront);
wavefront->status = wavefront_status_busy;
wavefront_init(wavefront,min_lo,max_hi);
return wavefront;
}
wavefront_t* wavefront_slab_allocate_free(
wavefront_slab_t* const wavefront_slab,
const int min_lo,
const int max_hi) {
vector_t* const wavefronts_free = wavefront_slab->wavefronts_free;
wavefront_t* const wavefront = *(vector_get_last_elm(wavefronts_free,wavefront_t*));
vector_dec_used(wavefronts_free);
wavefront->status = wavefront_status_busy;
wavefront_init(wavefront,min_lo,max_hi);
return wavefront;
}
wavefront_t* wavefront_slab_allocate(
wavefront_slab_t* const wavefront_slab,
const int min_lo,
const int max_hi) {
vector_t* const wavefronts_free = wavefront_slab->wavefronts_free;
const int wf_length = WAVEFRONT_LENGTH(min_lo,max_hi);
if (wavefront_slab->slab_mode == wf_slab_reuse) {
if (wf_length > wavefront_slab->current_wf_length) {
const int proposed_wf_length = (float)wf_length * WF_SLAB_EXPAND_FACTOR;
wavefront_slab->current_wf_length = proposed_wf_length; wavefront_slab_reap_free(wavefront_slab); }
if (vector_get_used(wavefronts_free) > 0) {
return wavefront_slab_allocate_free(wavefront_slab,min_lo,max_hi);
} else {
return wavefront_slab_allocate_new(wavefront_slab,
wavefront_slab->current_wf_length,min_lo,max_hi);
}
} else { if (wf_length <= wavefront_slab->init_wf_length) {
if (vector_get_used(wavefronts_free) > 0) {
return wavefront_slab_allocate_free(wavefront_slab,min_lo,max_hi);
} else {
return wavefront_slab_allocate_new(wavefront_slab,
wavefront_slab->init_wf_length,min_lo,max_hi); }
} else {
return wavefront_slab_allocate_new(wavefront_slab,
wf_length,min_lo,max_hi); }
}
}
void wavefront_slab_free(
wavefront_slab_t* const wavefront_slab,
wavefront_t* const wavefront) {
const int wf_length = wavefront->wf_elements_allocated;
const bool repurpose_reuse =
(wavefront_slab->slab_mode == wf_slab_reuse) &&
(wf_length == wavefront_slab->current_wf_length);
const bool repurpose_tight =
(wavefront_slab->slab_mode == wf_slab_tight) &&
(wf_length == wavefront_slab->init_wf_length);
if (repurpose_reuse || repurpose_tight) {
wavefront->status = wavefront_status_free;
vector_insert(wavefront_slab->wavefronts_free,wavefront,wavefront_t*);
} else {
wavefront->status = wavefront_status_deallocated;
wavefront_slab->memory_used -= wavefront_get_size(wavefront);
wavefront_free(wavefront,wavefront_slab->mm_allocator);
}
}
uint64_t wavefront_slab_get_size(
wavefront_slab_t* const wavefront_slab) {
return wavefront_slab->memory_used;
}