Messages in this thread | | | Subject | Re: [RFC PATCH 1/4] kmemtrace: Core implementation. | From | Pekka Enberg <> | Date | Mon, 28 Jul 2008 12:24:44 +0300 |
| |
Hi,
[I'm cc'ing Mathieu if he wants to comment on this.]
On Tue, 2008-07-22 at 21:36 +0300, Eduard - Gabriel Munteanu wrote: > kmemtrace provides tracing for slab allocator functions, such as kmalloc, > kfree, kmem_cache_alloc, kmem_cache_free etc.. Collected data is then fed > to the userspace application in order to analyse allocation hotspots, > internal fragmentation and so on, making it possible to see how well an > allocator performs, as well as debug and profile kernel code.
Reviewed-by: Pekka Enberg <penberg@cs.helsinki.fi>
> Signed-off-by: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro> > --- > Documentation/ABI/testing/debugfs-kmemtrace | 58 +++++++ > Documentation/kernel-parameters.txt | 10 + > Documentation/vm/kmemtrace.txt | 126 ++++++++++++++ > MAINTAINERS | 6 + > include/linux/kmemtrace.h | 110 ++++++++++++ > init/main.c | 2 + > lib/Kconfig.debug | 28 +++ > mm/Makefile | 2 +- > mm/kmemtrace.c | 244 +++++++++++++++++++++++++++ > 9 files changed, 585 insertions(+), 1 deletions(-) > create mode 100644 Documentation/ABI/testing/debugfs-kmemtrace > create mode 100644 Documentation/vm/kmemtrace.txt > create mode 100644 include/linux/kmemtrace.h > create mode 100644 mm/kmemtrace.c > > diff --git a/Documentation/ABI/testing/debugfs-kmemtrace b/Documentation/ABI/testing/debugfs-kmemtrace > new file mode 100644 > index 0000000..466c2bb > --- /dev/null > +++ b/Documentation/ABI/testing/debugfs-kmemtrace > @@ -0,0 +1,58 @@ > +What: /sys/kernel/debug/kmemtrace/ > +Date: July 2008 > +Contact: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro> > +Description: > + > +In kmemtrace-enabled kernels, the following files are created: > + > +/sys/kernel/debug/kmemtrace/ > + cpu<n> (0400) Per-CPU tracing data, see below. (binary) > + total_overruns (0400) Total number of bytes which were dropped from > + cpu<n> files because of full buffer condition, > + non-binary. (text) > + abi_version (0400) Kernel's kmemtrace ABI version. (text) > + > +Each per-CPU file should be read according to the relay interface. That is, > +the reader should set affinity to that specific CPU and, as currently done by > +the userspace application (though there are other methods), use poll() with > +an infinite timeout before every read(). Otherwise, erroneous data may be > +read. The binary data has the following _core_ format: > + Event id (1 byte) Unsigned integer, one of: > + 0 - erroneous event, this is illegal/invalid data and must > + not occur (KMEMTRACE_EVENT_NULL) > + 1 - represents an allocation (KMEMTRACE_EVENT_ALLOC) > + 2 - represents a freeing of previously allocated memory > + (KMEMTRACE_EVENT_FREE) > + Type id (1 byte) Unsigned integer, one of: > + 0 - this is a kmalloc() / kfree() > + 1 - this is a kmem_cache_alloc() / kmem_cache_free() > + 2 - this is a __get_free_pages() et al. > + Event size (2 bytes) Unsigned integer representing the > + size of this event. Used to extend > + kmemtrace. Discard the bytes you > + don't know about. > + Target CPU (4 bytes) Signed integer, valid for event id 1. > + If equal to -1, target CPU is the same > + as origin CPU, but the reverse might > + not be true. > + Caller address (8 bytes) Return address to the caller. > + Pointer to mem (8 bytes) Pointer to allocated memory, must not > + be NULL. > + Requested bytes (8 bytes) Total number of requested bytes, > + unsigned, must not be zero. > + Allocated bytes (8 bytes) Total number of actually allocated > + bytes, unsigned, must not be lower > + than requested bytes. > + Requested flags (8 bytes) GFP flags supplied by the caller. > + Timestamp (8 bytes) Signed integer representing timestamp. > + > +The data is made available in the same endianness the machine has. > + > +Other event ids and type ids may be defined and added. Other fields may be > +added by increasing event size. Every modification to the ABI, including > +new id definitions, are followed by bumping the ABI version by one. > + > + > +Users: > + kmemtrace-user - git://repo.or.cz/kmemtrace-user.git > + > diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt > index b52f47d..446a257 100644 > --- a/Documentation/kernel-parameters.txt > +++ b/Documentation/kernel-parameters.txt > @@ -49,6 +49,7 @@ parameter is applicable: > ISAPNP ISA PnP code is enabled. > ISDN Appropriate ISDN support is enabled. > JOY Appropriate joystick support is enabled. > + KMEMTRACE kmemtrace is enabled. > LIBATA Libata driver is enabled > LP Printer support is enabled. > LOOP Loopback device support is enabled. > @@ -941,6 +942,15 @@ and is between 256 and 4096 characters. It is defined in the file > use the HighMem zone if it exists, and the Normal > zone if it does not. > > + kmemtrace.enable= [KNL,KMEMTRACE] Format: { yes | no } > + Controls whether kmemtrace is enabled > + at boot-time. > + > + kmemtrace.subbufs=n [KNL,KMEMTRACE] Overrides the number of > + subbufs kmemtrace's relay channel has. Set this > + higher than default (KMEMTRACE_N_SUBBUFS in code) if > + you experience buffer overruns. > + > movablecore=nn[KMG] [KNL,X86-32,IA-64,PPC,X86-64] This parameter > is similar to kernelcore except it specifies the > amount of memory used for migratable allocations. > diff --git a/Documentation/vm/kmemtrace.txt b/Documentation/vm/kmemtrace.txt > new file mode 100644 > index 0000000..75360b1 > --- /dev/null > +++ b/Documentation/vm/kmemtrace.txt > @@ -0,0 +1,126 @@ > + kmemtrace - Kernel Memory Tracer > + > + by Eduard - Gabriel Munteanu > + <eduard.munteanu@linux360.ro> > + > +I. Introduction > +=============== > + > +kmemtrace helps kernel developers figure out two things: > +1) how different allocators (SLAB, SLUB etc.) perform > +2) how kernel code allocates memory and how much > + > +To do this, we trace every allocation and export information to the userspace > +through the relay interface. We export things such as the number of requested > +bytes, the number of bytes actually allocated (i.e. including internal > +fragmentation), whether this is a slab allocation or a plain kmalloc() and so > +on. > + > +The actual analysis is performed by a userspace tool (see section III for > +details on where to get it from). It logs the data exported by the kernel, > +processes it and (as of writing this) can provide the following information: > +- the total amount of memory allocated and fragmentation per call-site > +- the amount of memory allocated and fragmentation per allocation > +- total memory allocated and fragmentation in the collected dataset > +- number of cross-CPU allocation and frees (makes sense in NUMA environments) > + > +Moreover, it can potentially find inconsistent and erroneous behavior in > +kernel code, such as using slab free functions on kmalloc'ed memory or > +allocating less memory than requested (but not truly failed allocations). > + > +kmemtrace also makes provisions for tracing on some arch and analysing the > +data on another. > + > +II. Design and goals > +==================== > + > +kmemtrace was designed to handle rather large amounts of data. Thus, it uses > +the relay interface to export whatever is logged to userspace, which then > +stores it. Analysis and reporting is done asynchronously, that is, after the > +data is collected and stored. By design, it allows one to log and analyse > +on different machines and different arches. > + > +As of writing this, the ABI is not considered stable, though it might not > +change much. However, no guarantees are made about compatibility yet. When > +deemed stable, the ABI should still allow easy extension while maintaining > +backward compatibility. This is described further in Documentation/ABI. > + > +Summary of design goals: > + - allow logging and analysis to be done across different machines > + - be fast and anticipate usage in high-load environments (*) > + - be reasonably extensible > + - make it possible for GNU/Linux distributions to have kmemtrace > + included in their repositories > + > +(*) - one of the reasons Pekka Enberg's original userspace data analysis > + tool's code was rewritten from Perl to C (although this is more than a > + simple conversion) > + > + > +III. Quick usage guide > +====================== > + > +1) Get a kernel that supports kmemtrace and build it accordingly (i.e. enable > +CONFIG_KMEMTRACE and CONFIG_DEFAULT_ENABLED). > + > +2) Get the userspace tool and build it: > +$ git-clone git://repo.or.cz/kmemtrace-user.git # current repository > +$ cd kmemtrace-user/ > +$ ./autogen.sh > +$ ./configure > +$ make > + > +3) Boot the kmemtrace-enabled kernel if you haven't, preferably in the > +'single' runlevel (so that relay buffers don't fill up easily), and run > +kmemtrace: > +# '$' does not mean user, but root here. > +$ mount -t debugfs none /sys/kernel/debug > +$ mount -t proc none /proc > +$ cd path/to/kmemtrace-user/ > +$ ./kmemtraced > +Wait a bit, then stop it with CTRL+C. > +$ cat /sys/kernel/debug/kmemtrace/total_overruns # Check if we didn't > + # overrun, should > + # be zero. > +$ (Optionally) [Run kmemtrace_check separately on each cpu[0-9]*.out file to > + check its correctness] > +$ ./kmemtrace-report > + > +Now you should have a nice and short summary of how the allocator performs. > + > +IV. FAQ and known issues > +======================== > + > +Q: 'cat /sys/kernel/debug/kmemtrace/total_overruns' is non-zero, how do I fix > +this? Should I worry? > +A: If it's non-zero, this affects kmemtrace's accuracy, depending on how > +large the number is. You can fix it by supplying a higher > +'kmemtrace.subbufs=N' kernel parameter. > +--- > + > +Q: kmemtrace_check reports errors, how do I fix this? Should I worry? > +A: This is a bug and should be reported. It can occur for a variety of > +reasons: > + - possible bugs in relay code > + - possible misuse of relay by kmemtrace > + - timestamps being collected unorderly > +Or you may fix it yourself and send us a patch. > +--- > + > +Q: kmemtrace_report shows many errors, how do I fix this? Should I worry? > +A: This is a known issue and I'm working on it. These might be true errors > +in kernel code, which may have inconsistent behavior (e.g. allocating memory > +with kmem_cache_alloc() and freeing it with kfree()). Pekka Enberg pointed > +out this behavior may work with SLAB, but may fail with other allocators. > + > +It may also be due to lack of tracing in some unusual allocator functions. > + > +We don't want bug reports regarding this issue yet. > +--- > + > +V. See also > +=========== > + > +Documentation/kernel-parameters.txt > +Documentation/ABI/testing/debugfs-kmemtrace > + > diff --git a/MAINTAINERS b/MAINTAINERS > index 56a2f67..e967bc2 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -2425,6 +2425,12 @@ M: jason.wessel@windriver.com > L: kgdb-bugreport@lists.sourceforge.net > S: Maintained > > +KMEMTRACE > +P: Eduard - Gabriel Munteanu > +M: eduard.munteanu@linux360.ro > +L: linux-kernel@vger.kernel.org > +S: Maintained > + > KPROBES > P: Ananth N Mavinakayanahalli > M: ananth@in.ibm.com > diff --git a/include/linux/kmemtrace.h b/include/linux/kmemtrace.h > new file mode 100644 > index 0000000..48746ee > --- /dev/null > +++ b/include/linux/kmemtrace.h > @@ -0,0 +1,110 @@ > +/* > + * Copyright (C) 2008 Eduard - Gabriel Munteanu > + * > + * This file is released under GPL version 2. > + */ > + > +#ifndef _LINUX_KMEMTRACE_H > +#define _LINUX_KMEMTRACE_H > + > +#ifdef __KERNEL__ > + > +#include <linux/types.h> > +#include <linux/marker.h> > + > +/* ABI definition starts here. */ > + > +#define KMEMTRACE_ABI_VERSION 1 > + > +enum kmemtrace_event_id { > + KMEMTRACE_EVENT_NULL = 0, /* Erroneous event. */ > + KMEMTRACE_EVENT_ALLOC, > + KMEMTRACE_EVENT_FREE, > +}; > + > +enum kmemtrace_type_id { > + KMEMTRACE_TYPE_KMALLOC = 0, /* kmalloc() / kfree(). */ > + KMEMTRACE_TYPE_CACHE, /* kmem_cache_*(). */ > + KMEMTRACE_TYPE_PAGES, /* __get_free_pages() and friends. */ > +}; > + > +struct kmemtrace_event { > + u8 event_id; /* Allocate or free? */ > + u8 type_id; /* Kind of allocation/free. */ > + u16 event_size; /* Size of event */ > + s32 node; /* Target CPU. */ > + u64 call_site; /* Caller address. */ > + u64 ptr; /* Pointer to allocation. */ > + u64 bytes_req; /* Number of bytes requested. */ > + u64 bytes_alloc; /* Number of bytes allocated. */ > + u64 gfp_flags; /* Requested flags. */ > + s64 timestamp; /* When the operation occured in ns. */ > +} __attribute__ ((__packed__)); > + > +/* End of ABI definition. */ > + > +#ifdef CONFIG_KMEMTRACE > + > +extern void kmemtrace_init(void); > + > +static inline void kmemtrace_mark_alloc_node(enum kmemtrace_type_id type_id, > + unsigned long call_site, > + const void *ptr, > + size_t bytes_req, > + size_t bytes_alloc, > + gfp_t gfp_flags, > + int node) > +{ > + trace_mark(kmemtrace_alloc, "type_id %d call_site %lu ptr %lu " > + "bytes_req %lu bytes_alloc %lu gfp_flags %lu node %d", > + type_id, call_site, (unsigned long) ptr, > + bytes_req, bytes_alloc, (unsigned long) gfp_flags, node); > +} > + > +static inline void kmemtrace_mark_free(enum kmemtrace_type_id type_id, > + unsigned long call_site, > + const void *ptr) > +{ > + trace_mark(kmemtrace_free, "type_id %d call_site %lu ptr %lu", > + type_id, call_site, (unsigned long) ptr); > +} > + > +#else /* CONFIG_KMEMTRACE */ > + > +static inline void kmemtrace_init(void) > +{ > +} > + > +static inline void kmemtrace_mark_alloc_node(enum kmemtrace_type_id type_id, > + unsigned long call_site, > + const void *ptr, > + size_t bytes_req, > + size_t bytes_alloc, > + gfp_t gfp_flags, > + int node) > +{ > +} > + > +static inline void kmemtrace_mark_free(enum kmemtrace_type_id type_id, > + unsigned long call_site, > + const void *ptr) > +{ > +} > + > +#endif /* CONFIG_KMEMTRACE */ > + > +static inline void kmemtrace_mark_alloc(enum kmemtrace_type_id type_id, > + unsigned long call_site, > + const void *ptr, > + size_t bytes_req, > + size_t bytes_alloc, > + gfp_t gfp_flags) > +{ > + kmemtrace_mark_alloc_node(type_id, call_site, ptr, > + bytes_req, bytes_alloc, gfp_flags, -1); > +} > + > +#endif /* __KERNEL__ */ > + > +#endif /* _LINUX_KMEMTRACE_H */ > + > diff --git a/init/main.c b/init/main.c > index 057f364..c00659c 100644 > --- a/init/main.c > +++ b/init/main.c > @@ -66,6 +66,7 @@ > #include <asm/setup.h> > #include <asm/sections.h> > #include <asm/cacheflush.h> > +#include <linux/kmemtrace.h> > > #ifdef CONFIG_X86_LOCAL_APIC > #include <asm/smp.h> > @@ -641,6 +642,7 @@ asmlinkage void __init start_kernel(void) > enable_debug_pagealloc(); > cpu_hotplug_init(); > kmem_cache_init(); > + kmemtrace_init(); > debug_objects_mem_init(); > idr_init_cache(); > setup_per_cpu_pageset(); > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug > index d2099f4..0ade2ae 100644 > --- a/lib/Kconfig.debug > +++ b/lib/Kconfig.debug > @@ -674,6 +674,34 @@ config FIREWIRE_OHCI_REMOTE_DMA > > If unsure, say N. > > +config KMEMTRACE > + bool "Kernel memory tracer (kmemtrace)" > + depends on RELAY && DEBUG_FS && MARKERS > + help > + kmemtrace provides tracing for slab allocator functions, such as > + kmalloc, kfree, kmem_cache_alloc, kmem_cache_free etc.. Collected > + data is then fed to the userspace application in order to analyse > + allocation hotspots, internal fragmentation and so on, making it > + possible to see how well an allocator performs, as well as debug > + and profile kernel code. > + > + This requires an userspace application to use. See > + Documentation/vm/kmemtrace.txt for more information. > + > + Saying Y will make the kernel somewhat larger and slower. However, > + if you disable kmemtrace at run-time or boot-time, the performance > + impact is minimal (depending on the arch the kernel is built for). > + > + If unsure, say N. > + > +config KMEMTRACE_DEFAULT_ENABLED > + bool "Enabled by default at boot" > + depends on KMEMTRACE > + help > + Say Y here to enable kmemtrace at boot-time by default. Whatever > + the choice, the behavior can be overridden by a kernel parameter, > + as described in documentation. > + > source "samples/Kconfig" > > source "lib/Kconfig.kgdb" > diff --git a/mm/Makefile b/mm/Makefile > index 18c143b..d88a3bc 100644 > --- a/mm/Makefile > +++ b/mm/Makefile > @@ -33,4 +33,4 @@ obj-$(CONFIG_MIGRATION) += migrate.o > obj-$(CONFIG_SMP) += allocpercpu.o > obj-$(CONFIG_QUICKLIST) += quicklist.o > obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o > - > +obj-$(CONFIG_KMEMTRACE) += kmemtrace.o > diff --git a/mm/kmemtrace.c b/mm/kmemtrace.c > new file mode 100644 > index 0000000..4b33ace > --- /dev/null > +++ b/mm/kmemtrace.c > @@ -0,0 +1,244 @@ > +/* > + * Copyright (C) 2008 Pekka Enberg, Eduard - Gabriel Munteanu > + * > + * This file is released under GPL version 2. > + */ > + > +#include <linux/string.h> > +#include <linux/debugfs.h> > +#include <linux/relay.h> > +#include <linux/module.h> > +#include <linux/marker.h> > +#include <linux/gfp.h> > +#include <linux/kmemtrace.h> > + > +#define KMEMTRACE_SUBBUF_SIZE (8192 * sizeof(struct kmemtrace_event)) > +#define KMEMTRACE_N_SUBBUFS 20 > + > +static struct rchan *kmemtrace_chan; > +static u32 kmemtrace_buf_overruns; > + > +static unsigned int kmemtrace_n_subbufs; > +#ifdef CONFIG_KMEMTRACE_DEFAULT_ENABLED > +static unsigned int kmemtrace_enabled = 1; > +#else > +static unsigned int kmemtrace_enabled = 0; > +#endif > + > +static u32 kmemtrace_abi_version __read_mostly = KMEMTRACE_ABI_VERSION; > + > +static inline void kmemtrace_log_event(struct kmemtrace_event *event) > +{ > + relay_write(kmemtrace_chan, event, sizeof(struct kmemtrace_event)); > +} > + > +static void kmemtrace_probe_alloc(void *probe_data, void *call_data, > + const char *format, va_list *args) > +{ > + unsigned long flags; > + struct kmemtrace_event ev; > + > + /* > + * Don't convert this to use structure initializers, > + * C99 does not guarantee the rvalues evaluation order. > + */ > + ev.event_id = KMEMTRACE_EVENT_ALLOC; > + ev.type_id = va_arg(*args, int); > + ev.event_size = sizeof(struct kmemtrace_event); > + ev.call_site = va_arg(*args, unsigned long); > + ev.ptr = va_arg(*args, unsigned long); > + /* Don't trace ignored allocations. */ > + if (!ev.ptr) > + return; > + ev.bytes_req = va_arg(*args, unsigned long); > + ev.bytes_alloc = va_arg(*args, unsigned long); > + /* ev.timestamp set below, to preserve event ordering. */ > + ev.gfp_flags = va_arg(*args, unsigned long); > + ev.node = va_arg(*args, int); > + > + /* We disable IRQs for timestamps to match event ordering. */ > + local_irq_save(flags); > + ev.timestamp = ktime_to_ns(ktime_get()); > + kmemtrace_log_event(&ev); > + local_irq_restore(flags); > +} > + > +static void kmemtrace_probe_free(void *probe_data, void *call_data, > + const char *format, va_list *args) > +{ > + unsigned long flags; > + struct kmemtrace_event ev; > + > + /* > + * Don't convert this to use structure initializers, > + * C99 does not guarantee the rvalues evaluation order. > + */ > + ev.event_id = KMEMTRACE_EVENT_FREE; > + ev.type_id = va_arg(*args, int); > + ev.event_size = sizeof(struct kmemtrace_event); > + ev.call_site = va_arg(*args, unsigned long); > + ev.ptr = va_arg(*args, unsigned long); > + /* Don't trace ignored allocations. */ > + if (!ev.ptr) > + return; > + /* ev.timestamp set below, to preserve event ordering. */ > + > + /* We disable IRQs for timestamps to match event ordering. */ > + local_irq_save(flags); > + ev.timestamp = ktime_to_ns(ktime_get()); > + kmemtrace_log_event(&ev); > + local_irq_restore(flags); > +} > + > +static struct dentry * > +kmemtrace_create_buf_file(const char *filename, struct dentry *parent, > + int mode, struct rchan_buf *buf, int *is_global) > +{ > + return debugfs_create_file(filename, mode, parent, buf, > + &relay_file_operations); > +} > + > +static int kmemtrace_remove_buf_file(struct dentry *dentry) > +{ > + debugfs_remove(dentry); > + > + return 0; > +} > + > +static int kmemtrace_count_overruns(struct rchan_buf *buf, > + void *subbuf, void *prev_subbuf, > + size_t prev_padding) > +{ > + if (relay_buf_full(buf)) { > + /* > + * We know it's not SMP-safe, but neither > + * debugfs_create_u32() is. > + */ > + kmemtrace_buf_overruns++; > + return 0; > + } > + > + return 1; > +} > + > +static struct rchan_callbacks relay_callbacks = { > + .create_buf_file = kmemtrace_create_buf_file, > + .remove_buf_file = kmemtrace_remove_buf_file, > + .subbuf_start = kmemtrace_count_overruns, > +}; > + > +static struct dentry *kmemtrace_dir; > +static struct dentry *kmemtrace_overruns_dentry; > +static struct dentry *kmemtrace_abi_version_dentry; > + > +static void kmemtrace_cleanup(void) > +{ > + marker_probe_unregister("kmemtrace_alloc", kmemtrace_probe_alloc, NULL); > + marker_probe_unregister("kmemtrace_free", kmemtrace_probe_free, NULL); > + > + if (kmemtrace_abi_version_dentry) > + debugfs_remove(kmemtrace_abi_version_dentry); > + if (kmemtrace_overruns_dentry) > + debugfs_remove(kmemtrace_overruns_dentry); > + > + relay_close(kmemtrace_chan); > + kmemtrace_chan = NULL; > + > + if (kmemtrace_dir) > + debugfs_remove(kmemtrace_dir); > +} > + > +static int __init kmemtrace_setup_late(void) > +{ > + if (!kmemtrace_chan) > + goto failed; > + > + kmemtrace_dir = debugfs_create_dir("kmemtrace", NULL); > + if (!kmemtrace_dir) > + goto cleanup; > + > + kmemtrace_abi_version_dentry = > + debugfs_create_u32("abi_version", S_IRUSR, > + kmemtrace_dir, &kmemtrace_abi_version); > + kmemtrace_overruns_dentry = > + debugfs_create_u32("total_overruns", S_IRUSR, > + kmemtrace_dir, &kmemtrace_buf_overruns); > + if (!kmemtrace_overruns_dentry || !kmemtrace_abi_version_dentry) > + goto cleanup; > + > + if (relay_late_setup_files(kmemtrace_chan, "cpu", kmemtrace_dir)) > + goto cleanup; > + > + printk(KERN_INFO "kmemtrace: fully up.\n"); > + > + return 0; > + > +cleanup: > + kmemtrace_cleanup(); > +failed: > + return 1; > +} > +late_initcall(kmemtrace_setup_late); > + > +static int __init kmemtrace_set_boot_enabled(char *str) > +{ > + if (!str) > + return -EINVAL; > + > + if (!strcmp(str, "yes")) > + kmemtrace_enabled = 1; > + else if (!strcmp(str, "no")) > + kmemtrace_enabled = 0; > + else > + return -EINVAL; > + > + return 0; > +} > +early_param("kmemtrace.enable", kmemtrace_set_boot_enabled); > + > +static int __init kmemtrace_set_subbufs(char *str) > +{ > + get_option(&str, &kmemtrace_n_subbufs); > + return 0; > +} > +early_param("kmemtrace.subbufs", kmemtrace_set_subbufs); > + > +void kmemtrace_init(void) > +{ > + int err; > + > + if (!kmemtrace_enabled) > + return; > + > + if (!kmemtrace_n_subbufs) > + kmemtrace_n_subbufs = KMEMTRACE_N_SUBBUFS; > + > + kmemtrace_chan = relay_open(NULL, NULL, KMEMTRACE_SUBBUF_SIZE, > + kmemtrace_n_subbufs, &relay_callbacks, > + NULL); > + if (!kmemtrace_chan) { > + printk(KERN_INFO "kmemtrace: could not open relay channel\n"); > + return; > + } > + > + err = marker_probe_register("kmemtrace_alloc", "type_id %d " > + "call_site %lu ptr %lu " > + "bytes_req %lu bytes_alloc %lu " > + "gfp_flags %lu node %d", > + kmemtrace_probe_alloc, NULL); > + if (err) > + goto probe_fail; > + err = marker_probe_register("kmemtrace_free", "type_id %d " > + "call_site %lu ptr %lu", > + kmemtrace_probe_free, NULL); > + if (err) > + goto probe_fail; > + > + printk(KERN_INFO "kmemtrace: early init successful.\n"); > + return; > + > +probe_fail: > + printk(KERN_INFO "kmemtrace: could not register marker probes!\n"); > + kmemtrace_cleanup(); > +} > +
| |