Skip to content

Commit

Permalink
perf/x86/intel/pt: Split ToPA metadata and page layout
Browse files Browse the repository at this point in the history
PT uses page sized ToPA tables, where the ToPA table resides at the bottom
and its driver-specific metadata taking up a few words at the top of the
page. The split is currently calculated manually and needs to be redone
every time a field is added to or removed from the metadata structure.
Also, the 32-bit version can be made smaller.

By splitting the table and metadata into separate structures, we are making
the compiler figure out the division of the page.

Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Link: http://lkml.kernel.org/r/20190821124727.73310-5-alexander.shishkin@linux.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Alexander Shishkin authored and Ingo Molnar committed Aug 26, 2019
1 parent 539f7c2 commit 38bb8d7
Showing 1 changed file with 60 additions and 33 deletions.
93 changes: 60 additions & 33 deletions arch/x86/events/intel/pt.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,33 +545,55 @@ static void pt_config_buffer(void *buf, unsigned int topa_idx,
wrmsrl(MSR_IA32_RTIT_OUTPUT_MASK, reg);
}

/*
* Keep ToPA table-related metadata on the same page as the actual table,
* taking up a few words from the top
*/

#define TENTS_PER_PAGE (((PAGE_SIZE - 40) / sizeof(struct topa_entry)) - 1)

/**
* struct topa - page-sized ToPA table with metadata at the top
* @table: actual ToPA table entries, as understood by PT hardware
* struct topa - ToPA metadata
* @list: linkage to struct pt_buffer's list of tables
* @phys: physical address of this page
* @offset: offset of the first entry in this table in the buffer
* @size: total size of all entries in this table
* @last: index of the last initialized entry in this table
*/
struct topa {
struct topa_entry table[TENTS_PER_PAGE];
struct list_head list;
u64 phys;
u64 offset;
size_t size;
int last;
};

/*
* Keep ToPA table-related metadata on the same page as the actual table,
* taking up a few words from the top
*/

#define TENTS_PER_PAGE \
((PAGE_SIZE - sizeof(struct topa)) / sizeof(struct topa_entry))

/**
* struct topa_page - page-sized ToPA table with metadata at the top
* @table: actual ToPA table entries, as understood by PT hardware
* @topa: metadata
*/
struct topa_page {
struct topa_entry table[TENTS_PER_PAGE];
struct topa topa;
};

static inline struct topa_page *topa_to_page(struct topa *topa)
{
return container_of(topa, struct topa_page, topa);
}

static inline struct topa_page *topa_entry_to_page(struct topa_entry *te)
{
return (struct topa_page *)((unsigned long)te & PAGE_MASK);
}

/* make -1 stand for the last table entry */
#define TOPA_ENTRY(t, i) ((i) == -1 ? &(t)->table[(t)->last] : &(t)->table[(i)])
#define TOPA_ENTRY(t, i) \
((i) == -1 \
? &topa_to_page(t)->table[(t)->last] \
: &topa_to_page(t)->table[(i)])
#define TOPA_ENTRY_SIZE(t, i) (sizes(TOPA_ENTRY((t), (i))->size))

/**
Expand All @@ -584,27 +606,27 @@ struct topa {
static struct topa *topa_alloc(int cpu, gfp_t gfp)
{
int node = cpu_to_node(cpu);
struct topa *topa;
struct topa_page *tp;
struct page *p;

p = alloc_pages_node(node, gfp | __GFP_ZERO, 0);
if (!p)
return NULL;

topa = page_address(p);
topa->last = 0;
topa->phys = page_to_phys(p);
tp = page_address(p);
tp->topa.last = 0;
tp->topa.phys = page_to_phys(p);

/*
* In case of singe-entry ToPA, always put the self-referencing END
* link as the 2nd entry in the table
*/
if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries)) {
TOPA_ENTRY(topa, 1)->base = topa->phys >> TOPA_SHIFT;
TOPA_ENTRY(topa, 1)->end = 1;
TOPA_ENTRY(&tp->topa, 1)->base = tp->topa.phys;
TOPA_ENTRY(&tp->topa, 1)->end = 1;
}

return topa;
return &tp->topa;
}

/**
Expand Down Expand Up @@ -714,22 +736,23 @@ static void pt_topa_dump(struct pt_buffer *buf)
struct topa *topa;

list_for_each_entry(topa, &buf->tables, list) {
struct topa_page *tp = topa_to_page(topa);
int i;

pr_debug("# table @%p (%016Lx), off %llx size %zx\n", topa->table,
pr_debug("# table @%p (%016Lx), off %llx size %zx\n", tp->table,
topa->phys, topa->offset, topa->size);
for (i = 0; i < TENTS_PER_PAGE; i++) {
pr_debug("# entry @%p (%lx sz %u %c%c%c) raw=%16llx\n",
&topa->table[i],
(unsigned long)topa->table[i].base << TOPA_SHIFT,
sizes(topa->table[i].size),
topa->table[i].end ? 'E' : ' ',
topa->table[i].intr ? 'I' : ' ',
topa->table[i].stop ? 'S' : ' ',
*(u64 *)&topa->table[i]);
&tp->table[i],
(unsigned long)tp->table[i].base << TOPA_SHIFT,
sizes(tp->table[i].size),
tp->table[i].end ? 'E' : ' ',
tp->table[i].intr ? 'I' : ' ',
tp->table[i].stop ? 'S' : ' ',
*(u64 *)&tp->table[i]);
if ((intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) &&
topa->table[i].stop) ||
topa->table[i].end)
tp->table[i].stop) ||
tp->table[i].end)
break;
}
}
Expand Down Expand Up @@ -792,7 +815,7 @@ static void pt_update_head(struct pt *pt)
*/
static void *pt_buffer_region(struct pt_buffer *buf)
{
return phys_to_virt(buf->cur->table[buf->cur_idx].base << TOPA_SHIFT);
return phys_to_virt(TOPA_ENTRY(buf->cur, buf->cur_idx)->base << TOPA_SHIFT);
}

/**
Expand Down Expand Up @@ -869,9 +892,11 @@ static void pt_handle_status(struct pt *pt)
static void pt_read_offset(struct pt_buffer *buf)
{
u64 offset, base_topa;
struct topa_page *tp;

rdmsrl(MSR_IA32_RTIT_OUTPUT_BASE, base_topa);
buf->cur = phys_to_virt(base_topa);
tp = phys_to_virt(base_topa);
buf->cur = &tp->topa;

rdmsrl(MSR_IA32_RTIT_OUTPUT_MASK, offset);
/* offset within current output region */
Expand Down Expand Up @@ -1021,6 +1046,7 @@ static void pt_buffer_setup_topa_index(struct pt_buffer *buf)
*/
static void pt_buffer_reset_offsets(struct pt_buffer *buf, unsigned long head)
{
struct topa_page *cur_tp;
int pg;

if (buf->snapshot)
Expand All @@ -1029,7 +1055,8 @@ static void pt_buffer_reset_offsets(struct pt_buffer *buf, unsigned long head)
pg = (head >> PAGE_SHIFT) & (buf->nr_pages - 1);
pg = pt_topa_next_entry(buf, pg);

buf->cur = (struct topa *)((unsigned long)buf->topa_index[pg] & PAGE_MASK);
cur_tp = topa_entry_to_page(buf->topa_index[pg]);
buf->cur = &cur_tp->topa;
buf->cur_idx = buf->topa_index[pg] - TOPA_ENTRY(buf->cur, 0);
buf->output_off = head & (pt_buffer_region_size(buf) - 1);

Expand Down Expand Up @@ -1294,7 +1321,7 @@ void intel_pt_interrupt(void)
return;
}

pt_config_buffer(buf->cur->table, buf->cur_idx,
pt_config_buffer(topa_to_page(buf->cur)->table, buf->cur_idx,
buf->output_off);
pt_config(event);
}
Expand Down Expand Up @@ -1359,7 +1386,7 @@ static void pt_event_start(struct perf_event *event, int mode)
WRITE_ONCE(pt->handle_nmi, 1);
hwc->state = 0;

pt_config_buffer(buf->cur->table, buf->cur_idx,
pt_config_buffer(topa_to_page(buf->cur)->table, buf->cur_idx,
buf->output_off);
pt_config(event);

Expand Down

0 comments on commit 38bb8d7

Please sign in to comment.