perf_event源码分析(二)——cmd_report

__cmd_report() => perf_session_open(),打开perf.data=>perf_session_read_header()根据perf.data的头部初始化session->evlist链表上的各个事件。

perf_session__process_events()首先把0号进程封装成一个thread结构体th->comm=”swapper”,初始化th->mg,并将这个thread结构体放到session->threads红黑树上。

接下来,到perf.data的data_offset处,fetch_mapped_event()得到一个perf_event,perf_session__process_event()处理这个事件,++session->hists->stats.nr_events[0]以及nr_events[event->header.type],对于内核事件,perf_session__parse_sample()根据session->sample_type解析事件类型,确定perf_sample结构体内容(用户事件处理:perf_session__process_user_event()),最后由perf_session_deliver_event()根据event->header.type来处理各种类型事件:

1.      PERF_RECORD_MMAP:perf_event__process_mmap()

对于内核映射执行perf_event__process_mmap():

    Ø     对于名为"[kernel.kallsyms]”的映射,首先建立dso *kernel,并挂到machine->kernel_dsos链表上,初始化machine->vmlinux.maps[MAP__FUNCTION / MAP__VARIABLE],并挂到machine->kmaps->maps[MAP__FUNCTION / MAP__VARIABLE]红黑树上。

    Ø     对于内核module映射,创建一个dso并挂到machine->kernel_dsos,封装成map,插入到machine->kmaps->maps[MAP__FUNCTION]

对于用户映射,必定对应一个进程,根据pid到session->threads红黑树中查找得thread,下面根据映射文件名到machine->user_dsos链表中查找dso,封装得map,这个map要挂到thread->mg->maps[MAP__FUNCTION]红黑树中,另外在插入之前,还要调整map->end,以防映射地址重叠。

2.      PERF_RECORD_COMM:perf_event__process_comm()根据tid到session->threads红黑树中查找,若无就创建一个新thread结构体并挂到session->threads树中。

3.      PERF_RECORD_SAMPLEprocess_sample_event()=>perf_event__preprocess_sample()根据pid得thread,根据ip查找映射,如果是内核映射就到machine->kmaps中查找,否则就到thread->mg中查询,得到map。下面是从map里提取所有symbolmap__find_symbol(map, addr)=> map__load()=> dso_load(),

    Ø    对于内核类型的DSO,调用dso__load_kernel_sym(),进而会调用dso__load_vmlinux_path(),这个函数将会修改之前创建的dso *kernel,kernel->long_name = “/lib/module/3.0.0/build/vmlinux”,然后dso__load_sym()函数会读取vmlinux文件,对于.text段的所有符号,都会创建一个新符号,根据符号的起始地址,插入到dso->symbols[map->type]红黑树上,对于其他段上的符号,根据符号名[kernel.kallsyms].section_name,到map__kmap(map)->kmaps[map->type]中查找,如果没有找到,就为其创建一个新的映射和DSO并将new_map挂到红黑树上,最后还要将这个段下的所有符号都挂到新创建的new_dso->symbols[map->type]下,同时将这个new_dso插入dso->node链表上。总之,这个函数会把vmlinux中的所有符号都提取出来,根据起始地址插入dso->symbols[map->type]红黑树上,对于.text段下的所有符号,直接放到dso *kernel的红黑树下,其他段,就需要重新创建一个map和DSO。所有段下的所有dso->long_name = “/lib/module/3.0.0/build/vmlinux”,除.text段外,其他段下的dso->short_name = “[kernel.kallsyms].section_name”。

   Ø    对于用户类型的DSO,同样是调用dso__load_kernel_sym()加载用户层的ELF文件,如"/lib/x86_64-linux-gnu/libc-2.13.so",或"/bin/dd"。

3’.      处理完采样事件后,perf_session__add_hist_entry()会把sample_period添加到evesel->hists的一个hist_entry* he->period上,以及根据cpumode,确定加到he->period_sys/period_us,这个he还会记录这是哪个映射的哪个符号上的采样he->ms。

阅读更多
个人分类: 内核之旅
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭