diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/annotate.c | 74 | ||||
-rw-r--r-- | tools/perf/util/annotate.h | 7 | ||||
-rw-r--r-- | tools/perf/util/auxtrace.c | 3 | ||||
-rw-r--r-- | tools/perf/util/c++/clang.cpp | 2 | ||||
-rw-r--r-- | tools/perf/util/data.c | 4 | ||||
-rw-r--r-- | tools/perf/util/db-export.c | 15 | ||||
-rw-r--r-- | tools/perf/util/db-export.h | 3 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 25 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 8 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 51 | ||||
-rw-r--r-- | tools/perf/util/intel-bts.c | 20 | ||||
-rw-r--r-- | tools/perf/util/intel-pt.c | 2 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 14 | ||||
-rw-r--r-- | tools/perf/util/pmu.h | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 9 | ||||
-rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 8 | ||||
-rw-r--r-- | tools/perf/util/session.c | 4 | ||||
-rw-r--r-- | tools/perf/util/thread-stack.c | 16 | ||||
-rw-r--r-- | tools/perf/util/thread-stack.h | 6 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 23 | ||||
-rw-r--r-- | tools/perf/util/thread.h | 3 | ||||
-rw-r--r-- | tools/perf/util/time-utils.c | 51 | ||||
-rw-r--r-- | tools/perf/util/time-utils.h | 6 |
23 files changed, 248 insertions, 107 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 11a8a447a3af..5f6dbbf5d749 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -198,18 +198,18 @@ static void ins__delete(struct ins_operands *ops) } static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops) + struct ins_operands *ops, int max_ins_name) { - return scnprintf(bf, size, "%-6s %s", ins->name, ops->raw); + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); } int ins__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops) + struct ins_operands *ops, int max_ins_name) { if (ins->ops->scnprintf) - return ins->ops->scnprintf(ins, bf, size, ops); + return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); - return ins__raw_scnprintf(ins, bf, size, ops); + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); } bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) @@ -273,18 +273,18 @@ indirect_call: } static int call__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops) + struct ins_operands *ops, int max_ins_name) { if (ops->target.sym) - return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); if (ops->target.addr == 0) - return ins__raw_scnprintf(ins, bf, size, ops); + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.name) - return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.name); + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); - return scnprintf(bf, size, "%-6s *%" PRIx64, ins->name, ops->target.addr); + return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr); } static struct ins_ops call_ops = { @@ -388,15 +388,15 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s } static int jump__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops) + struct ins_operands *ops, int max_ins_name) { const char *c; if (!ops->target.addr || ops->target.offset < 0) - return ins__raw_scnprintf(ins, bf, size, ops); + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.outside && ops->target.sym != NULL) - return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); c = strchr(ops->raw, ','); c = validate_comma(c, ops); @@ -415,7 +415,7 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, c++; } - return scnprintf(bf, size, "%-6s %.*s%" PRIx64, + return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, ins->name, c ? c - ops->raw : 0, ops->raw, ops->target.offset); } @@ -483,16 +483,16 @@ out_free_ops: } static int lock__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops) + struct ins_operands *ops, int max_ins_name) { int printed; if (ops->locked.ins.ops == NULL) - return ins__raw_scnprintf(ins, bf, size, ops); + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); - printed = scnprintf(bf, size, "%-6s ", ins->name); + printed = scnprintf(bf, size, "%-*s ", max_ins_name, ins->name); return printed + ins__scnprintf(&ops->locked.ins, bf + printed, - size - printed, ops->locked.ops); + size - printed, ops->locked.ops, max_ins_name); } static void lock__delete(struct ins_operands *ops) @@ -564,9 +564,9 @@ out_free_source: } static int mov__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops) + struct ins_operands *ops, int max_ins_name) { - return scnprintf(bf, size, "%-6s %s,%s", ins->name, + return scnprintf(bf, size, "%-*s %s,%s", max_ins_name, ins->name, ops->source.name ?: ops->source.raw, ops->target.name ?: ops->target.raw); } @@ -604,9 +604,9 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops } static int dec__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops) + struct ins_operands *ops, int max_ins_name) { - return scnprintf(bf, size, "%-6s %s", ins->name, + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name ?: ops->target.raw); } @@ -616,9 +616,9 @@ static struct ins_ops dec_ops = { }; static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, - struct ins_operands *ops __maybe_unused) + struct ins_operands *ops __maybe_unused, int max_ins_name) { - return scnprintf(bf, size, "%-6s", "nop"); + return scnprintf(bf, size, "%-*s", max_ins_name, "nop"); } static struct ins_ops nop_ops = { @@ -1232,12 +1232,12 @@ void disasm_line__free(struct disasm_line *dl) annotation_line__delete(&dl->al); } -int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) +int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name) { if (raw || !dl->ins.ops) - return scnprintf(bf, size, "%-6s %s", dl->ins.name, dl->ops.raw); + return scnprintf(bf, size, "%-*s %s", max_ins_name, dl->ins.name, dl->ops.raw); - return ins__scnprintf(&dl->ins, bf, size, &dl->ops); + return ins__scnprintf(&dl->ins, bf, size, &dl->ops, max_ins_name); } static void annotation_line__add(struct annotation_line *al, struct list_head *head) @@ -2414,12 +2414,30 @@ static inline int width_jumps(int n) return 1; } +static int annotation__max_ins_name(struct annotation *notes) +{ + int max_name = 0, len; + struct annotation_line *al; + + list_for_each_entry(al, ¬es->src->source, node) { + if (al->offset == -1) + continue; + + len = strlen(disasm_line(al)->ins.name); + if (max_name < len) + max_name = len; + } + + return max_name; +} + void annotation__init_column_widths(struct annotation *notes, struct symbol *sym) { notes->widths.addr = notes->widths.target = notes->widths.min_addr = hex_width(symbol__size(sym)); notes->widths.max_addr = hex_width(sym->end); notes->widths.jumps = width_jumps(notes->max_jump_sources); + notes->widths.max_ins_name = annotation__max_ins_name(notes); } void annotation__update_column_widths(struct annotation *notes) @@ -2583,7 +2601,7 @@ call_like: obj__printf(obj, " "); } - disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset); + disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset, notes->widths.max_ins_name); } static void ipc_coverage_string(char *bf, int size, struct annotation *notes) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 95053cab41fe..df34fe483164 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -59,14 +59,14 @@ struct ins_ops { void (*free)(struct ins_operands *ops); int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); int (*scnprintf)(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops); + struct ins_operands *ops, int max_ins_name); }; bool ins__is_jump(const struct ins *ins); bool ins__is_call(const struct ins *ins); bool ins__is_ret(const struct ins *ins); bool ins__is_lock(const struct ins *ins); -int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); +int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name); bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); #define ANNOTATION__IPC_WIDTH 6 @@ -219,7 +219,7 @@ int __annotation__scnprintf_samples_period(struct annotation *notes, struct perf_evsel *evsel, bool show_freq); -int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); +int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name); size_t disasm__fprintf(struct list_head *head, FILE *fp); void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); @@ -289,6 +289,7 @@ struct annotation { u8 target; u8 min_addr; u8 max_addr; + u8 max_ins_name; } widths; bool have_cycles; struct annotated_source *src; diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 267e54df511b..fb76b6b232d4 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -1918,7 +1918,8 @@ static struct dso *load_dso(const char *name) if (!map) return NULL; - map__load(map); + if (map__load(map) < 0) + pr_err("File '%s' not found or has no symbols.\n", name); dso = dso__get(map->dso); diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index 39c0004f2886..fc361c3f8570 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp @@ -156,7 +156,7 @@ getBPFObjectFromModule(llvm::Module *Module) #endif if (NotAdded) { llvm::errs() << "TargetMachine can't emit a file of this type\n"; - return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; + return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr); } PM.run(*Module); diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 7bd5ddeb7a41..e098e189f93e 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -237,7 +237,7 @@ static int open_file(struct perf_data *data) open_file_read(data) : open_file_write(data); if (fd < 0) { - free(data->file.path); + zfree(&data->file.path); return -1; } @@ -270,7 +270,7 @@ int perf_data__open(struct perf_data *data) void perf_data__close(struct perf_data *data) { - free(data->file.path); + zfree(&data->file.path); close(data->file.fd); } diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index de9b4769d06c..d7315a00c731 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c @@ -510,18 +510,23 @@ int db_export__call_path(struct db_export *dbe, struct call_path *cp) return 0; } -int db_export__call_return(struct db_export *dbe, struct call_return *cr) +int db_export__call_return(struct db_export *dbe, struct call_return *cr, + u64 *parent_db_id) { int err; - if (cr->db_id) - return 0; - err = db_export__call_path(dbe, cr->cp); if (err) return err; - cr->db_id = ++dbe->call_return_last_db_id; + if (!cr->db_id) + cr->db_id = ++dbe->call_return_last_db_id; + + if (parent_db_id) { + if (!*parent_db_id) + *parent_db_id = ++dbe->call_return_last_db_id; + cr->parent_db_id = *parent_db_id; + } if (dbe->export_call_return) return dbe->export_call_return(dbe, cr); diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h index 67bc6b8ad2d6..4e2424c89df9 100644 --- a/tools/perf/util/db-export.h +++ b/tools/perf/util/db-export.h @@ -104,6 +104,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, int db_export__branch_types(struct db_export *dbe); int db_export__call_path(struct db_export *dbe, struct call_path *cp); -int db_export__call_return(struct db_export *dbe, struct call_return *cr); +int db_export__call_return(struct db_export *dbe, struct call_return *cr, + u64 *parent_db_id); #endif diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 08cedb643ea6..ed20f4379956 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -230,18 +230,33 @@ void perf_evlist__set_leader(struct perf_evlist *evlist) } } -void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr) +void perf_event_attr__set_max_precise_ip(struct perf_event_attr *pattr) { - attr->precise_ip = 3; + struct perf_event_attr attr = { + .type = PERF_TYPE_HARDWARE, + .config = PERF_COUNT_HW_CPU_CYCLES, + .exclude_kernel = 1, + .precise_ip = 3, + }; - while (attr->precise_ip != 0) { - int fd = sys_perf_event_open(attr, 0, -1, -1, 0); + event_attr_init(&attr); + + /* + * Unnamed union member, not supported as struct member named + * initializer in older compilers such as gcc 4.4.7 + */ + attr.sample_period = 1; + + while (attr.precise_ip != 0) { + int fd = sys_perf_event_open(&attr, 0, -1, -1, 0); if (fd != -1) { close(fd); break; } - --attr->precise_ip; + --attr.precise_ip; } + + pattr->precise_ip = attr.precise_ip; } int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index dfe2958e6287..3bbf73e979c0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -294,20 +294,12 @@ struct perf_evsel *perf_evsel__new_cycles(bool precise) if (!precise) goto new_event; - /* - * Unnamed union member, not supported as struct member named - * initializer in older compilers such as gcc 4.4.7 - * - * Just for probing the precise_ip: - */ - attr.sample_period = 1; perf_event_attr__set_max_precise_ip(&attr); /* * Now let the usual logic to set up the perf_event_attr defaults * to kick in when we return and before perf_evsel__open() is called. */ - attr.sample_period = 0; new_event: evsel = perf_evsel__new(&attr); if (evsel == NULL) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 669f961316f0..f9eb95bf3938 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -396,11 +396,8 @@ static int hist_entry__init(struct hist_entry *he, * adding new entries. So we need to save a copy. */ he->branch_info = malloc(sizeof(*he->branch_info)); - if (he->branch_info == NULL) { - map__zput(he->ms.map); - free(he->stat_acc); - return -ENOMEM; - } + if (he->branch_info == NULL) + goto err; memcpy(he->branch_info, template->branch_info, sizeof(*he->branch_info)); @@ -419,22 +416,16 @@ static int hist_entry__init(struct hist_entry *he, if (he->raw_data) { he->raw_data = memdup(he->raw_data, he->raw_size); + if (he->raw_data == NULL) + goto err_infos; + } - if (he->raw_data == NULL) { - map__put(he->ms.map); - if (he->branch_info) { - map__put(he->branch_info->from.map); - map__put(he->branch_info->to.map); - free(he->branch_info); - } - if (he->mem_info) { - map__put(he->mem_info->iaddr.map); - map__put(he->mem_info->daddr.map); - } - free(he->stat_acc); - return -ENOMEM; - } + if (he->srcline) { + he->srcline = strdup(he->srcline); + if (he->srcline == NULL) + goto err_rawdata; } + INIT_LIST_HEAD(&he->pairs.node); thread__get(he->thread); he->hroot_in = RB_ROOT_CACHED; @@ -444,6 +435,24 @@ static int hist_entry__init(struct hist_entry *he, he->leaf = true; return 0; + +err_rawdata: + free(he->raw_data); + +err_infos: + if (he->branch_info) { + map__put(he->branch_info->from.map); + map__put(he->branch_info->to.map); + free(he->branch_info); + } + if (he->mem_info) { + map__put(he->mem_info->iaddr.map); + map__put(he->mem_info->daddr.map); + } +err: + map__zput(he->ms.map); + free(he->stat_acc); + return -ENOMEM; } static void *hist_entry__zalloc(size_t size) @@ -606,7 +615,7 @@ __hists__add_entry(struct hists *hists, .map = al->map, .sym = al->sym, }, - .srcline = al->srcline ? strdup(al->srcline) : NULL, + .srcline = (char *) al->srcline, .socket = al->socket, .cpu = al->cpu, .cpumode = al->cpumode, @@ -963,7 +972,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, .map = al->map, .sym = al->sym, }, - .srcline = al->srcline ? strdup(al->srcline) : NULL, + .srcline = (char *) al->srcline, .parent = iter->parent, .raw_data = sample->raw_data, .raw_size = sample->raw_size, diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 0c0180c67574..47025bc727e1 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -328,35 +328,19 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip) { struct machine *machine = btsq->bts->machine; struct thread *thread; - struct addr_location al; unsigned char buf[INTEL_PT_INSN_BUF_SZ]; ssize_t len; - int x86_64; - uint8_t cpumode; + bool x86_64; int err = -1; - if (machine__kernel_ip(machine, ip)) - cpumode = PERF_RECORD_MISC_KERNEL; - else - cpumode = PERF_RECORD_MISC_USER; - thread = machine__find_thread(machine, -1, btsq->tid); if (!thread) return -1; - if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso) - goto out_put; - - len = dso__data_read_addr(al.map->dso, al.map, machine, ip, buf, - INTEL_PT_INSN_BUF_SZ); + len = thread__memcpy(thread, machine, buf, ip, INTEL_PT_INSN_BUF_SZ, &x86_64); if (len <= 0) goto out_put; - /* Load maps to ensure dso->is_64_bit has been updated */ - map__load(al.map); - - x86_64 = al.map->dso->is_64_bit; - if (intel_pt_get_insn(buf, len, x86_64, &btsq->intel_pt_insn)) goto out_put; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 3b497bab4324..6d288237887b 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -2531,6 +2531,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event, } pt->timeless_decoding = intel_pt_timeless_decoding(pt); + if (pt->timeless_decoding && !pt->tc.time_mult) + pt->tc.time_mult = 1; pt->have_tsc = intel_pt_have_tsc(pt); pt->sampling_mode = false; pt->est_tsc = !pt->timeless_decoding; diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 51d437f55d18..6199a3174ab9 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -752,6 +752,19 @@ perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) return NULL; } +static int pmu_max_precise(const char *name) +{ + char path[PATH_MAX]; + int max_precise = -1; + + scnprintf(path, PATH_MAX, + "bus/event_source/devices/%s/caps/max_precise", + name); + + sysfs__read_int(path, &max_precise); + return max_precise; +} + static struct perf_pmu *pmu_lookup(const char *name) { struct perf_pmu *pmu; @@ -784,6 +797,7 @@ static struct perf_pmu *pmu_lookup(const char *name) pmu->name = strdup(name); pmu->type = type; pmu->is_uncore = pmu_is_uncore(name); + pmu->max_precise = pmu_max_precise(name); pmu_add_cpu_aliases(&aliases, pmu); INIT_LIST_HEAD(&pmu->format); diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 47253c3daf55..bd9ec2704a57 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -26,6 +26,7 @@ struct perf_pmu { __u32 type; bool selectable; bool is_uncore; + int max_precise; struct perf_event_attr *default_config; struct cpu_map *cpus; struct list_head format; /* HEAD struct perf_pmu_format -> list */ diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 0030f9b9bf7e..a1b8d9649ca7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -472,9 +472,12 @@ static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi, strcpy(reason, "(unknown)"); } else dso__strerror_load(dso, reason, STRERR_BUFSIZE); - if (!silent) - pr_err("Failed to find the path for %s: %s\n", - module ?: "kernel", reason); + if (!silent) { + if (module) + pr_err("Module %s is not loaded, please specify its full path name.\n", module); + else + pr_err("Failed to find the path for the kernel: %s\n", reason); + } return NULL; } path = dso->long_name; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 0e17db41b49b..09604c6508f0 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1173,7 +1173,7 @@ static int python_export_call_return(struct db_export *dbe, u64 comm_db_id = cr->comm ? cr->comm->db_id : 0; PyObject *t; - t = tuple_new(11); + t = tuple_new(12); tuple_set_u64(t, 0, cr->db_id); tuple_set_u64(t, 1, cr->thread->db_id); @@ -1186,6 +1186,7 @@ static int python_export_call_return(struct db_export *dbe, tuple_set_u64(t, 8, cr->return_ref); tuple_set_u64(t, 9, cr->cp->parent->db_id); tuple_set_s32(t, 10, cr->flags); + tuple_set_u64(t, 11, cr->parent_db_id); call_object(tables->call_return_handler, t, "call_return_table"); @@ -1194,11 +1195,12 @@ static int python_export_call_return(struct db_export *dbe, return 0; } -static int python_process_call_return(struct call_return *cr, void *data) +static int python_process_call_return(struct call_return *cr, u64 *parent_db_id, + void *data) { struct db_export *dbe = data; - return db_export__call_return(dbe, cr); + return db_export__call_return(dbe, cr, parent_db_id); } static void python_process_general_event(struct perf_sample *sample, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c764bbc91009..db643f3c2b95 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -140,7 +140,7 @@ struct perf_session *perf_session__new(struct perf_data *data, if (perf_data__is_read(data)) { if (perf_session__open(session) < 0) - goto out_close; + goto out_delete; /* * set session attributes that are present in perf.data @@ -181,8 +181,6 @@ struct perf_session *perf_session__new(struct perf_data *data, return session; - out_close: - perf_data__close(data); out_delete: perf_session__delete(session); out: diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index a8b45168513c..41942c2aaa18 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c @@ -49,6 +49,7 @@ enum retpoline_state_t { * @timestamp: timestamp (if known) * @ref: external reference (e.g. db_id of sample) * @branch_count: the branch count when the entry was created + * @db_id: id used for db-export * @cp: call path * @no_call: a 'call' was not seen * @trace_end: a 'call' but trace ended @@ -59,6 +60,7 @@ struct thread_stack_entry { u64 timestamp; u64 ref; u64 branch_count; + u64 db_id; struct call_path *cp; bool no_call; bool trace_end; @@ -280,12 +282,14 @@ static int thread_stack__call_return(struct thread *thread, .comm = ts->comm, .db_id = 0, }; + u64 *parent_db_id; tse = &ts->stack[idx]; cr.cp = tse->cp; cr.call_time = tse->timestamp; cr.return_time = timestamp; cr.branch_count = ts->branch_count - tse->branch_count; + cr.db_id = tse->db_id; cr.call_ref = tse->ref; cr.return_ref = ref; if (tse->no_call) @@ -295,7 +299,14 @@ static int thread_stack__call_return(struct thread *thread, if (tse->non_call) cr.flags |= CALL_RETURN_NON_CALL; - return crp->process(&cr, crp->data); + /* + * The parent db_id must be assigned before exporting the child. Note + * it is not possible to export the parent first because its information + * is not yet complete because its 'return' has not yet been processed. + */ + parent_db_id = idx ? &(tse - 1)->db_id : NULL; + + return crp->process(&cr, parent_db_id, crp->data); } static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts) @@ -484,7 +495,7 @@ void thread_stack__sample(struct thread *thread, int cpu, } struct call_return_processor * -call_return_processor__new(int (*process)(struct call_return *cr, void *data), +call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data), void *data) { struct call_return_processor *crp; @@ -537,6 +548,7 @@ static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr, tse->no_call = no_call; tse->trace_end = trace_end; tse->non_call = false; + tse->db_id = 0; return 0; } diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h index b7c04e19ad41..9c45f947f5a9 100644 --- a/tools/perf/util/thread-stack.h +++ b/tools/perf/util/thread-stack.h @@ -55,6 +55,7 @@ enum { * @call_ref: external reference to 'call' sample (e.g. db_id) * @return_ref: external reference to 'return' sample (e.g. db_id) * @db_id: id used for db-export + * @parent_db_id: id of parent call used for db-export * @flags: Call/Return flags */ struct call_return { @@ -67,6 +68,7 @@ struct call_return { u64 call_ref; u64 return_ref; u64 db_id; + u64 parent_db_id; u32 flags; }; @@ -79,7 +81,7 @@ struct call_return { */ struct call_return_processor { struct call_path_root *cpr; - int (*process)(struct call_return *cr, void *data); + int (*process)(struct call_return *cr, u64 *parent_db_id, void *data); void *data; }; @@ -93,7 +95,7 @@ void thread_stack__free(struct thread *thread); size_t thread_stack__depth(struct thread *thread, int cpu); struct call_return_processor * -call_return_processor__new(int (*process)(struct call_return *cr, void *data), +call_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data), void *data); void call_return_processor__free(struct call_return_processor *crp); int thread_stack__process(struct thread *thread, struct comm *comm, diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 4c179fef442d..50678d318185 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -12,6 +12,7 @@ #include "debug.h" #include "namespaces.h" #include "comm.h" +#include "map.h" #include "symbol.h" #include "unwind.h" @@ -393,3 +394,25 @@ struct thread *thread__main_thread(struct machine *machine, struct thread *threa return machine__find_thread(machine, thread->pid_, thread->pid_); } + +int thread__memcpy(struct thread *thread, struct machine *machine, + void *buf, u64 ip, int len, bool *is64bit) +{ + u8 cpumode = PERF_RECORD_MISC_USER; + struct addr_location al; + long offset; + + if (machine__kernel_ip(machine, ip)) + cpumode = PERF_RECORD_MISC_KERNEL; + + if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso || + al.map->dso->data.status == DSO_DATA_STATUS_ERROR || + map__load(al.map) < 0) + return -1; + + offset = al.map->map_ip(al.map, ip); + if (is64bit) + *is64bit = al.map->dso->is_64_bit; + + return dso__data_read_offset(al.map->dso, machine, offset, buf, len); +} diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 8276ffeec556..cf8375c017a0 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -113,6 +113,9 @@ struct symbol *thread__find_symbol_fb(struct thread *thread, u8 cpumode, void thread__find_cpumode_addr_location(struct thread *thread, u64 addr, struct addr_location *al); +int thread__memcpy(struct thread *thread, struct machine *machine, + void *buf, u64 ip, int len, bool *is64bit); + static inline void *thread__priv(struct thread *thread) { return thread->priv; diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c index 6193b46050a5..0f53baec660e 100644 --- a/tools/perf/util/time-utils.c +++ b/tools/perf/util/time-utils.c @@ -11,6 +11,8 @@ #include "perf.h" #include "debug.h" #include "time-utils.h" +#include "session.h" +#include "evlist.h" int parse_nsec_time(const char *str, u64 *ptime) { @@ -374,7 +376,7 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, struct perf_time_interval *ptime; int i; - if ((timestamp == 0) || (num == 0)) + if ((!ptime_buf) || (timestamp == 0) || (num == 0)) return false; if (num == 1) @@ -396,6 +398,53 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, return (i == num) ? true : false; } +int perf_time__parse_for_ranges(const char *time_str, + struct perf_session *session, + struct perf_time_interval **ranges, + int *range_size, int *range_num) +{ + struct perf_time_interval *ptime_range; + int size, num, ret; + + ptime_range = perf_time__range_alloc(time_str, &size); + if (!ptime_range) + return -ENOMEM; + + if (perf_time__parse_str(ptime_range, time_str) != 0) { + if (session->evlist->first_sample_time == 0 && + session->evlist->last_sample_time == 0) { + pr_err("HINT: no first/last sample time found in perf data.\n" + "Please use latest perf binary to execute 'perf record'\n" + "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n"); + ret = -EINVAL; + goto error; + } + + num = perf_time__percent_parse_str( + ptime_range, size, + time_str, + session->evlist->first_sample_time, + session->evlist->last_sample_time); + + if (num < 0) { + pr_err("Invalid time string\n"); + ret = -EINVAL; + goto error; + } + } else { + num = 1; + } + + *range_size = size; + *range_num = num; + *ranges = ptime_range; + return 0; + +error: + free(ptime_range); + return ret; +} + int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz) { u64 sec = timestamp / NSEC_PER_SEC; diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h index 70b177d2b98c..b923de44e36f 100644 --- a/tools/perf/util/time-utils.h +++ b/tools/perf/util/time-utils.h @@ -23,6 +23,12 @@ bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp); bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, int num, u64 timestamp); +struct perf_session; + +int perf_time__parse_for_ranges(const char *str, struct perf_session *session, + struct perf_time_interval **ranges, + int *range_size, int *range_num); + int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); int fetch_current_timestamp(char *buf, size_t sz); |