I would like to have a library that allows you to "self-profile" critical sections of Linux executables. Likewise, you can highlight a section using gettimeofday () or RDTSC. I would like to be able to count events like branch misses and cache hits.
There are a number of tools that perform similar actions ( perf , PAPI , likwid ), but I did not find anything that matches what I'm looking for. Likwid comes closer, so I mainly look at ways to modify the existing token API .
Counters for each core are stored in the MSR (model-specific registers), but for current Intel processors (Sandy Bridge onward), measurements of "uncore" (memory access and other things related to the CPU as a whole) access to PCI.
The usual approach is that MSRs are read using the msr kernel module and that PCI counters (if supported) are read from the sysfs-pci hierarchy . The problem is that both or for this requires the reader to work as root and have "setcap cap_sys_rawio". This is difficult (or impossible) for many users.
It is also not particularly fast. Since the goal is to profile small pieces of code, the “skew” from reading each counter using syscall is significant. It turns out that MSR registers can be read by a regular user using RDPMC. I don't have a great solution for reading PCI registers yet.
One way is to proxy everything through an “access server” running as root. This will work, but will be even slower (and therefore less accurate) than using / proc / bus / pci. I’m trying to figure out how best to make the PCI counter configuration space visible to an unprivileged program.
, , - root, Unix. root, , . . , ?
, pread() ( - ) , . sub-1000, . , Memory Mapped I/O.
, , , - IOMMU, . Intel Architectures Software Developer Vol 1 16.3.1 " -" .
. proc_bus_pci_mmap() /proc/bus/pci, , , root CAP_SYS_RAWIO.
static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
{
struct pci_dev *dev = PDE_DATA(file_inode(file));
struct pci_filp_private *fpriv = file->private_data;
int i, ret;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
if (pci_mmap_fits(dev, i, vma, PCI_MMAP_PROCFS))
break;
}
if (i >= PCI_ROM_RESOURCE)
return -ENODEV;
ret = pci_mmap_page_range(dev, vma,
fpriv->mmap_state,
fpriv->write_combine);
if (ret < 0)
return ret;
return 0;
}
, , mmap(), , mmap'd , .
(, !)
, - , PCI , ?
1) , root/dev/mem, , . , .
2) , linux/drivers/pci/proc.c, . , PCI, , .
3). ( )