我想要一个库,允许对 Linux 可执行文件的关键部分进行“自我分析”。就像可以使用 gettimeofday()RDTSC 对一个部分计时一样,我希望能够计算诸如分支未命中和缓存命中之类的事件。

有许多工具可以做类似的事情( perfPAPIlikwid ),但我没有找到任何与我正在寻找的东西相匹配的东西。 Likwid 最接近,所以我主要是在寻找修改它现有 Marker API 的方法。

每核计数器是存储在 MSR(模型特定寄存器)中的值,但对于当前的英特尔处理器(Sandy Bridge 以后),“非核心”测量(内存访问和与 CPU 整体相关的其他内容)是通过访问PCI。

通常采用的方法是使用 msr kernel module 读取 MSR,并从 sysfs-pci 层次结构中读取 PCI 计数器(如果支持)。问题是两者都需要读者以 root 身份运行并具有“setcap cap_sys_rawio”。这对许多用户来说是困难的(或不可能的)。

它也不是特别快。由于目标是分析小段代码,因此使用系统调用读取每个计数器的“偏差”很重要。事实证明,普通用户可以使用 RDPMC 读取 MSR 寄存器。我还没有一个很好的解决方案来读取 PCI 寄存器。

一种方法是通过以 root 身份运行的“访问服务器”代理所有内容。这会起作用,但比使用/proc/bus/pci 会更慢(因此更不准确)。我试图弄清楚如何最好地使计数器的 PCI“配置”空间对非特权程序可见。

我想出的最好的方法是让服务器以 root 身份运行,客户端可以在启动时通过 Unix 本地域套接字连接到该服务器。作为 root,服务器将打开适当的设备文件和 pass the open file handle to the client 。然后客户端应该能够在自己的执行过程中进行多次读取。有什么理由这不起作用吗?

但即使我这样做,我仍然会为每次访问使用 pread() system call(或类似的东西),其中可能有数十亿。如果尝试对小于 1000 个循环的小节段计时,这可能会造成过多的开销。相反,我想弄清楚如何以 Memory Mapped I/O 的形式访问这些计数器。

也就是说,我希望对由内存中的地址表示的每个计数器进行只读访问,I/O 映射发生在处理器和 IOMMU 级别,而不是涉及操作系统。这在 Intel Architectures Software Developer Vol 1 in section 16.3.1 Memory Mapped I/O 中有描述。

这似乎几乎是可能的。在 proc_bus_pci_mmap() 中,device handler for /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;

        /* Make sure the caller is mapping a real resource for this device */
        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 的区域。

(最后,我们来回答问题!)

因此,假设我真的希望在非特权进程中有一个指针,它每次都可以在没有内核帮助的情况下从 PCI 配置空间读取,我有什么选择?

1)也许我可以让一个根进程打开/dev/mem,然后将该打开的文件描述符传递给子进程,然后子进程可以映射它想要的部分。但是我想不出任何方法可以使远程安全。

2) 我可以编写自己的内核模块,它看起来很像 linux/drivers/pci/proc.c,但省略了对通常权限的检查。由于我可以将其锁定为只读并且仅用于我想要的 PCI 空间,因此它应该是相当安全的。

3)??? (这是你进来的地方)

最佳答案

也许答案有点晚了。答案是使用 likwid。
正如你所说,阅读 MSR/sysfs-pci 必须由 root 完成。构建 likwid accessDaemon 并授予其访问 MSR 的权限将绕过此问题。当然,由于一些进程间通信,性能值可能会有一些延迟。这个延迟不是很高。
(对于小代码段,性能计数器在某种程度上是不精确的。)

Likwid 也可以处理 uncore 事件。
最好的

关于c - 我应该如何以非 root 身份读取 Linux 上的 Intel PCI uncore 性能计数器?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20120812/

10-12 14:56