aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-08-23 10:36:46 +0200
committerbfredl <bjorn.linse@gmail.com>2022-08-24 14:22:26 +0200
commitbcf5ee328e228d5a536b4de2069a79234f9f3e9e (patch)
treece25e8627bb00363deb6919561400fa1807ebf47
parentc0d60526541a3cf977ae623471ae4a347b492af1 (diff)
downloadrneovim-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.c11
-rw-r--r--src/nvim/ex_getln.c3
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua5
-rw-r--r--src/nvim/highlight_group.c2
-rw-r--r--src/nvim/lua/executor.c2
-rw-r--r--src/nvim/memory.c50
-rw-r--r--src/nvim/memory.h2
-rw-r--r--src/nvim/msgpack_rpc/channel.c8
-rw-r--r--src/nvim/msgpack_rpc/unpacker.c12
-rw-r--r--src/nvim/msgpack_rpc/unpacker.h2
-rw-r--r--src/nvim/popupmenu.c3
-rw-r--r--src/nvim/screen.c3
-rw-r--r--src/nvim/tui/input.c2
-rw-r--r--src/nvim/ui.c3
-rw-r--r--src/nvim/ui.h2
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.