lkml.org 
[lkml]   [2007]   [Sep]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [patch 3/6] Linux Kernel Markers - Documentation
On Thu, 06 Sep 2007 16:07:36 -0400 Mathieu Desnoyers wrote:

> Here is some documentation explaining what is/how to use the Linux
> Kernel Markers.
> ---
>
> Documentation/marker.txt | 257 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 257 insertions(+)
>
> Index: linux-2.6-lttng/Documentation/marker.txt
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6-lttng/Documentation/marker.txt 2007-08-17 11:56:20.000000000 -0400
> @@ -0,0 +1,257 @@
> + Using the Linux Kernel Markers
> +
> + Mathieu Desnoyers
> +
> +
> +This document introduces Linux Kernel Markers and their use. It provides
> +examples of how to insert markers in the kernel and connect probe functions to
> +them and provides some examples of probe functions.
> +
> +
> +* Purpose of markers
> +
> +A marker placed in your code provides a hook to call a function (probe) that

^^^^ I would drop "your". It quite likely
could be someone else's code.

> +you can provide at runtime. A marker can be "on" (a probe is connected to it) or
> +"off" (no probe is attached). When a marker is "off" it has no effect, except
> +for adding a tiny time penality (checking a condition for a branch) and space

penalty

> +penality (adding a few bytes for the function call at the end of the

penalty

> +instrumented function and adds a data structure in a separate section). The
> +immediate values are used to minimize the impact on data cache, encoding the
> +condition in the instruction stream. When a marker is "on", the function you
> +provide is called each time the marker is executed, in the execution context of
> +the caller. When the function provided ends its execution, it returns to the
> +caller (continuing from the marker site).
> +
> +You can put markers at important locations in the code. Markers are
> +lightweight hooks that can pass an arbitrary number of parameters,
> +described in a printk-like format string, to the attached probe function.
> +
> +They can be used for tracing and performance accounting.
> +
> +
> +* Usage
> +
> +In order to use the macro trace_mark, you should include linux/marker.h.
> +
> +#include <linux/marker.h>
> +
> +Add, in your code :

And,

> +
> +trace_mark(subsystem_event, "%d %s", someint, somestring);
> +Where :
> +- subsystem_event is an identifier unique to your event
> + - subsystem is the name of your subsystem.
> + - event is the name of the event to mark.
> +- "%d %s" is the formatted string for the serializer.
> +- someint is an integer.
> +- somestring is a char pointer.
> +
> +Connecting a function (probe) to a marker is done by providing a probe (function
> +to call) for the specific marker through marker_probe_register() and can be
> +activated by calling marker_arm(). Marker deactivation can be done by calling
> +marker_disarm() as many times as marker_arm() has been called. Removing a probe
> +is done through marker_probe_unregister(); it will disarm the probe and make
> +sure there is no caller left using the probe when it returns. Probe removal is
> +preempt-safe because preemption is disabled around the probe call. See the
> +"Probe example" section below for a sample probe module.
> +
> +The marker mechanism supports inserting multiple instances of the same marker.
> +Markers can be put in inline functions, inlined static functions, and
> +unrolled loops.
> +
> +The naming scheme "subsystem_event" is suggested here as a convention intended
> +to limit collisions. Marker names are global to the kernel: they are considered
> +as being the same whether they are in the core kernel image or in modules.
> +Conflicting format strings for markers with the same name will cause the markers
> +to be detected to have a different format string not to be armed and will output
> +a printk warning which identifies the inconsistency:
> +
> +"Format mismatch for probe probe_name (format), marker (format)"
> +
> +
> +* Optimization for a given architecture
> +
> +One can implement optimized markers for a given architecture by replacing
> +asm-$ARCH/marker.h.
> +
> +To force use of a non-optimized version of the markers, _trace_mark() should be
> +used. It takes the same parameters as the normal markers, but it does not use
> +the immediate values based on code patching.
> +
> +
> +* Probe example

I would much prefer that you put marker-related docs into
Documentation/marker[s]/ and then put the Makefile and source files
into Documentation/marker[s]/src/.

This make the source files more visible (findable, grepable) to other
developers & users. It also makes it feasible to use and test them
on a regular basis so that API changes (=> bugs:) can be easily
found and fixed.

And then you can drop those "CUT" lines. :)


> +You can build the kernel modules, probe-example.ko and marker-example.ko,
> +using the following Makefile:
> +------------------------------ CUT -------------------------------------
> +obj-m := probe-example.o marker-example.o
> +KDIR := /lib/modules/$(shell uname -r)/build
> +PWD := $(shell pwd)
> +default:
> + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
> +clean:
> + rm -f *.mod.c *.ko *.o
> +------------------------------ CUT -------------------------------------
> +/* probe-example.c
> + *
> + * Connects two functions to marker call sites.
> + *
> + * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
> + *
> + * This file is released under the GPLv2.
> + * See the file COPYING for more details.
> + */
> +
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/marker.h>
> +#include <asm/atomic.h>
> +
> +struct probe_data {
> + const char *name;
> + const char *format;
> + marker_probe_func *probe_func;
> +};
> +
> +void probe_subsystem_event(const struct __mark_marker *mdata,
> + const char *format, ...)
> +{
> + va_list ap;
> + /* Declare args */
> + unsigned int value;
> + const char *mystr;
> +
> + /* Assign args */
> + va_start(ap, format);
> + value = va_arg(ap, typeof(value));
> + mystr = va_arg(ap, typeof(mystr));
> +
> + /* Call printk */
> + printk("Value %u, string %s\n", value, mystr);
> +
> + /* or count, check rights, serialize data in a buffer */
> +
> + va_end(ap);
> +}
> +
> +atomic_t eventb_count = ATOMIC_INIT(0);
> +
> +void probe_subsystem_eventb(const struct __mark_marker *mdata,
> + const char *format, ...)
> +{
> + /* Increment counter */
> + atomic_inc(&eventb_count);
> +}
> +
> +static struct probe_data probe_array[] =
> +{
> + { .name = "subsystem_event",
> + .format = "%d %s",
> + .probe_func = probe_subsystem_event },
> + { .name = "subsystem_eventb",
> + .format = MARK_NOARGS,
> + .probe_func = probe_subsystem_eventb },
> +};
> +
> +static int __init probe_init(void)
> +{
> + int result;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(probe_array); i++) {
> + result = marker_probe_register(probe_array[i].name,
> + probe_array[i].format,
> + probe_array[i].probe_func, &probe_array[i]);
> + if (result)
> + printk(KERN_INFO "Unable to register probe %s\n",
> + probe_array[i].name);
> + result = marker_arm(probe_array[i].name);
> + if (result)
> + printk(KERN_INFO "Unable to arm probe %s\n",
> + probe_array[i].name);
> + }
> + return 0;
> +}
> +
> +static void __exit probe_fini(void)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(probe_array); i++) {
> + marker_probe_unregister(probe_array[i].name);
> + }
> + printk("Number of event b : %u\n", atomic_read(&eventb_count));
> +}
> +
> +module_init(probe_init);
> +module_exit(probe_fini);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Mathieu Desnoyers");
> +MODULE_DESCRIPTION("SUBSYSTEM Probe");
> +------------------------------ CUT -------------------------------------
> +/* marker-example.c
> + *
> + * Executes a marker when /proc/marker-example is opened.
> + *
> + * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
> + *
> + * This file is released under the GPLv2.
> + * See the file COPYING for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/marker.h>
> +#include <linux/sched.h>
> +#include <linux/proc_fs.h>
> +
> +struct proc_dir_entry *pentry_example = NULL;
> +
> +static int my_open(struct inode *inode, struct file *file)
> +{
> + int i;
> +
> + trace_mark(subsystem_event, "%d %s", 123, "example string");
> + for (i=0; i<10; i++) {
> + trace_mark(subsystem_eventb, MARK_NOARGS);
> + }
> + return -EPERM;
> +}
> +
> +static struct file_operations mark_ops = {
> + .open = my_open,
> +};
> +
> +static int example_init(void)
> +{
> + printk(KERN_ALERT "example init\n");
> + pentry_example = create_proc_entry("marker-example", 0444, NULL);
> + if (pentry_example)
> + pentry_example->proc_fops = &mark_ops;
> + else
> + return -EPERM;
> + return 0;
> +}
> +
> +static void example_exit(void)
> +{
> + printk(KERN_ALERT "example exit\n");
> + remove_proc_entry("marker-example", NULL);
> +}
> +
> +module_init(example_init)
> +module_exit(example_exit)
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Mathieu Desnoyers");
> +MODULE_DESCRIPTION("Linux Trace Toolkit example");
> +------------------------------ CUT -------------------------------------
> +Sequence of operations : (as root)
> +make
> +insmod marker-example.ko (insmod order is not important)
> +insmod probe-example.ko
> +cat /proc/marker-example (returns an expected error)
> +rmmod marker-example probe-example
> +dmesg
> +------------------------------ CUT -------------------------------------

---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2007-09-07 01:53    [W:0.153 / U:0.456 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site