This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
Re: Fwd: proc_mem modification to allow use in timer probes
Hi Charley,
On Wed, 2010-02-10 at 14:38 -0500, Charley Wang wrote:
> When I attempt to use proc_mem functions in their current form I seem to
> sometimes pick up the memory usage of processes I'm not interested in:
> http://chwang.fedorapeople.org/systemtap-proc_mem-without-setup.png
>
> Probably it would be better to try and get the 'current' for a target pid
> than to store mm_struct like this... I'd be happy to investigate further
> and post a bug, if you like.
Attached is a patch that adds proc_mem function variants that take a
task (as returned by one of the task.stp tapset functions). That should
give you the option to feed it any pid/task you are interested in. e.g.
to monitor firefox as target process:
$ stap -e 'probe timer.s(3)
{ log(proc_mem_string_task(pid2task(target()))) }' \
-x `pidof firefox`
size: 1.10G, rss: 473M, shr: 26.2M, txt: 88.0K, data: 649M
size: 1.23G, rss: 534M, shr: 27.1M, txt: 88.0K, data: 701M
size: 1.26G, rss: 534M, shr: 27.4M, txt: 88.0K, data: 727M
size: 1.25G, rss: 523M, shr: 27.4M, txt: 88.0K, data: 724M
size: 1.25G, rss: 526M, shr: 27.4M, txt: 88.0K, data: 724M
Note that you have to be sure that the task really exists otherwise the
@cast or kread() functions will happily ERROR out and abort your
scripts.
I made the new functions /* pure */, since they return the same value
when called from the same context, but not /* unprivileged */ since they
could "leak" information about processes you don't own. Although it
seems /proc/<anypid>/statm is readable for anybody, so maybe they could
be marked unprivileged? I would be slightly concerned that @cast/kread()
could be fed an arbitrary address, that happens to look like a task
struct, but in reality isn't and so would provide an information leak.
But that would be the case for any ordinary @cast() I guess. Opinions?
Cheers,
Mark
diff --git a/tapset/proc_mem.stp b/tapset/proc_mem.stp
index 7641ffe..f413ec8 100644
--- a/tapset/proc_mem.stp
+++ b/tapset/proc_mem.stp
@@ -32,6 +32,28 @@
}
%}
+function _stp_get_mm_counter_file_rss:long(mm:long)
+%{ /* pure */
+ struct mm_struct *mm = (struct mm_struct *)(long)THIS->mm;
+#if USE_SPLIT_PTLOCKS
+ THIS->__retvalue = (unsigned long) kread(&(mm->_file_rss.counter));
+#else
+ THIS->__retvalue = (unsigned long) kread(&(mm->_file_rss));
+#endif
+CATCH_DEREF_FAULT();
+%}
+
+function _stp_get_mm_counter_anon_rss(mm:long)
+%{ /* pure */
+ struct mm_struct *mm = (struct mm_struct *)(long)THIS->mm;
+#if USE_SPLIT_PTLOCKS
+ THIS->__retvalue = (unsigned long) kread(&(mm->_anon_rss.counter));
+#else
+ THIS->__retvalue = (unsigned long) kread(&(mm->_anon_rss));
+#endif
+CATCH_DEREF_FAULT();
+%}
+
/**
* sfunction proc_mem_size - Total program virtual memory size in pages.
*
@@ -48,6 +70,11 @@ function proc_mem_size:long ()
THIS->__retvalue = 0;
%}
+function proc_mem_size_task:long (task:long)
+{
+ return @cast(task, "task_struct", "kernel<linux/sched.h>")->mm->total_vm;
+}
+
/**
* sfunction proc_mem_rss - Program resident set size in pages.
*
@@ -65,6 +92,13 @@ function proc_mem_rss:long ()
THIS->__retvalue = 0;
%}
+function proc_mem_rss_task:long (task:long)
+{
+ mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm;
+ return (_stp_get_mm_counter_file_rss (mm)
+ + _stp_get_mm_counter_anon_rss (mm));
+}
+
/**
* sfunction proc_mem_shr - Program shared pages (from shared mappings).
*
@@ -81,6 +115,12 @@ function proc_mem_shr:long ()
THIS->__retvalue = 0;
%}
+function proc_mem_shr_task:long (task:long)
+{
+ mm = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm;
+ return _stp_get_mm_counter_file_rss (mm);
+}
+
/**
* sfunction proc_mem_txt - Program text (code) size in pages.
*
@@ -98,6 +138,21 @@ function proc_mem_txt:long ()
THIS->__retvalue = 0;
%}
+function _stp_mem_txt_adjust:long (start_code:long, end_code:long)
+%{ /* pure */
+ unsigned long start_code = (unsigned long) THIS->start_code;
+ unsigned long end_code = (unsigned long) THIS->end_code;
+ THIS->__retvalue = (PAGE_ALIGN(end_code)
+ - (start_code & PAGE_MASK)) >> PAGE_SHIFT;
+%}
+
+function proc_mem_txt_task:long (task:long)
+{
+ start = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm->start_code;
+ end = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm->end_code;
+ return _stp_mem_txt_adjust (start, end);
+}
+
/**
* sfunction proc_mem_data - Program data size (data + stack) in pages.
*
@@ -114,6 +169,13 @@ function proc_mem_data:long ()
THIS->__retvalue = 0;
%}
+function proc_mem_data_task:long (task:long)
+{
+ total = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm->total_vm;
+ shared = @cast(task, "task_struct", "kernel<linux/sched.h>")->mm->shared_vm;
+ return total - shared;
+}
+
/**
* sfunction mem_page_size - Number of bytes in a page for this architecture.
*/
@@ -194,3 +256,13 @@ function proc_mem_string:string ()
pages_to_string(proc_mem_txt()),
pages_to_string(proc_mem_data()));
}
+
+function proc_mem_string_task:string (task:long)
+{
+ return sprintf ("size: %s, rss: %s, shr: %s, txt: %s, data: %s",
+ pages_to_string(proc_mem_size_task(task)),
+ pages_to_string(proc_mem_rss_task(task)),
+ pages_to_string(proc_mem_shr_task(task)),
+ pages_to_string(proc_mem_txt_task(task)),
+ pages_to_string(proc_mem_data_task(task)));
+}