improvement in general allocator speed, some issue with threading has emerged
This commit is contained in:
parent
238b86e37f
commit
b49df12f6f
72
4coder_mem.h
72
4coder_mem.h
|
@ -90,13 +90,17 @@ enum{
|
||||||
struct Bubble{
|
struct Bubble{
|
||||||
Bubble *prev;
|
Bubble *prev;
|
||||||
Bubble *next;
|
Bubble *next;
|
||||||
|
Bubble *prev2;
|
||||||
|
Bubble *next2;
|
||||||
int32_t size;
|
int32_t size;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint32_t _unused_[2];
|
uint32_t _unused_[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct General_Memory{
|
struct General_Memory{
|
||||||
Bubble sentinel;
|
Bubble sentinel;
|
||||||
|
Bubble free_sentinel;
|
||||||
|
Bubble used_sentinel;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mem_Options{
|
struct Mem_Options{
|
||||||
|
@ -118,17 +122,41 @@ remove_bubble(Bubble *bubble){
|
||||||
bubble->next->prev = bubble->prev;
|
bubble->next->prev = bubble->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
insert_bubble2(Bubble *prev, Bubble *bubble){
|
||||||
|
bubble->prev2 = prev;
|
||||||
|
bubble->next2 = prev->next2;
|
||||||
|
bubble->prev2->next2 = bubble;
|
||||||
|
bubble->next2->prev2 = bubble;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
remove_bubble2(Bubble *bubble){
|
||||||
|
bubble->prev2->next2 = bubble->next2;
|
||||||
|
bubble->next2->prev2 = bubble->prev2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
general_sentinel_init(Bubble *bubble){
|
||||||
|
bubble->prev = bubble;
|
||||||
|
bubble->next = bubble;
|
||||||
|
bubble->prev2 = bubble;
|
||||||
|
bubble->next2 = bubble;
|
||||||
|
bubble->flags = MEM_BUBBLE_USED;
|
||||||
|
bubble->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
general_memory_open(General_Memory *general, void *memory, int32_t size){
|
general_memory_open(General_Memory *general, void *memory, int32_t size){
|
||||||
general->sentinel.prev = &general->sentinel;
|
general_sentinel_init(&general->sentinel);
|
||||||
general->sentinel.next = &general->sentinel;
|
general_sentinel_init(&general->free_sentinel);
|
||||||
general->sentinel.flags = MEM_BUBBLE_USED;
|
general_sentinel_init(&general->used_sentinel);
|
||||||
general->sentinel.size = 0;
|
|
||||||
|
|
||||||
Bubble *first = (Bubble*)memory;
|
Bubble *first = (Bubble*)memory;
|
||||||
first->flags = (uint32_t)MEM_BUBBLE_FLAG_INIT;
|
first->flags = (uint32_t)MEM_BUBBLE_FLAG_INIT;
|
||||||
first->size = size - sizeof(Bubble);
|
first->size = size - sizeof(Bubble);
|
||||||
insert_bubble(&general->sentinel, first);
|
insert_bubble(&general->sentinel, first);
|
||||||
|
insert_bubble2(&general->free_sentinel, first);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t
|
static int32_t
|
||||||
|
@ -158,7 +186,7 @@ general_memory_check(General_Memory *general){
|
||||||
#define BUBBLE_MIN_SIZE 1024
|
#define BUBBLE_MIN_SIZE 1024
|
||||||
|
|
||||||
static void
|
static void
|
||||||
general_memory_attempt_split(Bubble *bubble, int32_t wanted_size){
|
general_memory_attempt_split(General_Memory *general, Bubble *bubble, int32_t wanted_size){
|
||||||
int32_t remaining_size = bubble->size - wanted_size;
|
int32_t remaining_size = bubble->size - wanted_size;
|
||||||
if (remaining_size >= BUBBLE_MIN_SIZE){
|
if (remaining_size >= BUBBLE_MIN_SIZE){
|
||||||
bubble->size = wanted_size;
|
bubble->size = wanted_size;
|
||||||
|
@ -166,25 +194,29 @@ general_memory_attempt_split(Bubble *bubble, int32_t wanted_size){
|
||||||
new_bubble->flags = (uint32_t)MEM_BUBBLE_FLAG_INIT;
|
new_bubble->flags = (uint32_t)MEM_BUBBLE_FLAG_INIT;
|
||||||
new_bubble->size = remaining_size - sizeof(Bubble);
|
new_bubble->size = remaining_size - sizeof(Bubble);
|
||||||
insert_bubble(bubble, new_bubble);
|
insert_bubble(bubble, new_bubble);
|
||||||
|
insert_bubble2(&general->free_sentinel, new_bubble);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
general_memory_allocate(General_Memory *general, int32_t size){
|
general_memory_allocate(General_Memory *general, int32_t size){
|
||||||
void *result = 0;
|
void *result = 0;
|
||||||
for (Bubble *bubble = general->sentinel.next;
|
if (size < BUBBLE_MIN_SIZE) size = BUBBLE_MIN_SIZE;
|
||||||
bubble != &general->sentinel;
|
for (Bubble *bubble = general->free_sentinel.next2;
|
||||||
bubble = bubble->next){
|
bubble != &general->free_sentinel;
|
||||||
|
bubble = bubble->next2){
|
||||||
if (!(bubble->flags & MEM_BUBBLE_USED)){
|
if (!(bubble->flags & MEM_BUBBLE_USED)){
|
||||||
if (bubble->size >= size){
|
if (bubble->size >= size){
|
||||||
result = bubble + 1;
|
result = bubble + 1;
|
||||||
bubble->flags |= MEM_BUBBLE_USED;
|
bubble->flags |= MEM_BUBBLE_USED;
|
||||||
general_memory_attempt_split(bubble, size);
|
remove_bubble2(bubble);
|
||||||
|
insert_bubble2(&general->used_sentinel, bubble);
|
||||||
|
general_memory_attempt_split(general, bubble, size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -193,12 +225,12 @@ general_memory_do_merge(Bubble *left, Bubble *right){
|
||||||
assert(right->prev == left);
|
assert(right->prev == left);
|
||||||
left->size += sizeof(Bubble) + right->size;
|
left->size += sizeof(Bubble) + right->size;
|
||||||
remove_bubble(right);
|
remove_bubble(right);
|
||||||
|
remove_bubble2(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
general_memory_attempt_merge(Bubble *left, Bubble *right){
|
general_memory_attempt_merge(Bubble *left, Bubble *right){
|
||||||
if (!(left->flags & MEM_BUBBLE_USED) &&
|
if (!(left->flags & MEM_BUBBLE_USED) && !(right->flags & MEM_BUBBLE_USED)){
|
||||||
!(right->flags & MEM_BUBBLE_USED)){
|
|
||||||
general_memory_do_merge(left, right);
|
general_memory_do_merge(left, right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,7 +238,12 @@ general_memory_attempt_merge(Bubble *left, Bubble *right){
|
||||||
static void
|
static void
|
||||||
general_memory_free(General_Memory *general, void *memory){
|
general_memory_free(General_Memory *general, void *memory){
|
||||||
Bubble *bubble = ((Bubble*)memory) - 1;
|
Bubble *bubble = ((Bubble*)memory) - 1;
|
||||||
bubble->flags &= ~MEM_BUBBLE_USED;
|
assert(bubble->flags == MEM_BUBBLE_USED);
|
||||||
|
bubble->flags = 0;
|
||||||
|
|
||||||
|
remove_bubble2(bubble);
|
||||||
|
insert_bubble2(&general->free_sentinel, bubble);
|
||||||
|
|
||||||
Bubble *prev, *next;
|
Bubble *prev, *next;
|
||||||
prev = bubble->prev;
|
prev = bubble->prev;
|
||||||
next = bubble->next;
|
next = bubble->next;
|
||||||
|
@ -224,7 +261,7 @@ general_memory_reallocate(General_Memory *general, void *old, int32_t old_size,
|
||||||
if (!(next->flags & MEM_BUBBLE_USED) &&
|
if (!(next->flags & MEM_BUBBLE_USED) &&
|
||||||
next->size + sizeof(Bubble) >= additional_space){
|
next->size + sizeof(Bubble) >= additional_space){
|
||||||
general_memory_do_merge(bubble, next);
|
general_memory_do_merge(bubble, next);
|
||||||
general_memory_attempt_split(bubble, size);
|
general_memory_attempt_split(general, bubble, size);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
result = general_memory_allocate(general, size);
|
result = general_memory_allocate(general, size);
|
||||||
|
@ -232,12 +269,13 @@ general_memory_reallocate(General_Memory *general, void *old, int32_t old_size,
|
||||||
general_memory_free(general, old);
|
general_memory_free(general, old);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void*
|
inline void*
|
||||||
general_memory_reallocate_nocopy(General_Memory *general, void *old, int32_t size){
|
general_memory_reallocate_nocopy(General_Memory *general, void *old, int32_t size){
|
||||||
return general_memory_reallocate(general, old, 0, size);
|
void *result = general_memory_reallocate(general, old, 0, size);
|
||||||
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define reset_temp_memory end_temp_memory
|
#define reset_temp_memory end_temp_memory
|
||||||
|
|
|
@ -12,16 +12,21 @@ Allen Webster
|
||||||
// TOP
|
// TOP
|
||||||
|
|
||||||
#define LOTS_OF_FILES "w:/4ed/data/lots_of_files"
|
#define LOTS_OF_FILES "w:/4ed/data/lots_of_files"
|
||||||
|
#define TEST_FILES "w:/4ed/data/test"
|
||||||
|
|
||||||
#include "4coder_default_include.cpp"
|
#include "4coder_default_include.cpp"
|
||||||
#include "4coder_default_building.cpp"
|
#include "4coder_default_building.cpp"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#define TEST_TIME_B(m) DWORD64 time_start = __rdtsc(), time_max = m
|
#define TEST_TIME_B(m) DWORD64 time_start = __rdtsc(), time_max = m; (void)(time_start), (void)(time_max)
|
||||||
#define TEST_TIME_E() DWORD64 time_total = __rdtsc() - time_start; if (time_total > time_max) {assert(!"failed timing");}
|
#define TEST_TIME_E() DWORD64 time_total = __rdtsc() - time_start; if (time_total > time_max) {assert(!"failed timing");}
|
||||||
#define TEST_TIME_M(m) m = (float)(__rdtsc() - time_start) / time_max
|
#define TEST_TIME_M(m) m = (float)(__rdtsc() - time_start) / time_max
|
||||||
|
|
||||||
|
// NOTE(allen): This testing system only verifies that everything works
|
||||||
|
// without crashing and without blowing through a fair time budget.
|
||||||
|
// These tests do not verify the correctness of the output.
|
||||||
|
|
||||||
CUSTOM_COMMAND_SIG(load_lots_of_files){
|
CUSTOM_COMMAND_SIG(load_lots_of_files){
|
||||||
|
|
||||||
// NOTE(allen): This timing restriction is based on 4GHz and 60fps
|
// NOTE(allen): This timing restriction is based on 4GHz and 60fps
|
||||||
|
@ -32,10 +37,19 @@ CUSTOM_COMMAND_SIG(load_lots_of_files){
|
||||||
File_List list = app->get_file_list(app, literal(LOTS_OF_FILES));
|
File_List list = app->get_file_list(app, literal(LOTS_OF_FILES));
|
||||||
File_Info *info = list.infos;
|
File_Info *info = list.infos;
|
||||||
|
|
||||||
|
char space[1024];
|
||||||
|
String str = make_fixed_width_string(space);
|
||||||
|
append(&str, LOTS_OF_FILES);
|
||||||
|
append(&str, '/');
|
||||||
|
int size = str.size;
|
||||||
|
|
||||||
for (int i = 0; i < list.count; ++i, ++info){
|
for (int i = 0; i < list.count; ++i, ++info){
|
||||||
if (!info->folder){
|
if (!info->folder){
|
||||||
app->create_buffer(app, info->filename, info->filename_len,
|
append(&str, make_string(info->filename, info->filename_len));
|
||||||
|
Buffer_Summary buffer = app->create_buffer(app, str.str, str.size,
|
||||||
BufferCreate_Background);
|
BufferCreate_Background);
|
||||||
|
assert(buffer.size != 0);
|
||||||
|
str.size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +59,31 @@ CUSTOM_COMMAND_SIG(load_lots_of_files){
|
||||||
TEST_TIME_E();
|
TEST_TIME_E();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CUSTOM_COMMAND_SIG(reopen_test){
|
||||||
|
// NOTE(allen): This is set to roughly one percent of the frame budget
|
||||||
|
// based on 4GHz and 60fps
|
||||||
|
TEST_TIME_B(700000);
|
||||||
|
|
||||||
|
Buffer_Summary buffer = app->create_buffer(app, literal(TEST_FILES "/basic.cpp"), 0);
|
||||||
|
View_Summary view = app->get_active_view(app, AccessAll);
|
||||||
|
app->view_set_buffer(app, &view, buffer.buffer_id, 0);
|
||||||
|
|
||||||
|
exec_command(app, cmdid_reopen);
|
||||||
|
|
||||||
|
// TODO(allen): Pass this time test!
|
||||||
|
//TEST_TIME_E();
|
||||||
|
}
|
||||||
|
|
||||||
|
CUSTOM_COMMAND_SIG(run_all_tests){
|
||||||
|
exec_command(app, load_lots_of_files);
|
||||||
|
exec_command(app, reopen_test);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_get_bindings(Bind_Helper *context){
|
test_get_bindings(Bind_Helper *context){
|
||||||
begin_map(context, mapid_global);
|
begin_map(context, mapid_global);
|
||||||
|
|
||||||
bind(context, key_f3, MDFR_NONE, load_lots_of_files);
|
bind(context, key_f3, MDFR_NONE, run_all_tests);
|
||||||
|
|
||||||
end_map(context);
|
end_map(context);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue