提交 70a7c127 编写于 作者: I Ingo Molnar

Merge branch 'perf' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core

此差异已折叠。
......@@ -10,7 +10,6 @@
#include "../perf.h"
#include "../util/util.h"
#include "../util/parse-options.h"
#include "../util/string.h"
#include "../util/header.h"
#include "bench.h"
......
......@@ -14,7 +14,6 @@
#include "util/cache.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
#include "util/string.h"
#include "perf.h"
#include "util/debug.h"
......
......@@ -363,19 +363,21 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
struct alloc_stat *data = rb_entry(next, struct alloc_stat,
node);
struct symbol *sym = NULL;
struct map *map;
char buf[BUFSIZ];
u64 addr;
if (is_caller) {
addr = data->call_site;
if (!raw_ip)
sym = map_groups__find_function(&session->kmaps, addr, NULL);
sym = map_groups__find_function(&session->kmaps,
addr, &map, NULL);
} else
addr = data->ptr;
if (sym != NULL)
snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
addr - sym->start);
addr - map->unmap_ip(map, sym->start));
else
snprintf(buf, sizeof(buf), "%#Lx", addr);
printf(" %-34s |", buf);
......@@ -488,6 +490,9 @@ static int __cmd_kmem(void)
if (session == NULL)
return -ENOMEM;
if (perf_session__create_kernel_maps(session) < 0)
goto out_delete;
if (!perf_session__has_traces(session, "kmem record"))
goto out_delete;
......
......@@ -15,7 +15,6 @@
#include "util/util.h"
#include "util/parse-options.h"
#include "util/parse-events.h"
#include "util/string.h"
#include "util/header.h"
#include "util/event.h"
......@@ -575,6 +574,9 @@ static int __cmd_record(int argc, const char **argv)
err = event__synthesize_kernel_mmap(process_synthesized_event,
session, "_text");
if (err < 0)
err = event__synthesize_kernel_mmap(process_synthesized_event,
session, "_stext");
if (err < 0) {
pr_err("Couldn't record kernel reference relocation symbol.\n");
return err;
......
......@@ -14,7 +14,6 @@
#include "util/cache.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
#include "util/string.h"
#include "util/callchain.h"
#include "util/strlist.h"
#include "util/values.h"
......@@ -89,9 +88,12 @@ static int perf_session__add_hist_entry(struct perf_session *self,
struct event_stat_id *stats;
struct perf_event_attr *attr;
if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain)
if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
syms = perf_session__resolve_callchain(self, al->thread,
data->callchain, &parent);
if (syms == NULL)
return -ENOMEM;
}
attr = perf_header__find_attr(data->id, &self->header);
if (attr)
......@@ -110,8 +112,8 @@ static int perf_session__add_hist_entry(struct perf_session *self,
if (symbol_conf.use_callchain) {
if (!hit)
callchain_init(&he->callchain);
err = append_chain(&he->callchain, data->callchain, syms);
callchain_init(he->callchain);
err = append_chain(he->callchain, data->callchain, syms);
free(syms);
if (err)
......@@ -303,14 +305,16 @@ static int __cmd_report(void)
next = rb_first(&session->stats_by_id);
while (next) {
struct event_stat_id *stats;
u64 nr_hists;
stats = rb_entry(next, struct event_stat_id, rb_node);
perf_session__collapse_resort(&stats->hists);
perf_session__output_resort(&stats->hists, stats->stats.total);
nr_hists = perf_session__output_resort(&stats->hists,
stats->stats.total);
if (use_browser)
perf_session__browse_hists(&stats->hists,
stats->stats.total, help);
perf_session__browse_hists(&stats->hists, nr_hists,
stats->stats.total, help,
input_name);
else {
if (rb_first(&session->stats_by_id) ==
rb_last(&session->stats_by_id))
......@@ -469,7 +473,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
setup_sorting(report_usage, options);
if (parent_pattern != default_parent_pattern) {
sort_dimension__add("parent");
if (sort_dimension__add("parent") < 0)
return -1;
sort_parent.elide = 1;
} else
symbol_conf.exclude_other = false;
......
......@@ -21,7 +21,6 @@
#include "util/cache.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
#include "util/string.h"
#include "util/callchain.h"
#include "util/strlist.h"
......
......@@ -13,7 +13,6 @@
#include "util/quote.h"
#include "util/run-command.h"
#include "util/parse-events.h"
#include "util/string.h"
#include "util/debugfs.h"
bool use_browser;
......
#!/bin/sh
GVF=PERF-VERSION-FILE
if [ $# -eq 1 ] ; then
OUTPUT=$1
fi
GVF=${OUTPUT}PERF-VERSION-FILE
DEF_VER=v0.0.2.PERF
LF='
......
......@@ -166,6 +166,31 @@ int perf_color_default_config(const char *var, const char *value, void *cb)
return perf_default_config(var, value, cb);
}
static int __color_vsnprintf(char *bf, size_t size, const char *color,
const char *fmt, va_list args, const char *trail)
{
int r = 0;
/*
* Auto-detect:
*/
if (perf_use_color_default < 0) {
if (isatty(1) || pager_in_use())
perf_use_color_default = 1;
else
perf_use_color_default = 0;
}
if (perf_use_color_default && *color)
r += snprintf(bf, size, "%s", color);
r += vsnprintf(bf + r, size - r, fmt, args);
if (perf_use_color_default && *color)
r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
if (trail)
r += snprintf(bf + r, size - r, "%s", trail);
return r;
}
static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
va_list args, const char *trail)
{
......@@ -191,11 +216,28 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
return r;
}
int color_vsnprintf(char *bf, size_t size, const char *color,
const char *fmt, va_list args)
{
return __color_vsnprintf(bf, size, color, fmt, args, NULL);
}
int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
{
return __color_vfprintf(fp, color, fmt, args, NULL);
}
int color_snprintf(char *bf, size_t size, const char *color,
const char *fmt, ...)
{
va_list args;
int r;
va_start(args, fmt);
r = color_vsnprintf(bf, size, color, fmt, args);
va_end(args);
return r;
}
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
{
......@@ -203,10 +245,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
int r;
va_start(args, fmt);
if (use_browser)
r = vfprintf(fp, fmt, args);
else
r = color_vfprintf(fp, color, fmt, args);
r = color_vfprintf(fp, color, fmt, args);
va_end(args);
return r;
}
......@@ -277,3 +316,9 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
return r;
}
int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent)
{
const char *color = get_percent_color(percent);
return color_snprintf(bf, size, color, fmt, percent);
}
......@@ -32,10 +32,14 @@ int perf_color_default_config(const char *var, const char *value, void *cb);
int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
void color_parse(const char *value, const char *var, char *dst);
void color_parse_mem(const char *value, int len, const char *var, char *dst);
int color_vsnprintf(char *bf, size_t size, const char *color,
const char *fmt, va_list args);
int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent);
int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
const char *get_percent_color(double percent);
......
......@@ -10,13 +10,29 @@ extern int dump_trace;
int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void trace_event(event_t *event);
struct ui_progress;
#ifdef NO_NEWT_SUPPORT
static inline int browser__show_help(const char *format __used, va_list ap __used)
{
return 0;
}
static inline struct ui_progress *ui_progress__new(const char *title __used,
u64 total __used)
{
return (struct ui_progress *)1;
}
static inline void ui_progress__update(struct ui_progress *self __used,
u64 curr __used) {}
static inline void ui_progress__delete(struct ui_progress *self __used) {}
#else
int browser__show_help(const char *format, va_list ap);
struct ui_progress *ui_progress__new(const char *title, u64 total);
void ui_progress__update(struct ui_progress *self, u64 curr);
void ui_progress__delete(struct ui_progress *self);
#endif
#endif /* __PERF_DEBUG_H */
......@@ -130,6 +130,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
continue;
pbf += n + 3;
if (*pbf == 'x') { /* vm_exec */
u64 vm_pgoff;
char *execname = strchr(bf, '/');
/* Catch VDSO */
......@@ -139,6 +140,14 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
if (execname == NULL)
continue;
pbf += 3;
n = hex2u64(pbf, &vm_pgoff);
/* pgoff is in bytes, not pages */
if (n >= 0)
ev.mmap.pgoff = vm_pgoff << getpagesize();
else
ev.mmap.pgoff = 0;
size = strlen(execname);
execname[size - 1] = '\0'; /* Remove \n */
memcpy(ev.mmap.filename, execname, size);
......
......@@ -50,7 +50,8 @@ struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
p = &(*p)->rb_right;
}
he = malloc(sizeof(*he));
he = malloc(sizeof(*he) + (symbol_conf.use_callchain ?
sizeof(struct callchain_node) : 0));
if (!he)
return NULL;
*he = entry;
......@@ -168,7 +169,7 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root,
struct hist_entry *iter;
if (symbol_conf.use_callchain)
callchain_param.sort(&he->sorted_chain, &he->callchain,
callchain_param.sort(&he->sorted_chain, he->callchain,
min_callchain_hits, &callchain_param);
while (*p != NULL) {
......@@ -185,12 +186,13 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root,
rb_insert_color(&he->rb_node, root);
}
void perf_session__output_resort(struct rb_root *hists, u64 total_samples)
u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples)
{
struct rb_root tmp;
struct rb_node *next;
struct hist_entry *n;
u64 min_callchain_hits;
u64 nr_hists = 0;
min_callchain_hits =
total_samples * (callchain_param.min_percent / 100);
......@@ -205,9 +207,11 @@ void perf_session__output_resort(struct rb_root *hists, u64 total_samples)
rb_erase(&n->rb_node, hists);
perf_session__insert_output_hist_entry(&tmp, n,
min_callchain_hits);
++nr_hists;
}
*hists = tmp;
return nr_hists;
}
static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
......@@ -452,16 +456,17 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
return ret;
}
size_t hist_entry__fprintf(struct hist_entry *self,
int hist_entry__snprintf(struct hist_entry *self,
char *s, size_t size,
struct perf_session *pair_session,
bool show_displacement,
long displacement, FILE *fp,
long displacement, bool color,
u64 session_total)
{
struct sort_entry *se;
u64 count, total;
const char *sep = symbol_conf.field_sep;
size_t ret;
int ret;
if (symbol_conf.exclude_other && !self->parent)
return 0;
......@@ -474,17 +479,22 @@ size_t hist_entry__fprintf(struct hist_entry *self,
total = session_total;
}
if (total)
ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%",
(count * 100.0) / total);
else
ret = fprintf(fp, sep ? "%lld" : "%12lld ", count);
if (total) {
if (color)
ret = percent_color_snprintf(s, size,
sep ? "%.2f" : " %6.2f%%",
(count * 100.0) / total);
else
ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
(count * 100.0) / total);
} else
ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count);
if (symbol_conf.show_nr_samples) {
if (sep)
ret += fprintf(fp, "%c%lld", *sep, count);
ret += snprintf(s + ret, size - ret, "%c%lld", *sep, count);
else
ret += fprintf(fp, "%11lld", count);
ret += snprintf(s + ret, size - ret, "%11lld", count);
}
if (pair_session) {
......@@ -504,9 +514,9 @@ size_t hist_entry__fprintf(struct hist_entry *self,
snprintf(bf, sizeof(bf), " ");
if (sep)
ret += fprintf(fp, "%c%s", *sep, bf);
ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
else
ret += fprintf(fp, "%11.11s", bf);
ret += snprintf(s + ret, size - ret, "%11.11s", bf);
if (show_displacement) {
if (displacement)
......@@ -515,9 +525,9 @@ size_t hist_entry__fprintf(struct hist_entry *self,
snprintf(bf, sizeof(bf), " ");
if (sep)
ret += fprintf(fp, "%c%s", *sep, bf);
ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
else
ret += fprintf(fp, "%6.6s", bf);
ret += snprintf(s + ret, size - ret, "%6.6s", bf);
}
}
......@@ -525,11 +535,25 @@ size_t hist_entry__fprintf(struct hist_entry *self,
if (se->elide)
continue;
ret += fprintf(fp, "%s", sep ?: " ");
ret += se->print(fp, self, se->width ? *se->width : 0);
ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
ret += se->snprintf(self, s + ret, size - ret,
se->width ? *se->width : 0);
}
return ret + fprintf(fp, "\n");
return ret;
}
int hist_entry__fprintf(struct hist_entry *self,
struct perf_session *pair_session,
bool show_displacement,
long displacement, FILE *fp,
u64 session_total)
{
char bf[512];
hist_entry__snprintf(self, bf, sizeof(bf), pair_session,
show_displacement, displacement,
true, session_total);
return fprintf(fp, "%s\n", bf);
}
static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
......@@ -658,7 +682,7 @@ size_t perf_session__fprintf_hists(struct rb_root *hists,
if (h->ms.map == NULL && verbose > 1) {
__map_groups__fprintf_maps(&h->thread->mg,
MAP__FUNCTION, fp);
MAP__FUNCTION, verbose, fp);
fprintf(fp, "%.10s end\n", graph_dotted_line);
}
}
......
......@@ -18,14 +18,19 @@ struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
u64 count, bool *hit);
extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
size_t hist_entry__fprintf(struct hist_entry *self,
int hist_entry__fprintf(struct hist_entry *self,
struct perf_session *pair_session,
bool show_displacement,
long displacement, FILE *fp,
u64 session_total);
int hist_entry__snprintf(struct hist_entry *self,
char *bf, size_t size,
struct perf_session *pair_session,
bool show_displacement, long displacement,
bool color, u64 session_total);
void hist_entry__free(struct hist_entry *);
void perf_session__output_resort(struct rb_root *hists, u64 total_samples);
u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples);
void perf_session__collapse_resort(struct rb_root *hists);
size_t perf_session__fprintf_hists(struct rb_root *hists,
struct perf_session *pair,
......
#include "symbol.h"
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
......@@ -234,18 +235,211 @@ u64 map__objdump_2ip(struct map *map, u64 addr)
return ip;
}
void map_groups__init(struct map_groups *self)
{
int i;
for (i = 0; i < MAP__NR_TYPES; ++i) {
self->maps[i] = RB_ROOT;
INIT_LIST_HEAD(&self->removed_maps[i]);
}
}
void map_groups__flush(struct map_groups *self)
{
int type;
for (type = 0; type < MAP__NR_TYPES; type++) {
struct rb_root *root = &self->maps[type];
struct rb_node *next = rb_first(root);
while (next) {
struct map *pos = rb_entry(next, struct map, rb_node);
next = rb_next(&pos->rb_node);
rb_erase(&pos->rb_node, root);
/*
* We may have references to this map, for
* instance in some hist_entry instances, so
* just move them to a separate list.
*/
list_add_tail(&pos->node, &self->removed_maps[pos->type]);
}
}
}
struct symbol *map_groups__find_symbol(struct map_groups *self,
enum map_type type, u64 addr,
struct map **mapp,
symbol_filter_t filter)
{
struct map *map = map_groups__find(self, type, addr);
if (map != NULL)
if (map != NULL) {
if (mapp != NULL)
*mapp = map;
return map__find_symbol(map, map->map_ip(map, addr), filter);
}
return NULL;
}
struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
enum map_type type,
const char *name,
struct map **mapp,
symbol_filter_t filter)
{
struct rb_node *nd;
for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node);
struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
if (sym == NULL)
continue;
if (mapp != NULL)
*mapp = pos;
return sym;
}
return NULL;
}
size_t __map_groups__fprintf_maps(struct map_groups *self,
enum map_type type, int verbose, FILE *fp)
{
size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
struct rb_node *nd;
for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node);
printed += fprintf(fp, "Map:");
printed += map__fprintf(pos, fp);
if (verbose > 2) {
printed += dso__fprintf(pos->dso, type, fp);
printed += fprintf(fp, "--\n");
}
}
return printed;
}
size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp)
{
size_t printed = 0, i;
for (i = 0; i < MAP__NR_TYPES; ++i)
printed += __map_groups__fprintf_maps(self, i, verbose, fp);
return printed;
}
static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
enum map_type type,
int verbose, FILE *fp)
{
struct map *pos;
size_t printed = 0;
list_for_each_entry(pos, &self->removed_maps[type], node) {
printed += fprintf(fp, "Map:");
printed += map__fprintf(pos, fp);
if (verbose > 1) {
printed += dso__fprintf(pos->dso, type, fp);
printed += fprintf(fp, "--\n");
}
}
return printed;
}
static size_t map_groups__fprintf_removed_maps(struct map_groups *self,
int verbose, FILE *fp)
{
size_t printed = 0, i;
for (i = 0; i < MAP__NR_TYPES; ++i)
printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp);
return printed;
}
size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp)
{
size_t printed = map_groups__fprintf_maps(self, verbose, fp);
printed += fprintf(fp, "Removed maps:\n");
return printed + map_groups__fprintf_removed_maps(self, verbose, fp);
}
int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
int verbose, FILE *fp)
{
struct rb_root *root = &self->maps[map->type];
struct rb_node *next = rb_first(root);
while (next) {
struct map *pos = rb_entry(next, struct map, rb_node);
next = rb_next(&pos->rb_node);
if (!map__overlap(pos, map))
continue;
if (verbose >= 2) {
fputs("overlapping maps:\n", fp);
map__fprintf(map, fp);
map__fprintf(pos, fp);
}
rb_erase(&pos->rb_node, root);
/*
* We may have references to this map, for instance in some
* hist_entry instances, so just move them to a separate
* list.
*/
list_add_tail(&pos->node, &self->removed_maps[map->type]);
/*
* Now check if we need to create new maps for areas not
* overlapped by the new map:
*/
if (map->start > pos->start) {
struct map *before = map__clone(pos);
if (before == NULL)
return -ENOMEM;
before->end = map->start - 1;
map_groups__insert(self, before);
if (verbose >= 2)
map__fprintf(before, fp);
}
if (map->end < pos->end) {
struct map *after = map__clone(pos);
if (after == NULL)
return -ENOMEM;
after->start = map->end + 1;
map_groups__insert(self, after);
if (verbose >= 2)
map__fprintf(after, fp);
}
}
return 0;
}
/*
* XXX This should not really _copy_ te maps, but refcount them.
*/
int map_groups__clone(struct map_groups *self,
struct map_groups *parent, enum map_type type)
{
struct rb_node *nd;
for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
struct map *map = rb_entry(nd, struct map, rb_node);
struct map *new = map__clone(map);
if (new == NULL)
return -ENOMEM;
map_groups__insert(self, new);
}
return 0;
}
static u64 map__reloc_map_ip(struct map *map, u64 ip)
{
return ip + (s64)map->pgoff;
......
......@@ -97,11 +97,14 @@ struct map_groups {
};
size_t __map_groups__fprintf_maps(struct map_groups *self,
enum map_type type, FILE *fp);
enum map_type type, int verbose, FILE *fp);
void maps__insert(struct rb_root *maps, struct map *map);
struct map *maps__find(struct rb_root *maps, u64 addr);
void map_groups__init(struct map_groups *self);
size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
int map_groups__clone(struct map_groups *self,
struct map_groups *parent, enum map_type type);
size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
static inline void map_groups__insert(struct map_groups *self, struct map *map)
{
......@@ -116,15 +119,33 @@ static inline struct map *map_groups__find(struct map_groups *self,
struct symbol *map_groups__find_symbol(struct map_groups *self,
enum map_type type, u64 addr,
struct map **mapp,
symbol_filter_t filter);
static inline struct symbol *map_groups__find_function(struct map_groups *self,
u64 addr,
symbol_filter_t filter)
struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
enum map_type type,
const char *name,
struct map **mapp,
symbol_filter_t filter);
static inline
struct symbol *map_groups__find_function(struct map_groups *self, u64 addr,
struct map **mapp, symbol_filter_t filter)
{
return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
return map_groups__find_symbol(self, MAP__FUNCTION, addr, mapp, filter);
}
static inline
struct symbol *map_groups__find_function_by_name(struct map_groups *self,
const char *name, struct map **mapp,
symbol_filter_t filter)
{
return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
}
int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
int verbose, FILE *fp);
struct map *map_groups__find_by_name(struct map_groups *self,
enum map_type type, const char *name);
int __map_groups__create_kernel_maps(struct map_groups *self,
......@@ -134,5 +155,6 @@ int map_groups__create_kernel_maps(struct map_groups *self,
struct map *vmlinux_maps[MAP__NR_TYPES]);
struct map *map_groups__new_module(struct map_groups *self, u64 start,
const char *filename);
void map_groups__flush(struct map_groups *self);
#endif /* __PERF_MAP_H */
......@@ -12,6 +12,72 @@
#include "sort.h"
#include "symbol.h"
struct ui_progress {
newtComponent form, scale;
};
struct ui_progress *ui_progress__new(const char *title, u64 total)
{
struct ui_progress *self = malloc(sizeof(*self));
if (self != NULL) {
int cols;
newtGetScreenSize(&cols, NULL);
cols -= 4;
newtCenteredWindow(cols, 1, title);
self->form = newtForm(NULL, NULL, 0);
if (self->form == NULL)
goto out_free_self;
self->scale = newtScale(0, 0, cols, total);
if (self->scale == NULL)
goto out_free_form;
newtFormAddComponents(self->form, self->scale, NULL);
newtRefresh();
}
return self;
out_free_form:
newtFormDestroy(self->form);
out_free_self:
free(self);
return NULL;
}
void ui_progress__update(struct ui_progress *self, u64 curr)
{
newtScaleSet(self->scale, curr);
newtRefresh();
}
void ui_progress__delete(struct ui_progress *self)
{
newtFormDestroy(self->form);
newtPopWindow();
free(self);
}
static char browser__last_msg[1024];
int browser__show_help(const char *format, va_list ap)
{
int ret;
static int backlog;
ret = vsnprintf(browser__last_msg + backlog,
sizeof(browser__last_msg) - backlog, format, ap);
backlog += ret;
if (browser__last_msg[backlog - 1] == '\n') {
newtPopHelpLine();
newtPushHelpLine(browser__last_msg);
newtRefresh();
backlog = 0;
}
return ret;
}
static void newt_form__set_exit_keys(newtComponent self)
{
newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
......@@ -228,60 +294,17 @@ static void hist_entry__append_callchain_browser(struct hist_entry *self,
}
}
/*
* FIXME: get lib/string.c linked with perf somehow
*/
static char *skip_spaces(const char *str)
{
while (isspace(*str))
++str;
return (char *)str;
}
static char *strim(char *s)
{
size_t size;
char *end;
s = skip_spaces(s);
size = strlen(s);
if (!size)
return s;
end = s + size - 1;
while (end >= s && isspace(*end))
end--;
*(end + 1) = '\0';
return s;
}
static size_t hist_entry__append_browser(struct hist_entry *self,
newtComponent tree, u64 total)
{
char bf[1024], *s;
FILE *fp;
char s[256];
size_t ret;
if (symbol_conf.exclude_other && !self->parent)
return 0;
fp = fmemopen(bf, sizeof(bf), "w");
if (fp == NULL)
return 0;
hist_entry__fprintf(self, NULL, false, 0, fp, total);
fclose(fp);
/*
* FIXME: We shouldn't need to trim, as the printing routines shouldn't
* add spaces it in the first place, the stdio output routines should
* call a __snprintf method instead of the current __print (that
* actually is a __fprintf) one, but get the raw string and _then_ add
* the newline, as this is a detail of stdio printing, not needed in
* other UIs, e.g. newt.
*/
s = strim(bf);
ret = hist_entry__snprintf(self, s, sizeof(s), NULL,
false, 0, false, total);
if (symbol_conf.use_callchain) {
int indexes[2];
......@@ -291,10 +314,11 @@ static size_t hist_entry__append_browser(struct hist_entry *self,
} else
newtListboxAppendEntry(tree, s, &self->ms);
return strlen(s);
return ret;
}
static void map_symbol__annotate_browser(const struct map_symbol *self)
static void map_symbol__annotate_browser(const struct map_symbol *self,
const char *input_name)
{
FILE *fp;
int cols, rows;
......@@ -308,8 +332,8 @@ static void map_symbol__annotate_browser(const struct map_symbol *self)
if (self->sym == NULL)
return;
if (asprintf(&str, "perf annotate -d \"%s\" %s 2>&1 | expand",
self->map->dso->name, self->sym->name) < 0)
if (asprintf(&str, "perf annotate -i \"%s\" -d \"%s\" %s 2>&1 | expand",
input_name, self->map->dso->name, self->sym->name) < 0)
return;
fp = popen(str, "r");
......@@ -358,90 +382,121 @@ static const void *newt__symbol_tree_get_current(newtComponent self)
return newtListboxGetCurrent(self);
}
static void perf_session__selection(newtComponent self, void *data)
static void hist_browser__selection(newtComponent self, void *data)
{
const struct map_symbol **symbol_ptr = data;
*symbol_ptr = newt__symbol_tree_get_current(self);
}
void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
const char *helpline)
{
struct sort_entry *se;
struct rb_node *nd;
char seq[] = ".";
unsigned int width;
char *col_width = symbol_conf.col_width_list_str;
int rows, cols, idx;
int max_len = 0;
char str[1024];
newtComponent form, tree;
struct newtExitStruct es;
struct hist_browser {
newtComponent form, tree;
const struct map_symbol *selection;
};
snprintf(str, sizeof(str), "Samples: %Ld", session_total);
newtDrawRootText(0, 0, str);
newtPushHelpLine(helpline);
newtGetScreenSize(&cols, &rows);
static struct hist_browser *hist_browser__new(void)
{
struct hist_browser *self = malloc(sizeof(*self));
if (symbol_conf.use_callchain)
tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
NEWT_FLAG_SCROLL);
else
tree = newtListbox(0, 0, rows - 5, (NEWT_FLAG_SCROLL |
NEWT_FLAG_RETURNEXIT));
if (self != NULL) {
char seq[] = ".";
int rows;
newtComponentAddCallback(tree, perf_session__selection, &selection);
newtGetScreenSize(NULL, &rows);
list_for_each_entry(se, &hist_entry__sort_list, list) {
if (se->elide)
continue;
width = strlen(se->header);
if (se->width) {
if (symbol_conf.col_width_list_str) {
if (col_width) {
*se->width = atoi(col_width);
col_width = strchr(col_width, ',');
if (col_width)
++col_width;
}
}
*se->width = max(*se->width, width);
}
if (symbol_conf.use_callchain)
self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq,
NEWT_FLAG_SCROLL);
else
self->tree = newtListbox(0, 0, rows - 5,
(NEWT_FLAG_SCROLL |
NEWT_FLAG_RETURNEXIT));
newtComponentAddCallback(self->tree, hist_browser__selection,
&self->selection);
}
return self;
}
static void hist_browser__delete(struct hist_browser *self)
{
newtFormDestroy(self->form);
newtPopWindow();
free(self);
}
static int hist_browser__populate(struct hist_browser *self, struct rb_root *hists,
u64 nr_hists, u64 session_total)
{
int max_len = 0, idx, cols, rows;
struct ui_progress *progress;
struct rb_node *nd;
u64 curr_hist = 0;
progress = ui_progress__new("Adding entries to the browser...", nr_hists);
if (progress == NULL)
return -1;
idx = 0;
for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
int len = hist_entry__append_browser(h, tree, session_total);
int len = hist_entry__append_browser(h, self->tree, session_total);
if (len > max_len)
max_len = len;
if (symbol_conf.use_callchain)
hist_entry__append_callchain_browser(h, tree, session_total, idx++);
hist_entry__append_callchain_browser(h, self->tree,
session_total, idx++);
++curr_hist;
if (curr_hist % 5)
ui_progress__update(progress, curr_hist);
}
ui_progress__delete(progress);
newtGetScreenSize(&cols, &rows);
if (max_len > cols)
max_len = cols - 3;
if (!symbol_conf.use_callchain)
newtListboxSetWidth(tree, max_len);
newtListboxSetWidth(self->tree, max_len);
newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0),
rows - 5, "Report");
form = newt_form__new();
newtFormAddHotKey(form, 'A');
newtFormAddHotKey(form, 'a');
newtFormAddHotKey(form, NEWT_KEY_RIGHT);
newtFormAddComponents(form, tree, NULL);
selection = newt__symbol_tree_get_current(tree);
self->form = newt_form__new();
newtFormAddHotKey(self->form, 'A');
newtFormAddHotKey(self->form, 'a');
newtFormAddHotKey(self->form, NEWT_KEY_RIGHT);
newtFormAddComponents(self->form, self->tree, NULL);
self->selection = newt__symbol_tree_get_current(self->tree);
return 0;
}
int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists,
u64 session_total, const char *helpline,
const char *input_name)
{
struct newtExitStruct es;
char str[1024];
int err = -1;
struct hist_browser *browser = hist_browser__new();
if (browser == NULL)
return -1;
snprintf(str, sizeof(str), "Samples: %Ld", session_total);
newtDrawRootText(0, 0, str);
newtPushHelpLine(helpline);
if (hist_browser__populate(browser, hists, nr_hists, session_total) < 0)
goto out;
while (1) {
char annotate[512];
const char *options[2];
int nr_options = 0, choice = 0;
newtFormRun(form, &es);
newtFormRun(browser->form, &es);
if (es.reason == NEWT_EXIT_HOTKEY) {
if (toupper(es.u.key) == 'A')
goto do_annotate;
......@@ -455,9 +510,9 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
}
}
if (selection->sym != NULL) {
if (browser->selection->sym != NULL) {
snprintf(annotate, sizeof(annotate),
"Annotate %s", selection->sym->name);
"Annotate %s", browser->selection->sym->name);
options[nr_options++] = annotate;
}
......@@ -466,41 +521,22 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
if (choice == nr_options - 1)
break;
do_annotate:
if (selection->sym != NULL && choice >= 0) {
if (selection->map->dso->origin == DSO__ORIG_KERNEL) {
if (browser->selection->sym != NULL && choice >= 0) {
if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
newtPopHelpLine();
newtPushHelpLine("No vmlinux file found, can't "
"annotate with just a "
"kallsyms file");
continue;
}
map_symbol__annotate_browser(selection);
map_symbol__annotate_browser(browser->selection,
input_name);
}
}
newtFormDestroy(form);
newtPopWindow();
}
static char browser__last_msg[1024];
int browser__show_help(const char *format, va_list ap)
{
int ret;
static int backlog;
ret = vsnprintf(browser__last_msg + backlog,
sizeof(browser__last_msg) - backlog, format, ap);
backlog += ret;
if (browser__last_msg[backlog - 1] == '\n') {
newtPopHelpLine();
newtPushHelpLine(browser__last_msg);
newtRefresh();
backlog = 0;
}
return ret;
err = 0;
out:
hist_browser__delete(browser);
return err;
}
void setup_browser(void)
......
......@@ -52,11 +52,6 @@ static int perf_session__open(struct perf_session *self, bool force)
return -1;
}
static inline int perf_session__create_kernel_maps(struct perf_session *self)
{
return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps);
}
struct perf_session *perf_session__new(const char *filename, int mode, bool force)
{
size_t len = filename ? strlen(filename) + 1 : 0;
......@@ -123,16 +118,11 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
struct symbol **parent)
{
u8 cpumode = PERF_RECORD_MISC_USER;
struct map_symbol *syms = NULL;
unsigned int i;
struct map_symbol *syms = calloc(chain->nr, sizeof(*syms));
if (symbol_conf.use_callchain) {
syms = calloc(chain->nr, sizeof(*syms));
if (!syms) {
fprintf(stderr, "Can't allocate memory for symbols\n");
exit(-1);
}
}
if (!syms)
return NULL;
for (i = 0; i < chain->nr; i++) {
u64 ip = chain->ips[i];
......@@ -397,6 +387,10 @@ int __perf_session__process_events(struct perf_session *self,
event_t *event;
uint32_t size;
char *buf;
struct ui_progress *progress = ui_progress__new("Processing events...",
self->size);
if (progress == NULL)
return -1;
perf_event_ops__fill_defaults(ops);
......@@ -425,6 +419,7 @@ int __perf_session__process_events(struct perf_session *self,
more:
event = (event_t *)(buf + head);
ui_progress__update(progress, offset);
if (self->header.needs_swap)
perf_event_header__bswap(&event->header);
......@@ -475,6 +470,7 @@ int __perf_session__process_events(struct perf_session *self,
done:
err = 0;
out_err:
ui_progress__delete(progress);
return err;
}
......
......@@ -80,6 +80,11 @@ static inline int __perf_session__create_kernel_maps(struct perf_session *self,
self->vmlinux_maps, kernel);
}
static inline int perf_session__create_kernel_maps(struct perf_session *self)
{
return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps);
}
static inline struct map *
perf_session__new_module_map(struct perf_session *self,
u64 start, const char *filename)
......@@ -88,11 +93,17 @@ static inline struct map *
}
#ifdef NO_NEWT_SUPPORT
static inline void perf_session__browse_hists(struct rb_root *hists __used,
static inline int perf_session__browse_hists(struct rb_root *hists __used,
u64 nr_hists __used,
u64 session_total __used,
const char *helpline __used) {}
const char *helpline __used,
const char *input_name __used)
{
return 0;
}
#else
void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
const char *helpline);
int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists,
u64 session_total, const char *helpline,
const char *input_name);
#endif
#endif /* __PERF_SESSION_H */
......@@ -18,10 +18,21 @@ char * field_sep;
LIST_HEAD(hist_entry__sort_list);
static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
struct sort_entry sort_thread = {
.header = "Command: Pid",
.cmp = sort__thread_cmp,
.print = sort__thread_print,
.snprintf = hist_entry__thread_snprintf,
.width = &threads__col_width,
};
......@@ -29,27 +40,27 @@ struct sort_entry sort_comm = {
.header = "Command",
.cmp = sort__comm_cmp,
.collapse = sort__comm_collapse,
.print = sort__comm_print,
.snprintf = hist_entry__comm_snprintf,
.width = &comms__col_width,
};
struct sort_entry sort_dso = {
.header = "Shared Object",
.cmp = sort__dso_cmp,
.print = sort__dso_print,
.snprintf = hist_entry__dso_snprintf,
.width = &dsos__col_width,
};
struct sort_entry sort_sym = {
.header = "Symbol",
.cmp = sort__sym_cmp,
.print = sort__sym_print,
.snprintf = hist_entry__sym_snprintf,
};
struct sort_entry sort_parent = {
.header = "Parent symbol",
.cmp = sort__parent_cmp,
.print = sort__parent_print,
.snprintf = hist_entry__parent_snprintf,
.width = &parent_symbol__col_width,
};
......@@ -85,45 +96,38 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
return right->thread->pid - left->thread->pid;
}
int repsep_fprintf(FILE *fp, const char *fmt, ...)
static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
{
int n;
va_list ap;
va_start(ap, fmt);
if (!field_sep)
n = vfprintf(fp, fmt, ap);
else {
char *bf = NULL;
n = vasprintf(&bf, fmt, ap);
if (n > 0) {
char *sep = bf;
while (1) {
sep = strchr(sep, *field_sep);
if (sep == NULL)
break;
*sep = '.';
}
n = vsnprintf(bf, size, fmt, ap);
if (field_sep && n > 0) {
char *sep = bf;
while (1) {
sep = strchr(sep, *field_sep);
if (sep == NULL)
break;
*sep = '.';
}
fputs(bf, fp);
free(bf);
}
va_end(ap);
return n;
}
size_t
sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width)
{
return repsep_fprintf(fp, "%*s:%5d", width - 6,
return repsep_snprintf(bf, size, "%*s:%5d", width,
self->thread->comm ?: "", self->thread->pid);
}
size_t
sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width)
{
return repsep_fprintf(fp, "%*s", width, self->thread->comm);
return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
}
/* --sort dso */
......@@ -149,16 +153,16 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
return strcmp(dso_name_l, dso_name_r);
}
size_t
sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width)
{
if (self->ms.map && self->ms.map->dso) {
const char *dso_name = !verbose ? self->ms.map->dso->short_name :
self->ms.map->dso->long_name;
return repsep_fprintf(fp, "%-*s", width, dso_name);
return repsep_snprintf(bf, size, "%-*s", width, dso_name);
}
return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
return repsep_snprintf(bf, size, "%*Lx", width, self->ip);
}
/* --sort symbol */
......@@ -177,22 +181,22 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
return (int64_t)(ip_r - ip_l);
}
size_t
sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width __used)
{
size_t ret = 0;
if (verbose) {
char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
ret += repsep_snprintf(bf, size, "%#018llx %c ", self->ip, o);
}
ret += repsep_fprintf(fp, "[%c] ", self->level);
ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
if (self->ms.sym)
ret += repsep_fprintf(fp, "%s", self->ms.sym->name);
ret += repsep_snprintf(bf + ret, size - ret, "%s",
self->ms.sym->name);
else
ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
ret += repsep_snprintf(bf + ret, size - ret, "%#016llx", self->ip);
return ret;
}
......@@ -231,10 +235,10 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
return strcmp(sym_l->name, sym_r->name);
}
size_t
sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width)
{
return repsep_fprintf(fp, "%-*s", width,
return repsep_snprintf(bf, size, "%-*s", width,
self->parent ? self->parent->name : "[other]");
}
......@@ -260,9 +264,8 @@ int sort_dimension__add(const char *tok)
char err[BUFSIZ];
regerror(ret, &parent_regex, err, sizeof(err));
fprintf(stderr, "Invalid regex: %s\n%s",
parent_pattern, err);
exit(-1);
pr_err("Invalid regex: %s\n%s", parent_pattern, err);
return -EINVAL;
}
sort__has_parent = 1;
}
......
......@@ -49,12 +49,12 @@ struct hist_entry {
u64 ip;
char level;
struct symbol *parent;
struct callchain_node callchain;
union {
unsigned long position;
struct hist_entry *pair;
struct rb_root sorted_chain;
};
struct callchain_node callchain[0];
};
enum sort_type {
......@@ -76,7 +76,8 @@ struct sort_entry {
int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
int (*snprintf)(struct hist_entry *self, char *bf, size_t size,
unsigned int width);
unsigned int *width;
bool elide;
};
......@@ -86,7 +87,6 @@ extern struct list_head hist_entry__sort_list;
void setup_sorting(const char * const usagestr[], const struct option *opts);
extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
......
#ifndef __PERF_STRING_H_
#define __PERF_STRING_H_
#include <stdbool.h>
#include "types.h"
s64 perf_atoll(const char *str);
char **argv_split(const char *str, int *argcp);
void argv_free(char **argv);
bool strglobmatch(const char *str, const char *pat);
bool strlazymatch(const char *str, const char *pat);
#define _STR(x) #x
#define STR(x) _STR(x)
#endif /* __PERF_STRING_H */
......@@ -38,15 +38,6 @@ int find_all_tid(int pid, pid_t ** all_tid)
return ret;
}
void map_groups__init(struct map_groups *self)
{
int i;
for (i = 0; i < MAP__NR_TYPES; ++i) {
self->maps[i] = RB_ROOT;
INIT_LIST_HEAD(&self->removed_maps[i]);
}
}
static struct thread *thread__new(pid_t pid)
{
struct thread *self = zalloc(sizeof(*self));
......@@ -62,28 +53,6 @@ static struct thread *thread__new(pid_t pid)
return self;
}
static void map_groups__flush(struct map_groups *self)
{
int type;
for (type = 0; type < MAP__NR_TYPES; type++) {
struct rb_root *root = &self->maps[type];
struct rb_node *next = rb_first(root);
while (next) {
struct map *pos = rb_entry(next, struct map, rb_node);
next = rb_next(&pos->rb_node);
rb_erase(&pos->rb_node, root);
/*
* We may have references to this map, for
* instance in some hist_entry instances, so
* just move them to a separate list.
*/
list_add_tail(&pos->node, &self->removed_maps[pos->type]);
}
}
}
int thread__set_comm(struct thread *self, const char *comm)
{
int err;
......@@ -110,69 +79,10 @@ int thread__comm_len(struct thread *self)
return self->comm_len;
}
size_t __map_groups__fprintf_maps(struct map_groups *self,
enum map_type type, FILE *fp)
{
size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
struct rb_node *nd;
for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
struct map *pos = rb_entry(nd, struct map, rb_node);
printed += fprintf(fp, "Map:");
printed += map__fprintf(pos, fp);
if (verbose > 2) {
printed += dso__fprintf(pos->dso, type, fp);
printed += fprintf(fp, "--\n");
}
}
return printed;
}
size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
{
size_t printed = 0, i;
for (i = 0; i < MAP__NR_TYPES; ++i)
printed += __map_groups__fprintf_maps(self, i, fp);
return printed;
}
static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
enum map_type type, FILE *fp)
{
struct map *pos;
size_t printed = 0;
list_for_each_entry(pos, &self->removed_maps[type], node) {
printed += fprintf(fp, "Map:");
printed += map__fprintf(pos, fp);
if (verbose > 1) {
printed += dso__fprintf(pos->dso, type, fp);
printed += fprintf(fp, "--\n");
}
}
return printed;
}
static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
{
size_t printed = 0, i;
for (i = 0; i < MAP__NR_TYPES; ++i)
printed += __map_groups__fprintf_removed_maps(self, i, fp);
return printed;
}
static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
{
size_t printed = map_groups__fprintf_maps(self, fp);
printed += fprintf(fp, "Removed maps:\n");
return printed + map_groups__fprintf_removed_maps(self, fp);
}
static size_t thread__fprintf(struct thread *self, FILE *fp)
{
return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
map_groups__fprintf(&self->mg, fp);
map_groups__fprintf(&self->mg, verbose, fp);
}
struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
......@@ -214,87 +124,12 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
return th;
}
static int map_groups__fixup_overlappings(struct map_groups *self,
struct map *map)
{
struct rb_root *root = &self->maps[map->type];
struct rb_node *next = rb_first(root);
while (next) {
struct map *pos = rb_entry(next, struct map, rb_node);
next = rb_next(&pos->rb_node);
if (!map__overlap(pos, map))
continue;
if (verbose >= 2) {
fputs("overlapping maps:\n", stderr);
map__fprintf(map, stderr);
map__fprintf(pos, stderr);
}
rb_erase(&pos->rb_node, root);
/*
* We may have references to this map, for instance in some
* hist_entry instances, so just move them to a separate
* list.
*/
list_add_tail(&pos->node, &self->removed_maps[map->type]);
/*
* Now check if we need to create new maps for areas not
* overlapped by the new map:
*/
if (map->start > pos->start) {
struct map *before = map__clone(pos);
if (before == NULL)
return -ENOMEM;
before->end = map->start - 1;
map_groups__insert(self, before);
if (verbose >= 2)
map__fprintf(before, stderr);
}
if (map->end < pos->end) {
struct map *after = map__clone(pos);
if (after == NULL)
return -ENOMEM;
after->start = map->end + 1;
map_groups__insert(self, after);
if (verbose >= 2)
map__fprintf(after, stderr);
}
}
return 0;
}
void thread__insert_map(struct thread *self, struct map *map)
{
map_groups__fixup_overlappings(&self->mg, map);
map_groups__fixup_overlappings(&self->mg, map, verbose, stderr);
map_groups__insert(&self->mg, map);
}
/*
* XXX This should not really _copy_ te maps, but refcount them.
*/
static int map_groups__clone(struct map_groups *self,
struct map_groups *parent, enum map_type type)
{
struct rb_node *nd;
for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
struct map *map = rb_entry(nd, struct map, rb_node);
struct map *new = map__clone(map);
if (new == NULL)
return -ENOMEM;
map_groups__insert(self, new);
}
return 0;
}
int thread__fork(struct thread *self, struct thread *parent)
{
int i;
......
......@@ -42,12 +42,14 @@
#define _ALL_SOURCE 1
#define _GNU_SOURCE 1
#define _BSD_SOURCE 1
#define HAS_BOOL
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
......@@ -78,6 +80,7 @@
#include <pwd.h>
#include <inttypes.h>
#include "../../../include/linux/magic.h"
#include "types.h"
#ifndef NO_ICONV
......@@ -415,4 +418,13 @@ void git_qsort(void *base, size_t nmemb, size_t size,
int mkdir_p(char *path, mode_t mode);
int copyfile(const char *from, const char *to);
s64 perf_atoll(const char *str);
char **argv_split(const char *str, int *argcp);
void argv_free(char **argv);
bool strglobmatch(const char *str, const char *pat);
bool strlazymatch(const char *str, const char *pat);
#define _STR(x) #x
#define STR(x) _STR(x)
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册