Profiling
This commit is contained in:
@@ -80,6 +80,7 @@ impl LocalApic {
|
||||
self.write(0xF0, 0x100);
|
||||
}
|
||||
self.setup_error_int();
|
||||
|
||||
//self.setup_timer();
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -5,7 +5,7 @@ use core::mem;
|
||||
|
||||
use crate::LogicalCpuId;
|
||||
use crate::paging::{RmmA, RmmArch};
|
||||
use crate::percpu::PercpuBlock;
|
||||
use crate::percpu::{PercpuBlock, RingBuffer};
|
||||
|
||||
use x86::bits64::task::TaskStateSegment;
|
||||
use x86::Ring;
|
||||
@@ -201,8 +201,19 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
|
||||
pcr.percpu = PercpuBlock {
|
||||
cpu_id,
|
||||
switch_internals: Default::default(),
|
||||
profiling: None,
|
||||
};
|
||||
}
|
||||
pub unsafe fn init_allocator() {
|
||||
let percpu = PercpuBlock::current();
|
||||
|
||||
if percpu.cpu_id.get() == 4 { return }
|
||||
|
||||
let profiling = RingBuffer::create();
|
||||
|
||||
crate::scheme::debug::BUFS[percpu.cpu_id.get() as usize].store(profiling as *const _ as *mut _, core::sync::atomic::Ordering::SeqCst);
|
||||
(core::ptr::addr_of!(percpu.profiling) as *mut Option<&'static RingBuffer>).write(Some(profiling));
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(packed)]
|
||||
|
||||
@@ -24,7 +24,7 @@ pub type IdtReservations = [AtomicU64; 4];
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Idt {
|
||||
entries: IdtEntries,
|
||||
pub(crate) entries: IdtEntries,
|
||||
reservations: IdtReservations,
|
||||
}
|
||||
impl Idt {
|
||||
@@ -232,11 +232,12 @@ pub unsafe fn init_generic(is_bsp: bool, idt: &mut Idt) {
|
||||
// reserve bits 49:32, which are for the standard IRQs, and for the local apic timer and error.
|
||||
*current_reservations[0].get_mut() |= 0x0003_FFFF_0000_0000;
|
||||
} else {
|
||||
current_idt[32].set_func(irq::aux_timer);
|
||||
// TODO: use_default_irqs! but also the legacy IRQs that are only needed on one CPU
|
||||
current_idt[49].set_func(irq::lapic_error);
|
||||
|
||||
// reserve bit 49
|
||||
*current_reservations[0].get_mut() |= 1 << 49;
|
||||
*current_reservations[0].get_mut() |= 1 << 32 | 1 << 49;
|
||||
}
|
||||
|
||||
// Set IPI handlers
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use x86::irq::PageFaultError;
|
||||
|
||||
use crate::memory::GenericPfFlags;
|
||||
use crate::{
|
||||
interrupt::stack_trace,
|
||||
paging::VirtualAddress,
|
||||
ptrace,
|
||||
syscall::flag::*,
|
||||
|
||||
interrupt_stack,
|
||||
@@ -23,7 +24,7 @@ interrupt_stack!(divide_by_zero, |stack| {
|
||||
});
|
||||
|
||||
interrupt_stack!(debug, @paranoid, |stack| {
|
||||
let mut handled = false;
|
||||
/*let mut handled = false;
|
||||
|
||||
// Disable singlestep before there is a breakpoint, since the breakpoint
|
||||
// handler might end up setting it again but unless it does we want the
|
||||
@@ -38,19 +39,54 @@ interrupt_stack!(debug, @paranoid, |stack| {
|
||||
stack.set_singlestep(had_singlestep);
|
||||
}
|
||||
|
||||
if !handled {
|
||||
if !handled {*/
|
||||
println!("Debug trap");
|
||||
stack.dump();
|
||||
loop {}
|
||||
/*
|
||||
ksignal(SIGTRAP);
|
||||
}
|
||||
}*/
|
||||
});
|
||||
|
||||
interrupt_stack!(non_maskable, @paranoid, |stack| {
|
||||
println!("Non-maskable interrupt");
|
||||
stack.dump();
|
||||
let Some(profiling) = crate::percpu::PercpuBlock::current().profiling else {
|
||||
return;
|
||||
};
|
||||
if stack.iret.cs & 0b00 == 0b11 {
|
||||
profiling.nmi_ucount.store(profiling.nmi_ucount.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||
return;
|
||||
} else {
|
||||
profiling.nmi_kcount.store(profiling.nmi_kcount.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||
};
|
||||
|
||||
let mut buf = [0_usize; 32];
|
||||
buf[0] = stack.iret.rip & !(1<<63);
|
||||
buf[1] = x86::time::rdtsc() as usize;
|
||||
|
||||
let mut bp = stack.preserved.rbp;
|
||||
|
||||
let mut len = 2;
|
||||
|
||||
for i in 2..32 {
|
||||
if bp.saturating_add(16) < crate::KERNEL_HEAP_OFFSET || bp >= crate::KERNEL_HEAP_OFFSET + crate::PML4_SIZE {
|
||||
break;
|
||||
}
|
||||
let ip = ((bp + 8) as *const usize).read();
|
||||
bp = (bp as *const usize).read();
|
||||
|
||||
if ip < crate::kernel_executable_offsets::__text_start() || ip >= crate::kernel_executable_offsets::__text_end() {
|
||||
break;
|
||||
}
|
||||
buf[i] = ip;
|
||||
|
||||
len = i + 1;
|
||||
}
|
||||
|
||||
let _ = profiling.extend(&buf[..len]);
|
||||
});
|
||||
|
||||
interrupt_stack!(breakpoint, |stack| {
|
||||
/*
|
||||
// The processor lets RIP point to the instruction *after* int3, so
|
||||
// unhandled breakpoint interrupt don't go in an infinite loop. But we
|
||||
// throw SIGTRAP anyway, so that's not a problem.
|
||||
@@ -64,11 +100,13 @@ interrupt_stack!(breakpoint, |stack| {
|
||||
// int3 instruction. After all, it's the sanest thing to do.
|
||||
stack.iret.rip -= 1;
|
||||
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() {
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() {*/
|
||||
println!("Breakpoint trap");
|
||||
stack.dump();
|
||||
loop {}
|
||||
/*
|
||||
ksignal(SIGTRAP);
|
||||
}
|
||||
}*/
|
||||
});
|
||||
|
||||
interrupt_stack!(overflow, |stack| {
|
||||
@@ -127,8 +165,8 @@ interrupt_error!(stack_segment, |stack, _code| {
|
||||
ksignal(SIGSEGV);
|
||||
});
|
||||
|
||||
interrupt_error!(protection, |stack, _code| {
|
||||
println!("Protection fault");
|
||||
interrupt_error!(protection, |stack, code| {
|
||||
println!("Protection fault code={:#0x}", code);
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGSEGV);
|
||||
|
||||
@@ -252,6 +252,10 @@ interrupt!(lapic_timer, || {
|
||||
println!("Local apic timer interrupt");
|
||||
lapic_eoi();
|
||||
});
|
||||
interrupt!(aux_timer, || {
|
||||
lapic_eoi();
|
||||
crate::ipi::ipi(IpiKind::Profile, IpiTarget::Other);
|
||||
});
|
||||
|
||||
interrupt!(lapic_error, || {
|
||||
println!("Local apic internal error: ESR={:#0x}", local_apic::LOCAL_APIC.esr());
|
||||
|
||||
@@ -5,6 +5,7 @@ pub enum IpiKind {
|
||||
Tlb = 0x41,
|
||||
Switch = 0x42,
|
||||
Pit = 0x43,
|
||||
Profile = 0x44,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -24,6 +25,11 @@ pub fn ipi(_kind: IpiKind, _target: IpiTarget) {}
|
||||
pub fn ipi(kind: IpiKind, target: IpiTarget) {
|
||||
use crate::device::local_apic::LOCAL_APIC;
|
||||
|
||||
let icr = (target as u64) << 18 | 1 << 14 | (kind as u64);
|
||||
unsafe { LOCAL_APIC.set_icr(icr) };
|
||||
if matches!(kind, IpiKind::Profile) {
|
||||
let icr = (target as u64) << 18 | 1 << 14 | 0b100 << 8;
|
||||
unsafe { LOCAL_APIC.set_icr(icr) };
|
||||
} else {
|
||||
let icr = (target as u64) << 18 | 1 << 14 | (kind as u64);
|
||||
unsafe { LOCAL_APIC.set_icr(icr) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +150,8 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
// Setup kernel heap
|
||||
allocator::init();
|
||||
|
||||
gdt::init_allocator();
|
||||
|
||||
// Set up double buffer for grpahical debug now that heap is available
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
graphical_debug::init_heap();
|
||||
@@ -234,6 +236,8 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
// Set up GDT with TLS
|
||||
gdt::init_paging(stack_end, cpu_id);
|
||||
|
||||
gdt::init_allocator();
|
||||
|
||||
// Set up IDT for AP
|
||||
idt::init_paging_post_heap(false, cpu_id);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user