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