Merge pull request #15509 from bfredl/miniperf

perf(api): avoid spurious allocations when converting small objects
This commit is contained in:
Björn Linse 2021-08-28 18:38:31 +02:00 committed by GitHub
commit 636ecd0c3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 51 deletions

View File

@ -29,7 +29,7 @@ set(API_UI_EVENTS_GENERATOR ${GENERATOR_DIR}/gen_api_ui_events.lua)
set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua)
set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
set(MSGPACK_LUA_C_BINDINGS ${GENERATED_DIR}/msgpack_lua_c_bindings.generated.c)
set(LUA_API_C_BINDINGS ${GENERATED_DIR}/lua_api_c_bindings.generated.c)
set(HEADER_GENERATOR ${GENERATOR_DIR}/gen_declarations.lua)
set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include)
set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.generated.h)
@ -305,11 +305,11 @@ add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES}
add_custom_command(
OUTPUT ${GENERATED_API_DISPATCH} ${GENERATED_FUNCS_METADATA}
${API_METADATA} ${MSGPACK_LUA_C_BINDINGS}
${API_METADATA} ${LUA_API_C_BINDINGS}
COMMAND ${LUA_PRG} ${API_DISPATCH_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}
${GENERATED_API_DISPATCH}
${GENERATED_FUNCS_METADATA} ${API_METADATA}
${MSGPACK_LUA_C_BINDINGS}
${LUA_API_C_BINDINGS}
${API_HEADERS}
DEPENDS
${API_HEADERS}
@ -333,7 +333,7 @@ add_custom_command(
)
list(APPEND NVIM_GENERATED_SOURCES
"${MSGPACK_LUA_C_BINDINGS}"
"${LUA_API_C_BINDINGS}"
)
add_custom_command(

View File

@ -37,7 +37,7 @@
/// Helper structure for vim_to_object
typedef struct {
kvec_t(Object) stack; ///< Object stack.
kvec_withinit_t(Object, 2) stack; ///< Object stack.
} EncodedData;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@ -418,28 +418,25 @@ void set_option_to(uint64_t channel_id, void *to, int type,
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
#define TYPVAL_ENCODE_CONV_NIL(tv) \
kv_push(edata->stack, NIL)
kvi_push(edata->stack, NIL)
#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
kv_push(edata->stack, BOOLEAN_OBJ((Boolean)(num)))
kvi_push(edata->stack, BOOLEAN_OBJ((Boolean)(num)))
#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
kv_push(edata->stack, INTEGER_OBJ((Integer)(num)))
kvi_push(edata->stack, INTEGER_OBJ((Integer)(num)))
#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
kv_push(edata->stack, FLOAT_OBJ((Float)(flt)))
kvi_push(edata->stack, FLOAT_OBJ((Float)(flt)))
#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \
do { \
const size_t len_ = (size_t)(len); \
const char *const str_ = (const char *)(str); \
assert(len_ == 0 || str_ != NULL); \
kv_push(edata->stack, STRING_OBJ(((String) { \
.data = xmemdupz((len_?str_:""), len_), \
.size = len_ \
}))); \
kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_?str_:""), len_))); \
} while (0)
#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
@ -458,17 +455,17 @@ void set_option_to(uint64_t channel_id, void *to, int type,
#define TYPVAL_ENCODE_CONV_FUNC_END(tv)
#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
kv_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
kvi_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
kv_push(edata->stack, \
DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 })))
kvi_push(edata->stack, \
DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 })))
static inline void typval_encode_list_start(EncodedData *const edata,
const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
kv_push(edata->stack, ARRAY_OBJ(((Array) {
kvi_push(edata->stack, ARRAY_OBJ(((Array) {
.capacity = len,
.size = 0,
.items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.array.items)),
@ -510,7 +507,7 @@ static inline void typval_encode_dict_start(EncodedData *const edata,
const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
kv_push(edata->stack, DICTIONARY_OBJ(((Dictionary) {
kvi_push(edata->stack, DICTIONARY_OBJ(((Dictionary) {
.capacity = len,
.size = 0,
.items = xmalloc(len * sizeof(
@ -618,14 +615,15 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
/// @return The converted value
Object vim_to_object(typval_T *obj)
{
EncodedData edata = { .stack = KV_INITIAL_VALUE };
EncodedData edata;
kvi_init(edata.stack);
const int evo_ret = encode_vim_to_object(&edata, obj,
"vim_to_object argument");
(void)evo_ret;
assert(evo_ret == OK);
Object ret = kv_A(edata.stack, 0);
assert(kv_size(edata.stack) == 1);
kv_destroy(edata.stack);
kvi_destroy(edata.stack);
return ret;
}

View File

@ -7,7 +7,7 @@ if arg[1] == '--help' then
print(' 2: dispatch output file (dispatch_wrappers.generated.h)')
print(' 3: functions metadata output file (funcs_metadata.generated.h)')
print(' 4: API metadata output file (api_metadata.mpack)')
print(' 5: lua C bindings output file (msgpack_lua_c_bindings.generated.c)')
print(' 5: lua C bindings output file (lua_api_c_bindings.generated.c)')
print(' rest: C files where API functions are defined')
end
assert(#arg >= 4)
@ -378,7 +378,7 @@ output:write('\n')
local lua_c_functions = {}
local function process_function(fn)
local lua_c_function_name = ('nlua_msgpack_%s'):format(fn.name)
local lua_c_function_name = ('nlua_api_%s'):format(fn.name)
write_shifted_output(output, string.format([[
static int %s(lua_State *lstate)

View File

@ -196,8 +196,9 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
{
bool ret = true;
const int initial_size = lua_gettop(lstate);
kvec_t(TVPopStackItem) stack = KV_INITIAL_VALUE;
kv_push(stack, ((TVPopStackItem) { ret_tv, false, false, 0 }));
kvec_withinit_t(TVPopStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
kvi_push(stack, ((TVPopStackItem) { ret_tv, false, false, 0 }));
while (ret && kv_size(stack)) {
if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) {
emsgf(_("E1502: Lua failed to grow stack to %i"), lua_gettop(lstate) + 3);
@ -234,7 +235,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
tv_list_append_owned_tv(kv_pair, (typval_T) {
.v_type = VAR_UNKNOWN,
});
kv_push(stack, cur);
kvi_push(stack, cur);
tv_list_append_list(cur.tv->vval.v_list, kv_pair);
cur = (TVPopStackItem) {
.tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair)),
@ -247,7 +248,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) {
abort();
}
kv_push(stack, cur);
kvi_push(stack, cur);
cur = (TVPopStackItem) { &di->di_tv, false, false, 0 };
}
} else {
@ -265,7 +266,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
tv_list_append_owned_tv(cur.tv->vval.v_list, (typval_T) {
.v_type = VAR_UNKNOWN,
});
kv_push(stack, cur);
kvi_push(stack, cur);
// TODO(ZyX-I): Use indexes, here list item *will* be reallocated.
cur = (TVPopStackItem) {
.tv = TV_LIST_ITEM_TV(tv_list_last(cur.tv->vval.v_list)),
@ -343,7 +344,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
if (table_props.maxidx != 0) {
cur.container = true;
cur.idx = lua_gettop(lstate);
kv_push(stack, cur);
kvi_push(stack, cur);
}
break;
}
@ -373,7 +374,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
}
cur.container = true;
cur.idx = lua_gettop(lstate);
kv_push(stack, cur);
kvi_push(stack, cur);
lua_pushnil(lstate);
}
break;
@ -434,7 +435,7 @@ nlua_pop_typval_table_processing_end:
lua_pop(lstate, 1);
}
}
kv_destroy(stack);
kvi_destroy(stack);
if (!ret) {
tv_clear(ret_tv);
*ret_tv = (typval_T) {
@ -1060,15 +1061,16 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
{
Object ret = NIL;
const int initial_size = lua_gettop(lstate);
kvec_t(ObjPopStackItem) stack = KV_INITIAL_VALUE;
kv_push(stack, ((ObjPopStackItem) { &ret, false }));
kvec_withinit_t(ObjPopStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
kvi_push(stack, ((ObjPopStackItem) { &ret, false }));
while (!ERROR_SET(err) && kv_size(stack)) {
if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) {
api_set_error(err, kErrorTypeException, "Lua failed to grow stack");
break;
}
ObjPopStackItem cur = kv_pop(stack);
if (cur.container) {
if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) {
api_set_error(err, kErrorTypeException, "Lua failed to grow stack");
break;
}
if (cur.obj->type == kObjectTypeDictionary) {
// stack: …, dict, key
if (cur.obj->data.dictionary.size
@ -1095,7 +1097,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
.data = xmemdupz(s, len),
.size = len,
};
kv_push(stack, cur);
kvi_push(stack, cur);
cur = (ObjPopStackItem) {
.obj = &cur.obj->data.dictionary.items[idx].value,
.container = false,
@ -1117,7 +1119,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
lua_pop(lstate, 2);
continue;
}
kv_push(stack, cur);
kvi_push(stack, cur);
cur = (ObjPopStackItem) {
.obj = &cur.obj->data.array.items[idx],
.container = false,
@ -1169,7 +1171,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
sizeof(cur.obj->data.array.items[0]));
cur.obj->data.array.capacity = table_props.maxidx;
cur.container = true;
kv_push(stack, cur);
kvi_push(stack, cur);
}
break;
}
@ -1185,7 +1187,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
sizeof(cur.obj->data.dictionary.items[0]));
cur.obj->data.dictionary.capacity = table_props.string_keys_num;
cur.container = true;
kv_push(stack, cur);
kvi_push(stack, cur);
lua_pushnil(lstate);
}
break;
@ -1239,7 +1241,7 @@ type_error:
lua_pop(lstate, 1);
}
}
kv_destroy(stack);
kvi_destroy(stack);
if (ERROR_SET(err)) {
api_free_object(ret);
ret = NIL;

View File

@ -86,8 +86,9 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
FUNC_ATTR_NONNULL_ALL
{
bool ret = true;
kvec_t(MPToAPIObjectStackItem) stack = KV_INITIAL_VALUE;
kv_push(stack, ((MPToAPIObjectStackItem) {
kvec_withinit_t(MPToAPIObjectStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
kvi_push(stack, ((MPToAPIObjectStackItem) {
.mobj = obj,
.aobj = arg,
.container = false,
@ -155,7 +156,7 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
const size_t idx = cur.idx;
cur.idx++;
kv_last(stack) = cur;
kv_push(stack, ((MPToAPIObjectStackItem) {
kvi_push(stack, ((MPToAPIObjectStackItem) {
.mobj = &cur.mobj->via.array.ptr[idx],
.aobj = &cur.aobj->data.array.items[idx],
.container = false,
@ -209,7 +210,7 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
}
}
if (ret) {
kv_push(stack, ((MPToAPIObjectStackItem) {
kvi_push(stack, ((MPToAPIObjectStackItem) {
.mobj = &cur.mobj->via.map.ptr[idx].val,
.aobj = &cur.aobj->data.dictionary.items[idx].value,
.container = false,
@ -265,7 +266,7 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
(void)kv_pop(stack);
}
}
kv_destroy(stack);
kvi_destroy(stack);
return ret;
}
@ -375,8 +376,9 @@ typedef struct {
void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
FUNC_ATTR_NONNULL_ARG(2)
{
kvec_t(APIToMPObjectStackItem) stack = KV_INITIAL_VALUE;
kv_push(stack, ((APIToMPObjectStackItem) { &result, false, 0 }));
kvec_withinit_t(APIToMPObjectStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
kvi_push(stack, ((APIToMPObjectStackItem) { &result, false, 0 }));
while (kv_size(stack)) {
APIToMPObjectStackItem cur = kv_last(stack);
STATIC_ASSERT(kObjectTypeWindow == kObjectTypeBuffer + 1
@ -428,7 +430,7 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
const size_t idx = cur.idx;
cur.idx++;
kv_last(stack) = cur;
kv_push(stack, ((APIToMPObjectStackItem) {
kvi_push(stack, ((APIToMPObjectStackItem) {
.aobj = &cur.aobj->data.array.items[idx],
.container = false,
}));
@ -451,7 +453,7 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
kv_last(stack) = cur;
msgpack_rpc_from_string(cur.aobj->data.dictionary.items[idx].key,
res);
kv_push(stack, ((APIToMPObjectStackItem) {
kvi_push(stack, ((APIToMPObjectStackItem) {
.aobj = &cur.aobj->data.dictionary.items[idx].value,
.container = false,
}));
@ -468,7 +470,7 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
(void)kv_pop(stack);
}
}
kv_destroy(stack);
kvi_destroy(stack);
}
void msgpack_rpc_from_array(Array result, msgpack_packer *res)