Just to be clear, this post is about measuring the times at which events happen. Making things happen at specific times is a completely separate (and much harder) problem.
The clock_gettime() function (under Raspbian) gives results with only microsecond resolution and also requires almost a microsecond to execute. This isn’t very helpful when trying to measure short-duration events. What we want is access to the CPU’s cycle counter, which gives closer to nanosecond resolution and has low overhead. This is easy to accomplish:
static inline unsigned ccnt_read (void) { unsigned cc; asm volatile ("mrc p15, 0, %0, c15, c12, 1" : "=r" (cc)); return cc; }
The problem is that if you call this code from user mode, your process will die due to executing an illegal instruction. By default, user mode does not get to read the cycle count register. To change this, we need a silly little LKM:
#include <linux/module.h> #include <linux/kernel.h> /* * works for ARM1176JZ-F */ int init_module(void) { asm volatile ("mcr p15, 0, %0, c15, c9, 0\n" : : "r" (1)); printk (KERN_INFO "User-level access to CCR has been turned on.\n"); return 0; } void cleanup_module(void) { }
After the insmod call, the cycle count register will be accessible. For all I know there’s a good reason why this access is disabled by default, so please think twice before using this LKM on your security-critical Raspberry Pi. (UPDATE: See pm215’s comment below, but keep in mind that if a local user wants to DOS your RPi board, there are many other ways to accomplish this.)
Annoyingly, the Raspbian folks have not yet released a kernel headers package for the current kernel (3.2.27+). Also, an LKM compiled against older headers will fail to load. However, this thread contains a link to some updated headers.
Here’s a tarball containing the code from this post and also a compiled LKM for the 3.2.27+ Raspbian kernel.
I’m writing this up since cycle counters are awesome and also stupid problems like the missing kernel headers made it take an embarrassing amount of time for me to get this going. There’s a lot of ARM timer code out there but all of it that I found is either intended for kernel mode or else fails to work on an ARM11 chip. I actually had to read the manual to make this work.
The solution here is the best one that doesn’t involve modifying the kernel. A better approach would be to expose this functionality through /proc.
4 responses to “High-Resolution Timing on the Raspberry Pi”
My *guess* as to why this is off by default is that some people might care about preventing timing based side channels disclosures. Safe by default my be annoying, but it’s still safe.
Hi bcs, that sounds reasonable. Also it looks like this bit gives access to the system validation registers, which I don’t know anything about.
Setting the V bit also allows userspace to access the System Validation Operations Register. Among other amusing effects this allows any userspace process to schedule a hard reset of the CPU in N cycles time.
NB also that to set the V bit in the first place you need to be in the Secure world. I assume the RPi is, but that’s not the usual configuration for most systems out there, which is probably another reason Linux doesn’t try to do anything with this register.
Hi pm215, thanks. Yes, the RPi must be using the secure world since I can confirm that this code works.
Adding an ioctl() to my little driver (and not setting the V bit) would be the easy way to securely expose the cycle counter to user space, but this may not end up being any faster than clock_gettime().