[PATCH 38/49] perf record: Introduce struct record_thread

Jiri Olsa
2018-01-09T15:37:35Z

Adding struct record_thread to carry the single thread's maps.

Link: http://lkml.kernel.org/n/tip-dsyi97xdc7ullvsisqmha0ca@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/perf/builtin-record.c | 179 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 179 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f208a898851c..2c8500163d24 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -64,6 +64,15 @@ struct switch_output {
bool set;
};

+struct record_thread {
+ struct perf_mmap **mmap;
+ int mmap_nr;
+ struct perf_mmap **ovw_mmap;
+ int ovw_mmap_nr;
+ struct fdarray pollfd;
+ struct record *rec;
+};
+
struct record {
struct perf_tool tool;
struct record_opts opts;
@@ -83,6 +92,8 @@ struct record {
bool timestamp_boundary;
struct switch_output switch_output;
unsigned long long samples;
+ struct record_thread *threads;
+ int threads_cnt;
};

static volatile int auxtrace_record__snapshot_started;
@@ -940,6 +951,166 @@ static int record__synthesize(struct record *rec, bool tail)
return err;
}

+static void
+record_thread__clean(struct record_thread *th)
+{
+ free(th->mmap);
+ free(th->ovw_mmap);
+}
+
+static void
+record__threads_clean(struct record *rec)
+{
+ struct record_thread *threads = rec->threads;
+ int i;
+
+ if (threads) {
+ for (i = 0; i < rec->threads_cnt; i++)
+ record_thread__clean(threads + i);
+ }
+}
+
+static void record_thread__init(struct record_thread *th, struct record *rec)
+{
+ memset(th, 0, sizeof(*th));
+ fdarray__init(&th->pollfd, 64);
+ th->rec = rec;
+}
+
+static int
+record_thread__mmap(struct record_thread *th, int nr, int nr_ovw)
+{
+ struct perf_mmap **mmap;
+
+ mmap = zalloc(sizeof(*mmap) * nr);
+ if (!mmap)
+ return -ENOMEM;
+
+ th->mmap = mmap;
+ th->mmap_nr = nr;
+
+ if (nr_ovw) {
+ mmap = zalloc(sizeof(*mmap) * nr_ovw);
+ if (!mmap)
+ return -ENOMEM;
+
+ th->ovw_mmap = mmap;
+ th->ovw_mmap_nr = nr;
+ }
+
+ return 0;
+}
+
+static int
+record__threads_assign(struct record *rec)
+{
+ struct record_thread *threads = rec->threads;
+ struct record_thread *thread0 = threads;
+ struct perf_evlist *evlist = rec->evlist;
+ int i, j, nr, nr0, nr_ovw, nr_trk;
+ int ret = -ENOMEM;
+
+ nr = evlist->mmap ? evlist->nr_mmaps : 0;
+ nr_trk = evlist->track_mmap ? evlist->nr_mmaps : 0;
+ nr_ovw = evlist->overwrite_mmap ? evlist->nr_mmaps : 0;
+
+ nr0 = nr_trk;
+ nr0 += nr;
+
+ if (record_thread__mmap(thread0, nr0, nr_ovw))
+ goto out_error;
+
+ for (i = 0; i < nr_ovw; i++)
+ thread0->ovw_mmap[i] = &evlist->overwrite_mmap[i];
+
+ for (i = 0; i < nr_trk; i++)
+ thread0->mmap[i] = &evlist->track_mmap[i];
+
+ for (j = 0; i < nr0 && j < nr; i++, j++)
+ thread0->mmap[i] = &evlist->mmap[j];
+
+ ret = 0;
+
+out_error:
+ return ret;
+}
+
+static int
+record_thread__create_poll(struct record_thread *th,
+ struct perf_evlist *evlist)
+{
+ struct fdarray *fda = &evlist->pollfd;
+ struct perf_mmap *mmap;
+ int i, j;
+
+ for (i = 0; i < th->mmap_nr; i++) {
+ mmap = th->mmap[i];
+
+ for (j = 0; j < fda->nr; j++) {
+ if (mmap != fda->priv[j].ptr)
+ continue;
+
+ if (fdarray__add_clone(&th->pollfd, j, fda) < 0)
+ return -ENOMEM;
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+record__threads_create_poll(struct record *rec)
+{
+ struct record_thread *threads = rec->threads;
+ int ret = 0, i;
+
+ for (i = 0; !ret && (i < rec->threads_cnt); i++)
+ ret = record_thread__create_poll(threads + i, rec->evlist);
+
+ return ret;
+}
+
+static int
+record__threads_create(struct record *rec)
+{
+ struct record_thread *threads;
+ int i, cnt = rec->threads_cnt;
+
+ threads = zalloc(sizeof(*threads) * cnt);
+ if (threads) {
+ for (i = 0; i < cnt; i++)
+ record_thread__init(threads + i, rec);
+
+ rec->threads = threads;
+ }
+
+ return threads ? 0 : -ENOMEM;
+}
+
+static int
+record__threads_config(struct record *rec)
+{
+ int ret;
+
+ ret = record__threads_create(rec);
+ if (ret)
+ goto out;
+
+ ret = record__threads_assign(rec);
+ if (ret)
+ goto out;
+
+ ret = record__threads_create_poll(rec);
+
+out:
+ if (ret)
+ record__threads_clean(rec);
+
+ return ret;
+}
+
static int __cmd_record(struct record *rec, int argc, const char **argv)
{
int err;
@@ -1007,6 +1178,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
goto out_child;
}

+ if (record__threads_config(rec)) {
+ err = -1;
+ goto out_child;
+ }
+
if (opts->index) {
err = record__mmap_index(rec);
if (err)
@@ -1284,6 +1460,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)

perf_hooks__invoke_record_end();

+ record__threads_clean(rec);
+
if (!err && !quiet) {
char samples[128];
const char *postfix = rec->timestamp_filename ?
@@ -1623,6 +1801,7 @@ static struct record record = {
.mmap2 = perf_event__process_mmap2,
.ordered_events = true,
},
+ .threads_cnt = 1,
};

const char record_callchain_help[] = CALLCHAIN_RECORD_HELP
--
2.13.6