// memory/vm related tapset // Copyright (C) 2005, 2006 IBM Corp. // Copyright (C) 2006 Intel Corporation. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General // Public License (GPL); either version 2, or (at your option) any // later version. // // This family of probe points is used to probe memory-related events. // %{ #include %} global VM_FAULT_OOM=0, VM_FAULT_SIGBUS=1, VM_FAULT_MINOR=2, VM_FAULT_MAJOR=3 global VM_FAULT_NOPAGE=4, VM_FAULT_LOCKED=5, VM_FAULT_ERROR=6 global FAULT_FLAG_WRITE=1 /** * sfunction vm_fault_contains - Test return value for page fault reason * @value: The fault_type returned by vm.page_fault.return * @test: The type of fault to test for (VM_FAULT_OOM or similar) */ function vm_fault_contains:long (value:long, test:long) %{ int res; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) switch (THIS->test){ case 0: res = THIS->value == VM_FAULT_OOM; break; case 1: res = THIS->value == VM_FAULT_SIGBUS; break; case 2: res = THIS->value == VM_FAULT_MINOR; break; case 3: res = THIS->value == VM_FAULT_MAJOR; break; default: res = 0; break; } #else switch (THIS->test){ case 0: res = THIS->value & VM_FAULT_OOM; break; case 1: res = THIS->value & VM_FAULT_SIGBUS; break; case 2: /* VM_FAULT_MINOR infered by that flags off */ res = !((VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_MAJOR) & THIS->value); break; case 3: res = THIS->value & VM_FAULT_MAJOR; break; case 4: res = THIS->value & VM_FAULT_NOPAGE; break; case 5: res = THIS->value & VM_FAULT_LOCKED; break; case 6: res = THIS->value & VM_FAULT_ERROR; break; default: res = 0; } #endif THIS->__retvalue = (res != 0); return; %} /** * probe vm.pagefault - Records that a page fault occurred. * @address: The address of the faulting memory access; i.e. the address that caused the page fault. * @write_access: Indicates whether this was a write or read access; 1 indicates a write, * while 0 indicates a read. * * Context: The process which triggered the fault */ probe vm.pagefault = kernel.function("__handle_mm_fault@mm/memory.c") ?, kernel.function("handle_mm_fault@mm/memory.c") ? { %( kernel_v >= "2.6.31" %? write_access = $flags & FAULT_FLAG_WRITE %: write_access = $write_access %) address = $address } /** * probe vm.pagefault.return - Indicates what type of fault occurred. * @fault_type: Returns either * 0 (VM_FAULT_OOM) for out of memory faults, * 2 (VM_FAULT_MINOR) for minor faults, 3 (VM_FAULT_MAJOR) for * major faults, or 1 (VM_FAULT_SIGBUS) if the fault was neither OOM, minor fault, * nor major fault. */ probe vm.pagefault.return = kernel.function("__handle_mm_fault@mm/memory.c").return ?, kernel.function("handle_mm_fault@mm/memory.c").return ? { fault_type = $return } /** * sfunction addr_to_node - Returns which node a given address belongs to within a NUMA system. * @addr: The address of the faulting memory access. * */ function addr_to_node:long(addr:long) %{ /* pure */ int pfn = __pa(THIS->addr) >> PAGE_SHIFT; int nid; #ifdef for_each_online_node for_each_online_node(nid) #else for (nid=0; nidnode_start_pfn <= pfn && pfn < (NODE_DATA(nid)->node_start_pfn + NODE_DATA(nid)->node_spanned_pages) ) { THIS->__retvalue = nid; break; } %} // Return whether a page to be copied is a zero page. function _IS_ZERO_PAGE:long(from:long, vaddr:long) %{ /* pure */ THIS->__retvalue = (THIS->from == (long) ZERO_PAGE(THIS->vaddr)); %} /** * probe vm.write_shared - Attempts at writing to a shared page. * @address: The address of the shared write. * * Context: * The context is the process attempting the write. * * Fires when a process attempts to write to a shared page. * If a copy is necessary, this will be followed by a * vm.write_shared_copy. */ probe vm.write_shared = kernel.function("do_wp_page") { address = $address } /** * probe vm.write_shared_copy - Page copy for shared page write. * @address: The address of the shared write. * @zero: Boolean indicating whether it is a zero page * (can do a clear instead of a copy). * * Context: * The process attempting the write. * * Fires when a write to a shared page requires a page copy. This is * always preceded by a vm.shared_write. */ probe vm.write_shared_copy = kernel.function("copy_cow_page")? { address = $address zero = _IS_ZERO_PAGE($from, address); } /** * probe vm.mmap - Fires when an mmap is requested. * @address: The requested address * @length: The length of the memory segment * * Context: * The process calling mmap. */ probe vm.mmap = kernel.function("do_mmap"), kernel.function("do_mmap2")? { address = $addr length = $len } /** * probe vm.munmap - Fires when an munmap is requested. * @address: The requested address * @length: The length of the memory segment * * Context: * The process calling munmap. */ probe vm.munmap = kernel.function("do_munmap") { address = $start length = $len } /** * probe vm.brk - Fires when a brk is requested (i.e. the heap will be resized). * @address: The requested address * @length: The length of the memory segment * * Context: * The process calling brk. */ probe vm.brk = kernel.function("do_brk") { address = $addr length = $len } /** * probe vm.oom_kill - Fires when a thread is selected for termination by the OOM killer. * @task: The task being killed * * Context: * The process that tried to consume excessive memory, and thus * triggered the OOM. */ probe vm.oom_kill = kernel.function("__oom_kill_task") { task = $p } function __gfp_flag_str:string(gfp_flag:long) %{ long gfp_flag = THIS->gfp_flag; THIS->__retvalue[0] = '\0'; /* Older kernels < 2.6.32 didn't have some of these GFP defines yet. */ #ifndef __GFP_MOVABLE #define __GFP_MOVABLE ((__force gfp_t)0x08u) /* Page is movable */ #endif #ifndef GFP_ZONEMASK #define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE) #endif #ifndef __GFP_NOTRACK #ifdef CONFIG_KMEMCHECK #define __GFP_NOTRACK ((__force gfp_t)0x200000u) /* Don't track with kmemcheck */ #else #define __GFP_NOTRACK ((__force gfp_t)0) #endif #endif #ifndef __GFP_THISNODE #define __GFP_THISNODE ((__force gfp_t)0x40000u) #endif #ifndef __GFP_RECLAIMABLE #define __GFP_RECLAIMABLE ((__force gfp_t)0x80000u) #endif #ifndef GFP_TEMPORARY #define GFP_TEMPORARY (__GFP_WAIT | __GFP_IO | __GFP_FS | \ __GFP_RECLAIMABLE) #endif #ifndef GFP_HIGHUSER_MOVABLE #define GFP_HIGHUSER_MOVABLE (__GFP_WAIT | __GFP_IO | __GFP_FS | \ __GFP_HARDWALL | __GFP_HIGHMEM | \ __GFP_MOVABLE) #endif #ifndef GFP_THISNODE #ifdef CONFIG_NUMA #define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY) #else #define GFP_THISNODE ((__force gfp_t)0) #endif #endif /* Macro for GFP Bitmasks. */ /* The resulted GFP_FLAGS may be either single or concatenation of the multiple bitmasks. */ #define __GFP_BITMASKS(FLAG) if(gfp_flag & FLAG) { if(THIS->__retvalue[0] != '\0') \ strlcat(THIS->__retvalue, " | "#FLAG, MAXSTRINGLEN); \ else strlcat(THIS->__retvalue, #FLAG, MAXSTRINGLEN); } /* Macro for Composite Flags. */ /* Each Composite GFP_FLAG is the combination of multiple bitmasks. */ #define __GFP_COMPOSITE_FLAG(FLAG) if(gfp_flag == FLAG) { \ strlcat(THIS->__retvalue, #FLAG, MAXSTRINGLEN); return; } /* Composite GFP FLAGS of the BitMasks. */ __GFP_COMPOSITE_FLAG(GFP_ZONEMASK) __GFP_COMPOSITE_FLAG(GFP_ATOMIC) __GFP_COMPOSITE_FLAG(GFP_NOIO) __GFP_COMPOSITE_FLAG(GFP_NOFS) __GFP_COMPOSITE_FLAG(GFP_KERNEL) __GFP_COMPOSITE_FLAG(GFP_TEMPORARY) __GFP_COMPOSITE_FLAG(GFP_USER) __GFP_COMPOSITE_FLAG(GFP_HIGHUSER) __GFP_COMPOSITE_FLAG(GFP_HIGHUSER_MOVABLE) __GFP_COMPOSITE_FLAG(GFP_THISNODE) __GFP_COMPOSITE_FLAG(GFP_DMA) __GFP_COMPOSITE_FLAG(GFP_DMA32) /* GFP BitMasks */ __GFP_BITMASKS(__GFP_DMA) __GFP_BITMASKS(__GFP_HIGHMEM) __GFP_BITMASKS(__GFP_MOVABLE) __GFP_BITMASKS(__GFP_WAIT) __GFP_BITMASKS(__GFP_HIGH) __GFP_BITMASKS(__GFP_IO) __GFP_BITMASKS(__GFP_FS) __GFP_BITMASKS(__GFP_COLD) __GFP_BITMASKS(__GFP_NOWARN) __GFP_BITMASKS(__GFP_REPEAT) __GFP_BITMASKS(__GFP_NOFAIL) __GFP_BITMASKS(__GFP_COMP) __GFP_BITMASKS(__GFP_ZERO) __GFP_BITMASKS(__GFP_NOMEMALLOC) __GFP_BITMASKS(__GFP_HARDWALL) __GFP_BITMASKS(__GFP_THISNODE) __GFP_BITMASKS(__GFP_RECLAIMABLE) __GFP_BITMASKS(__GFP_NOTRACK) #undef __GFP_BITMASKS #undef __GFP_COMPOSITE_FLAG %} /* The Formal Parameters will be displayed if available, otherwise \ "0" or "unknown" will be displayed */ probe __vm.kmalloc.tp = kernel.trace("kmalloc") { name = "kmalloc" call_site = $call_site caller_function = symname(call_site) bytes_req = $bytes_req bytes_alloc = $bytes_alloc gfp_flags = $gfp_flags gfp_flag_name = __gfp_flag_str($gfp_flags) ptr = $ptr } /* It is unsafe to invoke __builtin_return_address() \ presently(to get call_site for kprobe based probes) \ and that it can be improved later when fix for bugs bz#6961 and bz#6580 is available. */ probe __vm.kmalloc.kp = kernel.function("kmalloc").return { name = "kmalloc" call_site = 0 caller_function = "unknown" bytes_req = $size bytes_alloc = bytes_req // pretend they are always the same gfp_flags = $flags gfp_flag_name = __gfp_flag_str(gfp_flags) ptr = $return } /** * probe vm.kmalloc - Fires when kmalloc is requested. * @call_site: Address of the kmemory function. * @caller_function: Name of the caller function. * @bytes_req: Requested Bytes * @bytes_alloc: Allocated Bytes * @gfp_flags: type of kmemory to allocate * @gfp_flag_name: type of kmemory to allocate (in String format) * @ptr: Pointer to the kmemory allocated */ probe vm.kmalloc = __vm.kmalloc.tp !, __vm.kmalloc.kp {} probe __vm.kmem_cache_alloc.tp = kernel.trace("kmem_cache_alloc") { name = "kmem_cache_alloc" call_site = $call_site caller_function = symname(call_site) bytes_req = $bytes_req bytes_alloc = $bytes_alloc gfp_flags = $gfp_flags gfp_flag_name = __gfp_flag_str($gfp_flags) ptr = $ptr } probe __vm.kmem_cache_alloc.kp = kernel.function("kmem_cache_alloc").return { name = "kmem_cache_alloc" call_site = 0 caller_function = "unknown" bytes_req = $cachep->buffer_size bytes_alloc = bytes_req // pretend they are always the same gfp_flags = $flags gfp_flag_name = __gfp_flag_str(gfp_flags) ptr = $return } /** * probe vm.kmem_cache_alloc - Fires when \ * kmem_cache_alloc is requested. * @call_site: Address of the function calling this kmemory function. * @caller_function: Name of the caller function. * @bytes_req: Requested Bytes * @bytes_alloc: Allocated Bytes * @gfp_flags: type of kmemory to allocate * @gfp_flag_name: Type of kmemory to allocate(in string format) * @ptr: Pointer to the kmemory allocated */ probe vm.kmem_cache_alloc = __vm.kmem_cache_alloc.tp !, __vm.kmem_cache_alloc.kp {} probe __vm.kmalloc_node.tp = kernel.trace("kmalloc_node")? { name = "kmalloc_node" call_site = $call_site caller_function = symname(call_site) bytes_req = $bytes_req bytes_alloc = $bytes_alloc gfp_flags = $gfp_flags gfp_flag_name = __gfp_flag_str($gfp_flags) ptr = $ptr } probe __vm.kmalloc_node.kp = kernel.function("kmalloc_node").return? { name = "kmalloc_node" call_site = 0 caller_function = "unknown" bytes_req = $size bytes_alloc = bytes_req // pretend they are always the same gfp_flags = $flags gfp_flag_name = __gfp_flag_str(gfp_flags) ptr = $return } /** * probe vm.kmalloc_node - Fires when kmalloc_node is requested. * @call_site: Address of the function caling this kmemory function. * @caller_function: Name of the caller function. * @bytes_req: Requested Bytes * @bytes_alloc: Allocated Bytes * @gfp_flags: type of kmemory to allocate * @gfp_flag_name: Type of kmemory to allocate(in string format) * @ptr: Pointer to the kmemory allocated */ probe vm.kmalloc_node = __vm.kmalloc_node.tp !, __vm.kmalloc_node.kp {} probe __vm.kmem_cache_alloc_node.tp = kernel.trace("kmem_cache_alloc_node")? { name = "kmem_cache_alloc_node" call_site = $call_site caller_function = symname(call_site) bytes_req = $bytes_req bytes_alloc = $bytes_alloc gfp_flags = $gfp_flags gfp_flag_name = __gfp_flag_str($gfp_flags) ptr = $ptr } probe __vm.kmem_cache_alloc_node.kp = kernel.function("kmem_cache_alloc_node").return? { name = "kmem_cache_alloc_node" call_site = 0 caller_function = "unknown" bytes_req = $cachep->buffer_size bytes_alloc = bytes_req // pretend they are always the same gfp_flags = $flags gfp_flag_name = __gfp_flag_str(gfp_flags) ptr = $return } /** * probe vm.kmem_cache_alloc_node - Fires when \ * kmem_cache_alloc_node is requested. * @call_site: Address of the function calling this kmemory function. * @caller_function: Name of the caller function. * @bytes_req: Requested Bytes * @bytes_alloc: Allocated Bytes * @gfp_flags: type of kmemory to allocate * @gfp_flag_name: Type of kmemory to allocate(in string format) * @ptr: Pointer to the kmemory allocated */ probe vm.kmem_cache_alloc_node = __vm.kmem_cache_alloc_node.tp !, __vm.kmem_cache_alloc_node.kp {} probe __vm.kfree.tp = kernel.trace("kfree") { name = "kfree" call_site = $call_site caller_function = symname(call_site) ptr = $ptr } probe __vm.kfree.kp = kernel.function("kfree").return { name = "kfree" call_site = 0 caller_function = "unknown" ptr = $objp } /** * probe vm.kfree - Fires when kfree is requested. * @call_site: Address of the function calling this kmemory function. * @caller_function: Name of the caller function. * @ptr: Pointer to the kmemory allocated which is returned by kmalloc */ probe vm.kfree = __vm.kfree.tp !, __vm.kfree.kp {} probe __vm.kmem_cache_free.tp = kernel.trace("kmem_cache_free") { name = "kmem_cache_free" call_site = $call_site caller_function = symname(call_site) ptr = $ptr } probe __vm.kmem_cache_free.kp = kernel.function("kmem_cache_free").return { name = "kmem_cache_free" call_site = 0 caller_function = "unknown" ptr = $objp } /** * probe vm.kmem_cache_free - Fires when \ * kmem_cache_free is requested. * @call_site: Address of the function calling this kmemory function. * @caller_function: Name of the caller function. * @ptr: Pointer to the kmemory allocated which is returned by kmem_cache */ probe vm.kmem_cache_free = __vm.kmem_cache_free.tp !, __vm.kmem_cache_free.kp {}