HPET: High Precision Event Timer. My team is going to use it to measure some kernel activity and for starters I’ve written a userspace program that uses the timer. Well that turned out to be a bit more difficult than I thought. It’s not that well documented.

HPET is quite PC oriented, so you don’t get it on other architectures. When a machine has one, it might take over the task of the Real Time Clock and the OS timer. In each of the two machines I examined, there was one HPET block and it had three “timers” in it. Actually there was one counter and three comparators. But for the purposes of software we can consider it to be three separate but related timers. The HPET spec waxes eloquent about how you can have bunches of timers and comparators in a machine, but I haven’t seen it yet. Maybe in specialized hardware. Update I have another machine with 4 comparators; the first two are reserved by Linux and the other two are available for when /dev/hpet is opened. If you open /dev/hpet a third time (without closing any) it will say it’s busy.

The Linux kernel uses the first two timers for itself, and makes the third one available to entities that ask for it. Userspace can use it via the /dev/hpet device. You open /dev/hpet, then you can make fcntl and ioctl calls on it. Eventually you close the device. You can open the device in read-only mode, even if you’re going to set the timer, because you will never call write on it.

The API for using the HPET is rather narrow, you can’t examine all the registers or anything. You can ask the driver to fill in hpet_info for you with the INFO ioctl call. That fills in a data structure like this (I was looking at kernel 2.6.35):

struct hpet_info {
        unsigned long hi_ireqfreq;      /* Hz */
        unsigned long hi_flags; /* information */
        unsigned short hi_hpet;
        unsigned short hi_timer;

I could find NO documentation on what goes into this structure, aside from reading the code. And you have to read the code pretty closely and in conjunction with the HPET spec … Anyway:

hpet_info gets filled with the info for the timer device in question. In this case, with timer 2 (because that’s the “leftover timer that gets used for /dev/hpet requests”.

  • hi_ireqfreq is (not surprisingly) the requested frequency of the periodic timer. The device driver does a little arithmetic to give you a value in Hz, rather than the raw numbers from the register.

  • hi_flags contains 0 if the timer is capable of periodic (repeated) interrupts in hardware and 2 if not (kind of a waste of a 32 bit field, oh well)

  • hi_hpet contains the id of the timer (2 in the case of timer 2) … in this block, I think. I only have one block.

  • hi_timer contains the address offset between datastructures in the kernel. I have no idea why they thought that might be interesting to userspace … Update It is supposed to be counting the number of structures, rather than giving an address offset. But it should have given 2, and it actually returned 0x40 (twice the structure size). ???

It turns out that (at least on my hardware) you can’t set a one-shot timer. When triggered, the interrupt handler adds the period into the comparator and the timer will trigger again. And again, and again, until you turn it off. I haven’t tried turning it off in the interrupt handler yet. Not sure if that’s a safe operation for the interrupt handler. I guess I’ll find out tomorrow! Update Turning the interrupt off in the interrupt handler worked. That time. YMMV.

As it turns out, it would do that even if the timer was capable of doing periodic interrupts in hardware. To use the hardware periodic interrupts, you have to stop, reset and start the whole timer block (with all the comparators). Kinda catastrophic for the block with the system clock in it, so Linux just doesn’t use the hardware period timers.

Well I’m not done looking at this, I’ll update the post when I learn more.