Skip to content

Commit

Permalink
perf intel-pt: Add a tree for VMCS information
Browse files Browse the repository at this point in the history
Even when VMX TSC Offset is not changing (during perf record), different
virtual machines can have different TSC Offsets. There is a Virtual Machine
Control Structure (VMCS) for each virtual CPU, the address of which is
reported to Intel PT in the VMCS packet. We do not know which VMCS belongs
to which virtual machine, so use a tree to keep track of VMCS information.
Then the decoder will be able to use the current VMCS value to look up the
current TSC Offset.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: https://lore.kernel.org/r/20210430070309.17624-9-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
  • Loading branch information
Adrian Hunter authored and Arnaldo Carvalho de Melo committed May 12, 2021
1 parent 335358c commit 0fc9d33
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 0 deletions.
2 changes: 2 additions & 0 deletions tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ struct intel_pt_decoder {
uint64_t max_insn_cnt, void *data);
bool (*pgd_ip)(uint64_t ip, void *data);
int (*lookahead)(void *data, intel_pt_lookahead_cb_t cb, void *cb_data);
struct intel_pt_vmcs_info *(*findnew_vmcs_info)(void *data, uint64_t vmcs);
void *data;
struct intel_pt_state state;
const unsigned char *buf;
Expand Down Expand Up @@ -258,6 +259,7 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params)
decoder->walk_insn = params->walk_insn;
decoder->pgd_ip = params->pgd_ip;
decoder->lookahead = params->lookahead;
decoder->findnew_vmcs_info = params->findnew_vmcs_info;
decoder->data = params->data;
decoder->return_compression = params->return_compression;
decoder->branch_enable = params->branch_enable;
Expand Down
11 changes: 11 additions & 0 deletions tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <stddef.h>
#include <stdbool.h>

#include <linux/rbtree.h>

#include "intel-pt-insn-decoder.h"

#define INTEL_PT_IN_TX (1 << 0)
Expand Down Expand Up @@ -199,6 +201,14 @@ struct intel_pt_blk_items {
bool is_32_bit;
};

struct intel_pt_vmcs_info {
struct rb_node rb_node;
uint64_t vmcs;
uint64_t tsc_offset;
bool reliable;
bool error_printed;
};

struct intel_pt_state {
enum intel_pt_sample_type type;
bool from_nr;
Expand Down Expand Up @@ -244,6 +254,7 @@ struct intel_pt_params {
uint64_t max_insn_cnt, void *data);
bool (*pgd_ip)(uint64_t ip, void *data);
int (*lookahead)(void *data, intel_pt_lookahead_cb_t cb, void *cb_data);
struct intel_pt_vmcs_info *(*findnew_vmcs_info)(void *data, uint64_t vmcs);
void *data;
bool return_compression;
bool branch_enable;
Expand Down
66 changes: 66 additions & 0 deletions tools/perf/util/intel-pt.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ struct intel_pt {

struct ip_callchain *chain;
struct branch_stack *br_stack;

u64 dflt_tsc_offset;
struct rb_root vmcs_info;
};

enum switch_state {
Expand Down Expand Up @@ -271,6 +274,65 @@ static bool intel_pt_log_events(struct intel_pt *pt, u64 tm)
return !n || !perf_time__ranges_skip_sample(range, n, tm);
}

static struct intel_pt_vmcs_info *intel_pt_findnew_vmcs(struct rb_root *rb_root,
u64 vmcs,
u64 dflt_tsc_offset)
{
struct rb_node **p = &rb_root->rb_node;
struct rb_node *parent = NULL;
struct intel_pt_vmcs_info *v;

while (*p) {
parent = *p;
v = rb_entry(parent, struct intel_pt_vmcs_info, rb_node);

if (v->vmcs == vmcs)
return v;

if (vmcs < v->vmcs)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}

v = zalloc(sizeof(*v));
if (v) {
v->vmcs = vmcs;
v->tsc_offset = dflt_tsc_offset;
v->reliable = dflt_tsc_offset;

rb_link_node(&v->rb_node, parent, p);
rb_insert_color(&v->rb_node, rb_root);
}

return v;
}

static struct intel_pt_vmcs_info *intel_pt_findnew_vmcs_info(void *data, uint64_t vmcs)
{
struct intel_pt_queue *ptq = data;
struct intel_pt *pt = ptq->pt;

if (!vmcs && !pt->dflt_tsc_offset)
return NULL;

return intel_pt_findnew_vmcs(&pt->vmcs_info, vmcs, pt->dflt_tsc_offset);
}

static void intel_pt_free_vmcs_info(struct intel_pt *pt)
{
struct intel_pt_vmcs_info *v;
struct rb_node *n;

n = rb_first(&pt->vmcs_info);
while (n) {
v = rb_entry(n, struct intel_pt_vmcs_info, rb_node);
n = rb_next(n);
rb_erase(&v->rb_node, &pt->vmcs_info);
free(v);
}
}

static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a,
struct auxtrace_buffer *b)
{
Expand Down Expand Up @@ -1109,6 +1171,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt,
params.get_trace = intel_pt_get_trace;
params.walk_insn = intel_pt_walk_next_insn;
params.lookahead = intel_pt_lookahead;
params.findnew_vmcs_info = intel_pt_findnew_vmcs_info;
params.data = ptq;
params.return_compression = intel_pt_return_compression(pt);
params.branch_enable = intel_pt_branch_enable(pt);
Expand Down Expand Up @@ -2970,6 +3033,7 @@ static void intel_pt_free(struct perf_session *session)
auxtrace_heap__free(&pt->heap);
intel_pt_free_events(session);
session->auxtrace = NULL;
intel_pt_free_vmcs_info(pt);
thread__put(pt->unknown_thread);
addr_filters__exit(&pt->filts);
zfree(&pt->chain);
Expand Down Expand Up @@ -3475,6 +3539,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
if (!pt)
return -ENOMEM;

pt->vmcs_info = RB_ROOT;

addr_filters__init(&pt->filts);

err = perf_config(intel_pt_perf_config, pt);
Expand Down

0 comments on commit 0fc9d33

Please sign in to comment.