From 65f51deabd83d4f97fe0146d950238316a7b4e74 Mon Sep 17 00:00:00 2001 From: Thaumy Date: Wed, 20 Mar 2024 11:40:09 +0800 Subject: [PATCH] add helper functions for `TracepointEvent` - `TracepointEvent::from_event_name`: construct `TracepointEvent` from event name. - `TracepointEvent::available_event_names`: get all available event names. --- src/perf_event/event/tracepoint.rs | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/perf_event/event/tracepoint.rs b/src/perf_event/event/tracepoint.rs index 6abfed5..6911ecb 100644 --- a/src/perf_event/event/tracepoint.rs +++ b/src/perf_event/event/tracepoint.rs @@ -13,6 +13,25 @@ // see . use crate::perf_event::event::Event; +use std::num::ParseIntError; +use std::ops::Not; +use std::path::PathBuf; +use std::{fs, io}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("Event name is invalid")] + InvalidEventName, + #[error("Event is unsupported")] + UnsupportedEvent, + #[error("Failed to find tracefs")] + FailedToFindTracefs, + #[error("Failed to parse id file: {0}")] + FailedToParseIdFile(ParseIntError), + #[error("I/O error: {0}")] + IoError(io::Error), +} #[derive(Clone, Debug)] pub struct TracepointEvent { @@ -24,6 +43,57 @@ impl TracepointEvent { pub const fn new(id: u64) -> Self { Self { id } } + + /// The format of the event name is `lhs:rhs`, for example: `sched:sched_switch` + /// + /// For all available events, see: `/sys/kernel/debug/tracing/available_events` + pub fn from_event_name(event_name: &str) -> Result { + let mut split = event_name.split(':'); + let path = match (split.next(), split.next()) { + (_, None) => return Err(Error::InvalidEventName), + (None, _) => return Err(Error::InvalidEventName), + (Some(lhs), Some(rhs)) => { + let mut path = tracefs_path()?; + path.push("events"); + path.push(lhs); + path.push(rhs); + path.push("id"); + path + } + }; + + if path.exists().not() { + return Err(Error::UnsupportedEvent); + } + + let contents = fs::read_to_string(path).map_err(Error::IoError)?; + let id = + str::parse::(&contents.replace('\n', "")).map_err(Error::FailedToParseIdFile)?; + + Ok(Self { id }) + } + + /// Get all available event names from `/sys/kernel/debug/tracing/available_events` + pub fn available_event_names() -> Result, Error> { + let mut path = tracefs_path()?; + path.push("available_events"); + + let contents = fs::read_to_string(path).map_err(Error::IoError)?; + let lines: Vec = contents.lines().map(|it| it.to_string()).collect(); + + Ok(lines) + } +} + +fn tracefs_path() -> Result { + let contents = fs::read_to_string("/proc/mounts").map_err(Error::IoError)?; + + contents + .lines() + .find(|line| line.starts_with("tracefs")) + .and_then(|line| line.split(' ').nth(1)) + .ok_or_else(|| Error::FailedToFindTracefs) + .map(PathBuf::from) } impl From for Event { @@ -31,3 +101,18 @@ impl From for Event { Self::Tracepoint(value) } } + +#[test] +fn test_from_event_name() { + let ev_name = "kmem:kfree"; + let ev = TracepointEvent::from_event_name(ev_name); + dbg!(ev.unwrap()); +} + +#[test] +fn test_available_event_names() { + let ev_names = TracepointEvent::available_event_names(); + dbg!(&ev_names); + let ev_names = ev_names.unwrap(); + assert!(ev_names.len() > 0); +}