Profiling Rust Code: Finding Bottlenecks for Beginners

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Profile Rust Code?

\n\n

Rust is renowned for its speed and safety, but even the fastest code can run slowly if it has bottlenecks. Profiling is the process of measuring program performance: execution time, CPU load, memory, and other metrics. For beginner Rust developers, this is an indispensable skill that allows you to turn "just working" code into efficient and fast code.

\n\n

Imagine you've written a log parser or a game in Rust. Everything compiles, but the program runs longer than expected. Instead of guessing which part of the code is slow, you can use profilers that will show you the exact "hotspots." In this article, we'll cover the main profiling tools for Rust beginners: cargo-flamegraph, perf, and simple measurements using std::time::Instant.

\n\n

1. The Simplest Way: Timing with std::time::Instant

\n\n

Before moving on to complex tools, learn how to measure the execution time of individual code sections. This is a basic but effective method for beginners.

\n\n

Example: Measuring Function Execution Time

\n\n
use std::time::Instant;\n\nfn slow_function() {\n    let mut sum = 0u64;\n    for i in 0..1_000_000 {\n        sum += i;\n    }\n    println!("Sum: {}", sum);\n}\n\nfn main() {\n    let start = Instant::now();\n    slow_function();\n    let duration = start.elapsed();\n    println!("Execution time: {:?}", duration);\n}\n
\n\n

This code will output the exact runtime of slow_function. However, this approach is inconvenient for large projects: you'll have to manually place measurements in every suspicious location.

\n\n

When is this useful?

\n
    \n
  • You want to quickly test a hypothesis about a slow function.
  • \n
  • You don't have the ability to install additional tools.
  • \n
  • You are working with single-threaded code without complex logic.
  • \n
\n\n

Drawback: Manual measurements don't show how much time is spent inside called functions (e.g., memory allocations or system calls). For that, you need profilers.

\n\n

2. Profiling with perf (Linux)

\n\n

The perf utility is a powerful profiler for Linux that works at the kernel level. It collects samples of where the program spends its time. First, make sure perf is installed:

\n\n
sudo apt install linux-tools-common linux-tools-generic  # Ubuntu/Debian\n
\n\n

Step 1: Compile with Debug Information

\n

For perf to show function names and code lines, compile your project in debug mode (or release with debuginfo flags):

\n\n
cargo build\n# or\nRUSTFLAGS="-g" cargo build --release\n
\n\n

Step 2: Run Profiling

\n
perf record -g ./target/debug/your_program\nperf report\n
\n\n

The -g flag enables call graph recording. After running perf report, you'll see an interactive list of functions sorted by execution time.

\n\n

Example Interpretation

\n

Suppose you see that 70% of the time is spent in the Vec::push function. This might mean you are frequently reallocating memory. Solution: pre-allocate the vector's capacity using Vec::with_capacity.

\n\n

Tip: For beginners, perf may seem complex due to the abundance of data. Start with perf top in real-time to see which functions are "hot" right now.

\n\n

3. Visualization with cargo-flamegraph

\n\n

If you need a visual picture, use cargo-flamegraph. This tool builds flamegraphs — charts where the width of a rectangle shows the function's execution time, and the depth shows the call stack.

Blogs

Book Recommendations