Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf/core: Define PERF_PMU_TXN_READ interface

Define a new PERF_PMU_TXN_READ interface to read a group of counters
at once.

pmu->start_txn() // Initialize before first event

for each event in group
pmu->read(event); // Queue each event to be read

rc = pmu->commit_txn() // Read/update all queued counters

Note that we use this interface with all PMUs. PMUs that implement this
interface use the ->read() operation to _queue_ the counters to be read
and use ->commit_txn() to actually read all the queued counters at once.

PMUs that don't implement PERF_PMU_TXN_READ ignore ->start_txn() and
->commit_txn() and continue to read counters one at a time.

Thanks to input from Peter Zijlstra.

Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
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/1441336073-22750-9-git-send-email-sukadev@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Sukadev Bhattiprolu and committed by
Ingo Molnar
4a00c16e 7d88962e

+21 -6
+1
include/linux/perf_event.h
··· 202 202 #define PERF_EVENT_TXN 0x1 203 203 204 204 #define PERF_PMU_TXN_ADD 0x1 /* txn to add/schedule event on PMU */ 205 + #define PERF_PMU_TXN_READ 0x2 /* txn to read event group from PMU */ 205 206 206 207 /** 207 208 * pmu::capabilities flags
+20 -6
kernel/events/core.c
··· 3199 3199 struct perf_event *sub, *event = data->event; 3200 3200 struct perf_event_context *ctx = event->ctx; 3201 3201 struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); 3202 + struct pmu *pmu = event->pmu; 3202 3203 3203 3204 /* 3204 3205 * If this is a task context, we need to check whether it is ··· 3218 3217 } 3219 3218 3220 3219 update_event_times(event); 3221 - if (event->state == PERF_EVENT_STATE_ACTIVE) 3222 - event->pmu->read(event); 3223 - 3224 - if (!data->group) 3220 + if (event->state != PERF_EVENT_STATE_ACTIVE) 3225 3221 goto unlock; 3222 + 3223 + if (!data->group) { 3224 + pmu->read(event); 3225 + data->ret = 0; 3226 + goto unlock; 3227 + } 3228 + 3229 + pmu->start_txn(pmu, PERF_PMU_TXN_READ); 3230 + 3231 + pmu->read(event); 3226 3232 3227 3233 list_for_each_entry(sub, &event->sibling_list, group_entry) { 3228 3234 update_event_times(sub); 3229 - if (sub->state == PERF_EVENT_STATE_ACTIVE) 3235 + if (sub->state == PERF_EVENT_STATE_ACTIVE) { 3236 + /* 3237 + * Use sibling's PMU rather than @event's since 3238 + * sibling could be on different (eg: software) PMU. 3239 + */ 3230 3240 sub->pmu->read(sub); 3241 + } 3231 3242 } 3232 - data->ret = 0; 3243 + 3244 + data->ret = pmu->commit_txn(pmu); 3233 3245 3234 3246 unlock: 3235 3247 raw_spin_unlock(&ctx->lock);