commit 54deb2dd88d55fc877b13833fd0c5542f922c97b
parent 7b9e6f180caaf63b03a5cacf1de0f54f36aba488
Author: William Casarin <jb55@jb55.com>
Date: Sun, 23 Mar 2025 10:43:49 -0700
switch to profiling crates
This switches to the profiling crate for compatible
profiling between rust libraries.
To enable:
$ cargo build --release --features puffin
Feel free to experiment with other profiling backends
as well! Would be great to get tracy working.
Diffstat:
20 files changed, 46 insertions(+), 80 deletions(-)
diff --git a/.envrc b/.envrc
@@ -13,6 +13,6 @@ source scripts/macos_build_secrets.sh || :
export PATH=$PATH:$HOME/.cargo/bin
export JB55=32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245
-export JACK=npub1sg6plzptd64u62a878hep2kev88swjh3tw00gjsfl8f237lmu63q0uf63m
-export VROD=bd1e19980e2c91e6dc657e92c25762ca882eb9272d2579e221f037f93788de91
-export JEFFG=npub1zuuajd7u3sx8xu92yav9jwxpr839cs0kc3q6t56vd5u9q033xmhsk6c2uc
+# simple todo reminders
+export TODO_FILE=TODO
+2>/dev/null todo.sh ls || :
diff --git a/.gitignore b/.gitignore
@@ -1,4 +1,5 @@
.buildcmd
+TODO.bak
android-config.json
build.log
perf.data
diff --git a/Cargo.lock b/Cargo.lock
@@ -2740,6 +2740,7 @@ dependencies = [
"nostr",
"nostrdb",
"poll-promise",
+ "profiling",
"puffin",
"puffin_egui",
"serde",
@@ -2765,6 +2766,7 @@ dependencies = [
"egui_extras",
"notedeck",
"notedeck_columns",
+ "profiling",
"puffin",
"puffin_egui",
"serde",
@@ -2803,6 +2805,7 @@ dependencies = [
"open",
"poll-promise",
"pretty_assertions",
+ "profiling",
"puffin",
"puffin_egui",
"rfd",
@@ -3487,6 +3490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
dependencies = [
"profiling-procmacros",
+ "puffin",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
@@ -62,6 +62,7 @@ bincode = "1.3.3"
mime_guess = "2.0.5"
pretty_assertions = "1.4.1"
jni = "0.21.1"
+profiling = "1.0"
[profile.small]
inherits = 'release'
@@ -84,6 +85,8 @@ eframe = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055
egui-winit = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
egui_extras = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
epaint = { git = "https://github.com/damus-io/egui", rev = "93cd1cedc1e8eed2b055e317226838e37a845aad" }
+puffin = { git = "https://github.com/jb55/puffin", package = "puffin", rev = "c6a6242adaf90b6292c0f462d2acd34d96d224d2" }
+puffin_egui = { git = "https://github.com/jb55/puffin", package = "puffin_egui", rev = "c6a6242adaf90b6292c0f462d2acd34d96d224d2" }
#winit = { git = "https://github.com/damus-io/winit", rev = "14d61a74bee0c9863abe7ef28efae2c4d8bd3743" }
#winit = { path = "/home/jb55/dev/github/rust-windowing/winit" }
#android-activity = { git = "https://github.com/damus-io/android-activity", rev = "da17773852312a58c3445422dfe477162f2f1265" }
diff --git a/TODO b/TODO
diff --git a/crates/notedeck/Cargo.toml b/crates/notedeck/Cargo.toml
@@ -32,6 +32,7 @@ ehttp = {workspace = true }
mime_guess = { workspace = true }
egui-winit = { workspace = true }
tokenator = { workspace = true }
+profiling = { workspace = true }
[dev-dependencies]
tempfile = { workspace = true }
@@ -40,4 +41,4 @@ tempfile = { workspace = true }
jni = { workspace = true }
[features]
-profiling = ["puffin", "puffin_egui"]
+puffin = ["puffin_egui", "dep:puffin"]
diff --git a/crates/notedeck/src/app.rs b/crates/notedeck/src/app.rs
@@ -76,8 +76,7 @@ fn render_notedeck(notedeck: &mut Notedeck, ctx: &egui::Context) {
impl eframe::App for Notedeck {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
- #[cfg(feature = "profiling")]
- puffin::GlobalProfiler::lock().new_frame();
+ profiling::finish_frame!();
// handle account updates
self.accounts.update(&mut self.ndb, &mut self.pool, ctx);
@@ -97,7 +96,7 @@ impl eframe::App for Notedeck {
}
}
- #[cfg(feature = "profiling")]
+ #[cfg(feature = "puffin")]
puffin_egui::profiler_window(ctx);
}
@@ -107,15 +106,16 @@ impl eframe::App for Notedeck {
}
}
-#[cfg(feature = "profiling")]
-fn setup_profiling() {
+#[cfg(feature = "puffin")]
+fn setup_puffin() {
+ info!("setting up puffin");
puffin::set_scopes_on(true); // tell puffin to collect data
}
impl Notedeck {
pub fn new<P: AsRef<Path>>(ctx: &egui::Context, data_path: P, args: &[String]) -> Self {
- #[cfg(feature = "profiling")]
- setup_profiling();
+ #[cfg(feature = "puffin")]
+ setup_puffin();
// Skip the first argument, which is the program name.
let (parsed_args, unrecognized_args) = Args::parse(&args[1..]);
diff --git a/crates/notedeck/src/unknowns.rs b/crates/notedeck/src/unknowns.rs
@@ -246,6 +246,7 @@ impl UnknownId {
/// We return all of this in a HashSet so that we can fetch these from
/// remote relays.
///
+#[profiling::function]
pub fn get_unknown_note_ids<'a>(
ndb: &Ndb,
cached_note: &CachedNote,
@@ -253,9 +254,6 @@ pub fn get_unknown_note_ids<'a>(
note: &Note<'a>,
ids: &mut HashMap<UnknownId, HashSet<RelayUrl>>,
) -> Result<()> {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
// the author pubkey
if ndb.get_profile_by_pubkey(txn, note.pubkey()).is_err() {
ids.entry(UnknownId::Pubkey(Pubkey::new(*note.pubkey())))
diff --git a/crates/notedeck_chrome/Cargo.toml b/crates/notedeck_chrome/Cargo.toml
@@ -23,6 +23,7 @@ tokio = { workspace = true }
tracing-appender = { workspace = true }
tracing-subscriber = { workspace = true }
tracing = { workspace = true }
+profiling = { workspace = true }
[dev-dependencies]
tempfile = { workspace = true }
@@ -40,7 +41,7 @@ path = "src/preview.rs"
[features]
default = []
-profiling = ["notedeck_columns/puffin", "puffin", "puffin_egui"]
+puffin = ["profiling/profile-with-puffin", "dep:puffin"]
debug-widget-callstack = ["egui/callstack"]
debug-interactive-widgets = []
diff --git a/crates/notedeck_columns/Cargo.toml b/crates/notedeck_columns/Cargo.toml
@@ -49,6 +49,7 @@ uuid = { workspace = true }
sha2 = { workspace = true }
base64 = { workspace = true }
egui-winit = { workspace = true }
+profiling = { workspace = true }
[target.'cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))'.dependencies]
rfd = "0.15"
@@ -62,5 +63,5 @@ security-framework = "2.11.0"
[features]
default = []
-profiling = ["puffin", "puffin_egui"]
+puffin = ["dep:puffin", "profiling/profile-with-puffin"]
diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs
@@ -507,10 +507,8 @@ fn circle_icon(ui: &mut egui::Ui, openness: f32, response: &egui::Response) {
}
*/
+#[profiling::function]
fn render_damus_mobile(app: &mut Damus, app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui) {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
//let routes = app.timelines[0].routes.clone();
if !app.columns(app_ctx.accounts).columns().is_empty()
@@ -522,10 +520,8 @@ fn render_damus_mobile(app: &mut Damus, app_ctx: &mut AppContext<'_>, ui: &mut e
}
}
+#[profiling::function]
fn render_damus_desktop(app: &mut Damus, app_ctx: &mut AppContext<'_>, ui: &mut egui::Ui) {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let screen_size = ui.ctx().screen_rect().width();
let calc_panel_width = (screen_size
/ get_active_columns(app_ctx.accounts, &app.decks_cache).num_columns() as f32)
diff --git a/crates/notedeck_columns/src/images.rs b/crates/notedeck_columns/src/images.rs
@@ -67,10 +67,8 @@ pub fn aspect_fill(
response
}
+#[profiling::function]
pub fn round_image(image: &mut ColorImage) {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
// The radius to the edge of of the avatar circle
let edge_radius = image.size[0] as f32 / 2.0;
let edge_radius_squared = edge_radius * edge_radius;
@@ -114,10 +112,8 @@ pub fn round_image(image: &mut ColorImage) {
}
}
+#[profiling::function]
fn process_pfp_bitmap(imgtyp: ImageType, mut image: image::DynamicImage) -> ColorImage {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
match imgtyp {
ImageType::Content => {
let image_buffer = image.clone().into_rgba8();
@@ -156,10 +152,8 @@ fn process_pfp_bitmap(imgtyp: ImageType, mut image: image::DynamicImage) -> Colo
}
}
+#[profiling::function]
fn parse_img_response(response: ehttp::Response, imgtyp: ImageType) -> Result<ColorImage> {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let content_type = response.content_type().unwrap_or_default();
let size_hint = match imgtyp {
ImageType::Profile(size) => SizeHint::Size(size, size),
@@ -167,16 +161,14 @@ fn parse_img_response(response: ehttp::Response, imgtyp: ImageType) -> Result<Co
};
if content_type.starts_with("image/svg") {
- #[cfg(feature = "profiling")]
- puffin::profile_scope!("load_svg");
+ profiling::scope!("load_svg");
let mut color_image =
egui_extras::image::load_svg_bytes_with_size(&response.bytes, Some(size_hint))?;
round_image(&mut color_image);
Ok(color_image)
} else if content_type.starts_with("image/") {
- #[cfg(feature = "profiling")]
- puffin::profile_scope!("load_from_memory");
+ profiling::scope!("load_from_memory");
let dyn_image = image::load_from_memory(&response.bytes)?;
Ok(process_pfp_bitmap(imgtyp, dyn_image))
} else {
diff --git a/crates/notedeck_columns/src/ui/mention.rs b/crates/notedeck_columns/src/ui/mention.rs
@@ -63,6 +63,7 @@ impl egui::Widget for Mention<'_> {
}
#[allow(clippy::too_many_arguments)]
+#[profiling::function]
fn mention_ui(
ndb: &Ndb,
img_cache: &mut Images,
@@ -72,9 +73,6 @@ fn mention_ui(
size: f32,
selectable: bool,
) -> egui::InnerResponse<Option<NoteAction>> {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let link_color = ui.visuals().hyperlink_color;
ui.horizontal(|ui| {
diff --git a/crates/notedeck_columns/src/ui/note/contents.rs b/crates/notedeck_columns/src/ui/note/contents.rs
@@ -60,6 +60,7 @@ impl egui::Widget for &mut NoteContents<'_, '_> {
/// Render an inline note preview with a border. These are used when
/// notes are references within a note
#[allow(clippy::too_many_arguments)]
+#[profiling::function]
pub fn render_note_preview(
ui: &mut egui::Ui,
note_context: &mut NoteContext,
@@ -68,9 +69,6 @@ pub fn render_note_preview(
parent: NoteKey,
note_options: NoteOptions,
) -> NoteResponse {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let note = if let Ok(note) = note_context.ndb.get_note_by_id(txn, id) {
// TODO: support other preview kinds
if note.kind() == 1 {
@@ -118,6 +116,7 @@ pub fn render_note_preview(
}
#[allow(clippy::too_many_arguments)]
+#[profiling::function]
fn render_note_contents(
ui: &mut egui::Ui,
note_context: &mut NoteContext,
@@ -125,9 +124,6 @@ fn render_note_contents(
note: &Note,
options: NoteOptions,
) -> NoteResponse {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let note_key = note.key().expect("todo: implement non-db notes");
let selectable = options.has_selectable_text();
let mut images: Vec<(String, MediaCacheType)> = vec![];
@@ -197,8 +193,6 @@ fn render_note_contents(
},
BlockType::Hashtag => {
- #[cfg(feature = "profiling")]
- puffin::profile_scope!("hashtag contents");
let resp = ui.colored_label(link_color, format!("#{}", block.as_str()));
if resp.clicked() {
@@ -223,8 +217,6 @@ fn render_note_contents(
}
};
if hide_media || !found_supported() {
- #[cfg(feature = "profiling")]
- puffin::profile_scope!("url contents");
ui.add(Hyperlink::from_label_and_url(
RichText::new(block.as_str()).color(link_color),
block.as_str(),
@@ -233,8 +225,6 @@ fn render_note_contents(
}
BlockType::Text => {
- #[cfg(feature = "profiling")]
- puffin::profile_scope!("text contents");
if options.has_scramble_text() {
ui.add(egui::Label::new(rot13(block.as_str())).selectable(selectable));
} else {
diff --git a/crates/notedeck_columns/src/ui/note/context.rs b/crates/notedeck_columns/src/ui/note/context.rs
@@ -97,10 +97,8 @@ impl NoteContextButton {
Self::max_distance_between_circles() / Self::expansion_multiple()
}
+ #[profiling::function]
pub fn show(ui: &mut egui::Ui, note_key: NoteKey, put_at: Rect) -> egui::Response {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let id = ui.id().with(("more_options_anim", note_key));
let min_radius = Self::min_radius();
@@ -138,13 +136,11 @@ impl NoteContextButton {
response
}
+ #[profiling::function]
pub fn menu(
ui: &mut egui::Ui,
button_response: egui::Response,
) -> Option<NoteContextSelection> {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let mut context_selection: Option<NoteContextSelection> = None;
stationary_arbitrary_menu_button(ui, button_response, |ui| {
diff --git a/crates/notedeck_columns/src/ui/note/mod.rs b/crates/notedeck_columns/src/ui/note/mod.rs
@@ -307,15 +307,13 @@ impl<'a, 'd> NoteView<'a, 'd> {
}
}
+ #[profiling::function]
fn note_header(
ui: &mut egui::Ui,
note_cache: &mut NoteCache,
note: &Note,
profile: &Result<nostrdb::ProfileRecord<'_>, nostrdb::Error>,
) {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let note_key = note.key().unwrap();
ui.horizontal(|ui| {
@@ -327,9 +325,8 @@ impl<'a, 'd> NoteView<'a, 'd> {
});
}
+ #[profiling::function]
fn show_standard(&mut self, ui: &mut egui::Ui) -> NoteResponse {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
let note_key = self.note.key().expect("todo: support non-db notes");
let txn = self.note.txn().expect("todo: support non-db notes");
@@ -563,14 +560,12 @@ fn note_hitbox_clicked(
}
}
+#[profiling::function]
fn render_note_actionbar(
ui: &mut egui::Ui,
note_id: &[u8; 32],
note_key: NoteKey,
) -> egui::InnerResponse<Option<NoteAction>> {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
ui.horizontal(|ui| {
let reply_resp = reply_button(ui, note_key);
let quote_resp = quote_repost_button(ui, note_key);
@@ -590,14 +585,12 @@ fn secondary_label(ui: &mut egui::Ui, s: impl Into<String>) {
ui.add(Label::new(RichText::new(s).size(10.0).color(color)));
}
+#[profiling::function]
fn render_reltime(
ui: &mut egui::Ui,
note_cache: &mut CachedNote,
before: bool,
) -> egui::InnerResponse<()> {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
ui.horizontal(|ui| {
if before {
secondary_label(ui, "⋅");
diff --git a/crates/notedeck_columns/src/ui/note/reply_description.rs b/crates/notedeck_columns/src/ui/note/reply_description.rs
@@ -8,6 +8,7 @@ use nostrdb::{Note, NoteReply, Transaction};
use super::{contents::NoteContext, NoteOptions};
#[must_use = "Please handle the resulting note action"]
+#[profiling::function]
pub fn reply_desc(
ui: &mut egui::Ui,
txn: &Transaction,
@@ -15,9 +16,6 @@ pub fn reply_desc(
note_context: &mut NoteContext,
note_options: NoteOptions,
) -> Option<NoteAction> {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let mut note_action: Option<NoteAction> = None;
let size = 10.0;
let selectable = false;
diff --git a/crates/notedeck_columns/src/ui/profile/picture.rs b/crates/notedeck_columns/src/ui/profile/picture.rs
@@ -80,6 +80,7 @@ impl<'cache, 'url> ProfilePic<'cache, 'url> {
}
}
+#[profiling::function]
fn render_pfp(
ui: &mut egui::Ui,
img_cache: &mut Images,
@@ -87,9 +88,6 @@ fn render_pfp(
ui_size: f32,
border: Option<Stroke>,
) -> egui::Response {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
// We will want to downsample these so it's not blurry on hi res displays
let img_size = 128u32;
@@ -116,15 +114,13 @@ fn render_pfp(
)
}
+#[profiling::function]
fn pfp_image(
ui: &mut egui::Ui,
img: &TextureHandle,
size: f32,
border: Option<Stroke>,
) -> egui::Response {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let (rect, response) = ui.allocate_at_least(vec2(size, size), Sense::hover());
if let Some(stroke) = border {
draw_bg_border(ui, rect.center(), size, stroke);
diff --git a/crates/notedeck_columns/src/unknowns.rs b/crates/notedeck_columns/src/unknowns.rs
@@ -25,6 +25,7 @@ pub fn update_from_columns(
}
}
+#[profiling::function]
pub fn get_unknown_ids(
txn: &Transaction,
unknown_ids: &mut UnknownIds,
@@ -32,9 +33,6 @@ pub fn get_unknown_ids(
ndb: &Ndb,
note_cache: &mut NoteCache,
) -> Result<()> {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
let mut new_cached_notes: Vec<(NoteKey, CachedNote)> = vec![];
for (_kind, timeline) in timeline_cache.timelines.iter() {
diff --git a/preview b/preview
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# pass --mobile for mobile previews
-#RUST_LOG=info cargo run --bin ui_preview --features profiling --release -- "$@"
+#RUST_LOG=info cargo run --bin ui_preview --features puffin --release -- "$@"
cargo run --bin ui_preview --release -- "$@"