diff --git a/Cargo.toml b/Cargo.toml index 6e78296fc8..38d63919a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ doc = [] graphical_debug = [] lpss_debug = [] multi_core = ["acpi"] +profiling = [] #TODO: remove when threading issues are fixed pti = [] qemu_debug = [] diff --git a/src/arch/x86_64/gdt.rs b/src/arch/x86_64/gdt.rs index 86fa4f1beb..80e26c15dc 100644 --- a/src/arch/x86_64/gdt.rs +++ b/src/arch/x86_64/gdt.rs @@ -201,6 +201,8 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) { pcr.percpu = PercpuBlock { cpu_id, switch_internals: Default::default(), + + #[cfg(feature = "profiling")] profiling: None, }; } diff --git a/src/arch/x86_64/idt.rs b/src/arch/x86_64/idt.rs index 35c1410fdb..a5ea9e045a 100644 --- a/src/arch/x86_64/idt.rs +++ b/src/arch/x86_64/idt.rs @@ -8,7 +8,6 @@ use hashbrown::HashMap; use x86::segmentation::Descriptor as X86IdtEntry; use x86::dtables::{self, DescriptorTablePointer}; -use crate::profiling::maybe_setup_timer; use crate::{interrupt::*, LogicalCpuId}; use crate::interrupt::irq::{__generic_interrupts_end, __generic_interrupts_start}; use crate::ipi::IpiKind; @@ -255,7 +254,8 @@ pub unsafe fn init_generic(cpu_id: LogicalCpuId, idt: &mut Idt) { current_idt[0x80].set_flags(IdtFlags::PRESENT | IdtFlags::RING_3 | IdtFlags::INTERRUPT); idt.set_reserved_mut(0x80, true); - maybe_setup_timer(idt, cpu_id); + #[cfg(feature = "profiling")] + crate::profiling::maybe_setup_timer(idt, cpu_id); dtables::lidt(&idtr); } diff --git a/src/arch/x86_64/interrupt/exception.rs b/src/arch/x86_64/interrupt/exception.rs index 3094309f37..6a73d59079 100644 --- a/src/arch/x86_64/interrupt/exception.rs +++ b/src/arch/x86_64/interrupt/exception.rs @@ -46,7 +46,14 @@ interrupt_stack!(debug, @paranoid, |stack| { }); interrupt_stack!(non_maskable, @paranoid, |stack| { + #[cfg(feature = "profiling")] crate::profiling::nmi_handler(stack); + + #[cfg(not(feature = "profiling"))] + { + println!("Non-maskable interrupt"); + stack.dump(); + } }); interrupt_stack!(breakpoint, |stack| { diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index c40babf4a9..36191ee762 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -252,6 +252,7 @@ interrupt!(lapic_timer, || { println!("Local apic timer interrupt"); lapic_eoi(); }); +#[cfg(feature = "profiling")] interrupt!(aux_timer, || { lapic_eoi(); crate::ipi::ipi(IpiKind::Profile, IpiTarget::Other); diff --git a/src/arch/x86_64/ipi.rs b/src/arch/x86_64/ipi.rs index 00c2a0ec0f..d5b11df906 100644 --- a/src/arch/x86_64/ipi.rs +++ b/src/arch/x86_64/ipi.rs @@ -5,6 +5,8 @@ pub enum IpiKind { Tlb = 0x41, Switch = 0x42, Pit = 0x43, + + #[cfg(feature = "profiling")] Profile = 0x44, } @@ -25,6 +27,7 @@ pub fn ipi(_kind: IpiKind, _target: IpiTarget) {} pub fn ipi(kind: IpiKind, target: IpiTarget) { use crate::device::local_apic::LOCAL_APIC; + #[cfg(feature = "profiling")] if matches!(kind, IpiKind::Profile) { let icr = (target as u64) << 18 | 1 << 14 | 0b100 << 8; unsafe { LOCAL_APIC.set_icr(icr) }; diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index a3bd054387..b7ac9fd919 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -6,7 +6,7 @@ use core::slice; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering, AtomicU32}; -use crate::{allocator, memory, LogicalCpuId, profiling}; +use crate::{allocator, memory, LogicalCpuId}; #[cfg(feature = "acpi")] use crate::acpi; use crate::arch::pti; @@ -150,7 +150,8 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Setup kernel heap allocator::init(); - profiling::init(); + #[cfg(feature = "profiling")] + crate::profiling::init(); // Set up double buffer for grpahical debug now that heap is available #[cfg(feature = "graphical_debug")] @@ -236,7 +237,8 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! { // Set up GDT with TLS gdt::init_paging(stack_end, cpu_id); - profiling::init(); + #[cfg(feature = "profiling")] + crate::profiling::init(); // Set up IDT for AP idt::init_paging_post_heap(cpu_id); diff --git a/src/main.rs b/src/main.rs index 37e09cf8f9..046a8d893f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -122,6 +122,7 @@ mod percpu; mod ptrace; /// Performance profiling of the kernel +#[cfg(feature = "profiling")] pub mod profiling; /// Schemes, filesystem handlers @@ -190,6 +191,8 @@ fn kmain(cpu_count: u32, bootstrap: Bootstrap) -> ! { info!("Env: {:?}", ::core::str::from_utf8(bootstrap.env)); BOOTSTRAP.call_once(|| bootstrap); + + #[cfg(feature = "profiling")] profiling::ready_for_profiling(); match context::contexts_mut().spawn(userspace_init) { @@ -221,6 +224,7 @@ fn kmain(cpu_count: u32, bootstrap: Bootstrap) -> ! { /// This is the main kernel entry point for secondary CPUs #[allow(unreachable_code, unused_variables)] fn kmain_ap(cpu_id: LogicalCpuId) -> ! { + #[cfg(feature = "profiling")] profiling::maybe_run_profiling_helper_forever(cpu_id); if cfg!(feature = "multi_core") { @@ -229,6 +233,7 @@ fn kmain_ap(cpu_id: LogicalCpuId) -> ! { let pid = syscall::getpid(); info!("AP {}: {:?}", cpu_id, pid); + #[cfg(feature = "profiling")] profiling::ready_for_profiling(); loop { diff --git a/src/percpu.rs b/src/percpu.rs index c7bd84b7c2..2107ec60d0 100644 --- a/src/percpu.rs +++ b/src/percpu.rs @@ -1,6 +1,5 @@ use crate::LogicalCpuId; use crate::context::switch::ContextSwitchPercpu; -use crate::profiling::RingBuffer; /// The percpu block, that stored all percpu variables. pub struct PercpuBlock { @@ -13,7 +12,8 @@ pub struct PercpuBlock { // TODO: Put mailbox queues here, e.g. for TLB shootdown? Just be sure to 128-byte align it // first to avoid cache invalidation. - pub profiling: Option<&'static RingBuffer>, + #[cfg(feature = "profiling")] + pub profiling: Option<&'static crate::profiling::RingBuffer>, } // PercpuBlock::current() is implemented somewhere in the arch-specific modules diff --git a/src/scheme/debug.rs b/src/scheme/debug.rs index e2cbbd6c31..a00daaeb8e 100644 --- a/src/scheme/debug.rs +++ b/src/scheme/debug.rs @@ -1,7 +1,6 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; -use crate::LogicalCpuId; use crate::arch::debug::Writer; use crate::event; use crate::scheme::*; @@ -45,6 +44,8 @@ impl KernelScheme for DebugScheme { let num = match path { "" => !0, + + #[cfg(feature = "profiling")] p if p.starts_with("profiling-") => { path[10..].parse().map_err(|_| Error::new(ENOENT))? } @@ -110,12 +111,13 @@ impl KernelScheme for DebugScheme { *handles.get(&id).ok_or(Error::new(EBADF))? }; - if handle.num == !0 { - INPUT - .receive_into_user(buf, handle.flags & O_NONBLOCK != O_NONBLOCK, "DebugScheme::read") - } else { - crate::profiling::drain_buffer(LogicalCpuId::new(handle.num as u32), buf) + #[cfg(feature = "profiling")] + if handle.num != !0 { + return crate::profiling::drain_buffer(crate::LogicalCpuId::new(handle.num as u32), buf); } + + INPUT + .receive_into_user(buf, handle.flags & O_NONBLOCK != O_NONBLOCK, "DebugScheme::read") } fn kwrite(&self, id: usize, buf: UserSliceRo) -> Result { diff --git a/src/scheme/serio.rs b/src/scheme/serio.rs index 679c53a6f1..13979c5d0e 100644 --- a/src/scheme/serio.rs +++ b/src/scheme/serio.rs @@ -27,6 +27,7 @@ static HANDLES: RwLock> = RwLock::new(BTreeMap::new()); /// Add to the input queue pub fn serio_input(index: usize, data: u8) { + #[cfg(feature = "profiling")] crate::profiling::serio_command(index, data); INPUT[index].send(data);