Skip to content

Commit 0d4c0e1

Browse files
committed
puffin_http server: no need to call update() each frame
1 parent 091459e commit 0d4c0e1

File tree

3 files changed

+44
-13
lines changed

3 files changed

+44
-13
lines changed

puffin/src/lib.rs

+28
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,12 @@ impl Ord for OrderedData {
512512
}
513513
}
514514

515+
/// Add these to [`GlobalProfiler`] with [`GlobalProfiler::add_sink`].
516+
pub type FrameSink = Box<dyn Fn(Arc<FrameData>) + Send>;
517+
518+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
519+
pub struct FrameSinkId(u64);
520+
515521
/// Singleton. Collects profiling data from multiple threads.
516522
pub struct GlobalProfiler {
517523
current_frame_index: FrameIndex,
@@ -523,6 +529,9 @@ pub struct GlobalProfiler {
523529

524530
slowest_frames: std::collections::BinaryHeap<OrderedData>,
525531
max_slow: usize,
532+
533+
next_sink_id: FrameSinkId,
534+
sinks: std::collections::HashMap<FrameSinkId, FrameSink>,
526535
}
527536

528537
impl Default for GlobalProfiler {
@@ -537,6 +546,8 @@ impl Default for GlobalProfiler {
537546
max_recent,
538547
slowest_frames: std::collections::BinaryHeap::with_capacity(max_slow),
539548
max_slow,
549+
next_sink_id: FrameSinkId(1),
550+
sinks: Default::default(),
540551
}
541552
}
542553
}
@@ -573,6 +584,10 @@ impl GlobalProfiler {
573584

574585
/// Manually add frame data.
575586
pub fn add_frame(&mut self, new_frame: Arc<FrameData>) {
587+
for sink in self.sinks.values() {
588+
sink(new_frame.clone());
589+
}
590+
576591
let add_to_slowest = if self.slowest_frames.len() < self.max_slow {
577592
true
578593
} else if let Some(fastest_of_the_slow) = self.slowest_frames.peek() {
@@ -703,6 +718,19 @@ impl GlobalProfiler {
703718

704719
Ok(slf)
705720
}
721+
722+
/// Call this function with each new finished frame.
723+
/// The returned [`FrameSinkId`] can be used to remove the sink with [`Self::remove_sink`].
724+
pub fn add_sink(&mut self, sink: FrameSink) -> FrameSinkId {
725+
let id = self.next_sink_id;
726+
self.next_sink_id.0 += 1;
727+
self.sinks.insert(id, sink);
728+
id
729+
}
730+
731+
pub fn remove_sink(&mut self, id: FrameSinkId) -> Option<FrameSink> {
732+
self.sinks.remove(&id)
733+
}
706734
}
707735

708736
// ----------------------------------------------------------------------------

puffin_http/examples/server.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ fn main() {
77
let server_addr = format!("0.0.0.0:{}", puffin_http::DEFAULT_PORT);
88
eprintln!("Serving demo profile data on {}", server_addr);
99

10-
let puffin_server = puffin_http::Server::new(&server_addr).unwrap();
10+
let _puffin_server = puffin_http::Server::new(&server_addr).unwrap();
1111

1212
puffin::set_scopes_on(true);
1313

@@ -16,7 +16,6 @@ fn main() {
1616
loop {
1717
puffin::profile_scope!("main_loop");
1818
puffin::GlobalProfiler::lock().new_frame();
19-
puffin_server.update();
2019

2120
// Give us something to inspect:
2221

puffin_http/src/server.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use anyhow::Context as _;
2+
use puffin::GlobalProfiler;
23
use std::{
34
io::Write,
45
net::{SocketAddr, TcpListener, TcpStream},
@@ -7,8 +8,10 @@ use std::{
78

89
/// Listens for incoming connections
910
/// and streams them puffin profiler data.
11+
///
12+
/// Drop to stop transmitting and listening for new connections.
1013
pub struct Server {
11-
tx: std::sync::mpsc::Sender<Arc<puffin::FrameData>>,
14+
sink_id: puffin::FrameSinkId,
1215
}
1316

1417
impl Server {
@@ -19,9 +22,8 @@ impl Server {
1922
.set_nonblocking(true)
2023
.context("TCP set_nonblocking")?;
2124

22-
let (tx, rx) = std::sync::mpsc::channel();
23-
24-
let server = Server { tx };
25+
let (tx, rx): (std::sync::mpsc::Sender<Arc<puffin::FrameData>>, _) =
26+
std::sync::mpsc::channel();
2527

2628
std::thread::Builder::new()
2729
.name("puffin-server".to_owned())
@@ -42,15 +44,17 @@ impl Server {
4244
})
4345
.context("Couldn't spawn thread")?;
4446

45-
Ok(server)
47+
let sink_id = GlobalProfiler::lock().add_sink(Box::new(move |frame| {
48+
tx.send(frame).ok();
49+
}));
50+
51+
Ok(Server { sink_id })
4652
}
53+
}
4754

48-
/// Call this once per frame, right after calling [`puffin::GlobalProfiler::new_frame`].
49-
pub fn update(&self) {
50-
let latest_frame = puffin::GlobalProfiler::lock().latest_frame();
51-
if let Some(latest_frame) = latest_frame {
52-
self.tx.send(latest_frame).ok();
53-
}
55+
impl Drop for Server {
56+
fn drop(&mut self) {
57+
GlobalProfiler::lock().remove_sink(self.sink_id);
5458
}
5559
}
5660

0 commit comments

Comments
 (0)