Skip to content

chore: memory profiling Forest#5837

Merged
LesnyRumcajs merged 1 commit into
mainfrom
memory-profile
Aug 22, 2025
Merged

chore: memory profiling Forest#5837
LesnyRumcajs merged 1 commit into
mainfrom
memory-profile

Conversation

@LesnyRumcajs
Copy link
Copy Markdown
Member

@LesnyRumcajs LesnyRumcajs commented Jul 15, 2025

Summary of changes

Changes introduced in this pull request:

  • added some profiling tooling to the Makefile and the build file to facilitate future memory usage investigations.
  • removed legacy docs with heaptrack.

Reference issue to close (if applicable)

Closes #5879

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

Summary by CodeRabbit

  • New Features

    • Optional system-allocator feature to switch runtime allocator for memory profiling.
    • New Makefile targets/workflows to generate heap profiles (gperftools and Heaptrack) and guidance for visualizing them.
  • Documentation

    • Removed the outdated Memory analysis guide and its table-of-contents entry.
  • Chores

    • Added a dedicated profiling build profile and tightened release settings (overflow checks, thin LTO).
    • Improved build-time env opt-out behavior for configurability.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 15, 2025

Walkthrough

Adds a profiling Cargo profile and system-alloc feature; adds Makefile targets/variables for gperftools and Heaptrack memory profiling; updates build.rs to optionally link tcmalloc and unify an env truthiness check; removes the memory-analysis documentation; and adds a System allocator branch in runtime selection.

Changes

Cohort / File(s) Summary
Cargo profiling and features
Cargo.toml
Added [profile.profiling] (inherits="dev", opt-level=0, debug=true, split-debuginfo="unpacked", panic="abort"); added overflow-checks = true and lto = "thin" to [profile.release]; added system-alloc = [] allocator option and feature.
Makefile memory profiling tooling
Makefile
Added Memory Profiling section with variables/targets: gperfheapprofile, gperfheapprofile.forest, memprofile-heaptrack, memprofile-heaptrack.forest; builds with --profile=profiling and --features system-alloc; added .PHONY: $(MAKECMDGOALS) and usage notes.
Build gating and tcmalloc link
build.rs
Added is_env_truthy(env: &str) helper; link to tcmalloc gated by FOREST_PROFILING_GPERFTOOLS_BUILD; replaced previous sidecar gating with !is_env_truthy("FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT").
Allocator selection
src/lib.rs
Added system-alloc cfg branch that imports std::alloc::System and declares it as the global allocator when the feature is enabled (alongside existing jemalloc/rustalloc branches).
Docs removal
documentation/src/SUMMARY.md, documentation/src/developer_documentation/memory-analysis.md
Removed the "Memory analysis" TOC entry and deleted the memory-analysis guide file.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as Developer
  participant Make as Makefile
  participant Cargo as cargo (profile=profiling)
  participant Build as build.rs
  participant Bin as target/profiling/forest
  participant OS as OS

  Dev->>Make: make gperfheapprofile.forest
  Make->>Cargo: FOREST_PROFILING_GPERFTOOLS_BUILD=1 build --no-default-features --features system-alloc --profile=profiling --bin forest
  Cargo->>Build: run build script (env)
  Note right of Build: Detects FOREST_PROFILING_GPERFTOOLS_BUILD truthy → link tcmalloc
  Build-->>Cargo: build metadata (link tcmalloc)
  Cargo-->>Make: build artifacts (target/profiling/forest)
  Make->>OS: ulimit -n 8192
  Make->>Bin: HEAPPROFILE_USE_PID=t HEAPPROFILE=/tmp/gperfheap.forest.prof (run)
  Bin-->>Make: generates heap profile file
Loading
sequenceDiagram
  autonumber
  participant Dev as Developer
  participant Make as Makefile
  participant Cargo as cargo (profile=profiling)
  participant Build as build.rs
  participant Bin as target/profiling/forest
  participant Heap as heaptrack

  Dev->>Make: make memprofile-heaptrack.forest
  Make->>Cargo: build --no-default-features --features system-alloc --profile=profiling --bin forest
  Cargo->>Build: run build script
  Note right of Build: Normal build (no tcmalloc link) — allocator may be System via feature
  Cargo-->>Make: build artifacts
  Make->>Heap: heaptrack -o /tmp/heaptrack.forest.%p.zst target/profiling/forest ...
  Heap->>Bin: launch and trace
  Heap-->>Make: writes compressed heap profile
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
Use various memory profiling tools to analyze Forest (#5879)
Fix the biggest memory issues (referenced work) (#5879)
Provide vetted set of tools and hints for future researchers (#5879) Removal of the existing memory-analysis guide eliminates in-repo vetted instructions rather than preserving/consolidating them.
Share findings (meeting/post) (#5879) No artifacts (reports/notes) or dissemination changes included in this PR; unclear if published elsewhere.

Out-of-scope changes

Code Change Explanation
Deletion of memory-analysis guide (documentation/src/developer_documentation/memory-analysis.md) The linked issue includes facilitating future researchers; removing the guide is contrary to that objective.
Sidecar build gating logic change (build.rs) Replacing is_sidecar_ffi_enabled() with !is_env_truthy("FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT") modifies sidecar FFI gating unrelated to memory profiling tools.

Suggested reviewers

  • sudo-shashank
  • akaladarshi
  • hanabi1224

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f5326a6 and 52799b7.

⛔ Files ignored due to path filters (6)
  • documentation/src/developer_documentation/heaptrack/bottom_up.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/caller_callee.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/consumed.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/flamegraph.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/sizes.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/summary.png is excluded by !**/*.png
📒 Files selected for processing (6)
  • Cargo.toml (2 hunks)
  • Makefile (1 hunks)
  • build.rs (2 hunks)
  • documentation/src/SUMMARY.md (0 hunks)
  • documentation/src/developer_documentation/memory-analysis.md (0 hunks)
  • src/lib.rs (1 hunks)
💤 Files with no reviewable changes (2)
  • documentation/src/developer_documentation/memory-analysis.md
  • documentation/src/SUMMARY.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/lib.rs
  • build.rs
  • Makefile
  • Cargo.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: tests-release
  • GitHub Check: tests
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: All lint checks
  • GitHub Check: Build MacOS
  • GitHub Check: Build Ubuntu
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: Analyze (ruby)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (actions)
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (go)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch memory-profile

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@LesnyRumcajs LesnyRumcajs changed the title mem profiling [skip ci] chore: memory profiling Forest Jul 15, 2025
@LesnyRumcajs LesnyRumcajs force-pushed the memory-profile branch 2 times, most recently from 44ed8e6 to ca45b66 Compare July 16, 2025 11:20
@LesnyRumcajs LesnyRumcajs force-pushed the memory-profile branch 2 times, most recently from 64ffac5 to 75e6e7c Compare August 21, 2025 10:28
@LesnyRumcajs LesnyRumcajs marked this pull request as ready for review August 21, 2025 10:56
@LesnyRumcajs LesnyRumcajs requested a review from a team as a code owner August 21, 2025 10:56
@LesnyRumcajs LesnyRumcajs requested review from elmattic and hanabi1224 and removed request for a team August 21, 2025 10:56
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (6)
src/lib.rs (1)

33-36: Make allocator features mutually exclusive to avoid accidental dual selection

Adding system-alloc looks good. However, right now nothing prevents users from enabling jemalloc and system-alloc (or rustalloc) together, in which case the first matching cfg_if! branch silently wins. This can be confusing during profiling and lead to false conclusions.

Recommend compile-time guards to enforce mutual exclusivity.

Apply these additions (outside this range) near the top of the file before the cfg_if!:

// Allocator feature sanity checks
#[cfg(all(feature = "jemalloc", feature = "system-alloc"))]
compile_error!("Features 'jemalloc' and 'system-alloc' are mutually exclusive; enable only one.");

#[cfg(all(feature = "rustalloc", any(feature = "jemalloc", feature = "system-alloc")))]
compile_error!("Feature 'rustalloc' cannot be combined with 'jemalloc' or 'system-alloc'.");
Cargo.toml (1)

301-301: Document allocator feature intent

Consider adding a short comment indicating system-alloc is intended for profiling workflows (with gperftools/heaptrack) and should not be combined with jemalloc or rustalloc. This complements the compile-time checks suggested in lib.rs.

 [features]
 default = ["jemalloc", "tokio-console", "tracing-loki", "tracing-chrome"]
 slim = ["rustalloc"]
-system-alloc = []
+system-alloc = [] # Use the platform allocator (for memory profiling). Do not combine with 'jemalloc' or 'rustalloc'.
build.rs (2)

7-10: Gate tcmalloc linking by OS to avoid surprising failures on non-Linux hosts

Linking tcmalloc is primarily useful/available on Linux; on macOS or others this can fail even when users set the env var. Add a small OS gate + warning to make failures more predictable.

-    if is_env_truthy("FOREST_PROFILING_GPERFTOOLS_BUILD") {
-        println!("cargo:rustc-link-lib=tcmalloc");
-    }
+    if is_env_truthy("FOREST_PROFILING_GPERFTOOLS_BUILD") {
+        // tcmalloc is mainly supported on Linux; emit a warning elsewhere.
+        #[cfg(target_os = "linux")]
+        {
+            println!("cargo:rustc-link-lib=tcmalloc");
+        }
+        #[cfg(not(target_os = "linux"))]
+        {
+            println!("cargo:warning=FOREST_PROFILING_GPERFTOOLS_BUILD=1 set, \
+                      but tcmalloc linking is only attempted on Linux.");
+        }
+    }

49-54: Tighten truthiness parsing and avoid allocation

Current implementation lowercases the whole string and accepts an unusual _yes_ token. Suggest trimming whitespace, supporting common tokens, and using eq_ignore_ascii_case to avoid allocating.

-fn is_env_truthy(env: &str) -> bool {
-    std::env::var(env)
-        .ok()
-        .map(|var| matches!(var.to_lowercase().as_str(), "1" | "true" | "yes" | "_yes_"))
-        .unwrap_or_default()
-}
+fn is_env_truthy(env: &str) -> bool {
+    std::env::var(env).map_or(false, |v| {
+        let v = v.trim();
+        v == "1"
+            || v.eq_ignore_ascii_case("true")
+            || v.eq_ignore_ascii_case("yes")
+            || v.eq_ignore_ascii_case("on")
+    })
+}

If _yes_ is intentional for some pipeline quirk, consider documenting it or keeping it as an extra match with a short comment.

Makefile (2)

133-139: gperftools heap profiling flow looks correct; minor env nit

The build + run sequence with --features system-alloc and FOREST_PROFILING_GPERFTOOLS_BUILD=1 is spot-on. Tiny nit: HEAPPROFILE_USE_PID is typically set to 1 in docs/examples—t likely works but 1 is clearer.

-	HEAPPROFILE_USE_PID=t HEAPPROFILE=/tmp/gperfheap.$(1).prof target/profiling/$(1) $(2)
+	HEAPPROFILE_USE_PID=1 HEAPPROFILE=/tmp/gperfheap.$(1).prof target/profiling/$(1) $(2)

Also consider supporting an override for the output path via a make var like GPROF_OUT ?= /tmp to avoid hardcoding /tmp in containerized runs.


147-153: Heaptrack target LGTM; add existence checks and guidance

This target is practical. To improve UX, add quick checks that heaptrack exists and print a hint otherwise.

-memprofile-heaptrack = cargo build --no-default-features --features system-alloc --profile=profiling --bin $(1); \
-						 ulimit -n 8192; \
-             heaptrack -o /tmp/heaptrack.$(1).%p.zst target/profiling/$(1) $(2)
+memprofile-heaptrack = command -v heaptrack >/dev/null 2>&1 || { echo "heaptrack not found. See https://github.com/KDE/heaptrack"; exit 127; }; \
+	 cargo build --no-default-features --features system-alloc --profile=profiling --bin $(1); \
+	 ulimit -n 8192; \
+	 heaptrack -o /tmp/heaptrack.$(1).%p.zst target/profiling/$(1) $(2)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9752098 and 0968b04.

⛔ Files ignored due to path filters (6)
  • documentation/src/developer_documentation/heaptrack/bottom_up.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/caller_callee.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/consumed.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/flamegraph.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/sizes.png is excluded by !**/*.png
  • documentation/src/developer_documentation/heaptrack/summary.png is excluded by !**/*.png
📒 Files selected for processing (6)
  • Cargo.toml (2 hunks)
  • Makefile (1 hunks)
  • build.rs (2 hunks)
  • documentation/src/SUMMARY.md (0 hunks)
  • documentation/src/developer_documentation/memory-analysis.md (0 hunks)
  • src/lib.rs (1 hunks)
💤 Files with no reviewable changes (2)
  • documentation/src/SUMMARY.md
  • documentation/src/developer_documentation/memory-analysis.md
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: LesnyRumcajs
PR: ChainSafe/forest#5907
File: src/rpc/methods/state.rs:523-570
Timestamp: 2025-08-06T15:44:33.467Z
Learning: LesnyRumcajs prefers to rely on BufWriter's Drop implementation for automatic flushing rather than explicit flush() calls in Forest codebase.
📚 Learning: 2025-08-07T13:39:15.107Z
Learnt from: hanabi1224
PR: ChainSafe/forest#5886
File: interop-tests/src/tests/go_app/gen.go:29-29
Timestamp: 2025-08-07T13:39:15.107Z
Learning: Auto-generated files like those created by rust2go (indicated by "Generated by rust2go. Please DO NOT edit this C part manually." comment) in the Forest project should be skipped during code review as they are not intended for manual editing.

Applied to files:

  • build.rs
📚 Learning: 2025-08-08T12:10:45.218Z
Learnt from: hanabi1224
PR: ChainSafe/forest#5867
File: src/ipld/util.rs:553-558
Timestamp: 2025-08-08T12:10:45.218Z
Learning: Forest project targets Rust stable >=1.89; features stabilized in 1.88 like let-chains are acceptable in this codebase.

Applied to files:

  • build.rs
📚 Learning: 2025-08-04T13:36:22.993Z
Learnt from: hanabi1224
PR: ChainSafe/forest#5835
File: src/chain/tests.rs:58-76
Timestamp: 2025-08-04T13:36:22.993Z
Learning: In the Forest codebase, `Vec<u8>` can be used as an `AsyncWrite` implementation in test contexts. The user confirmed that tests using `&mut Vec<u8>` with `export` and `export_v2` functions compile and pass both locally and on CI.

Applied to files:

  • build.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: tests-release
  • GitHub Check: tests
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: Bootstrap checks - Lotus
  • GitHub Check: Snapshot unordered export checks
  • GitHub Check: Calibnet no discovery checks
  • GitHub Check: Snapshot export checks v2 with F3 data
  • GitHub Check: Snapshot export checks
  • GitHub Check: Wallet tests
  • GitHub Check: Devnet checks
  • GitHub Check: Calibnet check
  • GitHub Check: Forest CLI checks
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (go)
🔇 Additional comments (3)
Cargo.toml (1)

279-285: Profiling profile LGTM; aligns with memory tooling needs

The dedicated [profile.profiling] with debug info and panic = "abort" is appropriate for heap profilers. No issues spotted.

build.rs (1)

17-39: Env opt-out semantics for f3-sidecar: confirm docs and CI expectations

Switching to !is_env_truthy("FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT") changes the default to “build sidecar unless explicitly opted out.” That’s fine, but please ensure:

  • The new variable is documented in CONTRIBUTING/docs.
  • CI and release pipelines do not set legacy envs expecting the old behavior.

I can scan the repo/CI for references to FOREST_F3_SIDECAR_FFI_BUILD_OPT_OUT vs any older sidecar env and report mismatches if helpful.

Makefile (1)

120-126: Nice: clear, discoverable profiling section

The section header and link to reference material are appreciated. This will save time for future investigations.

hanabi1224
hanabi1224 previously approved these changes Aug 21, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
Cargo.toml (1)

279-285: Profiling profile is a good start; consider codegen-units=1 and a small opt-level bump for more realistic allocation behavior.

  • For memory investigations that aim to resemble production allocation patterns (while keeping good symbols), opt-level=1 (or 2) often strikes a better balance than 0. opt-level=0 can materially change inlining and allocation sites. Optional tweak below.
  • Adding codegen-units = 1 helps produce tighter, more stable call stacks for profilers and can modestly reduce noise across runs.
  • Minor: split-debuginfo = "unpacked" is already inherited from [profile.dev]; it’s harmless to keep, but redundant.

Apply if desired:

 [profile.profiling]
 inherits = "dev"
-opt-level = 0
+opt-level = 1
 debug = true
 split-debuginfo = "unpacked"
 panic = "abort"
+codegen-units = 1

If you prefer keeping opt-level = 0, you can still add only codegen-units = 1.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4b5d324 and f5326a6.

📒 Files selected for processing (1)
  • Cargo.toml (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: LesnyRumcajs
PR: ChainSafe/forest#5907
File: src/rpc/methods/state.rs:523-570
Timestamp: 2025-08-06T15:44:33.467Z
Learning: LesnyRumcajs prefers to rely on BufWriter's Drop implementation for automatic flushing rather than explicit flush() calls in Forest codebase.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: All lint checks
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: Build MacOS
  • GitHub Check: Build Ubuntu
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: tests
  • GitHub Check: tests-release
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (go)

Comment thread Cargo.toml
@LesnyRumcajs LesnyRumcajs enabled auto-merge August 22, 2025 15:27
@LesnyRumcajs LesnyRumcajs added this pull request to the merge queue Aug 22, 2025
Merged via the queue into main with commit 40342cb Aug 22, 2025
54 of 55 checks passed
@LesnyRumcajs LesnyRumcajs deleted the memory-profile branch August 22, 2025 16:25
@coderabbitai coderabbitai Bot mentioned this pull request May 15, 2026
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory usage in Forest analysis

3 participants