LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Jiri Olsa <jolsa@kernel.org>
To: Arnaldo Carvalho de Melo <acme@kernel.org>,
	Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: lkml <linux-kernel@vger.kernel.org>,
	Ingo Molnar <mingo@kernel.org>,
	Namhyung Kim <namhyung@kernel.org>,
	David Ahern <dsahern@gmail.com>,
	Alexander Shishkin <alexander.shishkin@linux.intel.com>,
	Stephane Eranian <eranian@google.com>,
	Milian Wolff <milian.wolff@kdab.com>,
	Andi Kleen <andi@firstfloor.org>,
	Frederic Weisbecker <frederic@kernel.org>
Subject: [PATCH 08/10] perf/cputime: Add cputime pmu
Date: Thu,  7 Jun 2018 00:15:11 +0200	[thread overview]
Message-ID: <20180606221513.11302-9-jolsa@kernel.org> (raw)
In-Reply-To: <20180606221513.11302-1-jolsa@kernel.org>

The CPUTIME_* counters account the time for CPU runtimes.
Adding 'cputime' PMU, that provides perf interface to those
counters.

The 'cputime' interface is standard software PMU, that provides
following events, meassuring their CPUTIME counterparts:

  PERF_CPUTIME_USER       - CPUTIME_USER
  PERF_CPUTIME_NICE       - CPUTIME_NICE
  PERF_CPUTIME_SYSTEM     - CPUTIME_SYSTEM
  PERF_CPUTIME_SOFTIRQ    - CPUTIME_SOFTIRQ
  PERF_CPUTIME_IRQ        - CPUTIME_IRQ
  PERF_CPUTIME_IDLE       - CPUTIME_IDLE
  PERF_CPUTIME_IOWAIT     - CPUTIME_IOWAIT
  PERF_CPUTIME_STEAL      - CPUTIME_STEAL
  PERF_CPUTIME_GUEST      - CPUTIME_GUEST
  PERF_CPUTIME_GUEST_NICE - CPUTIME_GUEST_NICE

The 'cputime' PMU adds 'events' and 'format' directory,
with above events specifics.

It can be used via perf tool like:

  # perf stat -e cputime/system/,cputime/user/ yes > /dev/null
  ^Cyes: Interrupt

   Performance counter stats for 'yes':

       2,177,550,368 ns   cputime/system/
         567,029,895 ns   cputime/user/

         2.749451438 seconds time elapsed

         0.567127000 seconds user
         2.177924000 seconds sys

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 include/linux/perf_event.h |   2 +
 kernel/events/Makefile     |   2 +-
 kernel/events/core.c       |   1 +
 kernel/events/cputime.c    | 198 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 202 insertions(+), 1 deletion(-)
 create mode 100644 kernel/events/cputime.c

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index bea0b0cd4bf7..aa9eaab370be 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1160,6 +1160,8 @@ static inline int perf_callchain_store(struct perf_callchain_entry_ctx *ctx, u64
 	}
 }
 
+extern int __init perf_cputime_register(void);
+
 extern int sysctl_perf_event_paranoid;
 extern int sysctl_perf_event_mlock;
 extern int sysctl_perf_event_sample_rate;
diff --git a/kernel/events/Makefile b/kernel/events/Makefile
index 3c022e33c109..02271b8433a7 100644
--- a/kernel/events/Makefile
+++ b/kernel/events/Makefile
@@ -3,7 +3,7 @@ ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_core.o = $(CC_FLAGS_FTRACE)
 endif
 
-obj-y := core.o ring_buffer.o callchain.o
+obj-y := core.o ring_buffer.o callchain.o cputime.o
 
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_UPROBES) += uprobes.o
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 08f5e1b42b43..27a8459ce576 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -11678,6 +11678,7 @@ void __init perf_event_init(void)
 	perf_pmu_register(&perf_cpu_clock, NULL, -1);
 	perf_pmu_register(&perf_task_clock, NULL, -1);
 	perf_tp_register();
+	perf_cputime_register();
 	perf_event_init_cpu(smp_processor_id());
 	register_reboot_notifier(&perf_reboot_notifier);
 
diff --git a/kernel/events/cputime.c b/kernel/events/cputime.c
new file mode 100644
index 000000000000..efad24543f13
--- /dev/null
+++ b/kernel/events/cputime.c
@@ -0,0 +1,198 @@
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/perf_event.h>
+
+enum perf_cputime_id {
+	PERF_CPUTIME_USER,
+	PERF_CPUTIME_NICE,
+	PERF_CPUTIME_SYSTEM,
+	PERF_CPUTIME_SOFTIRQ,
+	PERF_CPUTIME_IRQ,
+	PERF_CPUTIME_IDLE,
+	PERF_CPUTIME_IOWAIT,
+	PERF_CPUTIME_STEAL,
+	PERF_CPUTIME_GUEST,
+	PERF_CPUTIME_GUEST_NICE,
+	PERF_CPUTIME_MAX,
+};
+
+static enum cpu_usage_stat map[PERF_CPUTIME_MAX] = {
+	[PERF_CPUTIME_USER]		= CPUTIME_USER,
+	[PERF_CPUTIME_NICE]		= CPUTIME_NICE,
+	[PERF_CPUTIME_SYSTEM]		= CPUTIME_SYSTEM,
+	[PERF_CPUTIME_SOFTIRQ]		= CPUTIME_SOFTIRQ,
+	[PERF_CPUTIME_IRQ]		= CPUTIME_IRQ,
+	[PERF_CPUTIME_IDLE]		= CPUTIME_IDLE,
+	[PERF_CPUTIME_IOWAIT]		= CPUTIME_IOWAIT,
+	[PERF_CPUTIME_STEAL]		= CPUTIME_STEAL,
+	[PERF_CPUTIME_GUEST]		= CPUTIME_GUEST,
+	[PERF_CPUTIME_GUEST_NICE]	= CPUTIME_GUEST_NICE,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-63");
+
+static struct attribute *cputime_format_attrs[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group cputime_format_attr_group = {
+	.name = "format",
+	.attrs = cputime_format_attrs,
+};
+
+static ssize_t
+cputime_event_attr_show(struct device *dev, struct device_attribute *attr,
+		    char *page)
+{
+	struct perf_pmu_events_attr *pmu_attr =
+		container_of(attr, struct perf_pmu_events_attr, attr);
+
+	return sprintf(page, "event=%llu\n", pmu_attr->id);
+}
+
+#define __A(__n, __e)					\
+	PMU_EVENT_ATTR(__n, cputime_attr_##__n,		\
+		       __e, cputime_event_attr_show);	\
+	PMU_EVENT_ATTR_STRING(__n.unit,			\
+			cputime_attr_##__n##_unit, "ns");
+
+__A(user,	PERF_CPUTIME_USER)
+__A(nice,	PERF_CPUTIME_NICE)
+__A(system,	PERF_CPUTIME_SYSTEM)
+__A(softirq,	PERF_CPUTIME_SOFTIRQ)
+__A(irq,	PERF_CPUTIME_IRQ)
+__A(idle,	PERF_CPUTIME_IDLE)
+__A(iowait,	PERF_CPUTIME_IOWAIT)
+__A(steal,	PERF_CPUTIME_STEAL)
+__A(guest,	PERF_CPUTIME_GUEST)
+__A(guest_nice,	PERF_CPUTIME_GUEST_NICE)
+
+#undef __A
+
+static struct attribute *cputime_events_attrs[] = {
+#define __A(__n)				\
+	&cputime_attr_##__n.attr.attr,		\
+	&cputime_attr_##__n##_unit.attr.attr,
+
+	__A(user)
+	__A(nice)
+	__A(system)
+	__A(softirq)
+	__A(irq)
+	__A(idle)
+	__A(iowait)
+	__A(steal)
+	__A(guest)
+	__A(guest_nice)
+
+	NULL,
+
+#undef __A
+};
+
+static struct attribute_group cputime_events_attr_group = {
+	.name = "events",
+	.attrs = cputime_events_attrs,
+};
+
+static const struct attribute_group *cputime_attr_groups[] = {
+	&cputime_format_attr_group,
+	&cputime_events_attr_group,
+	NULL,
+};
+
+static u64 cputime_read_counter(struct perf_event *event)
+{
+	int cpu = event->oncpu;
+
+	return kcpustat_cpu(cpu).cpustat[event->hw.config];
+}
+
+static void perf_cputime_update(struct perf_event *event)
+{
+	u64 prev, now;
+	s64 delta;
+
+	/* Careful, an NMI might modify the previous event value: */
+again:
+	prev = local64_read(&event->hw.prev_count);
+	now = cputime_read_counter(event);
+
+	if (local64_cmpxchg(&event->hw.prev_count, prev, now) != prev)
+		goto again;
+
+	delta = now - prev;
+	local64_add(delta, &event->count);
+}
+
+static void cputime_event_start(struct perf_event *event, int flags)
+{
+	u64 now = cputime_read_counter(event);
+
+	local64_set(&event->hw.prev_count, now);
+}
+
+static void cputime_event_stop(struct perf_event *event, int flags)
+{
+	perf_cputime_update(event);
+}
+
+static int cputime_event_add(struct perf_event *event, int flags)
+{
+	if (flags & PERF_EF_START)
+		cputime_event_start(event, flags);
+
+	return 0;
+}
+
+static void cputime_event_del(struct perf_event *event, int flags)
+{
+	cputime_event_stop(event, PERF_EF_UPDATE);
+}
+
+static void perf_cputime_read(struct perf_event *event)
+{
+	perf_cputime_update(event);
+}
+
+static int cputime_event_init(struct perf_event *event)
+{
+	u64 cfg = event->attr.config;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	/* unsupported modes and filters */
+	if (event->attr.exclude_user   ||
+	    event->attr.exclude_kernel ||
+	    event->attr.exclude_hv     ||
+	    event->attr.exclude_idle   ||
+	    event->attr.exclude_host   ||
+	    event->attr.exclude_guest  ||
+	    event->attr.sample_period) /* no sampling */
+		return -EINVAL;
+
+	if (cfg >= PERF_CPUTIME_MAX)
+		return -EINVAL;
+
+	event->hw.config = map[cfg];
+	return 0;
+}
+
+static struct pmu perf_cputime = {
+	.task_ctx_nr	= perf_sw_context,
+	.attr_groups	= cputime_attr_groups,
+	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+	.event_init	= cputime_event_init,
+	.add		= cputime_event_add,
+	.del		= cputime_event_del,
+	.start		= cputime_event_start,
+	.stop		= cputime_event_stop,
+	.read		= perf_cputime_read,
+};
+
+int __init perf_cputime_register(void)
+{
+	return perf_pmu_register(&perf_cputime, "cputime", -1);
+}
-- 
2.13.6

  parent reply	other threads:[~2018-06-06 22:16 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-06 22:15 [RFC 00/10] perf: Add cputime events/metrics Jiri Olsa
2018-06-06 22:15 ` [PATCH 01/10] perf tools: Uniquify the event name if there's no other matched event Jiri Olsa
2018-06-06 23:19   ` Andi Kleen
2018-06-07  6:22     ` Jiri Olsa
2018-06-07 16:09       ` Stephane Eranian
2018-06-08  0:06         ` Jiri Olsa
2018-06-06 22:15 ` [PATCH 02/10] perf tools: Fix error index for pmu event parser Jiri Olsa
2018-06-07 18:53   ` Arnaldo Carvalho de Melo
2018-06-14  6:21   ` [tip:perf/urgent] " tip-bot for Jiri Olsa
2018-06-06 22:15 ` [PATCH 03/10] perf stat: Add --interval-clear option Jiri Olsa
2018-06-07 18:57   ` Arnaldo Carvalho de Melo
2018-06-14  6:21   ` [tip:perf/urgent] " tip-bot for Jiri Olsa
2018-06-06 22:15 ` [PATCH 04/10] perf stat: Use only color_fprintf call in print_metric_only Jiri Olsa
2018-06-07 19:00   ` Arnaldo Carvalho de Melo
2018-06-14  6:22   ` [tip:perf/urgent] " tip-bot for Jiri Olsa
2018-06-06 22:15 ` [PATCH 05/10] perf stat: Fix metric column display Jiri Olsa
2018-06-07 19:00   ` Arnaldo Carvalho de Melo
2018-06-14  6:22   ` [tip:perf/urgent] perf stat: Fix metric column header display alignment tip-bot for Jiri Olsa
2018-06-06 22:15 ` [PATCH 06/10] perf stat: Allow to specify specific metric column len Jiri Olsa
2018-06-14  6:23   ` [tip:perf/urgent] " tip-bot for Jiri Olsa
2018-06-06 22:15 ` [PATCH 07/10] perf stat: Add event parsing error handling to add_default_attributes Jiri Olsa
2018-06-07 19:04   ` Arnaldo Carvalho de Melo
2018-06-07 19:05     ` Arnaldo Carvalho de Melo
2018-06-14  6:23   ` [tip:perf/urgent] " tip-bot for Jiri Olsa
2018-06-06 22:15 ` Jiri Olsa [this message]
2018-06-06 22:15 ` [PATCH 09/10] perf/cputime: Don't stop idle tick if there's live cputime event Jiri Olsa
2018-06-07 15:45   ` Andi Kleen
2018-06-07 16:01     ` Stephane Eranian
2018-06-08  0:12       ` Jiri Olsa
2018-06-06 22:15 ` [PATCH 10/10] perf stat: Add cputime metric support Jiri Olsa
2018-06-06 23:10 ` [RFC 00/10] perf: Add cputime events/metrics Andi Kleen
2018-09-26 14:44   ` Milian Wolff
2018-09-26 21:48     ` Jiri Olsa

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180606221513.11302-9-jolsa@kernel.org \
    --to=jolsa@kernel.org \
    --cc=a.p.zijlstra@chello.nl \
    --cc=acme@kernel.org \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=andi@firstfloor.org \
    --cc=dsahern@gmail.com \
    --cc=eranian@google.com \
    --cc=frederic@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=milian.wolff@kdab.com \
    --cc=mingo@kernel.org \
    --cc=namhyung@kernel.org \
    --subject='Re: [PATCH 08/10] perf/cputime: Add cputime pmu' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).