# Profiler tests. -*- tcl -*- # # Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1998-2000 by Ajuba Solutions. # All rights reserved. # ------------------------------------------------------------------------- source [file join \ [file dirname [file dirname [file join [pwd] [info script]]]] \ devtools testutilities.tcl] testsNeedTcl 8.3 testsNeedTcltest 1.0 testing { useLocal profiler.tcl profiler } proc do {script} { set c [interp create] interp alias $c parentSet {} set $c eval [list source [localPath profiler.tcl]] $c eval profiler::init set result [$c eval $script] interp delete $c set result } # ------------------------------------------------------------------------- test profiler-1.0 {profiler::init redirects the proc command} { do { list [interp alias {} proc] [info commands ::_oldProc] } } [list ::profiler::profProc ::_oldProc] test profiler-2.0 {profiler creates two wrapper proc and real proc} tcl8.3only { do { proc foo {} { puts "foo!" } list [info commands foo] [info commands fooORIG] } } [list foo fooORIG] test profiler-2.1 {profiler creates procs in correct scope} tcl8.3only { do { namespace eval foo {} proc ::foo::foo {} { puts "foo!" } list [info commands ::foo::foo] [info commands ::foo::fooORIG] } } [list ::foo::foo ::foo::fooORIG] test profiler-2.2 {profiler creates procs in correct scope} {tcl8.3only} { do { namespace eval foo { proc foo {} { puts "foo!" } } list [info commands ::foo::foo] [info commands ::foo::fooORIG] } } [list ::foo::foo ::foo::fooORIG] test profiler-2.3 {profiler creates procs in correct scope} {tcl8.3only} { do { namespace eval foo { namespace eval bar {} proc bar::foo {} { puts "foo!" } } list [info commands ::foo::bar::foo] [info commands ::foo::bar::fooORIG] } } [list ::foo::bar::foo ::foo::bar::fooORIG] test profiler-2.4 {profiler creates procs in correct scope} {tcl8.3only} { do { namespace eval foo { proc ::foo {} { puts "foo!" } } list [info commands ::foo] [info commands ::fooORIG] } } [list ::foo ::fooORIG] test profiler-3.1 {profiler wrappers do profiling} { array set bar [do { proc ::foo {} { set foobar 0 } foo foo foo foo profiler::dump ::foo }] array set foo $bar(::foo) set result [list callCount $foo(callCount) callerDist $foo(callerDist)] unset foo bar set result } [list callCount 4 callerDist [list GLOBAL 4]] test profiler::leaveHandler::initialize_descendent_time {} { # Verify that the profiler tracks descendent time correctly. We'll make # a simple call tree, foo -> bar, then invoke foo, then check the profiler # stats to see that _some_ descendent time has been logged for the call # to bar. We won't be able to predict exactly how much time will get # billed there, but it should be non-zero. array set stats [lindex [do { proc ::foo {} { ::bar } proc ::bar {} { after 300 } foo profiler::dump ::foo }] 1] list descendantTime [expr {$stats(descendantTime) > 0}] } {descendantTime 1} test profiler::leaveHandler::increment_descendent_time {} { # Verify that the profiler increments descendent time each time a # a descendent is invoked. We'll make a simple call tree, foo -> bar, then # invoke foo, check the descendent time for foo, then invoke foo again and # check the descendent time again. It should have been incremented after # the second call. do { proc ::foo {} { ::bar } proc ::bar {} { after 300 } foo array set stats [lindex [profiler::dump ::foo] 1] set before $stats(descendantTime) foo array set stats [lindex [profiler::dump ::foo] 1] set after $stats(descendantTime) list \ before [expr {$before - $before}] \ after [expr {($after - $before) > 0}] } } {before 0 after 1} test profiler-4.1 {profiler::print produces nicer output than dump} { set result [do { proc ::foo {} { set foobar 0 } foo foo foo foo profiler::print ::foo }] regsub {Compile time:.*} $result {} result string trim $result } [tcltest::viewFile [asset 4.1]] test profiler-5.1 {profiler respects suspend/resume} { set result [do { proc ::foo {} { set foobar 0 } foo foo foo foo profiler::suspend ::foo ; # note the qualification, has to match proc! foo foo set res [profiler::print ::foo] profiler::resume set res }] regsub {Compile time:.*} $result {} result string trim $result } [tcltest::viewFile [asset 5.1]] test profiler-5.2 {profiler respects new-disabled/enabled} { set result [do { profiler::new-disabled proc ::bar {} { set foobar 0 } profiler::new-enabled proc ::foo {} { set foobar 0 } #--- foo bar profiler::resume bar #--- set res [profiler::print ::foo] regsub {Compile time:.*} $res {} res set res [string trim $res] append res \n\n [profiler::print ::bar] regsub {Compile time:.*} $res {} res set res }] string trim $result } [tcltest::viewFile [asset 5.2]] test profiler-6.1 {profiler handles functions with funny names} { array set bar [do { proc ::foo(bar) {} { set foobar 0 } foo(bar); foo(bar); foo(bar) profiler::dump ::foo(bar) }] array set foo ${bar(::foo(bar))} set result [list callCount $foo(callCount) callerDist $foo(callerDist)] unset foo bar set result } [list callCount 3 callerDist [list GLOBAL 3]] test profiler-7.1 {sortFunctions} { do { catch {profiler::sortFunctions} res set res } } "unknown statistic \"\": should be calls, compileTime, exclusiveRuntime,\ nonCompileTime, totalRuntime, avgExclusiveRuntime, or avgRuntime" test profiler-7.2 {sortFunctions} tcl8.4only { do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; profiler::sortFunctions calls } } [list [list ::bar 1] [list ::foo 2]] test profiler-7.2-85 {sortFunctions} tcl8.5only { do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; profiler::sortFunctions calls } } [list [list ::tcl::clock::scan 0] [list ::tcl::clock::format 0] [list ::tcl::clock::add 0] [list ::bar 1] [list ::foo 2]] test profiler-7.2-86 {sortFunctions} tcl8.6plus { do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; profiler::sortFunctions calls } } [list [list ::bar 1] [list ::foo 2]] test profiler-7.3 {sortFunctions} { do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; catch {profiler::sortFunctions compileTime} } } 0 test profiler-7.4 {sortFunctions} { do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; catch {profiler::sortFunctions totalRuntime} } } 0 test profiler-7.5 {sortFunctions} { do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; catch {profiler::sortFunctions avgRuntime} } } 0 test profiler-8.1 {reset} { array set bar [do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; profiler::reset profiler::dump ::foo }] array set foo $bar(::foo) set result [list callCount $foo(callCount) callerDist $foo(callerDist)] unset foo bar set result } [list callCount 0 callerDist [list ]] test profiler-8.2 {reset with a pattern} { array set data [do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; profiler::reset ::foo profiler::dump * }] array set foo $data(::foo) array set bar $data(::bar) set result [list \ [list callCount $foo(callCount) callerDist $foo(callerDist)] \ [list callCount $bar(callCount) callerDist $bar(callerDist)]] unset foo bar data set result } [list \ [list callCount 0 callerDist [list ]] \ [list callCount 1 callerDist [list GLOBAL 1]]] test profiler-9.1 {dump for multiple functions} { array set data [do { proc ::foo {} { set foobar 0 } proc ::bar {} { set foobar 1 } foo; foo; bar; profiler::dump * }] array set foo $data(::foo) array set bar $data(::bar) set result [list \ [list callCount $foo(callCount) callerDist $foo(callerDist)] \ [list callCount $bar(callCount) callerDist $bar(callerDist)]] unset foo bar data set result } [list \ [list callCount 2 callerDist [list GLOBAL 2]] \ [list callCount 1 callerDist [list GLOBAL 1]]] test profiler-10.0-tkt-0dd4b31bb8 {result of leave handler} { join [do { set trace {} # proc echo args { global trace; lappend trace $args; return $args } proc tracer args { global trace; lappend trace $args; return $args } # trace add execution echo leave tracer echo hi # set trace }] \n } [viewFile [asset tkt-0dd4b31bb8]] test profiler-11.0-tkt-3603260fff {reset descendants} { do { proc profile_a {} { for {set f 0} {$f<100} {incr f} { profile_b } } proc profile_b {} { for {set f 0} {$f<100000} {incr f} {} } profile_a profiler::reset profile_a expr {$profiler::totalRuntime(::profile_a) < $profiler::descendantTime(::profile_a)} } } 0 # ------------------------------------------------------------------------- rename do {} testsuiteCleanup return