Skip to content

Commit 657ee55

Browse files
liu-song-6acmel
authored andcommitted
perf evlist: Introduce side band thread
This patch introduces side band thread that captures extended information for events like PERF_RECORD_BPF_EVENT. This new thread uses its own evlist that uses ring buffer with very low watermark for lower latency. To use side band thread, we need to: 1. add side band event(s) by calling perf_evlist__add_sb_event(); 2. calls perf_evlist__start_sb_thread(); 3. at the end of perf run, perf_evlist__stop_sb_thread(). In the next patch, we use this thread to handle PERF_RECORD_BPF_EVENT. Committer notes: Add fix by Jiri Olsa for when te sb_tread can't get started and then at the end the stop_sb_thread() segfaults when joining the (non-existing) thread. That can happen when running 'perf top' or 'perf record' as a normal user, for instance. Further checks need to be done on top of this to more graciously handle these possible failure scenarios. Signed-off-by: Song Liu <songliubraving@fb.com> Reviewed-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stanislav Fomichev <sdf@google.com> Link: http://lkml.kernel.org/r/20190312053051.2690567-15-songliubraving@fb.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 6987561 commit 657ee55

File tree

5 files changed

+155
-0
lines changed

5 files changed

+155
-0
lines changed

tools/perf/builtin-record.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
11371137
struct perf_data *data = &rec->data;
11381138
struct perf_session *session;
11391139
bool disabled = false, draining = false;
1140+
struct perf_evlist *sb_evlist = NULL;
11401141
int fd;
11411142

11421143
atexit(record__sig_exit);
@@ -1237,6 +1238,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
12371238
goto out_child;
12381239
}
12391240

1241+
if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target)) {
1242+
pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
1243+
opts->no_bpf_event = true;
1244+
}
1245+
12401246
err = record__synthesize(rec, false);
12411247
if (err < 0)
12421248
goto out_child;
@@ -1487,6 +1493,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
14871493

14881494
out_delete_session:
14891495
perf_session__delete(session);
1496+
1497+
if (!opts->no_bpf_event)
1498+
perf_evlist__stop_sb_thread(sb_evlist);
14901499
return status;
14911500
}
14921501

tools/perf/builtin-top.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,7 @@ int cmd_top(int argc, const char **argv)
15011501
"number of thread to run event synthesize"),
15021502
OPT_END()
15031503
};
1504+
struct perf_evlist *sb_evlist = NULL;
15041505
const char * const top_usage[] = {
15051506
"perf top [<options>]",
15061507
NULL
@@ -1636,8 +1637,16 @@ int cmd_top(int argc, const char **argv)
16361637
goto out_delete_evlist;
16371638
}
16381639

1640+
if (perf_evlist__start_sb_thread(sb_evlist, target)) {
1641+
pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
1642+
opts->no_bpf_event = true;
1643+
}
1644+
16391645
status = __cmd_top(&top);
16401646

1647+
if (!opts->no_bpf_event)
1648+
perf_evlist__stop_sb_thread(sb_evlist);
1649+
16411650
out_delete_evlist:
16421651
perf_evlist__delete(top.evlist);
16431652
perf_session__delete(top.session);

tools/perf/util/evlist.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "debug.h"
2020
#include "units.h"
2121
#include "asm/bug.h"
22+
#include "bpf-event.h"
2223
#include <signal.h>
2324
#include <unistd.h>
2425

@@ -1856,3 +1857,121 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
18561857
}
18571858
return leader;
18581859
}
1860+
1861+
int perf_evlist__add_sb_event(struct perf_evlist **evlist,
1862+
struct perf_event_attr *attr,
1863+
perf_evsel__sb_cb_t cb,
1864+
void *data)
1865+
{
1866+
struct perf_evsel *evsel;
1867+
bool new_evlist = (*evlist) == NULL;
1868+
1869+
if (*evlist == NULL)
1870+
*evlist = perf_evlist__new();
1871+
if (*evlist == NULL)
1872+
return -1;
1873+
1874+
if (!attr->sample_id_all) {
1875+
pr_warning("enabling sample_id_all for all side band events\n");
1876+
attr->sample_id_all = 1;
1877+
}
1878+
1879+
evsel = perf_evsel__new_idx(attr, (*evlist)->nr_entries);
1880+
if (!evsel)
1881+
goto out_err;
1882+
1883+
evsel->side_band.cb = cb;
1884+
evsel->side_band.data = data;
1885+
perf_evlist__add(*evlist, evsel);
1886+
return 0;
1887+
1888+
out_err:
1889+
if (new_evlist) {
1890+
perf_evlist__delete(*evlist);
1891+
*evlist = NULL;
1892+
}
1893+
return -1;
1894+
}
1895+
1896+
static void *perf_evlist__poll_thread(void *arg)
1897+
{
1898+
struct perf_evlist *evlist = arg;
1899+
bool draining = false;
1900+
int i;
1901+
1902+
while (draining || !(evlist->thread.done)) {
1903+
if (draining)
1904+
draining = false;
1905+
else if (evlist->thread.done)
1906+
draining = true;
1907+
1908+
if (!draining)
1909+
perf_evlist__poll(evlist, 1000);
1910+
1911+
for (i = 0; i < evlist->nr_mmaps; i++) {
1912+
struct perf_mmap *map = &evlist->mmap[i];
1913+
union perf_event *event;
1914+
1915+
if (perf_mmap__read_init(map))
1916+
continue;
1917+
while ((event = perf_mmap__read_event(map)) != NULL) {
1918+
struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
1919+
1920+
if (evsel && evsel->side_band.cb)
1921+
evsel->side_band.cb(event, evsel->side_band.data);
1922+
else
1923+
pr_warning("cannot locate proper evsel for the side band event\n");
1924+
1925+
perf_mmap__consume(map);
1926+
}
1927+
perf_mmap__read_done(map);
1928+
}
1929+
}
1930+
return NULL;
1931+
}
1932+
1933+
int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
1934+
struct target *target)
1935+
{
1936+
struct perf_evsel *counter;
1937+
1938+
if (!evlist)
1939+
return 0;
1940+
1941+
if (perf_evlist__create_maps(evlist, target))
1942+
goto out_delete_evlist;
1943+
1944+
evlist__for_each_entry(evlist, counter) {
1945+
if (perf_evsel__open(counter, evlist->cpus,
1946+
evlist->threads) < 0)
1947+
goto out_delete_evlist;
1948+
}
1949+
1950+
if (perf_evlist__mmap(evlist, UINT_MAX))
1951+
goto out_delete_evlist;
1952+
1953+
evlist__for_each_entry(evlist, counter) {
1954+
if (perf_evsel__enable(counter))
1955+
goto out_delete_evlist;
1956+
}
1957+
1958+
evlist->thread.done = 0;
1959+
if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
1960+
goto out_delete_evlist;
1961+
1962+
return 0;
1963+
1964+
out_delete_evlist:
1965+
perf_evlist__delete(evlist);
1966+
evlist = NULL;
1967+
return -1;
1968+
}
1969+
1970+
void perf_evlist__stop_sb_thread(struct perf_evlist *evlist)
1971+
{
1972+
if (!evlist)
1973+
return;
1974+
evlist->thread.done = 1;
1975+
pthread_join(evlist->thread.th, NULL);
1976+
perf_evlist__delete(evlist);
1977+
}

tools/perf/util/evlist.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ struct perf_evlist {
5454
struct perf_sample *sample);
5555
u64 first_sample_time;
5656
u64 last_sample_time;
57+
struct {
58+
pthread_t th;
59+
volatile int done;
60+
} thread;
5761
};
5862

5963
struct perf_evsel_str_handler {
@@ -87,6 +91,14 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
8791

8892
int perf_evlist__add_dummy(struct perf_evlist *evlist);
8993

94+
int perf_evlist__add_sb_event(struct perf_evlist **evlist,
95+
struct perf_event_attr *attr,
96+
perf_evsel__sb_cb_t cb,
97+
void *data);
98+
int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
99+
struct target *target);
100+
void perf_evlist__stop_sb_thread(struct perf_evlist *evlist);
101+
90102
int perf_evlist__add_newtp(struct perf_evlist *evlist,
91103
const char *sys, const char *name, void *handler);
92104

tools/perf/util/evsel.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ struct perf_evsel_config_term {
7373

7474
struct perf_stat_evsel;
7575

76+
typedef int (perf_evsel__sb_cb_t)(union perf_event *event, void *data);
77+
7678
/** struct perf_evsel - event selector
7779
*
7880
* @evlist - evlist this evsel is in, if it is in one.
@@ -151,6 +153,10 @@ struct perf_evsel {
151153
bool collect_stat;
152154
bool weak_group;
153155
const char *pmu_name;
156+
struct {
157+
perf_evsel__sb_cb_t *cb;
158+
void *data;
159+
} side_band;
154160
};
155161

156162
union u64_swap {

0 commit comments

Comments
 (0)