Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions crates/memtrack/src/ebpf/libbpf_log.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::prelude::*;
use libbpf_rs::PrintLevel;

fn strip(msg: &str) -> &str {
let msg = msg.trim_end();
msg.strip_prefix("libbpf: ").unwrap_or(msg)
}

fn to_log(level: PrintLevel, msg: String) {
let msg = strip(&msg);
match level {
PrintLevel::Warn => warn!(target: "libbpf", "{msg}"),
PrintLevel::Info => info!(target: "libbpf", "{msg}"),
PrintLevel::Debug => debug!(target: "libbpf", "{msg}"),
}
}

fn to_debug(_level: PrintLevel, msg: String) {
debug!(target: "libbpf", "{}", strip(&msg));
}

/// Route libbpf's output through the logger, so `CODSPEED_LOG` filters it like
/// any other target (e.g. `libbpf=debug`). The minimum level follows the
/// logger's so libbpf skips formatting messages that would be dropped.
pub fn init_libbpf_logging() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we don't really need this anymore after we merge #531, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think we do though, it's for libbpf loggin not really memtrack logging

let min_level = match log::max_level() {
log::LevelFilter::Off => {
libbpf_rs::set_print(None);
return;
}
log::LevelFilter::Error | log::LevelFilter::Warn => PrintLevel::Warn,
log::LevelFilter::Info => PrintLevel::Info,
log::LevelFilter::Debug | log::LevelFilter::Trace => PrintLevel::Debug,
};
libbpf_rs::set_print(Some((min_level, to_log)));
}

/// Run `f` with every libbpf message logged at debug, for calls whose failure
/// the caller handles and reports itself.
pub(crate) fn with_libbpf_demoted<T>(f: impl FnOnce() -> T) -> T {
let prev = libbpf_rs::get_print();
if let Some((min_level, _)) = prev {
libbpf_rs::set_print(Some((min_level, to_debug)));
}
let result = f();
libbpf_rs::set_print(prev);
result
}
22 changes: 22 additions & 0 deletions crates/memtrack/src/ebpf/memtrack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,27 @@ fn page_shift() -> Result<u32> {
Ok((page_size as u32).trailing_zeros())
}

/// Bump RLIMIT_MEMLOCK for kernels older than 5.11. Newer kernels account BPF
/// memory against the cgroup, so a denied raise (no CAP_SYS_RESOURCE) is harmless.
/// libbpf's own attempt is disabled, as it warns on that same harmless denial.
fn bump_memlock_rlimit() {
let rlimit = libc::rlimit {
rlim_cur: libc::RLIM_INFINITY,
rlim_max: libc::RLIM_INFINITY,
};

let ret = unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlimit) };
if ret != 0 {
let err = std::io::Error::last_os_error();
debug!(
"Could not raise RLIMIT_MEMLOCK ({err}); continuing since kernels >= 5.11 don't require it"
);
}

// Fails with EBUSY once libbpf has run its bump check, which is then moot.
let _ = unsafe { libbpf_rs::libbpf_sys::libbpf_set_memlock_rlim(0) };
}

/// Attach targets resolved from a library's symbol tables.
pub struct ResolvedSymbols {
offsets: HashMap<String, usize>,
Expand Down Expand Up @@ -132,6 +153,7 @@ pub struct MemtrackBpf {
impl MemtrackBpf {
pub fn new(options: &TrackerOptions) -> Result<Self> {
crate::kernel::KernelBtf::ensure_available()?;
bump_memlock_rlimit();

let variant = options.variant.unwrap_or_else(|| {
if has_delegated_bpf_token() {
Expand Down
5 changes: 3 additions & 2 deletions crates/memtrack/src/ebpf/memtrack/tracking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ impl MemtrackBpf {
self.attach_sched_process_exec()?;
self.attach_sched_process_exit()?;
if self.physical {
if let Err(e) = self.attach_rss_stat() {
warn!("Failed to attach rss_stat tracepoint, RSS collection disabled: {e:#}");
let attached = crate::ebpf::libbpf_log::with_libbpf_demoted(|| self.attach_rss_stat());
if let Err(e) = attached {
debug!("Failed to attach rss_stat tracepoint, RSS collection disabled: {e:#}");
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/memtrack/src/ebpf/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod attach_worker;
mod events;
pub(crate) mod libbpf_log;
mod memtrack;
pub(crate) mod pause;
pub(crate) mod poller;
Expand All @@ -8,6 +9,7 @@ mod spawn;
mod stacks;
mod tracker;

pub use libbpf_log::init_libbpf_logging;
pub use memtrack::{
BpfVariant, MemtrackBpf, OwnershipMaps, ResolvedSymbols, RmapSupport, resolve_symbol_offsets,
};
Expand Down
21 changes: 0 additions & 21 deletions crates/memtrack/src/ebpf/tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ impl Tracker {
}

fn build(mut bpf: MemtrackBpf, options: TrackerOptions) -> Result<Self> {
Self::bump_memlock_rlimit()?;

bpf.attach_tracepoints()?;
if options.allocators {
bpf.attach_exec_watcher()?;
Expand Down Expand Up @@ -242,23 +240,4 @@ impl Tracker {
pub fn detach(&self) {
self.bpf.lock().detach_probes();
}

/// Bump RLIMIT_MEMLOCK for kernels older than 5.11. Newer kernels account BPF
/// memory against the cgroup, so a denied raise (no CAP_SYS_RESOURCE) is harmless.
fn bump_memlock_rlimit() -> Result<()> {
let rlimit = libc::rlimit {
rlim_cur: libc::RLIM_INFINITY,
rlim_max: libc::RLIM_INFINITY,
};

let ret = unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlimit) };
if ret != 0 {
let err = std::io::Error::last_os_error();
debug!(
"Could not raise RLIMIT_MEMLOCK ({err}); continuing since kernels >= 5.11 don't require it"
);
}

Ok(())
}
}
1 change: 1 addition & 0 deletions crates/memtrack/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ fn main() -> Result<()> {
.parse_env(env_logger::Env::new().filter_or("CODSPEED_LOG", "info"))
.format_timestamp(None)
.init();
memtrack::init_libbpf_logging();

let cli = Cli::parse();

Expand Down
Loading