2024年3月5日发(作者:)
cmd_record ;; new a struct "record" rec, and a struct "evlist" in rec->evlist; perf_evlist__new perf_config __cmd_record(&record, argc, argv); // fill out "struct record"
perf_session__new(file, false, tool); // New a sesssion for this rec, rec->session, attention: file is "struct perf_data_file *file", &rec->file; machines__init(&session->machines); ordered_events__init(&session->ordered_events, ordered_events__deliver_event); perf_data_file__open(file)
check_pipe(file) file->path = "" // If not specified name, fill out file->path open_file(file); fd = perf_data_file__is_read(file) ? open_file_read(file) : open_file_write(file); file->fd = fd; perf_session__create_kernel_maps(session) //
fd = perf_data_file__fd(file); // Get rec's fd, rec->file->fd record__init_features(rec);
perf_header__set_feat // Fill out session's header of this rec, rec->session->header record__open(rec) perf_evlist__config(evlist, opts); // perf_evlist perf_evsel__config(evsel, opts); // perf_evsel perf_header__clear_feat perf_header__write_pipe / perf_session__write_header perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, machine); perf_event__synthesize_modules(tool, process_synthesized_event, machine); machines__process_guests(&session->machines,perf_event__synthesize_guest_os, tool); __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,process_synthesized_event, opts->sample_address);
tools/perf/ cmd_record(int argc, const char **argv, const char *prefix __maybe_unused){ int err = -ENOMEM; struct record *rec = &record; char errbuf[BUFSIZ]; rec->evlist = perf_evlist__new(); if (rec->evlist == NULL) return -ENOMEM; perf_config(perf_record_config, rec); // 解析, tools/perf/util/config.c argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target__none(&rec->)) usage_with_options(record_usage, record_options); if (nr_cgroups && !rec->_wide) { ui__error("cgroup monitoring only available in" " system-wide moden"); usage_with_options(record_usage, record_options); }}
tools/perf/util/_events // tools/perf/builtin-stat.c parse_events // tools/perf/util/parse-events.c
parse_events // tools/perf/util/ parse_events(struct perf_evlist *evlist, const char *str){ struct parse_events_evlist data = { .list = LIST_HEAD_INIT(), .idx = evlist->nr_entries, }; int ret; ret = parse_events__scanner(str, &data, PE_START_EVENTS); perf_pmu__parse_cleanup(); if (!ret) { int entries = - evlist->nr_entries; perf_evlist__splice_list_tail(evlist, &, entries); evlist->nr_groups += _groups; return 0; } /* * There are 2 users - builtin-record and builtin-test objects. * Both call perf_evlist__delete in case of error, so we dont * need to bother. */ return ret;}struct introductiontools/perf/util/t target { const char *pid; const char *tid; const char *cpu_list; const char *uid_str; uid_t uid; bool system_wide; bool uses_mmap; bool default_per_cpu; bool per_thread;};===tools/perf/util/t perf_data_file { const char *path; int fd; bool is_pipe; bool force; unsigned long size; enum perf_data_mode mode;};===
tools/perf/util/session.h
tools/perf/util/t perf_session { struct perf_header header; struct machines machines; struct perf_evlist *evlist; struct trace_event tevent; bool repipe; bool one_mmap; void *one_mmap_addr; u64 one_mmap_offset; struct ordered_events ordered_events; struct perf_data_file *file; struct perf_tool *tool;};===tools/perf/util/evlist.h
struct perf_evlist { struct list_head entries; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; int nr_entries; int nr_groups; int nr_mmaps; size_t mmap_len; int id_pos; int is_pos; u64 combined_sample_type; struct { int cork_fd; pid_t pid; } workload; bool overwrite; struct fdarray pollfd; struct perf_mmap *mmap; struct thread_map *threads; // threads struct cpu_map *cpus; // cpus struct perf_evsel *selected; struct events_stats stats;};===
/** struct perf_evsel - event selector **/Each event passed from user mapping one perf_evsel struct.
struct perf_evsel { struct list_head node; struct perf_event_attr attr; char *filter; struct xyarray *fd; struct xyarray *sample_id; u64 *id; struct perf_counts *counts; struct perf_counts *prev_raw_counts; int idx; u32 ids; char *name; double scale; const char *unit; bool snapshot; struct event_format *tp_format; ...
... struct perf_evsel *leader;}===
tools/perf/t record { struct perf_tool tool; struct record_opts opts; u64 bytes_written; struct perf_data_file file; struct perf_evlist *evlist; struct perf_session *session; const char *progname; int realtime_prio; bool no_buildid; bool no_buildid_cache; long samples;};===Here is important, perf_stat is an array include three "struct stats" in "perf_stat",
and will init perf_stat:
for (i = 0; i < 3; i++) init_stats(&ps->res_stats[i]);struct perf_stat { struct stats res_stats[3];};tools/perf/util/t stats{ double n, mean, M2; u64 max, min;};====
tools/perf/util/t perf_counts_values { union { struct { u64 val; u64 ena; u64 run; }; u64 values[3]; };};struct perf_counts { s8 scaled; struct perf_counts_values aggr; struct perf_counts_values cpu[];};perf stat's CALL CHAIN
CALL CHAIN:
commands // tools/perf/perf.c cmd_stat // tools/perf/builtin-stat.c parse_events_option // If perf stat -e xxx, specified event name, will check this event name
parse_events parse_events__scanner // check events
parse_events_lex_init_extra parse_events__scan_string parse_events_parse parse_events__flush_buffer parse_events__delete_buffer parse_events_lex_destroy perf_pmu__parse_cleanup: perf_evlist__new(); perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, struct thread_map *threads) // evlist->cpus, evlist->threads perf_evlist__set_maps ///
parse_options parse_options_usage add_default_attributes() target__validate(&target); perf_evlist__create_maps(evsel_list, &target) // fill out evlist->threads(thread_map) evlist->threads = thread_map__new_str(target->pid, target->tid,target->uid); // evlist->threads evlist->threads(thread_map) = [tid,tid,tid,tid,...] target__uses_dummy_map(target)
evlist->cpus = cpu_map__dummy_new() // evlist->cpus evlist->cpus = cpu_map__new(target->cpu_list) perf_evlist__alloc_stats(evsel_list, interval) // Traverse all evsel evlist__for_each(evlist, evsel) { perf_evsel__alloc_stat_priv(evsel) // Alloc memory for each evsel->priv = zalloc(sizeof(struct perf_stat)); perf_evsel__reset_stat_priv(evsel) init_stats // Fill out "struct perf_stat", perf_stat include 3 elements of "struct stats{}" perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) // Alloc evsel->counts alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) // Alloc evsel->prev_raw_counts = addr; } perf_stat_init_aggr_mode() cpu_map__build_socket_map cpu_map__build_map(cpus, sockp, cpu_map__get_socket); cpu_map__get_socket cpu_map__build_core_map cpu_map__build_map(cpus, corep, cpu_map__get_core); cpu_map__get_core cpu_map__get_socket
run_perf_stat(argc, argv); __run_perf_stat(argc, argv); perf_evlist__prepare_workload(evsel_list, &target, argv, false, workload_exec_failed_signal) perf_evlist__set_leader(evsel_list); // evlist->nr_groups = 1 or 0 ? decide by evlist->nr_entries > 1 or not __perf_evlist__set_leader(&evlist->entries); evlist__for_each(evsel_list, evsel) { // Traverse all evsel create_perf_stat_counter(evsel) struct perf_event_attr *attr = &evsel->attr; attr->xxx = xxx perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel) perf_evsel__is_group_leader(evsel) perf_evsel__open_per_thread(evsel, evsel_list->threads) // important: __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, struct thread_map *threads) __perf_evsel__open(evsel, &empty_cpu_, threads)
// perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads), if system_wide: nthreads = 1 perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); for (cpu = 0; cpu < cpus->nr; cpu++) { for (thread = 0; thread < nthreads; thread++) {
group_fd = get_group_fd(evsel, cpu, thread); sys_perf_event_open(&evsel->attr, pid, cpus->map[cpu], group_fd, flags);
}
print_stat
print_aggr // AGGR_CORE AGGR_SOCKET print_counter_aggr(evsel, NULL); // AGGR_GLOBAL print_counter(evsel, NULL) // AGGR_NONEtools/perf/util/t perf_evsel {}


发布评论