2017-12-05 22:41:32

by Liang, Kan

[permalink] [raw]
Subject: [PATCH 0/5] perf top overwrite mode

From: Kan Liang <[email protected]>

perf_top__mmap_read has severe performance issue in
Knights Landing/Mill, when monitoring in heavy load system. It costs
several minutes to finish, which is unacceptable.

Currently, perf top is non overwrite mode. For non overwrite mode, it
tries to read everything in the ringbuffer and doesn't pause the
ringbuffer. Once there are lots of samples delivered persistently,
the processing time could be very long. Also, the latest samples could
be lost when the ringbuffer is full.

It's better to change it to overwrite mode, which takes a snapshot for
the system by pausing the ringbuffer and could significantly reducing
the processing time (from several minutes to several seconds).
Also, the overwrite mode always keep the latest samples.

Patch 1-3: Modify perf_mmap__read_catchup and perf_mmap__read_backward.
Make them ready for overwrite mode
Patch 4: Swith perf top to overwrite mode
Patch 5: The latency could be still higher than refresh time in some
extreme cases. Give user some hints to reduce the latency.

Kan Liang (5):
perf tools: remove stale perf evlist mmap read for backward
perf tools: rewrite perf mmap read for overwrite
perf tools: reuse perf_mmap__read_catchup in perf_mmap__push
perf top: switch to overwrite mode
perf top: check the latency of perf_top__mmap_read

tools/perf/builtin-top.c | 40 ++++++-----
tools/perf/tests/backward-ring-buffer.c | 9 ++-
tools/perf/ui/browsers/hists.c | 12 +++-
tools/perf/util/evlist.c | 17 -----
tools/perf/util/evlist.h | 4 --
tools/perf/util/mmap.c | 119 +++++++++++++++-----------------
tools/perf/util/mmap.h | 7 +-
7 files changed, 102 insertions(+), 106 deletions(-)

--
2.5.5


2017-12-05 22:40:16

by Liang, Kan

[permalink] [raw]
Subject: [PATCH 3/5] perf tools: reuse perf_mmap__read_catchup in perf_mmap__push

From: Kan Liang <[email protected]>

perf_mmap__push uses the same codes as perf_mmap__read_catchup to
calculate the ring buffer start, end and size.

No funcational change.

Signed-off-by: Kan Liang <[email protected]>
---
tools/perf/util/mmap.c | 31 ++++++-------------------------
1 file changed, 6 insertions(+), 25 deletions(-)

diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
index bf67460..61237eb 100644
--- a/tools/perf/util/mmap.c
+++ b/tools/perf/util/mmap.c
@@ -285,36 +285,16 @@ int perf_mmap__push(struct perf_mmap *md, bool overwrite,
void *to, int push(void *to, void *buf, size_t size))
{
u64 head = perf_mmap__read_head(md);
- u64 old = md->prev;
- u64 end = head, start = old;
+ u64 end, start;
unsigned char *data = md->base + page_size;
unsigned long size;
void *buf;
- int rc = 0;
+ int rc;

- start = overwrite ? head : old;
- end = overwrite ? old : head;

- if (start == end)
- return 0;
-
- size = end - start;
- if (size > (unsigned long)(md->mask) + 1) {
- if (!overwrite) {
- WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
-
- md->prev = head;
- perf_mmap__consume(md, overwrite);
- return 0;
- }
-
- /*
- * Backward ring buffer is full. We still have a chance to read
- * most of data from it.
- */
- if (overwrite_rb_find_range(data, md->mask, head, &start, &end))
- return -1;
- }
+ rc = perf_mmap__read_catchup(md, overwrite, &start, &end, &size);
+ if (rc < 1)
+ return rc;

if ((start & md->mask) + size != (end & md->mask)) {
buf = &data[start & md->mask];
@@ -338,6 +318,7 @@ int perf_mmap__push(struct perf_mmap *md, bool overwrite,

md->prev = head;
perf_mmap__consume(md, overwrite);
+ rc = 0;
out:
return rc;
}
--
2.5.5

2017-12-05 22:40:19

by Liang, Kan

[permalink] [raw]
Subject: [PATCH 4/5] perf top: switch to overwrite mode

From: Kan Liang <[email protected]>

perf_top__mmap_read has severe performance issue in
Knights Landing/Mill, when monitoring in heavy load system. It costs
several minutes to finish, which is unacceptable.

Currently, perf top is non overwrite mode. For non overwrite mode, it
tries to read everything in the ringbuffer and doesn't pause the
ringbuffer. Once there are lots of samples delivered persistently,
the processing time could be very long. Also, the latest samples could
be lost when the ringbuffer is full.

For overwrite mode, it takes a snapshot for the system by pausing the
ringbuffer, which could significantly reducing the processing time.
Also, the overwrite mode always keep the latest samples.
Considering the real time requirement for perf top, the overwrite mode
is more suitable for perf top.

Actually, perf top was overwrite mode. It is changed to non overwrite
mode since commit 93fc64f14472 ("perf top: Switch to non overwrite
mode"). It's better to change it back to overwrite mode.

There would be some records lost in overwrite mode because of pausing
the ringbuffer. It has little impact for the accuracy of the snapshot
and could be tolerant.
The lost events checking is removed.

Unconditionally wait 100 ms before each snapshot. It also reduce the
overhead caused by pausing ringbuffer, especially on light load system.

Signed-off-by: Kan Liang <[email protected]>
---
tools/perf/builtin-top.c | 30 ++++++++++++++----------------
tools/perf/ui/browsers/hists.c | 12 +++++++++---
2 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 540461f..721d786 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -283,16 +283,6 @@ static void perf_top__print_sym_table(struct perf_top *top)

printf("%-*.*s\n", win_width, win_width, graph_dotted_line);

- if (hists->stats.nr_lost_warned !=
- hists->stats.nr_events[PERF_RECORD_LOST]) {
- hists->stats.nr_lost_warned =
- hists->stats.nr_events[PERF_RECORD_LOST];
- color_fprintf(stdout, PERF_COLOR_RED,
- "WARNING: LOST %d chunks, Check IO/CPU overload",
- hists->stats.nr_lost_warned);
- ++printed;
- }
-
if (top->sym_filter_entry) {
perf_top__show_details(top);
return;
@@ -807,14 +797,19 @@ static void perf_event__process_sample(struct perf_tool *tool,

static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
{
+ struct perf_mmap *md = &top->evlist->overwrite_mmap[idx];
struct perf_sample sample;
struct perf_evsel *evsel;
struct perf_session *session = top->session;
union perf_event *event;
struct machine *machine;
+ unsigned long size;
+ u64 end, start;
int ret;

- while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
+ perf_mmap__read_catchup(md, true, &start, &end, &size);
+
+ while ((event = perf_mmap__read_backward(md, &start, end)) != NULL) {
ret = perf_evlist__parse_sample(top->evlist, event, &sample);
if (ret) {
pr_err("Can't parse sample, err = %d\n", ret);
@@ -869,16 +864,21 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
} else
++session->evlist->stats.nr_unknown_events;
next_event:
- perf_evlist__mmap_consume(top->evlist, idx);
+ perf_mmap__consume(md, true);
}
+
+ perf_mmap__read_done(md);
}

static void perf_top__mmap_read(struct perf_top *top)
{
int i;

+ perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_DATA_PENDING);
for (i = 0; i < top->evlist->nr_mmaps; i++)
perf_top__mmap_read_idx(top, i);
+ perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_EMPTY);
+ perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_RUNNING);
}

static int perf_top__start_counters(struct perf_top *top)
@@ -1029,12 +1029,9 @@ static int __cmd_top(struct perf_top *top)
}

while (!done) {
- u64 hits = top->samples;
-
perf_top__mmap_read(top);

- if (hits == top->samples)
- ret = perf_evlist__poll(top->evlist, 100);
+ ret = perf_evlist__poll(top->evlist, 100);

if (resize) {
perf_top__resize(top);
@@ -1127,6 +1124,7 @@ int cmd_top(int argc, const char **argv)
.uses_mmap = true,
},
.proc_map_timeout = 500,
+ .overwrite = 1,
},
.max_stack = sysctl_perf_event_max_stack,
.sym_pcnt_filter = 5,
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 68146f4..56023e4 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -638,8 +638,13 @@ 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);

- if (browser->hists->stats.nr_lost_warned !=
- browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
+ /*
+ * Don't print lost events warning for perf top,
+ * because it is overwrite mode.
+ * Perf top is the only tool which has hbt timer.
+ */
+ if ((browser->hists->stats.nr_lost_warned !=
+ browser->hists->stats.nr_events[PERF_RECORD_LOST]) && !hbt) {
browser->hists->stats.nr_lost_warned =
browser->hists->stats.nr_events[PERF_RECORD_LOST];
ui_browser__warn_lost_events(&browser->b);
@@ -3203,7 +3208,8 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
case K_TIMER:
hbt->timer(hbt->arg);

- if (!menu->lost_events_warned && menu->lost_events) {
+ if (!menu->lost_events_warned &&
+ menu->lost_events && !hbt) {
ui_browser__warn_lost_events(&menu->b);
menu->lost_events_warned = true;
}
--
2.5.5

2017-12-05 22:40:59

by Liang, Kan

[permalink] [raw]
Subject: [PATCH 5/5] perf top: check the latency of perf_top__mmap_read

From: Kan Liang <[email protected]>

The latency of perf_top__mmap_read should be lower than refresh time.
If not, give some hints to reduce the latency.

Signed-off-by: Kan Liang <[email protected]>
---
tools/perf/builtin-top.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 721d786..f36936c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -872,13 +872,23 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)

static void perf_top__mmap_read(struct perf_top *top)
{
+ unsigned long long start, end;
int i;

+ start = rdclock();
perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_DATA_PENDING);
for (i = 0; i < top->evlist->nr_mmaps; i++)
perf_top__mmap_read_idx(top, i);
perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_EMPTY);
perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_RUNNING);
+ end = rdclock();
+
+ if ((end - start) > (unsigned long long)top->delay_secs * NSEC_PER_SEC)
+ ui__warning("Too slow to read ring buffer.\n"
+ "Please try increasing the period (-c) or\n"
+ "decreasing the freq (-F) or\n"
+ "limiting the number of CPUs (-C)\n");
+
}

static int perf_top__start_counters(struct perf_top *top)
--
2.5.5

2017-12-05 22:41:16

by Liang, Kan

[permalink] [raw]
Subject: [PATCH 2/5] perf tools: rewrite perf mmap read for overwrite

From: Kan Liang <[email protected]>

perf_mmap__read_catchup and perf_mmap__read_backward are used to read
events one by one from ring buffer under overwrite mode.
It always read the stale buffer which is already processed.
Because the previous location of processed ring buffer is discarded.

Introducing the perf_mmap__read_done, which update the map->prev to
indicate the position of processed buffer.

Refining perf_mmap__read_catchup to calculate the start and the end of
ring buffer. It only need to do the calculation once at the beginning,
because the ring buffer is paused in overwrite mode.
Doesn't need to do the calculation in perf_mmap__read_backward.

For now, the only user is backward-ring-buffer in perf test.

Signed-off-by: Kan Liang <[email protected]>
---
tools/perf/tests/backward-ring-buffer.c | 9 +++-
tools/perf/util/mmap.c | 88 +++++++++++++++++++--------------
tools/perf/util/mmap.h | 7 ++-
3 files changed, 63 insertions(+), 41 deletions(-)

diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
index 4035d43..66d9e54 100644
--- a/tools/perf/tests/backward-ring-buffer.c
+++ b/tools/perf/tests/backward-ring-buffer.c
@@ -31,10 +31,14 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count,
int i;

for (i = 0; i < evlist->nr_mmaps; i++) {
+ struct perf_mmap *map = &evlist->overwrite_mmap[i];
union perf_event *event;
+ unsigned long size;
+ u64 start, end;

- perf_mmap__read_catchup(&evlist->overwrite_mmap[i]);
- while ((event = perf_mmap__read_backward(&evlist->overwrite_mmap[i])) != NULL) {
+ perf_mmap__read_catchup(map, true, &start, &end, &size);
+ while ((event = perf_mmap__read_backward(map, &start, end)) !=
+ NULL) {
const u32 type = event->header.type;

switch (type) {
@@ -49,6 +53,7 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count,
return TEST_FAIL;
}
}
+ perf_mmap__read_done(map);
}
return TEST_OK;
}
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
index 05076e6..bf67460 100644
--- a/tools/perf/util/mmap.c
+++ b/tools/perf/util/mmap.c
@@ -85,51 +85,65 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *map)
return perf_mmap__read(map, old, head, &map->prev);
}

-union perf_event *perf_mmap__read_backward(struct perf_mmap *map)
+union perf_event *perf_mmap__read_backward(struct perf_mmap *map,
+ u64 *start, u64 end)
{
- u64 head, end;
- u64 start = map->prev;
-
- /*
- * Check if event was unmapped due to a POLLHUP/POLLERR.
- */
- if (!refcount_read(&map->refcnt))
- return NULL;
-
- head = perf_mmap__read_head(map);
- if (!head)
- return NULL;
+ union perf_event *event = NULL;

- /*
- * 'head' pointer starts from 0. Kernel minus sizeof(record) form
- * it each time when kernel writes to it, so in fact 'head' is
- * negative. 'end' pointer is made manually by adding the size of
- * the ring buffer to 'head' pointer, means the validate data can
- * read is the whole ring buffer. If 'end' is positive, the ring
- * buffer has not fully filled, so we must adjust 'end' to 0.
- *
- * However, since both 'head' and 'end' is unsigned, we can't
- * simply compare 'end' against 0. Here we compare '-head' and
- * the size of the ring buffer, where -head is the number of bytes
- * kernel write to the ring buffer.
- */
- if (-head < (u64)(map->mask + 1))
- end = 0;
- else
- end = head + map->mask + 1;
+ event = perf_mmap__read(map, *start, end, &map->prev);
+ *start = map->prev;

- return perf_mmap__read(map, start, end, &map->prev);
+ return event;
}

-void perf_mmap__read_catchup(struct perf_mmap *map)
+static int overwrite_rb_find_range(void *buf, int mask, u64 head,
+ u64 *start, u64 *end);
+
+int perf_mmap__read_catchup(struct perf_mmap *map,
+ bool overwrite,
+ u64 *start, u64 *end,
+ unsigned long *size)
{
- u64 head;
+ u64 head = perf_mmap__read_head(map);
+ u64 old = map->prev;
+ unsigned char *data = map->base + page_size;

- if (!refcount_read(&map->refcnt))
- return;
+ *start = overwrite ? head : old;
+ *end = overwrite ? old : head;

- head = perf_mmap__read_head(map);
- map->prev = head;
+ if (*start == *end)
+ return 0;
+
+ *size = *end - *start;
+ if (*size > (unsigned long)(map->mask) + 1) {
+ if (!overwrite) {
+ WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
+
+ map->prev = head;
+ perf_mmap__consume(map, overwrite);
+ return 0;
+ }
+
+ /*
+ * Backward ring buffer is full. We still have a chance to read
+ * most of data from it.
+ */
+ if (overwrite_rb_find_range(data, map->mask, head, start, end))
+ return -1;
+ }
+
+ return 1;
+}
+
+/*
+ * Mandatory for overwrite mode
+ * The direction of overwrite mode is backward.
+ * The last mmap__read_event will set tail to map->prev.
+ * Need to correct the map->prev to head which is the end of next read.
+ */
+void perf_mmap__read_done(struct perf_mmap *map)
+{
+ map->prev = perf_mmap__read_head(map);
}

static bool perf_mmap__empty(struct perf_mmap *map)
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
index d640273..a91222e 100644
--- a/tools/perf/util/mmap.h
+++ b/tools/perf/util/mmap.h
@@ -65,7 +65,9 @@ void perf_mmap__put(struct perf_mmap *map);

void perf_mmap__consume(struct perf_mmap *map, bool overwrite);

-void perf_mmap__read_catchup(struct perf_mmap *md);
+int perf_mmap__read_catchup(struct perf_mmap *map, bool overwrite,
+ u64 *start, u64 *end, unsigned long *size);
+void perf_mmap__read_done(struct perf_mmap *map);

static inline u64 perf_mmap__read_head(struct perf_mmap *mm)
{
@@ -87,7 +89,8 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail)
}

union perf_event *perf_mmap__read_forward(struct perf_mmap *map);
-union perf_event *perf_mmap__read_backward(struct perf_mmap *map);
+union perf_event *perf_mmap__read_backward(struct perf_mmap *map,
+ u64 *start, u64 end);

int perf_mmap__push(struct perf_mmap *md, bool backward,
void *to, int push(void *to, void *buf, size_t size));
--
2.5.5

2017-12-05 22:41:29

by Liang, Kan

[permalink] [raw]
Subject: [PATCH 1/5] perf tools: remove stale perf evlist mmap read for backward

From: Kan Liang <[email protected]>

perf_evlist__mmap_read_catchup and perf_evlist__mmap_read_backward are
only for overwrite mode.
But they read the evlist->mmap buffer which is for non-overwrite mode.

It did not bring any serious problem yet, because there is no one use
it.

Remove the unused interfaces.

Signed-off-by: Kan Liang <[email protected]>
---
tools/perf/util/evlist.c | 17 -----------------
tools/perf/util/evlist.h | 4 ----
2 files changed, 21 deletions(-)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3570355..4b6a06d 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -714,28 +714,11 @@ union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int
return perf_mmap__read_forward(md);
}

-union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx)
-{
- struct perf_mmap *md = &evlist->mmap[idx];
-
- /*
- * No need to check messup for backward ring buffer:
- * We can always read arbitrary long data from a backward
- * ring buffer unless we forget to pause it before reading.
- */
- return perf_mmap__read_backward(md);
-}
-
union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
{
return perf_evlist__mmap_read_forward(evlist, idx);
}

-void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx)
-{
- perf_mmap__read_catchup(&evlist->mmap[idx]);
-}
-
void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
{
perf_mmap__consume(&evlist->mmap[idx], false);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 7516066..a80fd47 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -132,10 +132,6 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx);

union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist,
int idx);
-union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist,
- int idx);
-void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx);
-
void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);

int perf_evlist__open(struct perf_evlist *evlist);
--
2.5.5

2017-12-06 01:59:15

by Wang Nan

[permalink] [raw]
Subject: Re: [PATCH 4/5] perf top: switch to overwrite mode



On 2017/12/6 6:39, [email protected] wrote:
> From: Kan Liang <[email protected]>
>
> perf_top__mmap_read has severe performance issue in
> Knights Landing/Mill, when monitoring in heavy load system. It costs
> several minutes to finish, which is unacceptable.
>
> Currently, perf top is non overwrite mode. For non overwrite mode, it
> tries to read everything in the ringbuffer and doesn't pause the
> ringbuffer. Once there are lots of samples delivered persistently,
> the processing time could be very long. Also, the latest samples could
> be lost when the ringbuffer is full.
>
> For overwrite mode, it takes a snapshot for the system by pausing the
> ringbuffer, which could significantly reducing the processing time.
> Also, the overwrite mode always keep the latest samples.
> Considering the real time requirement for perf top, the overwrite mode
> is more suitable for perf top.
>
> Actually, perf top was overwrite mode. It is changed to non overwrite
> mode since commit 93fc64f14472 ("perf top: Switch to non overwrite
> mode"). It's better to change it back to overwrite mode.
>
> There would be some records lost in overwrite mode because of pausing
> the ringbuffer. It has little impact for the accuracy of the snapshot
> and could be tolerant.
> The lost events checking is removed.
>
> Unconditionally wait 100 ms before each snapshot. It also reduce the
> overhead caused by pausing ringbuffer, especially on light load system.
>
> Signed-off-by: Kan Liang <[email protected]>
> ---
> tools/perf/builtin-top.c | 30 ++++++++++++++----------------
> tools/perf/ui/browsers/hists.c | 12 +++++++++---
> 2 files changed, 23 insertions(+), 19 deletions(-)
>
> diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
> index 540461f..721d786 100644
> --- a/tools/perf/builtin-top.c
> +++ b/tools/perf/builtin-top.c
> @@ -283,16 +283,6 @@ static void perf_top__print_sym_table(struct perf_top *top)
>
> printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
>
> - if (hists->stats.nr_lost_warned !=
> - hists->stats.nr_events[PERF_RECORD_LOST]) {
> - hists->stats.nr_lost_warned =
> - hists->stats.nr_events[PERF_RECORD_LOST];
> - color_fprintf(stdout, PERF_COLOR_RED,
> - "WARNING: LOST %d chunks, Check IO/CPU overload",
> - hists->stats.nr_lost_warned);
> - ++printed;
> - }
> -
> if (top->sym_filter_entry) {
> perf_top__show_details(top);
> return;
> @@ -807,14 +797,19 @@ static void perf_event__process_sample(struct perf_tool *tool,
>
> static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
> {
> + struct perf_mmap *md = &top->evlist->overwrite_mmap[idx];
> struct perf_sample sample;
> struct perf_evsel *evsel;
> struct perf_session *session = top->session;
> union perf_event *event;
> struct machine *machine;
> + unsigned long size;
> + u64 end, start;
> int ret;
>
> - while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
> + perf_mmap__read_catchup(md, true, &start, &end, &size);
> +
> + while ((event = perf_mmap__read_backward(md, &start, end)) != NULL) {
> ret = perf_evlist__parse_sample(top->evlist, event, &sample);
> if (ret) {
> pr_err("Can't parse sample, err = %d\n", ret);
> @@ -869,16 +864,21 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
> } else
> ++session->evlist->stats.nr_unknown_events;
> next_event:
> - perf_evlist__mmap_consume(top->evlist, idx);
> + perf_mmap__consume(md, true);
> }
> +
> + perf_mmap__read_done(md);
> }
>
> static void perf_top__mmap_read(struct perf_top *top)
> {
> int i;
>
> + perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_DATA_PENDING);
> for (i = 0; i < top->evlist->nr_mmaps; i++)
> perf_top__mmap_read_idx(top, i);
> + perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_EMPTY);
> + perf_evlist__toggle_bkw_mmap(top->evlist, BKW_MMAP_RUNNING);
> }
>
> static int perf_top__start_counters(struct perf_top *top)
> @@ -1029,12 +1029,9 @@ static int __cmd_top(struct perf_top *top)
> }
>
> while (!done) {
> - u64 hits = top->samples;
> -
> perf_top__mmap_read(top);
>
> - if (hits == top->samples)
> - ret = perf_evlist__poll(top->evlist, 100);
> + ret = perf_evlist__poll(top->evlist, 100);
>
> if (resize) {
> perf_top__resize(top);
> @@ -1127,6 +1124,7 @@ int cmd_top(int argc, const char **argv)
> .uses_mmap = true,
> },
> .proc_map_timeout = 500,
> + .overwrite = 1,

This breaks old kernel:

# ./perf top
Error:
Reading from overwrite event is not supported by this kernel.
# uname -r
3.0.13-0.27-default

We need a way to fall back to normal ring buffer when kernel
doesn't support backward ring buffer.

Thank you.