-
Notifications
You must be signed in to change notification settings - Fork 10
/
normbench.tcl
executable file
·322 lines (302 loc) · 8.39 KB
/
normbench.tcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
#!/usr/bin/env tclsh
# normbench.tcl ?options?
#
set RCS {RCS: @(#) $Id: normbench.tcl,v 1.7 2010/09/28 04:36:19 hobbs Exp $}
#
# Copyright (c) 2000-2007 Jeffrey Hobbs.
#
# Run the main script from an 8.2+ interp
#
if {[catch {package require Tcl 8.2}]} {
set me [file tail [info script]]
puts stderr "$me requires 8.2+ to run, although it can benchmark\
any Tcl v7+ interpreter"
exit 1
}
regexp {,v (\d+\.\d+)} $RCS -> VERSION
set MYDIR [file dirname [info script]]
set ME [file tail [info script]]
proc usage {} {
puts stderr "Usage (v$::VERSION): $::ME ?options?\
\n\t-help # print out this message\
\n\t-delta # delta range for wiki highlight (default: 0.05)\
\n\t-normalize <version> # normalize numbers to given version\
\n\t-output <text|list|csv|wiki> # style of output (default: match input format)\
\n\t?file? # runbench output file to normalize (or stdin)"
exit 1
}
#
# Process args
#
array set opts {
norm {}
fid stdin
output {}
delta {0.05}
}
if {[llength $argv]} {
while {[llength $argv]} {
set key [lindex $argv 0]
switch -glob -- $key {
-help* { usage }
-norm* {
set opts(norm) [lindex $argv 1]
set argv [lreplace $argv 0 1]
}
-delta {
set opts(delta) [lindex $argv 1]
set argv [lreplace $argv 0 1]
}
-out* {
# Output style
set opts(output) [lindex $argv 1]
if {![regexp {^(text|list|csv|wiki)$} $opts(output)]} { usage }
set argv [lreplace $argv 0 1]
}
default {
if {![file exists $key]} {
usage
} else {
set opts(fid) [open $key r]
set argv [lreplace $argv 0 0]
# The file should be the last arg
if {[llength $argv]} { usage }
}
}
}
}
}
proc csv2list {str {sepChar ,}} {
regsub -all {(\A\"|\"\Z)} $str \0 str
set str [string map [list $sepChar\"\"\" $sepChar\0\" \
\"\"\"$sepChar \"\0$sepChar \
\"\" \" \" \0 ] $str]
set end 0
while {[regexp -indices -start $end {(\0)[^\0]*(\0)} $str \
-> start end]} {
set start [lindex $start 0]
set end [lindex $end 0]
set range [string range $str $start $end]
set first [string first $sepChar $range]
if {$first >= 0} {
set str [string replace $str $start $end \
[string map [list $sepChar \1] $range]]
}
incr end
}
set str [string map [list $sepChar \0 \1 $sepChar \0 {} ] $str]
return [split $str \0]
}
proc list2csv {list {sepChar ,}} {
set out ""
foreach l $list {
set sep {}
foreach val $l {
if {[string match "*\[\"$sepChar\]*" $val]} {
append out $sep\"[string map [list \" \"\"] $val]\"
} else {
append out $sep$val
}
set sep $sepChar
}
append out \n
}
return $out
}
proc list2text {l} {
global DESCLEN
set num [lindex $l 0]
set desc [lindex $l 1]
set times [lrange $l 2 end]
if {![info exists DESCLEN]} {
# make desclen max available for 80 char display
set DESCLEN [expr {74 - 9*[llength $times]}]
if {$DESCLEN < 40} { set DESCLEN 40 }
}
set text [format "%.3d %-*s" $num $DESCLEN $desc]
foreach t $times {
if {[string is double -strict $t]} {
append text [format " %8.2f" $t]
} else {
append text [format " %8s" $t]
}
}
return $text
}
proc text2list {str} {
global DESCLEN
if {![info exists DESCLEN]} {
# first creation - determine desclen on distance to first datapoint
# At this point we have to guess ...
set DESCLEN [expr {[string first 1: $str]-1}]
}
set times [string range $str $DESCLEN end]
regexp {\d+} $str num ; # use RE to catch 0-prefaced nums
set desc [string trim [string range $str [string length $num] $DESCLEN]]
return [concat [list $num $desc] $times]
}
proc min {times} {
set min [expr {1<<16}]
foreach t $times {
if {[string is double -strict $t]} { if {$t < $min} { set min $t } }
}
return $min
}
proc max {times} {
set max 0
foreach t $times {
if {[string is double -strict $t]} { if {$t > $max} { set max $t } }
}
return $max
}
proc wikisafe {str} {
return [string map [list | <<pipe>> "\[" "\[\[" "\]" "\]\]" ] $str]
}
proc wiki2list {str} {
# remove first and last 2 chars and split on | symbol
set out [list]
foreach elem [split [string range $str 2 end-2] "|"] {
set elem [string trim $elem '] ; # remove wiki highlighting
lappend out [string map [list "\[\[" "\[" "\]\]" "\]"] $elem]
}
return $out
}
proc list2wiki {l} {
if {[lsearch -regexp $l {(VER|BENCH)}] != -1} {
return "%|[join [wikisafe $l] |]|%\n" ; # header
} else {
return "&|[join [wikisafe $l] |]|&\n"
}
}
proc findVersion {norm versions} {
if {$norm == "" || $norm == "none"} { return 0 }
set i [lsearch -exact $versions $norm]
if {$i >= 0} { return $i }
set i [lsearch -glob $versions *$norm*]
if {$i >= 0} { return $i }
puts stderr "Unable to normalize \"$norm\": must be one of [join $versions {, }]"
usage
}
proc normalize-text {norm line} {
global start col
scan $line %d num
if {$num == 0} {
set start [expr {[string first 1: $line]-1}]
set col [findVersion $norm [string range $line $start end]]
return $line
}
set times [string range $line $start end]
set ntime [lindex $times $col]
if {![string is double -strict $ntime] || $ntime == 0} {
# This didn't return valid data. Try walking backwards to find
# a newer version that we can normalize this row on, since newer
# versions are to the left.
for {set i $col} {$i >= 0} {incr i -1} {
set ntime [lindex $times $i]
if {[string is double -strict $ntime] && $ntime} { break }
}
# Hmph. No usable data.
if {$i == -1} { return $line }
}
set out [string range $line 0 [expr {$start-1}]]
foreach t $times {
if {$norm != "none" && [string is double -strict $t]} {
append out [format " %7.2f" \
[expr {double($t) / double($ntime)}]]
} else {
append out [format " %7s" $t]
}
}
return $out
}
proc normalize-list {norm line} {
global col opts
if {[lindex $line 0] == 0} {
set col [findVersion $norm [lrange $line 2 end]]
return $line
}
set times [lrange $line 2 end]
set ntime [lindex $times $col]
if {![string is double -strict $ntime]} {
return $line
} else {
set out [lrange $line 0 1]
if {$opts(output) == "wiki"} {
set min [min $times]
set max [max $times]
}
foreach t $times {
if {[string is double -strict $t]} {
if {$norm == "none"} {
set elem $t
} else {
set elem [format "%.2f" [expr {double($t)/$ntime}]]
}
if {$opts(output) == "wiki"} {
# do magic highlighting within DELTA% of min or max
if {$t < ($min*(1.0+$opts(delta)))} {
set elem "''$elem''" ; # italic
} elseif {$t > ($max*(1.0-$opts(delta)))} {
set elem "'''$elem'''" ; # bold
}
}
lappend out $elem
} else {
lappend out $t
}
}
return $out
}
}
proc normalize {norm indata outformat} {
set lines [split $indata \n]
foreach line $lines {
if {!([string match {[0-9]*} $line] || [string match {?|[0-9]*} $line])
|| [string match {*milliseconds} $line]} {
if {$outformat == "wiki"} {
puts stdout " [string trimleft $line]"
} else {
puts stdout $line
}
continue
}
regexp {^(?:[%&]\|)?(\d+)} $line -> num ; # gets first number in line
if {$num == 0} {
# guess format based on first line of version input
if {[string match "0,VER*" $line]} {
set informat csv
} elseif {[string match "0 VER*" $line]} {
set informat list
} elseif {[string match "?|0*|VER*" $line]} {
set informat wiki
} elseif {[string match "0*VER*" $line]} {
set informat text
} else {
puts stderr "Unrecognized runbench format input file '$line'"
exit
}
if {$outformat == ""} {
set outformat $informat
}
}
# Allow separate input/output format, so convert input to list form
if {($informat == $outformat) && $informat == "text"} {
puts stdout [normalize-text $norm $line]
} else {
switch -exact -- $informat {
text { set line [text2list $line] }
csv { set line [csv2list $line] }
wiki { set line [wiki2list $line] }
}
set line [normalize-list $norm $line]
switch -exact -- $outformat {
text { puts stdout [list2text $line] }
list { puts stdout $line }
csv { puts -nonewline stdout [list2csv [list $line]] }
wiki { puts -nonewline stdout [list2wiki $line] }
}
}
}
}
fconfigure stdout -encoding iso8859-1 ; # avoid utf-8 output
normalize $opts(norm) [read -nonewline $opts(fid)] $opts(output)