-
are there any best-practices for minimizing overhead for calling back into a rust library from lua(u)? I have a setup that will be making 100's of millions of small calls. |
Beta Was this translation helpful? Give feedback.
Replies: 9 comments 19 replies
-
Try to avoid setting fields on UserData object. The fastest way is UserData with methods only. |
Beta Was this translation helpful? Give feedback.
-
oh, indeed that's much faster on my quick test. It gave a 4X speed improvement. Now a naive question, with that change, the syntax for my user expressions go from: I am guessing not from looking at docs here but wanted to be sure. |
Beta Was this translation helpful? Give feedback.
-
Actually, I notice if I have a single method vs a single field, the performance difference is negligible. I assume the difference is more when there are more fields vs more methods? Comparing a single field to ~15 field, I see a dramatic performance improvement when only a single field is specified (using same expression on only that single field). |
Beta Was this translation helpful? Give feedback.
-
It should not really matter, the complexity is O(1), fields and methods are stored in a hashmap.
You can try to set fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_meta_field_with("__index", |lua| {
lua.create_function(
|lua, (this, key): (mlua::UserDataRef<Self>, mlua::String)| match key.as_bytes() {
b"field" => Ok(this.field),
_ => Err(mlua::Error::RuntimeError("no such field".to_string())),
},
)
})
} |
Beta Was this translation helpful? Give feedback.
-
I tried userdata_ref with only the Record struct (no Alignment) here
Unless there's an obvious way to fix this I will try again to use your other suggestion: fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_meta_field_with("__index", |lua| {
lua.create_function(
|lua, (this, key): (mlua::UserDataRef<Self>, mlua::String)| match key.as_bytes() {
b"field" => Ok(this.field),
_ => Err(mlua::Error::RuntimeError("no such field".to_string())),
},
)
})
} since that will limit the number of fields that need to be copied for non_static_userdata. |
Beta Was this translation helpful? Give feedback.
-
If I have something like this (with __index): fn register_variant(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<Variant>(|reg| {
reg.add_meta_function(
MetaMethod::Index,
|_lua, (_, name): (AnyUserData, String)| {
let msg = format!("field '{}' variant.{} not found", name, name);
Err::<LuaValue<'_>, mlua::Error>(mlua::Error::RuntimeError(msg))
},
);
... // other reg.add_field_method_get definitions
} I just want to give an error if the user access an unset field (rather than returning nil). |
Beta Was this translation helpful? Give feedback.
-
ok. Thanks @khvzak . I benchmarked it and the difference is minimal for a typical use-case so I'll leave it for now. Another question. I have this: reg.add_field_method_get("id", |lua: &Lua, this: &Variant| {
let id = this.0.id();
Ok(Value::String(unsafe {
lua.create_string(String::from_utf8_unchecked(id.to_vec()))?
}))
});
reg.add_field_method_set(
"id",
|_lua: &Lua, this: &mut Variant, val: String| match this.0.set_id(val.as_bytes()) {
Err(e) => Err(mlua::Error::ExternalError(Arc::new(e))),
Ok(_) => Ok(()),
},
); and I can read
Any pointers here? I am using: let ud = scope.create_any_userdata_ref(variant)?;
globals.set("variant", ud)?; |
Beta Was this translation helpful? Give feedback.
-
here is a full example: https://github.com/brentp/help-repositories/blob/1a6a22ff264e2042794f539cd9527b71b12c9188/src/main.rs#L48-L57 it seems to find the getters before __index, but not the setters before __newindex. |
Beta Was this translation helpful? Give feedback.
-
I know things have changed in v0.10+, is |
Beta Was this translation helpful? Give feedback.
It should not really matter, the complexity is O(1), fields and methods are stored in a hashmap.
However Luau at compile time can predict hashmap slot when userdata has only methods. Whereas with fields(+ methods) lookup is always dynamic.
You can try to set
__index
metamethod for your case: