perf hist: Replace ->print() routines by ->snprintf() equivalents
Then hist_entry__fprintf will just us the newly introduced hist_entry__snprintf, add the newline and fprintf it to the supplied FILE descriptor. This allows us to remove the use_browser checking in the color_printf routines, that now got color_snprintf variants too. The newt TUI browser (and other GUIs that may come in the future) don't have to worry about stdio specific stuff in the strings they get from the se->snprintf routines and instead use whatever means to do the equivalent. Also the newt TUI browser don't have to use the fmemopen() hack, instead it can use the se->snprintf routines directly. For now tho use the hist_entry__snprintf routine to reduce the patch size. Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
70162138c9
commit
a4e3b956a8
@ -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);
|
||||
|
||||
|
@ -455,16 +455,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;
|
||||
@ -477,17 +478,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) {
|
||||
@ -507,9 +513,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)
|
||||
@ -518,9 +524,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,11 +534,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,
|
||||
|
@ -18,11 +18,16 @@ 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 *);
|
||||
|
||||
u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples);
|
||||
|
@ -294,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];
|
||||
|
||||
@ -357,7 +314,7 @@ 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)
|
||||
|
@ -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;
|
||||
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 = '.';
|
||||
}
|
||||
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]");
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user