1
------------------------------------------------------------------------------
2
-- Lua SciMark (2010-12-20).
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.
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:
18
-- The above copyright notice and this permission notice shall be
19
-- included in all copies or substantial portions of the Software.
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.
29
-- [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
30
------------------------------------------------------------------------------
32
local SCIMARK_VERSION = "2010-12-10"
33
local SCIMARK_COPYRIGHT = "Copyright (C) 2006-2010 Mike Pall"
36
local RANDOM_SEED = 101009 -- Must be odd.
37
local SIZE_SELECT = "small"
40
"FFT", "SOR", "MC", "SPARSE", "LU",
45
SPARSE = { 1000, 5000 },
52
SPARSE = { 100000, 1000000 },
57
local abs, log, sin, floor = math.abs, math.log, math.sin, math.floor
58
local pi, clock = math.pi, os.clock
59
local format = string.format
61
------------------------------------------------------------------------------
62
-- Select array type: Lua tables or native (FFI) arrays
63
------------------------------------------------------------------------------
67
local function array_init()
68
if jit and jit.status and jit.status() then
69
local ok, ffi = pcall(require, "ffi")
71
darray = ffi.typeof("double[?]")
72
iarray = ffi.typeof("int[?]")
76
function darray(n) return {} end
80
------------------------------------------------------------------------------
81
-- This is a Lagged Fibonacci Pseudo-random Number Generator with
82
-- j, k, M = 5, 17, 31. Pretty weak, but same as C/Java SciMark.
83
------------------------------------------------------------------------------
87
if jit and jit.status and jit.status() then
88
-- LJ2 has bit operations and zero-based arrays (internally).
89
local bit = require("bit")
90
local band, sar = bit.band, bit.arshift
91
function rand_init(seed)
92
local Rm, Rj, Ri = iarray(17), 16, 11
93
for i=0,16 do Rm[i] = 0 end
95
seed = band(seed*9069, 0x7fffffff)
99
local i = band(Ri+1, sar(Ri-16, 31))
100
local j = band(Rj+1, sar(Rj-16, 31))
102
local k = band(Rm[i] - Rm[j], 0x7fffffff)
104
return k * (1.0/2147483647.0)
108
-- Better for standard Lua with one-based arrays and without bit operations.
109
function rand_init(seed)
111
for i=1,17 do Rm[i] = 0 end
113
seed = (seed*9069) % (2^31)
119
if h < 1 then h = h + 17 end
120
local k = m[h] - m[j]
121
if k < 0 then k = k + 2147483647 end
123
if j < 17 then Rj = j + 1 else Rj = 1 end
124
return k * (1.0/2147483647.0)
129
local function random_vector(n)
130
local v = darray(n+1)
131
for x=1,n do v[x] = rand() end
135
local function random_matrix(m, n)
138
local v = darray(n+1)
140
for x=1,n do v[x] = rand() end
145
------------------------------------------------------------------------------
146
-- FFT: Fast Fourier Transform.
147
------------------------------------------------------------------------------
149
local function fft_bitreverse(v, n)
153
v[i+1], v[i+2], v[j+1], v[j+2] = v[j+1], v[j+2], v[i+1], v[i+2]
156
while k <= j do j = j - k; k = k / 2 end
161
local function fft_transform(v, n, dir)
162
if n <= 1 then return end
167
for i=1,2*n-1,2*dual2 do
169
local ir, ii = v[i], v[i+1]
170
local jr, ji = v[j], v[j+1]
171
v[j], v[j+1] = ir - jr, ii - ji
172
v[i], v[i+1] = ir + jr, ii + ji
174
local theta = dir * pi / dual
175
local s, s2 = sin(theta), 2.0 * sin(theta * 0.5)^2
176
local wr, wi = 1.0, 0.0
178
wr, wi = wr - s*wi - s2*wr, wi + s*wr - s2*wi
179
for i=a,a+2*(n-dual2),2*dual2 do
181
local jr, ji = v[j], v[j+1]
182
local dr, di = wr*jr - wi*ji, wr*ji + wi*jr
183
local ir, ii = v[i], v[i+1]
184
v[j], v[j+1] = ir - dr, ii - di
185
v[i], v[i+1] = ir + dr, ii + di
192
function benchmarks.FFT(n)
193
local l2n = log(n)/log(2)
195
io.stderr:write("Error: FFT data length is not a power of 2\n")
198
local v = random_vector(n*2)
199
return function(cycles)
202
fft_transform(v, n, -1)
203
fft_transform(v, n, 1)
204
for i=1,n*2 do v[i] = v[i] * norm end
206
return ((5*n-2)*l2n + 2*(n+1)) * cycles
210
------------------------------------------------------------------------------
211
-- SOR: Jacobi Successive Over-Relaxation.
212
------------------------------------------------------------------------------
214
local function sor_run(mat, m, n, cycles, omega)
215
local om4, om1 = omega*0.25, 1.0-omega
220
local v, vp, vn = mat[y], mat[y-1], mat[y+1]
222
v[x] = om4*((vp[x]+vn[x])+(v[x-1]+v[x+1])) + om1*v[x]
228
function benchmarks.SOR(n)
229
local mat = random_matrix(n, n)
230
return function(cycles)
231
sor_run(mat, n, n, cycles, 1.25)
232
return (n-1)*(n-1)*cycles*6
236
------------------------------------------------------------------------------
237
-- MC: Monte Carlo Integration.
238
------------------------------------------------------------------------------
240
local function mc_integrate(cycles)
241
local under_curve = 0
246
if x*x + y*y <= 1.0 then under_curve = under_curve + 1 end
248
return (under_curve/cycles) * 4
251
function benchmarks.MC()
252
return function(cycles)
253
local res = mc_integrate(cycles)
254
assert(math.sqrt(cycles)*math.abs(res-math.pi) < 5.0, "bad MC result")
255
return cycles * 4 -- Way off, but same as SciMark in C/Java.
259
------------------------------------------------------------------------------
260
-- Sparse Matrix Multiplication.
261
------------------------------------------------------------------------------
263
local function sparse_mult(n, cycles, vy, val, row, col, vx)
267
for i=row[r],row[r+1]-1 do sum = sum + vx[col[i]] * val[i] end
273
function benchmarks.SPARSE(n, nz)
274
local nr = floor(nz/n)
276
local vx = random_vector(n)
277
local val = random_vector(anz)
278
local vy, col, row = darray(n+1), iarray(nz+1), iarray(n+2)
281
local step = floor(r/nr)
282
if step < 1 then step = 1 end
285
for i=0,nr-1 do col[rr+i] = 1+i*step end
287
return function(cycles)
288
sparse_mult(n, cycles, vy, val, row, col, vx)
293
------------------------------------------------------------------------------
294
-- LU: Dense Matrix Factorization.
295
------------------------------------------------------------------------------
297
local function lu_factor(a, pivot, m, n)
298
local min_m_n = m < n and m or n
300
local jp, t = j, abs(a[j][j])
302
local ab = abs(a[i][j])
309
if a[jp][j] == 0 then error("zero pivot") end
310
if jp ~= j then a[j], a[jp] = a[jp], a[j] end
312
local recp = 1.0 / a[j][j]
320
local vi, vj = a[i], a[j]
322
for k=j+1,n do vi[k] = vi[k] - eij * vj[k] end
328
local function matrix_alloc(m, n)
330
for y=1,m do a[y] = darray(n+1) end
334
local function matrix_copy(dst, src, m, n)
336
local vd, vs = dst[y], src[y]
337
for x=1,n do vd[x] = vs[x] end
341
function benchmarks.LU(n)
342
local mat = random_matrix(n, n)
343
local tmp = matrix_alloc(n, n)
344
local pivot = iarray(n+1)
345
return function(cycles)
347
matrix_copy(tmp, mat, n, n)
348
lu_factor(tmp, pivot, n, n)
350
return 2.0/3.0*n*n*n*cycles
354
------------------------------------------------------------------------------
356
------------------------------------------------------------------------------
358
local function printf(...)
359
io.write(format(...))
362
local function fmtparams(p1, p2)
363
if p2 then return format("[%d, %d]", p1, p2)
364
elseif p1 then return format("[%d]", p1) end
368
local function measure(min_time, name, ...)
370
rand_init(RANDOM_SEED)
371
local run = benchmarks[name](...)
375
local flops = run(cycles, ...)
377
if tm >= min_time then
378
local res = flops / tm * 1.0e-6
380
printf("%-7s %8.2f %s\n", name, res, fmtparams(...))
387
--printf("Lua SciMark %s based on SciMark 2.0a. %s.\n\n",
388
-- SCIMARK_VERSION, SCIMARK_COPYRIGHT)
390
while arg and arg[1] do
391
local a = table.remove(arg, 1)
392
if a == "-noffi" then
393
package.preload.ffi = nil
394
elseif a == "-small" then
395
SIZE_SELECT = "small"
396
elseif a == "-large" then
397
SIZE_SELECT = "large"
398
elseif benchmarks[a] then
399
local p = benchmarks[SIZE_SELECT][a]
400
measure(MIN_TIME, a, tonumber(arg[1]) or p[1], tonumber(arg[2]) or p[2])
403
printf("Usage: scimark [-noffi] [-small|-large] [BENCH params...]\n\n")
404
printf("BENCH -small -large\n")
405
printf("---------------------------------------\n")
406
for _,name in ipairs(benchmarks) do
407
printf("%-7s %-13s %s\n", name,
408
fmtparams(unpack(benchmarks.small[name])),
409
fmtparams(unpack(benchmarks.large[name])))
416
local params = benchmarks[SIZE_SELECT]
418
for _,name in ipairs(benchmarks) do
419
sum = sum + measure(MIN_TIME, name, unpack(params[name]))
421
printf("\nSciMark %8.2f [%s problem sizes]\n", sum / #benchmarks, SIZE_SELECT)