linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V3 0/3] Integration of function trace with System Trace IP blocks
@ 2016-08-09  6:32 Chunyan Zhang
  2016-08-09  6:32 ` [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only Chunyan Zhang
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Chunyan Zhang @ 2016-08-09  6:32 UTC (permalink / raw)
  To: rostedt, mathieu.poirier, alexander.shishkin, mingo
  Cc: arnd, mike.leach, tor, maxime.coquelin, philippe.langlais,
	nicolas.guion, felipe.balbi, zhang.lyra, linux-kernel,
	linux-arm-kernel

IP blocks allowing a variety of trace sources to log debugging
information to a pre-defined area have been introduced on a couple of
architecture [1][2]. These system trace blocks (also known as STM)
typically follow the MIPI STPv2 protocol [3] and provide a system wide
logging facility to any device, running a kernel or not, with access
to the block's log entry port(s).  Since each trace message has a
timestamp, it is possible to correlate events happening in the entire
system rather than being confined to the logging facility of a single
entity.

This patchset is trying to use STM IP blocks to store some function
tracing information produced by Ftrace and I'm taking the Function trace
(TRACE_FN) as the example in this patchset, but other types of traces
also can be supported.

Logging information generated by the function trace subsystem
and gathered in the coresight sink can be used in conjunction with
trace data from other board components, also collected in the same
trace sink.  This example is using ARM coresight STM but the same would
apply to any architecture wishing to do the same.

In this patchset made many modifications according to the comments on
last patchset, the first two patches of this serial have been midified
completely. This patchset implemented the similar features, but in the
completely different way.

Comments and advice would be greatly appreciated.

Thanks,
Chunyan

[1]. https://lwn.net/Articles/674746/
[2]. http://lxr.free-electrons.com/source/drivers/hwtracing/intel_th/
[3]. http://mipi.org/specifications/debug#STP

Changes v3:
* Rebased on v4.8-rc1.
* Added trace_export class, and make traces can be exported to not only
ring buffer but also other area such as STM.
* Made stm_ftrace as an trace_export.
* More detailed changes are described in change log of each patch.

Changes v2:
* Addressed comments from Alexander Shishkin:
 - Modified some ambiguous change logs.
 - Decoupled stm_ftrace and trace_output interface to STM.
 - Changed the file name from stm_ftrace.c to stm/ftrace.c.
 - Implemented link/unlink hooks for stm_ftrace.
* Removed useless header file include from stm/ftrace.c
* Added Acked-by from Steven Rostedt on 4/4.

Chunyan Zhang (3):
  tracing: add a possibility of exporting function trace to other places
    instead of ring buffer only
  stm class: ftrace: Add ftrace-export-over-stm driver
  stm: Mark the functions of writing buffer with notrace

 drivers/hwtracing/coresight/coresight-stm.c |   2 +-
 drivers/hwtracing/intel_th/sth.c            |  11 ++-
 drivers/hwtracing/stm/Kconfig               |  11 +++
 drivers/hwtracing/stm/Makefile              |   2 +
 drivers/hwtracing/stm/core.c                |   7 +-
 drivers/hwtracing/stm/dummy_stm.c           |   2 +-
 drivers/hwtracing/stm/ftrace.c              |  87 +++++++++++++++++++
 include/linux/stm.h                         |   4 +-
 include/linux/trace.h                       |  31 +++++++
 kernel/trace/trace.c                        | 124 +++++++++++++++++++++++++++-
 kernel/trace/trace.h                        |  31 +++++++
 11 files changed, 300 insertions(+), 12 deletions(-)
 create mode 100644 drivers/hwtracing/stm/ftrace.c
 create mode 100644 include/linux/trace.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only
  2016-08-09  6:32 [PATCH V3 0/3] Integration of function trace with System Trace IP blocks Chunyan Zhang
@ 2016-08-09  6:32 ` Chunyan Zhang
  2016-08-09  6:58   ` Chunyan Zhang
  2016-08-09 15:35   ` Steven Rostedt
  2016-08-09  6:32 ` [PATCH V3 2/3] stm class: ftrace: Add ftrace-export-over-stm driver Chunyan Zhang
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 9+ messages in thread
From: Chunyan Zhang @ 2016-08-09  6:32 UTC (permalink / raw)
  To: rostedt, mathieu.poirier, alexander.shishkin, mingo
  Cc: arnd, mike.leach, tor, maxime.coquelin, philippe.langlais,
	nicolas.guion, felipe.balbi, zhang.lyra, linux-kernel,
	linux-arm-kernel

Currently ring buffer is the only output of Function traces, this patch
added trace_export concept which would process the traces and export
traces to a registered destination which can be ring buffer or some other
storage, in this way if we want Function traces to be sent to other
destination rather than ring buffer only, we just need to register a new
trace_export and implement its own .commit() callback or just use
'trace_generic_commit()' which this patch also added and hooks up its
own .write() functio for writing traces to the storage.

Currently, only Function trace (TRACE_FN) is supported.

Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
---
 include/linux/trace.h |  31 +++++++++++++
 kernel/trace/trace.c  | 124 +++++++++++++++++++++++++++++++++++++++++++++++++-
 kernel/trace/trace.h  |  31 +++++++++++++
 3 files changed, 185 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/trace.h

diff --git a/include/linux/trace.h b/include/linux/trace.h
new file mode 100644
index 0000000..bc7f503
--- /dev/null
+++ b/include/linux/trace.h
@@ -0,0 +1,31 @@
+#ifndef _LINUX_TRACE_H
+#define _LINUX_TRACE_H
+
+#include <linux/ring_buffer.h>
+struct trace_array;
+
+#ifdef CONFIG_TRACING
+/*
+ * The trace export - an export of function traces.  Every ftrace_ops
+ * has at least one export which would output function traces to ring
+ * buffer.
+ *
+ * tr		- the trace_array this export belongs to
+ * commit	- commit the traces to ring buffer and/or some other places
+ * write	- copy traces which have been delt with ->commit() to
+ *		  the destination
+ */
+struct trace_export {
+	char name[16];
+	struct trace_export	*next;
+	struct trace_array	*tr;
+	void (*commit)(struct trace_array *, struct ring_buffer_event *);
+	void (*write)(const char *, unsigned int);
+};
+
+int register_trace_export(struct trace_export *export);
+int unregister_trace_export(struct trace_export *export);
+
+#endif	/* CONFIG_TRACING */
+
+#endif	/* _LINUX_TRACE_H */
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index dade4c9..67ae581 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -40,6 +40,7 @@
 #include <linux/poll.h>
 #include <linux/nmi.h>
 #include <linux/fs.h>
+#include <linux/trace.h>
 #include <linux/sched/rt.h>
 
 #include "trace.h"
@@ -2128,6 +2129,127 @@ void trace_buffer_unlock_commit_regs(struct trace_array *tr,
 	ftrace_trace_userstack(buffer, flags, pc);
 }
 
+static inline void
+trace_generic_commit(struct trace_array *tr,
+	       struct ring_buffer_event *event)
+{
+	struct trace_entry *entry;
+	struct trace_export *export = tr->export;
+	unsigned int size = 0;
+
+	entry = ring_buffer_event_data(event);
+
+	trace_entry_size(size, entry->type);
+	if (!size)
+		return;
+
+	if (export->write)
+		export->write((char *)entry, size);
+}
+
+static inline void
+trace_rb_commit(struct trace_array *tr,
+	       struct ring_buffer_event *event)
+{
+	__buffer_unlock_commit(tr->trace_buffer.buffer, event);
+}
+
+static DEFINE_MUTEX(trace_export_lock);
+
+static struct trace_export trace_export_rb __read_mostly = {
+	.name		= "rb",
+	.commit	= trace_rb_commit,
+	.next		= NULL,
+};
+static struct trace_export *trace_fn_exports __read_mostly = &trace_export_rb;
+
+inline void
+trace_function_exports(struct trace_array *tr,
+		       struct ring_buffer_event *event)
+{
+	struct trace_export *export;
+
+	mutex_lock(&trace_export_lock);
+
+	for (export = trace_fn_exports; export && export->commit;
+	     export = export->next) {
+		tr->export = export;
+		export->commit(tr, event);
+	}
+
+	mutex_unlock(&trace_export_lock);
+}
+
+static void add_trace_fn_export(struct trace_export **list,
+			  struct trace_export *export)
+{
+	export->next = *list;
+	/*
+	 * We are entering export into the list but another
+	 * CPU might be walking that list. We need to make sure
+	 * the export->next pointer is valid before another CPU sees
+	 * the export pointer included into the list.
+	 */
+	rcu_assign_pointer(*list, export);
+
+}
+
+static int rm_trace_fn_export(struct trace_export **list,
+			  struct trace_export *export)
+{
+	struct trace_export **p;
+
+	for (p = list; *p != &trace_export_rb; p = &(*p)->next)
+		if (*p == export)
+			break;
+
+	if (*p != export)
+		return -1;
+
+	*p = (*p)->next;
+
+	return 0;
+}
+
+int register_trace_export(struct trace_export *export)
+{
+	if (!export->write) {
+		pr_warn("trace_export must have the write() call back.\n");
+		return -1;
+	}
+
+	mutex_lock(&trace_export_lock);
+
+	export->tr = trace_fn_exports->tr;
+	export->commit = trace_generic_commit;
+
+	add_trace_fn_export(&trace_fn_exports, export);
+
+	mutex_unlock(&trace_export_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(register_trace_export);
+
+int unregister_trace_export(struct trace_export *export)
+{
+	int ret;
+
+	if (!export->name) {
+		pr_warn("trace_export must have a name.\n");
+		return -1;
+	}
+
+	mutex_lock(&trace_export_lock);
+
+	ret = rm_trace_fn_export(&trace_fn_exports, export);
+
+	mutex_unlock(&trace_export_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(unregister_trace_export);
+
 void
 trace_function(struct trace_array *tr,
 	       unsigned long ip, unsigned long parent_ip, unsigned long flags,
@@ -2147,7 +2269,7 @@ trace_function(struct trace_array *tr,
 	entry->parent_ip		= parent_ip;
 
 	if (!call_filter_check_discard(call, entry, buffer, event))
-		__buffer_unlock_commit(buffer, event);
+		trace_function_exports(tr, event);
 }
 
 #ifdef CONFIG_STACKTRACE
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index f783df4..a40f07c 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -260,6 +260,7 @@ struct trace_array {
 	/* function tracing enabled */
 	int			function_enabled;
 #endif
+	struct trace_export	*export;
 };
 
 enum {
@@ -301,6 +302,13 @@ static inline struct trace_array *top_trace_array(void)
 		break;					\
 	}
 
+#undef IF_SIZE
+#define IF_SIZE(size, var, etype, id)		\
+		if (var == id) {		\
+			size = (sizeof(etype));	\
+			break;			\
+		}
+
 /* Will cause compile errors if type is not found. */
 extern void __ftrace_bad_type(void);
 
@@ -339,6 +347,29 @@ extern void __ftrace_bad_type(void);
 	} while (0)
 
 /*
+ * The trace_entry_size return the size of specific trace type
+ *
+ * IF_SIZE(size, var);
+ *
+ * Where "var" is just the given trace type.
+ */
+#define trace_entry_size(size, var)					\
+	do {								\
+		IF_SIZE(size, var, struct ftrace_entry, TRACE_FN);	\
+		IF_SIZE(size, var, struct stack_entry, TRACE_STACK);	\
+		IF_SIZE(size, var, struct userstack_entry,		\
+			TRACE_USER_STACK);				\
+		IF_SIZE(size, var, struct print_entry, TRACE_PRINT);	\
+		IF_SIZE(size, var, struct bprint_entry, TRACE_BPRINT);	\
+		IF_SIZE(size, var, struct bputs_entry, TRACE_BPUTS);	\
+		IF_SIZE(size, var, struct trace_branch, TRACE_BRANCH);	\
+		IF_SIZE(size, var, struct ftrace_graph_ent_entry,	\
+			TRACE_GRAPH_ENT);				\
+		IF_SIZE(size, var, struct ftrace_graph_ret_entry,	\
+			TRACE_GRAPH_RET);				\
+	} while (0)
+
+/*
  * An option specific to a tracer. This is a boolean value.
  * The bit is the bit index that sets its value on the
  * flags value in struct tracer_flags.
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH V3 2/3] stm class: ftrace: Add ftrace-export-over-stm driver
  2016-08-09  6:32 [PATCH V3 0/3] Integration of function trace with System Trace IP blocks Chunyan Zhang
  2016-08-09  6:32 ` [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only Chunyan Zhang
@ 2016-08-09  6:32 ` Chunyan Zhang
  2016-08-09  6:59   ` Chunyan Zhang
  2016-08-09  6:32 ` [PATCH V3 3/3] stm: Mark the functions of writing buffer with notrace Chunyan Zhang
  2016-08-09  6:57 ` [PATCH V3 0/3] Integration of function trace with System Trace IP blocks Chunyan Zhang
  3 siblings, 1 reply; 9+ messages in thread
From: Chunyan Zhang @ 2016-08-09  6:32 UTC (permalink / raw)
  To: rostedt, mathieu.poirier, alexander.shishkin, mingo
  Cc: arnd, mike.leach, tor, maxime.coquelin, philippe.langlais,
	nicolas.guion, felipe.balbi, zhang.lyra, linux-kernel,
	linux-arm-kernel

This patch adds a driver that models itself as an stm_source and
registers itself as a trace_export.  Once the stm and stm_source
have been linked via sysfs, everything that is passed to the
interface from Ftrace subsystem will endup in the STM trace engine.

Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
---
 drivers/hwtracing/stm/Kconfig  | 11 ++++++
 drivers/hwtracing/stm/Makefile |  2 +
 drivers/hwtracing/stm/ftrace.c | 87 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+)
 create mode 100644 drivers/hwtracing/stm/ftrace.c

diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig
index 847a39b..b34ea96 100644
--- a/drivers/hwtracing/stm/Kconfig
+++ b/drivers/hwtracing/stm/Kconfig
@@ -39,4 +39,15 @@ config STM_SOURCE_HEARTBEAT
 	  If you want to send heartbeat messages over STM devices,
 	  say Y.
 
+config STM_SOURCE_FTRACE
+	tristate "Copy the output from kernel Ftrace to STM engine"
+	depends on TRACING
+	help
+	  This option can be used to copy the output from kernel Ftrace
+	  to STM engine. Enabling this option will introduce a slight
+	  timing effect.
+
+	  If you want to send kernel Ftrace messages over STM devices,
+	  say Y.
+
 endif
diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile
index a9ce3d4..3abd84c 100644
--- a/drivers/hwtracing/stm/Makefile
+++ b/drivers/hwtracing/stm/Makefile
@@ -6,6 +6,8 @@ obj-$(CONFIG_STM_DUMMY)	+= dummy_stm.o
 
 obj-$(CONFIG_STM_SOURCE_CONSOLE)	+= stm_console.o
 obj-$(CONFIG_STM_SOURCE_HEARTBEAT)	+= stm_heartbeat.o
+obj-$(CONFIG_STM_SOURCE_FTRACE)		+= stm_ftrace.o
 
 stm_console-y		:= console.o
 stm_heartbeat-y		:= heartbeat.o
+stm_ftrace-y		:= ftrace.o
diff --git a/drivers/hwtracing/stm/ftrace.c b/drivers/hwtracing/stm/ftrace.c
new file mode 100644
index 0000000..1101f46
--- /dev/null
+++ b/drivers/hwtracing/stm/ftrace.c
@@ -0,0 +1,87 @@
+/*
+ * Simple kernel driver to link kernel Ftrace and an STM device
+ * Copyright (c) 2016, Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/stm.h>
+#include <linux/trace.h>
+
+#define STM_FTRACE_NR_CHANNELS 1
+#define STM_FTRACE_CHAN 0
+
+static int stm_ftrace_link(struct stm_source_data *data);
+static void stm_ftrace_unlink(struct stm_source_data *data);
+
+static struct stm_ftrace {
+	struct stm_source_data	data;
+	struct trace_export	ftrace;
+} stm_ftrace = {
+	.data	= {
+		.name		= "ftrace",
+		.nr_chans	= STM_FTRACE_NR_CHANNELS,
+		.link		= stm_ftrace_link,
+		.unlink		= stm_ftrace_unlink,
+	},
+};
+
+/**
+ * stm_ftrace_write() - write data to STM via 'stm_ftrace' source
+ * @buf:	buffer containing the data packet
+ * @len:	length of the data packet
+ */
+static void notrace
+stm_ftrace_write(const char *buf, unsigned int len)
+{
+	stm_source_write(&stm_ftrace.data, STM_FTRACE_CHAN, buf, len);
+}
+
+static int stm_ftrace_link(struct stm_source_data *data)
+{
+	struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data);
+
+	strcpy(sf->ftrace.name, "stm_ftrace");
+	sf->ftrace.write = stm_ftrace_write;
+	sf->ftrace.next = NULL;
+
+	return register_trace_export(&sf->ftrace);
+}
+
+static void stm_ftrace_unlink(struct stm_source_data *data)
+{
+	struct stm_ftrace *sc = container_of(data, struct stm_ftrace, data);
+
+	unregister_trace_export(&sc->ftrace);
+}
+
+static int __init stm_ftrace_init(void)
+{
+	int ret;
+
+	ret = stm_source_register_device(NULL, &stm_ftrace.data);
+	if (ret)
+		pr_err("Failed to register stm_source - ftrace.\n");
+
+	return ret;
+}
+
+static void __exit stm_ftrace_exit(void)
+{
+	stm_source_unregister_device(&stm_ftrace.data);
+}
+
+module_init(stm_ftrace_init);
+module_exit(stm_ftrace_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("stm_ftrace driver");
+MODULE_AUTHOR("Chunyan Zhang <zhang.chunyan@linaro.org>");
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH V3 3/3] stm: Mark the functions of writing buffer with notrace
  2016-08-09  6:32 [PATCH V3 0/3] Integration of function trace with System Trace IP blocks Chunyan Zhang
  2016-08-09  6:32 ` [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only Chunyan Zhang
  2016-08-09  6:32 ` [PATCH V3 2/3] stm class: ftrace: Add ftrace-export-over-stm driver Chunyan Zhang
@ 2016-08-09  6:32 ` Chunyan Zhang
  2016-08-09  6:57 ` [PATCH V3 0/3] Integration of function trace with System Trace IP blocks Chunyan Zhang
  3 siblings, 0 replies; 9+ messages in thread
From: Chunyan Zhang @ 2016-08-09  6:32 UTC (permalink / raw)
  To: rostedt, mathieu.poirier, alexander.shishkin, mingo
  Cc: arnd, mike.leach, tor, maxime.coquelin, philippe.langlais,
	nicolas.guion, felipe.balbi, zhang.lyra, linux-kernel,
	linux-arm-kernel

If CONFIG_STM_FTRACE is selected, Function trace data can be writen
to sink via STM, all functions that related to writing data packets
to STM should be marked 'notrace' to avoid being traced by Ftrace,
otherwise the program would stall into an endless loop.

Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
---
 drivers/hwtracing/coresight/coresight-stm.c |  2 +-
 drivers/hwtracing/intel_th/sth.c            | 11 +++++++----
 drivers/hwtracing/stm/core.c                |  7 ++++---
 drivers/hwtracing/stm/dummy_stm.c           |  2 +-
 include/linux/stm.h                         |  4 ++--
 5 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index 73be58a..345c81e 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -386,7 +386,7 @@ static long stm_generic_set_options(struct stm_data *stm_data,
 	return 0;
 }
 
-static ssize_t stm_generic_packet(struct stm_data *stm_data,
+static ssize_t notrace stm_generic_packet(struct stm_data *stm_data,
 				  unsigned int master,
 				  unsigned int channel,
 				  unsigned int packet,
diff --git a/drivers/hwtracing/intel_th/sth.c b/drivers/hwtracing/intel_th/sth.c
index e1aee61..b034446 100644
--- a/drivers/hwtracing/intel_th/sth.c
+++ b/drivers/hwtracing/intel_th/sth.c
@@ -67,10 +67,13 @@ static void sth_iowrite(void __iomem *dest, const unsigned char *payload,
 	}
 }
 
-static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master,
-			      unsigned int channel, unsigned int packet,
-			      unsigned int flags, unsigned int size,
-			      const unsigned char *payload)
+static ssize_t notrace sth_stm_packet(struct stm_data *stm_data,
+				      unsigned int master,
+				      unsigned int channel,
+				      unsigned int packet,
+				      unsigned int flags,
+				      unsigned int size,
+				      const unsigned char *payload)
 {
 	struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
 	struct intel_th_channel __iomem *out =
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
index 51f81d6..37d3bcb 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -425,7 +425,7 @@ static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width)
 	return ret;
 }
 
-static ssize_t stm_write(struct stm_data *data, unsigned int master,
+static ssize_t notrace stm_write(struct stm_data *data, unsigned int master,
 			  unsigned int channel, const char *buf, size_t count)
 {
 	unsigned int flags = STP_PACKET_TIMESTAMPED;
@@ -1121,8 +1121,9 @@ void stm_source_unregister_device(struct stm_source_data *data)
 }
 EXPORT_SYMBOL_GPL(stm_source_unregister_device);
 
-int stm_source_write(struct stm_source_data *data, unsigned int chan,
-		     const char *buf, size_t count)
+int notrace stm_source_write(struct stm_source_data *data,
+			     unsigned int chan,
+			     const char *buf, size_t count)
 {
 	struct stm_source_device *src = data->src;
 	struct stm_device *stm;
diff --git a/drivers/hwtracing/stm/dummy_stm.c b/drivers/hwtracing/stm/dummy_stm.c
index a86612d..c5f94ca 100644
--- a/drivers/hwtracing/stm/dummy_stm.c
+++ b/drivers/hwtracing/stm/dummy_stm.c
@@ -21,7 +21,7 @@
 #include <linux/slab.h>
 #include <linux/stm.h>
 
-static ssize_t
+static ssize_t notrace
 dummy_stm_packet(struct stm_data *stm_data, unsigned int master,
 		 unsigned int channel, unsigned int packet, unsigned int flags,
 		 unsigned int size, const unsigned char *payload)
diff --git a/include/linux/stm.h b/include/linux/stm.h
index 8369d8a..210ff22 100644
--- a/include/linux/stm.h
+++ b/include/linux/stm.h
@@ -133,7 +133,7 @@ int stm_source_register_device(struct device *parent,
 			       struct stm_source_data *data);
 void stm_source_unregister_device(struct stm_source_data *data);
 
-int stm_source_write(struct stm_source_data *data, unsigned int chan,
-		     const char *buf, size_t count);
+int notrace stm_source_write(struct stm_source_data *data, unsigned int chan,
+			     const char *buf, size_t count);
 
 #endif /* _STM_H_ */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH V3 0/3] Integration of function trace with System Trace IP blocks
  2016-08-09  6:32 [PATCH V3 0/3] Integration of function trace with System Trace IP blocks Chunyan Zhang
                   ` (2 preceding siblings ...)
  2016-08-09  6:32 ` [PATCH V3 3/3] stm: Mark the functions of writing buffer with notrace Chunyan Zhang
@ 2016-08-09  6:57 ` Chunyan Zhang
  3 siblings, 0 replies; 9+ messages in thread
From: Chunyan Zhang @ 2016-08-09  6:57 UTC (permalink / raw)
  To: Steven Rostedt, Mathieu Poirier, Alexander Shishkin, mingo
  Cc: Arnd Bergmann, Mike Leach, Tor Jeremiassen, philippe.langlais,
	Nicolas GUION, felipe.balbi, Lyra Zhang, linux-kernel,
	linux-arm-kernel

Removing maxime.coquelin@st.com since it seems an unreachable address

On Tue, Aug 9, 2016 at 2:32 PM, Chunyan Zhang <zhang.chunyan@linaro.org> wrote:
> IP blocks allowing a variety of trace sources to log debugging
> information to a pre-defined area have been introduced on a couple of
> architecture [1][2]. These system trace blocks (also known as STM)
> typically follow the MIPI STPv2 protocol [3] and provide a system wide
> logging facility to any device, running a kernel or not, with access
> to the block's log entry port(s).  Since each trace message has a
> timestamp, it is possible to correlate events happening in the entire
> system rather than being confined to the logging facility of a single
> entity.
>
> This patchset is trying to use STM IP blocks to store some function
> tracing information produced by Ftrace and I'm taking the Function trace
> (TRACE_FN) as the example in this patchset, but other types of traces
> also can be supported.
>
> Logging information generated by the function trace subsystem
> and gathered in the coresight sink can be used in conjunction with
> trace data from other board components, also collected in the same
> trace sink.  This example is using ARM coresight STM but the same would
> apply to any architecture wishing to do the same.
>
> In this patchset made many modifications according to the comments on
> last patchset, the first two patches of this serial have been midified
> completely. This patchset implemented the similar features, but in the
> completely different way.
>
> Comments and advice would be greatly appreciated.
>
> Thanks,
> Chunyan
>
> [1]. https://lwn.net/Articles/674746/
> [2]. http://lxr.free-electrons.com/source/drivers/hwtracing/intel_th/
> [3]. http://mipi.org/specifications/debug#STP
>
> Changes v3:
> * Rebased on v4.8-rc1.
> * Added trace_export class, and make traces can be exported to not only
> ring buffer but also other area such as STM.
> * Made stm_ftrace as an trace_export.
> * More detailed changes are described in change log of each patch.
>
> Changes v2:
> * Addressed comments from Alexander Shishkin:
>  - Modified some ambiguous change logs.
>  - Decoupled stm_ftrace and trace_output interface to STM.
>  - Changed the file name from stm_ftrace.c to stm/ftrace.c.
>  - Implemented link/unlink hooks for stm_ftrace.
> * Removed useless header file include from stm/ftrace.c
> * Added Acked-by from Steven Rostedt on 4/4.
>
> Chunyan Zhang (3):
>   tracing: add a possibility of exporting function trace to other places
>     instead of ring buffer only
>   stm class: ftrace: Add ftrace-export-over-stm driver
>   stm: Mark the functions of writing buffer with notrace
>
>  drivers/hwtracing/coresight/coresight-stm.c |   2 +-
>  drivers/hwtracing/intel_th/sth.c            |  11 ++-
>  drivers/hwtracing/stm/Kconfig               |  11 +++
>  drivers/hwtracing/stm/Makefile              |   2 +
>  drivers/hwtracing/stm/core.c                |   7 +-
>  drivers/hwtracing/stm/dummy_stm.c           |   2 +-
>  drivers/hwtracing/stm/ftrace.c              |  87 +++++++++++++++++++
>  include/linux/stm.h                         |   4 +-
>  include/linux/trace.h                       |  31 +++++++
>  kernel/trace/trace.c                        | 124 +++++++++++++++++++++++++++-
>  kernel/trace/trace.h                        |  31 +++++++
>  11 files changed, 300 insertions(+), 12 deletions(-)
>  create mode 100644 drivers/hwtracing/stm/ftrace.c
>  create mode 100644 include/linux/trace.h
>
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only
  2016-08-09  6:32 ` [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only Chunyan Zhang
@ 2016-08-09  6:58   ` Chunyan Zhang
  2016-08-09 15:35   ` Steven Rostedt
  1 sibling, 0 replies; 9+ messages in thread
From: Chunyan Zhang @ 2016-08-09  6:58 UTC (permalink / raw)
  To: Steven Rostedt, Mathieu Poirier, Alexander Shishkin, mingo
  Cc: Arnd Bergmann, Mike Leach, Tor Jeremiassen, philippe.langlais,
	Nicolas GUION, felipe.balbi, Lyra Zhang, linux-kernel,
	linux-arm-kernel

Removing maxime.coquelin@st.com since it seems an unreachable address

On Tue, Aug 9, 2016 at 2:32 PM, Chunyan Zhang <zhang.chunyan@linaro.org> wrote:
> Currently ring buffer is the only output of Function traces, this patch
> added trace_export concept which would process the traces and export
> traces to a registered destination which can be ring buffer or some other
> storage, in this way if we want Function traces to be sent to other
> destination rather than ring buffer only, we just need to register a new
> trace_export and implement its own .commit() callback or just use
> 'trace_generic_commit()' which this patch also added and hooks up its
> own .write() functio for writing traces to the storage.
>
> Currently, only Function trace (TRACE_FN) is supported.
>
> Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
> ---
>  include/linux/trace.h |  31 +++++++++++++
>  kernel/trace/trace.c  | 124 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  kernel/trace/trace.h  |  31 +++++++++++++
>  3 files changed, 185 insertions(+), 1 deletion(-)
>  create mode 100644 include/linux/trace.h
>
> diff --git a/include/linux/trace.h b/include/linux/trace.h
> new file mode 100644
> index 0000000..bc7f503
> --- /dev/null
> +++ b/include/linux/trace.h
> @@ -0,0 +1,31 @@
> +#ifndef _LINUX_TRACE_H
> +#define _LINUX_TRACE_H
> +
> +#include <linux/ring_buffer.h>
> +struct trace_array;
> +
> +#ifdef CONFIG_TRACING
> +/*
> + * The trace export - an export of function traces.  Every ftrace_ops
> + * has at least one export which would output function traces to ring
> + * buffer.
> + *
> + * tr          - the trace_array this export belongs to
> + * commit      - commit the traces to ring buffer and/or some other places
> + * write       - copy traces which have been delt with ->commit() to
> + *               the destination
> + */
> +struct trace_export {
> +       char name[16];
> +       struct trace_export     *next;
> +       struct trace_array      *tr;
> +       void (*commit)(struct trace_array *, struct ring_buffer_event *);
> +       void (*write)(const char *, unsigned int);
> +};
> +
> +int register_trace_export(struct trace_export *export);
> +int unregister_trace_export(struct trace_export *export);
> +
> +#endif /* CONFIG_TRACING */
> +
> +#endif /* _LINUX_TRACE_H */
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index dade4c9..67ae581 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -40,6 +40,7 @@
>  #include <linux/poll.h>
>  #include <linux/nmi.h>
>  #include <linux/fs.h>
> +#include <linux/trace.h>
>  #include <linux/sched/rt.h>
>
>  #include "trace.h"
> @@ -2128,6 +2129,127 @@ void trace_buffer_unlock_commit_regs(struct trace_array *tr,
>         ftrace_trace_userstack(buffer, flags, pc);
>  }
>
> +static inline void
> +trace_generic_commit(struct trace_array *tr,
> +              struct ring_buffer_event *event)
> +{
> +       struct trace_entry *entry;
> +       struct trace_export *export = tr->export;
> +       unsigned int size = 0;
> +
> +       entry = ring_buffer_event_data(event);
> +
> +       trace_entry_size(size, entry->type);
> +       if (!size)
> +               return;
> +
> +       if (export->write)
> +               export->write((char *)entry, size);
> +}
> +
> +static inline void
> +trace_rb_commit(struct trace_array *tr,
> +              struct ring_buffer_event *event)
> +{
> +       __buffer_unlock_commit(tr->trace_buffer.buffer, event);
> +}
> +
> +static DEFINE_MUTEX(trace_export_lock);
> +
> +static struct trace_export trace_export_rb __read_mostly = {
> +       .name           = "rb",
> +       .commit = trace_rb_commit,
> +       .next           = NULL,
> +};
> +static struct trace_export *trace_fn_exports __read_mostly = &trace_export_rb;
> +
> +inline void
> +trace_function_exports(struct trace_array *tr,
> +                      struct ring_buffer_event *event)
> +{
> +       struct trace_export *export;
> +
> +       mutex_lock(&trace_export_lock);
> +
> +       for (export = trace_fn_exports; export && export->commit;
> +            export = export->next) {
> +               tr->export = export;
> +               export->commit(tr, event);
> +       }
> +
> +       mutex_unlock(&trace_export_lock);
> +}
> +
> +static void add_trace_fn_export(struct trace_export **list,
> +                         struct trace_export *export)
> +{
> +       export->next = *list;
> +       /*
> +        * We are entering export into the list but another
> +        * CPU might be walking that list. We need to make sure
> +        * the export->next pointer is valid before another CPU sees
> +        * the export pointer included into the list.
> +        */
> +       rcu_assign_pointer(*list, export);
> +
> +}
> +
> +static int rm_trace_fn_export(struct trace_export **list,
> +                         struct trace_export *export)
> +{
> +       struct trace_export **p;
> +
> +       for (p = list; *p != &trace_export_rb; p = &(*p)->next)
> +               if (*p == export)
> +                       break;
> +
> +       if (*p != export)
> +               return -1;
> +
> +       *p = (*p)->next;
> +
> +       return 0;
> +}
> +
> +int register_trace_export(struct trace_export *export)
> +{
> +       if (!export->write) {
> +               pr_warn("trace_export must have the write() call back.\n");
> +               return -1;
> +       }
> +
> +       mutex_lock(&trace_export_lock);
> +
> +       export->tr = trace_fn_exports->tr;
> +       export->commit = trace_generic_commit;
> +
> +       add_trace_fn_export(&trace_fn_exports, export);
> +
> +       mutex_unlock(&trace_export_lock);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(register_trace_export);
> +
> +int unregister_trace_export(struct trace_export *export)
> +{
> +       int ret;
> +
> +       if (!export->name) {
> +               pr_warn("trace_export must have a name.\n");
> +               return -1;
> +       }
> +
> +       mutex_lock(&trace_export_lock);
> +
> +       ret = rm_trace_fn_export(&trace_fn_exports, export);
> +
> +       mutex_unlock(&trace_export_lock);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(unregister_trace_export);
> +
>  void
>  trace_function(struct trace_array *tr,
>                unsigned long ip, unsigned long parent_ip, unsigned long flags,
> @@ -2147,7 +2269,7 @@ trace_function(struct trace_array *tr,
>         entry->parent_ip                = parent_ip;
>
>         if (!call_filter_check_discard(call, entry, buffer, event))
> -               __buffer_unlock_commit(buffer, event);
> +               trace_function_exports(tr, event);
>  }
>
>  #ifdef CONFIG_STACKTRACE
> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
> index f783df4..a40f07c 100644
> --- a/kernel/trace/trace.h
> +++ b/kernel/trace/trace.h
> @@ -260,6 +260,7 @@ struct trace_array {
>         /* function tracing enabled */
>         int                     function_enabled;
>  #endif
> +       struct trace_export     *export;
>  };
>
>  enum {
> @@ -301,6 +302,13 @@ static inline struct trace_array *top_trace_array(void)
>                 break;                                  \
>         }
>
> +#undef IF_SIZE
> +#define IF_SIZE(size, var, etype, id)          \
> +               if (var == id) {                \
> +                       size = (sizeof(etype)); \
> +                       break;                  \
> +               }
> +
>  /* Will cause compile errors if type is not found. */
>  extern void __ftrace_bad_type(void);
>
> @@ -339,6 +347,29 @@ extern void __ftrace_bad_type(void);
>         } while (0)
>
>  /*
> + * The trace_entry_size return the size of specific trace type
> + *
> + * IF_SIZE(size, var);
> + *
> + * Where "var" is just the given trace type.
> + */
> +#define trace_entry_size(size, var)                                    \
> +       do {                                                            \
> +               IF_SIZE(size, var, struct ftrace_entry, TRACE_FN);      \
> +               IF_SIZE(size, var, struct stack_entry, TRACE_STACK);    \
> +               IF_SIZE(size, var, struct userstack_entry,              \
> +                       TRACE_USER_STACK);                              \
> +               IF_SIZE(size, var, struct print_entry, TRACE_PRINT);    \
> +               IF_SIZE(size, var, struct bprint_entry, TRACE_BPRINT);  \
> +               IF_SIZE(size, var, struct bputs_entry, TRACE_BPUTS);    \
> +               IF_SIZE(size, var, struct trace_branch, TRACE_BRANCH);  \
> +               IF_SIZE(size, var, struct ftrace_graph_ent_entry,       \
> +                       TRACE_GRAPH_ENT);                               \
> +               IF_SIZE(size, var, struct ftrace_graph_ret_entry,       \
> +                       TRACE_GRAPH_RET);                               \
> +       } while (0)
> +
> +/*
>   * An option specific to a tracer. This is a boolean value.
>   * The bit is the bit index that sets its value on the
>   * flags value in struct tracer_flags.
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH V3 2/3] stm class: ftrace: Add ftrace-export-over-stm driver
  2016-08-09  6:32 ` [PATCH V3 2/3] stm class: ftrace: Add ftrace-export-over-stm driver Chunyan Zhang
@ 2016-08-09  6:59   ` Chunyan Zhang
  0 siblings, 0 replies; 9+ messages in thread
From: Chunyan Zhang @ 2016-08-09  6:59 UTC (permalink / raw)
  To: Steven Rostedt, Mathieu Poirier, Alexander Shishkin, mingo
  Cc: Arnd Bergmann, Mike Leach, Tor Jeremiassen, philippe.langlais,
	Nicolas GUION, felipe.balbi, Lyra Zhang, linux-kernel,
	linux-arm-kernel

Removing maxime.coquelin@st.com since it seems an unreachable address

On Tue, Aug 9, 2016 at 2:32 PM, Chunyan Zhang <zhang.chunyan@linaro.org> wrote:
> This patch adds a driver that models itself as an stm_source and
> registers itself as a trace_export.  Once the stm and stm_source
> have been linked via sysfs, everything that is passed to the
> interface from Ftrace subsystem will endup in the STM trace engine.
>
> Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
> ---
>  drivers/hwtracing/stm/Kconfig  | 11 ++++++
>  drivers/hwtracing/stm/Makefile |  2 +
>  drivers/hwtracing/stm/ftrace.c | 87 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 100 insertions(+)
>  create mode 100644 drivers/hwtracing/stm/ftrace.c
>
> diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig
> index 847a39b..b34ea96 100644
> --- a/drivers/hwtracing/stm/Kconfig
> +++ b/drivers/hwtracing/stm/Kconfig
> @@ -39,4 +39,15 @@ config STM_SOURCE_HEARTBEAT
>           If you want to send heartbeat messages over STM devices,
>           say Y.
>
> +config STM_SOURCE_FTRACE
> +       tristate "Copy the output from kernel Ftrace to STM engine"
> +       depends on TRACING
> +       help
> +         This option can be used to copy the output from kernel Ftrace
> +         to STM engine. Enabling this option will introduce a slight
> +         timing effect.
> +
> +         If you want to send kernel Ftrace messages over STM devices,
> +         say Y.
> +
>  endif
> diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile
> index a9ce3d4..3abd84c 100644
> --- a/drivers/hwtracing/stm/Makefile
> +++ b/drivers/hwtracing/stm/Makefile
> @@ -6,6 +6,8 @@ obj-$(CONFIG_STM_DUMMY) += dummy_stm.o
>
>  obj-$(CONFIG_STM_SOURCE_CONSOLE)       += stm_console.o
>  obj-$(CONFIG_STM_SOURCE_HEARTBEAT)     += stm_heartbeat.o
> +obj-$(CONFIG_STM_SOURCE_FTRACE)                += stm_ftrace.o
>
>  stm_console-y          := console.o
>  stm_heartbeat-y                := heartbeat.o
> +stm_ftrace-y           := ftrace.o
> diff --git a/drivers/hwtracing/stm/ftrace.c b/drivers/hwtracing/stm/ftrace.c
> new file mode 100644
> index 0000000..1101f46
> --- /dev/null
> +++ b/drivers/hwtracing/stm/ftrace.c
> @@ -0,0 +1,87 @@
> +/*
> + * Simple kernel driver to link kernel Ftrace and an STM device
> + * Copyright (c) 2016, Linaro Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/stm.h>
> +#include <linux/trace.h>
> +
> +#define STM_FTRACE_NR_CHANNELS 1
> +#define STM_FTRACE_CHAN 0
> +
> +static int stm_ftrace_link(struct stm_source_data *data);
> +static void stm_ftrace_unlink(struct stm_source_data *data);
> +
> +static struct stm_ftrace {
> +       struct stm_source_data  data;
> +       struct trace_export     ftrace;
> +} stm_ftrace = {
> +       .data   = {
> +               .name           = "ftrace",
> +               .nr_chans       = STM_FTRACE_NR_CHANNELS,
> +               .link           = stm_ftrace_link,
> +               .unlink         = stm_ftrace_unlink,
> +       },
> +};
> +
> +/**
> + * stm_ftrace_write() - write data to STM via 'stm_ftrace' source
> + * @buf:       buffer containing the data packet
> + * @len:       length of the data packet
> + */
> +static void notrace
> +stm_ftrace_write(const char *buf, unsigned int len)
> +{
> +       stm_source_write(&stm_ftrace.data, STM_FTRACE_CHAN, buf, len);
> +}
> +
> +static int stm_ftrace_link(struct stm_source_data *data)
> +{
> +       struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data);
> +
> +       strcpy(sf->ftrace.name, "stm_ftrace");
> +       sf->ftrace.write = stm_ftrace_write;
> +       sf->ftrace.next = NULL;
> +
> +       return register_trace_export(&sf->ftrace);
> +}
> +
> +static void stm_ftrace_unlink(struct stm_source_data *data)
> +{
> +       struct stm_ftrace *sc = container_of(data, struct stm_ftrace, data);
> +
> +       unregister_trace_export(&sc->ftrace);
> +}
> +
> +static int __init stm_ftrace_init(void)
> +{
> +       int ret;
> +
> +       ret = stm_source_register_device(NULL, &stm_ftrace.data);
> +       if (ret)
> +               pr_err("Failed to register stm_source - ftrace.\n");
> +
> +       return ret;
> +}
> +
> +static void __exit stm_ftrace_exit(void)
> +{
> +       stm_source_unregister_device(&stm_ftrace.data);
> +}
> +
> +module_init(stm_ftrace_init);
> +module_exit(stm_ftrace_exit);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("stm_ftrace driver");
> +MODULE_AUTHOR("Chunyan Zhang <zhang.chunyan@linaro.org>");
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only
  2016-08-09  6:32 ` [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only Chunyan Zhang
  2016-08-09  6:58   ` Chunyan Zhang
@ 2016-08-09 15:35   ` Steven Rostedt
  2016-08-10  3:19     ` Chunyan Zhang
  1 sibling, 1 reply; 9+ messages in thread
From: Steven Rostedt @ 2016-08-09 15:35 UTC (permalink / raw)
  To: Chunyan Zhang
  Cc: mathieu.poirier, alexander.shishkin, mingo, arnd, mike.leach,
	tor, maxime.coquelin, philippe.langlais, nicolas.guion,
	felipe.balbi, zhang.lyra, linux-kernel, linux-arm-kernel

On Tue,  9 Aug 2016 14:32:39 +0800
Chunyan Zhang <zhang.chunyan@linaro.org> wrote:

> Currently ring buffer is the only output of Function traces, this patch
> added trace_export concept which would process the traces and export
> traces to a registered destination which can be ring buffer or some other
> storage, in this way if we want Function traces to be sent to other
> destination rather than ring buffer only, we just need to register a new
> trace_export and implement its own .commit() callback or just use
> 'trace_generic_commit()' which this patch also added and hooks up its
> own .write() functio for writing traces to the storage.
> 
> Currently, only Function trace (TRACE_FN) is supported.
> 
> Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
> ---
>  include/linux/trace.h |  31 +++++++++++++
>  kernel/trace/trace.c  | 124 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  kernel/trace/trace.h  |  31 +++++++++++++
>  3 files changed, 185 insertions(+), 1 deletion(-)
>  create mode 100644 include/linux/trace.h
> 
> diff --git a/include/linux/trace.h b/include/linux/trace.h
> new file mode 100644
> index 0000000..bc7f503
> --- /dev/null
> +++ b/include/linux/trace.h
> @@ -0,0 +1,31 @@
> +#ifndef _LINUX_TRACE_H
> +#define _LINUX_TRACE_H
> +
> +#include <linux/ring_buffer.h>
> +struct trace_array;
> +
> +#ifdef CONFIG_TRACING
> +/*
> + * The trace export - an export of function traces.  Every ftrace_ops
> + * has at least one export which would output function traces to ring
> + * buffer.
> + *
> + * tr		- the trace_array this export belongs to
> + * commit	- commit the traces to ring buffer and/or some other places
> + * write	- copy traces which have been delt with ->commit() to
> + *		  the destination
> + */
> +struct trace_export {
> +	char name[16];
> +	struct trace_export	*next;

Should document above name and next. What's name used for? Is it
visible to userspace? Add "next" just to be consistent as that's pretty
obvious what it is for.

> +	struct trace_array	*tr;
> +	void (*commit)(struct trace_array *, struct ring_buffer_event *);
> +	void (*write)(const char *, unsigned int);
> +};
> +
> +int register_trace_export(struct trace_export *export);
> +int unregister_trace_export(struct trace_export *export);
> +
> +#endif	/* CONFIG_TRACING */
> +
> +#endif	/* _LINUX_TRACE_H */
> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
> index dade4c9..67ae581 100644
> --- a/kernel/trace/trace.c
> +++ b/kernel/trace/trace.c
> @@ -40,6 +40,7 @@
>  #include <linux/poll.h>
>  #include <linux/nmi.h>
>  #include <linux/fs.h>
> +#include <linux/trace.h>
>  #include <linux/sched/rt.h>
>  
>  #include "trace.h"
> @@ -2128,6 +2129,127 @@ void trace_buffer_unlock_commit_regs(struct trace_array *tr,
>  	ftrace_trace_userstack(buffer, flags, pc);
>  }
>  
> +static inline void
> +trace_generic_commit(struct trace_array *tr,
> +	       struct ring_buffer_event *event)
> +{
> +	struct trace_entry *entry;
> +	struct trace_export *export = tr->export;
> +	unsigned int size = 0;
> +
> +	entry = ring_buffer_event_data(event);
> +
> +	trace_entry_size(size, entry->type);
> +	if (!size)
> +		return;
> +
> +	if (export->write)
> +		export->write((char *)entry, size);
> +}
> +
> +static inline void
> +trace_rb_commit(struct trace_array *tr,
> +	       struct ring_buffer_event *event)
> +{
> +	__buffer_unlock_commit(tr->trace_buffer.buffer, event);
> +}
> +
> +static DEFINE_MUTEX(trace_export_lock);
> +
> +static struct trace_export trace_export_rb __read_mostly = {
> +	.name		= "rb",
> +	.commit	= trace_rb_commit,
> +	.next		= NULL,
> +};
> +static struct trace_export *trace_fn_exports __read_mostly = &trace_export_rb;
> +
> +inline void
> +trace_function_exports(struct trace_array *tr,
> +		       struct ring_buffer_event *event)
> +{
> +	struct trace_export *export;
> +
> +	mutex_lock(&trace_export_lock);

Wait! Are you calling a mutex from the function tracer? This will blow
up easily. The function callbacks must be totally lockless!

> +
> +	for (export = trace_fn_exports; export && export->commit;
> +	     export = export->next) {
> +		tr->export = export;
> +		export->commit(tr, event);
> +	}
> +
> +	mutex_unlock(&trace_export_lock);
> +}
> +
> +static void add_trace_fn_export(struct trace_export **list,
> +			  struct trace_export *export)
> +{
> +	export->next = *list;
> +	/*
> +	 * We are entering export into the list but another
> +	 * CPU might be walking that list. We need to make sure
> +	 * the export->next pointer is valid before another CPU sees
> +	 * the export pointer included into the list.
> +	 */
> +	rcu_assign_pointer(*list, export);
> +
> +}
> +
> +static int rm_trace_fn_export(struct trace_export **list,
> +			  struct trace_export *export)
> +{
> +	struct trace_export **p;
> +
> +	for (p = list; *p != &trace_export_rb; p = &(*p)->next)
> +		if (*p == export)
> +			break;
> +
> +	if (*p != export)
> +		return -1;
> +
> +	*p = (*p)->next;
> +
> +	return 0;
> +}
> +
> +int register_trace_export(struct trace_export *export)
> +{
> +	if (!export->write) {
> +		pr_warn("trace_export must have the write() call back.\n");
> +		return -1;
> +	}
> +
> +	mutex_lock(&trace_export_lock);
> +
> +	export->tr = trace_fn_exports->tr;
> +	export->commit = trace_generic_commit;
> +
> +	add_trace_fn_export(&trace_fn_exports, export);
> +
> +	mutex_unlock(&trace_export_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(register_trace_export);
> +
> +int unregister_trace_export(struct trace_export *export)
> +{
> +	int ret;
> +
> +	if (!export->name) {

Why this check? Perhaps you want this in the register code?

-- Steve


> +		pr_warn("trace_export must have a name.\n");
> +		return -1;
> +	}
> +
> +	mutex_lock(&trace_export_lock);
> +
> +	ret = rm_trace_fn_export(&trace_fn_exports, export);
> +
> +	mutex_unlock(&trace_export_lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(unregister_trace_export);
> +
>  void
>  trace_function(struct trace_array *tr,
>  	       unsigned long ip, unsigned long parent_ip, unsigned long flags,
> @@ -2147,7 +2269,7 @@ trace_function(struct trace_array *tr,
>  	entry->parent_ip		= parent_ip;
>  
>  	if (!call_filter_check_discard(call, entry, buffer, event))
> -		__buffer_unlock_commit(buffer, event);
> +		trace_function_exports(tr, event);
>  }
>  
>  #ifdef CONFIG_STACKTRACE
> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
> index f783df4..a40f07c 100644
> --- a/kernel/trace/trace.h
> +++ b/kernel/trace/trace.h
> @@ -260,6 +260,7 @@ struct trace_array {
>  	/* function tracing enabled */
>  	int			function_enabled;
>  #endif
> +	struct trace_export	*export;
>  };
>  
>  enum {
> @@ -301,6 +302,13 @@ static inline struct trace_array *top_trace_array(void)
>  		break;					\
>  	}
>  
> +#undef IF_SIZE
> +#define IF_SIZE(size, var, etype, id)		\
> +		if (var == id) {		\
> +			size = (sizeof(etype));	\
> +			break;			\
> +		}
> +
>  /* Will cause compile errors if type is not found. */
>  extern void __ftrace_bad_type(void);
>  
> @@ -339,6 +347,29 @@ extern void __ftrace_bad_type(void);
>  	} while (0)
>  
>  /*
> + * The trace_entry_size return the size of specific trace type
> + *
> + * IF_SIZE(size, var);
> + *
> + * Where "var" is just the given trace type.
> + */
> +#define trace_entry_size(size, var)					\
> +	do {								\
> +		IF_SIZE(size, var, struct ftrace_entry, TRACE_FN);	\
> +		IF_SIZE(size, var, struct stack_entry, TRACE_STACK);	\
> +		IF_SIZE(size, var, struct userstack_entry,		\
> +			TRACE_USER_STACK);				\
> +		IF_SIZE(size, var, struct print_entry, TRACE_PRINT);	\
> +		IF_SIZE(size, var, struct bprint_entry, TRACE_BPRINT);	\
> +		IF_SIZE(size, var, struct bputs_entry, TRACE_BPUTS);	\
> +		IF_SIZE(size, var, struct trace_branch, TRACE_BRANCH);	\
> +		IF_SIZE(size, var, struct ftrace_graph_ent_entry,	\
> +			TRACE_GRAPH_ENT);				\
> +		IF_SIZE(size, var, struct ftrace_graph_ret_entry,	\
> +			TRACE_GRAPH_RET);				\
> +	} while (0)
> +
> +/*
>   * An option specific to a tracer. This is a boolean value.
>   * The bit is the bit index that sets its value on the
>   * flags value in struct tracer_flags.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only
  2016-08-09 15:35   ` Steven Rostedt
@ 2016-08-10  3:19     ` Chunyan Zhang
  0 siblings, 0 replies; 9+ messages in thread
From: Chunyan Zhang @ 2016-08-10  3:19 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Mathieu Poirier, Alexander Shishkin, mingo, Arnd Bergmann,
	Mike Leach, Tor Jeremiassen, philippe.langlais, Nicolas GUION,
	felipe.balbi, Lyra Zhang, linux-kernel, linux-arm-kernel

On Tue, Aug 9, 2016 at 11:35 PM, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Tue,  9 Aug 2016 14:32:39 +0800
> Chunyan Zhang <zhang.chunyan@linaro.org> wrote:
>
>> Currently ring buffer is the only output of Function traces, this patch
>> added trace_export concept which would process the traces and export
>> traces to a registered destination which can be ring buffer or some other
>> storage, in this way if we want Function traces to be sent to other
>> destination rather than ring buffer only, we just need to register a new
>> trace_export and implement its own .commit() callback or just use
>> 'trace_generic_commit()' which this patch also added and hooks up its
>> own .write() functio for writing traces to the storage.
>>
>> Currently, only Function trace (TRACE_FN) is supported.
>>
>> Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>
>> ---
>>  include/linux/trace.h |  31 +++++++++++++
>>  kernel/trace/trace.c  | 124 +++++++++++++++++++++++++++++++++++++++++++++++++-
>>  kernel/trace/trace.h  |  31 +++++++++++++
>>  3 files changed, 185 insertions(+), 1 deletion(-)
>>  create mode 100644 include/linux/trace.h
>>
>> diff --git a/include/linux/trace.h b/include/linux/trace.h
>> new file mode 100644
>> index 0000000..bc7f503
>> --- /dev/null
>> +++ b/include/linux/trace.h
>> @@ -0,0 +1,31 @@
>> +#ifndef _LINUX_TRACE_H
>> +#define _LINUX_TRACE_H
>> +
>> +#include <linux/ring_buffer.h>
>> +struct trace_array;
>> +
>> +#ifdef CONFIG_TRACING
>> +/*
>> + * The trace export - an export of function traces.  Every ftrace_ops
>> + * has at least one export which would output function traces to ring
>> + * buffer.
>> + *
>> + * tr                - the trace_array this export belongs to
>> + * commit    - commit the traces to ring buffer and/or some other places
>> + * write     - copy traces which have been delt with ->commit() to
>> + *             the destination
>> + */
>> +struct trace_export {
>> +     char name[16];
>> +     struct trace_export     *next;
>
> Should document above name and next. What's name used for? Is it

Sure, I will document them in the next revision.

Speaking to the 'name' here... I just think it will probably be useful
in the future, for example, if we need an userspace interface for
users to decide which trace_export should be used.

> visible to userspace? Add "next" just to be consistent as that's pretty
> obvious what it is for.
>
>> +     struct trace_array      *tr;
>> +     void (*commit)(struct trace_array *, struct ring_buffer_event *);
>> +     void (*write)(const char *, unsigned int);
>> +};
>> +
>> +int register_trace_export(struct trace_export *export);
>> +int unregister_trace_export(struct trace_export *export);
>> +
>> +#endif       /* CONFIG_TRACING */
>> +
>> +#endif       /* _LINUX_TRACE_H */
>> diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
>> index dade4c9..67ae581 100644
>> --- a/kernel/trace/trace.c
>> +++ b/kernel/trace/trace.c
>> @@ -40,6 +40,7 @@
>>  #include <linux/poll.h>
>>  #include <linux/nmi.h>
>>  #include <linux/fs.h>
>> +#include <linux/trace.h>
>>  #include <linux/sched/rt.h>
>>
>>  #include "trace.h"
>> @@ -2128,6 +2129,127 @@ void trace_buffer_unlock_commit_regs(struct trace_array *tr,
>>       ftrace_trace_userstack(buffer, flags, pc);
>>  }
>>
>> +static inline void
>> +trace_generic_commit(struct trace_array *tr,
>> +            struct ring_buffer_event *event)
>> +{
>> +     struct trace_entry *entry;
>> +     struct trace_export *export = tr->export;
>> +     unsigned int size = 0;
>> +
>> +     entry = ring_buffer_event_data(event);
>> +
>> +     trace_entry_size(size, entry->type);
>> +     if (!size)
>> +             return;
>> +
>> +     if (export->write)
>> +             export->write((char *)entry, size);
>> +}
>> +
>> +static inline void
>> +trace_rb_commit(struct trace_array *tr,
>> +            struct ring_buffer_event *event)
>> +{
>> +     __buffer_unlock_commit(tr->trace_buffer.buffer, event);
>> +}
>> +
>> +static DEFINE_MUTEX(trace_export_lock);
>> +
>> +static struct trace_export trace_export_rb __read_mostly = {
>> +     .name           = "rb",
>> +     .commit = trace_rb_commit,
>> +     .next           = NULL,
>> +};
>> +static struct trace_export *trace_fn_exports __read_mostly = &trace_export_rb;
>> +
>> +inline void
>> +trace_function_exports(struct trace_array *tr,
>> +                    struct ring_buffer_event *event)
>> +{
>> +     struct trace_export *export;
>> +
>> +     mutex_lock(&trace_export_lock);
>
> Wait! Are you calling a mutex from the function tracer? This will blow
> up easily. The function callbacks must be totally lockless!

Okay, I just wanted to protect the list from being changed while being used.
What do you think if I change to make adding/removing trace exports
from the list are only permitted when the trace isn't enabled?

>
>> +
>> +     for (export = trace_fn_exports; export && export->commit;
>> +          export = export->next) {
>> +             tr->export = export;
>> +             export->commit(tr, event);
>> +     }
>> +
>> +     mutex_unlock(&trace_export_lock);
>> +}
>> +
>> +static void add_trace_fn_export(struct trace_export **list,
>> +                       struct trace_export *export)
>> +{
>> +     export->next = *list;
>> +     /*
>> +      * We are entering export into the list but another
>> +      * CPU might be walking that list. We need to make sure
>> +      * the export->next pointer is valid before another CPU sees
>> +      * the export pointer included into the list.
>> +      */
>> +     rcu_assign_pointer(*list, export);
>> +
>> +}
>> +
>> +static int rm_trace_fn_export(struct trace_export **list,
>> +                       struct trace_export *export)
>> +{
>> +     struct trace_export **p;
>> +
>> +     for (p = list; *p != &trace_export_rb; p = &(*p)->next)
>> +             if (*p == export)
>> +                     break;
>> +
>> +     if (*p != export)
>> +             return -1;
>> +
>> +     *p = (*p)->next;
>> +
>> +     return 0;
>> +}
>> +
>> +int register_trace_export(struct trace_export *export)
>> +{
>> +     if (!export->write) {
>> +             pr_warn("trace_export must have the write() call back.\n");
>> +             return -1;
>> +     }
>> +
>> +     mutex_lock(&trace_export_lock);
>> +
>> +     export->tr = trace_fn_exports->tr;
>> +     export->commit = trace_generic_commit;
>> +
>> +     add_trace_fn_export(&trace_fn_exports, export);
>> +
>> +     mutex_unlock(&trace_export_lock);
>> +
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(register_trace_export);
>> +
>> +int unregister_trace_export(struct trace_export *export)
>> +{
>> +     int ret;
>> +
>> +     if (!export->name) {
>
> Why this check? Perhaps you want this in the register code?

Sorry this was my mistake.  Will move this to the register code if you
think 'name' is worth keeping.

Thanks for your comments,
Chunyan

>
> -- Steve
>
>
>> +             pr_warn("trace_export must have a name.\n");
>> +             return -1;
>> +     }
>> +
>> +     mutex_lock(&trace_export_lock);
>> +
>> +     ret = rm_trace_fn_export(&trace_fn_exports, export);
>> +
>> +     mutex_unlock(&trace_export_lock);
>> +
>> +     return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(unregister_trace_export);
>> +
>>  void
>>  trace_function(struct trace_array *tr,
>>              unsigned long ip, unsigned long parent_ip, unsigned long flags,
>> @@ -2147,7 +2269,7 @@ trace_function(struct trace_array *tr,
>>       entry->parent_ip                = parent_ip;
>>
>>       if (!call_filter_check_discard(call, entry, buffer, event))
>> -             __buffer_unlock_commit(buffer, event);
>> +             trace_function_exports(tr, event);
>>  }
>>
>>  #ifdef CONFIG_STACKTRACE
>> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
>> index f783df4..a40f07c 100644
>> --- a/kernel/trace/trace.h
>> +++ b/kernel/trace/trace.h
>> @@ -260,6 +260,7 @@ struct trace_array {
>>       /* function tracing enabled */
>>       int                     function_enabled;
>>  #endif
>> +     struct trace_export     *export;
>>  };
>>
>>  enum {
>> @@ -301,6 +302,13 @@ static inline struct trace_array *top_trace_array(void)
>>               break;                                  \
>>       }
>>
>> +#undef IF_SIZE
>> +#define IF_SIZE(size, var, etype, id)                \
>> +             if (var == id) {                \
>> +                     size = (sizeof(etype)); \
>> +                     break;                  \
>> +             }
>> +
>>  /* Will cause compile errors if type is not found. */
>>  extern void __ftrace_bad_type(void);
>>
>> @@ -339,6 +347,29 @@ extern void __ftrace_bad_type(void);
>>       } while (0)
>>
>>  /*
>> + * The trace_entry_size return the size of specific trace type
>> + *
>> + * IF_SIZE(size, var);
>> + *
>> + * Where "var" is just the given trace type.
>> + */
>> +#define trace_entry_size(size, var)                                  \
>> +     do {                                                            \
>> +             IF_SIZE(size, var, struct ftrace_entry, TRACE_FN);      \
>> +             IF_SIZE(size, var, struct stack_entry, TRACE_STACK);    \
>> +             IF_SIZE(size, var, struct userstack_entry,              \
>> +                     TRACE_USER_STACK);                              \
>> +             IF_SIZE(size, var, struct print_entry, TRACE_PRINT);    \
>> +             IF_SIZE(size, var, struct bprint_entry, TRACE_BPRINT);  \
>> +             IF_SIZE(size, var, struct bputs_entry, TRACE_BPUTS);    \
>> +             IF_SIZE(size, var, struct trace_branch, TRACE_BRANCH);  \
>> +             IF_SIZE(size, var, struct ftrace_graph_ent_entry,       \
>> +                     TRACE_GRAPH_ENT);                               \
>> +             IF_SIZE(size, var, struct ftrace_graph_ret_entry,       \
>> +                     TRACE_GRAPH_RET);                               \
>> +     } while (0)
>> +
>> +/*
>>   * An option specific to a tracer. This is a boolean value.
>>   * The bit is the bit index that sets its value on the
>>   * flags value in struct tracer_flags.
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-08-10  3:19 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-09  6:32 [PATCH V3 0/3] Integration of function trace with System Trace IP blocks Chunyan Zhang
2016-08-09  6:32 ` [PATCH V3 1/3] tracing: add a possibility of exporting function trace to other places instead of ring buffer only Chunyan Zhang
2016-08-09  6:58   ` Chunyan Zhang
2016-08-09 15:35   ` Steven Rostedt
2016-08-10  3:19     ` Chunyan Zhang
2016-08-09  6:32 ` [PATCH V3 2/3] stm class: ftrace: Add ftrace-export-over-stm driver Chunyan Zhang
2016-08-09  6:59   ` Chunyan Zhang
2016-08-09  6:32 ` [PATCH V3 3/3] stm: Mark the functions of writing buffer with notrace Chunyan Zhang
2016-08-09  6:57 ` [PATCH V3 0/3] Integration of function trace with System Trace IP blocks Chunyan Zhang

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).