Intel PCM in userspace Linux

Recently I have been using Intel® Performance Counter Monitor Tool quite heavily to obtain code performance. The tool has been designed to work with Nehalem, Westmere, Sandy Bridge and Ivy Bridge micro-architecture  as well as with Atom (R), and I have to admit, it does its job flawlessly. However, one annoying drawback of using this tool in Linux is the fact that one must run the tool as root, to get performance results. I decided to fix this problem, and make it possible to obtain all the results in user space.

The problem

In order for Intel PCM to obtain results directly from the CPU, it must be able to issue ioctl requests to the processor. This is done through the Linux kernel, by reading / writing to


The Linux kernel, comes with an MSR kernel module, responsible for quering the model-specific registers of the CPU which are control registers in the x86 instruction set used for debugging, program execution tracing, computer performance monitoring, and toggling certain CPU features. Ideally, executing:

chmod go+rw /dev/cpu/*/msr

should allow users which are not root to be able to read / write from the MSR devices, however, this is not the case, and executing the command above will result in reporting the same error from Intel PCM tool:

Try to execute 'modprobe msr' as root user and then
you also must have read and write permissions for /dev/cpu/*/msr devices (/dev/msr* for Android). The 'chown' command can help.
Access to Intel(r) Performance Counter Monitor has denied (no MSR or PCI CFG space access).

I have inspected the code of the msr.c kernel module, and I figure it out that the problem is in static int msr_open(struct inode *inode, struct file *file) function:

static int msr_open(struct inode *inode, struct file *file)
	unsigned int cpu = iminor(file_inode(file));
	struct cpuinfo_x86 *c;

	if (!capable(CAP_SYS_RAWIO))
		return -EPERM;

	if (cpu >= nr_cpu_ids || !cpu_online(cpu))
		return -ENXIO;	/* No such CPU */

	c = &cpu_data(cpu);
	if (!cpu_has(c, X86_FEATURE_MSR))
		return -EIO;	/* MSR not supported */

	return 0;

The function capable makes sure that the user is root, and root only, and therefore, no matter what kind of permissions are set to /dev/cpu/*/msr, this function will return it the user is any other user than root.

The Solution

The simplest solution is to comment the function capable and avoid the check for root user. This solution is not safe. Having access to users other than root, can impose a serious vulnerability to the system. However, I am the only user having access to my machine, and I prefer productivity over safety.

In order to make the change, I need to recompile the kernel module, and replace the old msr.ko module. Additionally I can also benefit from udev, to set the proper permissions to the kernel module, so I don’t have to redo them every time the machine boots up. The good thing is that I can put everything into one simple Makefile:

obj-$(CONFIG_X86_MSR) += msr.o

	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

install: all
	rm -rf /lib/modules/$(shell uname -r)/kernel/arch/x86/kernel/msr.ko
	cp msr.ko /lib/modules/$(shell uname -r)/kernel/arch/x86/kernel/msr.ko
	echo "KERNEL==\"msr[0-9]*\", NAME=\"cpu/%n/msr\", MODE=\"0666\"" > /etc/udev/rules.d/20-msr.rules

The module can be built and installed using (must be logged in as root, not sudo):

make install

And after executing modprobe msr, everything else should magically work in user-space.


2 thoughts on “Intel PCM in userspace Linux

  1. I happened across your post on a search. Thanks!
    I think you can also do this on a per-executable basis with ‘setcap cap_sys_rawio’.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s