Bladeren bron

refactor: refactor tracepoint (#1186)

* Refactor: refactor tracepoint

Move tracepoints into separate module.
Macro implementation closer to Linux.
Add the id and formt files corresponding to each tracepoint.
Correctly handle trace/trace_pipe files.

Signed-off-by: Godones <chenlinfeng25@outlook.com>
linfeng 1 week geleden
bovenliggende
commit
58e7943c13

+ 129 - 173
kernel/src/debug/tracing/events.rs

@@ -1,139 +1,101 @@
-use crate::debug::tracing::tracepoint::{CommonTracePointMeta, TracePoint};
+use alloc::string::ToString;
+
 use crate::debug::tracing::TracingDirCallBack;
 use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData};
 use crate::filesystem::kernfs::KernFSInode;
 use crate::filesystem::vfs::syscall::ModeType;
 use crate::filesystem::vfs::PollStatus;
-use crate::libs::spinlock::SpinLock;
-use alloc::boxed::Box;
-use alloc::collections::BTreeMap;
-use alloc::string::{String, ToString};
+use crate::tracepoint::*;
 use alloc::sync::Arc;
 use system_error::SystemError;
 
 #[derive(Debug)]
-pub struct TracingEventsManager {
-    root: Arc<KernFSInode>,
-    subsystems: SpinLock<BTreeMap<String, Arc<EventsSubsystem>>>,
-}
+struct EnableCallBack;
 
-impl TracingEventsManager {
-    pub fn new(root: Arc<KernFSInode>) -> Self {
-        Self {
-            root,
-            subsystems: SpinLock::new(BTreeMap::new()),
+impl KernFSCallback for EnableCallBack {
+    fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn read(
+        &self,
+        data: KernCallbackData,
+        buf: &mut [u8],
+        offset: usize,
+    ) -> Result<usize, SystemError> {
+        let pri_data = data.private_data().as_ref().unwrap();
+        let tracepoint_info = pri_data.debugfs_tracepoint().unwrap();
+        let enable_value = tracepoint_info.enable_file().read();
+        if offset >= enable_value.as_bytes().len() {
+            return Ok(0); // Offset is beyond the length of the string
         }
+        let len = buf.len().min(enable_value.as_bytes().len() - offset);
+        buf[..len].copy_from_slice(&enable_value.as_bytes()[offset..offset + len]);
+        Ok(len)
     }
 
-    /// Create a subsystem by name
-    ///
-    /// If the subsystem already exists, return the existing subsystem.
-    pub fn create_subsystem(
+    fn write(
         &self,
-        subsystem_name: &str,
-    ) -> Result<Arc<EventsSubsystem>, SystemError> {
-        if self.subsystems.lock().contains_key(subsystem_name) {
-            return Ok(self.get_subsystem(subsystem_name).unwrap());
+        data: KernCallbackData,
+        buf: &[u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        let pri_data = data.private_data().as_ref().unwrap();
+        let tracepoint = pri_data.debugfs_tracepoint().unwrap();
+        if buf.is_empty() {
+            return Err(SystemError::EINVAL);
         }
-        let dir = self.root.add_dir(
-            subsystem_name.to_string(),
-            ModeType::from_bits_truncate(0o755),
-            None,
-            Some(&TracingDirCallBack),
-        )?;
-        let subsystem = Arc::new(EventsSubsystem::new(dir));
-        self.subsystems
-            .lock()
-            .insert(subsystem_name.to_string(), subsystem.clone());
-        Ok(subsystem)
+        tracepoint.enable_file().write(buf[0] as _);
+        Ok(buf.len())
     }
 
-    /// Get the subsystem by name
-    pub fn get_subsystem(&self, subsystem_name: &str) -> Option<Arc<EventsSubsystem>> {
-        self.subsystems.lock().get(subsystem_name).cloned()
+    fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
+        Err(SystemError::ENOSYS)
     }
 }
 
 #[derive(Debug)]
-pub struct EventsSubsystem {
-    root: Arc<KernFSInode>,
-    events: SpinLock<BTreeMap<String, Arc<EventInfo>>>,
-}
+struct FormatCallBack;
 
-impl EventsSubsystem {
-    pub fn new(root: Arc<KernFSInode>) -> Self {
-        Self {
-            root,
-            events: SpinLock::new(BTreeMap::new()),
-        }
-    }
-
-    /// Insert a new event into the subsystem
-    pub fn insert_event(
-        &self,
-        event_name: &str,
-        event_info: Arc<EventInfo>,
-    ) -> Result<(), SystemError> {
-        self.events
-            .lock()
-            .insert(event_name.to_string(), event_info);
+impl KernFSCallback for FormatCallBack {
+    fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
         Ok(())
     }
 
-    /// Get the event by name
-    #[allow(unused)]
-    pub fn get_event(&self, event_name: &str) -> Option<Arc<EventInfo>> {
-        self.events.lock().get(event_name).cloned()
+    fn read(
+        &self,
+        data: KernCallbackData,
+        buf: &mut [u8],
+        offset: usize,
+    ) -> Result<usize, SystemError> {
+        let pri_data = data.private_data().as_ref().unwrap();
+        let tracepoint = pri_data.debugfs_tracepoint().unwrap();
+        let format_str = tracepoint.format_file().read();
+        if offset >= format_str.as_bytes().len() {
+            return Ok(0); // Offset is beyond the length of the string
+        }
+        let len = buf.len().min(format_str.as_bytes().len() - offset);
+        buf[..len].copy_from_slice(&format_str.as_bytes()[offset..offset + len]);
+        Ok(len)
     }
 
-    /// Get the root inode of the subsystem
-    pub fn root(&self) -> Arc<KernFSInode> {
-        self.root.clone()
+    fn write(
+        &self,
+        _data: KernCallbackData,
+        _buf: &[u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        Err(SystemError::EPERM)
     }
-}
 
-#[derive(Debug)]
-pub struct EventInfo {
-    #[allow(unused)]
-    enable: Arc<KernFSInode>,
-    // filter: Arc<KernFSInode>,
-    // trigger: Arc<KernFSInode>,
-}
-
-impl EventInfo {
-    pub fn new(tracepoint: &'static TracePoint, subsystem: Arc<KernFSInode>) -> Arc<Self> {
-        let trace_dir = subsystem
-            .add_dir(
-                tracepoint.name().to_string(),
-                ModeType::from_bits_truncate(0o755),
-                None,
-                Some(&TracingDirCallBack),
-            )
-            .expect("add tracepoint dir failed");
-        let enable_inode = trace_dir
-            .add_file(
-                "enable".to_string(),
-                ModeType::from_bits_truncate(0o644),
-                None,
-                Some(KernInodePrivateData::DebugFS(tracepoint)),
-                Some(&EnableCallBack),
-            )
-            .expect("add enable file failed");
-
-        Arc::new(Self {
-            enable: enable_inode,
-        })
+    fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
+        Err(SystemError::ENOSYS)
     }
 }
 
-impl Drop for EventInfo {
-    fn drop(&mut self) {}
-}
-
 #[derive(Debug)]
-struct EnableCallBack;
-
-impl KernFSCallback for EnableCallBack {
+struct IDCallBack;
+impl KernFSCallback for IDCallBack {
     fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
         Ok(())
     }
@@ -144,55 +106,25 @@ impl KernFSCallback for EnableCallBack {
         buf: &mut [u8],
         offset: usize,
     ) -> Result<usize, SystemError> {
-        if offset > 0 {
-            return Ok(0);
-        }
-        let pri_data = data.private_data();
-        match pri_data {
-            Some(pri_data) => {
-                let tracepoint = pri_data.debugfs_tracepoint().ok_or(SystemError::EINVAL)?;
-                let buf_value = if tracepoint.is_enabled() { b"1" } else { b"0" };
-                let len = buf.len().min(buf_value.len());
-                buf[..len].copy_from_slice(&buf_value[..len]);
-                Ok(len)
-            }
-            None => {
-                return Err(SystemError::EINVAL);
-            }
+        let pri_data = data.private_data().as_ref().unwrap();
+        let tracepoint = pri_data.debugfs_tracepoint().unwrap();
+        let id_str = tracepoint.id_file().read();
+
+        if offset >= id_str.as_bytes().len() {
+            return Ok(0); // Offset is beyond the length of the string
         }
+        let len = buf.len().min(id_str.as_bytes().len() - offset);
+        buf[..len].copy_from_slice(&id_str.as_bytes()[offset..offset + len]);
+        Ok(len)
     }
 
     fn write(
         &self,
-        data: KernCallbackData,
-        buf: &[u8],
+        _data: KernCallbackData,
+        _buf: &[u8],
         _offset: usize,
     ) -> Result<usize, SystemError> {
-        let pri_data = data.private_data();
-        match pri_data {
-            Some(pri_data) => {
-                let tracepoint = pri_data.debugfs_tracepoint().ok_or(SystemError::EINVAL)?;
-                let value = core::str::from_utf8(buf)
-                    .map_err(|_| SystemError::EINVAL)?
-                    .trim();
-                match value {
-                    "0" => {
-                        tracepoint.disable();
-                    }
-                    "1" => {
-                        tracepoint.enable();
-                    }
-                    _ => {
-                        log::info!("EnableCallBack invalid value: {}", value);
-                        return Err(SystemError::EINVAL);
-                    }
-                }
-                Ok(buf.len())
-            }
-            None => {
-                return Err(SystemError::EINVAL);
-            }
-        }
+        Err(SystemError::EPERM)
     }
 
     fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
@@ -202,38 +134,62 @@ impl KernFSCallback for EnableCallBack {
 
 static mut TRACING_EVENTS_MANAGER: Option<TracingEventsManager> = None;
 
-/// Initialize the tracing events
-pub fn init_events(events_root: Arc<KernFSInode>) -> Result<(), SystemError> {
-    let events_manager = TracingEventsManager::new(events_root);
-    let tracepoint_data_start = _tracepoint as usize as *const CommonTracePointMeta;
-    let tracepoint_data_end = _etracepoint as usize as *const CommonTracePointMeta;
-    let tracepoint_data_len = (tracepoint_data_end as usize - tracepoint_data_start as usize)
-        / size_of::<CommonTracePointMeta>();
-    let tracepoint_data =
-        unsafe { core::slice::from_raw_parts(tracepoint_data_start, tracepoint_data_len) };
-    for tracepoint_meta in tracepoint_data {
-        let tracepoint = tracepoint_meta.trace_point;
-        tracepoint.register(tracepoint_meta.print_func, Box::new(()));
-        log::info!(
-            "tracepoint name: {}, module path: {}",
-            tracepoint.name(),
-            tracepoint.module_path()
-        );
-        // kernel::{subsystem}::
-        let mut subsys_name = tracepoint.module_path().split("::");
-        let subsys_name = subsys_name.nth(1).ok_or(SystemError::EINVAL)?;
-        let subsys = events_manager.create_subsystem(subsys_name)?;
-        let event_info = EventInfo::new(tracepoint, subsys.root());
-        subsys.insert_event(tracepoint.name(), event_info)?;
+pub fn tracing_events_manager() -> &'static TracingEventsManager {
+    unsafe {
+        TRACING_EVENTS_MANAGER
+            .as_ref()
+            .expect("TracingEventsManager not initialized")
     }
+}
 
+pub fn init_events(root: Arc<KernFSInode>) -> Result<(), SystemError> {
+    let events_manager = crate::tracepoint::global_init_events()?;
+    // Register the global tracing events manager
+    for subsystem_name in events_manager.subsystem_names() {
+        let subsystem = events_manager.get_subsystem(&subsystem_name).unwrap();
+        // Register the subsystem in the root inode
+        let subsystem_inode = root.add_dir(
+            subsystem_name,
+            ModeType::from_bits_truncate(0o755),
+            None,
+            Some(&TracingDirCallBack),
+        )?;
+        for event_name in subsystem.event_names() {
+            let event_info = subsystem.get_event(&event_name).unwrap();
+            let event_inode = subsystem_inode.add_dir(
+                event_name,
+                ModeType::from_bits_truncate(0o755),
+                None,
+                Some(&TracingDirCallBack),
+            )?;
+            // add enable file for the event
+            let _enable_inode = event_inode.add_file(
+                "enable".to_string(),
+                ModeType::from_bits_truncate(0o644),
+                None,
+                Some(KernInodePrivateData::DebugFS(event_info.clone())),
+                Some(&EnableCallBack),
+            )?;
+            // add format file for the event
+            let _format_inode = event_inode.add_file(
+                "format".to_string(),
+                ModeType::from_bits_truncate(0o644),
+                None,
+                Some(KernInodePrivateData::DebugFS(event_info.clone())),
+                Some(&FormatCallBack),
+            )?;
+            // add id file for the event
+            let _id_inode = event_inode.add_file(
+                "id".to_string(),
+                ModeType::from_bits_truncate(0o644),
+                None,
+                Some(KernInodePrivateData::DebugFS(event_info)),
+                Some(&IDCallBack),
+            )?;
+        }
+    }
     unsafe {
         TRACING_EVENTS_MANAGER = Some(events_manager);
     }
-
     Ok(())
 }
-extern "C" {
-    fn _tracepoint();
-    fn _etracepoint();
-}

+ 76 - 38
kernel/src/debug/tracing/mod.rs

@@ -1,59 +1,47 @@
 mod events;
 pub mod trace_pipe;
-pub mod tracepoint;
 
 use crate::debug::sysfs::debugfs_kset;
-use crate::debug::tracing::trace_pipe::TRACE_PIPE_MAX_RECORD;
 use crate::driver::base::kobject::KObject;
 use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData};
 use crate::filesystem::kernfs::KernFSInode;
 use crate::filesystem::vfs::syscall::ModeType;
 use crate::filesystem::vfs::PollStatus;
+use crate::libs::spinlock::SpinLock;
+use crate::tracepoint::TracePointInfo;
 use alloc::string::ToString;
 use alloc::sync::Arc;
 use system_error::SystemError;
-use tracepoint::TracePoint;
 
 static mut TRACING_ROOT_INODE: Option<Arc<KernFSInode>> = None;
 
-#[allow(unused)]
-fn tracing_root_inode() -> Arc<KernFSInode> {
-    unsafe { TRACING_ROOT_INODE.clone().unwrap() }
-}
-
-/// Initialize the debugfs tracing directory
-pub fn init_debugfs_tracing() -> Result<(), SystemError> {
-    let debugfs = debugfs_kset();
-    let root_dir = debugfs.inode().ok_or(SystemError::ENOENT)?;
-    let tracing_root = root_dir.add_dir(
-        "tracing".to_string(),
-        ModeType::from_bits_truncate(0o555),
-        None,
-        Some(&TracingDirCallBack),
-    )?;
-    let events_root = tracing_root.add_dir(
-        "events".to_string(),
-        ModeType::from_bits_truncate(0o755),
-        None,
-        Some(&TracingDirCallBack),
-    )?;
+static TRACE_RAW_PIPE: SpinLock<crate::tracepoint::TracePipeRaw> =
+    SpinLock::new(crate::tracepoint::TracePipeRaw::new(4096));
 
-    tracing_root.add_file(
-        "trace_pipe".to_string(),
-        ModeType::from_bits_truncate(0o444),
-        Some(TRACE_PIPE_MAX_RECORD),
-        None,
-        Some(&trace_pipe::TracePipeCallBack),
-    )?;
+static TRACE_CMDLINE_CACHE: SpinLock<crate::tracepoint::TraceCmdLineCache> =
+    SpinLock::new(crate::tracepoint::TraceCmdLineCache::new(128));
 
-    trace_pipe::init_trace_pipe();
+pub fn trace_pipe_push_raw_record(record: &[u8]) {
+    TRACE_RAW_PIPE.lock().push_event(record.to_vec());
+}
 
-    events::init_events(events_root)?;
+pub fn trace_cmdline_push(pid: u32) {
+    let process = crate::process::ProcessManager::current_pcb();
+    let binding = process.basic();
+    let pname = binding
+        .name()
+        .split(' ')
+        .next()
+        .unwrap_or("unknown")
+        .split('/')
+        .last()
+        .unwrap_or("unknown");
+    TRACE_CMDLINE_CACHE.lock().insert(pid, pname.to_string());
+}
 
-    unsafe {
-        TRACING_ROOT_INODE = Some(tracing_root);
-    }
-    Ok(())
+#[allow(unused)]
+fn tracing_root_inode() -> Arc<KernFSInode> {
+    unsafe { TRACING_ROOT_INODE.clone().unwrap() }
 }
 
 #[derive(Debug)]
@@ -88,10 +76,60 @@ impl KernFSCallback for TracingDirCallBack {
 }
 
 impl KernInodePrivateData {
-    pub fn debugfs_tracepoint(&self) -> Option<&'static TracePoint> {
+    pub fn debugfs_tracepoint(&self) -> Option<&Arc<TracePointInfo>> {
         return match self {
             KernInodePrivateData::DebugFS(tracepoint) => Some(tracepoint),
             _ => None,
         };
     }
+
+    pub fn tracepipe(&mut self) -> Option<&mut crate::tracepoint::TracePipeSnapshot> {
+        return match self {
+            KernInodePrivateData::TracePipe(snapshot) => Some(snapshot),
+            _ => None,
+        };
+    }
+}
+
+/// Initialize the debugfs tracing directory
+pub fn init_debugfs_tracing() -> Result<(), SystemError> {
+    let debugfs = debugfs_kset();
+    let root_dir = debugfs.inode().ok_or(SystemError::ENOENT)?;
+    let tracing_root = root_dir.add_dir(
+        "tracing".to_string(),
+        ModeType::from_bits_truncate(0o555),
+        None,
+        Some(&TracingDirCallBack),
+    )?;
+    let events_root = tracing_root.add_dir(
+        "events".to_string(),
+        ModeType::from_bits_truncate(0o755),
+        None,
+        Some(&TracingDirCallBack),
+    )?;
+
+    // tracing_root.add_file(
+    //     "trace".to_string(),
+    //     ModeType::from_bits_truncate(0o444),
+    //     Some(4096),
+    //     None,
+    //     Some(&trace_pipe::TraceCallBack),
+    // )?;
+
+    tracing_root.add_file_lazy("trace".to_string(), trace_pipe::kernel_inode_provider)?;
+
+    tracing_root.add_file(
+        "trace_pipe".to_string(),
+        ModeType::from_bits_truncate(0o444),
+        Some(4096),
+        None,
+        Some(&trace_pipe::TracePipeCallBack),
+    )?;
+
+    events::init_events(events_root)?;
+
+    unsafe {
+        TRACING_ROOT_INODE = Some(tracing_root);
+    }
+    Ok(())
 }

+ 107 - 76
kernel/src/debug/tracing/trace_pipe.rs

@@ -1,98 +1,111 @@
-use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback};
+use crate::filesystem::kernfs::callback::{KernCallbackData, KernFSCallback, KernInodePrivateData};
+use crate::filesystem::kernfs::{KernFSInodeArgs, KernInodeType};
+use crate::filesystem::vfs::syscall::ModeType;
 use crate::filesystem::vfs::PollStatus;
-use crate::libs::spinlock::SpinLock;
-use alloc::string::String;
-use alloc::vec::Vec;
+use crate::libs::wait_queue::WaitQueue;
+use crate::process::{ProcessFlags, ProcessManager};
+use crate::sched::SchedMode;
+use crate::tracepoint::{TraceEntryParser, TracePipeOps};
 use core::fmt::Debug;
 use system_error::SystemError;
 
-static mut TRACE_PIPE: Option<TracePipe> = None;
-
-pub const TRACE_PIPE_MAX_RECORD: usize = 4096;
-
-pub fn init_trace_pipe() {
-    unsafe {
-        TRACE_PIPE = Some(TracePipe::new(TRACE_PIPE_MAX_RECORD));
+fn common_trace_pipe_read(
+    trace_buf: &mut dyn TracePipeOps,
+    buf: &mut [u8],
+) -> Result<usize, SystemError> {
+    let manager = super::events::tracing_events_manager();
+    let tracepint_map = manager.tracepoint_map();
+    let trace_cmdline_cache = super::TRACE_CMDLINE_CACHE.lock();
+    // read real trace data
+    let mut copy_len = 0;
+    let mut peek_flag = false;
+    loop {
+        if let Some(record) = trace_buf.peek() {
+            let record_str = TraceEntryParser::parse(&tracepint_map, &trace_cmdline_cache, record);
+            if copy_len + record_str.len() > buf.len() {
+                break; // Buffer is full
+            }
+            let len = record_str.len();
+            buf[copy_len..copy_len + len].copy_from_slice(record_str.as_bytes());
+            copy_len += len;
+            peek_flag = true;
+        }
+        if peek_flag {
+            trace_buf.pop(); // Remove the record after reading
+            peek_flag = false;
+        } else {
+            break; // No more records to read
+        }
     }
+    Ok(copy_len)
 }
 
-pub fn trace_pipe() -> &'static TracePipe {
-    unsafe { TRACE_PIPE.as_ref().unwrap() }
-}
-
-/// Push a record to trace pipe
-pub fn trace_pipe_push_record(record: String) {
-    trace_pipe().push_record(record);
-}
-
-pub struct TracePipe {
-    buf: SpinLock<TracePipeBuf>,
-}
-
-struct TracePipeBuf {
-    size: usize,
-    max_record: usize,
-    buf: Vec<String>,
-}
+#[derive(Debug)]
+pub struct TraceCallBack;
 
-impl TracePipeBuf {
-    pub const fn new(max_record: usize) -> Self {
-        Self {
-            max_record,
-            size: 0,
-            buf: Vec::new(),
-        }
+impl KernFSCallback for TraceCallBack {
+    fn open(&self, mut data: KernCallbackData) -> Result<(), SystemError> {
+        let pri_data = data.private_data_mut();
+        let snapshot = super::TRACE_RAW_PIPE.lock().snapshot();
+        pri_data.replace(KernInodePrivateData::TracePipe(snapshot));
+        Ok(())
     }
 
-    pub fn push_str(&mut self, record: String) {
-        let record_size = record.len();
-        if self.size + record_size > self.max_record {
-            let mut i = 0;
-            while i < record_size {
-                let t = self.buf.pop().unwrap();
-                self.size -= t.len();
-                i += t.len();
-            }
+    fn read(
+        &self,
+        mut data: KernCallbackData,
+        buf: &mut [u8],
+        offset: usize,
+    ) -> Result<usize, SystemError> {
+        let pri_data = data.private_data_mut().as_mut().unwrap();
+        let snapshot = pri_data.tracepipe().unwrap();
+
+        let default_fmt_str = snapshot.default_fmt_str();
+        if offset >= default_fmt_str.len() {
+            common_trace_pipe_read(snapshot, buf)
+        } else {
+            let len = buf.len().min(default_fmt_str.len() - offset);
+            buf[..len].copy_from_slice(&default_fmt_str.as_bytes()[offset..offset + len]);
+            Ok(len)
         }
-        self.buf.push(record);
-        self.size += record_size;
     }
 
-    pub fn read_at(&self, buf: &mut [u8], offset: usize) -> Result<usize, SystemError> {
-        if offset == self.size {
-            return Ok(0);
-        }
-        if buf.len() < self.size {
-            return Err(SystemError::EINVAL);
-        }
-        let mut count = 0;
-        for line in self.buf.iter() {
-            let line = line.as_bytes();
-            buf[count..count + line.len()].copy_from_slice(line);
-            count += line.len();
-        }
-        Ok(count)
+    fn write(
+        &self,
+        _data: KernCallbackData,
+        _buf: &[u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        Err(SystemError::EPERM)
     }
-}
 
-impl TracePipe {
-    pub const fn new(max_record: usize) -> Self {
-        Self {
-            buf: SpinLock::new(TracePipeBuf::new(max_record)),
-        }
-    }
-    pub fn push_record(&self, record: String) {
-        self.buf.lock().push_str(record);
+    fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
+        Ok(PollStatus::READ)
     }
+}
 
-    pub fn read_at(&self, buf: &mut [u8], offset: usize) -> Result<usize, SystemError> {
-        self.buf.lock().read_at(buf, offset)
+pub fn kernel_inode_provider() -> KernFSInodeArgs {
+    KernFSInodeArgs {
+        mode: ModeType::from_bits_truncate(0o444),
+        callback: Some(&TraceCallBack),
+        inode_type: KernInodeType::File,
+        size: Some(4096),
+        private_data: None,
     }
 }
 
+static TracePipeCallBackWaitQueue: WaitQueue = WaitQueue::default();
+
 #[derive(Debug)]
 pub struct TracePipeCallBack;
 
+impl TracePipeCallBack {
+    fn readable(&self) -> bool {
+        let trace_raw_pipe = super::TRACE_RAW_PIPE.lock();
+        !trace_raw_pipe.is_empty()
+    }
+}
+
 impl KernFSCallback for TracePipeCallBack {
     fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
         Ok(())
@@ -100,12 +113,30 @@ impl KernFSCallback for TracePipeCallBack {
 
     fn read(
         &self,
-        _data: KernCallbackData,
+        data: KernCallbackData,
         buf: &mut [u8],
-        offset: usize,
+        _offset: usize,
     ) -> Result<usize, SystemError> {
-        let trace_pipe = trace_pipe();
-        trace_pipe.read_at(buf, offset)
+        drop(data); // We don't need the data here, release the internal lock
+        let read_len = loop {
+            let mut trace_raw_pipe = super::TRACE_RAW_PIPE.lock();
+            let read_len = common_trace_pipe_read(&mut *trace_raw_pipe, buf).unwrap();
+            if read_len != 0 {
+                break read_len;
+            }
+            // Release the lock before waiting
+            drop(trace_raw_pipe);
+            // wait for new data
+            let r = wq_wait_event_interruptible!(TracePipeCallBackWaitQueue, self.readable(), {});
+            if r.is_err() {
+                ProcessManager::current_pcb()
+                    .flags()
+                    .insert(ProcessFlags::HAS_PENDING_SIGNAL);
+                return Err(SystemError::ERESTARTSYS);
+            }
+            // todo!(wq_wait_event_interruptible may has a bug)
+        };
+        Ok(read_len)
     }
 
     fn write(

+ 0 - 187
kernel/src/debug/tracing/tracepoint.rs

@@ -1,187 +0,0 @@
-use crate::libs::spinlock::{SpinLock, SpinLockGuard};
-use alloc::boxed::Box;
-use alloc::collections::BTreeMap;
-use core::any::Any;
-use core::fmt::Debug;
-use static_keys::StaticFalseKey;
-
-pub struct TracePoint {
-    name: &'static str,
-    module_path: &'static str,
-    key: &'static StaticFalseKey,
-    register: Option<fn()>,
-    unregister: Option<fn()>,
-    callback: SpinLock<BTreeMap<usize, TracePointFunc>>,
-}
-
-impl Debug for TracePoint {
-    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        f.debug_struct("TracePoint")
-            .field("name", &self.name)
-            .finish()
-    }
-}
-
-#[derive(Debug)]
-#[repr(C)]
-pub struct CommonTracePointMeta {
-    pub trace_point: &'static TracePoint,
-    pub print_func: fn(),
-}
-
-#[derive(Debug)]
-pub struct TracePointFunc {
-    pub func: fn(),
-    pub data: Box<dyn Any + Send + Sync>,
-}
-
-impl TracePoint {
-    pub const fn new(
-        key: &'static StaticFalseKey,
-        name: &'static str,
-        module_path: &'static str,
-        register: Option<fn()>,
-        unregister: Option<fn()>,
-    ) -> Self {
-        Self {
-            name,
-            module_path,
-            key,
-            register,
-            unregister,
-            callback: SpinLock::new(BTreeMap::new()),
-        }
-    }
-
-    pub fn name(&self) -> &'static str {
-        self.name
-    }
-
-    pub fn module_path(&self) -> &'static str {
-        self.module_path
-    }
-
-    /// Register a callback function to the tracepoint
-    pub fn register(&self, func: fn(), data: Box<dyn Any + Sync + Send>) {
-        let trace_point_func = TracePointFunc { func, data };
-        let mut funcs = self.callback.lock();
-        if let Some(register) = self.register {
-            register();
-        }
-        let ptr = func as usize;
-        funcs.entry(ptr).or_insert(trace_point_func);
-    }
-
-    /// Unregister a callback function from the tracepoint
-    pub fn unregister(&self, func: fn()) {
-        let mut funcs = self.callback.lock();
-        if let Some(unregister) = self.unregister {
-            unregister();
-        }
-        let func_ptr = func as usize;
-        funcs.remove(&func_ptr);
-    }
-
-    /// Get the callback list
-    pub fn callback_list(&self) -> SpinLockGuard<BTreeMap<usize, TracePointFunc>> {
-        self.callback.lock()
-    }
-
-    /// Enable the tracepoint
-    pub fn enable(&self) {
-        unsafe {
-            self.key.enable();
-        }
-    }
-
-    /// Disable the tracepoint
-    pub fn disable(&self) {
-        unsafe {
-            self.key.disable();
-        }
-    }
-
-    /// Check if the tracepoint is enabled
-    pub fn is_enabled(&self) -> bool {
-        self.key.is_enabled()
-    }
-}
-
-/// Define a tracepoint
-///
-/// User should call register_trace_\$name to register a callback function to the tracepoint and
-/// call trace_\$name to trigger the callback function
-#[macro_export]
-macro_rules! define_trace_point {
-    ($name:ident $(,$arg:ident:$arg_type:ty),*) => {
-        paste::paste!{
-            static_keys::define_static_key_false!([<__ $name _KEY>]);
-            #[allow(non_upper_case_globals)]
-            #[used]
-            static [<__ $name>]: $crate::debug::tracing::tracepoint::TracePoint = $crate::debug::tracing::tracepoint::TracePoint::new(&[<__ $name _KEY>],stringify!($name), module_path!(),None,None);
-
-            #[inline(always)]
-            #[allow(non_snake_case)]
-            pub fn [<TRACE_ $name>]( $($arg:$arg_type),* ){
-
-                if static_keys::static_branch_unlikely!([<__ $name _KEY>]){
-                    let mut funcs = [<__ $name>].callback_list();
-                    for trace_func in funcs.values_mut(){
-                        let func = trace_func.func;
-                        let data = trace_func.data.as_mut();
-                        let func = unsafe{core::mem::transmute::<fn(),fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*)>(func)};
-                        func(data $(,$arg)*);
-                    }
-                }
-
-            }
-
-            #[allow(unused,non_snake_case)]
-            pub fn [<register_trace_ $name>](func:fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),data:alloc::boxed::Box<dyn core::any::Any+Send+Sync>){
-                let func = unsafe{core::mem::transmute::<fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),fn()>(func)};
-                [<__ $name>].register(func,data);
-            }
-
-            #[allow(unused,non_snake_case)]
-            pub fn [<unregister_trace_ $name>](func:fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*)){
-                let func = unsafe{core::mem::transmute::<fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),fn()>(func)};
-                [<__ $name>].unregister(func);
-            }
-
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! define_event_trace{
-    ($name:ident,
-        ($($arg:ident:$arg_type:ty),*),
-        $fmt:expr) =>{
-        define_trace_point!($name $(,$arg:$arg_type),*);
-        paste::paste!{
-            #[derive(Debug)]
-            #[repr(C)]
-            #[allow(non_snake_case)]
-            #[allow(non_camel_case_types)]
-            struct [<__ $name _TracePointMeta>]{
-                trace_point: &'static $crate::debug::tracing::tracepoint::TracePoint,
-                print_func: fn(&mut (dyn core::any::Any+Send+Sync),$($arg_type),*),
-            }
-             #[allow(non_upper_case_globals)]
-             #[link_section = ".tracepoint"]
-             #[used]
-            static [<__ $name _meta>]: [<__ $name _TracePointMeta>] = [<__ $name _TracePointMeta>]{
-                trace_point:&[<__ $name>],
-                print_func:[<TRACE_PRINT_ $name>],
-            };
-            #[allow(non_snake_case)]
-            pub fn [<TRACE_PRINT_ $name>](_data:&mut (dyn core::any::Any+Send+Sync),$($arg:$arg_type),* ){
-                 let time = $crate::time::Instant::now();
-                 let cpu_id = $crate::arch::cpu::current_cpu_id().data();
-                 let current_pid = $crate::process::ProcessManager::current_pcb().pid().data();
-                 let format = format!("[{}][{}][{}] {}\n",time,cpu_id,current_pid,$fmt);
-                 $crate::debug::tracing::trace_pipe::trace_pipe_push_record(format);
-            }
-        }
-    };
-}

+ 3 - 2
kernel/src/filesystem/kernfs/callback.rs

@@ -1,5 +1,5 @@
 use super::KernFSInode;
-use crate::debug::tracing::tracepoint::TracePoint;
+use crate::tracepoint::{TracePipeSnapshot, TracePointInfo};
 use crate::{
     filesystem::{sysfs::SysFSKernPrivateData, vfs::PollStatus},
     libs::spinlock::SpinLockGuard,
@@ -86,7 +86,8 @@ impl<'a> KernCallbackData<'a> {
 #[derive(Debug)]
 pub enum KernInodePrivateData {
     SysFS(SysFSKernPrivateData),
-    DebugFS(&'static TracePoint),
+    DebugFS(Arc<TracePointInfo>),
+    TracePipe(TracePipeSnapshot),
 }
 
 impl KernInodePrivateData {

+ 51 - 8
kernel/src/filesystem/kernfs/mod.rs

@@ -1,3 +1,4 @@
+use alloc::string::ToString;
 use core::{cmp::min, fmt::Debug, intrinsics::unlikely};
 
 use alloc::{
@@ -115,6 +116,7 @@ impl KernFS {
             callback: None,
             children: SpinLock::new(HashMap::new()),
             inode_type: KernInodeType::Dir,
+            lazy_list: SpinLock::new(HashMap::new()),
         });
 
         return root_inode;
@@ -138,6 +140,16 @@ pub struct KernFSInode {
     inode_type: KernInodeType,
     /// Inode名称
     name: String,
+    /// lazy list
+    lazy_list: SpinLock<HashMap<String, fn() -> KernFSInodeArgs>>,
+}
+
+pub struct KernFSInodeArgs {
+    pub mode: ModeType,
+    pub inode_type: KernInodeType,
+    pub size: Option<usize>,
+    pub private_data: Option<KernInodePrivateData>,
+    pub callback: Option<&'static dyn KernFSCallback>,
 }
 
 #[derive(Debug)]
@@ -245,12 +257,25 @@ impl IndexNode for KernFSInode {
             }
             name => {
                 // 在子目录项中查找
-                return Ok(self
-                    .children
-                    .lock()
-                    .get(name)
-                    .ok_or(SystemError::ENOENT)?
-                    .clone());
+                let child = self.children.lock().get(name).cloned();
+                if let Some(child) = child {
+                    return Ok(child);
+                }
+                let lazy_list = self.lazy_list.lock();
+                if let Some(provider) = lazy_list.get(name) {
+                    // 如果存在lazy list,则调用提供者函数创建
+                    let args = provider();
+                    let inode = self.inner_create(
+                        name.to_string(),
+                        args.inode_type,
+                        args.mode,
+                        args.size.unwrap_or(4096),
+                        args.private_data,
+                        args.callback,
+                    )?;
+                    return Ok(inode);
+                }
+                Err(SystemError::ENOENT)
             }
         }
     }
@@ -321,7 +346,7 @@ impl IndexNode for KernFSInode {
         offset: usize,
         len: usize,
         buf: &mut [u8],
-        _data: SpinLockGuard<FilePrivateData>,
+        data: SpinLockGuard<FilePrivateData>,
     ) -> Result<usize, SystemError> {
         if self.inode_type == KernInodeType::SymLink {
             let inner = self.inner.read();
@@ -350,6 +375,8 @@ impl IndexNode for KernFSInode {
             warn!("kernfs: callback is none");
             return Err(SystemError::ENOSYS);
         }
+        // release the private data lock before calling the callback
+        drop(data);
 
         let callback_data =
             KernCallbackData::new(self.self_ref.upgrade().unwrap(), self.private_data.lock());
@@ -365,7 +392,7 @@ impl IndexNode for KernFSInode {
         offset: usize,
         len: usize,
         buf: &[u8],
-        _data: SpinLockGuard<FilePrivateData>,
+        data: SpinLockGuard<FilePrivateData>,
     ) -> Result<usize, SystemError> {
         if self.inode_type != KernInodeType::File {
             return Err(SystemError::EISDIR);
@@ -375,6 +402,9 @@ impl IndexNode for KernFSInode {
             return Err(SystemError::ENOSYS);
         }
 
+        // release the private data lock before calling the callback
+        drop(data);
+
         let callback_data =
             KernCallbackData::new(self.self_ref.upgrade().unwrap(), self.private_data.lock());
         return self
@@ -411,6 +441,7 @@ impl KernFSInode {
             callback,
             children: SpinLock::new(HashMap::new()),
             inode_type,
+            lazy_list: SpinLock::new(HashMap::new()),
         });
 
         {
@@ -500,6 +531,18 @@ impl KernFSInode {
         );
     }
 
+    pub fn add_file_lazy(
+        &self,
+        name: String,
+        provider: fn() -> KernFSInodeArgs,
+    ) -> Result<(), SystemError> {
+        if unlikely(self.inode_type != KernInodeType::Dir) {
+            return Err(SystemError::ENOTDIR);
+        }
+        self.lazy_list.lock().insert(name, provider);
+        Ok(())
+    }
+
     fn inner_create(
         &self,
         name: String,

+ 28 - 4
kernel/src/filesystem/vfs/vcore.rs

@@ -5,7 +5,7 @@ use log::{error, info};
 use system_error::SystemError;
 
 use crate::{
-    define_event_trace, define_trace_point,
+    define_event_trace,
     driver::base::block::{gendisk::GenDisk, manager::block_dev_manager},
     filesystem::{
         devfs::devfs_init,
@@ -167,15 +167,39 @@ pub fn mount_root_fs() -> Result<(), SystemError> {
     return Ok(());
 }
 
-define_event_trace!(DO_MKDIR_AT,(path:&str,mode:FileMode),
-    format_args!("mkdir at {} with mode {:?}",path, mode));
+define_event_trace!(
+    do_mkdir_at,
+    TP_system(vfs),
+    TP_PROTO(path:&str, mode: FileMode),
+    TP_STRUCT__entry {
+        fmode: FileMode,
+        path: [u8;64],
+    },
+    TP_fast_assign {
+        fmode: mode,
+        path: {
+            let mut buf = [0u8; 64];
+            let path = path.as_bytes();
+            let len = path.len().min(63);
+            buf[..len].copy_from_slice(&path[..len]);
+            buf[len] = 0; // null-terminate
+            buf
+        },
+    },
+    TP_ident(__entry),
+    TP_printk({
+        let path = core::str::from_utf8(&__entry.path).unwrap_or("invalid utf8");
+        let mode = __entry.fmode;
+        format!("mkdir at {} with mode {:?}", path, mode)
+    })
+);
 /// @brief 创建文件/文件夹
 pub fn do_mkdir_at(
     dirfd: i32,
     path: &str,
     mode: FileMode,
 ) -> Result<Arc<dyn IndexNode>, SystemError> {
-    TRACE_DO_MKDIR_AT(path, mode);
+    trace_do_mkdir_at(path, mode);
     // debug!("Call do mkdir at");
     let (mut current_inode, path) =
         user_path_at(&ProcessManager::current_pcb(), dirfd, path.trim())?;

+ 7 - 1
kernel/src/lib.rs

@@ -23,7 +23,12 @@
 #![feature(vec_into_raw_parts)]
 #![feature(linkage)]
 #![feature(panic_can_unwind)]
-#![allow(static_mut_refs, non_local_definitions, internal_features)]
+#![allow(
+    static_mut_refs,
+    non_local_definitions,
+    internal_features,
+    non_upper_case_globals
+)]
 // clippy的配置
 #![deny(clippy::all)]
 // 取消下面的注释以启用clippy对栈帧大小的检查
@@ -70,6 +75,7 @@ mod sched;
 mod smp;
 mod syscall;
 mod time;
+mod tracepoint;
 #[cfg(target_arch = "x86_64")]
 mod virt;
 

+ 175 - 0
kernel/src/tracepoint/basic_macro.rs

@@ -0,0 +1,175 @@
+/// Define a tracepoint with the given parameters.
+///
+/// This macro generates a tracepoint with the specified name, arguments, entry structure, assignment logic, identifier, and print format.
+/// # Parameters
+/// - `name`: The name of the tracepoint.
+/// - `TP_system`: The subsystem or system to which the tracepoint belongs.
+/// - `TP_PROTO`: The prototype of the tracepoint function.
+/// - `TP_STRUCT__entry`: The structure of the tracepoint entry.
+/// - `TP_fast_assign`: The assignment logic for the tracepoint entry.
+/// - `TP_ident`: The identifier for the tracepoint entry.
+/// - `TP_printk`: The print format for the tracepoint.
+///
+/// # Example
+/// ```rust
+/// define_event_trace!(
+///     TEST2,
+///     TP_PROTO(a: u32, b: u32),
+///     TP_STRUCT__entry{
+///           a: u32,
+///           b: u32,
+///     },
+///     TP_fast_assign{
+///           a:a,
+///           b:{
+///             // do something with b
+///             b
+///           }
+///     },
+///     TP_ident(__entry),
+///     TP_printk({
+///           // do something with __entry
+///           format!("Hello from tracepoint! a={}, b={}", __entry.a, __entry.b)
+///     })
+/// );
+/// ```
+#[macro_export]
+macro_rules! define_event_trace{
+    (
+        $name:ident,
+        TP_system($system:ident),
+        TP_PROTO($($arg:ident:$arg_type:ty),*),
+        TP_STRUCT__entry{$($entry:ident:$entry_type:ty,)*},
+        TP_fast_assign{$($assign:ident:$value:expr,)*},
+        TP_ident($tp_ident:ident),
+        TP_printk($fmt_expr: expr)
+    ) => {
+        paste::paste!{
+            static_keys::define_static_key_false!([<__ $name _KEY>]);
+            #[allow(non_upper_case_globals)]
+            #[used]
+            static [<__ $name>]: $crate::tracepoint::TracePoint = $crate::tracepoint::TracePoint::new(&[<__ $name _KEY>],stringify!($name), stringify!($system),[<trace_fmt_ $name>], [<trace_fmt_show $name>]);
+
+            #[inline(always)]
+            #[allow(non_snake_case)]
+            pub fn [<trace_ $name>]( $($arg:$arg_type),* ){
+                if static_keys::static_branch_unlikely!([<__ $name _KEY>]){
+                    let mut f = |trace_func: &$crate::tracepoint::TracePointFunc |{
+                        let func = trace_func.func;
+                        let data = trace_func.data.as_ref();
+                        let func = unsafe{core::mem::transmute::<fn(),fn(& (dyn core::any::Any+Send+Sync), $($arg_type),*)>(func)};
+                        func(data $(,$arg)*);
+                    };
+                    let trace_point = &[<__ $name>];
+                    trace_point.callback_list(&mut f);
+                }
+            }
+            #[allow(unused,non_snake_case)]
+            pub fn [<register_trace_ $name>](func: fn(& (dyn core::any::Any+Send+Sync), $($arg_type),*), data: alloc::boxed::Box<dyn core::any::Any+Send+Sync>){
+                let func = unsafe{core::mem::transmute::<fn(& (dyn core::any::Any+Send+Sync), $($arg_type),*), fn()>(func)};
+                [<__ $name>].register(func,data);
+            }
+            #[allow(unused,non_snake_case)]
+            pub fn [<unregister_trace_ $name>](func: fn(& (dyn core::any::Any+Send+Sync), $($arg_type),*)){
+                let func = unsafe{core::mem::transmute::<fn(& (dyn core::any::Any+Send+Sync), $($arg_type),*), fn()>(func)};
+                [<__ $name>].unregister(func);
+            }
+
+
+            #[derive(Debug)]
+            #[repr(C)]
+            #[allow(non_snake_case,non_camel_case_types)]
+            struct [<__ $name _TracePointMeta>]{
+                trace_point: &'static $crate::tracepoint::TracePoint,
+                print_func: fn(&mut (dyn core::any::Any+Send+Sync), $($arg_type),*),
+            }
+
+            #[allow(non_upper_case_globals)]
+            #[link_section = ".tracepoint"]
+            #[used]
+            static [<__ $name _meta>]: [<__ $name _TracePointMeta>] = [<__ $name _TracePointMeta>]{
+                trace_point:& [<__ $name>],
+                print_func:[<trace_default_ $name>],
+            };
+
+            #[allow(unused,non_snake_case)]
+            pub fn [<trace_default_ $name>](_data:&mut (dyn core::any::Any+Send+Sync), $($arg:$arg_type),* ){
+                #[repr(C)]
+                struct Entry {
+                    $($entry: $entry_type,)*
+                }
+                #[repr(C)]
+                struct FullEntry {
+                    common: $crate::tracepoint::TraceEntry,
+                    entry: Entry,
+                }
+
+                let entry = Entry {
+                    $($assign: $value,)*
+                };
+
+                let process = $crate::process::ProcessManager::current_pcb();
+                let pid = process.pid().data() as _;
+
+                let common = $crate::tracepoint::TraceEntry {
+                    type_: [<__ $name>].id() as _,
+                    flags: [<__ $name>].flags(),
+                    preempt_count: 0,
+                    pid,
+                };
+
+                let full_entry = FullEntry {
+                    common,
+                    entry,
+                };
+
+                let event_buf = unsafe {
+                    core::slice::from_raw_parts(
+                        &full_entry as *const FullEntry as *const u8,
+                        core::mem::size_of::<FullEntry>(),
+                    )
+                };
+                $crate::debug::tracing::trace_cmdline_push(pid as u32);
+                $crate::debug::tracing::trace_pipe_push_raw_record(event_buf);
+            }
+
+            #[allow(unused,non_snake_case)]
+            pub fn [<trace_fmt_ $name>](buf_ptr: *const u8) -> alloc::string::String {
+                #[repr(C)]
+                struct Entry {
+                    $($entry: $entry_type,)*
+                }
+                let $tp_ident = unsafe {
+                    &*(buf_ptr as *const Entry)
+                };
+                let fmt = format!("{}", $fmt_expr);
+                fmt
+            }
+
+            #[allow(unused,non_snake_case)]
+            pub fn [<trace_fmt_show $name>]()-> alloc::string::String {
+                let mut fmt = format!("format:
+\tfield: u16 common_type; offset: 0; size: 2; signed: 0;
+\tfield: u8 common_flags; offset: 2; size: 1; signed: 0;
+\tfield: u8 common_preempt_count; offset: 3; size: 1; signed: 0;
+\tfield: i32 common_pid; offset: 4; size: 4; signed: 1;
+
+");
+                fn is_signed<T>() -> bool {
+                    match core::any::type_name::<T>() {
+                        "i8" | "i16" | "i32" | "i64" | "i128" | "isize" => true,
+                        _ => false,
+                    }
+                }
+                let mut offset = 8;
+                $(
+                    fmt.push_str(&format!("\tfield: {} {} offset: {}; size: {}; signed: {};\n",
+                        stringify!($entry_type), stringify!($entry), offset, core::mem::size_of::<$entry_type>(), if is_signed::<$entry_type>() { 1 } else { 0 }));
+                    offset += core::mem::size_of::<$entry_type>();
+                )*
+                fmt.push_str(&format!("\nprint fmt: \"{}\"", stringify!($fmt_expr)));
+                fmt
+            }
+        }
+    };
+}

+ 293 - 0
kernel/src/tracepoint/mod.rs

@@ -0,0 +1,293 @@
+#![allow(clippy::new_without_default)]
+
+mod basic_macro;
+mod point;
+mod trace_pipe;
+
+use alloc::{
+    boxed::Box,
+    collections::BTreeMap,
+    string::{String, ToString},
+    sync::Arc,
+    vec::Vec,
+};
+use core::{
+    ops::{Deref, DerefMut},
+    sync::atomic::AtomicUsize,
+};
+pub use point::{CommonTracePointMeta, TraceEntry, TracePoint, TracePointFunc};
+use system_error::SystemError;
+pub use trace_pipe::{
+    TraceCmdLineCache, TraceEntryParser, TracePipeOps, TracePipeRaw, TracePipeSnapshot,
+};
+
+use crate::libs::spinlock::{SpinLock, SpinLockGuard};
+
+#[derive(Debug)]
+pub struct TracePointMap(BTreeMap<u32, &'static TracePoint>);
+
+impl TracePointMap {
+    /// Create a new TracePointMap
+    fn new() -> Self {
+        Self(BTreeMap::new())
+    }
+}
+
+impl Deref for TracePointMap {
+    type Target = BTreeMap<u32, &'static TracePoint>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl DerefMut for TracePointMap {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+#[derive(Debug)]
+pub struct TracingEventsManager {
+    subsystems: SpinLock<BTreeMap<String, Arc<EventsSubsystem>>>,
+    map: SpinLock<TracePointMap>,
+}
+
+impl TracingEventsManager {
+    fn new(map: TracePointMap) -> Self {
+        Self {
+            subsystems: SpinLock::new(BTreeMap::new()),
+            map: SpinLock::new(map),
+        }
+    }
+
+    /// Get the tracepoint map
+    pub fn tracepoint_map(&self) -> SpinLockGuard<TracePointMap> {
+        self.map.lock()
+    }
+
+    /// Create a subsystem by name
+    ///
+    /// If the subsystem already exists, return the existing subsystem.
+    fn create_subsystem(&self, subsystem_name: &str) -> Arc<EventsSubsystem> {
+        if self.subsystems.lock().contains_key(subsystem_name) {
+            return self
+                .get_subsystem(subsystem_name)
+                .expect("Subsystem should exist");
+        }
+        let subsystem = Arc::new(EventsSubsystem::new());
+        self.subsystems
+            .lock()
+            .insert(subsystem_name.to_string(), subsystem.clone());
+        subsystem
+    }
+
+    /// Get the subsystem by name
+    pub fn get_subsystem(&self, subsystem_name: &str) -> Option<Arc<EventsSubsystem>> {
+        self.subsystems.lock().get(subsystem_name).cloned()
+    }
+
+    #[allow(unused)]
+    /// Remove the subsystem by name
+    pub fn remove_subsystem(&self, subsystem_name: &str) -> Option<Arc<EventsSubsystem>> {
+        self.subsystems.lock().remove(subsystem_name)
+    }
+
+    /// Get all subsystems
+    pub fn subsystem_names(&self) -> Vec<String> {
+        let res = self
+            .subsystems
+            .lock()
+            .keys()
+            .cloned()
+            .collect::<Vec<String>>();
+        res
+    }
+}
+
+#[derive(Debug)]
+pub struct EventsSubsystem {
+    events: SpinLock<BTreeMap<String, Arc<TracePointInfo>>>,
+}
+
+impl EventsSubsystem {
+    fn new() -> Self {
+        Self {
+            events: SpinLock::new(BTreeMap::new()),
+        }
+    }
+
+    /// Create an event by name
+    fn create_event(&self, event_name: &str, event_info: TracePointInfo) {
+        self.events
+            .lock()
+            .insert(event_name.to_string(), Arc::new(event_info));
+    }
+
+    /// Get the event by name
+    pub fn get_event(&self, event_name: &str) -> Option<Arc<TracePointInfo>> {
+        self.events.lock().get(event_name).cloned()
+    }
+
+    /// Get all events in the subsystem
+    pub fn event_names(&self) -> Vec<String> {
+        let res = self.events.lock().keys().cloned().collect::<Vec<String>>();
+        res
+    }
+}
+#[derive(Debug)]
+pub struct TracePointInfo {
+    enable: TracePointEnableFile,
+    tracepoint: &'static TracePoint,
+    format: TracePointFormatFile,
+    id: TracePointIdFile,
+    // filter:,
+    // trigger:,
+}
+
+impl TracePointInfo {
+    fn new(tracepoint: &'static TracePoint) -> Self {
+        let enable = TracePointEnableFile::new(tracepoint);
+        let format = TracePointFormatFile::new(tracepoint);
+        let id = TracePointIdFile::new(tracepoint);
+        Self {
+            enable,
+            tracepoint,
+            format,
+            id,
+        }
+    }
+
+    /// Get the tracepoint
+    pub fn tracepoint(&self) -> &'static TracePoint {
+        self.tracepoint
+    }
+
+    /// Get the enable file
+    pub fn enable_file(&self) -> &TracePointEnableFile {
+        &self.enable
+    }
+
+    /// Get the format file
+    pub fn format_file(&self) -> &TracePointFormatFile {
+        &self.format
+    }
+
+    /// Get the ID file
+    pub fn id_file(&self) -> &TracePointIdFile {
+        &self.id
+    }
+}
+
+/// TracePointFormatFile provides a way to get the format of the tracepoint.
+#[derive(Debug, Clone)]
+pub struct TracePointFormatFile {
+    tracepoint: &'static TracePoint,
+}
+
+impl TracePointFormatFile {
+    fn new(tracepoint: &'static TracePoint) -> Self {
+        Self { tracepoint }
+    }
+
+    /// Read the tracepoint format
+    ///
+    /// Returns the format string of the tracepoint.
+    pub fn read(&self) -> String {
+        self.tracepoint.print_fmt()
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct TracePointEnableFile {
+    tracepoint: &'static TracePoint,
+}
+
+impl TracePointEnableFile {
+    fn new(tracepoint: &'static TracePoint) -> Self {
+        Self { tracepoint }
+    }
+
+    /// Read the tracepoint status
+    ///
+    /// Returns true if the tracepoint is enabled, false otherwise.
+    pub fn read(&self) -> &'static str {
+        if self.tracepoint.is_enabled() {
+            "1\n"
+        } else {
+            "0\n"
+        }
+    }
+    /// Enable or disable the tracepoint
+    pub fn write(&self, enable: char) {
+        match enable {
+            '1' => self.tracepoint.enable(),
+            '0' => self.tracepoint.disable(),
+            _ => {
+                log::warn!("Invalid value for tracepoint enable: {}", enable);
+            }
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct TracePointIdFile {
+    tracepoint: &'static TracePoint,
+}
+
+impl TracePointIdFile {
+    fn new(tracepoint: &'static TracePoint) -> Self {
+        Self { tracepoint }
+    }
+
+    /// Read the tracepoint ID
+    ///
+    /// Returns the ID of the tracepoint.
+    pub fn read(&self) -> String {
+        format!("{}\n", self.tracepoint.id())
+    }
+}
+
+extern "C" {
+    fn _tracepoint();
+    fn _etracepoint();
+}
+
+/// Initialize the tracing events
+pub fn global_init_events() -> Result<TracingEventsManager, SystemError> {
+    static TRACE_POINT_ID: AtomicUsize = AtomicUsize::new(0);
+    let events_manager = TracingEventsManager::new(TracePointMap::new());
+    let tracepoint_data_start = _tracepoint as usize as *mut CommonTracePointMeta;
+    let tracepoint_data_end = _etracepoint as usize as *mut CommonTracePointMeta;
+    log::info!(
+        "tracepoint_data_start: {:#x}, tracepoint_data_end: {:#x}",
+        tracepoint_data_start as usize,
+        tracepoint_data_end as usize
+    );
+    let tracepoint_data_len = (tracepoint_data_end as usize - tracepoint_data_start as usize)
+        / size_of::<CommonTracePointMeta>();
+    let tracepoint_data =
+        unsafe { core::slice::from_raw_parts_mut(tracepoint_data_start, tracepoint_data_len) };
+
+    log::info!("tracepoint_data_len: {}", tracepoint_data_len);
+
+    let mut tracepoint_map = events_manager.tracepoint_map();
+    for tracepoint_meta in tracepoint_data {
+        let tracepoint = tracepoint_meta.trace_point;
+        let id = TRACE_POINT_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
+        tracepoint.set_id(id as u32);
+        tracepoint.register(tracepoint_meta.print_func, Box::new(()));
+        tracepoint_map.insert(id as u32, tracepoint);
+        log::info!(
+            "tracepoint registered: {}:{}",
+            tracepoint.system(),
+            tracepoint.name(),
+        );
+        let subsys_name = tracepoint.system();
+        let subsys = events_manager.create_subsystem(subsys_name);
+        let event_info = TracePointInfo::new(tracepoint);
+        subsys.create_event(tracepoint.name(), event_info);
+    }
+    drop(tracepoint_map); // Release the lock on the tracepoint map
+    Ok(events_manager)
+}

+ 179 - 0
kernel/src/tracepoint/point.rs

@@ -0,0 +1,179 @@
+use crate::libs::spinlock::SpinLock;
+use alloc::{boxed::Box, collections::BTreeMap, format, string::String};
+use core::{any::Any, sync::atomic::AtomicU32};
+use static_keys::StaticFalseKey;
+
+#[derive(Debug)]
+#[repr(C)]
+pub struct TraceEntry {
+    pub type_: u16,
+    pub flags: u8,
+    pub preempt_count: u8,
+    pub pid: i32,
+}
+
+impl TraceEntry {
+    pub fn trace_print_lat_fmt(&self) -> String {
+        // todo!("Implement IRQs off logic");
+        let irqs_off = '.';
+        let resched = '.';
+        let hardsoft_irq = '.';
+        let mut preempt_low = '.';
+        if self.preempt_count & 0xf != 0 {
+            preempt_low = ((b'0') + (self.preempt_count & 0xf)) as char;
+        }
+        let mut preempt_high = '.';
+        if self.preempt_count >> 4 != 0 {
+            preempt_high = ((b'0') + (self.preempt_count >> 4)) as char;
+        }
+        format!(
+            "{}{}{}{}{}",
+            irqs_off, resched, hardsoft_irq, preempt_low, preempt_high
+        )
+    }
+}
+
+pub struct TracePoint {
+    name: &'static str,
+    system: &'static str,
+    key: &'static StaticFalseKey,
+    id: AtomicU32,
+    inner: SpinLock<TracePointInner>,
+    trace_entry_fmt_func: fn(*const u8) -> String,
+    trace_print_func: fn() -> String,
+    flags: u8,
+}
+
+struct TracePointInner {
+    callback: BTreeMap<usize, TracePointFunc>,
+}
+
+impl core::fmt::Debug for TracePoint {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("TracePoint")
+            .field("name", &self.name)
+            .field("system", &self.system)
+            .field("id", &self.id())
+            .field("flags", &self.flags)
+            .finish()
+    }
+}
+
+#[derive(Debug)]
+#[repr(C)]
+pub struct CommonTracePointMeta {
+    pub trace_point: &'static TracePoint,
+    pub print_func: fn(),
+}
+
+#[derive(Debug)]
+pub struct TracePointFunc {
+    pub func: fn(),
+    pub data: Box<dyn Any + Send + Sync>,
+}
+
+impl TracePoint {
+    pub const fn new(
+        key: &'static StaticFalseKey,
+        name: &'static str,
+        system: &'static str,
+        fmt_func: fn(*const u8) -> String,
+        trace_print_func: fn() -> String,
+    ) -> Self {
+        Self {
+            name,
+            system,
+            key,
+            id: AtomicU32::new(0),
+            flags: 0,
+            trace_entry_fmt_func: fmt_func,
+            trace_print_func,
+            inner: SpinLock::new(TracePointInner {
+                callback: BTreeMap::new(),
+            }),
+        }
+    }
+
+    /// Returns the name of the tracepoint.
+    pub fn name(&self) -> &'static str {
+        self.name
+    }
+
+    /// Returns the system of the tracepoint.
+    pub fn system(&self) -> &'static str {
+        self.system
+    }
+
+    /// Sets the ID of the tracepoint.
+    pub(crate) fn set_id(&self, id: u32) {
+        self.id.store(id, core::sync::atomic::Ordering::Relaxed);
+    }
+
+    /// Returns the ID of the tracepoint.
+    pub fn id(&self) -> u32 {
+        self.id.load(core::sync::atomic::Ordering::Relaxed)
+    }
+
+    /// Returns the flags of the tracepoint.
+    pub fn flags(&self) -> u8 {
+        self.flags
+    }
+
+    /// Returns the format function for the tracepoint.
+    pub(crate) fn fmt_func(&self) -> fn(*const u8) -> String {
+        self.trace_entry_fmt_func
+    }
+
+    /// Returns a string representation of the format function for the tracepoint.
+    ///
+    /// You can use `cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_openat/format` in linux
+    /// to see the format of the tracepoint.
+    pub fn print_fmt(&self) -> String {
+        let post_str = (self.trace_print_func)();
+        format!("name: {}\nID: {}\n{}\n", self.name(), self.id(), post_str)
+    }
+
+    /// Register a callback function to the tracepoint
+    pub fn register(&self, func: fn(), data: Box<dyn Any + Sync + Send>) {
+        let trace_point_func = TracePointFunc { func, data };
+        let ptr = func as usize;
+        self.inner
+            .lock()
+            .callback
+            .entry(ptr)
+            .or_insert(trace_point_func);
+    }
+
+    /// Unregister a callback function from the tracepoint
+    pub fn unregister(&self, func: fn()) {
+        let func_ptr = func as usize;
+        self.inner.lock().callback.remove(&func_ptr);
+    }
+
+    /// Iterate over all registered callback functions
+    pub fn callback_list(&self, f: &dyn Fn(&TracePointFunc)) {
+        let inner = self.inner.lock();
+        for trace_func in inner.callback.values() {
+            f(trace_func);
+        }
+    }
+
+    /// Enable the tracepoint
+    pub fn enable(&self) {
+        unsafe {
+            self.key.enable();
+        }
+    }
+
+    /// Disable the tracepoint
+    pub fn disable(&self) {
+        unsafe {
+            self.key.disable();
+        }
+    }
+
+    /// Check if the tracepoint is enabled
+    pub fn is_enabled(&self) -> bool {
+        self.key.is_enabled()
+    }
+}

+ 221 - 0
kernel/src/tracepoint/trace_pipe.rs

@@ -0,0 +1,221 @@
+use crate::tracepoint::{TraceEntry, TracePointMap};
+use alloc::{format, string::String, vec::Vec};
+
+pub trait TracePipeOps {
+    /// Returns the first event in the trace pipe buffer without removing it.
+    fn peek(&self) -> Option<&Vec<u8>>;
+
+    /// Remove and return the first event in the trace pipe buffer.
+    fn pop(&mut self) -> Option<Vec<u8>>;
+
+    /// Whether the trace pipe buffer is empty.
+    fn is_empty(&self) -> bool;
+}
+
+/// A raw trace pipe buffer that stores trace events as byte vectors.
+pub struct TracePipeRaw {
+    max_record: usize,
+    event_buf: Vec<Vec<u8>>,
+}
+
+impl TracePipeRaw {
+    pub const fn new(max_record: usize) -> Self {
+        Self {
+            max_record,
+            event_buf: Vec::new(),
+        }
+    }
+
+    /// Set the maximum number of records to keep in the trace pipe buffer.
+    ///
+    /// If the current number of records exceeds this limit, the oldest records will be removed.
+    pub fn set_max_record(&mut self, max_record: usize) {
+        self.max_record = max_record;
+        if self.event_buf.len() > max_record {
+            self.event_buf.truncate(max_record); // Keep only the latest records
+        }
+    }
+
+    /// Push a new event into the trace pipe buffer.
+    pub fn push_event(&mut self, event: Vec<u8>) {
+        if self.event_buf.len() >= self.max_record {
+            self.event_buf.remove(0); // Remove the oldest record
+        }
+        self.event_buf.push(event);
+    }
+
+    /// The number of events currently in the trace pipe buffer.
+    pub fn event_count(&self) -> usize {
+        self.event_buf.len()
+    }
+
+    /// Clear the trace pipe buffer.
+    pub fn clear(&mut self) {
+        self.event_buf.clear();
+    }
+
+    /// Create a snapshot of the current state of the trace pipe buffer.
+    pub fn snapshot(&self) -> TracePipeSnapshot {
+        TracePipeSnapshot::new(self.event_buf.clone())
+    }
+}
+
+impl TracePipeOps for TracePipeRaw {
+    fn peek(&self) -> Option<&Vec<u8>> {
+        self.event_buf.first()
+    }
+
+    fn pop(&mut self) -> Option<Vec<u8>> {
+        if self.event_buf.is_empty() {
+            None
+        } else {
+            Some(self.event_buf.remove(0))
+        }
+    }
+
+    fn is_empty(&self) -> bool {
+        self.event_buf.is_empty()
+    }
+}
+
+#[derive(Debug)]
+pub struct TracePipeSnapshot(Vec<Vec<u8>>);
+
+impl TracePipeSnapshot {
+    pub fn new(event_buf: Vec<Vec<u8>>) -> Self {
+        Self(event_buf)
+    }
+
+    /// The formatted string representation to be used as a header for the trace pipe output.
+    pub fn default_fmt_str(&self) -> String {
+        let show = "#
+#
+#                                _-----=> irqs-off/BH-disabled
+#                               / _----=> need-resched
+#                              | / _---=> hardirq/softirq
+#                              || / _--=> preempt-depth
+#                              ||| / _-=> migrate-disable
+#                              |||| /     delay
+#           TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION
+#              | |         |   |||||     |         |
+";
+        format!(
+            "# tracer: nop\n#\n# entries-in-buffer/entries-written: {}/{}   #P:32\n{}",
+            self.0.len(),
+            self.0.len(),
+            show
+        )
+    }
+}
+
+impl TracePipeOps for TracePipeSnapshot {
+    fn peek(&self) -> Option<&Vec<u8>> {
+        self.0.first()
+    }
+
+    fn pop(&mut self) -> Option<Vec<u8>> {
+        if self.0.is_empty() {
+            None
+        } else {
+            Some(self.0.remove(0))
+        }
+    }
+
+    fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+}
+
+/// A cache for storing command line arguments for each trace point.
+///
+/// See https://www.kernel.org/doc/Documentation/trace/ftrace.txt
+pub struct TraceCmdLineCache {
+    cmdline: Vec<(u32, [u8; 16])>,
+    max_record: usize,
+}
+
+impl TraceCmdLineCache {
+    pub const fn new(max_record: usize) -> Self {
+        Self {
+            cmdline: Vec::new(),
+            max_record,
+        }
+    }
+
+    /// Insert a command line argument for a trace point.
+    ///
+    /// If the command line exceeds 16 bytes, it will be truncated.
+    /// If the cache exceeds the maximum record limit, the oldest entry will be removed.
+    pub fn insert(&mut self, id: u32, cmdline: String) {
+        if self.cmdline.len() >= self.max_record {
+            // Remove the oldest entry if we exceed the max record limit
+            self.cmdline.remove(0);
+        }
+        let mut cmdline_bytes = [0u8; 16];
+        if cmdline.len() > 16 {
+            // Truncate to fit the fixed size
+            cmdline_bytes.copy_from_slice(&cmdline.as_bytes()[..16]);
+        } else {
+            // Copy the command line bytes into the fixed size array
+            cmdline_bytes[..cmdline.len()].copy_from_slice(cmdline.as_bytes());
+        }
+        self.cmdline.push((id, cmdline_bytes));
+    }
+
+    /// Get the command line argument for a trace point.
+    pub fn get(&self, id: u32) -> Option<&str> {
+        self.cmdline.iter().find_map(|(key, value)| {
+            if *key == id {
+                Some(core::str::from_utf8(value).unwrap().trim_end_matches('\0'))
+            } else {
+                None
+            }
+        })
+    }
+
+    /// Set the maximum length for command line arguments.
+    pub fn set_max_record(&mut self, max_len: usize) {
+        self.max_record = max_len;
+        if self.cmdline.len() > max_len {
+            self.cmdline.truncate(max_len); // Keep only the latest records
+        }
+    }
+}
+
+pub struct TraceEntryParser;
+
+impl TraceEntryParser {
+    /// Parse the trace entry and return a formatted string.
+    pub fn parse(
+        tracepoint_map: &TracePointMap,
+        cmdline_cache: &TraceCmdLineCache,
+        entry: &[u8],
+    ) -> String {
+        let trace_entry = unsafe { &*(entry.as_ptr() as *const TraceEntry) };
+        let id = trace_entry.type_ as u32;
+        let tracepoint = tracepoint_map.get(&id).expect("TracePoint not found");
+        let fmt_func = tracepoint.fmt_func();
+        let offset = core::mem::size_of::<TraceEntry>();
+        let str = fmt_func(unsafe { entry.as_ptr().add(offset) });
+
+        let time = crate::time::Instant::now().total_micros() * 1000; // Convert to nanoseconds
+        let cpu_id = crate::arch::cpu::current_cpu_id().data();
+
+        let pname = cmdline_cache.get(trace_entry.pid as u32).unwrap_or("<...>");
+
+        let secs = time / 1_000_000_000;
+        let usec_rem = time % 1_000_000_000 / 1000;
+
+        format!(
+            "{:>16}-{:<7} [{:03}] {} {:5}.{:06}: {}({})\n",
+            pname,
+            trace_entry.pid,
+            cpu_id,
+            trace_entry.trace_print_lat_fmt(),
+            secs,
+            usec_rem,
+            tracepoint.name(),
+            str
+        )
+    }
+}