Performance 使用perf_event_open监视Docker容器

Performance 使用perf_event_open监视Docker容器,performance,docker,linux-kernel,perf,linux-containers,Performance,Docker,Linux Kernel,Perf,Linux Containers,我用C编写了一个程序来检索性能事件,比如Docker容器的cpu周期。 我的意思是,主机级的用户空间程序(主机级监控,而不是docker内部)。我将docker容器的pid作为的pid条目,但是,我始终将0作为返回值。我已经测试了其他非docker PID的程序,例如firefox,它运行得非常好 我将PERF\u FLAG\u PID\u CGROUP设置为标志,没有任何变化! 代码如下: #include <stdio.h> #include <stdlib.h> #

我用C编写了一个程序来检索性能事件,比如Docker容器的cpu周期。 我的意思是,主机级的用户空间程序(主机级监控,而不是docker内部)。我将docker容器的pid作为的pid条目,但是,我始终将0作为返回值。我已经测试了其他非docker PID的程序,例如firefox,它运行得非常好

我将PERF\u FLAG\u PID\u CGROUP设置为标志,没有任何变化! 代码如下:

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

    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(int argc, char **argv)
   {
       struct perf_event_attr pe;
       long long count;
       int fd;

       fd = open("/sys/fs/cgroup/perf_event/docker/f42c13cd9dd700544fe670e30d0b3216bdceaf01ddc370405618fdecfd10b26d", O_RDONLY);
       if (fd == -1)
          return 0;

       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_CPU_CYCLES;
       pe.disabled = 1;
       pe.exclude_kernel = 0;
       pe.exclude_hv = 0;

       fd = perf_event_open(&pe, fd, -1, -1, PERF_FLAG_PID_CGROUP);
       if (fd == -1) {
          fprintf(stderr, "Error opening leader %llx\n", pe.config);
          exit(EXIT_FAILURE);
       }

       ioctl(fd, PERF_EVENT_IOC_RESET, 0);
       ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

       usleep(100);

       ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
       read(fd, &count, sizeof(long long));

       printf("Used %lld instructions\n", count);

       close(fd);
   }
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
静态长性能事件打开(结构性能事件属性*硬件事件、pid、int cpu、int group fd、无符号长标志)
{
int ret;
ret=syscall(_unr_perf_event_open,hw_event,pid,cpu,
组(fd,flags),;
返回ret;
}
int
主(内部argc,字符**argv)
{
结构性能事件属性;
长计数;
int-fd;
fd=打开(“/sys/fs/cgroup/perf_event/docker/F42C13CD9DD700544FE670E30D0B3216BDCEAF01DDC37045618FDECFD10B26D”,仅适用于O_rdo);
如果(fd==-1)
返回0;
memset(&pe,0,sizeof(struct perf_event_attr));
pe.type=性能类型硬件;
pe.size=sizeof(结构性能事件属性);
pe.config=性能计数\u硬件\u CPU \u周期;
pe.disabled=1;
pe.exclude_kernel=0;
pe.hv=0;
fd=性能事件打开(&pe,fd,-1,-1,性能标志\u PID\u CGROUP);
如果(fd==-1){
fprintf(stderr,“打开引线%llx\n时出错”,pe.config);
退出(退出失败);
}
ioctl(fd,性能事件IOC重置,0);
ioctl(fd,性能事件IOC启用,0);
usleep(100);
ioctl(fd,性能事件IOC禁用,0);
读取(fd、计数和大小(长));
printf(“已使用%lld条指令”,计数);
关闭(fd);
}
根据perf_event_open()的手册页,我还给出了在groupfs中docker容器目录下打开的fd。不行

你能帮我解决这个问题吗? 谢谢

更新: 我已经检查了其他事件,例如性能计数、硬件缓存和引用, 我将0视为返回值

操作系统:Ubuntu 16.04

内核:4.15.0-041500-generic


体系结构:X86\u 64

您尚未指定正在使用的linux内核版本。我将根据最新的linux内核版本给出答案

传递给
perf\u event\u open
syscall的参数看起来正确,只有一个除外

在本例中,您将cpu=-1作为参数传递给
perf\u event\u open

虽然这通常适用于正常的
perf事件
过滤(即每个cpu或每个线程),但传递
cpu=-1
在基于cgroup的
perf
过滤中不起作用。在cgroup模式下,
pid
参数用于将打开的fd传递到
cgroupfs
中的cgroup目录(您似乎已正确传递)。
cpu
参数指定要在其上监视来自该cgroup的线程的cpu。当
cpu=-1
时,表示
perf事件
测量任何cpu上的指定进程/线程(不考虑该cpu是否属于您正在测量的cgroup)

这是最新Linux代码中对它的描述

if((flags&PERF_FLAG_PID_CGROUP)和&(PID=-1 | | cpu=-1))
返回-艾因瓦尔

您可以清楚地看到,如果
PID=-1或CPU=-1
,syscall方法将返回错误


工作示例

perf\u event\u open
文档中可以清楚地看到--

cgroup监视仅适用于系统范围的事件,因此可能需要额外的权限。

由于我们在本例中进行cgroup监控,这已经被理解为我们在监控容器的
perf events
,因此我们必须在系统范围内监控事件。这意味着对系统中的所有可用CPU进行监控

工作代码

我的系统中有4个内核,因此我使用CPU-0,1,2,3

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

    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(int argc, char **argv)
   {
       struct perf_event_attr pe;
       long long count, count1, count2, count3;
       int fd, fd1, fd2, fd3, fd4;

       fd1 = open("/sys/fs/cgroup/perf_event/docker/001706b1a71617b0ce9d340f706d901e00ee398091dd62aded2a1863fc8c274a", O_RDONLY);
       if (fd1 == -1)
          return 0;

       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_hv = 0;

       fd = perf_event_open(&pe, fd1, 0, -1, PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC);
       if (fd == -1) {
          fprintf(stderr, "Error opening leader: %s\n", strerror(errno));
          exit(EXIT_FAILURE);
       }
       fd2 = perf_event_open(&pe, fd1, 1, -1, PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC);
       if (fd2 == -1) {
          fprintf(stderr, "Error: %s\n", strerror(errno));
          exit(EXIT_FAILURE);
       }
       fd3 = perf_event_open(&pe, fd1, 2, -1, PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC);
       if (fd3 == -1) {
          fprintf(stderr, "Error: %s\n", strerror(errno));
          exit(EXIT_FAILURE);
       } 
       fd4 = perf_event_open(&pe, fd1, 3, -1, PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC);
       if (fd4 == -1) {
          fprintf(stderr, "Error: %s\n", strerror(errno));
          exit(EXIT_FAILURE);
       }

       ioctl(fd, PERF_EVENT_IOC_RESET, 0);
       ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

       ioctl(fd2, PERF_EVENT_IOC_RESET, 0);
       ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);

       ioctl(fd3, PERF_EVENT_IOC_RESET, 0);
       ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);

       ioctl(fd4, PERF_EVENT_IOC_RESET, 0);
       ioctl(fd4, PERF_EVENT_IOC_ENABLE, 0);

       sleep(10);   // using sleep(10) to actually observe instructions

       ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
       ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
       ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
       ioctl(fd4, PERF_EVENT_IOC_DISABLE, 0);

       read(fd, &count, sizeof(long long));
       read(fd2, &count1, sizeof(long long));
       read(fd3, &count2, sizeof(long long));
       read(fd4, &count3, sizeof(long long));

       printf("Used %lld instructions\n", count+count1+count2+count3);

       close(fd);
       close(fd2);
       close(fd3);
       close(fd4);
  }
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
静态长性能事件打开(结构性能事件属性*硬件事件、pid、int cpu、int group fd、无符号长标志)
{
int ret;
ret=syscall(_unr_perf_event_open,hw_event,pid,cpu,
组(fd,flags),;
返回ret;
}
int
主(内部argc,字符**argv)
{
结构性能事件属性;
长长计数,计数1,计数2,计数3;
int fd、fd1、fd2、fd3、fd4;
fd1=打开(“/sys/fs/cgroup/perf_event/docker/001706b1a71617b0ce9d340f706d901e00ee398091dd62aded2a1863fc8c274a”,仅适用于O);
如果(fd1==-1)
返回0;
memset(&pe,0,sizeof(struct perf_event_attr));
pe.type=性能类型硬件;
pe.size=sizeof(结构性能事件属性);
pe.config=性能计数硬件指令;
pe.disabled=1;
pe.exclude_kernel=0;
pe.hv=0;
fd=perf_event_open(&pe,fd1,0,-1,perf_FLAG_PID_CGROUP | perf_FLAG_fd_CLOEXEC);
如果(fd==-1){
fprintf(stderr,“错误打开前导:%s\n”,strerror(errno));
退出(退出失败);
}
fd2=性能事件(打开)(&pe,fd1,1,-1,性能标志(PID)组(性能标志(FD)组);
如果(fd2==-1){
fprintf(stderr,“错误:%s\n”,strerror(errno));
退出(退出失败);
}
fd3=性能事件(打开)(&pe,fd1,2,-1,性能标志(PID)组(性能标志(FD)组);
如果(fd3==-1){
fprintf(stderr,“错误:%s\n”,strerror(errno));
退出(退出失败);
} 
fd4=性能事件操作