# How to Convert Rust pprof Profiles for Code-Graph-RAG: A Complete Guide

> Convert Rust pprof profiles for Code-Graph-RAG using our guide. Learn to demangle symbols and filter repositories with convert_rust_pprof. Optimize your RAG workflow today.

- Repository: [Vitali Avagyan/code-graph-rag](https://github.com/vitali87/code-graph-rag)
- Tags: how-to-guide
- Published: 2026-09-06

---

**Rust pprof profiles are converted for Code-Graph-RAG by reusing the generic Go pprof decoder with Rust-specific symbol demangling and repository filtering applied via `convert_rust_pprof` in [`codebase_rag/trace/rust_pprof.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/trace/rust_pprof.py).**

The [vitali87/code-graph-rag](https://github.com/vitali87/code-graph-rag) repository ingests dynamic execution data from CPU profiles to enrich its retrieval-augmented generation (RAG) pipeline. Because the Rust `pprof-rs` crate emits protobuf profiles identical to Go's pprof format on the wire, the conversion leverages a shared decoder with language-specific customizations for symbol normalization and build artifact filtering.

## Understanding the Rust pprof Profile Format

The `pprof` Rust crate (commonly used via `cargo-flamegraph`) generates gzipped protobuf files containing `sample`, `function`, `location`, and `string` tables. These match the [Google pprof protocol](https://github.com/google/pprof/tree/main/proto) exactly.

This structural compatibility means Code-Graph-RAG doesn't need a separate parser. Instead, it delegates to the language-agnostic decoder in [`codebase_rag/trace/pprof.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/trace/pprof.py) and injects Rust-specific behavior through callback functions.

## Rust-Specific Conversion Logic

Three customizations differentiate Rust profile conversion from Go profiles:

- **Symbol demangling and frame normalization** — handled by `_bare_name()` in [`codebase_rag/trace/rust_pprof.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/trace/rust_pprof.py)
- **Repository-scope filtering** — implemented in `_build_frame()` to exclude `target/` directories and external files
- **Language tagging** — applied through constants from [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py)

### Frame Name Normalization with `_bare_name`

Rust symbols require aggressive cleaning before they can match static analysis results. The `_bare_name()` function applies a multi-stage pipeline:

1. **Strip legacy hash suffixes** — removes `::h<hex>` compiler-inserted hashes
2. **Remove generic arguments** — eliminates `<...>` turbofish syntax and type parameters
3. **Discard function arguments** — strips `(...)` parameter lists
4. **Split qualified paths** — respects nesting depth of brackets and parentheses
5. **Collapse closures** — maps anonymous closure frames to `cs.TRACE_QUALNAME_ANONYMOUS`

The helper `_split_top_level()` performs depth-aware path splitting, ensuring that nested angle brackets in generic types don't break the module hierarchy.

### Repository Filtering in `_build_frame`

The `_build_frame()` function constructs `FramePoint` objects identical to the Go path, but with two Rust-specific exclusions:

- Files outside the `repo_root` are skipped
- Files inside `target/` directories (Cargo's build output) are ignored

This prevents build artifacts and standard library internals from polluting the dynamic call graph.

## The Conversion Pipeline

The `convert_rust_pprof()` function orchestrates the full workflow:

```python
def convert_rust_pprof(profile_path, repo_root, output, workload=None):
    # Delegate to generic pipeline with Rust-specific callbacks

    return convert_pprof_profile(
        profile_path=profile_path,
        build_frame=_build_frame,           # Rust frame construction

        language=cs.TRACE_LANGUAGE_RUST,    # "rust"

        tracer_name=cs.TRACE_TOOL_NAME_RUST_PPROF,  # "rust-pprof"

        output_path=output,
        workload=workload,
    )

```

The `convert_pprof_profile()` function in [`pprof.py`](https://github.com/vitali87/code-graph-rag/blob/main/pprof.py) handles:
- Reading and decompressing the gzipped protobuf
- Parsing profile tables into in-memory structures
- Iterating samples and converting stacks to call-edge records
- Writing JSON-Lines output with language-specific metadata

## Practical Code Examples

### Python API Conversion

Convert a Rust profile programmatically:

```python
from pathlib import Path
from codebase_rag.trace.rust_pprof import convert_rust_pprof

profile = Path("target/debug/cpu.pb")       # Output from pprof-rs / cargo-flamegraph

repo_root = Path("/path/to/your/project")   # Repository root for filtering

output = Path("trace_edges.jsonl")          # Trace interchange format

edges_written = convert_rust_pprof(
    profile_path=profile,
    repo_root=repo_root,
    output=output,
    workload="my-rust-binary",              # Optional workload identifier

)

print(f"Converted {edges_written} call edges")

```

### CLI Conversion

The `cgr trace` command auto-detects Rust profiles:

```bash
cgr trace pull \
    --language rust \
    --profile /path/to/cpu.pb \
    --repo-root /path/to/project \
    --output edges.jsonl

```

The CLI dispatcher in [`codebase_rag/trace/cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/trace/cli.py) (lines 86–96) routes `--language rust` to `convert_rust_pprof()`.

## Key Source Files

| File | Purpose |
|------|---------|
| [`codebase_rag/trace/rust_pprof.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/trace/rust_pprof.py) | Core conversion logic, symbol demangling (`_bare_name`, `_split_top_level`, `_strip_generics_and_args`), and frame building (`_build_frame`) |
| [`codebase_rag/trace/pprof.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/trace/pprof.py) | Language-agnostic protobuf decoder and `convert_pprof_profile()` pipeline |
| [`codebase_rag/trace/cli.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/trace/cli.py) | Command-line interface, dispatches to Rust converter |
| [`codebase_rag/trace/records.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/trace/records.py) | `FramePoint` and trace record definitions |
| [`codebase_rag/constants.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/constants.py) | Language tags (`TRACE_LANGUAGE_RUST`, `TRACE_TOOL_NAME_RUST_PPROF`) and anonymous closure sentinel |

## Summary

- Rust pprof profiles use the **same protobuf format as Go**, enabling decoder reuse
- **Symbol demangling** is Rust-specific: hashes, generics, and closures are normalized via `_bare_name()`
- **`target/` and external files are filtered** to keep only project-relevant frames
- The **`convert_rust_pprof()` function** wraps the generic pipeline with Rust callbacks and constants
- Both **Python API and CLI** interfaces are available for production workflows

## Frequently Asked Questions

### Why does Rust use the same pprof decoder as Go?

The `pprof-rs` crate implements the **Google pprof protocol** identically on the wire. Both Go's runtime profiler and `pprof-rs` output gzip-compressed protobuf files with matching table structures for samples, functions, locations, and strings. Code-Graph-RAG exploits this compatibility by factoring the parsing logic into [`pprof.py`](https://github.com/vitali87/code-graph-rag/blob/main/pprof.py) and injecting language-specific behavior through the `build_frame` callback.

### How does symbol demangling handle Rust's complex generics?

The `_bare_name()` function uses `_strip_generics_and_args()` to recursively remove `<...>` turbofish blocks and `(...)` argument lists while tracking nesting depth. The `_split_top_level()` helper then decomposes the remaining path into module components without breaking on internal brackets. This produces clean `module::Type::method` signatures that align with static analysis results.

### What files are excluded during Rust profile conversion?

The `_build_frame()` function in [`rust_pprof.py`](https://github.com/vitali87/code-graph-rag/blob/main/rust_pprof.py) filters out two categories: **files outside the repository root** (to exclude standard library and dependency code) and **files inside `target/` directories** (to exclude Cargo build artifacts). Only source files within your project's actual codebase contribute to the dynamic call graph.

### Can I use this with profiling tools other than cargo-flamegraph?

Yes. Any tool that produces **pprof-compatible protobuf output** works, including direct `pprof-rs` integration, `tokio-console`, or custom instrumentation. The key requirement is the standard pprof wire format; the converter handles all Rust-specific symbol processing regardless of how the profile was collected.