diff mbox series

[10/35] perf tools: Add machine_pid and vcpu to id_index

Message ID 20220711093218.10967-11-adrian.hunter@intel.com (mailing list archive)
State New, archived
Headers show
Series perf intel-pt: Add support for tracing virtual machine user space on the host | expand

Commit Message

Adrian Hunter July 11, 2022, 9:31 a.m. UTC
When injecting events from a guest perf.data file, the events will have
separate sample ID numbers. These ID numbers can then be used to determine
which machine an event belongs to. To facilitate that, add machine_pid and
vcpu to id_index records. For backward compatibility, these are added at
the end of the record, and the length of the record is used to determine
if they are present or not.

Note, this is needed because the events from a guest perf.data file contain
the pid/tid of the process running at that time inside the VM not the
pid/tid of the (QEMU) hypervisor thread. So a way is needed to relate
guest events back to the guest machine and VCPU, and using sample ID
numbers for that is relatively simple and convenient.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/lib/perf/include/internal/evsel.h |  4 ++
 tools/lib/perf/include/perf/event.h     |  5 +++
 tools/perf/util/session.c               | 40 ++++++++++++++++---
 tools/perf/util/synthetic-events.c      | 51 +++++++++++++++++++------
 tools/perf/util/synthetic-events.h      |  1 +
 5 files changed, 84 insertions(+), 17 deletions(-)

Comments

Ian Rogers July 19, 2022, 5:48 p.m. UTC | #1
On Mon, Jul 11, 2022 at 2:33 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>
> When injecting events from a guest perf.data file, the events will have
> separate sample ID numbers. These ID numbers can then be used to determine
> which machine an event belongs to. To facilitate that, add machine_pid and
> vcpu to id_index records. For backward compatibility, these are added at
> the end of the record, and the length of the record is used to determine
> if they are present or not.
>
> Note, this is needed because the events from a guest perf.data file contain
> the pid/tid of the process running at that time inside the VM not the
> pid/tid of the (QEMU) hypervisor thread. So a way is needed to relate
> guest events back to the guest machine and VCPU, and using sample ID
> numbers for that is relatively simple and convenient.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/lib/perf/include/internal/evsel.h |  4 ++
>  tools/lib/perf/include/perf/event.h     |  5 +++
>  tools/perf/util/session.c               | 40 ++++++++++++++++---
>  tools/perf/util/synthetic-events.c      | 51 +++++++++++++++++++------
>  tools/perf/util/synthetic-events.h      |  1 +
>  5 files changed, 84 insertions(+), 17 deletions(-)
>
> diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
> index 2a912a1f1989..a99a75d9e78f 100644
> --- a/tools/lib/perf/include/internal/evsel.h
> +++ b/tools/lib/perf/include/internal/evsel.h
> @@ -30,6 +30,10 @@ struct perf_sample_id {
>         struct perf_cpu          cpu;
>         pid_t                    tid;
>
> +       /* Guest machine pid and VCPU, valid only if machine_pid is non-zero */
> +       pid_t                    machine_pid;
> +       struct perf_cpu          vcpu;
> +
>         /* Holds total ID period value for PERF_SAMPLE_READ processing. */
>         u64                      period;
>  };
> diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h
> index 9f7ca070da87..c2dbd3e88885 100644
> --- a/tools/lib/perf/include/perf/event.h
> +++ b/tools/lib/perf/include/perf/event.h
> @@ -237,6 +237,11 @@ struct id_index_entry {
>         __u64                    tid;
>  };
>
> +struct id_index_entry_2 {
> +       __u64                    machine_pid;
> +       __u64                    vcpu;
> +};
> +
>  struct perf_record_id_index {
>         struct perf_event_header header;
>         __u64                    nr;
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index 4c9513bc6d89..5141fe164e97 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -2756,18 +2756,35 @@ int perf_event__process_id_index(struct perf_session *session,
>  {
>         struct evlist *evlist = session->evlist;
>         struct perf_record_id_index *ie = &event->id_index;
> +       size_t sz = ie->header.size - sizeof(*ie);
>         size_t i, nr, max_nr;
> +       size_t e1_sz = sizeof(struct id_index_entry);
> +       size_t e2_sz = sizeof(struct id_index_entry_2);
> +       size_t etot_sz = e1_sz + e2_sz;
> +       struct id_index_entry_2 *e2;
>
> -       max_nr = (ie->header.size - sizeof(struct perf_record_id_index)) /
> -                sizeof(struct id_index_entry);
> +       max_nr = sz / e1_sz;
>         nr = ie->nr;
> -       if (nr > max_nr)
> +       if (nr > max_nr) {
> +               printf("Too big: nr %zu max_nr %zu\n", nr, max_nr);
>                 return -EINVAL;
> +       }
> +
> +       if (sz >= nr * etot_sz) {
> +               max_nr = sz / etot_sz;
> +               if (nr > max_nr) {
> +                       printf("Too big2: nr %zu max_nr %zu\n", nr, max_nr);
> +                       return -EINVAL;
> +               }
> +               e2 = (void *)ie + sizeof(*ie) + nr * e1_sz;
> +       } else {
> +               e2 = NULL;
> +       }
>
>         if (dump_trace)
>                 fprintf(stdout, " nr: %zu\n", nr);
>
> -       for (i = 0; i < nr; i++) {
> +       for (i = 0; i < nr; i++, (e2 ? e2++ : 0)) {
>                 struct id_index_entry *e = &ie->entries[i];
>                 struct perf_sample_id *sid;
>
> @@ -2775,15 +2792,28 @@ int perf_event__process_id_index(struct perf_session *session,
>                         fprintf(stdout, " ... id: %"PRI_lu64, e->id);
>                         fprintf(stdout, "  idx: %"PRI_lu64, e->idx);
>                         fprintf(stdout, "  cpu: %"PRI_ld64, e->cpu);
> -                       fprintf(stdout, "  tid: %"PRI_ld64"\n", e->tid);
> +                       fprintf(stdout, "  tid: %"PRI_ld64, e->tid);
> +                       if (e2) {
> +                               fprintf(stdout, "  machine_pid: %"PRI_ld64, e2->machine_pid);
> +                               fprintf(stdout, "  vcpu: %"PRI_lu64"\n", e2->vcpu);
> +                       } else {
> +                               fprintf(stdout, "\n");
> +                       }
>                 }
>
>                 sid = evlist__id2sid(evlist, e->id);
>                 if (!sid)
>                         return -ENOENT;
> +
>                 sid->idx = e->idx;
>                 sid->cpu.cpu = e->cpu;
>                 sid->tid = e->tid;
> +
> +               if (!e2)
> +                       continue;
> +
> +               sid->machine_pid = e2->machine_pid;
> +               sid->vcpu.cpu = e2->vcpu;
>         }
>         return 0;
>  }
> diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
> index ed9623702f34..2ae59c03ae77 100644
> --- a/tools/perf/util/synthetic-events.c
> +++ b/tools/perf/util/synthetic-events.c
> @@ -1759,19 +1759,26 @@ int perf_event__synthesize_id_sample(__u64 *array, u64 type, const struct perf_s
>         return (void *)array - (void *)start;
>  }
>
> -int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
> -                                   struct evlist *evlist, struct machine *machine)
> +int __perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
> +                                     struct evlist *evlist, struct machine *machine, size_t from)
>  {
>         union perf_event *ev;
>         struct evsel *evsel;
> -       size_t nr = 0, i = 0, sz, max_nr, n;
> +       size_t nr = 0, i = 0, sz, max_nr, n, pos;
> +       size_t e1_sz = sizeof(struct id_index_entry);
> +       size_t e2_sz = sizeof(struct id_index_entry_2);
> +       size_t etot_sz = e1_sz + e2_sz;
> +       bool e2_needed = false;
>         int err;
>
> -       max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) /
> -                sizeof(struct id_index_entry);
> +       max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / etot_sz;
>
> -       evlist__for_each_entry(evlist, evsel)
> +       pos = 0;
> +       evlist__for_each_entry(evlist, evsel) {
> +               if (pos++ < from)
> +                       continue;
>                 nr += evsel->core.ids;
> +       }
>
>         if (!nr)
>                 return 0;
> @@ -1779,31 +1786,38 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
>         pr_debug2("Synthesizing id index\n");
>
>         n = nr > max_nr ? max_nr : nr;
> -       sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry);
> +       sz = sizeof(struct perf_record_id_index) + n * etot_sz;
>         ev = zalloc(sz);
>         if (!ev)
>                 return -ENOMEM;
>
> +       sz = sizeof(struct perf_record_id_index) + n * e1_sz;
> +
>         ev->id_index.header.type = PERF_RECORD_ID_INDEX;
> -       ev->id_index.header.size = sz;
>         ev->id_index.nr = n;
>
> +       pos = 0;
>         evlist__for_each_entry(evlist, evsel) {
>                 u32 j;
>
> -               for (j = 0; j < evsel->core.ids; j++) {
> +               if (pos++ < from)
> +                       continue;
> +               for (j = 0; j < evsel->core.ids; j++, i++) {
>                         struct id_index_entry *e;
> +                       struct id_index_entry_2 *e2;
>                         struct perf_sample_id *sid;
>
>                         if (i >= n) {
> +                               ev->id_index.header.size = sz + (e2_needed ? n * e2_sz : 0);
>                                 err = process(tool, ev, NULL, machine);
>                                 if (err)
>                                         goto out_err;
>                                 nr -= n;
>                                 i = 0;
> +                               e2_needed = false;
>                         }
>
> -                       e = &ev->id_index.entries[i++];
> +                       e = &ev->id_index.entries[i];
>
>                         e->id = evsel->core.id[j];
>
> @@ -1816,11 +1830,18 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
>                         e->idx = sid->idx;
>                         e->cpu = sid->cpu.cpu;
>                         e->tid = sid->tid;
> +
> +                       if (sid->machine_pid)
> +                               e2_needed = true;
> +
> +                       e2 = (void *)ev + sz;
> +                       e2[i].machine_pid = sid->machine_pid;
> +                       e2[i].vcpu        = sid->vcpu.cpu;
>                 }
>         }
>
> -       sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry);
> -       ev->id_index.header.size = sz;
> +       sz = sizeof(struct perf_record_id_index) + nr * e1_sz;
> +       ev->id_index.header.size = sz + (e2_needed ? nr * e2_sz : 0);
>         ev->id_index.nr = nr;
>
>         err = process(tool, ev, NULL, machine);
> @@ -1830,6 +1851,12 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
>         return err;
>  }
>
> +int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
> +                                   struct evlist *evlist, struct machine *machine)
> +{
> +       return __perf_event__synthesize_id_index(tool, process, evlist, machine, 0);
> +}
> +
>  int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
>                                   struct target *target, struct perf_thread_map *threads,
>                                   perf_event__handler_t process, bool needs_mmap,
> diff --git a/tools/perf/util/synthetic-events.h b/tools/perf/util/synthetic-events.h
> index b136ec3ec95d..81cb3d6af0b9 100644
> --- a/tools/perf/util/synthetic-events.h
> +++ b/tools/perf/util/synthetic-events.h
> @@ -55,6 +55,7 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evs
>  int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
>  int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, struct evlist *evlist, perf_event__handler_t process);
>  int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, struct evlist *evlist, struct machine *machine);
> +int __perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, struct evlist *evlist, struct machine *machine, size_t from);

Given there is only 1 use in the file defining the function, should
this just be static with no header file declaration?

Thanks,
Ian

>  int perf_event__synthesize_id_sample(__u64 *array, u64 type, const struct perf_sample *sample);
>  int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
>  int perf_event__synthesize_mmap_events(struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, struct machine *machine, bool mmap_data);
> --
> 2.25.1
>
Adrian Hunter Aug. 9, 2022, 12:19 p.m. UTC | #2
On 19/07/22 20:48, Ian Rogers wrote:
> On Mon, Jul 11, 2022 at 2:33 AM Adrian Hunter <adrian.hunter@intel.com> wrote:
>>
>> When injecting events from a guest perf.data file, the events will have
>> separate sample ID numbers. These ID numbers can then be used to determine
>> which machine an event belongs to. To facilitate that, add machine_pid and
>> vcpu to id_index records. For backward compatibility, these are added at
>> the end of the record, and the length of the record is used to determine
>> if they are present or not.
>>
>> Note, this is needed because the events from a guest perf.data file contain
>> the pid/tid of the process running at that time inside the VM not the
>> pid/tid of the (QEMU) hypervisor thread. So a way is needed to relate
>> guest events back to the guest machine and VCPU, and using sample ID
>> numbers for that is relatively simple and convenient.
>>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>  tools/lib/perf/include/internal/evsel.h |  4 ++
>>  tools/lib/perf/include/perf/event.h     |  5 +++
>>  tools/perf/util/session.c               | 40 ++++++++++++++++---
>>  tools/perf/util/synthetic-events.c      | 51 +++++++++++++++++++------
>>  tools/perf/util/synthetic-events.h      |  1 +
>>  5 files changed, 84 insertions(+), 17 deletions(-)
>>
>> diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
>> index 2a912a1f1989..a99a75d9e78f 100644
>> --- a/tools/lib/perf/include/internal/evsel.h
>> +++ b/tools/lib/perf/include/internal/evsel.h
>> @@ -30,6 +30,10 @@ struct perf_sample_id {
>>         struct perf_cpu          cpu;
>>         pid_t                    tid;
>>
>> +       /* Guest machine pid and VCPU, valid only if machine_pid is non-zero */
>> +       pid_t                    machine_pid;
>> +       struct perf_cpu          vcpu;
>> +
>>         /* Holds total ID period value for PERF_SAMPLE_READ processing. */
>>         u64                      period;
>>  };
>> diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h
>> index 9f7ca070da87..c2dbd3e88885 100644
>> --- a/tools/lib/perf/include/perf/event.h
>> +++ b/tools/lib/perf/include/perf/event.h
>> @@ -237,6 +237,11 @@ struct id_index_entry {
>>         __u64                    tid;
>>  };
>>
>> +struct id_index_entry_2 {
>> +       __u64                    machine_pid;
>> +       __u64                    vcpu;
>> +};
>> +
>>  struct perf_record_id_index {
>>         struct perf_event_header header;
>>         __u64                    nr;
>> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
>> index 4c9513bc6d89..5141fe164e97 100644
>> --- a/tools/perf/util/session.c
>> +++ b/tools/perf/util/session.c
>> @@ -2756,18 +2756,35 @@ int perf_event__process_id_index(struct perf_session *session,
>>  {
>>         struct evlist *evlist = session->evlist;
>>         struct perf_record_id_index *ie = &event->id_index;
>> +       size_t sz = ie->header.size - sizeof(*ie);
>>         size_t i, nr, max_nr;
>> +       size_t e1_sz = sizeof(struct id_index_entry);
>> +       size_t e2_sz = sizeof(struct id_index_entry_2);
>> +       size_t etot_sz = e1_sz + e2_sz;
>> +       struct id_index_entry_2 *e2;
>>
>> -       max_nr = (ie->header.size - sizeof(struct perf_record_id_index)) /
>> -                sizeof(struct id_index_entry);
>> +       max_nr = sz / e1_sz;
>>         nr = ie->nr;
>> -       if (nr > max_nr)
>> +       if (nr > max_nr) {
>> +               printf("Too big: nr %zu max_nr %zu\n", nr, max_nr);
>>                 return -EINVAL;
>> +       }
>> +
>> +       if (sz >= nr * etot_sz) {
>> +               max_nr = sz / etot_sz;
>> +               if (nr > max_nr) {
>> +                       printf("Too big2: nr %zu max_nr %zu\n", nr, max_nr);
>> +                       return -EINVAL;
>> +               }
>> +               e2 = (void *)ie + sizeof(*ie) + nr * e1_sz;
>> +       } else {
>> +               e2 = NULL;
>> +       }
>>
>>         if (dump_trace)
>>                 fprintf(stdout, " nr: %zu\n", nr);
>>
>> -       for (i = 0; i < nr; i++) {
>> +       for (i = 0; i < nr; i++, (e2 ? e2++ : 0)) {
>>                 struct id_index_entry *e = &ie->entries[i];
>>                 struct perf_sample_id *sid;
>>
>> @@ -2775,15 +2792,28 @@ int perf_event__process_id_index(struct perf_session *session,
>>                         fprintf(stdout, " ... id: %"PRI_lu64, e->id);
>>                         fprintf(stdout, "  idx: %"PRI_lu64, e->idx);
>>                         fprintf(stdout, "  cpu: %"PRI_ld64, e->cpu);
>> -                       fprintf(stdout, "  tid: %"PRI_ld64"\n", e->tid);
>> +                       fprintf(stdout, "  tid: %"PRI_ld64, e->tid);
>> +                       if (e2) {
>> +                               fprintf(stdout, "  machine_pid: %"PRI_ld64, e2->machine_pid);
>> +                               fprintf(stdout, "  vcpu: %"PRI_lu64"\n", e2->vcpu);
>> +                       } else {
>> +                               fprintf(stdout, "\n");
>> +                       }
>>                 }
>>
>>                 sid = evlist__id2sid(evlist, e->id);
>>                 if (!sid)
>>                         return -ENOENT;
>> +
>>                 sid->idx = e->idx;
>>                 sid->cpu.cpu = e->cpu;
>>                 sid->tid = e->tid;
>> +
>> +               if (!e2)
>> +                       continue;
>> +
>> +               sid->machine_pid = e2->machine_pid;
>> +               sid->vcpu.cpu = e2->vcpu;
>>         }
>>         return 0;
>>  }
>> diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
>> index ed9623702f34..2ae59c03ae77 100644
>> --- a/tools/perf/util/synthetic-events.c
>> +++ b/tools/perf/util/synthetic-events.c
>> @@ -1759,19 +1759,26 @@ int perf_event__synthesize_id_sample(__u64 *array, u64 type, const struct perf_s
>>         return (void *)array - (void *)start;
>>  }
>>
>> -int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
>> -                                   struct evlist *evlist, struct machine *machine)
>> +int __perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
>> +                                     struct evlist *evlist, struct machine *machine, size_t from)
>>  {
>>         union perf_event *ev;
>>         struct evsel *evsel;
>> -       size_t nr = 0, i = 0, sz, max_nr, n;
>> +       size_t nr = 0, i = 0, sz, max_nr, n, pos;
>> +       size_t e1_sz = sizeof(struct id_index_entry);
>> +       size_t e2_sz = sizeof(struct id_index_entry_2);
>> +       size_t etot_sz = e1_sz + e2_sz;
>> +       bool e2_needed = false;
>>         int err;
>>
>> -       max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) /
>> -                sizeof(struct id_index_entry);
>> +       max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / etot_sz;
>>
>> -       evlist__for_each_entry(evlist, evsel)
>> +       pos = 0;
>> +       evlist__for_each_entry(evlist, evsel) {
>> +               if (pos++ < from)
>> +                       continue;
>>                 nr += evsel->core.ids;
>> +       }
>>
>>         if (!nr)
>>                 return 0;
>> @@ -1779,31 +1786,38 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
>>         pr_debug2("Synthesizing id index\n");
>>
>>         n = nr > max_nr ? max_nr : nr;
>> -       sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry);
>> +       sz = sizeof(struct perf_record_id_index) + n * etot_sz;
>>         ev = zalloc(sz);
>>         if (!ev)
>>                 return -ENOMEM;
>>
>> +       sz = sizeof(struct perf_record_id_index) + n * e1_sz;
>> +
>>         ev->id_index.header.type = PERF_RECORD_ID_INDEX;
>> -       ev->id_index.header.size = sz;
>>         ev->id_index.nr = n;
>>
>> +       pos = 0;
>>         evlist__for_each_entry(evlist, evsel) {
>>                 u32 j;
>>
>> -               for (j = 0; j < evsel->core.ids; j++) {
>> +               if (pos++ < from)
>> +                       continue;
>> +               for (j = 0; j < evsel->core.ids; j++, i++) {
>>                         struct id_index_entry *e;
>> +                       struct id_index_entry_2 *e2;
>>                         struct perf_sample_id *sid;
>>
>>                         if (i >= n) {
>> +                               ev->id_index.header.size = sz + (e2_needed ? n * e2_sz : 0);
>>                                 err = process(tool, ev, NULL, machine);
>>                                 if (err)
>>                                         goto out_err;
>>                                 nr -= n;
>>                                 i = 0;
>> +                               e2_needed = false;
>>                         }
>>
>> -                       e = &ev->id_index.entries[i++];
>> +                       e = &ev->id_index.entries[i];
>>
>>                         e->id = evsel->core.id[j];
>>
>> @@ -1816,11 +1830,18 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
>>                         e->idx = sid->idx;
>>                         e->cpu = sid->cpu.cpu;
>>                         e->tid = sid->tid;
>> +
>> +                       if (sid->machine_pid)
>> +                               e2_needed = true;
>> +
>> +                       e2 = (void *)ev + sz;
>> +                       e2[i].machine_pid = sid->machine_pid;
>> +                       e2[i].vcpu        = sid->vcpu.cpu;
>>                 }
>>         }
>>
>> -       sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry);
>> -       ev->id_index.header.size = sz;
>> +       sz = sizeof(struct perf_record_id_index) + nr * e1_sz;
>> +       ev->id_index.header.size = sz + (e2_needed ? nr * e2_sz : 0);
>>         ev->id_index.nr = nr;
>>
>>         err = process(tool, ev, NULL, machine);
>> @@ -1830,6 +1851,12 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
>>         return err;
>>  }
>>
>> +int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
>> +                                   struct evlist *evlist, struct machine *machine)
>> +{
>> +       return __perf_event__synthesize_id_index(tool, process, evlist, machine, 0);
>> +}
>> +
>>  int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
>>                                   struct target *target, struct perf_thread_map *threads,
>>                                   perf_event__handler_t process, bool needs_mmap,
>> diff --git a/tools/perf/util/synthetic-events.h b/tools/perf/util/synthetic-events.h
>> index b136ec3ec95d..81cb3d6af0b9 100644
>> --- a/tools/perf/util/synthetic-events.h
>> +++ b/tools/perf/util/synthetic-events.h
>> @@ -55,6 +55,7 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evs
>>  int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
>>  int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, struct evlist *evlist, perf_event__handler_t process);
>>  int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, struct evlist *evlist, struct machine *machine);
>> +int __perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, struct evlist *evlist, struct machine *machine, size_t from);
> 
> Given there is only 1 use in the file defining the function, should
> this just be static with no header file declaration?

It is used perf inject also.

> 
> Thanks,
> Ian
> 
>>  int perf_event__synthesize_id_sample(__u64 *array, u64 type, const struct perf_sample *sample);
>>  int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
>>  int perf_event__synthesize_mmap_events(struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, struct machine *machine, bool mmap_data);
>> --
>> 2.25.1
>>
diff mbox series

Patch

diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h
index 2a912a1f1989..a99a75d9e78f 100644
--- a/tools/lib/perf/include/internal/evsel.h
+++ b/tools/lib/perf/include/internal/evsel.h
@@ -30,6 +30,10 @@  struct perf_sample_id {
 	struct perf_cpu		 cpu;
 	pid_t			 tid;
 
+	/* Guest machine pid and VCPU, valid only if machine_pid is non-zero */
+	pid_t			 machine_pid;
+	struct perf_cpu		 vcpu;
+
 	/* Holds total ID period value for PERF_SAMPLE_READ processing. */
 	u64			 period;
 };
diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h
index 9f7ca070da87..c2dbd3e88885 100644
--- a/tools/lib/perf/include/perf/event.h
+++ b/tools/lib/perf/include/perf/event.h
@@ -237,6 +237,11 @@  struct id_index_entry {
 	__u64			 tid;
 };
 
+struct id_index_entry_2 {
+	__u64			 machine_pid;
+	__u64			 vcpu;
+};
+
 struct perf_record_id_index {
 	struct perf_event_header header;
 	__u64			 nr;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 4c9513bc6d89..5141fe164e97 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -2756,18 +2756,35 @@  int perf_event__process_id_index(struct perf_session *session,
 {
 	struct evlist *evlist = session->evlist;
 	struct perf_record_id_index *ie = &event->id_index;
+	size_t sz = ie->header.size - sizeof(*ie);
 	size_t i, nr, max_nr;
+	size_t e1_sz = sizeof(struct id_index_entry);
+	size_t e2_sz = sizeof(struct id_index_entry_2);
+	size_t etot_sz = e1_sz + e2_sz;
+	struct id_index_entry_2 *e2;
 
-	max_nr = (ie->header.size - sizeof(struct perf_record_id_index)) /
-		 sizeof(struct id_index_entry);
+	max_nr = sz / e1_sz;
 	nr = ie->nr;
-	if (nr > max_nr)
+	if (nr > max_nr) {
+		printf("Too big: nr %zu max_nr %zu\n", nr, max_nr);
 		return -EINVAL;
+	}
+
+	if (sz >= nr * etot_sz) {
+		max_nr = sz / etot_sz;
+		if (nr > max_nr) {
+			printf("Too big2: nr %zu max_nr %zu\n", nr, max_nr);
+			return -EINVAL;
+		}
+		e2 = (void *)ie + sizeof(*ie) + nr * e1_sz;
+	} else {
+		e2 = NULL;
+	}
 
 	if (dump_trace)
 		fprintf(stdout, " nr: %zu\n", nr);
 
-	for (i = 0; i < nr; i++) {
+	for (i = 0; i < nr; i++, (e2 ? e2++ : 0)) {
 		struct id_index_entry *e = &ie->entries[i];
 		struct perf_sample_id *sid;
 
@@ -2775,15 +2792,28 @@  int perf_event__process_id_index(struct perf_session *session,
 			fprintf(stdout,	" ... id: %"PRI_lu64, e->id);
 			fprintf(stdout,	"  idx: %"PRI_lu64, e->idx);
 			fprintf(stdout,	"  cpu: %"PRI_ld64, e->cpu);
-			fprintf(stdout,	"  tid: %"PRI_ld64"\n", e->tid);
+			fprintf(stdout, "  tid: %"PRI_ld64, e->tid);
+			if (e2) {
+				fprintf(stdout, "  machine_pid: %"PRI_ld64, e2->machine_pid);
+				fprintf(stdout, "  vcpu: %"PRI_lu64"\n", e2->vcpu);
+			} else {
+				fprintf(stdout, "\n");
+			}
 		}
 
 		sid = evlist__id2sid(evlist, e->id);
 		if (!sid)
 			return -ENOENT;
+
 		sid->idx = e->idx;
 		sid->cpu.cpu = e->cpu;
 		sid->tid = e->tid;
+
+		if (!e2)
+			continue;
+
+		sid->machine_pid = e2->machine_pid;
+		sid->vcpu.cpu = e2->vcpu;
 	}
 	return 0;
 }
diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
index ed9623702f34..2ae59c03ae77 100644
--- a/tools/perf/util/synthetic-events.c
+++ b/tools/perf/util/synthetic-events.c
@@ -1759,19 +1759,26 @@  int perf_event__synthesize_id_sample(__u64 *array, u64 type, const struct perf_s
 	return (void *)array - (void *)start;
 }
 
-int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
-				    struct evlist *evlist, struct machine *machine)
+int __perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
+				      struct evlist *evlist, struct machine *machine, size_t from)
 {
 	union perf_event *ev;
 	struct evsel *evsel;
-	size_t nr = 0, i = 0, sz, max_nr, n;
+	size_t nr = 0, i = 0, sz, max_nr, n, pos;
+	size_t e1_sz = sizeof(struct id_index_entry);
+	size_t e2_sz = sizeof(struct id_index_entry_2);
+	size_t etot_sz = e1_sz + e2_sz;
+	bool e2_needed = false;
 	int err;
 
-	max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) /
-		 sizeof(struct id_index_entry);
+	max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / etot_sz;
 
-	evlist__for_each_entry(evlist, evsel)
+	pos = 0;
+	evlist__for_each_entry(evlist, evsel) {
+		if (pos++ < from)
+			continue;
 		nr += evsel->core.ids;
+	}
 
 	if (!nr)
 		return 0;
@@ -1779,31 +1786,38 @@  int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
 	pr_debug2("Synthesizing id index\n");
 
 	n = nr > max_nr ? max_nr : nr;
-	sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry);
+	sz = sizeof(struct perf_record_id_index) + n * etot_sz;
 	ev = zalloc(sz);
 	if (!ev)
 		return -ENOMEM;
 
+	sz = sizeof(struct perf_record_id_index) + n * e1_sz;
+
 	ev->id_index.header.type = PERF_RECORD_ID_INDEX;
-	ev->id_index.header.size = sz;
 	ev->id_index.nr = n;
 
+	pos = 0;
 	evlist__for_each_entry(evlist, evsel) {
 		u32 j;
 
-		for (j = 0; j < evsel->core.ids; j++) {
+		if (pos++ < from)
+			continue;
+		for (j = 0; j < evsel->core.ids; j++, i++) {
 			struct id_index_entry *e;
+			struct id_index_entry_2 *e2;
 			struct perf_sample_id *sid;
 
 			if (i >= n) {
+				ev->id_index.header.size = sz + (e2_needed ? n * e2_sz : 0);
 				err = process(tool, ev, NULL, machine);
 				if (err)
 					goto out_err;
 				nr -= n;
 				i = 0;
+				e2_needed = false;
 			}
 
-			e = &ev->id_index.entries[i++];
+			e = &ev->id_index.entries[i];
 
 			e->id = evsel->core.id[j];
 
@@ -1816,11 +1830,18 @@  int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
 			e->idx = sid->idx;
 			e->cpu = sid->cpu.cpu;
 			e->tid = sid->tid;
+
+			if (sid->machine_pid)
+				e2_needed = true;
+
+			e2 = (void *)ev + sz;
+			e2[i].machine_pid = sid->machine_pid;
+			e2[i].vcpu        = sid->vcpu.cpu;
 		}
 	}
 
-	sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry);
-	ev->id_index.header.size = sz;
+	sz = sizeof(struct perf_record_id_index) + nr * e1_sz;
+	ev->id_index.header.size = sz + (e2_needed ? nr * e2_sz : 0);
 	ev->id_index.nr = nr;
 
 	err = process(tool, ev, NULL, machine);
@@ -1830,6 +1851,12 @@  int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_
 	return err;
 }
 
+int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
+				    struct evlist *evlist, struct machine *machine)
+{
+	return __perf_event__synthesize_id_index(tool, process, evlist, machine, 0);
+}
+
 int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
 				  struct target *target, struct perf_thread_map *threads,
 				  perf_event__handler_t process, bool needs_mmap,
diff --git a/tools/perf/util/synthetic-events.h b/tools/perf/util/synthetic-events.h
index b136ec3ec95d..81cb3d6af0b9 100644
--- a/tools/perf/util/synthetic-events.h
+++ b/tools/perf/util/synthetic-events.h
@@ -55,6 +55,7 @@  int perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evs
 int perf_event__synthesize_extra_kmaps(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
 int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, struct evlist *evlist, perf_event__handler_t process);
 int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, struct evlist *evlist, struct machine *machine);
+int __perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, struct evlist *evlist, struct machine *machine, size_t from);
 int perf_event__synthesize_id_sample(__u64 *array, u64 type, const struct perf_sample *sample);
 int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
 int perf_event__synthesize_mmap_events(struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, struct machine *machine, bool mmap_data);