]> sourceware.org Git - systemtap.git/commitdiff
PR16665: new tapset for task resource limit queries + demo script
authorRobin Hack <rhack@redhat.com>
Fri, 28 Mar 2014 15:52:10 +0000 (11:52 -0400)
committerFrank Ch. Eigler <fche@redhat.com>
Fri, 28 Mar 2014 16:02:46 +0000 (12:02 -0400)
* tapset/linux/rlimit.stp, task.stp: New function task_rlimit() and
  assistants.
* testsuite/systemtap.examples/process/rlimit_nofile.*: New sample.

doc/SystemTap_Tapset_Reference/tapsets.tmpl
tapset/linux/rlimit.stp [new file with mode: 0644]
tapset/linux/task.stp
testsuite/buildok/task_rlimit_test.stp [new file with mode: 0755]
testsuite/systemtap.examples/process/rlimit_nofile.meta [new file with mode: 0644]
testsuite/systemtap.examples/process/rlimit_nofile.stp [new file with mode: 0755]

index 27b16909e29e864a1b956d0830c0f6e8f0574124..ca65bb44df957f0bda170d2a32c6e02cde9fff34 100644 (file)
       It contains the following functions:
     </para>
 !Itapset/errno.stp
+  </chapter>
+  <chapter id="rlimit.stp">
+    <title>RLIMIT Tapset</title>
+    <para>
+      This set of functions is used to handle string which defines resource limits (RLIMIT_*) and returns
+      corresponding number of resource limit.
+      It contains the following functions:
+    </para>
+!Itapset/rlimit.stp
   </chapter>
   <chapter id="dev.stp">
     <title>Device Tapset</title>
diff --git a/tapset/linux/rlimit.stp b/tapset/linux/rlimit.stp
new file mode 100644 (file)
index 0000000..10b38b2
--- /dev/null
@@ -0,0 +1,55 @@
+%{
+#include <linux/version.h>
+%}
+
+/**
+ * sfunction rlimit_from_str - Symbolic string associated with resource limit code
+ *
+ * @lim_str: The string representation of limit
+ *
+ * Description: This function returns the number associated
+ * with the given string, such as 0 for the string RLIMIT_CPU, or
+ * -1 for an out-of-range value.
+ */
+function rlimit_from_str:long (lim_str:string)
+%{ /* pure */
+    char *lim_str = (char *)(long)STAP_ARG_lim_str;
+
+#define aux_rlimit(limit_arg) \
+    if (strncmp(lim_str, #limit_arg, MAXSTRINGLEN) == 0) { \
+        STAP_RETVALUE = limit_arg; \
+        return; \
+    }
+
+    /* Little kernel history digging */
+    /* This set is stable from 2.6.1 kernel version */
+    aux_rlimit(RLIMIT_CPU);
+    aux_rlimit(RLIMIT_FSIZE);
+    aux_rlimit(RLIMIT_DATA);
+    aux_rlimit(RLIMIT_STACK);
+    aux_rlimit(RLIMIT_CORE);
+    aux_rlimit(RLIMIT_RSS);
+    aux_rlimit(RLIMIT_NPROC);
+    aux_rlimit(RLIMIT_NOFILE);
+    aux_rlimit(RLIMIT_MEMLOCK);
+    aux_rlimit(RLIMIT_AS);
+    aux_rlimit(RLIMIT_LOCKS);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
+    aux_rlimit(RLIMIT_SIGPENDING);
+    aux_rlimit(RLIMIT_MSGQUEUE);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+    aux_rlimit(RLIMIT_NICE);
+    aux_rlimit(RLIMIT_RTPRIO);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+    aux_rlimit(RLIMIT_RTTIME);
+#endif
+
+    STAP_RETVALUE = -1;
+
+#undef aux_rlimit
+%}
index be859871879974c73bffe024c2189e25bb2796f2..f317e27554b501dde6b22d19e1783a096e28f3ed 100644 (file)
@@ -32,6 +32,134 @@ function task_current:long () %{ /* pure */
     STAP_RETVALUE = (long)current;
 %}
 
+function _task_rlimit_cur:long (task:long, nd_limit:long)
+{
+    if (nd_limit < 0 || nd_limit >= %{ RLIM_NLIMITS %}) {
+        return -1;
+    }
+    sig = @cast(task, "task_struct", "kernel<linux/sched.h>")->signal;
+    rlimit = @cast(sig, "signal_struct", "kernel<linux/sched.h>")->rlim;
+    return @cast(rlimit, "rlimit", "kernel<linux/sched.h>")[nd_limit]->rlim_cur;
+}
+
+/* sfunction task_rlimit - The current resource limit of the tash
+ *
+ * @task: task_struct pointer
+ * @lim_str: String representing limit.
+ *
+ * Description: Little bit slower way how ger resource limits of
+ * process.
+ * There is need translate string into number for each call.
+ */
+function task_rlimit:long (task:long, lim_str:string)
+{
+    lim = rlimit_from_str(lim_str);
+    if (lim == -1) { return -1; }
+    return _task_rlimit_cur(task, lim);
+}
+
+/* Fast and "safe" way how to do it. */
+
+function task_rlimit_cpu:long (task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_CPU %} );
+}
+
+function task_rlimit_fsize:long (task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_FSIZE %});
+}
+
+function task_rlimit_data:long (task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_DATA %});
+}
+
+function task_rlimit_stack:long (task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_STACK %});
+}
+
+function task_rlimit_core:long (task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_CORE %});
+}
+
+function task_rlimit_rss:long (task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_RSS %});
+}
+
+function task_rlimit_nproc:long (task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_NPROC %});
+}
+
+function task_rlimit_nofile:long(task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_NOFILE %});
+}
+
+function task_rlimit_memlock:long(task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_MEMLOCK %});
+}
+
+function task_rlimit_as:long(task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_AS %});
+}
+
+function task_rlimit_locks:long(task:long)
+{
+    return _task_rlimit_cur(task, %{ RLIMIT_LOCKS %});
+}
+
+function task_rlimit_sigpending:long(task:long)
+{
+    %( kernel_v >= "2.6.8" %?
+        return _task_rlimit_cur(task, %{ RLIMIT_SIGPENDING %});
+    %:
+        return -1
+    %)
+}
+
+function task_rlimit_msgqueue:long(task:long)
+{
+    %( kernel_v >= "2.6.8" %?
+        return _task_rlimit_cur(task, %{ RLIMIT_MSGQUEUE %});
+    %:
+        return -1
+    %)
+}
+
+function task_rlimit_nice:long(task:long)
+{
+    %( kernel_v >= "2.6.12" %?
+        return _task_rlimit_cur(task, %{ RLIMIT_NICE %});
+    %:
+        return -1
+    %)
+}
+
+function task_rlimit_rtprio:long(task:long)
+{
+    %( kernel_v >= "2.6.12" %?
+        return _task_rlimit_cur(task, %{ RLIMIT_RTPRIO %});
+    %:
+        return -1
+    %)
+}
+
+function task_rlimit_rttime:long(task:long)
+{
+    %( kernel_v >= "2.6.25" %?
+        return _task_rlimit_cur(task, %{ RLIMIT_RTTIME %});
+    %:
+        return -1
+    %)
+}
+
 /**
  * sfunction task_parent - The task_struct of the parent task
  *
diff --git a/testsuite/buildok/task_rlimit_test.stp b/testsuite/buildok/task_rlimit_test.stp
new file mode 100755 (executable)
index 0000000..df48e54
--- /dev/null
@@ -0,0 +1,20 @@
+probe begin
+{
+    print (task_rlimit_cpu(0) +
+            task_rlimit_fsize(0) +
+            task_rlimit_data(0) +
+            task_rlimit_stack(0) +
+            task_rlimit_core(0) +
+            task_rlimit_rss(0) +
+            task_rlimit_nproc(0) +
+            task_rlimit_nofile(0) +
+            task_rlimit_memlock(0) +
+            task_rlimit_as(0) +
+            task_rlimit_locks(0) +
+            task_rlimit_sigpending(0) +
+            task_rlimit_msgqueue(0) +
+            task_rlimit_nice(0) +
+            task_rlimit_rtprio(0) +
+            task_rlimit_rttime(0) +
+            rlimit_from_str(""));
+}
diff --git a/testsuite/systemtap.examples/process/rlimit_nofile.meta b/testsuite/systemtap.examples/process/rlimit_nofile.meta
new file mode 100644 (file)
index 0000000..cb20ee5
--- /dev/null
@@ -0,0 +1,7 @@
+title: Trace processes running out of file descriptors 
+name: rlimit_nofile.stp
+keywords: limits
+subsystem: process
+description: This script watches processes being scheduled and which try to allocate a file descriptor without luck.
+test_check: stap -p4 rlimit_nofile.stp
+test_installcheck: stap rlimit_nofile.stp -c "sleep 0.2"
diff --git a/testsuite/systemtap.examples/process/rlimit_nofile.stp b/testsuite/systemtap.examples/process/rlimit_nofile.stp
new file mode 100755 (executable)
index 0000000..3a18d5d
--- /dev/null
@@ -0,0 +1,38 @@
+############################################################
+# rlimit_nofile.stp
+# Author: Robin Hack <rhack@redhat.com>
+# This script watches processes being scheduled and which
+# try to allocate a file descriptor without luck.
+############################################################
+
+global failed_calls
+
+probe kernel.trace("sched_wakeup")
+{
+    pid = task_pid($p);
+    name = task_execname($p);
+    open_ds = task_open_file_handles($p);
+    max_ds = task_rlimit_nofile($p);
+    if (failed_calls[name, pid] == "EMFILE") {
+        printf ("%s %s(%d) open: %d - max: %d Hit: %s\n",
+                ctime(gettimeofday_s()), name, pid, open_ds, max_ds,
+                failed_calls[name, pid]);
+    }
+}
+
+probe kernel.trace("sched_process_exit")
+{
+    pid = task_pid($p);
+    name = task_execname($p);
+    delete failed_calls[name, pid];
+}
+
+# This is exactly point where all the fun happens
+# This function returns only EMFILE errno.
+probe kernel.function("__alloc_fd@fs/file.c").return
+{
+    if (errno_str($return) == "EMFILE")
+    {
+        failed_calls[execname(), pid()] = errno_str($return);
+    }
+}
This page took 0.038612 seconds and 5 git commands to generate.