progress on single async-filled computation artifact cache; hook up to text cache layer, eliminate bespoke cache for text only

This commit is contained in:
Ryan Fleury
2025-09-22 15:13:31 -07:00
parent 9459327687
commit 811e58c249
5 changed files with 306 additions and 514 deletions
+52 -6
View File
@@ -13,6 +13,8 @@ ac_init(void)
ac_shared->cache_slots_count = 256;
ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count);
ac_shared->cache_stripes = stripe_array_alloc(arena);
ac_shared->req_mutex = mutex_alloc();
ac_shared->req_arena = arena_alloc();
}
////////////////////////////////
@@ -88,12 +90,13 @@ ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create,
}
else
{
node = push_array(stripe->arena, AC_Node, 1);
DLLPushBack(slot->first, slot->last, node);
// TODO(rjf): string allocator for keys
node->key = str8_copy(stripe->arena, key);
node->working_count = 1;
node = push_array_no_zero(stripe->arena, AC_Node, 1);
}
MemoryZeroStruct(node);
DLLPushBack(slot->first, slot->last, node);
// TODO(rjf): string allocator for keys
node->key = str8_copy(stripe->arena, key);
node->working_count = 1;
}
}
if(found)
@@ -110,6 +113,7 @@ ac_artifact_from_key(Access *access, String8 key, AC_CreateFunctionType *create,
n->v.key = str8_copy(ac_shared->req_arena, key);
n->v.create = create;
}
cond_var_broadcast(async_tick_start_cond_var);
}
}
}
@@ -199,7 +203,49 @@ ac_tick(void)
//- rjf: do all requests on all lanes
for EachIndex(idx, reqs_count)
{
reqs[idx].create(reqs[idx].key);
lane_sync();
// rjf: compute val
void *val = reqs[idx].create(reqs[idx].key);
// rjf: create function -> cache
AC_Cache *cache = 0;
{
U64 cache_hash = u64_hash_from_str8(str8_struct(&reqs[idx].create));
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
RWMutexScope(cache_stripe->rw_mutex, 0)
{
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
{
if(c->create == reqs[idx].create)
{
cache = c;
break;
}
}
}
}
// rjf: write value into cache
if(lane_idx() == 0)
{
U64 hash = u64_hash_from_str8(reqs[idx].key);
U64 slot_idx = hash%cache->slots_count;
AC_Slot *slot = &cache->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
RWMutexScope(stripe->rw_mutex, 1)
{
for(AC_Node *n = slot->first; n != 0; n = n->next)
{
if(str8_match(n->key, reqs[idx].key, 0))
{
n->val = val;
ins_atomic_u64_dec_eval(&n->working_count);
}
}
}
}
}
lane_sync();
-3
View File
@@ -65,9 +65,6 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
fs_init();
#endif
#if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL)
txt_init();
#endif
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
mtx_init();
#endif
+11
View File
@@ -65,6 +65,10 @@ struct TCTX
Arena *access_arena;
Access *free_access;
Touch *free_touch;
// rjf: progress
U64 *progress_counter_ptr;
U64 *progress_target_ptr;
};
////////////////////////////////
@@ -108,4 +112,11 @@ internal void access_touch(Access *access, AccessPt *pt, CondVar cv);
//- rjf: access points
internal B32 access_pt_is_expired(AccessPt *pt);
//- rjf: progress counters
#define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr))
#define set_progress_target_ptr(ptr) (tctx_selected()->progress_target_ptr = (ptr))
#define set_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
#define add_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_add_eval(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
#define set_progress_target(val) (tctx_selected()->progress_target_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_target_ptr, (val)) : (void)0)
#endif // BASE_THREAD_CONTEXT_H
+238 -476
View File
@@ -1590,117 +1590,6 @@ txt_token_array_from_string__disasm_x64_intel(Arena *arena, U64 *bytes_processed
return result;
}
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void
txt_init(void)
{
Arena *arena = arena_alloc();
txt_shared = push_array(arena, TXT_Shared, 1);
txt_shared->arena = arena;
txt_shared->slots_count = 1024;
txt_shared->slots = push_array(arena, TXT_Slot, txt_shared->slots_count);
txt_shared->stripes = stripe_array_alloc(arena);
txt_shared->stripes_free_nodes = push_array(arena, TXT_Node *, txt_shared->stripes.count);
txt_shared->u2p_ring_size = KB(64);
txt_shared->u2p_ring_base = push_array_no_zero(arena, U8, txt_shared->u2p_ring_size);
txt_shared->u2p_ring_cv = cond_var_alloc();
txt_shared->u2p_ring_mutex = mutex_alloc();
txt_shared->evictor_thread = thread_launch(txt_evictor_thread__entry_point, 0);
}
////////////////////////////////
//~ rjf: Cache Lookups
internal TXT_TextInfo
txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang)
{
TXT_TextInfo info = {0};
if(!u128_match(hash, u128_zero()))
{
U64 slot_idx = hash.u64[1]%txt_shared->slots_count;
TXT_Slot *slot = &txt_shared->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx);
U64 stripe_idx = (stripe - txt_shared->stripes.v);
B32 found = 0;
MutexScopeR(stripe->rw_mutex)
{
for(TXT_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(hash, n->hash) && n->lang == lang)
{
MemoryCopyStruct(&info, &n->info);
info.bytes_processed = ins_atomic_u64_eval(&n->info.bytes_processed);
info.bytes_to_process = ins_atomic_u64_eval(&n->info.bytes_to_process);
found = 1;
access_touch(access, &n->access_pt, stripe->cv);
break;
}
}
}
B32 node_is_new = 0;
if(!found)
{
MutexScopeW(stripe->rw_mutex)
{
TXT_Node *node = 0;
for(TXT_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(hash, n->hash) && n->lang == lang)
{
node = n;
break;
}
}
if(node == 0)
{
node = txt_shared->stripes_free_nodes[stripe_idx];
if(node)
{
SLLStackPop(txt_shared->stripes_free_nodes[stripe_idx]);
}
else
{
node = push_array_no_zero(stripe->arena, TXT_Node, 1);
}
MemoryZeroStruct(node);
DLLPushBack(slot->first, slot->last, node);
node->hash = hash;
node->lang = lang;
node_is_new = 1;
}
}
}
if(node_is_new)
{
txt_u2p_enqueue_req(hash, lang, max_U64);
async_push_work(txt_parse_work);
}
}
return info;
}
internal TXT_TextInfo
txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out)
{
TXT_TextInfo result = {0};
for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1)
{
U128 hash = c_hash_from_key(key, rewind_idx);
result = txt_text_info_from_hash_lang(access, hash, lang);
if(result.lines_count != 0)
{
if(hash_out)
{
*hash_out = hash;
}
break;
}
}
return result;
}
////////////////////////////////
//~ rjf: Text Info Extractor Helpers
@@ -2062,120 +1951,61 @@ txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt)
}
////////////////////////////////
//~ rjf: Transfer Threads
//~ rjf: Artifact Cache Hooks / Lookups
internal B32
txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us)
typedef struct TXT_Artifact TXT_Artifact;
struct TXT_Artifact
{
B32 good = 0;
MutexScope(txt_shared->u2p_ring_mutex) for(;;)
{
U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos;
U64 available_size = txt_shared->u2p_ring_size - unconsumed_size;
if(available_size >= sizeof(hash)+sizeof(lang))
{
good = 1;
txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &hash);
txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &lang);
break;
}
if(os_now_microseconds() >= endt_us)
{
break;
}
cond_var_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, endt_us);
}
if(good)
{
cond_var_broadcast(txt_shared->u2p_ring_cv);
}
return good;
}
Arena *arena;
TXT_TextInfo info;
};
internal void
txt_u2p_dequeue_req(U128 *hash_out, TXT_LangKind *lang_out)
typedef struct TXT_ArtifactCreateShared TXT_ArtifactCreateShared;
struct TXT_ArtifactCreateShared
{
MutexScope(txt_shared->u2p_ring_mutex) for(;;)
{
U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos;
if(unconsumed_size >= sizeof(*hash_out) + sizeof(*lang_out))
{
txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, hash_out);
txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, lang_out);
break;
}
cond_var_wait(txt_shared->u2p_ring_cv, txt_shared->u2p_ring_mutex, max_U64);
}
cond_var_broadcast(txt_shared->u2p_ring_cv);
}
Arena *arena;
TXT_TextInfo info;
TXT_Artifact *artifact;
};
ASYNC_WORK_DEF(txt_parse_work)
internal void *
txt_artifact_create(String8 key)
{
ProfBeginFunction();
//- rjf: get next key
U128 hash = {0};
TXT_LangKind lang = TXT_LangKind_Null;
txt_u2p_dequeue_req(&hash, &lang);
Temp scratch = scratch_begin(0, 0);
Access *access = access_open();
//- rjf: unpack hash
U64 slot_idx = hash.u64[1]%txt_shared->slots_count;
TXT_Slot *slot = &txt_shared->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx);
//- rjf: take task
B32 got_task = 0;
MutexScopeR(stripe->rw_mutex)
//- rjf: get shared state
local_persist TXT_ArtifactCreateShared *shared = 0;
if(lane_idx() == 0)
{
for(TXT_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, hash) && n->lang == lang)
{
got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0);
break;
}
}
shared = push_array(scratch.arena, TXT_ArtifactCreateShared, 1);
}
lane_sync();
//- rjf: hash -> data
String8 data = {0};
if(got_task)
{
data = c_data_from_hash(access, hash);
}
//- rjf: unpack key
U128 hash = {0};
TXT_LangKind lang = TXT_LangKind_Null;
str8_deserial_read_struct(key, 0, &hash);
str8_deserial_read_struct(key, sizeof(hash), &lang);
String8 data = c_data_from_hash(access, hash);
TXT_LangLexFunctionType *lex_function = txt_lex_function_from_lang_kind(lang);
//- rjf: data -> text info
Arena *info_arena = 0;
TXT_TextInfo info = {0};
if(got_task && !u128_match(hash, u128_zero()))
if(!u128_match(hash, u128_zero()))
{
info_arena = arena_alloc();
//- rjf: grab pointers to working counters
U64 *bytes_processed_ptr = 0;
U64 *bytes_to_process_ptr = 0;
MutexScopeR(stripe->rw_mutex)
if(lane_idx() == 0)
{
for(TXT_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, hash) && n->lang == lang)
{
bytes_processed_ptr = &n->info.bytes_processed;
bytes_to_process_ptr = &n->info.bytes_to_process;
}
}
shared->arena = arena_alloc();
}
//- rjf: set # of bytes to process
if(bytes_to_process_ptr)
{
// (line ending calc) (line counting) (line measuring) (lexing)
ins_atomic_u64_eval_assign(bytes_to_process_ptr, Min(data.size, 1024) + data.size + data.size + data.size*(lang != TXT_LangKind_Null));
}
// (line ending calc) (line counting) (line measuring) (lexing)
set_progress_target(Min(data.size, 1024) + data.size + data.size + data.size*(lang != TXT_LangKind_Null));
//- rjf: detect line end kind
TXT_LineEndKind line_end_kind = TXT_LineEndKind_Null;
if(lane_idx() == 0)
{
U64 lf_count = 0;
U64 cr_count = 0;
@@ -2198,323 +2028,255 @@ ASYNC_WORK_DEF(txt_parse_work)
{
line_end_kind = TXT_LineEndKind_LF;
}
info.line_end_kind = line_end_kind;
}
//- rjf: bump progress
if(bytes_processed_ptr)
{
ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024));
shared->info.line_end_kind = line_end_kind;
}
lane_sync();
set_progress(Min(data.size, 1024));
//- rjf: count # of lines
U64 line_count = 1;
U64 byte_process_start_idx = 0;
for(U64 idx = 0; idx < data.size; idx += 1)
U64 lane_line_count = 0;
if(lane_idx() == 0)
{
if(data.str[idx] == '\n' || data.str[idx] == '\r')
lane_line_count = 1;
}
{
Rng1U64 range = lane_range(data.size);
for EachInRange(idx, range)
{
line_count += 1;
if(data.str[idx] == '\r')
if(data.str[idx] == '\n' || data.str[idx] == '\r')
{
idx += 1;
lane_line_count += 1;
if(data.str[idx] == '\r')
{
idx += 1;
}
}
if(idx && idx%1000 == 0)
{
add_progress(1000);
}
}
if(idx && idx%1000 == 0)
{
ins_atomic_u64_add_eval(bytes_processed_ptr, 1000);
}
}
//- rjf: bump progress
if(bytes_processed_ptr)
{
ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size);
}
ins_atomic_u64_add_eval(&shared->info.lines_count, lane_line_count);
lane_sync();
set_progress(Min(data.size, 1024) + data.size);
//- rjf: allocate & store line ranges
info.lines_count = line_count;
info.lines_ranges = push_array_no_zero(info_arena, Rng1U64, info.lines_count);
U64 line_idx = 0;
U64 line_start_idx = 0;
for(U64 idx = 0; idx <= data.size; idx += 1)
if(lane_idx() == 0)
{
if(idx == data.size || data.str[idx] == '\n' || data.str[idx] == '\r')
shared->info.lines_ranges = push_array_no_zero(shared->arena, Rng1U64, shared->info.lines_count);
U64 line_idx = 0;
U64 line_start_idx = 0;
for(U64 idx = 0; idx <= data.size; idx += 1)
{
Rng1U64 line_range = r1u64(line_start_idx, idx);
U64 line_size = dim_1u64(line_range);
info.lines_ranges[line_idx] = line_range;
info.lines_max_size = Max(info.lines_max_size, line_size);
line_idx += 1;
line_start_idx = idx+1;
if(idx < data.size && data.str[idx] == '\r')
if(idx == data.size || data.str[idx] == '\n' || data.str[idx] == '\r')
{
line_start_idx += 1;
idx += 1;
Rng1U64 line_range = r1u64(line_start_idx, idx);
U64 line_size = dim_1u64(line_range);
shared->info.lines_ranges[line_idx] = line_range;
shared->info.lines_max_size = Max(shared->info.lines_max_size, line_size);
line_idx += 1;
line_start_idx = idx+1;
if(idx < data.size && data.str[idx] == '\r')
{
line_start_idx += 1;
idx += 1;
}
}
if(idx && idx%1000 == 0)
{
add_progress(1000);
}
}
if(idx && idx%1000 == 0)
{
ins_atomic_u64_add_eval(bytes_processed_ptr, 1000);
}
}
//- rjf: bump progress
if(bytes_processed_ptr)
{
ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size + data.size);
}
lane_sync();
set_progress(Min(data.size, 1024) + data.size + data.size);
//- rjf: lex function * data -> tokens
TXT_TokenArray tokens = {0};
TXT_LangLexFunctionType *lex_function = txt_lex_function_from_lang_kind(lang);
if(lex_function != 0)
if(lane_idx() == 0 && lex_function != 0)
{
tokens = lex_function(info_arena, bytes_processed_ptr, data);
}
info.tokens = tokens;
//- rjf: bump progress
if(bytes_processed_ptr)
{
ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size + data.size + data.size*(lex_function != 0));
shared->info.tokens = lex_function(shared->arena, 0, data);
}
lane_sync();
set_progress(Min(data.size, 1024) + data.size + data.size + data.size*(lex_function != 0));
TXT_TokenArray tokens = shared->info.tokens;
//- rjf: count scope points
U64 scope_pt_opener_count = 0;
U64 scope_pt_count = 0;
for EachIndex(idx, tokens.count)
{
if(tokens.v[idx].kind == TXT_TokenKind_Symbol)
U64 lane_scope_pt_opener_count = 0;
U64 lane_scope_pt_count = 0;
Rng1U64 range = lane_range(tokens.count);
for EachInRange(idx, range)
{
String8 token_string = str8_substr(data, tokens.v[idx].range);
B32 is_opener = (token_string.str[0] == '{' ||
token_string.str[0] == '(' ||
token_string.str[0] == '[');
B32 is_closer = (token_string.str[0] == '}' ||
token_string.str[0] == ')' ||
token_string.str[0] == ']');
if(token_string.size == 1 && (is_opener || is_closer))
if(tokens.v[idx].kind == TXT_TokenKind_Symbol)
{
scope_pt_count += 1;
scope_pt_opener_count += !!is_opener;
}
}
}
//- rjf: allocate & fill scope data
info.scope_pts.count = scope_pt_count;
info.scope_pts.v = push_array_no_zero(info_arena, TXT_ScopePt, info.scope_pts.count);
info.scope_nodes.count = scope_pt_opener_count;
info.scope_nodes.v = push_array_no_zero(info_arena, TXT_ScopeNode, info.scope_nodes.count);
{
typedef struct ScopeTask ScopeTask;
struct ScopeTask
{
ScopeTask *next;
U64 scope_idx;
};
Temp scratch = scratch_begin(0, 0);
ScopeTask *top_scope_task = 0;
ScopeTask *free_scope_task = 0;
U64 pt_idx = 0;
U64 scope_idx = 0;
for EachIndex(token_idx, tokens.count)
{
if(tokens.v[token_idx].kind == TXT_TokenKind_Symbol)
{
String8 token_string = str8_substr(data, tokens.v[token_idx].range);
String8 token_string = str8_substr(data, tokens.v[idx].range);
B32 is_opener = (token_string.str[0] == '{' ||
token_string.str[0] == '(' ||
token_string.str[0] == '[');
B32 is_closer = (token_string.str[0] == '}' ||
token_string.str[0] == ')' ||
token_string.str[0] == ']');
// rjf: opener symbols -> push scope
if(is_opener)
if(token_string.size == 1 && (is_opener || is_closer))
{
// rjf: insert into scope tree
TXT_ScopeNode *new_scope = &info.scope_nodes.v[scope_idx];
new_scope->token_idx_range.min = token_idx;
if(top_scope_task)
{
U64 new_scope_num = scope_idx+1;
TXT_ScopeNode *parent = &info.scope_nodes.v[top_scope_task->scope_idx];
if(parent->first_num == 0)
{
parent->first_num = new_scope_num;
}
if(parent->last_num != 0)
{
TXT_ScopeNode *prev_scope = &info.scope_nodes.v[parent->last_num-1];
prev_scope->next_num = new_scope_num;
}
parent->last_num = new_scope_num;
new_scope->parent_num = top_scope_task->scope_idx+1;
}
lane_scope_pt_count += 1;
lane_scope_pt_opener_count += !!is_opener;
}
}
}
ins_atomic_u64_add_eval(&shared->info.scope_pts.count, lane_scope_pt_count);
ins_atomic_u64_add_eval(&shared->info.scope_nodes.count, lane_scope_pt_opener_count);
}
lane_sync();
//- rjf: allocate & fill scope data
if(lane_idx() == 0)
{
shared->info.scope_pts.v = push_array_no_zero(shared->arena, TXT_ScopePt, shared->info.scope_pts.count);
shared->info.scope_nodes.v = push_array_no_zero(shared->arena, TXT_ScopeNode, shared->info.scope_nodes.count);
{
typedef struct ScopeTask ScopeTask;
struct ScopeTask
{
ScopeTask *next;
U64 scope_idx;
};
Temp scratch = scratch_begin(0, 0);
ScopeTask *top_scope_task = 0;
ScopeTask *free_scope_task = 0;
U64 pt_idx = 0;
U64 scope_idx = 0;
for EachIndex(token_idx, tokens.count)
{
if(tokens.v[token_idx].kind == TXT_TokenKind_Symbol)
{
String8 token_string = str8_substr(data, tokens.v[token_idx].range);
B32 is_opener = (token_string.str[0] == '{' ||
token_string.str[0] == '(' ||
token_string.str[0] == '[');
B32 is_closer = (token_string.str[0] == '}' ||
token_string.str[0] == ')' ||
token_string.str[0] == ']');
// rjf: push onto scope stack
ScopeTask *scope_task = free_scope_task;
if(scope_task)
// rjf: opener symbols -> push scope
if(is_opener)
{
SLLStackPop(free_scope_task);
}
else
{
scope_task = push_array(scratch.arena, ScopeTask, 1);
}
scope_task->scope_idx = scope_idx;
scope_idx += 1;
SLLStackPush(top_scope_task, scope_task);
}
// rjf: opener or closer -> fill endpoint
if(top_scope_task && (is_opener || is_closer))
{
info.scope_pts.v[pt_idx].token_idx = token_idx;
info.scope_pts.v[pt_idx].scope_idx = top_scope_task->scope_idx;
pt_idx += 1;
}
// rjf: closer symbols -> pop
if(is_closer && top_scope_task != 0)
{
ScopeTask *popped = top_scope_task;
info.scope_nodes.v[popped->scope_idx].token_idx_range.max = token_idx;
SLLStackPop(top_scope_task);
SLLStackPush(free_scope_task, popped);
}
}
}
scratch_end(scratch);
}
}
//- rjf: commit results to cache
if(got_task) MutexScopeW(stripe->rw_mutex)
{
for(TXT_Node *n = slot->first; n != 0; n = n->next)
{
if(u128_match(n->hash, hash) && n->lang == lang)
{
c_hash_downstream_inc(n->hash);
n->arena = info_arena;
info.bytes_processed = n->info.bytes_processed;
info.bytes_to_process = n->info.bytes_to_process;
MemoryCopyStruct(&n->info, &info);
ins_atomic_u32_eval_assign(&n->is_working, 0);
ins_atomic_u64_inc_eval(&n->load_count);
break;
}
}
}
access_close(access);
ProfEnd();
return 0;
}
////////////////////////////////
//~ rjf: Evictor Threads
internal void
txt_evictor_thread__entry_point(void *p)
{
ThreadNameF("txt_evictor_thread");
for(;;)
{
for(U64 slot_idx = 0; slot_idx < txt_shared->slots_count; slot_idx += 1)
{
TXT_Slot *slot = &txt_shared->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx);
U64 stripe_idx = (stripe - txt_shared->stripes.v);
B32 slot_has_work = 0;
MutexScopeR(stripe->rw_mutex)
{
for(TXT_Node *n = slot->first; n != 0; n = n->next)
{
if(access_pt_is_expired(&n->access_pt) &&
n->load_count != 0 &&
n->is_working == 0)
{
slot_has_work = 1;
break;
}
}
}
if(slot_has_work) MutexScopeW(stripe->rw_mutex)
{
for(TXT_Node *n = slot->first, *next = 0; n != 0; n = next)
{
next = n->next;
if(access_pt_is_expired(&n->access_pt) &&
n->load_count != 0 &&
n->is_working == 0)
{
DLLRemove(slot->first, slot->last, n);
c_hash_downstream_dec(n->hash);
if(n->arena != 0)
{
arena_release(n->arena);
}
SLLStackPush(txt_shared->stripes_free_nodes[stripe_idx], n);
}
}
}
}
os_sleep_milliseconds(500);
}
}
////////////////////////////////
//~ rjf: Tick
internal void
txt_tick(void)
{
//- rjf: do eviction pass
{
Rng1U64 range = lane_range(txt_shared->slots_count);
for EachInRange(slot_idx, range)
{
TXT_Slot *slot = &txt_shared->slots[slot_idx];
Stripe *stripe = stripe_from_slot_idx(&txt_shared->stripes, slot_idx);
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
{
B32 slot_has_work = 0;
RWMutexScope(stripe->rw_mutex, write_mode)
{
for(TXT_Node *n = slot->first, *next = 0; n != 0; n = next)
{
next = n->next;
if(access_pt_is_expired(&n->access_pt) &&
n->load_count != 0 &&
n->is_working == 0)
{
slot_has_work = 1;
if(!write_mode)
// rjf: insert into scope tree
TXT_ScopeNode *new_scope = &shared->info.scope_nodes.v[scope_idx];
new_scope->token_idx_range.min = token_idx;
if(top_scope_task)
{
break;
U64 new_scope_num = scope_idx+1;
TXT_ScopeNode *parent = &shared->info.scope_nodes.v[top_scope_task->scope_idx];
if(parent->first_num == 0)
{
parent->first_num = new_scope_num;
}
if(parent->last_num != 0)
{
TXT_ScopeNode *prev_scope = &shared->info.scope_nodes.v[parent->last_num-1];
prev_scope->next_num = new_scope_num;
}
parent->last_num = new_scope_num;
new_scope->parent_num = top_scope_task->scope_idx+1;
}
// rjf: push onto scope stack
ScopeTask *scope_task = free_scope_task;
if(scope_task)
{
SLLStackPop(free_scope_task);
}
else
{
DLLRemove(slot->first, slot->last, n);
c_hash_downstream_dec(n->hash);
if(n->arena != 0)
{
arena_release(n->arena);
}
SLLStackPush(txt_shared->stripes_free_nodes[(stripe - txt_shared->stripes.v)], n);
scope_task = push_array(scratch.arena, ScopeTask, 1);
}
scope_task->scope_idx = scope_idx;
scope_idx += 1;
SLLStackPush(top_scope_task, scope_task);
}
// rjf: opener or closer -> fill endpoint
if(top_scope_task && (is_opener || is_closer))
{
shared->info.scope_pts.v[pt_idx].token_idx = token_idx;
shared->info.scope_pts.v[pt_idx].scope_idx = top_scope_task->scope_idx;
pt_idx += 1;
}
// rjf: closer symbols -> pop
if(is_closer && top_scope_task != 0)
{
ScopeTask *popped = top_scope_task;
shared->info.scope_nodes.v[popped->scope_idx].token_idx_range.max = token_idx;
SLLStackPop(top_scope_task);
SLLStackPush(free_scope_task, popped);
}
}
}
if(!slot_has_work)
{
break;
}
scratch_end(scratch);
}
}
lane_sync();
}
//- rjf: package as artifact
if(lane_idx() == 0 && shared->arena != 0)
{
shared->artifact = push_array(shared->arena, TXT_Artifact, 1);
shared->artifact->arena = shared->arena;
shared->artifact->info = shared->info;
}
lane_sync();
access_close(access);
scratch_end(scratch);
ProfEnd();
return shared->artifact;
}
internal void
txt_artifact_destroy(void *ptr)
{
if(ptr == 0) { return; }
TXT_Artifact *artifact = (TXT_Artifact *)ptr;
arena_release(artifact->arena);
}
internal TXT_TextInfo
txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang)
{
struct
{
U128 hash;
TXT_LangKind lang;
} key = {hash, lang};
String8 key_string = str8_struct(&key);
TXT_Artifact *artifact = ac_artifact_from_key(access, key_string, txt_artifact_create, txt_artifact_destroy, 1024);
TXT_TextInfo info = {0};
if(artifact != 0)
{
info = artifact->info;
}
return info;
}
internal TXT_TextInfo
txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out)
{
TXT_TextInfo result = {0};
for(U64 rewind_idx = 0; rewind_idx < C_KEY_HASH_HISTORY_COUNT; rewind_idx += 1)
{
U128 hash = c_hash_from_key(key, rewind_idx);
result = txt_text_info_from_hash_lang(access, hash, lang);
if(result.lines_count != 0)
{
if(hash_out)
{
*hash_out = hash;
}
break;
}
}
return result;
}
+5 -29
View File
@@ -208,9 +208,6 @@ struct TXT_Shared
{
Arena *arena;
// rjf: user clock
U64 user_clock_idx;
// rjf: cache
U64 slots_count;
TXT_Slot *slots;
@@ -240,7 +237,6 @@ struct TXT_Shared
//~ rjf: Globals
read_only global TXT_ScopeNode txt_scope_node_nil = {0};
global TXT_Shared *txt_shared = 0;
////////////////////////////////
//~ rjf: Basic Helpers
@@ -267,17 +263,6 @@ internal TXT_TokenArray txt_token_array_from_string__jai(Arena *arena, U64 *byte
internal TXT_TokenArray txt_token_array_from_string__zig(Arena *arena, U64 *bytes_processed_counter, String8 string);
internal TXT_TokenArray txt_token_array_from_string__disasm_x64_intel(Arena *arena, U64 *bytes_processed_counter, String8 string);
////////////////////////////////
//~ rjf: Main Layer Initialization
internal void txt_init(void);
////////////////////////////////
//~ rjf: Cache Lookups
internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang);
internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out);
////////////////////////////////
//~ rjf: Text Info Extractor Helpers
@@ -294,20 +279,11 @@ internal TXT_ScopeNode *txt_scope_node_from_info_off(TXT_TextInfo *info, U64 off
internal TXT_ScopeNode *txt_scope_node_from_info_pt(TXT_TextInfo *info, TxtPt pt);
////////////////////////////////
//~ rjf: Parse Threads
//~ rjf: Artifact Cache Hooks / Lookups
internal B32 txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us);
internal void txt_u2p_dequeue_req(U128 *hash_out, TXT_LangKind *lang_out);
ASYNC_WORK_DEF(txt_parse_work);
////////////////////////////////
//~ rjf: Evictor Threads
internal void txt_evictor_thread__entry_point(void *p);
////////////////////////////////
//~ rjf: Tick
internal void txt_tick(void);
internal void *txt_artifact_create(String8 key);
internal void txt_artifact_destroy(void *ptr);
internal TXT_TextInfo txt_text_info_from_hash_lang(Access *access, U128 hash, TXT_LangKind lang);
internal TXT_TextInfo txt_text_info_from_key_lang(Access *access, C_Key key, TXT_LangKind lang, U128 *hash_out);
#endif // TEXT_CACHE_H