This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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)));
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]