-
-
Notifications
You must be signed in to change notification settings - Fork 249
Only provide function name to CallContext in debug #1331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot!
with opt
You mean with the changes of this PR (and not "with optimized builds"), right?
If yes, that's really impressive 👀
Yeah sorry, to be clear, that should maybe be "with the changes" and "without the changes". I'll edit to be clearer |
API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1331 |
177739c
to
47bfe89
Compare
47bfe89
to
33f8f18
Compare
From a user's perspective, it's a bit strange that the callable name gets "optimized away". Seeing "optimized away" usually means some kind of "debug Symbol stripping", but the callable name is still there; it's just not being used. |
I'm not quite sure if I'm understanding what you mean, but the the string isn't necessarily there, it's provided as a As for Either way, after #1328 I'm a little gunshy to get too deep into a sweeping change considering this is pretty low hanging fruit. If there's a better solution that lets us keep the function name I'd say maybe it can be a separate PR. |
Hm, the debug stripping is also where I got this from, but isn't it the same from user PoV? We perform an optimization to not display the callable name 🤔 @lyonbeckers could you maybe add a small test that checks
I agree on this, small incremental PRs are quite nice 🙂 |
We could still use the name if we just optimize the string allocation by i.e. caching it somewhere, instead of just not using the name we already got. I feel like we either go all the way and remove the callable name entirely (in non debug builds) or we just optimize the critical part without restricting usability.
yes I also think keeping it smal is good. I wanted to put it out there because the impact of the optimization feels a bit arbitrary. "Why is the name not available here but in other places it is?" We can also move this to a separate PR or issue if you think it's worth pursuing. |
Very good points! Now I see that this is indeed a bit a strange middle-ground between caching and discarding the string. Caching might actually be quite simple, it's used in two ways:
So storing an additional Would be interesting to look if there's a notable perf difference between caching and entirely discarding the string. |
Added tests for the expected outcomes in release vs debug. I think this is a sensible way of testing it? I based it a little off of the test for
Heyo we've got some benches now, that'll be handy 😎 |
Not sure why the test failed on CI, it passes on |
#1336, so rebase onto |
Oh, I noticed the clippy issue, but would it have impacted the test? I guess we'll see 🤞 |
Ah, okay. Figured it out. My test was only passing locally because I hadn't changed the gdextension path in the itest godot project. Don't know how I overlooked that I'd have to do that, oops. On that note, I'll probably just remove the The way the test was working was by intercepting the panic received. The test fails because we actually don't report the call context in release build panics. The call context is passed to gdext/godot-core/src/private.rs Lines 420 to 424 in 8cc51a0
The context is also passed to gdext/godot-core/src/private.rs Lines 485 to 499 in 8cc51a0
I might be able to intercept it from this So unless there's some way of hooking into the godot console output that I'm not aware of, I don't actually know if there's a way I actually can write a release mode test for this, at least without making further changes to the caller? |
I'll check if we can use https://docs.godotengine.org/en/stable/classes/class_logger.html anyhow. |
Quick napkin code points out that logger might be good call. Tomorrow/at Sunday we might think out how to actually use it in the itest. As Godot docs points out: Warning: This function may be called from multiple different threads, so you may need to do your own locking. #[derive(GodotClass)]
#[class(init, base = Logger)]
pub struct GodotRustLogger {
error: Mutex<String>,
base: Base<Logger>
}
#[godot_api]
impl ILogger for GodotRustLogger {
fn log_error(&mut self, function: GString, file: GString, line: i32, code: GString, rationale: GString, editor_notify: bool, error_type: i32, backtrace: Array<godot::prelude::Gd<godot::classes::ScriptBacktrace>>) {
let mut val = self.error.lock().unwrap();
*val = code.to_string();
}
}
#[itest(focus)]
fn callable_context_custom_panic() {
// We need to poke ScriptBacktrace's `class_id` – otherwise it might be tried to be initialized simultaneously by two threads at once, causing the panic. Might/should be done in init although :thinking:.
let _script_backtrace = Gd::<godot::classes::ScriptBacktrace>::class_id();
let logger = GodotRustLogger::new_gd();
Os::singleton().add_logger(&logger);
let callable_name = if cfg!(debug_assertions) {
"test()"
} else {
"<optimized out>"
};
let expected_msg = format!("godot-rust function call failed: <Callable>::{}()\n Reason: function panicked: TEST: 0", callable_name);
(...)
assert_eq!(
*logger.bind().error.lock().unwrap(),
expected_msg
);
|
I created a branch with support for Godot's Logger to be added after the new prebuilt arrives :). It will be used like so: #[cfg(all(not(debug_assertions), since_api = "4.5"))]
#[itest(focus)]
fn callable_context_custom_panic() {
let expected_msg = "godot-rust function call failed: <Callable>::<optimized out>()\n Reason: function panicked: TEST: 0";
let logger = crate::common::itest_logger(GString::from(expected_msg));
let received = Arc::new(AtomicU32::new(0));
let callable = Callable::from_custom(PanicCallable(received));
callable.callv(&varray![]);
assert!(logger
.bind()
.was_error_called());
} |
Only provides function name to
CallContext
on debug builds for a fair bit of an optimization on release builds.Result of the benchmarks:
Less of a gain on the custom call side, but I think that's mostly just because
GString.to_string
is that much more expensive, or your mileage may vary depending on what the implementation ofstd::fmt::Display
is for aRustCallable
in the wild.Bonus: I added the option to provide a release argument to
check.sh
, but let me know if I should put that up in a separate PR. Just made testing this so much easier (although I feel like I should clarify that the benchmarks above were not debug vs release, to be clear).What an adventure this has been 😅
I'm creating this as a draft PR because when I ran the workflow on my fork, it failed a couple checks, failing the
codegen_test > changed_enum_apis
, but I'm not quite sure how that could be.