Professional Documents
Culture Documents
GEEP Presents
Linux Kernel
Debugging
Part II
Amit Kale
Presentation Outline
●
Kprobes
●
Kprobes: example
●
Spinlock: deadlocks
●
Spinlock: contention
●
Using strace
●
System software: learning
Kprobes
●
Bug at customer site Ethernet driver failure
●
ethtool shows xmit stops
●
Send an probe module
●
The probe module collects information
●
Dump to console
●
Customer sends /var/log/messages
Kprobes
●
insert a jprobe on driver D_start_xmit function
●
Probe function called every time D_start_xmit is
called
●
Probe function has same signature as
D_start_xmit
●
Probe function prints xmit ring tail and head on
each call
Kprobes: trace calls to xmit
Int D_xmit_frame(struct sk_buff *skb, struct
net_device *netdev) { .... }
long probe_xmit(struct sk_buff *skb, struct
net_device *netdev)
{
//print xmit ring head and tail }
Kprobes: register probe
struct jprobe xmit_probe = {
.entry = probe_xmit
};
xmit_probe.kp.symbol_name = “D_xmit_frame”;
register_jprobe(&xmit_probe);
Kprobes: Pros and cons
✔
Kprobes is used only when analyzing a problem
✔
Regular production code runs without overheads
✔
No need to add special debugging code in drivers
✔
Arbitrary information can be collected
✗
Kprobes has it's own overheads
✗
Not useful for intricate races (race may go away)
Spinlock: Analyzing
●
machine freeze.
●
Debugger or printk avoids freeze.
●
Debuggers and printks are heavy on CPU.
●
Static analysis – draw a lock dependency graph
➔
Loops in the graph indicate deadlocks.
●
How do you draw a lock graph for kernel?
●
Kernel builtin runtime validator can be used.
Spinlock: deadlock
void my_func(......) { int my_intr(.......) {
spin_lock(&mylock); spin_lock(&mylock);
....... .......
spin_unlock(&mylock); spin_unlock(&mylock);
} ........
}
Spinlock: deadlock
my_func(......)
➔
spin_lock(&mylock);
➔
Hardware interrupt (irq) occurs
➔
do_IRQ
➔
my_intr
➔
spin_lock(&mylock); ⇒DEADLOCK
Spinlock: good
void my_func(......) { int my_intr(.......) {
spin_lock_irqsave(&myl spin_lock(&mylock);
ock, flags); .......
....... spin_unlock(&mylock);
spin_unlock_irqrestore( ........
&mylock, flags); }
}
Spinlock: alternate
void my_func(......) { int my_intr(.......) {
spin_lock(&mylock); if (!spin_trylock(&mylock))
....... { .... return;}
spin_unlock(&mylock) .......
; } spin_unlock(&mylock);
........
}
Spinlock contention: symptoms
●
Not enough throughput.
●
CPU utilization CPU0: 85% CPU1: 90%
●
User level utilization < 10%
●
Spinlock contention likely.
●
Kernel code is optimized.
●
Look for contention in new code.
Spinlock contention: measurement
void my_func(......) {
c1 = get_cycles(); spin_lock(&mylock);
c2 = get_cycles();
.......
spin_unlock(&mylock);
c = c2 c1; }
Spinlock contention: analysis
●
Record min, max, avg values for c – the number
of cycles required to get the lock
●
Min 10 avg 15 max 20 – no contention
●
Min 10 avg 15 max 400 – occasional contention
●
Min 10 avg 50 max 400 – moderate contention
●
Min 10 avg 250 max 800 – heavy contention
Spinlock contention: avoiding
●
Reduce granularity – Use multiple locks for
multiple resources
●
Use instantaneous processing vs. delayed
processing
●
Enqueue work and process asynchronously in a
single thread.
Using strace
●
Strace shows a log of system calls and return
values
●
Locate cause to user or kernel land
●
Compare strace log with expected set of system
calls
●
strace o /tmp/log /bin/ls /
Strace log
execve("/bin/ls", ["/bin/ls", "/"], [/* 46 vars */]) = 0
....
stat64("/", {st_mode=S_IFDIR|0755, ...}) = 0
....
open("/", O_RDONLY|O_NONBLOCK|
O_LARGEFILE|O_DIRECTORY) = 3
.....
Strace log
getdents64(3, /* 30 entries */, 4096) = 800
getdents64(3, /* 0 entries */, 4096) = 0
close(3) = 0
....
exit_group(0) = ?
Systems software: learning
●
Why? Most system software is monolithic
●
Step 1 – bug analysis good for learning
debugging and understanding code
●
Step 2 – rebases, small extensions
●
Step 3 – Small code
●
Step 4 – Designs