summaryrefslogtreecommitdiffstats
path: root/testsuite/systemtap.examples/memory
diff options
context:
space:
mode:
Diffstat (limited to 'testsuite/systemtap.examples/memory')
-rwxr-xr-xtestsuite/systemtap.examples/memory/kmalloc-top171
-rw-r--r--testsuite/systemtap.examples/memory/kmalloc-top.meta13
-rw-r--r--testsuite/systemtap.examples/memory/pfaults.meta13
-rw-r--r--testsuite/systemtap.examples/memory/pfaults.stp35
4 files changed, 232 insertions, 0 deletions
diff --git a/testsuite/systemtap.examples/memory/kmalloc-top b/testsuite/systemtap.examples/memory/kmalloc-top
new file mode 100755
index 00000000..ccce0c17
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/kmalloc-top
@@ -0,0 +1,171 @@
+#!/usr/bin/perl
+#
+# This script accumulates the execution paths of all calls to kmalloc
+# in the kernel. On Ctrl-C (or exit of the command provided by -c option),
+# it sorts, filters and displays them on
+# stdout.
+#
+# The -e (exclude) option can be used to specify a comma-separated list
+# - any stack with contents matching any of the items in the list will
+# be excluded from the output.
+#
+# The -m (min) option can be used to specify the minimum number of
+# occurrences a stack needs to be included in the output.
+#
+# The -t (top) option can be used to specify printing only the
+# top N stack traces.
+#
+# The -c (command) option runs starts the command and script
+# only runs for the duration of the command.
+#
+# The -o (options) option passes the options to systemap.
+#
+# Usage: ./kmalloc-top [-m min] [-e exclude list] [-t top_n] [-c command]
+# [-o options]
+# Ctrl-c
+
+use Getopt::Std;
+
+my $kmalloc_stacks;
+my $total_kmallocs;
+my $filtered_kmallocs;
+my $sorted_stacks;
+my $first_n = 1000000000;
+my $min_count = 1;
+my $exclude;
+my $options;
+
+$SIG{INT} = \&sigint_handler;
+
+getopts('c:e:m:t:o:');
+
+if ($opt_e) {
+ $exclude = join('|', split(/,/, $opt_e));
+ print "Will exclude stacks containing: $exclude\n";
+}
+
+if ($opt_t) {
+ $first_n = $opt_t;
+ print "Will print only the top $first_n stacks.\n";
+}
+
+if ($opt_m) {
+ $min_count = $opt_m;
+}
+
+if ($opt_c) {
+ $command="-c \"$opt_c\""
+}
+
+if ($opt_o) {
+ $options=$opt_o
+}
+
+print "Will print stacks with counts >= $min_count.\n";
+print STDERR "Press Ctrl-C to stop.\n";
+
+#The systemtap script that instruments the kmalloc
+$script="
+global kmalloc_stack
+
+probe kernel.function(\"__kmalloc\") { kmalloc_stack[backtrace()]++ }
+
+probe timer.ms(100), end
+{
+ foreach (stack in kmalloc_stack) {
+ printf(\"<hashkey>\\n\")
+ print_stack(stack)
+ printf(\"</hashkey>\\n\")
+ printf(\"<hashval>%d</hashval>\\n\", kmalloc_stack[stack])
+ }
+ delete kmalloc_stack
+}
+";
+
+open STREAM, "stap $options -e '$script' $command|" or die "Couldn't get output stream $!";
+
+while (<STREAM>) {
+ if (/<hashval>(.*?)<\/hashval>/) {
+ update_hash($key, $1);
+ $key = "";
+ } elsif ($_ !~ (/<hashkey>|<\/hashkey>/)) {
+ $key .= $_;
+ }
+}
+
+$num_keys_before_filtering = scalar keys %kmalloc_stacks;
+$total_kmallocs = count_kmallocs();
+filter_stacks();
+sort_stacks();
+top_stacks();
+sort_stacks();
+$num_keys_after_filtering = scalar keys %kmalloc_stacks;
+$filtered_kmallocs = count_kmallocs();
+summarize();
+exit();
+
+sub update_hash
+{
+ my($key, $val) = @_;
+ $kmalloc_stacks{$key} += $val;
+}
+
+sub filter_stacks
+{
+ while (($stack, $count) = each %kmalloc_stacks) {
+ if ($count < $min_count) {
+ delete $kmalloc_stacks{$stack};
+ } elsif ($exclude && $stack =~ /$exclude/) {
+ delete $kmalloc_stacks{$stack};
+ }
+ }
+}
+
+sub top_stacks
+{
+ $count=0;
+ foreach $stack(@sorted_stacks) {
+ $count+=1;
+ if ($count > $first_n) {
+ delete $kmalloc_stacks{$stack};
+ }
+ }
+}
+
+sub sort_stacks
+{
+ @sorted_stacks = sort { $kmalloc_stacks{$b} <=> $kmalloc_stacks{$a} } keys %kmalloc_stacks;
+}
+
+sub count_kmallocs {
+ $count = 0;
+ foreach $stack(%kmalloc_stacks) {
+ $count += $kmalloc_stacks{$stack};
+ }
+ return $count;
+}
+
+sub summarize {
+ print "\n";
+ foreach $stack(@sorted_stacks) {
+ print "This path seen $kmalloc_stacks{$stack} times:\n$stack\n";
+ }
+
+ if ($total_kmallocs > 0) {
+ $percent = ($filtered_kmallocs)*100/$total_kmallocs;
+ } else {
+ $percent = 0;
+ }
+ print "Num stacks before filtering: $num_keys_before_filtering\n";
+ print "Num stacks after filtering: $num_keys_after_filtering\n";
+ print "Total kmallocs (before filtering): $total_kmallocs\n";
+ print "Total kmallocs (after filtering): $filtered_kmallocs\n";
+ print "The filter stacks have $percent of the total kmallocs\n";
+
+ close(STREAM);
+}
+
+sub sigint_handler
+{
+ system("pkill kmalloc-stacks");
+}
diff --git a/testsuite/systemtap.examples/memory/kmalloc-top.meta b/testsuite/systemtap.examples/memory/kmalloc-top.meta
new file mode 100644
index 00000000..93308909
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/kmalloc-top.meta
@@ -0,0 +1,13 @@
+title: Show Paths to Kernel Malloc (kmalloc) Invocations
+name: kmalloc-top
+version: 1.0
+author: anonymous
+keywords: memory
+subsystem: memory
+status: production
+exit: user-controlled
+output: sorted-list
+scope: system-wide
+description: The kmalloc-top perl program runs a small systemtap script to collect stack traces for each call to the kmalloc function and counts the time that each stack trace is observed. When kmalloc-top exits it prints out sorted list. The output can be be filtered to print only only the first stack traces (-t) stack traces with more a minimum counts (-m), or exclude certain stack traces (-e).
+test_check: ./kmalloc-top -o "-p4" -c "sleep 0"
+test_installcheck: ./kmalloc-top -c "sleep 1"
diff --git a/testsuite/systemtap.examples/memory/pfaults.meta b/testsuite/systemtap.examples/memory/pfaults.meta
new file mode 100644
index 00000000..149d83fa
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/pfaults.meta
@@ -0,0 +1,13 @@
+title: Generate Log of Major and Minor Page Faults
+name: pfaults.stp
+version: 1.0
+author: anonymous
+keywords: memory
+subsystem: memory
+status: production
+exit: user-controlled
+output: sorted-list
+scope: system-wide
+description: The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occuring.
+test_check: stap -p4 pfaults.stp
+test_installcheck: stap pfaults.stp -c "sleep 1"
diff --git a/testsuite/systemtap.examples/memory/pfaults.stp b/testsuite/systemtap.examples/memory/pfaults.stp
new file mode 100644
index 00000000..5bf1a8a6
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/pfaults.stp
@@ -0,0 +1,35 @@
+#! /usr/bin/env stap
+
+global fault_entry_time, fault_address, fault_access
+global time_offset
+
+probe begin { time_offset = gettimeofday_us() }
+
+probe vm.pagefault {
+ t = gettimeofday_us()
+ p = pid()
+ fault_entry_time[p] = t
+ fault_address[p] = address
+ fault_access[p] = write_access ? "w" : "r"
+}
+
+probe vm.pagefault.return {
+ t=gettimeofday_us()
+ p = pid()
+ if (!(p in fault_entry_time)) next
+ e = t - fault_entry_time[p]
+ if (vm_fault_contains(fault_type,VM_FAULT_MINOR)) {
+ ftype="minor"
+ } else if (vm_fault_contains(fault_type,VM_FAULT_MAJOR)) {
+ ftype="major"
+ } else {
+ next #only want to deal with minor and major page faults
+ }
+
+ printf("%d:%d:%p:%s:%s:%d\n",
+ t - time_offset, p, fault_address[p], fault_access[p], ftype, e)
+ #free up memory
+ delete fault_entry_time[p]
+ delete fault_address[p]
+ delete fault_access[p]
+}