Tk Library Source Code

Artifact [f1f4c2919c]
Login

Artifact f1f4c2919c5bc52ef45109934e9823a7ff609a2f:

Attachment "profiler.ema.txt" to ticket [828717ffff] added by fstockinger 2003-11-01 06:01:42.
Hallo,

using tcllib's profiler 0.2.1 with tcl 8.4 shows some problems
which I try to overcome.

The first problem or comment is related to a former posting of
Ulrich Schoebel and some Bug (582506, 582522) in the namespace import and
trace functionality. The workaround I found is to wrap the
import when profiling and set an 'interp alias ...' too.

But then I found out that the procedure name is not always the same
for a procedure depending on the scope of calling. So I
add a small patch to the trace handler to get more
'canonical' names using 'namespace origin'.

--- /usr/local/ActiveTcl-8.4.4/lib/tcllib1.5/profiler/profiler.tcl 2003-07-21 07:16:11.000000000 +0200
+++ profiler.tcl        2003-10-16 11:51:50.000000000 +0200
@@ -158,15 +158,31 @@
 #      None

 proc ::profiler::TraceHandler {name cmd args} {
-
+
     if { [info level] == 1 } {
         set caller GLOBAL
     } else {
         # Get the name of the calling procedure
        set caller [lindex [info level -1] 0]
+        if {[string length $caller]} {
+            set caller [uplevel [list namespace origin $caller]]
+        } else {
+            # if info level is empty try one more
+            if {[info level] > 2} {
+                set caller [lindex [info level -2] 0]
+                if {[string length $caller]} {
+                    set caller [uplevel [list namespace origin $caller]]
+                } else {
+                    set caller EMPTY
+                }
+            }
+        }
     }

     set type [lindex $args end]
+    # get a 'canonical' name
+    set name [uplevel [list namespace origin $name]]
+
     ::profiler::${type}Handler $name $caller
 }

Note, that if the info level is empty, which occurs with tcltest,
I go up another level if this is possible. A somehow strange effect, any
comments?

Next, it would be nice to add commands and procedures defined before
the profiler was initialized. Therefore I suggest an additional procedure:

# ::profiler::addCmd
#
# the procedure is derived from the tcllib profiler procedure
# procProf and allows to add commands to the profiling, which are not
# included before
proc ::profiler::addCmd {name} {
  variable callCount
  variable compileTime
  variable totalRuntime
  variable descendantTime
  variable statTime
  variable enabled
  variable paused

  set name [uplevel [list namespace origin $name]]

  # Set up accounting for this procedure
  set callCount($name) 0
  set compileTime($name) 0
  set totalRuntime($name) 0
  set descendantTime($name) 0
  set statTime($name) {}
  set enabled($name) [expr {!$paused}]

  if {[package vsatisfies [package provide Tcl] 8.4]} {
    trace add execution $name {enter leave} [list ::profiler::TraceHandler $name]
  } else {
    error "add commands to profiling needs tcl 8.4 or higher"
  }

  return
}

This procedure was derived from the ::profiler::profProc and allows to
add tcl commands, too.

But one must be careful profiling 'set', because you change the
internal profiler state while calling suspend and resume.
See the patch below. The same problems occur when you try to profile the profiler ;-)
apply to proc ::profiler::resume {{pattern *}}

@@ -571,10 +588,15 @@
     variable callCount
     variable enabled
     variable paused
-
     set paused 0
     foreach name [array names callCount $pattern] {
-        set enabled($name) 1
+      if {[string equal $name "::set"]} {
+        trace remove execution $name {enter leave} [list ::profiler::TraceHandler $name]
+      }
+      set enabled($name) 1
+      if {[string equal $name "::set"]} {
+        trace add execution $name {enter leave} [list ::profiler::TraceHandler $name]
+      }
     }

     return

Having add, remove would be nice too:

proc ::profiler::removeCmd {name} {
  variable callCount
  variable compileTime
  variable totalRuntime
  variable descendantTime
  variable statTime
  variable enabled
  variable paused

  set name [uplevel [list namespace origin $name]]
  if {![info exists enabled($name)]} return

  # Remove accounting for this procedure
  unset callCount($name)
  unset compileTime($name)
  unset totalRuntime($name)
  unset descendantTime($name)
  unset statTime($name)
  unset enabled($name)

  if {[package vsatisfies [package provide Tcl] 8.4]} {
    trace remove execution $name {enter leave} [list ::profiler::TraceHandler $name]
  } else {
    error "delete commands to profiling needs tcl 8.4 or higher"
  }

  return
}


And finally it would be nice to stop the profiler from arranging
procedures for profiling. I solve this by setting back the interpreter alias
of proc.

This are the points which are still open, IMHO
- separate init and profiler start
- leaving the profiler completely, something like package forget ...
- have a closer look on recursive function calls

- and maybe some day one could measure the coverage, too. IMHO that this should not be too difficult

If, you are interested I send the patched profiler and some tcltest.

<frank/>