我应该如何以非 root 身份读取 Linux 上的 Intel PCI 非核心性能计数器?

2024-05-27

我想要一个库,允许对 Linux 可执行文件的关键部分进行“自我分析”。就像人们可以使用一个部分计时一样获取当日时间() http://linux.die.net/man/2/gettimeofday or RDTSC http://www.strchr.com/performance_measurements_with_rdtsc我希望能够对分支未命中和缓存命中等事件进行计数。

有许多工具可以做类似的事情(perf https://perf.wiki.kernel.org/index.php/Main_Page, PAPI http://icl.cs.utk.edu/papi/, likwid https://code.google.com/p/likwid/)但我还没有找到任何符合我要找的东西。 Likwid 最接近,所以我主要在寻找修改它现有的方法标记API https://code.google.com/p/likwid/wiki/LikwidPerfCtr#Using_the_marker_API.

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

通常采取的方法是使用 MSR 来读取msr内核模块 http://man7.org/linux/man-pages/man4/msr.4.html,并且 PCI 计数器(如果支持)是从sysfs-pci https://www.kernel.org/doc/Documentation/filesystems/sysfs-pci.txt等级制度。问题是,这两个或这些都要求阅读器以 root 身份运行并具有“setcap cap_sys_rawio”。这对于许多用户来说很困难(或不可能)。

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

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

我想到的最好办法是让服务器以 root 身份运行,客户端可以在启动时通过 Unix 本地域套接字连接到该服务器。作为 root,服务器将打开相应的设备文件,并且将打开的文件句柄传递给客户端 http://www.lst.de/~okir/blackhats/node121.html。然后,客户端应该能够在执行期间自行进行多次读取。有什么理由这行不通吗?

但即使我这样做,我仍然会使用pread() 系统调用 http://man7.org/linux/man-pages/man2/pread.2.html(或类似的东西)每次访问,其中可能有数十亿次。如果尝试对小于 1000 个循环部分进行计时,这可能会产生太大的开销。相反,我想弄清楚如何访问这些计数器内存映射 I/O http://en.wikipedia.org/wiki/Memory-mapped_I/O.

也就是说,我希望对内存中地址表示的每个计数器进行只读访问,I/O 映射发生在处理器和 IOMMU 级别,而不涉及操作系统。这在英特尔架构软件开发人员第 1 卷第 16.3.1 节内存映射 I/O http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-1-manual.pdf.

这似乎几乎是可能的。在 proc_bus_pci_mmap() 中/proc/bus/pci 的设备处理程序 https://github.com/mirrors/linux/blob/HEAD/drivers/pci/proc.c似乎允许映射配置区域,但仅限根用户,并且仅当我有 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 还可以处理非核心事件。 最好的

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我应该如何以非 root 身份读取 Linux 上的 Intel PCI 非核心性能计数器? 的相关文章

  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • WCF RIA 服务 - 加载多个实体

    我正在寻找一种模式来解决以下问题 我认为这很常见 我正在使用 WCF RIA 服务在初始加载时将多个实体返回给客户端 我希望两个实体异步加载 以免锁定 UI 并且我想利用 RIA 服务来执行此操作 我的解决方案如下 似乎有效 这种方法会遇到
  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现

随机推荐