Skip to content

AppKit/UIKit: Improve tracing#4490

Open
madsmtm wants to merge 8 commits intomasterfrom
madsmtm/apple-tracing
Open

AppKit/UIKit: Improve tracing#4490
madsmtm wants to merge 8 commits intomasterfrom
madsmtm/apple-tracing

Conversation

@madsmtm
Copy link
Member

@madsmtm madsmtm commented Feb 18, 2026

Use tracing::span in clever ways to improve the logging infrastructure in the AppKit and UIKit backends. See the commits for details.

Running RUST_LOG='trace,winit_appkit::app=off' cargo run --example window and resizing now produces traces like:

2026-02-18T04:12:03.068240Z  INFO NSViewFrameDidChangeNotification: window: SurfaceResized(PhysicalSize { width: 1556, height: 930 })
2026-02-18T04:12:03.068380Z  INFO inside runloop{mode=NSEventTrackingRunLoopMode}:waiting: window: RedrawRequested
2026-02-18T04:12:03.073448Z  INFO inside runloop{mode=NSEventTrackingRunLoopMode}:processing timers:drawRect:: window: RedrawRequested

With this, one can glance that RedrawRequested is called inside drawRect:, and that it is in turn run inside NSEventTrackingRunLoopMode as a timer - which should in turn help debug why we're issuing RedrawRequested twice.

Tested AppKit backend on macOS 15.7.3 and UIKit briefly with Mac Catalyst.

I didn't include a changelog entry since these are meant to be internal.

@madsmtm madsmtm requested a review from kchibisov as a code owner February 18, 2026 03:04
@madsmtm madsmtm added DS - appkit Affects the AppKit/macOS backend S - maintenance Repaying technical debt labels Feb 18, 2026
@madsmtm madsmtm force-pushed the madsmtm/apple-tracing branch from 3c40c67 to bb405cc Compare February 18, 2026 03:40
Tracing subscribers must be set up before `EventLoop::new()`.
Add two run loop observers that:
- Create a TRACE-level span when the run loop enters a new state.
- Drops the span when the run loop exits that state.

These spans attach information to events, such that e.g. resizing a view
produces messages like:
```
TRACE inside runloop{mode=NSEventTrackingRunLoopMode}:timers:
  winit_appkit::util: Triggered `drawRect:` target="winit_appkit::view"
TRACE inside runloop{mode=NSEventTrackingRunLoopMode}:timers:
  winit_appkit::util: Completed `drawRect:` target="winit_appkit::view"
```
Spans are more powerful, and can even optionally be emitted as events by
using `.with_span_events(tracing_subscriber::fmt::format::FmtSpan::*)`.
This allows the examples to work a bit better in WASM and on iOS.
@madsmtm madsmtm force-pushed the madsmtm/apple-tracing branch from bb405cc to 29eb0dd Compare February 18, 2026 03:53
@madsmtm madsmtm added the DS - uikit Affects the UIKit backend (iOS, tvOS, watchOS, visionOS) label Feb 18, 2026
@madsmtm madsmtm changed the title AppKit: Improve tracing AppKit/UIKit: Improve tracing Feb 18, 2026
@madsmtm madsmtm removed the request for review from kchibisov February 18, 2026 03:59
Most events in AppKit go through `sendEvent:`, and they contain a lot of
information, so it's nice to surface this when debugging.

We could override `sendEvent:` in UIKit and track this in there too, but
that's much less important, since there the relevant events are fairly
narrowly scoped, see the link below, other events go through CFRunLoop.
https://developer.apple.com/documentation/uikit/uievent/eventtype
@madsmtm madsmtm force-pushed the madsmtm/apple-tracing branch from b3cccb8 to df2ccad Compare February 18, 2026 11:23
// FIXME(madsmtm): Use `std::ptr::fn_addr_eq` (Rust 1.85) once available in MSRV.
#[allow(unknown_lints, unpredictable_function_pointer_comparisons)]
if overridden == method.implementation() {
if ptr::fn_addr_eq(overridden, method.implementation()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be sent as a separate patch? Wouldn't mind that much though.

pub fn flush_requests(&self) -> Result<(), XError> {
unsafe { (self.xlib.XFlush)(self.display) };
// println!("XFlush");
// tracing::trace!("XFlush");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// tracing::trace!("XFlush");

pub fn sync_with_server(&self) -> Result<(), XError> {
unsafe { (self.xlib.XSync)(self.display, ffi::False) };
// println!("XSync");
// tracing::trace!("XSync");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// tracing::trace!("XSync");

ToUnicodeResult::Dead(dead_char) => {
// println!("{:?} - {:?} produced dead {:?}", key_code, mod_state,
// dead_char);
// trace!("{:?} - {:?} produced dead {:?}", key_code, mod_state, dead_char);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// trace!("{:?} - {:?} produced dead {:?}", key_code, mod_state, dead_char);

pub fn tracing_observers(
mtm: MainThreadMarker,
) -> Option<(MainRunLoopObserver, MainRunLoopObserver)> {
// HINT: You can use something like the following to emit relevant events:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This thing looks out of place?

};

extern "C-unwind" fn send_event(app: &NSApplication, sel: Sel, event: &NSEvent) {
// Pass `RUST_LOG='trace,winit_appkit::app=warn'` if you want TRACE logs but not this.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure who'll read this, maybe it should be somewhere more visible or do you left it for yourself?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DS - appkit Affects the AppKit/macOS backend DS - uikit Affects the UIKit backend (iOS, tvOS, watchOS, visionOS) S - maintenance Repaying technical debt

Development

Successfully merging this pull request may close these issues.

2 participants