tracing/kmemtrace: normalize the raw tracer event to the unified tracing API
Subsystems (4)
PATCH 1/1 tracing/kmemtrace: normalize the raw tracer event to the unified tracing API
Impact: new tracer
This patch adapts kmemtrace raw events tracing to the unified tracing API. It applies on latest tip/tracing/kmemtrace
To enable and use this tracer, just do the following:
echo kmemtrace > /debugfs/tracing/current_tracer
cat /debugfs/tracing/trace
You will have the following output:
type_id 1 call_site 18446744071565527833 ptr 18446612134395152256type_id 0 call_site 18446744071565585597 ptr 18446612134405955584 bytes_req 4096 bytes_alloc 4096 gfp_flags 208 node -1 type_id 1 call_site 18446744071565585534 ptr 18446612134405955584type_id 0 call_site 18446744071565585597 ptr 18446612134405955584 bytes_req 4096 bytes_alloc 4096 gfp_flags 208 node -1 type_id 0 call_site 18446744071565636711 ptr 18446612134345164672 bytes_req 240 bytes_alloc 240 gfp_flags 208 node -1 type_id 1 call_site 18446744071565585534 ptr 18446612134405955584type_id 0 call_site 18446744071565585597 ptr 18446612134405955584 bytes_req 4096 bytes_alloc 4096 gfp_flags 208 node -1 type_id 0 call_site 18446744071565636711 ptr 18446612134345164912 bytes_req 240 bytes_alloc 240 gfp_flags 208 node -1 type_id 1 call_site 18446744071565585534 ptr 18446612134405955584type_id 0 call_site 18446744071565585597 ptr 18446612134405955584 bytes_req 4096 bytes_alloc 4096 gfp_flags 208 node -1 type_id 0 call_site 18446744071565636711 ptr 18446612134345165152 bytes_req 240 bytes_alloc 240 gfp_flags 208 node -1 type_id 0 call_site 18446744071566144042 ptr 18446612134346191680 bytes_req 1304 bytes_alloc 1312 gfp_flags 208 node -1 type_id 1 call_site 18446744071565585534 ptr 18446612134405955584type_id 0 call_site 18446744071565585597 ptr 18446612134405955584 bytes_req 4096 bytes_alloc 4096 gfp_flags 208 node -1 type_id 1 call_site 18446744071565585534 ptr 18446612134405955584
That was to stay backward compatible with the format output produced in linux/tracepoint.h This is the default ouput, but note that I tried something else.
If you change an option:
echo kmem_minimalistic > /debugfs/trace_options
and then cat /debugfs/trace
You will have the following output:
- C 0xffff88007c088780 file_free_rcu + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname - C 0xffff88007cad6000 putname + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname + K 240 240 000000d0 0xffff8800790dc780 -1 d_alloc - C 0xffff88007cad6000 putname + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname + K 240 240 000000d0 0xffff8800790dc870 -1 d_alloc - C 0xffff88007cad6000 putname + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname + K 240 240 000000d0 0xffff8800790dc960 -1 d_alloc + K 1304 1312 000000d0 0xffff8800791d7340 -1 reiserfs_alloc_inode - C 0xffff88007cad6000 putname + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname - C 0xffff88007cad6000 putname + K 992 1000 000000d0 0xffff880079045b58 -1 alloc_inode + K 768 1024 000080d0 0xffff88007c096400 -1 alloc_pipe_info + K 240 240 000000d0 0xffff8800790dca50 -1 d_alloc + K 272 320 000080d0 0xffff88007c088780 -1 get_empty_filp + K 272 320 000080d0 0xffff88007c088000 -1 get_empty_filp
Yeah I shall confess kmem_minimalistic should be: kmem_alternative.
Whatever, I find it more readable but this a personal opinion of course. We can drop it if you want. On the ALLOC/FREE column, + means an allocation and - a free.
On the type column, you have K = kmalloc, C = cache, P = page
I would like the flags to be GFP_* strings but that would not be easy to not break the column with strings....
About the node...it seems to always be -1. I don't know why but that shouldn't be difficult to find.
I moved linux/tracepoint.h to trace/tracepoint.h as well. I think that would be more easy to find the tracer headers if they are all in their common directory.
Don't hesitate to comment, I'm not a kmemtrace specialist so...
--- include/linux/kmemtrace.h | 86 ---------- include/linux/slab_def.h | 2 +- include/linux/slub_def.h | 2 +- include/trace/kmemtrace.h | 75 +++++++++ init/main.c | 2 +- kernel/trace/Kconfig | 21 +++ kernel/trace/Makefile | 1 + kernel/trace/trace.h | 25 +++ kernel/trace/trace_kmemtrace.c | 345 ++++++++++++++++++++++++++++++++++++++++ lib/Kconfig.debug | 20 --- mm/kmemtrace.c | 2 +- mm/slob.c | 2 +- mm/slub.c | 2 +- 13 files changed, 473 insertions(+), 112 deletions(-)
include/linux/kmemtrace.h deleted +0 -86
@@ -1,86 +0,0 @@ -/* -* 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> - -enum kmemtrace_type_id { -KMEMTRACE_TYPE_KMALLOC =0 ,/* kmalloc() or kfree(). */ -KMEMTRACE_TYPE_CACHE ,/* kmem_cache_*(). */ -KMEMTRACE_TYPE_PAGES ,/* __get_free_pages() and friends. */ -}; - -#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, - (unsigned long ) bytes_req, (unsigned long ) 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 */ -
include/linux/slab_def.h +1 -1
@@ -14,7 +14,7 @@#include <asm/page.h> /* kmalloc_sizes.h needs PAGE_SIZE */ #include <asm/cache.h> /* kmalloc_sizes.h needs L1_CACHE_BYTES */ #include <linux/compiler.h> -#include <linux/kmemtrace.h> +#include <trace/kmemtrace.h> /* Size description struct for general caches. */ struct cache_sizes {
include/linux/slub_def.h +1 -1
@@ -10,7 +10,7 @@#include <linux/gfp.h> #include <linux/workqueue.h> #include <linux/kobject.h> -#include <linux/kmemtrace.h> +#include <trace/kmemtrace.h> enum stat_item {ALLOC_FASTPATH ,/* Allocation from cpu slab */
include/trace/kmemtrace.h new file +75 -0
75 lines not on this page · raw message
init/main.c +1 -1
@@ -70,7 +70,7 @@#include <asm/setup.h> #include <asm/sections.h> #include <asm/cacheflush.h> -#include <linux/kmemtrace.h> +#include <trace/kmemtrace.h> #ifdef CONFIG_X86_LOCAL_APIC #include <asm/smp.h>
kernel/trace/Kconfig +21 -0
@@ -264,6 +264,27 @@ config HW_BRANCH_TRACER This tracer records all branches on the system in a circular buffer giving access to the last N branches for each cpu. +config KMEMTRACE + bool "Trace SLAB allocations" + select TRACING + 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 DYNAMIC_FTRACE bool "enable/disable ftrace tracepoints dynamically" depends on FUNCTION_TRACER
kernel/trace/Makefile +1 -0
@@ -33,5 +33,6 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o obj-$(CONFIG_POWER_TRACER) += trace_power.o +obj-$(CONFIG_KMEMTRACE) += trace_kmemtrace.o libftrace-y := ftrace.o
kernel/trace/trace.h +25 -0
@@ -9,6 +9,7 @@#include <linux/mmiotrace.h> #include <linux/ftrace.h> #include <trace/boot.h> +#include <trace/kmemtrace.h> enum trace_type { __TRACE_FIRST_TYPE =0 ,
@@ -29,6 +30,8 @@ enum trace_type {TRACE_GRAPH_ENT ,TRACE_USER_STACK ,TRACE_HW_BRANCHES , +TRACE_KMEM_ALLOC , +TRACE_KMEM_FREE ,TRACE_POWER , __TRACE_LAST_TYPE
@@ -170,6 +173,24 @@ struct trace_power {struct power_trace state_data; }; +struct kmemtrace_alloc_entry { +struct trace_entry ent; +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; +}; + +struct kmemtrace_free_entry { +struct trace_entry ent; +enum kmemtrace_type_id type_id; +unsigned long call_site; +const void *ptr; +}; +/* * trace_flag_type is an enumeration that holds different * states when a trace occurs. These are:
@@ -280,6 +301,10 @@ extern void __ftrace_bad_type(void); TRACE_GRAPH_RET); \ IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\ IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \ + IF_ASSIGN(var, ent, struct kmemtrace_alloc_entry, \ +TRACE_KMEM_ALLOC ); \ + IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \ +TRACE_KMEM_FREE ); \__ftrace_bad_type (); \ }while (0 )
kernel/trace/trace_kmemtrace.c new file +345 -0
345 lines not on this page · raw message
lib/Kconfig.debug +0 -20
@@ -803,26 +803,6 @@ 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. - menuconfig BUILD_DOCSRC bool "Build targets in Documentation/ tree" depends on HEADERS_CHECK
mm/kmemtrace.c +1 -1
@@ -10,7 +10,7 @@#include <linux/module.h> #include <linux/marker.h> #include <linux/gfp.h> -#include <linux/kmemtrace.h> +#include <trace/kmemtrace.h> #define KMEMTRACE_SUBBUF_SIZE 524288#define KMEMTRACE_DEF_N_SUBBUFS 20
mm/slob.c +1 -1
@@ -65,7 +65,7 @@#include <linux/module.h> #include <linux/rcupdate.h> #include <linux/list.h> -#include <linux/kmemtrace.h> +#include <trace/kmemtrace.h> #include <asm/atomic.h> /*
mm/slub.c +1 -1
@@ -16,7 +16,7 @@#include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> -#include <linux/kmemtrace.h> +#include <trace/kmemtrace.h> #include <linux/cpu.h> #include <linux/cpuset.h> #include <linux/mempolicy.h>
Signature · 1 line
1.6.0.4
And of course the headers of the trace have been zapped by git-commit :-) An example with the headers:
# tracer: kmemtrace
#
#
# ALLOC TYPE REQ GIVEN FLAGS POINTER NODE CALLER
# FREE | | | | | | | |
# |
- C 0xffff88007c088780 file_free_rcu + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname - C 0xffff88007cad6000 putname + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname + K 240 240 000000d0 0xffff8800790dc780 -1 d_alloc - C 0xffff88007cad6000 putname + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname + K 240 240 000000d0 0xffff8800790dc870 -1 d_alloc - C 0xffff88007cad6000 putname + K 4096 4096 000000d0 0xffff88007cad6000 -1 getname + K 240 240 000000d0 0xffff8800790dc960 -1 d_alloc + K 1304 1312 000000d0 0xffff8800791d7340 -1 reiserfs_alloc_inode
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
Quoted 6 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
Hmm, forgot to cc Ingo...
Hi Frederic,
Quoted 6 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
It really depends on what we're tracing. If we're interested in just the allocation hotspots, a section will do just fine. However, if we're tracing memory footprint, we need to take into store the object pointer returned from kmalloc() and kmem_cache_alloc() so we can update call-site statistics properly upon kfree().
So I suppose we need both, a section for per call-site statistics and a hash table for the object -> call-site mapping.
Pekka
Quoted 16 lines · Pekka Enberg
Hi Frederic,
Quoted 6 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
It really depends on what we're tracing. If we're interested in just the allocation hotspots, a section will do just fine. However, if we're tracing memory footprint, we need to take into store the object pointer returned from
kmalloc()andkmem_cache_alloc()so we can update call-site statistics properly uponkfree().
Quoted 4 lines
So I suppose we need both, a section for per call-site statistics and a hash table for the object -> call-site mapping.
Pekka
Hi Frederic,
Thanks for doing this work.
kmemtrace-user currently shows two main views: per call-site and per-allocation. For the former, it uses a hashtable to accumulate statistics. There's also a hashtable for individual allocations (by ptr address), which we use to check for consistency for example ("if this is going to be freed, has it been allocated?"). Apart from those two views, it also shows global statistics.
Thanks again,
Eduard
Quoted 10 lines · Pekka Enberg
Hi Frederic,
Quoted 6 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
Quoted 8 lines
It really depends on what we're tracing. If we're interested in just the allocation hotspots, a section will do just fine. However, if we're tracing memory footprint, we need to take into store the object pointer returned from
kmalloc()andkmem_cache_alloc()so we can update call-site statistics properly uponkfree().So I suppose we need both, a section for per call-site statistics and a hash table for the object -> call-site mapping.
1)
i think the call_site based tracking should be a built-in capability - the branch tracer needs that too for example. That would also make it very simple on the usage place: you wouldnt have to worry about sections in slub.c/etc.
2)
i think a possibly useful intermediate object would be the slab cache itself, which could be the basis for some highlevel stats too. It would probably overlap /proc/slabinfo statistics but it's a natural part of this abstraction i think.
3)
the most lowlevel (and hence most allocation-footprint sensitive) object to track would be the memory object itself. I think the best approach would be to do a static, limited size hash that could track up to N memory objects.
The advantage of such an approach is that it does not impact allocation patterns at all (besides the one-time allocation cost of the hash itself during tracer startup).
The disadvantage is when an overflow happens: the sizing heuristics would get the size correct most of the time anyway, so it's not a practical issue. There would be some sort of sizing control similar to /debug/tracing/buffer_size_kb, and a special trace entry that signals an 'overflow' of the hash table. (in that case we wont track certain objects
- but it would be clear from the trace output what happens and the hash size can be adjusted.)
Another advantage would be that it would trivially not interact with any allocator - because the hash itself would never 'allocate' in any dynamic way. Either there are free entries available (in which case we use it), or not - in which case we emit an hash-overflow trace entry.
And this too would be driven from ftrace mainly - the SLAB code would only offer the alloc+free callbacks with the object IDs. [ and this means that we could detect memory leaks by looking at the hash table and print out the age of entries :-) ]
How does this sound to you?
Ingo
Quoted 10 lines · Ingo Molnar
3)
the most lowlevel (and hence most allocation-footprint sensitive) object to track would be the memory object itself. I think the best approach would be to do a static, limited size hash that could track up to N memory objects.
The advantage of such an approach is that it does not impact allocation patterns at all (besides the one-time allocation cost of the hash itself during tracer startup).
kmemtrace-user handles this by analysing offline :). I presume you could get around this by discarding every hash collision in a well-sized hashtable. The hashing algo in kmemtrace-user performs okay, considering it fills the hashtable almost entirely, but I presume you're doing that in-kernel and using other available code.
Quoted 4 lines
And this too would be driven from ftrace mainly - the SLAB code would only offer the alloc+free callbacks with the object IDs. [ and this means that we could detect memory leaks by looking at the hash table and print out the age of entries :-) ]
Some time ago I dropped timestamps because they were not providing a good way to reorder packets in userspace. We're currently relying on a sequence number to do that. You could take that as 'age', but it's not temporally-meaningful.
Eduard
Quoted 12 lines · Eduard - Gabriel Munteanu
Quoted 10 lines · Ingo Molnar
3)
the most lowlevel (and hence most allocation-footprint sensitive) object to track would be the memory object itself. I think the best approach would be to do a static, limited size hash that could track up to N memory objects.
The advantage of such an approach is that it does not impact allocation patterns at all (besides the one-time allocation cost of the hash itself during tracer startup).
Quoted 5 lines
kmemtrace-user handles this by analysing offline :). I presume you could get around this by discarding every hash collision in a well-sized hashtable. The hashing algo in kmemtrace-user performs okay, considering it fills the hashtable almost entirely, but I presume you're doing that in-kernel and using other available code.
yeah - this is not a replacement for kmemtrace-user - analyzing raw trace events offline is still possible of course.
Quoted 9 lines
Quoted 4 lines
And this too would be driven from ftrace mainly - the SLAB code would only offer the alloc+free callbacks with the object IDs. [ and this means that we could detect memory leaks by looking at the hash table and print out the age of entries :-) ]
Some time ago I dropped timestamps because they were not providing a good way to reorder packets in userspace. We're currently relying on a sequence number to do that. You could take that as 'age', but it's not temporally-meaningful.
yeah - ftrace entries generally have a timestamp so it should be rather easy.
Ingo
Hi Ingo,
Quoted 7 lines · Ingo Molnar
1)
i think the
call_sitebased tracking should be a built-in capability - the branch tracer needs that too for example. That would also make it very simple on the usage place: you wouldnt have to worry about sections in slub.c/etc.
Quoted 6 lines
2)
i think a possibly useful intermediate object would be the slab cache itself, which could be the basis for some highlevel stats too. It would probably overlap
/proc/slabinfostatistics but it's a natural part of this abstraction i think.
Makes sense but keep in mind that this is really just an extension to SLUB statistics and is only good for detecting allocation hotspots, not for analyzing memory footprint.
Quoted 24 lines · Ingo Molnar
3)
the most lowlevel (and hence most allocation-footprint sensitive) object to track would be the memory object itself. I think the best approach would be to do a static, limited size hash that could track up to N memory objects.
The advantage of such an approach is that it does not impact allocation patterns at all (besides the one-time allocation cost of the hash itself during tracer startup).
The disadvantage is when an overflow happens: the sizing heuristics would get the size correct most of the time anyway, so it's not a practical issue. There would be some sort of sizing control similar to /debug/tracing/buffer_size_kb, and a special trace entry that signals an 'overflow' of the hash table. (in that case we wont track certain objects
- but it would be clear from the trace output what happens and the hash size can be adjusted.)Another advantage would be that it would trivially not interact with any allocator - because the hash itself would never 'allocate' in any dynamic way. Either there are free entries available (in which case we use it), or not - in which case we emit an hash-overflow trace entry.
Quoted 6 lines
And this too would be driven from ftrace mainly - the SLAB code would only offer the alloc+free callbacks with the object IDs. [ and this means that we could detect memory leaks by looking at the hash table and print out the age of entries :-) ]
How does this sound to you?
That will probably be okay for things like analyzing memory footprint immediately after boot. However, as soon as the amount of active memory objects increases (think dentry and inode cache), the numbers might get skewed. One option would be to let the user exclude some of the caches from tracing.
Pekka
Quoted 51 lines · Pekka Enberg
Hi Ingo,
Quoted 7 lines · Ingo Molnar
1)
i think the
call_sitebased tracking should be a built-in capability - the branch tracer needs that too for example. That would also make it very simple on the usage place: you wouldnt have to worry about sections in slub.c/etc.Quoted 6 lines
2)
i think a possibly useful intermediate object would be the slab cache itself, which could be the basis for some highlevel stats too. It would probably overlap
/proc/slabinfostatistics but it's a natural part of this abstraction i think.Makes sense but keep in mind that this is really just an extension to SLUB statistics and is only good for detecting allocation hotspots, not for analyzing memory footprint.
Quoted 29 lines · Ingo Molnar
3)
the most lowlevel (and hence most allocation-footprint sensitive) object to track would be the memory object itself. I think the best approach would be to do a static, limited size hash that could track up to N memory objects.
The advantage of such an approach is that it does not impact allocation patterns at all (besides the one-time allocation cost of the hash itself during tracer startup).
The disadvantage is when an overflow happens: the sizing heuristics would get the size correct most of the time anyway, so it's not a practical issue. There would be some sort of sizing control similar to /debug/tracing/buffer_size_kb, and a special trace entry that signals an 'overflow' of the hash table. (in that case we wont track certain objects
- but it would be clear from the trace output what happens and the hash size can be adjusted.)Another advantage would be that it would trivially not interact with any allocator - because the hash itself would never 'allocate' in any dynamic way. Either there are free entries available (in which case we use it), or not - in which case we emit an hash-overflow trace entry.
And this too would be driven from ftrace mainly - the SLAB code would only offer the alloc+free callbacks with the object IDs. [ and this means that we could detect memory leaks by looking at the hash table and print out the age of entries :-) ]
Quoted 7 lines
Quoted 1 line
How does this sound to you?
That will probably be okay for things like analyzing memory footprint immediately after boot. However, as soon as the amount of active memory objects increases (think dentry and inode cache), the numbers might get skewed. One option would be to let the user exclude some of the caches from tracing.
well, it gets skewed only in terms of total footprint: the same way as if you had total_ram-hash_size amount of RAM. Since there are so many RAM sizes possible, this can be considered as if the test was done on a slighly smaller machine - but otherwise it's an invariant. It wont impact the micro-layout of the slab objects themselves (does not change their size), and it shouldnt impact most workloads which behave very gradually to small changes in total memory size.
Ingo
Quoted 22 lines · Ingo Molnar
Quoted 10 lines · Pekka Enberg
Hi Frederic,
Quoted 6 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
Quoted 8 lines
It really depends on what we're tracing. If we're interested in just the allocation hotspots, a section will do just fine. However, if we're tracing memory footprint, we need to take into store the object pointer returned from
kmalloc()andkmem_cache_alloc()so we can update call-site statistics properly uponkfree().So I suppose we need both, a section for per call-site statistics and a hash table for the object -> call-site mapping.
Quoted 6 lines
1)
i think the
call_sitebased tracking should be a built-in capability - the branch tracer needs that too for example. That would also make it very simple on the usage place: you wouldnt have to worry about sections in slub.c/etc.
I think that too. Can we use sections here? The traced functions are not directly kmalloc/kmem_cache_alloc and to use a section which contains the per site allocation requests, such a thing is required (we can't build a section with per site allocations requests by using intermediate level allocation function I fear...).
Quoted 30 lines
2)
i think a possibly useful intermediate object would be the slab cache itself, which could be the basis for some highlevel stats too. It would probably overlap
/proc/slabinfostatistics but it's a natural part of this abstraction i think.3)
the most lowlevel (and hence most allocation-footprint sensitive) object to track would be the memory object itself. I think the best approach would be to do a static, limited size hash that could track up to N memory objects.
The advantage of such an approach is that it does not impact allocation patterns at all (besides the one-time allocation cost of the hash itself during tracer startup).The disadvantage is when an overflow happens: the sizing heuristics would get the size correct most of the time anyway, so it's not a practical issue. There would be some sort of sizing control similar to /debug/tracing/buffer_size_kb, and a special trace entry that signals an 'overflow' of the hash table. (in that case we wont track certain objects
- but it would be clear from the trace output what happens and the hash size can be adjusted.)Another advantage would be that it would trivially not interact with any allocator - because the hash itself would never 'allocate' in any dynamic way. Either there are free entries available (in which case we use it), or not - in which case we emit an hash-overflow trace entry.
Quoted 8 lines
And this too would be driven from ftrace mainly - the SLAB code would only offer the alloc+free callbacks with the object IDs. [ and this means that we could detect memory leaks by looking at the hash table and print out the age of entries :-) ]
How does this sound to you?
Ingo
That looks good. Since we can have an overflow event, it would always be possible to built-in enlarge it for debugging purposes....
Quoted 31 lines · Frederic Weisbecker
Quoted 22 lines · Ingo Molnar
Quoted 10 lines · Pekka Enberg
Hi Frederic,
Quoted 6 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
Quoted 8 lines
It really depends on what we're tracing. If we're interested in just the allocation hotspots, a section will do just fine. However, if we're tracing memory footprint, we need to take into store the object pointer returned from
kmalloc()andkmem_cache_alloc()so we can update call-site statistics properly uponkfree().So I suppose we need both, a section for per call-site statistics and a hash table for the object -> call-site mapping.
Quoted 6 lines
1)
i think the
call_sitebased tracking should be a built-in capability - the branch tracer needs that too for example. That would also make it very simple on the usage place: you wouldnt have to worry about sections in slub.c/etc.
Quoted 5 lines
I think that too. Can we use sections here? The traced functions are not directly kmalloc/kmem_cache_alloc and to use a section which contains the per site allocation requests, such a thing is required (we can't build a section with per site allocations requests by using intermediate level allocation function I fear...).
i think initially this should be a fixed-size allocation array + hash as well. (like lockdep uses) The number of allocation sites is even the most extreme case at most a few thousand - and is typically at most a couple of hundred.
Ingo
Quoted 40 lines · Ingo Molnar
Quoted 31 lines · Frederic Weisbecker
Quoted 22 lines · Ingo Molnar
Quoted 10 lines · Pekka Enberg
Hi Frederic,
Quoted 6 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
Quoted 8 lines
It really depends on what we're tracing. If we're interested in just the allocation hotspots, a section will do just fine. However, if we're tracing memory footprint, we need to take into store the object pointer returned from
kmalloc()andkmem_cache_alloc()so we can update call-site statistics properly uponkfree().So I suppose we need both, a section for per call-site statistics and a hash table for the object -> call-site mapping.
Quoted 6 lines
1)
i think the
call_sitebased tracking should be a built-in capability - the branch tracer needs that too for example. That would also make it very simple on the usage place: you wouldnt have to worry about sections in slub.c/etc.Quoted 5 lines
I think that too. Can we use sections here? The traced functions are not directly kmalloc/kmem_cache_alloc and to use a section which contains the per site allocation requests, such a thing is required (we can't build a section with per site allocations requests by using intermediate level allocation function I fear...).
Quoted 6 lines
i think initially this should be a fixed-size allocation array + hash as well. (like lockdep uses) The number of allocation sites is even the most extreme case at most a few thousand - and is typically at most a couple of hundred.
Ingo
Why not. And if someone reports too much overruns, we could make the size of this array an option for the kernel.
Quoted 16 lines · Pekka Enberg
Hi Frederic,
Quoted 6 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
But I don't know your projects about this... whether you wanted to use a section or something else...
It really depends on what we're tracing. If we're interested in just the allocation hotspots, a section will do just fine. However, if we're tracing memory footprint, we need to take into store the object pointer returned from
kmalloc()andkmem_cache_alloc()so we can update call-site statistics properly uponkfree().
Quoted 5 lines
So I suppose we need both, a section for per call-site statistics and a hash table for the object -> call-site mapping.
Pekka
BTW. By looking on your needs, the statistical branch tracer and the rcu stat one, it looks like these tracers often (if not always) need several stat files, not only one.
Actually what I should do with stat tracing is to build a directory inside /debugfs/tracing devoted to the several stat output a tracer need.
Which means I have to make trace_stat.c completely reentrant and some other things....plus the fact that multiple tracers should be enable to run concurrently for 2.6.30... which means one directory of stat tracing for each running tracer.
Quoted 3 lines · Frederic Weisbecker
Pekka, note that I would be pleased to add statistical tracing on this tracer, but I would need a hashtable, or an array, or a list, or whatever iterable to insert the data into the stat tracing api.
there would be a couple of natural objects to group events by:
1) callsite [IP] of kmalloc()/kfree()/etc.
2) slab cache
3) slab object
for 1) callsite based histograms, i think ftrace should have a built-in mechanism for that. kmemtrace tracepoints already pass in a call_site argument that can be used to drive it.
for 2) slab cache based histograms (counts) - we need some knowledge about the affected slab caches, and we need some space as well. The tracepoints could be extended with a kmem_cache argument perhaps. A callback is needed at cache creation time (which could be in the form of a tracepoint) that gives kernel/tracing/kmemtrace.c the right place to allocate the per slab histogram. (so that the other tracepoints dont have to do it implicitly - which would be fragile as we are in the SLAB code, often with spinlocks taken, so we cannot allocate)
i think 3) is the hardest so lets skip it for now ;-)
Ingo
Quoted 8 lines · Frederic Weisbecker
Impact: new tracer
This patch adapts kmemtrace raw events tracing to the unified tracing API. It applies on latest tip/tracing/kmemtrace To enable and use this tracer, just do the following:
echo kmemtrace > /debugfs/tracing/current_tracer
cat /debugfs/tracing/trace
nice! I've put this into a separate topic for the time being:
tip/tracing/kmemtrace2, so that Pekka and Eduard can comment on it.
Ingo
Quoted 1 line · Frederic Weisbecker
kernel/trace/trace_kmemtrace.c | 345 ++++++++++++++++++++++++++++++++++++++++
btw., i renamed this to kernel/trace/kmemtrace.c. Mentioning 'trace' twice is enough already ;-)
Ingo
Steven Rostedt
maintainerQuoted 7 lines · Ingo Molnar
Quoted 1 line · Frederic Weisbecker
kernel/trace/trace_kmemtrace.c | 345 ++++++++++++++++++++++++++++++++++++++++btw., i renamed this to
kernel/trace/kmemtrace.c. Mentioning 'trace' twice is enough already ;-)
Should we rename all the kernel/trace/trace_(.*)\.c to kernel/trace/\1.c ?
Although I do like the trace in the function name, because it groups them nicely together, and keeps ftrace.c and ring_buffer.c stand out from the rest.
-- Steve
Quoted 11 lines · Steven Rostedt
Quoted 7 lines · Ingo Molnar
Quoted 1 line · Frederic Weisbecker
kernel/trace/trace_kmemtrace.c | 345 ++++++++++++++++++++++++++++++++++++++++btw., i renamed this to
kernel/trace/kmemtrace.c. Mentioning 'trace' twice is enough already ;-)
Quoted 8 lines
Should we rename all the kernel/trace/trace_(.*)\.c to kernel/trace/\1.c ?
Although I do like the trace in the function name, because it groups them nicely together, and keeps
ftrace.candring_buffer.cstand out from the rest.-- Steve
Or why not a subdirectory called "tracers" inside kernel/trace to store
the tracers files. This way, the core of tracing (ftrace.c/ring_buffer.c/trace_output.c/ /trace.c/trace_stat.c) can be found easily against the rest. Moreover, there is a risk that the number of tracers will tend to increase by the time.