From 085535d9e4ae0c1d891e51f4f6f42b94f947cfc8 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Tue, 12 Aug 2014 17:48:50 -0400 Subject: [PATCH] tracepoint_onthefly.exp: new testcase This testcase will be useful when tracepoints will support on-the-fly arming. See PR17256. --- .../tracepoint_onthefly.exp | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 testsuite/systemtap.onthefly/tracepoint_onthefly.exp diff --git a/testsuite/systemtap.onthefly/tracepoint_onthefly.exp b/testsuite/systemtap.onthefly/tracepoint_onthefly.exp new file mode 100644 index 000000000..fd19db412 --- /dev/null +++ b/testsuite/systemtap.onthefly/tracepoint_onthefly.exp @@ -0,0 +1,201 @@ +source $srcdir/$subdir/onthefly_common.tcl + +set test "tracepoint_onthefly" +if {![installtest_p]} { + untested "$test" + return +} + +# Goal: Ensure that tracepoints properly support on-the-fly arming/disarming. +# The script consists of a sched_process_fork tracepoint whose condition is +# toggled by a timer probe. We ensure that the tracepoint will always be +# triggered by running 'echo' in a loop in the background. We then analyze the +# actual debug statements printed out to ensure the toggled probe is armed and +# disarmed as expected. + +# Runs stap on a script with the given arguments +proc run_stap {subtest args script} { + global test + + # Start the background echos + set echo_loop "while \[ true \]; do /bin/echo 1>/dev/null; done" + set echo_pid [exec sh -c $echo_loop &] + + # We always need the DEBUG and -g flags + set args "$args -D DEBUG_STP_ON_THE_FLY -g" + + # Run stap and catch any errors (we will rethrow it later) + set err [catch {eval exec stap -e {$script} $args} out] + + # Kill echo + kill -INT $echo_pid 1 + + if {$err} {error $out} + return $out +} + +# Returns a script with some variables replaced. +# SUBTEST name of subtest +# ENABLED set to 1 to start the target probe as enabled, 0 as disabled +# MAXTOGGLES number of times we toggle the target probe condition +# TIMER if a number, then it's the period of the timer probe which +# toggles the target probes, if set to 'profile' then instead a +# timer.profile probe is used to toggle the target probe, if set +# to 'hardcore' then both a timer.profile probe and a +# kernel.trace("*") probe is used for toggling, if set to 'max' +# then a lot of various probe points are used for toggling +proc make_script {SUBTEST ENABLED MAXTOGGLES TIMER} { + global test + + set script { + + global enabled = ENABLED + global toggles = 0 + + # Simplification to ensure 'hit' is only printed once. This makes it + # easier later on to verify the output. + global hit = 0 + + probe kernel.trace("sched_process_fork") if (enabled) { + if (hit) + next + hit = 1 + println("hit") + } + + probe timer.us(TIMER) { + toggles++ + hit = 0 + if (toggles > MAXTOGGLES) + exit() + else { + println("toggling") + enabled = !enabled + } + } + + probe timer.s(360) { + println("timed out") + exit() + } + } + + # Set in values + set script [string map "TEST $test \ + SUBTEST $SUBTEST \ + ENABLED $ENABLED \ + MAXTOGGLES $MAXTOGGLES" $script] + if {[string match $TIMER "profile"]} { + set script [string map "timer.us(TIMER) timer.profile" $script] + } elseif {[string match $TIMER "hardcore"]} { + set script [string map "timer.us(TIMER) \ + {timer.profile, kernel.trace(\"*\")}" $script] + } elseif {[string match $TIMER "max"]} { + set script [string map "timer.us(TIMER) \ + {begin, end, error, kernel.function(\"*@workqueue.c\"), \ + process.begin, process.end, kernel.trace(\"*\"), \ + process(\"echo\").function(\"*\"), \ + netfilter.pf(\"NFPROTO_IPV4\").hook(\"NF_INET_LOCAL_IN\")?, \ + netfilter.pf(\"NFPROTO_IPV4\").hook(\"NF_INET_LOCAL_OUT\")?, \ + perf.sw.cpu_clock.sample(1000000)?, timer.profile.tick?}" $script] + } else { + set script [string map "TIMER $TIMER" $script] + } + + return $script +} + +# Creates the pattern which will be used by the is_valid_output proc to +# determine if the output is valid. In other words, given the initial value of +# enabled, the maximum number of toggles, and whether on-the-fly is turned on or +# not, this proc determines what the output of stap will be. +proc make_pattern {subtest start_enabled maxtoggles} { + set pattern "" + + # If we're not starting as enabled, then the kprobes will be registered as + # disabled. + if {!$start_enabled} { + lappend pattern "* not registering (tracepoint) pidx ?" + } + + # For each toggle: + # - if we were enabled, then we would have had a 'hit' line + # - if i == maxtoggles, then we'll exit so nothing more will be printed + # - if i < maxtoggles, then the timer probe will output 'toggling' followed + # by 'registering' or 'unregistering' lines + for {set i 0} {$i <= $maxtoggles} {incr i} { + if {$start_enabled} { + lappend pattern "hit" + } + if {$i < $maxtoggles} { + lappend pattern "toggling" + if {$start_enabled} { + set start_enabled 0 + lappend pattern "* unregistering (tracepoint) pidx ?" + } else { + set start_enabled 1 + if {$i < $maxtoggles} { + lappend pattern "* registering (tracepoint) pidx ?" + } + } + } + } + + return $pattern +} + +# Various on-the-fly tests + +# Toggle 0, 1, 2, 3, 4, and 5 times. This is important since we test if the +# probes finish well when disabled/enabled. + +run_subtest_valid "otf_finish_at_start_disabled" 0 0 500000 +run_subtest_valid "otf_finish_at_start_enabled" 1 0 500000 +run_subtest_valid "otf_start_disabled_iter_1" 0 1 500000 +run_subtest_valid "otf_start_enabled_iter_1" 1 1 500000 +run_subtest_valid "otf_start_disabled_iter_2" 0 2 500000 +run_subtest_valid "otf_start_enabled_iter_2" 1 2 500000 +run_subtest_valid "otf_start_disabled_iter_3" 0 3 500000 +run_subtest_valid "otf_start_enabled_iter_3" 1 3 500000 +run_subtest_valid "otf_start_disabled_iter_4" 0 4 500000 +run_subtest_valid "otf_start_enabled_iter_4" 1 4 500000 +run_subtest_valid "otf_start_disabled_iter_5" 0 5 500000 +run_subtest_valid "otf_start_enabled_iter_5" 1 5 500000 + +# Small interval tests + +run_subtest_valid "otf_timer_100ms" 1 5 100000 \ + -D STP_ON_THE_FLY_INTERVAL=1000000 +run_subtest_valid "otf_timer_50ms" 1 5 50000 \ + -D STP_ON_THE_FLY_INTERVAL=1000000 +run_subtest_valid "otf_timer_10ms" 1 5 10000 \ + -D STP_ON_THE_FLY_INTERVAL=1000000 + +# NB: if we go any shorter, the kernel might not have a chance to run +# systemtap_module_refresh() before the next toggling occurs, throwing off the +# expected output. + +# Stress tests + +# These tests are not validated, i.e. their outputs are not checked against a +# pattern (see NB above why). Instead, they're just meant to stress the +# on-the-fly mechanism to ensure stap/the kernel doesn't die. So if stap is +# successfully run and terminated, we just default to a pass. + +run_subtest_stress "otf_stress_5ms_iter_50" 1 50 5000 \ + -D STP_ON_THE_FLY_INTERVAL=100000 +run_subtest_stress "otf_stress_1ms_iter_50" 1 50 1000 \ + -D STP_ON_THE_FLY_INTERVAL=100000 +run_subtest_stress "otf_stress_500us_iter_50" 1 50 500 \ + -D STP_ON_THE_FLY_INTERVAL=100000 +run_subtest_stress "otf_stress_100us_iter_50" 1 50 100 \ + -D STP_ON_THE_FLY_INTERVAL=100000 + +run_subtest_stress "otf_stress_prof_iter_2000" 1 2000 profile \ + -D STP_ON_THE_FLY_INTERVAL=100000 + +run_subtest_stress "otf_stress_hard_iter_2000" 1 2000 hardcore \ + -D STP_ON_THE_FLY_INTERVAL=100000 + +run_subtest_stress "otf_stress_max_iter_5000" 1 5000 max \ + -D STP_ON_THE_FLY_INTERVAL=100000 -- 2.43.5