在内核内部实现 ioctl

在内核内部实现 ioctl

我正在研究 Linux 内核 4.19.2。我想在不使用 perf 或任何此类工具的情况下读取可用的性能计数器。

在用户空间中,我使用如下代码。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>

#define rdpmc(counter,low,high) \
     __asm__ __volatile__("rdpmc" \
        : "=a" (low), "=d" (high) \
        : "c" (counter))

void test(){
    printf(".");


}


static long
perf_event_open (struct perf_event_attr *hw_event, pid_t pid,
         int cpu, int group_fd, unsigned long flags)
{
  int ret;

  ret = syscall (__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
  return ret;
}





int
main ()
{
  unsigned long values1, values2;
  unsigned int fixed0, low, high;
  struct perf_event_attr pe;
  int fd, i;

  fixed0 = (1 << 30);

  memset (&pe, 0, sizeof (struct perf_event_attr));
  pe.type = PERF_TYPE_HARDWARE;
  pe.size = sizeof (struct perf_event_attr);
  pe.config = PERF_COUNT_HW_INSTRUCTIONS;
  pe.disabled = 1;
  pe.exclude_kernel = 0;
  pe.exclude_user = 0;
  pe.exclude_hv = 0;
  pe.exclude_idle = 0;

  fd = perf_event_open (&pe, 0, -1, -1, 0);
  if (fd == -1)
    {
      fprintf (stderr, "Error opening leader %llx\n", pe.config);
      exit (EXIT_FAILURE);
    }
for (i=1; i<=50; i++)
{
  ioctl (fd, PERF_EVENT_IOC_RESET, 0);
  ioctl (fd, PERF_EVENT_IOC_ENABLE, 0);

  rdpmc (fixed0, low, high);
  values1 = ((unsigned long) high << 32) + (unsigned long) low;

  test();

  rdpmc (fixed0, low, high);
  values2 = ((unsigned long) high << 32) + (unsigned long) low;

  ioctl (fd, PERF_EVENT_IOC_DISABLE, 0);
  printf (" %lu\n", values2 );  
}
  close (fd);
}

现在我想在内核代码中实现同样的事情。

我的目标是,在每次上下文切换时获取事件的计数并将其存储在任务结构中。因此最终我希望从内核中的 context_switch() 函数调用计数器。如果我从内核执行此操作,那么我将具有始终在当前线程的上下文中运行的优势。

我认为大部分代码也可以从内核中重用。但我不确定 ioctl() 部分。

答案1

从技术上讲,可以在内核代码中调用 ioctl。它被称为ksys_ioctl().[*] 注意init/唯一的其他代码是如何调用 ksys_ioctl() 的。温和地说,这是一件不寻常的事情。呼唤性能内核内部的 ioctl 听起来更可疑。

开始理解为什么这是不寻常的,我想指出这ksys_ioctl()仍然需要fd争论。这是文件描述符的编号在当前任务的范围内(进程/线程)。

[编辑] 我的目标是,在每次上下文切换时获取事件的计数并将其存储在任务结构中。因此最终我希望从内核中的 context_switch() 函数调用计数器。

啊啊啊。

所以你做到了不是想要从内核调用 ioctl()。 (你不会有一个文件描述符来调用 ioctl() 。而我有不是相信您想在每次 context_switch() 期间开始将文件描述符打开到当前任务的文件表中。即使您之后关闭它们)。

此时,您正在询问如何实现 Linuxperf子系统(较小版本)。子系统perf拥有性能计数器。如果您想使用性能计数器没有对于子系统perf,您应该首先禁用perf内核中的支持。在此过程的后期,您应该花时间查看以下内容中的相关材料:SDM(或相关手册 - 我还没有检查哪些)。


ksys_*()[*] 旁注:将指针传递给函数时存在限制。基本上他们期望__user内存,而不是内核内存,除非你使用set_fs()..


编写perf代码将是另一回事。您可以轻松找到代码并开始查看,例如单击PERF_EVENT_IOC_RESET。除了特定的行之外,它还会为您提供一个源文件(和目录)供您查看,您还可以继续单击:-)。因此我认为这不是你的问题。

相关内容