Debugging Rust Code in Ubuntu
Before debugging, ensure your Rust program includes debug symbols (enabled by default in cargo build). For explicit control, use:
cargo build # Debug build (includes debug info)
To compile with custom debug levels (e.g., for more detailed logs), configure the debug profile in Cargo.toml:
[profile.dev]
debug = true # Enabled by default
println!/dbg!:** Use println!(“{:?}”, variable)to print values ordbg!(variable)` to output the variable’s value along with its file and line number (handy for quick checks):fn main() {
let x = 42;
dbg!(x); // Output: [src/main.rs:2] x = 42
}
sudo apt install gdb lldb
cargo build.gdb target/debug/your_program.break main.rs:5), run (run), step through code (next/step), and inspect variables (print x).lldb target/debug/your_program.breakpoint set --name main, run, next, and frame variable to navigate and inspect.Rust provides wrappers around GDB/LLDB to automatically load debug symbols and improve Rust-specific debugging:
rust-gdb target/debug/your_program # Rust-aware GDB
rust-lldb target/debug/your_program # Rust-aware LLDB
These tools enhance symbol resolution and provide better formatting for Rust types (e.g., enums, structs).
For a graphical interface, use Visual Studio Code (VS Code) with the rust-analyzer extension:
rust-analyzer from the VS Code extensions marketplace.launch.json file in .vscode/ with debug configuration:{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/target/debug/your_program",
"args": [],
"cwd": "${workspaceFolder}"
}
]
}
F5 to start debugging. Use the debug sidebar to inspect variables, call stacks, and control execution.Use the log crate for structured logging and env_logger to control log levels via environment variables:
Cargo.toml:[dependencies]
log = "0.4"
env_logger = "0.10"
main.rs:use log::{info, warn};
fn main() {
env_logger::init(); // Initialize logger
info!("Program started");
warn!("This is a warning");
}
RUST_LOG=info cargo run # Show INFO and higher logs
Optimizing Rust Code in Ubuntu
release Mode: The --release flag enables optimizations (e.g., inlining, loop unrolling) for production builds:cargo build --release
RUSTFLAGS. For example, enable link-time optimization (LTO) for better performance:RUSTFLAGS="-C opt-level=3 -C lto" cargo build --release
Vec::with_capacity) to reduce dynamic resizing:let mut vec = Vec::with_capacity(100); // Pre-allocate space for 100 elements
iter().sum():let sum: i32 = vec![1, 2, 3].iter().sum(); // More efficient than a loop
Mutex) and use concurrent data structures (e.g., tokio::sync::Mutex for async code) to avoid bottlenecks.rayon crate to parallelize operations (e.g., summing a vector) with minimal code changes:use rayon::prelude::*;
let sum: i32 = vec![1, 2, 3].par_iter().sum(); // Automatically parallelized
tokio to handle concurrent tasks efficiently:use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = [0; 1024];
loop {
let bytes_read = socket.read(&mut buf).await.unwrap();
if bytes_read == 0 { return; }
socket.write_all(&buf[0..bytes_read]).await.unwrap();
}
});
}
}
jemalloc (faster for multi-threaded programs) by setting the RUSTFLAGS environment variable:export RUSTFLAGS="-C target-cpu=native -C link-arg=-ljemalloc"
cargo build --release
valgrind to detect memory leaks:valgrind --tool=memcheck --leak-check=full ./target/release/your_program
perf: Analyze CPU usage, cache hits, and function hotspots with perf:perf record ./target/release/your_program
perf report # View performance report
cargo install flamegraph
flamegraph ./target/release/your_program # Generate flamegraph.svg
ulimit -n 65536 # Temporary increase
For permanent changes, edit /etc/security/limits.conf.net.ipv4.tcp_max_syn_backlog) to improve network performance for high-throughput applications.