perf top: Show warning in display thread
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 389da42..751282f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -149,18 +149,22 @@ static void __zero_source_counters(struct hist_entry *he)
symbol__annotate_zero_histograms(sym);
}
-static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip)
+static void perf_top__init_warning(struct perf_top *top)
{
- char *warn_msg;
+ pthread_mutex_init(&top->warning.lock, NULL);
+ top->warning.code = PERF_TOP_WARN__NONE;
+}
- warn_msg = perf_top__warn_map_erange(map, sym, ip);
- ui__warning("%s", warn_msg ?: "Out of bounds address found\n");
- free(warn_msg);
-
- if (use_browser <= 0)
- sleep(5);
-
- map->erange_warned = true;
+static void perf_top__set_warning(struct perf_top *top,
+ enum perf_top_warning code,
+ struct map *map, struct symbol *sym, u64 ip)
+{
+ pthread_mutex_lock(&top->warning.lock);
+ top->warning.code = code;
+ top->warning.map = map;
+ top->warning.sym = sym;
+ top->warning.ip = ip;
+ pthread_mutex_unlock(&top->warning.lock);
}
static void perf_top__record_precise_ip(struct perf_top *top,
@@ -193,9 +197,11 @@ static void perf_top__record_precise_ip(struct perf_top *top,
*/
pthread_mutex_unlock(&he->hists->lock);
- if (err == -ERANGE && !he->ms.map->erange_warned)
- ui__warn_map_erange(he->ms.map, sym, ip);
- else if (err == -ENOMEM) {
+ if (err == -ERANGE && !he->ms.map->erange_warned) {
+ perf_top__set_warning(top, PERF_TOP_WARN__MAP_ERANGE,
+ he->ms.map, sym, ip);
+ he->ms.map->erange_warned = true;
+ } else if (err == -ENOMEM) {
pr_err("Not enough memory for annotating '%s' symbol!\n",
sym->name);
}
@@ -714,14 +720,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
symbol_conf.kptr_restrict &&
al.cpumode == PERF_RECORD_MISC_KERNEL) {
if (!perf_evlist__exclude_kernel(top->session->evlist)) {
- char *warn_msg;
-
- warn_msg = perf_top__warn_kptr_restrict(al.map);
- ui__warning("%s", warn_msg ?: "Kernel maps are restricted.\n");
- free(warn_msg);
-
- if (use_browser <= 0)
- sleep(5);
+ perf_top__set_warning(top, PERF_TOP_WARN__KPTR_RESTRICT,
+ al.map, NULL, 0);
}
machine->kptr_restrict_warned = true;
}
@@ -740,14 +740,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
*/
if (!machine->kptr_restrict_warned && !top->vmlinux_warned &&
__map__is_kernel(al.map) && map__has_symbols(al.map)) {
- char *warn_msg;
-
- warn_msg = perf_top__warn_vmlinux(al.map);
- ui__warning("%s", warn_msg ?: "Kernel symbols will not be resolved.\n");
- free(warn_msg);
-
- if (use_browser <= 0)
- sleep(5);
+ perf_top__set_warning(top, PERF_TOP_WARN__VMLINUX,
+ al.map, NULL, 0);
top->vmlinux_warned = true;
}
}
@@ -875,11 +869,8 @@ static void perf_top__mmap_read(struct perf_top *top)
end = rdclock();
if ((end - start) > (unsigned long long)top->delay_secs * NSEC_PER_SEC) {
- char *warn_msg;
-
- warn_msg = perf_top__warn_mmap_read();
- ui__warning("%s", warn_msg ?: "Too slow to read ring buffer.\n");
- free(warn_msg);
+ perf_top__set_warning(top, PERF_TOP_WARN__MMAP_READ,
+ NULL, NULL, 0);
}
}
@@ -1493,6 +1484,8 @@ int cmd_top(int argc, const char **argv)
signal(SIGWINCH, winch_sig);
}
+ perf_top__init_warning(&top);
+
status = __cmd_top(&top);
out_delete_evlist:
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a96f62c..e20ed33 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -606,6 +606,73 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
"Or reduce the sampling frequency.");
}
+static void ui_browser__perf_top_warn(struct ui_browser *browser,
+ struct perf_top *top)
+{
+ enum perf_top_warning code;
+ struct map *map;
+ struct symbol *sym;
+ u64 ip;
+ const char *msg;
+ bool alloc = true;
+
+ pthread_mutex_lock(&top->warning.lock);
+ code = top->warning.code;
+ map = top->warning.map;
+ sym = top->warning.sym;
+ ip = top->warning.ip;
+
+ top->warning.code = PERF_TOP_WARN__NONE;
+ pthread_mutex_unlock(&top->warning.lock);
+
+ if (code == PERF_TOP_WARN__NONE)
+ return;
+
+ switch (code) {
+ case PERF_TOP_WARN__MAP_ERANGE:
+ msg = perf_top__warn_map_erange(map, sym, ip);
+ if (msg == NULL) {
+ msg = "Out of bounds address found.\n";
+ alloc = false;
+ }
+ break;
+
+ case PERF_TOP_WARN__KPTR_RESTRICT:
+ msg = perf_top__warn_kptr_restrict(map);
+ if (msg == NULL) {
+ msg = "Kernel maps are restricted.\n";
+ alloc = false;
+ }
+ break;
+
+ case PERF_TOP_WARN__VMLINUX:
+ msg = perf_top__warn_vmlinux(map);
+ if (msg == NULL) {
+ msg = "Kernel symbols will not be resolved.\n";
+ alloc = false;
+ }
+ break;
+
+ case PERF_TOP_WARN__MMAP_READ:
+ msg = perf_top__warn_mmap_read();
+ if (msg == NULL) {
+ msg = "Too slow to read ring buffer.\n";
+ alloc = false;
+ }
+ break;
+
+ case PERF_TOP_WARN__NONE:
+ case PERF_TOP_WARN__MAX:
+ default:
+ return;
+ }
+
+ ui_browser__warning(browser, 5, "%s", msg);
+
+ if (alloc)
+ free((void *)msg);
+}
+
static int hist_browser__title(struct hist_browser *browser, char *bf, size_t size)
{
return browser->title ? browser->title(browser, bf, size) : 0;
@@ -642,6 +709,11 @@ int hist_browser__run(struct hist_browser *browser, const char *help,
nr_entries = hist_browser__nr_entries(browser);
ui_browser__update_nr_entries(&browser->b, nr_entries);
+ hist_browser__title(browser, title, sizeof(title));
+ ui_browser__show_title(&browser->b, title);
+
+ ui_browser__perf_top_warn(&browser->b, hbt->arg);
+
if (warn_lost_event &&
(browser->hists->stats.nr_lost_warned !=
browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
@@ -650,8 +722,6 @@ int hist_browser__run(struct hist_browser *browser, const char *help,
ui_browser__warn_lost_events(&browser->b);
}
- hist_browser__title(browser, title, sizeof(title));
- ui_browser__show_title(&browser->b, title);
continue;
}
case 'D': { /* Debug */
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 5a5a98a..0dd80ae 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -13,6 +13,16 @@ struct perf_evlist;
struct perf_evsel;
struct perf_session;
+enum perf_top_warning {
+ PERF_TOP_WARN__NONE = 0,
+ PERF_TOP_WARN__MAP_ERANGE,
+ PERF_TOP_WARN__KPTR_RESTRICT,
+ PERF_TOP_WARN__VMLINUX,
+ PERF_TOP_WARN__MMAP_READ,
+
+ PERF_TOP_WARN__MAX,
+};
+
struct perf_top {
struct perf_tool tool;
struct perf_evlist *evlist;
@@ -40,6 +50,14 @@ struct perf_top {
const char *sym_filter;
float min_percent;
unsigned int nr_threads_synthesize;
+
+ struct {
+ pthread_mutex_t lock;
+ enum perf_top_warning code;
+ struct map *map;
+ struct symbol *sym;
+ u64 ip;
+ } warning;
};
#define CONSOLE_CLEAR "[H[2J"