diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ec4135c..3817a9a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -74,6 +74,54 @@ static int process_synthesized_event(struct perf_tool *tool,
 	return record__write(rec, event, event->header.size);
 }
 
+static int record__search_read_start(struct perf_mmap *md, u64 head, u64 *pstart)
+{
+	unsigned char *data = md->base + page_size;
+	u64 evt_head = head;
+	u16 *pevt_size;
+
+	while (true) {
+		struct perf_event_header *pheader;
+
+		pevt_size = (void *)&data[(evt_head - sizeof(*pevt_size)) & md->mask];
+		
+		if (*pevt_size % sizeof(u16) != 0) {
+			pr_err("strange event size: %d\n", (int)(*pevt_size));
+			return -1;
+		}
+
+		if (!*pevt_size) {
+			if (evt_head) {
+				pr_err("size is 0 but evt_head (0x%lx) not 0\n",
+					 (unsigned long)evt_head);
+				return -1;
+			}
+			break;
+		}
+
+		if (evt_head < *pevt_size)
+			break;
+
+		evt_head -= *pevt_size;
+		if (evt_head + (md->mask + 1) < head) {
+			evt_head += *pevt_size;
+			pr_debug("evt_head=%lx, head=%lx, size=%d\n", evt_head, head, *pevt_size);
+			break;
+		}
+
+		pheader = (struct perf_event_header *)(&data[evt_head & md->mask]);
+
+		if (pheader->size != *pevt_size) {
+			pr_err("size mismatch: %d vs %d\n",
+				 (int)pheader->size, (int)(*pevt_size));
+			return -1;
+		}
+	}
+
+	*pstart = evt_head;
+	return 0;
+}
+
 static int record__mmap_read(struct record *rec, int idx)
 {
 	struct perf_mmap *md = &rec->evlist->mmap[idx];
@@ -83,6 +131,17 @@ static int record__mmap_read(struct record *rec, int idx)
 	unsigned long size;
 	void *buf;
 	int rc = 0;
+	bool overwrite = rec->evlist->overwrite;
+	int err;
+
+	if (idx >= rec->evlist->nr_mmaps)
+		overwrite = !overwrite;
+
+	if (overwrite) {
+		err = record__search_read_start(md, head, &old);
+		if (err)
+			return 0;
+	}
 
 	if (old == head)
 		return 0;
@@ -400,7 +459,7 @@ static struct perf_event_header finished_round_event = {
 	.type = PERF_RECORD_FINISHED_ROUND,
 };
 
-static int record__mmap_read_all(struct record *rec)
+static int __record__mmap_read_all(struct record *rec, bool next_half)
 {
 	u64 bytes_written = rec->bytes_written;
 	int i;
@@ -408,9 +467,10 @@ static int record__mmap_read_all(struct record *rec)
 
 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
+		int idx = i + (next_half ? rec->evlist->nr_mmaps : 0);
 
-		if (rec->evlist->mmap[i].base) {
-			if (record__mmap_read(rec, i) != 0) {
+		if (rec->evlist->mmap[idx].base) {
+			if (record__mmap_read(rec, idx) != 0) {
 				rc = -1;
 				goto out;
 			}
@@ -434,6 +494,11 @@ out:
 	return rc;
 }
 
+static int record__mmap_read_all(struct record *rec)
+{
+	return __record__mmap_read_all(rec, false);
+}
+
 static void record__init_features(struct record *rec)
 {
 	struct perf_session *session = rec->session;
@@ -727,6 +792,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 	}
 	auxtrace_snapshot_enabled = 0;
 
+	__record__mmap_read_all(rec, true);
+
 	if (forks && workload_exec_errno) {
 		char msg[STRERR_BUFSIZE];
 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 8dd59aa..a3421ee 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -800,7 +800,9 @@ void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
 {
 	struct perf_mmap *md = &evlist->mmap[idx];
 
-	if (!evlist->overwrite) {
+	if ((!evlist->overwrite && (idx < evlist->nr_mmaps)) ||
+		(evlist->overwrite && (idx >= evlist->nr_mmaps))) {
+
 		u64 old = md->prev;
 
 		perf_mmap__write_tail(md, old);
@@ -855,7 +857,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
 	if (evlist->mmap == NULL)
 		return;
 
-	for (i = 0; i < evlist->nr_mmaps; i++)
+	for (i = 0; i < 2 * evlist->nr_mmaps; i++)
 		__perf_evlist__munmap(evlist, i);
 
 	zfree(&evlist->mmap);
@@ -866,7 +868,7 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 	evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
 	if (cpu_map__empty(evlist->cpus))
 		evlist->nr_mmaps = thread_map__nr(evlist->threads);
-	evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
+	evlist->mmap = zalloc(2 * evlist->nr_mmaps * sizeof(struct perf_mmap));
 	return evlist->mmap != NULL ? 0 : -ENOMEM;
 }
 
@@ -897,6 +899,7 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
 	evlist->mmap[idx].mask = mp->mask;
 	evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
 				      MAP_SHARED, fd, 0);
+
 	if (evlist->mmap[idx].base == MAP_FAILED) {
 		pr_debug2("failed to mmap perf event ring buffer, error %d\n",
 			  errno);
@@ -911,18 +914,31 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
 	return 0;
 }
 
-static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
-				       struct mmap_params *mp, int cpu,
-				       int thread, int *output)
+static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int _idx,
+				       struct mmap_params *_mp, int cpu,
+				       int thread, int *output1, int *output2)
 {
 	struct perf_evsel *evsel;
+	int *output;
+	struct mmap_params new_mp = *_mp;
 
 	evlist__for_each(evlist, evsel) {
 		int fd;
+		int idx = _idx;
+		struct mmap_params *mp = _mp;
 
 		if (evsel->system_wide && thread)
 			continue;
 
+		if (evsel->overwrite ^ evlist->overwrite) {
+			output = output2;
+			new_mp.prot ^= PROT_WRITE;
+			mp = &new_mp;
+			idx = _idx + evlist->nr_mmaps;
+		} else {
+			output = output1;
+		}
+
 		fd = FD(evsel, cpu, thread);
 
 		if (*output == -1) {
@@ -936,6 +952,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 			perf_evlist__mmap_get(evlist, idx);
 		}
 
+		if (evsel->overwrite)
+			goto skip_poll_add;
 		/*
 		 * The system_wide flag causes a selected event to be opened
 		 * always without a pid.  Consequently it will never get a
@@ -949,6 +967,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
 			return -1;
 		}
 
+skip_poll_add:
+
 		if (evsel->attr.read_format & PERF_FORMAT_ID) {
 			if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread,
 						   fd) < 0)
@@ -970,14 +990,15 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
 
 	pr_debug2("perf event ring buffer mmapped per cpu\n");
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
-		int output = -1;
+		int output1 = -1;
+		int output2 = -1;
 
 		auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, cpu,
 					      true);
 
 		for (thread = 0; thread < nr_threads; thread++) {
 			if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
-							thread, &output))
+							thread, &output1, &output2))
 				goto out_unmap;
 		}
 	}
@@ -998,13 +1019,14 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
 
 	pr_debug2("perf event ring buffer mmapped per thread\n");
 	for (thread = 0; thread < nr_threads; thread++) {
-		int output = -1;
+		int output1 = -1;
+		int output2 = -1;
 
 		auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, thread,
 					      false);
 
 		if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
-						&output))
+						&output1, &output2))
 			goto out_unmap;
 	}
 
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3386437..8e40da9 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -910,6 +910,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
 	 * it overloads any global configuration.
 	 */
 	apply_config_terms(evsel, opts);
+
+	if (evsel->overwrite)
+		perf_evsel__set_sample_bit(evsel, SIZE_AT_END);
 }
 
 static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
