首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用-g`仿真`perf记录`perf_event_open`

用-g`仿真`perf记录`perf_event_open`
EN

Stack Overflow用户
提问于 2018-03-07 20:12:30
回答 1查看 1K关注 0票数 6

我的目标是编写一些代码,在某个时间间隔内记录所有CPU的当前调用堆栈。本质上,我想和perf record一样,但自己使用perf_event_open

根据手册,我似乎需要使用PERF_SAMPLE_CALLCHAIN示例类型并使用mmap读取结果。尽管如此,该手册非常简洁,一些示例代码现在会有很长的路要走。

有人能给我指明正确的方向吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-08 04:09:33

了解这一点的最好方法是阅读Linux内核源代码,看看如何自己模仿perf record -g

正如您正确识别的那样,perf events的记录将从系统调用perf_event_open开始。所以这就是我们可以开始的地方

打开

如果您观察到系统调用的参数,您将看到第一个参数是struct perf_event_attr *类型。这是接受系统调用属性的参数。这是您需要修改以记录调用链的内容。示例代码可以是这样的(请记住,您可以按您希望的方式调整其他参数和结构perf_event_attr的成员):

代码语言:javascript
复制
     int buf_size_shift = 8;

     static unsigned perf_mmap_size(int buf_size_shift)
     {
       return ((1U << buf_size_shift) + 1) * sysconf(_SC_PAGESIZE);
     }


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

       struct perf_event_attr pe;
       long long count;
       int fd;

       memset(&pe, 0, sizeof(struct perf_event_attr));
       pe.type = PERF_TYPE_HARDWARE;
       pe.sample_type = PERF_SAMPLE_CALLCHAIN; /* this is what allows you to obtain callchains */

       pe.size = sizeof(struct perf_event_attr);
       pe.config = PERF_COUNT_HW_INSTRUCTIONS;
       pe.disabled = 1;
       pe.exclude_kernel = 1;
       pe.sample_period = 1000;
       pe.exclude_hv = 1;

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

       /* associate a buffer with the file */
       struct perf_event_mmap_page *mpage;
       mpage = mmap(NULL,  perf_mmap_size(buf_size_shift),
        PROT_READ|PROT_WRITE, MAP_SHARED,
       fd, 0);
       if (mpage == (struct perf_event_mmap_page *)-1L) {
        close(fd);
        return -1;
       }

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

       printf("Measuring instruction count for this printf\n");

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

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

       close(fd);
     }

注释:理解所有这些perf事件处理的好方法和简单的方法可以在下面看到-

PMU-工具,Andi Kleen

如果您开始读取系统调用的源代码,您将看到正在调用一个函数异种。该函数除其他外,将设置使用perf record获取调用链的缓冲区。

函数缓冲器负责设置调用链缓冲区。

perf_event_open通过抽样/计数机制工作,如果与您正在分析的事件对应的性能监视计数器溢出,那么所有与事件相关的信息将由内核收集并存储到环形缓冲区中。这个环形缓冲器可以通过mmap(2)进行准备和访问.

编辑#1:

描述在执行perf record时使用mmap的流程图通过下面的图像显示。

模拟环缓冲区的过程将从调用perf record时的第一个函数开始--调用记录,这个函数调用打开,然后调用mmap,然后调用回避表,然后调用例如,然后调用cpu,最后在埃弗尔中完成大部分的任务--对于每个事件都执行mmap。

编辑2:

是的你是对的。当您将示例周期设置为1000时,这意味着对于事件的每1000次发生(在默认情况下是cycles),内核将将该事件的一个示例记录到此缓冲区中。这意味着perf计数器将被设置为1000,使其溢出到0,您将得到一个中断并最终记录这些示例。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49160450

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档