perf_event_open-如何监视多个事件

有谁知道如何设置perf_event_attr可触发PMU通过以下方式监视多个(类型)事件的结构perf_event_open()

像一样perf record -e cycles,faults

ls,它具有两种不同的事件类型(PERF_TYPE_HARDWARE和PERF_TYPE_SOFTWARE),但是在perf_event_open的联机帮助页上的示例中,perf_event_attr.type只能分配单个值。

任何建议将不胜感激,谢谢!

感谢@gudok为我指明方向,但结果似乎有些异常。如下所示的演示程序(用于测量整个系统的CPU周期和缓存未命中):

#define _GNU_SOURCE

#include <stdlib.h>

#include <stdio.h>

#include <unistd.h>

#include <sys/syscall.h>

#include <string.h>

#include <sys/ioctl.h>

#include <linux/perf_event.h>

#include <linux/hw_breakpoint.h>

#include <asm/unistd.h>

#include <errno.h>

#include <stdint.h>

#include <inttypes.h>

#include <time.h>

struct read_format {

uint64_t nr;

struct {

uint64_t value;

uint64_t id;

} values[];

};

int main(int argc, char* argv[]) {

struct perf_event_attr pea;

int fd1, fd2;

uint64_t id1, id2;

uint64_t val1, val2;

char buf[4096];

struct read_format* rf = (struct read_format*) buf;

int i,j;

struct timespec time, time2;

time.tv_sec = 1;

time.tv_nsec = 0;

memset(&pea, 0, sizeof(struct perf_event_attr));

pea.type = PERF_TYPE_HARDWARE;

pea.size = sizeof(struct perf_event_attr);

pea.config = PERF_COUNT_HW_CPU_CYCLES;

pea.disabled = 1;

pea.exclude_kernel = 1;

pea.exclude_hv = 1;

pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;

fd1 = syscall(__NR_perf_event_open, &pea, 0, -1, -1, 0);

ioctl(fd1, PERF_EVENT_IOC_ID, &id1);

memset(&pea, 0, sizeof(struct perf_event_attr));

pea.type = PERF_TYPE_HARDWARE;

pea.size = sizeof(struct perf_event_attr);

pea.config = PERF_COUNT_HW_CACHE_MISSES;

pea.disabled = 1;

pea.exclude_kernel = 1;

pea.exclude_hv = 1;

pea.precise_ip = 2; // want to using PEBS

pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;

fd2 = syscall(__NR_perf_event_open, &pea, 0, -1, fd1 /*!!!*/, 0);

ioctl(fd2, PERF_EVENT_IOC_ID, &id2);

ioctl(fd1, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);

ioctl(fd1, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);

while (1) {

nanosleep(&time, &time2);

//ioctl(fd1, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);

read(fd1, buf, sizeof(buf));

for (i = 0; i < rf->nr; i++) {

if (rf->values[i].id == id1) {

val1 = rf->values[i].value;

} else if (rf->values[i].id == id2) {

val2 = rf->values[i].value;

}

}

printf("cpu cycles: %"PRIu64"\n", val1);

printf("cache misses: %"PRIu64"\n", val2);

}

return 0;

}

输出为:

cpu cycles: 120   // Just have about 120 CPU cycles in a second

cache misses: 0 // and doesn't have any cache miss?

cpu cycles: 233

cache misses: 0

cpu cycles: 352

cache misses: 0

cpu cycles: 455

cache misses: 0

cpu cycles: 562

cache misses: 0

cpu cycles: 673

cache misses: 0

cpu cycles: 794

cache misses: 0

cpu cycles: 907

cache misses: 0

cpu cycles: 1011

cache misses: 0

cpu cycles: 1129

cache misses: 3

cpu cycles: 1269

cache misses: 4

cpu cycles: 1423

回答:

有点棘手。

我们照常创建第一个计数器。此外,我们通过PERF_FORMAT_GROUPPERF_FORMAT_ID能够同时使用多个计数器。这个柜台将是我们的小组组长。

struct perf_event_attr pea;

int fd1, fd2;

uint64_t id1, id2;

memset(&pea, 0, sizeof(struct perf_event_attr));

pea.type = PERF_TYPE_HARDWARE;

pea.size = sizeof(struct perf_event_attr);

pea.config = PERF_COUNT_HW_CPU_CYCLES;

pea.disabled = 1;

pea.exclude_kernel = 1;

pea.exclude_hv = 1;

pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;

fd1 = syscall(__NR_perf_event_open, &pea, 0, -1, -1, 0);

接下来,我们检索第一个计数器的标识符:

ioctl(fd1, PERF_EVENT_IOC_ID, &id1);

第二个(以及所有其他计数器)以相同的方式创建,只有一个例外:我们将fd1值作为组长参数传递:

memset(&pea, 0, sizeof(struct perf_event_attr));

pea.type = PERF_TYPE_SOFTWARE;

pea.size = sizeof(struct perf_event_attr);

pea.config = PERF_COUNT_SW_PAGE_FAULTS;

pea.disabled = 1;

pea.exclude_kernel = 1;

pea.exclude_hv = 1;

pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;

fd2 = syscall(__NR_perf_event_open, &pea, 0, -1, fd1, 0); // <-- here

ioctl(fd2, PERF_EVENT_IOC_ID, &id2);

接下来,我们需要声明一个数据结构以一次读取多个计数器。您必须根据传递给的标志声明不同的字段集perf_event_open。手册页提到了所有可能的字段。在我们的例子中,我们通过PERF_FORMAT_ID了添加id字段的标志。这将使我们能够区分不同的计数器。

struct read_format {

uint64_t nr;

struct {

uint64_t value;

uint64_t id;

} values[/*2*/];

};

现在我们将标准配置文件称为ioctl:

ioctl(fd1, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);

ioctl(fd1, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);

do_something();

ioctl(fd1, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);

最后,我们从组长文件描述符中读取计数器。这两个计数器都以read_format我们声明的单一结构返回:

char buf[4096];

struct read_format* rf = (struct read_format*) buf;

uint64_t val1, val2;

read(fd1, buf, sizeof(buf));

for (i = 0; i < rf->nr; i++) {

if (rf->values[i].id == id1) {

val1 = rf->values[i].value;

} else if (rf->values[i].id == id2) {

val2 = rf->values[i].value;

}

}

printf("cpu cycles: %"PRIu64"\n", val1);

printf("page faults: %"PRIu64"\n", val2);


以下是完整的程序清单:

#define _GNU_SOURCE

#include <stdlib.h>

#include <stdio.h>

#include <unistd.h>

#include <sys/syscall.h>

#include <string.h>

#include <sys/ioctl.h>

#include <linux/perf_event.h>

#include <linux/hw_breakpoint.h>

#include <asm/unistd.h>

#include <errno.h>

#include <stdint.h>

#include <inttypes.h>

struct read_format {

uint64_t nr;

struct {

uint64_t value;

uint64_t id;

} values[];

};

void do_something() {

int i;

char* ptr;

ptr = malloc(100*1024*1024);

for (i = 0; i < 100*1024*1024; i++) {

ptr[i] = (char) (i & 0xff); // pagefault

}

free(ptr);

}

int main(int argc, char* argv[]) {

struct perf_event_attr pea;

int fd1, fd2;

uint64_t id1, id2;

uint64_t val1, val2;

char buf[4096];

struct read_format* rf = (struct read_format*) buf;

int i;

memset(&pea, 0, sizeof(struct perf_event_attr));

pea.type = PERF_TYPE_HARDWARE;

pea.size = sizeof(struct perf_event_attr);

pea.config = PERF_COUNT_HW_CPU_CYCLES;

pea.disabled = 1;

pea.exclude_kernel = 1;

pea.exclude_hv = 1;

pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;

fd1 = syscall(__NR_perf_event_open, &pea, 0, -1, -1, 0);

ioctl(fd1, PERF_EVENT_IOC_ID, &id1);

memset(&pea, 0, sizeof(struct perf_event_attr));

pea.type = PERF_TYPE_SOFTWARE;

pea.size = sizeof(struct perf_event_attr);

pea.config = PERF_COUNT_SW_PAGE_FAULTS;

pea.disabled = 1;

pea.exclude_kernel = 1;

pea.exclude_hv = 1;

pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;

fd2 = syscall(__NR_perf_event_open, &pea, 0, -1, fd1 /*!!!*/, 0);

ioctl(fd2, PERF_EVENT_IOC_ID, &id2);

ioctl(fd1, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);

ioctl(fd1, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);

do_something();

ioctl(fd1, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);

read(fd1, buf, sizeof(buf));

for (i = 0; i < rf->nr; i++) {

if (rf->values[i].id == id1) {

val1 = rf->values[i].value;

} else if (rf->values[i].id == id2) {

val2 = rf->values[i].value;

}

}

printf("cpu cycles: %"PRIu64"\n", val1);

printf("page faults: %"PRIu64"\n", val2);

return 0;

}

以上是 perf_event_open-如何监视多个事件 的全部内容, 来源链接: utcz.com/qa/421025.html

回到顶部