The Linux Page

Make sleep() and other such functions work better in VirtualBox Guest on Linux

Sleeping like a dragon is not compatible with most software now a day...

I wrote software that runs a video service. That means I need to have code that handles video frames in realtime. For that purpose, I compute when the next frame is expected to "hit".

More or less, like most such software, I compute the time for the next frame which tells me whether I have time to wait or not.

next-frame = start-frame + interval * frame-number

When you write proper software next-frame is going to be in the future (i.e. you have enough CPU time to idle for a bit). That means you want to wait until that time to then send the next frame.

nanosleep(next-frame - now);

Unfortunately, by default a VirtualBox Virtual Machine (and most certainly most type of VMs) do not have direct access to a high precision timers. This is for various reasons such as to not use too much processor (i.e. in my case, it increases the CPU usage to 9% instead of my usual 2%, so it's a big hog! Luckily, I have 64 CPUs so it's mostly transparent to me, but definitely not a good thing).

I'd like to better understand why it's not possible to use the normal timers because in this case it feels like a resource that could easily be shared. Oh well...

So... what's the solution to make it work? Because by default any kind of sleep may end up sleeping as much as 10 seconds (rarely more than 1). There is actually a solution which is to turn on the High Precision Event Timer (HPET).

The flag is not accessible directly from the Graphical User Interface. This is for several reasons, the main one being what I just mentioned. Plus in many cases your software should not sleep. Instead, you should program using an event driven system such as poll() to track sockets, file system changes, etc.

So, to see the current value of the HPET, you can use the list command like so:

VBoxManage list vms --long | less

The "less" part is important if you want to easily scroll. It's going to be a long list for just one VM. If you have many... it's going to be really long.

To change the value of VM, you need its name of UUID. Then run the following command:

VBoxManage modifyvm "<name|uuid>" --hpet on

You can re-run the VBoxManager list command above to verify that it worked. Start the VM and you should see a huge improvement in the nanosleep() functionality and a huge drain on your CPUs.

Note that all the functions that use a timer are going to be working better with this change. The sleep() function itself generally works by default (at least on my modern computer, it seems to work just fine). So functions such as poll(), ppoll() and select() will also timeout at the proper time once HPET is turned on.

IMPORTANT NOTE: That actually did not help my app. which needs to sleep a few hundred nanoseconds. Often, it still misses the cap by waking up on the next second. So it's still not working right. It may still help your software if you do not need very high precision all the time.

Source: VirtualBox Forum

Documentation