File: queue.bench

package info (click to toggle)
tcllib 1.20%2Bdfsg-1
  • links: PTS
  • area: main
  • in suites: bullseye
  • size: 68,064 kB
  • sloc: tcl: 216,842; ansic: 14,250; sh: 2,846; xml: 1,766; yacc: 1,145; pascal: 881; makefile: 107; perl: 84; f90: 84; python: 33; ruby: 13; php: 11
file content (232 lines) | stat: -rw-r--r-- 5,793 bytes parent folder | download | duplicates (6)
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
# -*- tcl -*-
# Tcl Benchmark File
#
# This file contains a number of benchmarks for the 'struct::queue'
# data structure to allow developers to monitor package performance.
#
# (c) 2008-2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>

# We need at least version 8.4 for the package and thus the
# benchmarks.

if {![package vsatisfies [package present Tcl] 8.4]} {
    bench_puts "Need Tcl 8.4+, found Tcl [package present Tcl]"
    return
}

# ### ### ### ######### ######### ######### ###########################
## Setting up the environment ...

package require Tcl 8.4

package forget struct::list
package forget struct::queue

set self  [file join [pwd] [file dirname [info script]]]
set mod   [file dirname $self]
set index [file join [file dirname $self] tcllibc pkgIndex.tcl]

if 1 {
    if {[file exists $index]} {
	set ::dir [file dirname $index]
	uplevel #0 [list source $index]
	unset ::dir
	package require tcllibc
    }
}

source [file join $mod  cmdline cmdline.tcl]
source [file join $self list.tcl]
source [file join $self queue.tcl]


# ### ### ### ######### ######### ######### ###########################

proc makeNcmd {n} {
    return [linsert [struct::list iota $n] 0 s put]
}

proc makeN {n} {
    struct::queue s
    if {$n > 0} { eval [makeNcmd $n] }
    return
}

# ### ### ### ######### ######### ######### ###########################
## Get all the possible implementations

struct::queue::SwitchTo {}
foreach e [struct::queue::KnownImplementations] {
    ::struct::queue::LoadAccelerator $e
}

# ### ### ### ######### ######### ######### ###########################
## Benchmarks.

# We have only 6 queue operations
#
# * clear  - Remove all elements from the queue.
# * get    - Destructively retrieve N elements, N > 0
# * peek   - Retrieve N elements, keep on queue, N > 0
# * put    - Add N elements to the queue, N > 0
# * size   - Query the size of the queue.
# * unget  - Add N elements to _front_ of the queue, N > 0

# note on peek, get:
# - current testing is fine for single queue area.
# - split return/append => should check performance of peek crossing boundaries
# - split unget/return/append ? ditto, now possibly crossing 2 boundaries.

# peek/put:
# - Time to retrieve/remove 1/10/100/1000 elements incrementally from a queue.
# - Time to retrieve/remove ............. elements at once from a queue.
# - Queue sizes 10/100/1000/1000 and pop only elements less than size.
# Expected: Amortized linear time in number of retrieved/removed elements.

foreach queueimpl [struct::queue::Implementations] {
    struct::queue::SwitchTo $queueimpl

    bench_puts {=== get/peek =========}

    foreach base {10 100 1000 10000} {
	foreach remove {1 10 100 1000 10000} {
	    if {$remove > $base} continue

	    bench -desc "queue get once $base/$remove queue($queueimpl)" -ipre {
		makeN $base
	    } -body {
		s get $remove
	    } -ipost {
		s destroy
	    }

	    bench -desc "queue get incr $base/$remove queue($queueimpl)" -pre {
		set cmd {}
		foreach x [struct::list iota $remove] {
		    lappend cmd [list s get]
		}
		proc foo {} [join $cmd \n]
		catch {foo} ;# compile
	    } -ipre {
		makeN $base
	    } -body {
		foo
	    } -ipost {
		s destroy
	    } -post {
		rename foo {}
	    }

	    bench -desc "queue peek $base/$remove queue($queueimpl)" -ipre {
		makeN $base
	    } -body {
		s peek $remove
	    } -ipost {
		s destroy
	    }
	}
    }

    # put:
    # - Time to add 1/10/100/1000 elements incrementally to an empty queue
    # - Time to add ............. elements at once to an empty queue.
    # - As above, to a queue containing 1/10/100/1000 elements already.
    # Expected: Amortized linear time in number of elements added.

    bench_puts {=== put/unget =========}

    foreach base  {0 1 10 100 1000} {
	foreach add {1 10 100 1000} {

	    bench -desc "queue put once $base/$add queue($queueimpl)" -ipre {
		makeN $base
		set cmd [makeNcmd $add]
	    } -body {
		eval $cmd
	    } -ipost {
		s destroy
	    }

	    bench -desc "queue put incr $base/$add queue($queueimpl)" -pre {
		set cmd {}
		foreach x [struct::list iota $add] {
		    lappend cmd [list s put $x]
		}
		proc foo {} [join $cmd \n]
		catch {foo} ;# compile
	    } -ipre {
		makeN $base
	    } -body {
		foo
	    } -ipost {
		s destroy
	    } -post {
		rename foo {}
	    }

	    bench -desc "queue unget incr $base/$add queue($queueimpl)" -pre {
		set cmd {}
		foreach x [struct::list iota $add] {
		    lappend cmd [list s unget $x]
		}
		proc foo {} [join $cmd \n]
		catch {foo} ;# compile
	    } -ipre {
		makeN $base
	    } -body {
		foo
	    } -ipost {
		s destroy
	    } -post {
		rename foo {}
	    }
	}
    }

    # size
    # - Time to query size of queue containing 0/1/10/100/1000/10000 elements.
    # Expected: Constant time.

    bench_puts {=== size =========}

    foreach n {0 1 10 100 1000 10000} {
	bench -desc "queue size $n queue($queueimpl)" -pre {
	    makeN $n
	} -body {
	    s size
	} -post {
	    s destroy
	}
    }

    # clear
    # - Time to clear a queue containing 0/1/10/100/1000/10000 elements.
    # Expected: Constant to linear time in number of elements to clear.

    bench_puts {=== clear =========}

    foreach n {0 1 10 100 1000 10000} {
	bench -desc "queue clear $n queue($queueimpl)" -ipre {
	    makeN $n
	} -body {
	    s clear
	} -ipost {
	    s destroy
	}
    }
}

# ### ### ### ######### ######### ######### ###########################
## Complete

return

# ### ### ### ######### ######### ######### ###########################
## Notes ...

# Notes on optimizations we can do.
#
# Tcl - Cache structural data - depth, ancestors ...
# C   - Cache results, like child lists (Tcl_Obj's!)
#       Maybe use Tcl_Obj/List for child arrays instead
#       of N* ? Effect on modification performance ?