Why oh why is grub eating CPU resources in a VirtualBox VM?


While reviewing the performance on my desktop today, I noticed that one of my VirtualBox virtual machines was consuming 100% of one CPU:

Swap: 2097144k total, 59504k used, 2037640k free, 4004568k cached

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1895 matty 20 0 2037m 1.0g 57m S 96.2 13.0 831:13.06 VirtualBox

This was somewhat perplexing, given that the host in question was sitting at a grub> prompt (I’m cleaning up my grub notes to post to my website, so stay tuned!). When I strace’ed the VirtualBox process (having a system encapsulated in a userland process makes debugging these types of issues super easy), I noticed that the process was issuing poll()s and read()s in a tight loop:

[pid 1895] poll([{fd=15, events=POLLIN}, {fd=22, events=POLLIN|POLLPRI}, {fd=24, events=POLLIN|POLLPRI}, {fd=25, events=POLLIN|POLLPRI}, {fd=26, events=POLLIN|POLLPRI}, {fd=27, events=POLLIN}, {fd=28, events=POLLIN}, {fd=14, events=POLLIN}, {fd=29, events=POLLIN}, {fd=34, events=POLLIN}], 10, 0) = 0 (Timeout)
[pid 1895] read(14, 0x1492424, 4096) = -1 EAGAIN (Resource temporarily unavailable)
[pid 1895] read(14, 0x1492424, 4096) = -1 EAGAIN (Resource temporarily unavailable)
[pid 1895] read(27, 0x14fda94, 4096) = -1 EAGAIN (Resource temporarily unavailable)

At first I was perplexed by this, but upon further reflection this makes complete sense. The grub interpeter is executing a loop that polls the keyboard IO port for data, and continues to do so over and over again. Since most systems don’t stay at the grub prompt for extended periods of time, the grub developers didn’t use the HLT instruction to idle the CPUs when no actual work was being performed. For some reason this made me extremely curious about microprocessor implementations, so I started reading through the AMD64 Architecture Programmer’s Manual volume 1. So far this is a fantastic read, and I wish I would have read through it years ago!

This article was posted by Matty on 2010-01-12 21:14:00 -0400 -0400