2 package require sqlite3
5 #############################################################################
6 # Code to set up scrollbars for widgets. This is generic, boring stuff.
8 namespace eval autoscroll
{
9 proc scrollable
{widget path args
} {
11 set w
[$widget ${path
}.widget
{*}$args]
12 set vs
[::ttk::scrollbar ${path
}.vs
]
13 set hs
[::ttk::scrollbar ${path
}.hs
-orient horizontal
]
14 grid $w -row 0 -column 0 -sticky nsew
16 grid rowconfigure
$path 0 -weight 1
17 grid columnconfigure
$path 0 -weight 1
19 set grid [list grid $vs -row 0 -column 1 -sticky nsew
]
20 $w configure
-yscrollcommand [list ::autoscroll::scrollcommand $grid $vs]
21 $vs configure
-command [list $w yview
]
22 set grid [list grid $hs -row 1 -column 0 -sticky nsew
]
23 $w configure
-xscrollcommand [list ::autoscroll::scrollcommand $grid $hs]
24 $hs configure
-command [list $w xview
]
28 proc scrollcommand
{grid sb args
} {
30 set isRequired
[expr {[lindex $args 0] != 0.0 ||
[lindex $args 1] != 1.0}]
31 if {$isRequired && ![winfo ismapped
$sb]} {
34 if {!$isRequired && [winfo ismapped
$sb]} {
38 namespace export scrollable
40 namespace import
::autoscroll::*
41 #############################################################################
43 proc populate_text_widget
{db
} {
44 $::O(text) configure
-state normal
45 set id
[lindex [$::O(tree
) selection] 0]
46 set frame [lindex $id end
]
48 set line
[$db one
{SELECT line FROM
frame WHERE
frame = $frame}]
50 regexp {^
([^
:]*):([0-9]*)} $line -> file line
51 set content
[$db one
"SELECT content FROM file WHERE name = '$file'"]
52 $::O(text) delete
0.0 end
55 foreach L
[split $content "\n"] {
56 if {$iLine == $line} {
57 $::O(text) insert end
"$L\n" highlight
59 $::O(text) insert end
"$L\n"
63 $::O(text) yview
-pickplace ${line
}.0
65 $::O(text) configure
-state disabled
68 proc populate_index
{db
} {
69 $::O(text) configure
-state normal
71 $::O(text) delete
0.0 end
72 $::O(text) insert end
"\n\n"
74 set L
[format " % -40s%12s%12s\n" "Test Case" "Allocations" "Bytes"]
75 $::O(text) insert end
$L
76 $::O(text) insert end
" [string repeat - 64]\n"
79 SELECT 'TOTAL' AS ztest
, sum
(ncall
) AS calls
, sum
(nbyte
) AS bytes
82 SELECT ztest AS ztest
, sum
(ncall
) AS calls
, sum
(nbyte
) AS bytes
88 set tags
[list $ztest]
89 if {$ztest eq
$::O(current
)} {
90 lappend tags highlight
92 set L
[format " % -40s%12s%12s\n" $ztest $calls $bytes]
93 $::O(text) insert end
$L $tags
95 $::O(text) tag
bind $ztest <1> [list populate_tree_widget
$db $ztest]
96 $::O(text) tag
bind $ztest <Enter
> [list $::O(text) configure
-cursor hand2
]
97 $::O(text) tag
bind $ztest <Leave
> [list $::O(text) configure
-cursor ""]
100 $::O(text) configure
-state disabled
103 proc sort_tree_compare
{iLeft iRight
} {
105 switch -- [expr (int
($O(tree_sort
)/2))] {
107 set left
[$O(tree
) item
$iLeft -text]
108 set right
[$O(tree
) item
$iRight -text]
109 set res
[string compare
$left $right]
112 set left
[lindex [$O(tree
) item
$iLeft -values] 0]
113 set right
[lindex [$O(tree
) item
$iRight -values] 0]
114 set res
[expr $left - $right]
117 set left
[lindex [$O(tree
) item
$iLeft -values] 1]
118 set right
[lindex [$O(tree
) item
$iRight -values] 1]
119 set res
[expr $left - $right]
122 if {$O(tree_sort
)&0x01} {
123 set res
[expr -1 * $res]
128 proc sort_tree
{iMode
} {
130 if {$O(tree_sort
) == $iMode} {
133 set O
(tree_sort
) $iMode
136 set items
[$T children
{}]
137 set items
[lsort -command sort_tree_compare
$items]
138 for {set ii
0} {$ii < [llength $items]} {incr ii
} {
139 $T move
[lindex $items $ii] {} $ii
143 proc trim_frames
{stack
} {
144 while {[info exists
::O(ignore.
[lindex $stack 0])]} {
145 set stack
[lrange $stack 1 end
]
150 proc populate_tree_widget
{db zTest
} {
151 $::O(tree
) delete
[$::O(tree
) children
{}]
153 for {set ii
0} {$ii < 15} {incr ii
} {
158 trim_frames
(lrange(lstack
, 0, $ii)) AS stack
160 WHERE
(zTest
= $zTest OR
$zTest = 'TOTAL'
) AND
llength(lstack
)>$ii
164 set parent_id
[lrange $stack 0 end-1
]
165 set frame [lindex $stack end
]
166 set line
[$db one
{SELECT line FROM
frame WHERE
frame = $frame}]
167 set line
[lindex [split $line /] end
]
168 set v
[list $calls $bytes]
171 $::O(tree
) insert
$parent_id end
-id $stack -text $line -values $v
176 set ::O(current
) $zTest
184 ::ttk::panedwindow .pan
-orient horizontal
185 set O
(tree
) [scrollable
::ttk::treeview .pan.tree
]
188 set O
(text) [scrollable
text .pan.right.
text]
189 button .pan.right.index
-command {populate_index mddb
} -text "Show Index"
190 pack .pan.right.index
-side top
-fill x
191 pack .pan.right.
text -fill both
-expand true
193 $O(text) tag configure highlight
-background wheat
194 $O(text) configure
-wrap none
-height 35
199 $O(tree
) configure
-columns {calls bytes
}
200 $O(tree
) heading
#0 -text Line -anchor w -command {sort_tree 0}
201 $O(tree
) heading calls
-text Calls
-anchor w
-command {sort_tree
2}
202 $O(tree
) heading bytes
-text Bytes
-anchor w
-command {sort_tree
4}
203 $O(tree
) column
#0 -width 150
204 $O(tree
) column calls
-width 100
205 $O(tree
) column bytes
-width 100
207 pack .pan
-fill both
-expand 1
209 #--------------------------------------------------------------------
210 # Open the database containing the malloc data. The user specifies the
211 # database to use by passing the file-name on the command line.
213 proc open_database
{} {
214 if {[info exists
::BUILTIN]} {
215 sqlite3 mddb
:memory:
219 set zFilename
[lindex $::argv 0]
220 if {$zFilename eq
""} {
221 set zFilename mallocs.sql
223 set fd
[open $zFilename]
224 set zHdr
[read $fd 15]
225 if {$zHdr eq
"SQLite format 3"} {
227 sqlite3 mddb
$zFilename
230 sqlite3 mddb
:memory:
234 wm title .
$zFilename
237 mddb function
lrange -argcount 3 lrange
238 mddb function
llength -argcount 1 llength
239 mddb function trim_frames
-argcount 1 trim_frames
242 SELECT
frame FROM
frame
243 WHERE line LIKE '
%malloc.c
:%' OR line LIKE '
%mem2.c
:%'
245 set ::O(ignore.
$frame) 1
250 bind $O(tree
) <<TreeviewSelect
>> [list populate_text_widget mddb
]
252 populate_tree_widget mddb
[mddb one
{SELECT zTest FROM malloc LIMIT
1}]