Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/bench/tests/shootout/scimark.lua
2727 views
1
------------------------------------------------------------------------------
2
-- Lua SciMark (2010-12-20).
3
--
4
-- A literal translation of SciMark 2.0a, written in Java and C.
5
-- Credits go to the original authors Roldan Pozo and Bruce Miller.
6
-- See: http://math.nist.gov/scimark2/
7
------------------------------------------------------------------------------
8
-- Copyright (C) 2006-2010 Mike Pall. All rights reserved.
9
--
10
-- Permission is hereby granted, free of charge, to any person obtaining
11
-- a copy of this software and associated documentation files (the
12
-- "Software"), to deal in the Software without restriction, including
13
-- without limitation the rights to use, copy, modify, merge, publish,
14
-- distribute, sublicense, and/or sell copies of the Software, and to
15
-- permit persons to whom the Software is furnished to do so, subject to
16
-- the following conditions:
17
--
18
-- The above copyright notice and this permission notice shall be
19
-- included in all copies or substantial portions of the Software.
20
--
21
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
--
29
-- [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
30
------------------------------------------------------------------------------
31
32
------------------------------------------------------------------------------
33
-- Modification to be compatible with Lua 5.3
34
------------------------------------------------------------------------------
35
36
local function prequire(name) local success, result = pcall(require, name); return success and result end
37
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
38
39
function test()
40
41
if table and table.unpack then
42
unpack = table.unpack
43
end
44
45
------------------------------------------------------------------------------
46
47
local SCIMARK_VERSION = "2010-12-10"
48
local SCIMARK_COPYRIGHT = "Copyright (C) 2006-2010 Mike Pall"
49
50
local MIN_TIME = 0.2
51
local RANDOM_SEED = 101009 -- Must be odd.
52
local SIZE_SELECT = "small"
53
54
local benchmarks = {
55
"FFT", "SOR", "MC", "SPARSE", "LU",
56
small = {
57
FFT = { 1024 },
58
SOR = { 100 },
59
MC = { },
60
SPARSE = { 1000, 5000 },
61
LU = { 100 },
62
},
63
large = {
64
FFT = { 1048576 },
65
SOR = { 1000 },
66
MC = { },
67
SPARSE = { 100000, 1000000 },
68
LU = { 1000 },
69
},
70
}
71
72
local abs, log, sin, floor = math.abs, math.log, math.sin, math.floor
73
local pi, clock = math.pi, os.clock
74
local format = string.format
75
76
------------------------------------------------------------------------------
77
-- Select array type: Lua tables or native (FFI) arrays
78
------------------------------------------------------------------------------
79
80
local darray, iarray
81
82
local function array_init()
83
if jit and jit.status and jit.status() then
84
local ok, ffi = pcall(require, "ffi")
85
if ok then
86
darray = ffi.typeof("double[?]")
87
iarray = ffi.typeof("int[?]")
88
return
89
end
90
end
91
function darray(n) return {} end
92
iarray = darray
93
end
94
95
------------------------------------------------------------------------------
96
-- This is a Lagged Fibonacci Pseudo-random Number Generator with
97
-- j, k, M = 5, 17, 31. Pretty weak, but same as C/Java SciMark.
98
------------------------------------------------------------------------------
99
100
local rand, rand_init
101
102
if jit and jit.status and jit.status() then
103
-- LJ2 has bit operations and zero-based arrays (internally).
104
local bit = require("bit")
105
local band, sar = bit.band, bit.arshift
106
function rand_init(seed)
107
local Rm, Rj, Ri = iarray(17), 16, 11
108
for i=0,16 do Rm[i] = 0 end
109
for i=16,0,-1 do
110
seed = band(seed*9069, 0x7fffffff)
111
Rm[i] = seed
112
end
113
function rand()
114
local i = band(Ri+1, sar(Ri-16, 31))
115
local j = band(Rj+1, sar(Rj-16, 31))
116
Ri, Rj = i, j
117
local k = band(Rm[i] - Rm[j], 0x7fffffff)
118
Rm[j] = k
119
return k * (1.0/2147483647.0)
120
end
121
end
122
else
123
-- Better for standard Lua with one-based arrays and without bit operations.
124
function rand_init(seed)
125
local Rm, Rj = {}, 1
126
for i=1,17 do Rm[i] = 0 end
127
for i=17,1,-1 do
128
seed = (seed*9069) % (2^31)
129
Rm[i] = seed
130
end
131
function rand()
132
local j, m = Rj, Rm
133
local h = j - 5
134
if h < 1 then h = h + 17 end
135
local k = m[h] - m[j]
136
if k < 0 then k = k + 2147483647 end
137
m[j] = k
138
if j < 17 then Rj = j + 1 else Rj = 1 end
139
return k * (1.0/2147483647.0)
140
end
141
end
142
end
143
144
local function random_vector(n)
145
local v = darray(n+1)
146
for x=1,n do v[x] = rand() end
147
return v
148
end
149
150
local function random_matrix(m, n)
151
local a = {}
152
for y=1,m do
153
local v = darray(n+1)
154
a[y] = v
155
for x=1,n do v[x] = rand() end
156
end
157
return a
158
end
159
160
------------------------------------------------------------------------------
161
-- FFT: Fast Fourier Transform.
162
------------------------------------------------------------------------------
163
164
local function fft_bitreverse(v, n)
165
local j = 0
166
for i=0,2*n-4,2 do
167
if i < j then
168
v[i+1], v[i+2], v[j+1], v[j+2] = v[j+1], v[j+2], v[i+1], v[i+2]
169
end
170
local k = n
171
while k <= j do j = j - k; k = k / 2 end
172
j = j + k
173
end
174
end
175
176
local function fft_transform(v, n, dir)
177
if n <= 1 then return end
178
fft_bitreverse(v, n)
179
local dual = 1
180
repeat
181
local dual2 = 2*dual
182
for i=1,2*n-1,2*dual2 do
183
local j = i+dual2
184
local ir, ii = v[i], v[i+1]
185
local jr, ji = v[j], v[j+1]
186
v[j], v[j+1] = ir - jr, ii - ji
187
v[i], v[i+1] = ir + jr, ii + ji
188
end
189
local theta = dir * pi / dual
190
local s, s2 = sin(theta), 2.0 * sin(theta * 0.5)^2
191
local wr, wi = 1.0, 0.0
192
for a=3,dual2-1,2 do
193
wr, wi = wr - s*wi - s2*wr, wi + s*wr - s2*wi
194
for i=a,a+2*(n-dual2),2*dual2 do
195
local j = i+dual2
196
local jr, ji = v[j], v[j+1]
197
local dr, di = wr*jr - wi*ji, wr*ji + wi*jr
198
local ir, ii = v[i], v[i+1]
199
v[j], v[j+1] = ir - dr, ii - di
200
v[i], v[i+1] = ir + dr, ii + di
201
end
202
end
203
dual = dual2
204
until dual >= n
205
end
206
207
function benchmarks.FFT(n)
208
local l2n = log(n)/log(2)
209
if l2n % 1 ~= 0 then
210
io.stderr:write("Error: FFT data length is not a power of 2\n")
211
os.exit(1)
212
end
213
local v = random_vector(n*2)
214
return function(cycles)
215
local norm = 1.0 / n
216
for p=1,cycles do
217
fft_transform(v, n, -1)
218
fft_transform(v, n, 1)
219
for i=1,n*2 do v[i] = v[i] * norm end
220
end
221
return ((5*n-2)*l2n + 2*(n+1)) * cycles
222
end
223
end
224
225
------------------------------------------------------------------------------
226
-- SOR: Jacobi Successive Over-Relaxation.
227
------------------------------------------------------------------------------
228
229
local function sor_run(mat, m, n, cycles, omega)
230
local om4, om1 = omega*0.25, 1.0-omega
231
m = m - 1
232
n = n - 1
233
for i=1,cycles do
234
for y=2,m do
235
local v, vp, vn = mat[y], mat[y-1], mat[y+1]
236
for x=2,n do
237
v[x] = om4*((vp[x]+vn[x])+(v[x-1]+v[x+1])) + om1*v[x]
238
end
239
end
240
end
241
end
242
243
function benchmarks.SOR(n)
244
local mat = random_matrix(n, n)
245
return function(cycles)
246
sor_run(mat, n, n, cycles, 1.25)
247
return (n-1)*(n-1)*cycles*6
248
end
249
end
250
251
------------------------------------------------------------------------------
252
-- MC: Monte Carlo Integration.
253
------------------------------------------------------------------------------
254
255
local function mc_integrate(cycles)
256
local under_curve = 0
257
local rand = rand
258
for i=1,cycles do
259
local x = rand()
260
local y = rand()
261
if x*x + y*y <= 1.0 then under_curve = under_curve + 1 end
262
end
263
return (under_curve/cycles) * 4
264
end
265
266
function benchmarks.MC()
267
return function(cycles)
268
local res = mc_integrate(cycles)
269
assert(math.sqrt(cycles)*math.abs(res-math.pi) < 5.0, "bad MC result")
270
return cycles * 4 -- Way off, but same as SciMark in C/Java.
271
end
272
end
273
274
------------------------------------------------------------------------------
275
-- Sparse Matrix Multiplication.
276
------------------------------------------------------------------------------
277
278
local function sparse_mult(n, cycles, vy, val, row, col, vx)
279
for p=1,cycles do
280
for r=1,n do
281
local sum = 0
282
for i=row[r],row[r+1]-1 do sum = sum + vx[col[i]] * val[i] end
283
vy[r] = sum
284
end
285
end
286
end
287
288
function benchmarks.SPARSE(n, nz)
289
local nr = floor(nz/n)
290
local anz = nr*n
291
local vx = random_vector(n)
292
local val = random_vector(anz)
293
local vy, col, row = darray(n+1), iarray(nz+1), iarray(n+2)
294
row[1] = 1
295
for r=1,n do
296
local step = floor(r/nr)
297
if step < 1 then step = 1 end
298
local rr = row[r]
299
row[r+1] = rr+nr
300
for i=0,nr-1 do col[rr+i] = 1+i*step end
301
end
302
return function(cycles)
303
sparse_mult(n, cycles, vy, val, row, col, vx)
304
return anz*cycles*2
305
end
306
end
307
308
------------------------------------------------------------------------------
309
-- LU: Dense Matrix Factorization.
310
------------------------------------------------------------------------------
311
312
local function lu_factor(a, pivot, m, n)
313
local min_m_n = m < n and m or n
314
for j=1,min_m_n do
315
local jp, t = j, abs(a[j][j])
316
for i=j+1,m do
317
local ab = abs(a[i][j])
318
if ab > t then
319
jp = i
320
t = ab
321
end
322
end
323
pivot[j] = jp
324
if a[jp][j] == 0 then error("zero pivot") end
325
if jp ~= j then a[j], a[jp] = a[jp], a[j] end
326
if j < m then
327
local recp = 1.0 / a[j][j]
328
for k=j+1,m do
329
local v = a[k]
330
v[j] = v[j] * recp
331
end
332
end
333
if j < min_m_n then
334
for i=j+1,m do
335
local vi, vj = a[i], a[j]
336
local eij = vi[j]
337
for k=j+1,n do vi[k] = vi[k] - eij * vj[k] end
338
end
339
end
340
end
341
end
342
343
local function matrix_alloc(m, n)
344
local a = {}
345
for y=1,m do a[y] = darray(n+1) end
346
return a
347
end
348
349
local function matrix_copy(dst, src, m, n)
350
for y=1,m do
351
local vd, vs = dst[y], src[y]
352
for x=1,n do vd[x] = vs[x] end
353
end
354
end
355
356
function benchmarks.LU(n)
357
local mat = random_matrix(n, n)
358
local tmp = matrix_alloc(n, n)
359
local pivot = iarray(n+1)
360
return function(cycles)
361
for i=1,cycles do
362
matrix_copy(tmp, mat, n, n)
363
lu_factor(tmp, pivot, n, n)
364
end
365
return 2.0/3.0*n*n*n*cycles
366
end
367
end
368
369
------------------------------------------------------------------------------
370
-- Main program.
371
------------------------------------------------------------------------------
372
373
local function printf(...)
374
print(format(...))
375
end
376
377
local function fmtparams(p1, p2)
378
if p2 then return format("[%d, %d]", p1, p2)
379
elseif p1 then return format("[%d]", p1) end
380
return ""
381
end
382
383
local function measure(min_time, name, ...)
384
array_init()
385
rand_init(RANDOM_SEED)
386
local run = benchmarks[name](...)
387
--[[local cycles = 1
388
repeat
389
local tm = clock()
390
local flops = run(cycles, ...)
391
tm = clock() - tm
392
if tm >= min_time then
393
local res = flops / tm * 1.0e-6
394
local p1, p2 = ...
395
printf("%-7s %8.2f %s\n", name, res, fmtparams(...))
396
return res
397
end
398
cycles = cycles * 2
399
until false]]
400
401
run(10, ...)
402
return 10
403
end
404
405
printf("Lua SciMark %s based on SciMark 2.0a. %s.\n\n",
406
SCIMARK_VERSION, SCIMARK_COPYRIGHT)
407
408
while arg and arg[1] do
409
local a = table.remove(arg, 1)
410
if a == "-noffi" then
411
package.preload.ffi = nil
412
elseif a == "-small" then
413
SIZE_SELECT = "small"
414
elseif a == "-large" then
415
SIZE_SELECT = "large"
416
elseif benchmarks[a] then
417
local p = benchmarks[SIZE_SELECT][a]
418
measure(MIN_TIME, a, tonumber(arg[1]) or p[1], tonumber(arg[2]) or p[2])
419
return
420
else
421
printf("Usage: scimark [-noffi] [-small|-large] [BENCH params...]\n\n")
422
printf("BENCH -small -large\n")
423
printf("---------------------------------------\n")
424
for _,name in ipairs(benchmarks) do
425
printf("%-7s %-13s %s\n", name,
426
fmtparams(unpack(benchmarks.small[name])),
427
fmtparams(unpack(benchmarks.large[name])))
428
end
429
printf("\n")
430
os.exit(1)
431
end
432
end
433
434
local params = benchmarks[SIZE_SELECT]
435
local sum = 0
436
for _,name in ipairs(benchmarks) do
437
sum = sum + measure(MIN_TIME, name, unpack(params[name]))
438
end
439
--printf("\nSciMark %8.2f [%s problem sizes]\n", sum / #benchmarks, SIZE_SELECT)
440
441
end
442
443
bench.runCode(test, "scimark")
444
445