Skip to content

Commit d1e0e28

Browse files
committed
kms: Add tracy profiling
1 parent 5672e03 commit d1e0e28

File tree

5 files changed

+109
-12
lines changed

5 files changed

+109
-12
lines changed

Cargo.lock

Lines changed: 19 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ tiny-skia = "0.11"
4949
tracing = { version = "0.1.37", features = ["max_level_debug", "release_max_level_info"] }
5050
tracing-journald = "0.3.0"
5151
tracing-subscriber = {version = "0.3.16", features = ["env-filter", "tracing-log"]}
52+
tracy-client = { version = "0.18.0", default-features = false }
5253
wayland-backend = "0.3.3"
5354
wayland-scanner = "0.31.1"
5455
xcursor = "0.3.3"
@@ -100,7 +101,7 @@ rev = "e720136"
100101
debug = ["egui", "egui_plot", "smithay-egui", "anyhow/backtrace"]
101102
default = ["systemd"]
102103
systemd = ["libsystemd"]
103-
profile-with-tracy = ["profiling/profile-with-tracy"]
104+
profile-with-tracy = ["profiling/profile-with-tracy", "tracy-client/default"]
104105

105106
[profile.dev.package.tiny-skia]
106107
opt-level = 2

src/backend/kms/device.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ use std::{
4747
fmt,
4848
path::{Path, PathBuf},
4949
sync::{atomic::AtomicBool, mpsc::Receiver, Arc, RwLock},
50+
time::Duration,
5051
};
5152

5253
use super::{drm_helpers, socket::Socket, surface::Surface};
@@ -64,6 +65,7 @@ pub type GbmDrmOutputManager = DrmOutputManager<
6465
Option<(
6566
OutputPresentationFeedback,
6667
Receiver<(ScreencopyFrame, Vec<Rectangle<i32, BufferCoords>>)>,
68+
Duration,
6769
)>,
6870
DrmDeviceFd,
6971
>;

src/backend/kms/surface/mod.rs

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,17 @@ pub struct SurfaceThreadState {
146146

147147
#[cfg(feature = "debug")]
148148
egui: EguiState,
149+
150+
last_sequence: Option<u32>,
151+
/// Tracy frame that goes from vblank to vblank.
152+
vblank_frame: Option<tracy_client::Frame>,
153+
/// Frame name for the VBlank frame.
154+
vblank_frame_name: tracy_client::FrameName,
155+
/// Plot name for the time since presentation plot.
156+
time_since_presentation_plot_name: tracy_client::PlotName,
157+
/// Plot name for the presentation misprediction plot.
158+
presentation_misprediction_plot_name: tracy_client::PlotName,
159+
sequence_delta_plot_name: tracy_client::PlotName,
149160
}
150161

151162
pub type GbmDrmOutput = DrmOutput<
@@ -154,6 +165,7 @@ pub type GbmDrmOutput = DrmOutput<
154165
Option<(
155166
OutputPresentationFeedback,
156167
Receiver<(ScreencopyFrame, Vec<Rectangle<i32, BufferCoords>>)>,
168+
Duration,
157169
)>,
158170
DrmDeviceFd,
159171
>;
@@ -469,7 +481,8 @@ fn surface_thread(
469481
thread_receiver: Channel<ThreadCommand>,
470482
startup_done: Arc<AtomicBool>,
471483
) -> Result<()> {
472-
profiling::register_thread!(&format!("Surface Thread {}", output.name()));
484+
let name = output.name();
485+
profiling::register_thread!(&format!("Surface Thread {}", name));
473486

474487
let mut event_loop = EventLoop::try_new().unwrap();
475488

@@ -492,6 +505,14 @@ fn surface_thread(
492505
state
493506
};
494507

508+
let vblank_frame_name = tracy_client::FrameName::new_leak(format!("vblank on {name}"));
509+
let time_since_presentation_plot_name =
510+
tracy_client::PlotName::new_leak(format!("{name} time since presentation, ms"));
511+
let presentation_misprediction_plot_name =
512+
tracy_client::PlotName::new_leak(format!("{name} presentation misprediction, ms"));
513+
let sequence_delta_plot_name =
514+
tracy_client::PlotName::new_leak(format!("{name} sequence delta"));
515+
495516
let mut state = SurfaceThreadState {
496517
api,
497518
primary_node,
@@ -516,6 +537,13 @@ fn surface_thread(
516537
clock: Clock::new(),
517538
#[cfg(feature = "debug")]
518539
egui,
540+
541+
last_sequence: None,
542+
vblank_frame: None,
543+
vblank_frame_name,
544+
time_since_presentation_plot_name,
545+
presentation_misprediction_plot_name,
546+
sequence_delta_plot_name,
519547
};
520548

521549
let signal = event_loop.get_signal();
@@ -716,9 +744,46 @@ impl SurfaceThreadState {
716744
};
717745
let sequence = metadata.as_ref().map(|data| data.sequence).unwrap_or(0);
718746

747+
// finish tracy frame
748+
let _ = self.vblank_frame.take();
749+
719750
// mark last frame completed
720-
if let Ok(Some(Some((mut feedback, frames)))) = compositor.frame_submitted() {
751+
if let Ok(Some(Some((mut feedback, frames, estimated_presentation_time)))) =
752+
compositor.frame_submitted()
753+
{
721754
if self.mirroring.is_none() {
755+
let name = self.output.name();
756+
let message = if let Some(presentation_time) = presentation_time {
757+
let misprediction_s =
758+
presentation_time.as_secs_f64() - estimated_presentation_time.as_secs_f64();
759+
tracy_client::Client::running().unwrap().plot(
760+
self.presentation_misprediction_plot_name,
761+
misprediction_s * 1000.,
762+
);
763+
764+
let now = Duration::from(now);
765+
if presentation_time > now {
766+
let diff = presentation_time - now;
767+
tracy_client::Client::running().unwrap().plot(
768+
self.time_since_presentation_plot_name,
769+
-diff.as_secs_f64() * 1000.,
770+
);
771+
format!("vblank on {name}, presentation is {diff:?} later")
772+
} else {
773+
let diff = now - presentation_time;
774+
tracy_client::Client::running().unwrap().plot(
775+
self.time_since_presentation_plot_name,
776+
diff.as_secs_f64() * 1000.,
777+
);
778+
format!("vblank on {name}, presentation was {diff:?} ago")
779+
}
780+
} else {
781+
format!("vblank on {name}, presentation time unknown")
782+
};
783+
tracy_client::Client::running()
784+
.unwrap()
785+
.message(&message, 0);
786+
722787
let (clock, flags) = if let Some(tp) = presentation_time {
723788
(
724789
tp.into(),
@@ -751,6 +816,14 @@ impl SurfaceThreadState {
751816
None => Refresh::Unknown,
752817
};
753818

819+
if let Some(last_sequence) = self.last_sequence {
820+
let delta = sequence as f64 - last_sequence as f64;
821+
tracy_client::Client::running()
822+
.unwrap()
823+
.plot(self.sequence_delta_plot_name, delta);
824+
}
825+
self.last_sequence = Some(sequence);
826+
754827
feedback.presented(clock, refresh, sequence as u64, flags);
755828

756829
self.timings.presented(clock);
@@ -770,6 +843,11 @@ impl SurfaceThreadState {
770843
};
771844

772845
if redraw_needed || self.shell.read().unwrap().animations_going() {
846+
let vblank_frame = tracy_client::Client::running()
847+
.unwrap()
848+
.non_continuous_frame(self.vblank_frame_name);
849+
self.vblank_frame = Some(vblank_frame);
850+
773851
self.queue_redraw(false);
774852
} else {
775853
self.send_frame_callbacks();
@@ -1332,6 +1410,7 @@ impl SurfaceThreadState {
13321410
.unwrap()
13331411
.take_presentation_feedback(&self.output, &frame_result.states),
13341412
rx,
1413+
estimated_presentation,
13351414
))
13361415
} else {
13371416
None
@@ -1628,6 +1707,9 @@ impl SurfaceThreadState {
16281707
self.send_frame_callbacks();
16291708
}
16301709
} else {
1710+
// we don't expect a vblank
1711+
let _ = self.vblank_frame.take();
1712+
16311713
self.queue_estimated_vblank(
16321714
estimated_presentation,
16331715
// Make sure we redraw to reevaluate, if we intentionally missed content

src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ fn main() -> Result<(), Box<dyn Error>> {
127127
logger::init_logger()?;
128128
info!("Cosmic starting up!");
129129

130-
#[cfg(feature = "profile-with-tracy")]
131-
profiling::tracy_client::Client::start();
132130
profiling::register_thread!("Main Thread");
131+
#[cfg(feature = "profile-with-tracy")]
132+
tracy_client::Client::start();
133133

134134
utils::rlimit::increase_nofile_limit();
135135

0 commit comments

Comments
 (0)