diff options
Diffstat (limited to 'tests/perftest.lua')
-rw-r--r-- | tests/perftest.lua | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/tests/perftest.lua b/tests/perftest.lua new file mode 100644 index 0000000..8ce1b3c --- /dev/null +++ b/tests/perftest.lua | |||
@@ -0,0 +1,184 @@ | |||
1 | -- | ||
2 | -- PERFTEST.LUA Copyright (c) 2007-08, Asko Kauppi <akauppi@gmail.com> | ||
3 | -- | ||
4 | -- Performance comparison of multithreaded Lua (= how much ballast does using | ||
5 | -- Lua Lanes introduce) | ||
6 | -- | ||
7 | -- Usage: | ||
8 | -- [time] lua -lstrict perftest.lua [threads] [-plain|-single[=2..n]] [-time] [-prio[=-2..+2[,-2..+2]]] | ||
9 | -- | ||
10 | -- threads: number of threads to launch (loops in 'plain' mode) | ||
11 | -- -plain: runs in nonthreaded mode, to get a comparison baseline | ||
12 | -- -single: runs using just a single CPU core (or 'n' cores if given) | ||
13 | -- -prio: sets odd numbered threads to higher/lower priority | ||
14 | -- | ||
15 | -- History: | ||
16 | -- AKa 20-Jul-08: updated to Lanes 2008 | ||
17 | -- AK 14-Apr-07: works on Win32 | ||
18 | -- | ||
19 | -- To do: | ||
20 | -- (none?) | ||
21 | -- | ||
22 | |||
23 | -- On MSYS, stderr is buffered. In this test it matters. | ||
24 | -- Seems, even with this MSYS wants to buffer linewise, needing '\n' | ||
25 | -- before actual output. | ||
26 | -- | ||
27 | local MSYS= os.getenv("OSTYPE")=="msys" | ||
28 | |||
29 | |||
30 | require "lanes" | ||
31 | |||
32 | local m= require "argtable" | ||
33 | local argtable= assert( m.argtable ) | ||
34 | |||
35 | local N= 1000 -- threads/loops to use | ||
36 | local M= 1000 -- sieves from 1..M | ||
37 | local PLAIN= false -- single threaded (true) or using Lanes (false) | ||
38 | local SINGLE= false -- cores to use (false / 1..n) | ||
39 | local TIME= false -- use Lua for the timing | ||
40 | local PRIO_ODD, PRIO_EVEN -- -3..+3 | ||
41 | |||
42 | local function HELP() | ||
43 | io.stderr:write( "Usage: lua perftest.lua [threads]\n" ) | ||
44 | end | ||
45 | |||
46 | -- nil -> +2 | ||
47 | -- odd_prio[,even_prio] | ||
48 | -- | ||
49 | local function prio_param(v) | ||
50 | if v==true then return 2,-2 end | ||
51 | |||
52 | local a,b= string.match( v, "^([%+%-]?%d+)%,([%+%-]?%d+)$" ) | ||
53 | if a then | ||
54 | return tonumber(a), tonumber(b) | ||
55 | elseif tonumber(v) then | ||
56 | return tonumber(v) | ||
57 | else | ||
58 | error( "Bad priority: "..v ) | ||
59 | end | ||
60 | end | ||
61 | |||
62 | for k,v in pairs( argtable(...) ) do | ||
63 | if k==1 then N= tonumber(v) or HELP() | ||
64 | elseif k=="plain" then PLAIN= true | ||
65 | elseif k=="single" then SINGLE= v -- true/number | ||
66 | elseif k=="time" then TIME= true | ||
67 | elseif k=="prio" then PRIO_ODD, PRIO_EVEN= prio_param(v) | ||
68 | else HELP() | ||
69 | end | ||
70 | end | ||
71 | |||
72 | PRIO_ODD= PRIO_ODD or 0 | ||
73 | PRIO_EVEN= PRIO_EVEN or 0 | ||
74 | |||
75 | |||
76 | -- SAMPLE ADOPTED FROM Lua 5.1.1 test/sieve.lua -- | ||
77 | |||
78 | -- the sieve of of Eratosthenes programmed with coroutines | ||
79 | -- typical usage: lua -e N=1000 sieve.lua | column | ||
80 | |||
81 | -- AK: Wrapped within a surrounding function, so we can pass it to Lanes | ||
82 | -- Note that coroutines can perfectly fine be used within each Lane. :) | ||
83 | -- | ||
84 | -- AKa 20-Jul-2008: Now the wrapping to one function is no longer needed; | ||
85 | -- Lanes 2008 can take the used functions as upvalues. | ||
86 | -- | ||
87 | local function sieve_lane(N,id) | ||
88 | |||
89 | if MSYS then | ||
90 | io.stderr:setvbuf "no" | ||
91 | end | ||
92 | |||
93 | -- generate all the numbers from 2 to n | ||
94 | local function gen (n) | ||
95 | return coroutine.wrap(function () | ||
96 | for i=2,n do coroutine.yield(i) end | ||
97 | end) | ||
98 | end | ||
99 | |||
100 | -- filter the numbers generated by `g', removing multiples of `p' | ||
101 | local function filter (p, g) | ||
102 | return coroutine.wrap(function () | ||
103 | while 1 do | ||
104 | local n = g() | ||
105 | if n == nil then return end | ||
106 | if math.mod(n, p) ~= 0 then coroutine.yield(n) end | ||
107 | end | ||
108 | end) | ||
109 | end | ||
110 | |||
111 | local ret= {} -- returned values: { 2, 3, 5, 7, 11, ... } | ||
112 | N=N or 1000 -- from caller | ||
113 | local x = gen(N) -- generate primes up to N | ||
114 | while 1 do | ||
115 | local n = x() -- pick a number until done | ||
116 | if n == nil then break end | ||
117 | --print(n) -- must be a prime number | ||
118 | table.insert( ret, n ) | ||
119 | |||
120 | x = filter(n, x) -- now remove its multiples | ||
121 | end | ||
122 | |||
123 | io.stderr:write(id..(MSYS and "\n" or "\t")) -- mark we're ready | ||
124 | |||
125 | return ret | ||
126 | end | ||
127 | -- ** END OF LANE ** -- | ||
128 | |||
129 | |||
130 | -- Keep preparation code outside of the performance test | ||
131 | -- | ||
132 | local f_even= lanes.gen( "base,coroutine,math,table,io", -- "*" = all | ||
133 | { priority= PRIO_EVEN }, sieve_lane ) | ||
134 | |||
135 | local f_odd= lanes.gen( "base,coroutine,math,table,io", -- "*" = all | ||
136 | { priority= PRIO_ODD }, sieve_lane ) | ||
137 | |||
138 | io.stderr:write( "*** Counting primes 1.."..M.." "..N.." times ***\n\n" ) | ||
139 | |||
140 | local t0= TIME and os.time() | ||
141 | |||
142 | if PLAIN then | ||
143 | io.stderr:write( "Plain (no multithreading):\n" ) | ||
144 | |||
145 | for i=1,N do | ||
146 | local tmp= sieve_lane(M,i) | ||
147 | assert( type(tmp)=="table" and tmp[1]==2 and tmp[168]==997 ) | ||
148 | end | ||
149 | else | ||
150 | if SINGLE then | ||
151 | io.stderr:write( (tonumber(SINGLE) and SINGLE or 1) .. " core(s):\n" ) | ||
152 | lanes.single(SINGLE) -- limit to N cores (just OS X) | ||
153 | else | ||
154 | io.stderr:write( "Multi core:\n" ) | ||
155 | end | ||
156 | |||
157 | if PRIO_ODD ~= PRIO_EVEN then | ||
158 | io.stderr:write( ( PRIO_ODD > PRIO_EVEN and "ODD" or "EVEN" ).. | ||
159 | " LANES should come first (odd:"..PRIO_ODD..", even:"..PRIO_EVEN..")\n\n" ) | ||
160 | else | ||
161 | io.stderr:write( "EVEN AND ODD lanes should be mingled (both: "..PRIO_ODD..")\n\n" ) | ||
162 | end | ||
163 | local t= {} | ||
164 | for i=1,N do | ||
165 | t[i]= ((i%2==0) and f_even or f_odd) (M,i) | ||
166 | end | ||
167 | |||
168 | -- Make sure all lanes finished | ||
169 | -- | ||
170 | for i=1,N do | ||
171 | local tmp= t[i]:join() | ||
172 | assert( type(tmp)=="table" and tmp[1]==2 and tmp[168]==997 ) | ||
173 | end | ||
174 | end | ||
175 | |||
176 | io.stderr:write "\n" | ||
177 | |||
178 | if TIME then | ||
179 | local t= os.time() - t0 | ||
180 | io.stderr:write( "*** TIMING: "..t.." seconds ***\n" ) | ||
181 | end | ||
182 | |||
183 | -- | ||
184 | -- end | ||