lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sun,  7 Feb 2010 12:30:56 +0100
From:	highguy@...il.com
To:	mingo@...e.hu, linux-kernel@...r.kernel.org
Cc:	torvalds@...ux-foundation.org, efault@....de,
	a.p.zijlstra@...llo.nl, andrea@...e.de, tglx@...utronix.de,
	akpm@...ux-foundation.org, peterz@...radead.org,
	Stijn Devriendt <stijn@...jn.telenet.be>
Subject: [PATCH 3/6] Add handlers for adding counter events, reading counter events, counter resets, wakeups. Renamed old read handler to update.

From: Stijn Devriendt <stijn@...jn.telenet.be>

---
 arch/x86/kernel/cpu/perf_event.c |    4 +-
 include/linux/perf_event.h       |    8 ++-
 kernel/perf_event.c              |  120 +++++++++++++++++++++++++++-----------
 3 files changed, 94 insertions(+), 38 deletions(-)

diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index c223b7e..9738f22 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -2222,7 +2222,7 @@ void __init init_hw_perf_events(void)
 	pr_info("... event mask:             %016Lx\n", perf_event_mask);
 }
 
-static inline void x86_pmu_read(struct perf_event *event)
+static inline void x86_pmu_update(struct perf_event *event)
 {
 	x86_perf_event_update(event, &event->hw, event->hw.idx);
 }
@@ -2230,7 +2230,7 @@ static inline void x86_pmu_read(struct perf_event *event)
 static const struct pmu pmu = {
 	.enable		= x86_pmu_enable,
 	.disable	= x86_pmu_disable,
-	.read		= x86_pmu_read,
+	.update		= x86_pmu_update,
 	.unthrottle	= x86_pmu_unthrottle,
 };
 
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 0fa235e..4f7d318 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -513,8 +513,12 @@ struct perf_event;
 struct pmu {
 	int (*enable)			(struct perf_event *event);
 	void (*disable)			(struct perf_event *event);
-	void (*read)			(struct perf_event *event);
+	void (*update)			(struct perf_event *event);
 	void (*unthrottle)		(struct perf_event *event);
+	u64 (*add)                      (struct perf_event *event, u64 count);
+	int (*reset)                    (struct perf_event *event);
+	void (*wakeup)                  (struct perf_event *event);
+	u64 (*read)                     (struct perf_event *event);
 };
 
 /**
@@ -639,7 +643,7 @@ struct perf_event {
 	struct perf_mmap_data		*data;
 
 	/* poll related */
-	atomic_t			poll;		/* POLL_ for wakeups */
+	atomic_t			poll;		/* POLLX for wakeups */
 	wait_queue_head_t		waitq;
 	struct fasync_struct		*fasync;
 
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 70ca6e1..724aafd 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -1092,7 +1092,7 @@ static void __perf_event_sync_stat(struct perf_event *event,
 		return;
 
 	/*
-	 * Update the event value, we cannot use perf_event_read()
+	 * Update the event value, we cannot use perf_event_update()
 	 * because we're in the middle of a context switch and have IRQs
 	 * disabled, which upsets smp_call_function_single(), however
 	 * we know the event must be on the current CPU, therefore we
@@ -1100,7 +1100,7 @@ static void __perf_event_sync_stat(struct perf_event *event,
 	 */
 	switch (event->state) {
 	case PERF_EVENT_STATE_ACTIVE:
-		event->pmu->read(event);
+		event->pmu->update(event);
 		/* fall-through */
 
 	case PERF_EVENT_STATE_INACTIVE:
@@ -1534,10 +1534,23 @@ static void perf_event_enable_on_exec(struct task_struct *task)
 	local_irq_restore(flags);
 }
 
+static u64 __perf_event_read(struct perf_event *event)
+{
+	return atomic64_read(&event->count);
+}
+
+static u64 perf_event_read(struct perf_event *event)
+{
+	if (event->pmu->read)
+		return event->pmu->read(event);
+	else
+		return __perf_event_read(event);
+}
+
 /*
  * Cross CPU call to read the hardware event
  */
-static void __perf_event_read(void *info)
+static void __perf_event_update(void *info)
 {
 	struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
 	struct perf_event *event = info;
@@ -1558,10 +1571,10 @@ static void __perf_event_read(void *info)
 	update_event_times(event);
 	raw_spin_unlock(&ctx->lock);
 
-	event->pmu->read(event);
+	event->pmu->update(event);
 }
 
-static u64 perf_event_read(struct perf_event *event)
+static u64 perf_event_update(struct perf_event *event)
 {
 	/*
 	 * If event is enabled and currently active on a CPU, update the
@@ -1569,7 +1582,7 @@ static u64 perf_event_read(struct perf_event *event)
 	 */
 	if (event->state == PERF_EVENT_STATE_ACTIVE) {
 		smp_call_function_single(event->oncpu,
-					 __perf_event_read, event, 1);
+					 __perf_event_update, event, 1);
 	} else if (event->state == PERF_EVENT_STATE_INACTIVE) {
 		struct perf_event_context *ctx = event->ctx;
 		unsigned long flags;
@@ -1580,7 +1593,7 @@ static u64 perf_event_read(struct perf_event *event)
 		raw_spin_unlock_irqrestore(&ctx->lock, flags);
 	}
 
-	return atomic64_read(&event->count);
+	return perf_event_read(event);
 }
 
 /*
@@ -1793,14 +1806,14 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
 	*running = 0;
 
 	mutex_lock(&event->child_mutex);
-	total += perf_event_read(event);
+	total += perf_event_update(event);
 	*enabled += event->total_time_enabled +
 			atomic64_read(&event->child_total_time_enabled);
 	*running += event->total_time_running +
 			atomic64_read(&event->child_total_time_running);
 
 	list_for_each_entry(child, &event->child_list, child_list) {
-		total += perf_event_read(child);
+		total += perf_event_update(child);
 		*enabled += child->total_time_enabled;
 		*running += child->total_time_running;
 	}
@@ -1925,7 +1938,7 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
 
 	if (event->attr.threshold)
 	{
-		u64 count = atomic64_read(&event->count);
+		u64 count = perf_event_read(event);
 		if (count < event->attr.min_threshold)
 			events |= POLLIN;
 		else if (count > event->attr.max_threshold)
@@ -1937,13 +1950,25 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
 	return events;
 }
 
-static void perf_event_reset(struct perf_event *event)
+static void perf_event_reset_noop(struct perf_event *event)
+{
+}
+
+static void __perf_event_reset(struct perf_event *event)
 {
-	(void)perf_event_read(event);
+	(void)perf_event_update(event);
 	atomic64_set(&event->count, 0);
 	perf_event_update_userpage(event);
 }
 
+static void perf_event_reset(struct perf_event *event)
+{
+	if (event->pmu->reset)
+		event->pmu->reset(event);
+	else
+		__perf_event_reset(event);
+}
+
 /*
  * Holding the top-level event's child_mutex means that any
  * descendant process that has inherited this event will block
@@ -2123,7 +2148,7 @@ void perf_event_update_userpage(struct perf_event *event)
 	++userpg->lock;
 	barrier();
 	userpg->index = perf_event_index(event);
-	userpg->offset = atomic64_read(&event->count);
+	userpg->offset = perf_event_read(event);
 	if (event->state == PERF_EVENT_STATE_ACTIVE)
 		userpg->offset -= atomic64_read(&event->hw.prev_count);
 
@@ -2540,7 +2565,10 @@ static const struct file_operations perf_fops = {
 
 void perf_event_wakeup(struct perf_event *event)
 {
-	wake_up_all(&event->waitq);
+	if (event->pmu->wakeup)
+		event->pmu->wakeup(event);
+	else
+		wake_up_all(&event->waitq);
 
 	if (event->pending_kill) {
 		kill_fasync(&event->fasync, SIGIO, event->pending_kill);
@@ -2689,7 +2717,7 @@ static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail,
 
 static void __perf_output_wakeup(struct perf_event* event, int nmi)
 {
-	if (event->attr.threshold && atomic64_read(&event->count) > event->attr.max_threshold)
+	if (event->attr.threshold && perf_event_read(event) > event->attr.max_threshold)
 		return;
 	
 	atomic_set(&event->poll, POLLIN);
@@ -2912,7 +2940,7 @@ void perf_output_end(struct perf_output_handle *handle)
 	struct perf_event *event = handle->event;
 	struct perf_mmap_data *data = handle->data;
 
-	int wakeup_events = event->attr.thresold ? 1 : event->attr.wakeup_events;
+	int wakeup_events = event->attr.threshold ? 1 : event->attr.wakeup_events;
 
 	if (handle->sample && wakeup_events) {
 		int events = atomic_inc_return(&data->events);
@@ -2955,7 +2983,7 @@ static void perf_output_read_one(struct perf_output_handle *handle,
 	u64 values[4];
 	int n = 0;
 
-	values[n++] = atomic64_read(&event->count);
+	values[n++] = perf_event_read(event);
 	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
 		values[n++] = event->total_time_enabled +
 			atomic64_read(&event->child_total_time_enabled);
@@ -2990,7 +3018,7 @@ static void perf_output_read_group(struct perf_output_handle *handle,
 		values[n++] = leader->total_time_running;
 
 	if (leader != event)
-		leader->pmu->read(leader);
+		leader->pmu->update(leader);
 
 	values[n++] = atomic64_read(&leader->count);
 	if (read_format & PERF_FORMAT_ID)
@@ -3002,7 +3030,7 @@ static void perf_output_read_group(struct perf_output_handle *handle,
 		n = 0;
 
 		if (sub != event)
-			sub->pmu->read(sub);
+			sub->pmu->update(sub);
 
 		values[n++] = atomic64_read(&sub->count);
 		if (read_format & PERF_FORMAT_ID)
@@ -3737,6 +3765,29 @@ int perf_event_overflow(struct perf_event *event, int nmi,
 	return __perf_event_overflow(event, nmi, 1, data, regs);
 }
 
+static void perf_event_wakeup_one(struct perf_event *event)
+{
+	wake_up(&event->waitq);
+}
+
+static u64 __perf_event_add(struct perf_event *event, u64 count)
+{
+	return atomic64_add_return(count, &event->count);
+}
+
+static u64 perf_event_add(struct perf_event *event, u64 count)
+{
+	if (event->pmu->add)
+		return event->pmu->add(event, count);
+	else
+		return __perf_event_add(event, count);
+}
+
+static u64 perf_event_add_parent(struct perf_event *event, u64 count)
+{
+	return event->parent ? __perf_event_add(event->parent, count) : __perf_event_add(event, count);
+}
+
 /*
  * Generic software event infrastructure
  */
@@ -3811,7 +3862,7 @@ static void perf_swevent_add(struct perf_event *event, u64 nr,
 {
 	struct hw_perf_event *hwc = &event->hw;
 
-	atomic64_add(nr, &event->count);
+	perf_event_add(event, nr);
 
 	if (!regs)
 		return;
@@ -4011,10 +4062,11 @@ static void perf_swevent_disable(struct perf_event *event)
 {
 }
 
+
 static const struct pmu perf_ops_generic = {
 	.enable		= perf_swevent_enable,
 	.disable	= perf_swevent_disable,
-	.read		= perf_swevent_read,
+	.update		= perf_swevent_read,
 	.unthrottle	= perf_swevent_unthrottle,
 };
 
@@ -4031,7 +4083,7 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
 	u64 period;
 
 	event	= container_of(hrtimer, struct perf_event, hw.hrtimer);
-	event->pmu->read(event);
+	event->pmu->update(event);
 
 	data.addr = 0;
 	data.raw = NULL;
@@ -4097,7 +4149,7 @@ static void perf_swevent_cancel_hrtimer(struct perf_event *event)
  * Software event: cpu wall time clock
  */
 
-static void cpu_clock_perf_event_update(struct perf_event *event)
+static void __cpu_clock_perf_event_update(struct perf_event *event)
 {
 	int cpu = raw_smp_processor_id();
 	s64 prev;
@@ -4105,7 +4157,7 @@ static void cpu_clock_perf_event_update(struct perf_event *event)
 
 	now = cpu_clock(cpu);
 	prev = atomic64_xchg(&event->hw.prev_count, now);
-	atomic64_add(now - prev, &event->count);
+	perf_event_add(event, now - prev);
 }
 
 static int cpu_clock_perf_event_enable(struct perf_event *event)
@@ -4122,32 +4174,32 @@ static int cpu_clock_perf_event_enable(struct perf_event *event)
 static void cpu_clock_perf_event_disable(struct perf_event *event)
 {
 	perf_swevent_cancel_hrtimer(event);
-	cpu_clock_perf_event_update(event);
+	__cpu_clock_perf_event_update(event);
 }
 
-static void cpu_clock_perf_event_read(struct perf_event *event)
+static void cpu_clock_perf_event_update(struct perf_event *event)
 {
-	cpu_clock_perf_event_update(event);
+	__cpu_clock_perf_event_update(event);
 }
 
 static const struct pmu perf_ops_cpu_clock = {
 	.enable		= cpu_clock_perf_event_enable,
 	.disable	= cpu_clock_perf_event_disable,
-	.read		= cpu_clock_perf_event_read,
+	.update		= cpu_clock_perf_event_update,
 };
 
 /*
  * Software event: task time clock
  */
 
-static void task_clock_perf_event_update(struct perf_event *event, u64 now)
+static void __task_clock_perf_event_update(struct perf_event *event, u64 now)
 {
 	u64 prev;
 	s64 delta;
 
 	prev = atomic64_xchg(&event->hw.prev_count, now);
 	delta = now - prev;
-	atomic64_add(delta, &event->count);
+	perf_event_add(event, delta);
 }
 
 static int task_clock_perf_event_enable(struct perf_event *event)
@@ -4167,11 +4219,11 @@ static int task_clock_perf_event_enable(struct perf_event *event)
 static void task_clock_perf_event_disable(struct perf_event *event)
 {
 	perf_swevent_cancel_hrtimer(event);
-	task_clock_perf_event_update(event, event->ctx->time);
+	__task_clock_perf_event_update(event, event->ctx->time);
 
 }
 
-static void task_clock_perf_event_read(struct perf_event *event)
+static void task_clock_perf_event_update(struct perf_event *event)
 {
 	u64 time;
 
@@ -4184,13 +4236,13 @@ static void task_clock_perf_event_read(struct perf_event *event)
 		time = event->ctx->time + delta;
 	}
 
-	task_clock_perf_event_update(event, time);
+	__task_clock_perf_event_update(event, time);
 }
 
 static const struct pmu perf_ops_task_clock = {
 	.enable		= task_clock_perf_event_enable,
 	.disable	= task_clock_perf_event_disable,
-	.read		= task_clock_perf_event_read,
+	.update		= task_clock_perf_event_update,
 };
 
 #ifdef CONFIG_EVENT_PROFILE
-- 
1.6.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists