diff options
author | bfredl <bjorn.linse@gmail.com> | 2022-08-23 10:36:46 +0200 |
---|---|---|
committer | bfredl <bjorn.linse@gmail.com> | 2022-08-24 14:22:26 +0200 |
commit | bcf5ee328e228d5a536b4de2069a79234f9f3e9e (patch) | |
tree | ce25e8627bb00363deb6919561400fa1807ebf47 | |
parent | c0d60526541a3cf977ae623471ae4a347b492af1 (diff) | |
download | rneovim-bcf5ee328e228d5a536b4de2069a79234f9f3e9e.tar.gz rneovim-bcf5ee328e228d5a536b4de2069a79234f9f3e9e.tar.bz2 rneovim-bcf5ee328e228d5a536b4de2069a79234f9f3e9e.zip |
refactor(arena): use a shared block freelist
This is both simpler in client code and more effective (always reuse
block hottest in cache)
-rw-r--r-- | src/nvim/eval/funcs.c | 11 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 3 | ||||
-rw-r--r-- | src/nvim/generators/gen_api_dispatch.lua | 5 | ||||
-rw-r--r-- | src/nvim/highlight_group.c | 2 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 2 | ||||
-rw-r--r-- | src/nvim/memory.c | 50 | ||||
-rw-r--r-- | src/nvim/memory.h | 2 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 8 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/unpacker.c | 12 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/unpacker.h | 2 | ||||
-rw-r--r-- | src/nvim/popupmenu.c | 3 | ||||
-rw-r--r-- | src/nvim/screen.c | 3 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 2 | ||||
-rw-r--r-- | src/nvim/ui.c | 3 | ||||
-rw-r--r-- | src/nvim/ui.h | 2 |
15 files changed, 49 insertions, 61 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 5db584f6a8..cacac91ee8 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -114,8 +114,6 @@ static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); static char *e_invalwindow = N_("E957: Invalid window number"); static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); -static ArenaMem eval_reuse_blk = NULL; - /// Dummy va_list for passing to vim_snprintf /// /// Used because: @@ -281,10 +279,6 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) Error err = ERROR_INIT; Arena res_arena = ARENA_EMPTY; - if (handler.arena_return) { - // TODO(bfredl): also use arena for vim_to_object - arena_start(&res_arena, &eval_reuse_blk); - } Object result = handler.fn(VIML_INTERNAL_CALL, args, &res_arena, &err); if (ERROR_SET(&err)) { @@ -299,7 +293,7 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) end: api_free_array(args); if (handler.arena_return) { - arena_mem_free(arena_finish(&res_arena), &eval_reuse_blk); + arena_mem_free(arena_finish(&res_arena)); } else { api_free_object(result); } @@ -6885,7 +6879,6 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) uint64_t chan_id = (uint64_t)argvars[0].vval.v_number; const char *method = tv_get_string(&argvars[1]); - // TODO: putta in eval_reuse_blk ArenaMem res_mem = NULL; Object result = rpc_send_call(chan_id, method, args, &res_mem, &err); @@ -6921,7 +6914,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } end: - arena_mem_free(res_mem, &eval_reuse_blk); + arena_mem_free(res_mem); api_clear_error(&err); } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 9a7b093282..ef6e1cbb22 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3154,7 +3154,6 @@ draw_cmdline_no_arabicshape: static void ui_ext_cmdline_show(CmdlineInfo *line) { Arena arena = ARENA_EMPTY; - arena_start(&arena, &ui_ext_fixblk); Array content; if (cmdline_star) { content = arena_array(&arena, 1); @@ -3199,7 +3198,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) line->special_shift, line->level); } - arena_mem_free(arena_finish(&arena), &ui_ext_fixblk); + arena_mem_free(arena_finish(&arena)); } void ui_ext_cmdline_block_append(size_t indent, const char *line) diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index e4798bf5ce..67b8f5f0f5 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -413,8 +413,6 @@ output:write([[ #include "nvim/lua/executor.h" #include "nvim/memory.h" -static ArenaMem lua_reuse_blk = { 0 }; - ]]) include_headers(output, headers) output:write('\n') @@ -496,7 +494,6 @@ local function process_function(fn) cparams = cparams .. '&arena, ' write_shifted_output(output, [[ Arena arena = ARENA_EMPTY; - arena_start(&arena, &lua_reuse_blk); ]]) end @@ -536,7 +533,7 @@ local function process_function(fn) end local free_retval if fn.arena_return then - free_retval = "arena_mem_free(arena_finish(&arena), &lua_reuse_blk);" + free_retval = "arena_mem_free(arena_finish(&arena));" else free_retval = "api_free_"..return_type:lower().."(ret);" end diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 65a50df274..3bdaee8066 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -1303,7 +1303,7 @@ void free_highlight(void) { ga_clear(&highlight_ga); map_destroy(cstr_t, int)(&highlight_unames); - arena_mem_free(arena_finish(&highlight_arena), NULL); + arena_mem_free(arena_finish(&highlight_arena)); } #endif diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index d1d1480696..8316ab3bd1 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1093,7 +1093,7 @@ static int nlua_rpc(lua_State *lstate, bool request) Object result = rpc_send_call(chan_id, name, args, &res_mem, &err); if (!ERROR_SET(&err)) { nlua_push_Object(lstate, result, false); - arena_mem_free(res_mem, NULL); + arena_mem_free(res_mem); } } else { if (!rpc_send_event(chan_id, name, args)) { diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 91f066f458..7b4b104ec7 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -60,6 +60,8 @@ void try_to_free_memory(void) // Try to save all buffers and release as many blocks as possible mf_release_all(); + arena_free_reuse_blks(); + trying_to_free = false; } @@ -528,23 +530,18 @@ void time_to_bytes(time_t time_, uint8_t buf[8]) } #define ARENA_BLOCK_SIZE 4096 +#define REUSE_MAX 4 -void arena_start(Arena *arena, ArenaMem *reuse_blk) -{ - if (reuse_blk && *reuse_blk) { - arena->cur_blk = (char *)(*reuse_blk); - *reuse_blk = NULL; - arena->size = ARENA_BLOCK_SIZE; - arena->pos = 0; +static struct consumed_blk *arena_reuse_blk; +static size_t arena_reuse_blk_count = 0; - // address is the same as as (struct consumed_blk *)arena->cur_blk - struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true); - assert((char *)blk == (char *)arena->cur_blk); - blk->prev = NULL; - } else { - arena->cur_blk = NULL; - arena->size = 0; - arena->pos = 0; +static void arena_free_reuse_blks(void) +{ + while (arena_reuse_blk_count > 0) { + struct consumed_blk *blk = arena_reuse_blk; + arena_reuse_blk = arena_reuse_blk->prev; + xfree(blk); + arena_reuse_blk_count--; } } @@ -564,12 +561,18 @@ ArenaMem arena_finish(Arena *arena) void alloc_block(Arena *arena) { struct consumed_blk *prev_blk = (struct consumed_blk *)arena->cur_blk; - arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE); + if (arena_reuse_blk_count > 0) { + arena->cur_blk = (char *)arena_reuse_blk; + arena_reuse_blk = arena_reuse_blk->prev; + arena_reuse_blk_count--; + } else { + arena_alloc_count++; + arena->cur_blk = xmalloc(ARENA_BLOCK_SIZE); + } arena->pos = 0; arena->size = ARENA_BLOCK_SIZE; struct consumed_blk *blk = arena_alloc(arena, sizeof(struct consumed_blk), true); blk->prev = prev_blk; - arena_alloc_count++; } /// @param size if zero, will still return a non-null pointer, but not a unique one @@ -606,15 +609,17 @@ void *arena_alloc(Arena *arena, size_t size, bool align) return mem; } -void arena_mem_free(ArenaMem mem, ArenaMem *reuse_blk) +void arena_mem_free(ArenaMem mem) { struct consumed_blk *b = mem; // peel of the first block, as it is guaranteed to be ARENA_BLOCK_SIZE, // not a custom fix_blk - if (reuse_blk && *reuse_blk == NULL && b != NULL) { - *reuse_blk = b; + if (arena_reuse_blk_count < REUSE_MAX && b != NULL) { + struct consumed_blk *reuse_blk = b; b = b->prev; - (*reuse_blk)->prev = NULL; + reuse_blk->prev = arena_reuse_blk; + arena_reuse_blk = reuse_blk; + arena_reuse_blk_count++; } while (b) { @@ -815,6 +820,9 @@ void free_all_mem(void) nlua_free_all_mem(); ui_free_all_mem(); + + // should be last, in case earlier free functions deallocates arenas + arena_free_reuse_blks(); } #endif diff --git a/src/nvim/memory.h b/src/nvim/memory.h index 5e37847beb..f407192331 100644 --- a/src/nvim/memory.h +++ b/src/nvim/memory.h @@ -52,7 +52,7 @@ typedef struct { size_t pos, size; } Arena; -// inits an empty arena. use arena_start() to actually allocate space! +// inits an empty arena. #define ARENA_EMPTY { .cur_blk = NULL, .pos = 0, .size = 0 } #define kv_fixsize_arena(a, v, s) \ diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 66fd79c692..f00c62f766 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -158,7 +158,7 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem } // frame.result was allocated in an arena - arena_mem_free(frame.result_mem, &rpc->unpacker->reuse_blk); + arena_mem_free(frame.result_mem); frame.result_mem = NULL; } @@ -244,7 +244,7 @@ static void parse_msgpack(Channel *channel) ui_client_event_raw_line(p->grid_line_event); } else if (p->ui_handler.fn != NULL && p->result.type == kObjectTypeArray) { p->ui_handler.fn(p->result.data.array); - arena_mem_free(arena_finish(&p->arena), &p->reuse_blk); + arena_mem_free(arena_finish(&p->arena)); } } else if (p->type == kMessageTypeResponse) { ChannelCallFrame *frame = kv_last(channel->rpc.call_stack); @@ -295,7 +295,7 @@ static void handle_request(Channel *channel, Unpacker *p, Array args) if (!p->handler.fn) { send_error(channel, p->type, p->request_id, p->unpack_error.msg); api_clear_error(&p->unpack_error); - arena_mem_free(arena_finish(&p->arena), &p->reuse_blk); + arena_mem_free(arena_finish(&p->arena)); return; } @@ -364,7 +364,7 @@ static void request_event(void **argv) free_ret: // e->args (and possibly result) are allocated in an arena - arena_mem_free(arena_finish(&e->used_mem), &channel->rpc.unpacker->reuse_blk); + arena_mem_free(arena_finish(&e->used_mem)); channel_decref(channel); xfree(e); api_clear_error(&error); diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c index c8e9fdd4c3..24480835a1 100644 --- a/src/nvim/msgpack_rpc/unpacker.c +++ b/src/nvim/msgpack_rpc/unpacker.c @@ -181,13 +181,11 @@ void unpacker_init(Unpacker *p) p->unpack_error = (Error)ERROR_INIT; p->arena = (Arena)ARENA_EMPTY; - p->reuse_blk = NULL; } void unpacker_teardown(Unpacker *p) { - arena_mem_free(p->reuse_blk, NULL); - arena_mem_free(arena_finish(&p->arena), NULL); + arena_mem_free(arena_finish(&p->arena)); } bool unpacker_parse_header(Unpacker *p) @@ -308,7 +306,7 @@ bool unpacker_advance(Unpacker *p) p->state = 10; } else { p->state = p->type == kMessageTypeResponse ? 1 : 2; - arena_start(&p->arena, &p->reuse_blk); + p->arena = (Arena)ARENA_EMPTY; } } @@ -322,7 +320,7 @@ bool unpacker_advance(Unpacker *p) goto done; } else { // unpack other ui events using mpack_parse() - arena_start(&p->arena, &p->reuse_blk); + p->arena = (Arena)ARENA_EMPTY; } } @@ -416,13 +414,13 @@ redo: if (p->ui_handler.fn != ui_client_event_grid_line) { p->state = 12; if (p->grid_line_event) { - arena_mem_free(arena_finish(&p->arena), &p->reuse_blk); + arena_mem_free(arena_finish(&p->arena)); p->grid_line_event = NULL; } return true; } else { p->state = 13; - arena_start(&p->arena, &p->reuse_blk); + p->arena = (Arena)ARENA_EMPTY; p->grid_line_event = arena_alloc(&p->arena, sizeof *p->grid_line_event, true); g = p->grid_line_event; } diff --git a/src/nvim/msgpack_rpc/unpacker.h b/src/nvim/msgpack_rpc/unpacker.h index f39439be63..35048fb877 100644 --- a/src/nvim/msgpack_rpc/unpacker.h +++ b/src/nvim/msgpack_rpc/unpacker.h @@ -32,8 +32,6 @@ struct Unpacker { Error unpack_error; Arena arena; - // one length free-list of reusable blocks - ArenaMem reuse_blk; int nevents; int ncalls; diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index d392bb5a2c..f570556a29 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -156,7 +156,6 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i if (pum_external) { if (array_changed) { Arena arena = ARENA_EMPTY; - arena_start(&arena, &ui_ext_fixblk); Array arr = arena_array(&arena, (size_t)size); for (int i = 0; i < size; i++) { Array item = arena_array(&arena, 4); @@ -168,7 +167,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i } ui_call_popupmenu_show(arr, selected, pum_win_row, cursor_col, pum_anchor_grid); - arena_mem_free(arena_finish(&arena), &ui_ext_fixblk); + arena_mem_free(arena_finish(&arena)); } else { ui_call_popupmenu_select(selected); return; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index b471b93192..89b24e9440 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1094,7 +1094,6 @@ void draw_tabline(void) static void ui_ext_tabline_update(void) { Arena arena = ARENA_EMPTY; - arena_start(&arena, &ui_ext_fixblk); size_t n_tabs = 0; FOR_ALL_TABS(tp) { @@ -1135,7 +1134,7 @@ static void ui_ext_tabline_update(void) } ui_call_tabline_update(curtab->handle, tabs, curbuf->handle, buffers); - arena_mem_free(arena_finish(&arena), &ui_ext_fixblk); + arena_mem_free(arena_finish(&arena)); } void get_trans_bufname(buf_T *buf) diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 61a59bcf06..6afe7defe3 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -238,7 +238,7 @@ static void tinput_wait_enqueue(void **argv) ArenaMem res_mem = NULL; Object result = rpc_send_call(ui_client_channel_id, "nvim_input", args, &res_mem, &err); consumed = result.type == kObjectTypeInteger ? (size_t)result.data.integer : 0; - arena_mem_free(res_mem, NULL); + arena_mem_free(res_mem); } else { consumed = input_enqueue(keys); } diff --git a/src/nvim/ui.c b/src/nvim/ui.c index da671a3ad1..0126ad62b5 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -517,11 +517,10 @@ void ui_flush(void) } if (pending_mode_info_update) { Arena arena = ARENA_EMPTY; - arena_start(&arena, &ui_ext_fixblk); Array style = mode_style_array(&arena); bool enabled = (*p_guicursor != NUL); ui_call_mode_info_set(enabled, style); - arena_mem_free(arena_finish(&arena), &ui_ext_fixblk); + arena_mem_free(arena_finish(&arena)); pending_mode_info_update = false; } if (pending_mode_update && !starting) { diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 7dd2f5bce3..996b3467a6 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -47,8 +47,6 @@ enum { typedef int LineFlags; -EXTERN ArenaMem ui_ext_fixblk INIT(= NULL); - struct ui_t { bool rgb; bool override; ///< Force highest-requested UI capabilities. |