diff options
author | hunt <hunt> | 2006-03-09 08:48:06 +0000 |
---|---|---|
committer | hunt <hunt> | 2006-03-09 08:48:06 +0000 |
commit | 68642a15584f9e4fbf8cfc5765a3cfaeac0a5bbb (patch) | |
tree | 456b5d73292446a4017fcecf5162e5b20be86e95 /runtime/bench2 | |
parent | 43efac911763c31250e953fcd633d7f275d88270 (diff) | |
download | systemtap-steved-68642a15584f9e4fbf8cfc5765a3cfaeac0a5bbb.tar.gz systemtap-steved-68642a15584f9e4fbf8cfc5765a3cfaeac0a5bbb.tar.xz systemtap-steved-68642a15584f9e4fbf8cfc5765a3cfaeac0a5bbb.zip |
2006-03-09 Martin Hunt <hunt@redhat.com>
* bench2: New directory containing a benchmark framework.
Diffstat (limited to 'runtime/bench2')
-rw-r--r-- | runtime/bench2/Makefile | 7 | ||||
-rw-r--r-- | runtime/bench2/README | 26 | ||||
-rw-r--r-- | runtime/bench2/a.st | 13 | ||||
-rw-r--r-- | runtime/bench2/b.st | 16 | ||||
-rw-r--r-- | runtime/bench2/bench.rb | 225 | ||||
-rw-r--r-- | runtime/bench2/itest.c | 59 | ||||
-rw-r--r-- | runtime/bench2/results.txt | 32 | ||||
-rwxr-xr-x | runtime/bench2/run_bench | 40 | ||||
-rwxr-xr-x | runtime/bench2/stap_bench | 16 |
9 files changed, 434 insertions, 0 deletions
diff --git a/runtime/bench2/Makefile b/runtime/bench2/Makefile new file mode 100644 index 00000000..7fcfcfe4 --- /dev/null +++ b/runtime/bench2/Makefile @@ -0,0 +1,7 @@ +all: itest + +itest: itest.c + gcc -Wall -O3 -o itest itest.c + +clean: + /bin/rm -f itest diff --git a/runtime/bench2/README b/runtime/bench2/README new file mode 100644 index 00000000..626d4675 --- /dev/null +++ b/runtime/bench2/README @@ -0,0 +1,26 @@ +This is a framework for profiling systemtap scripts and the +underlying runtime functions. + +To try the tests: +>make +./run_bench +./stap_bench + +You will need ruby installed. "yum install ruby" or "up2date ruby" to get it. + +---- FILES ---- +a.st - sample script test file +b.st - sample script test file + +itest.c - used by tests. Type "make" to build +Makefile - makefile for itest + +run_bench - test driver with some test scripts. Tests may +be supplied in files (as in a.st and b.st) or in strings, as +in this example. + +stap_bench - test driver that tests all files ending in ".st" + +bench.rb - bench classes used by drivers. + +results.txt - Some results of "run_bench" on different machines. diff --git a/runtime/bench2/a.st b/runtime/bench2/a.st new file mode 100644 index 00000000..2efc771f --- /dev/null +++ b/runtime/bench2/a.st @@ -0,0 +1,13 @@ +# printf probefunc + +# You can put initialization in here +probe begin { + printf("BEGIN\n") +} + +# This gets probed millions of times. TEST gets replaces +# by the real probe point. +probe TEST { + printf("%s\n",probefunc()) +} + diff --git a/runtime/bench2/b.st b/runtime/bench2/b.st new file mode 100644 index 00000000..687f1a8f --- /dev/null +++ b/runtime/bench2/b.st @@ -0,0 +1,16 @@ +# printf execname + +# You can put initialization in here +probe begin { + printf("FOO\n") +} + +# This gets probed millions of times. TEST gets replaces +# by the real probe point. +probe TEST { + printf("%s\n", execname()) +} + +probe end { + printf("DONE\n") +} diff --git a/runtime/bench2/bench.rb b/runtime/bench2/bench.rb new file mode 100644 index 00000000..2c21b381 --- /dev/null +++ b/runtime/bench2/bench.rb @@ -0,0 +1,225 @@ +class Bench + def initialize(desc) + @desc = desc + @code = nil + @file = nil + @failures = "" + @results = 0 + if @@printed_header == 0 + print_header + end + if @@ftime == 0 + @@ftime = `./itest 5`.to_i + end + if @@stpd.nil? + for path in ['/usr/libexec/systemtap/stpd', '/usr/local/libexec/systemtap/stpd'] + if File.exist?(path) + @@stpd = path + break + end + end + end + if @@runtime.nil? + for path in ['/usr/share/systemtap/runtime', '/usr/local/share/systemtap/runtime'] + if File.exist?(path) + @@runtime = path + break + end + end + end + end + + attr_writer :code, :file + attr_reader :failures, :results + + def run + Signal.trap("INT") do + cleanup + exit + end + compile + load + @results = `./itest 1`.to_i - @@ftime + sleep 5 + `sudo killall -HUP stpd` + `tail #{@dir}/xxx > #{@dir}/xxx.out` + File.open("#{@dir}/xxx.out") do |file| + file.each_line {|line| @failures += line if line =~ /WARNING/} + end + Process.wait + cleanup + end + + def print + if @results + printf("runtime: %-20s\t%d\n", @desc, @results) + end + end + + private + @dir = nil + + protected + + # function call overhead + @@ftime = 0 + @@printed_header = 0 + @@stpd = nil + @@runtime = nil + + def cleanup + `/bin/rm -f stap.out` if File.exists?("stap.out") + `/bin/rm -f bench.stp` if File.exists?("bench.stp") + `/bin/rm -rf #{@dir}` unless @dir.nil? + end + + def load + fork do exec "sudo #{@@stpd} -rmq #{@dir}/bench.ko > #{@dir}/xxx" end + sleep 5 + end + + def compile + @dir = `mktemp -dt benchXXXXX`.strip + emit_code + modules = "/lib/modules/" + `uname -r`.strip + "/build" + res=`make -C \"#{modules}\" M=\"#{@dir}\" modules V=1` + if !File.exist?("#{@dir}/bench.ko") + puts res + cleanup + exit + end + end + + def emit_code + if @code + begin + f = File.new("#{@dir}/bench.c","w") + f << "#include \"runtime.h\" +#include \"probes.c\"\n +MODULE_DESCRIPTION(\"SystemTap probe: bench\"); +MODULE_AUTHOR(\"automatically generated by bench2/run_bench\");\n\n" + f << "static int inst_sys_getuid (struct kprobe *p, struct pt_regs *regs) {\n" + f << @code + f << "\n return 0;\n} +static struct kprobe kp[] = {\n {\n .addr = \"sys_getuid\", + .pre_handler = inst_sys_getuid\n }\n};\n +#define NUM_KPROBES 1\n +int probe_start(void)\n{\n return _stp_register_kprobes (kp, NUM_KPROBES);\n}\n +void probe_exit (void)\n{\n _stp_unregister_kprobes (kp, NUM_KPROBES); \n}\n" + rescue + puts "Error writing source file" + ensure + f.close unless f.nil? + end + makefile = File.new("#{@dir}/Makefile","w") + makefile << "CFLAGS += -Wno-unused -Werror +CFLAGS += -I \"#{@@runtime}\" +obj-m := bench.o +" + makefile.close + else + puts "NO CODE!" + end + end + + def print_header + @@printed_header = 1 + nproc=`grep ^processor /proc/cpuinfo`.count("\n") + physical_cpus=`grep "physical id" /proc/cpuinfo`.split("\n").uniq.length + model=`grep "model name" /proc/cpuinfo`.match(/(model name\t: )([^\n]*)/)[2] + puts "SystemTap BENCH2 \t" + `date` + puts "kernel: " + `uname -r`.strip + " " + `uname -m`.strip + begin + puts IO.read("/etc/redhat-release") + rescue + end + + puts `uname -n`.strip + ": " + `uptime` + if nproc > 1 + puts "processors: #{nproc} (#{physical_cpus} physical) #{model}" + else + puts "processors: #{nproc} #{model}" + end + + begin + mem=IO.read("/proc/meminfo").split("\n") + puts mem[0] + "\t" + mem[1] + rescue + end + puts "-"*64 + check_cpuspeed + @@ftime = `./itest 5`.to_i + puts "For comparison, function call overhead is #@@ftime nsecs." + puts "Times below are in nanoseconds and include kprobe overhead." + puts "-"*64 + end + + def check_cpuspeed + maxfile = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" + minfile = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq" + if File.exist?(maxfile) + maxfreq = `cat #{maxfile}`.to_i + minfreq = `cat #{minfile}`.to_i + if minfreq != maxfreq + `sudo /bin/sh -c \"echo #{maxfreq} > #{minfile}\"` + puts "CPU frequency scaling detected and disabled." + puts "After testing, enable it again by typing (as root)" + puts "echo #{minfreq} > #{minfile}" + puts "-"*64 + end + end + end +end + +class Stapbench < Bench + def print + if @results + printf("script : %-20s\t%d\n", @desc, @results) + end + end + + protected + + def load + # we do this in several steps because the compilation phase can take a long time + `stap -kvvp4 -m bench bench.stp &> stap.out` + IO.foreach("stap.out") {|line| @dir = line if line =~ /Created temporary directory/} + @dir = @dir.match(/"([^"]*)/)[1] + if !File.exist?("#{@dir}/bench.ko") + puts `cat stap.out` + cleanup + exit + end + fork do exec "sudo #{@@stpd} -rmq #{@dir}/bench.ko > #{@dir}/xxx" end + sleep 5 + end + + def compile + emit_code + end + + def emit_code + if @file + File.open("bench.stp","w") do |b| + File.open(@file,"r") do |f| + f.each_line do |line| + b.puts(line.sub(/TEST/,'kernel.function("sys_getuid")')) + end + end + end + elsif @code + begin + f = File.new("bench.stp","w") + f << "probe kernel.function(\"sys_getuid\") {\n" + f << @code + f << "\n}\n" + rescue + puts "Error writing source file" + ensure + f.close unless f.nil? + end + else + puts "NO CODE!" + end + end +end diff --git a/runtime/bench2/itest.c b/runtime/bench2/itest.c new file mode 100644 index 00000000..dc385567 --- /dev/null +++ b/runtime/bench2/itest.c @@ -0,0 +1,59 @@ +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/time.h> +#include <stdlib.h> +#include <sys/resource.h> +#include <unistd.h> + +typedef unsigned long long uint64; +struct timeval tstart, tstop; + +void start() +{ + gettimeofday (&tstart, NULL); +} + +uint64 usecs (struct timeval *tv) +{ + return tv->tv_sec * 1000000 + tv->tv_usec; +} + +uint64 stop() +{ + gettimeofday (&tstop, NULL); + return usecs(&tstop) - usecs(&tstart); +} + +void usage(char *name) +{ + printf ("Usage %s [time]\nWhere \"time\" is millions of times to loop.\n", name); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int i, n = 1; + uint64 nsecs; + + if (argc > 2) + usage(argv[0]); + + if (argc == 2) { + n = strtol(argv[1], NULL, 10); + if (n == 0) + usage(argv[0]); + } + + + start(); + for (i = 0; i < n * 1000000; i++) + getuid(); + + nsecs = stop() / (n * 1000); + + /* returns nanosecs per call */ + printf("%lld\n", nsecs); + return 0; +} diff --git a/runtime/bench2/results.txt b/runtime/bench2/results.txt new file mode 100644 index 00000000..a58f45dd --- /dev/null +++ b/runtime/bench2/results.txt @@ -0,0 +1,32 @@ +SystemTap BENCH2 Thu Mar 9 00:24:53 PST 2006 +kernel: 2.6.15-1.2025_FC5 i686 +Fedora Core release 4.92 (Pre-FC5) +monkey2: 00:24:53 up 2:48, 3 users, load average: 0.01, 0.05, 0.01 +processors: 1 Intel(R) Pentium(R) M processor 1.70GHz +MemTotal: 515200 kB MemFree: 73264 kB +---------------------------------------------------------------- +For comparison, function call overhead is 378 nsecs. +Times below are in nanoseconds and include kprobe overhead. +---------------------------------------------------------------- +runtime: empty probe 514 +script : empty probe 543 +runtime: printf 100 chars 1932 +script : printf 100 chars 1947 +runtime: printf 5 integers 3078 +script : printf 5 integers 3127 +SystemTap BENCH2 Thu Mar 9 00:30:12 PST 2006 +kernel: 2.6.15-1.1830_FC4.huntsmp i686 +Fedora Core release 4 (Stentz) +dragon: 00:30:12 up 3:02, 3 users, load average: 0.00, 0.00, 0.00 +processors: 2 (1 physical) Intel(R) Pentium(R) 4 CPU 2.60GHz +MemTotal: 2067716 kB MemFree: 1841188 kB +---------------------------------------------------------------- +For comparison, function call overhead is 795 nsecs. +Times below are in nanoseconds and include kprobe overhead. +---------------------------------------------------------------- +runtime: empty probe 1178 +script : empty probe 1372 +runtime: printf 100 chars 2408 +script : printf 100 chars 2504 +runtime: printf 5 integers 4048 +script : printf 5 integers 3590 diff --git a/runtime/bench2/run_bench b/runtime/bench2/run_bench new file mode 100755 index 00000000..1f868ced --- /dev/null +++ b/runtime/bench2/run_bench @@ -0,0 +1,40 @@ +#!/usr/bin/env ruby +load './bench.rb' + +# runtime test with empty kprobe +test = Bench.new("empty probe") +test.code = "" +test.run +test.print + +# script test with empty probe +test0 = Stapbench.new("empty probe") +test0.code = "" +test0.run +test0.print + +# runtime test to print 100 chars +test2 = Bench.new("printf 100 chars") +test2.code = "_stp_printf (\"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\\n\"); + _stp_print_flush();" +test2.run +test2.print + +# script test to print 100 chars +test2a = Stapbench.new("printf 100 chars") +test2a.code = "printf(\"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\\n\")" +test2a.run +test2a.print + +# runtime test to print 5 integers +test3 = Bench.new("printf 5 integers") +test3.code = "_stp_printf (\"%lld, %lld, %lld, %lld, %lld\\n\", 1LL, 0xffffLL, 0x8000ffffLL, 0xffff000011112222LL, 0x7000000000000000LL); + _stp_print_flush();" +test3.run +test3.print + +# script test to print 5 integers +test4 = Stapbench.new("printf 5 integers") +test4.code = "printf(\"%d, %d, %d, %d, %d\\n\", 1, 0xffff, 0x8000ffff, 0xffff000011112222, 0x7000000000000000)" +test4.run +test4.print diff --git a/runtime/bench2/stap_bench b/runtime/bench2/stap_bench new file mode 100755 index 00000000..b3b450d8 --- /dev/null +++ b/runtime/bench2/stap_bench @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +load './bench.rb' + +# run tests on all the files ending in ".st" +# These must be systemtap scripts. +# First line of scripts must be a comment with the test description. + +Dir["*.st"].each do |file| + File.open(file,"r") do |f| + desc = f.gets.sub(/^#/,'').strip + test = Stapbench.new(desc) + test.file = file + test.run + test.print + end +end |