Skip to content

Commit 2e335b5

Browse files
committed
[GR-13417] Add aobench benchmark
PullRequest: truffleruby/3467
2 parents d6465a4 + 87df90f commit 2e335b5

File tree

2 files changed

+296
-0
lines changed

2 files changed

+296
-0
lines changed

bench/classic/aobench.rb

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
# coding: BINARY
2+
3+
# From https://github.com/ruby/ruby/blob/master/benchmark/app_aobench.rb
4+
# with the encoding comment fixed, with validation and adapted for benchmark-interface
5+
6+
# AO render benchmark
7+
# Original program (C) Syoyo Fujita in Javascript (and other languages)
8+
# https://code.google.com/p/aobench/
9+
# Ruby(yarv2llvm) version by Hideki Miura
10+
#
11+
12+
IMAGE_WIDTH = 256
13+
IMAGE_HEIGHT = 256
14+
NSUBSAMPLES = 2
15+
NAO_SAMPLES = 8
16+
17+
class Vec
18+
def initialize(x, y, z)
19+
@x = x
20+
@y = y
21+
@z = z
22+
end
23+
24+
attr_accessor :x, :y, :z
25+
26+
def vadd(b)
27+
Vec.new(@x + b.x, @y + b.y, @z + b.z)
28+
end
29+
30+
def vsub(b)
31+
Vec.new(@x - b.x, @y - b.y, @z - b.z)
32+
end
33+
34+
def vcross(b)
35+
Vec.new(@y * b.z - @z * b.y,
36+
@z * b.x - @x * b.z,
37+
@x * b.y - @y * b.x)
38+
end
39+
40+
def vdot(b)
41+
@x * b.x + @y * b.y + @z * b.z
42+
end
43+
44+
def vlength
45+
Math.sqrt(@x * @x + @y * @y + @z * @z)
46+
end
47+
48+
def vnormalize
49+
len = vlength
50+
v = Vec.new(@x, @y, @z)
51+
if len > 1.0e-17 then
52+
v.x = v.x / len
53+
v.y = v.y / len
54+
v.z = v.z / len
55+
end
56+
v
57+
end
58+
end
59+
60+
61+
class Sphere
62+
def initialize(center, radius)
63+
@center = center
64+
@radius = radius
65+
end
66+
67+
attr_reader :center, :radius
68+
69+
def intersect(ray, isect)
70+
rs = ray.org.vsub(@center)
71+
b = rs.vdot(ray.dir)
72+
c = rs.vdot(rs) - (@radius * @radius)
73+
d = b * b - c
74+
if d > 0.0 then
75+
t = - b - Math.sqrt(d)
76+
77+
if t > 0.0 and t < isect.t then
78+
isect.t = t
79+
isect.hit = true
80+
isect.pl = Vec.new(ray.org.x + ray.dir.x * t,
81+
ray.org.y + ray.dir.y * t,
82+
ray.org.z + ray.dir.z * t)
83+
n = isect.pl.vsub(@center)
84+
isect.n = n.vnormalize
85+
else
86+
0.0
87+
end
88+
end
89+
nil
90+
end
91+
end
92+
93+
class Plane
94+
def initialize(p, n)
95+
@p = p
96+
@n = n
97+
end
98+
99+
def intersect(ray, isect)
100+
d = -@p.vdot(@n)
101+
v = ray.dir.vdot(@n)
102+
v0 = v
103+
if v < 0.0 then
104+
v0 = -v
105+
end
106+
if v0 < 1.0e-17 then
107+
return
108+
end
109+
110+
t = -(ray.org.vdot(@n) + d) / v
111+
112+
if t > 0.0 and t < isect.t then
113+
isect.hit = true
114+
isect.t = t
115+
isect.n = @n
116+
isect.pl = Vec.new(ray.org.x + t * ray.dir.x,
117+
ray.org.y + t * ray.dir.y,
118+
ray.org.z + t * ray.dir.z)
119+
end
120+
nil
121+
end
122+
end
123+
124+
class Ray
125+
def initialize(org, dir)
126+
@org = org
127+
@dir = dir
128+
end
129+
130+
attr_accessor :org, :dir
131+
end
132+
133+
class Isect
134+
def initialize
135+
@t = 10000000.0
136+
@hit = false
137+
@pl = Vec.new(0.0, 0.0, 0.0)
138+
@n = Vec.new(0.0, 0.0, 0.0)
139+
end
140+
141+
attr_accessor :t, :hit, :pl, :n
142+
end
143+
144+
def clamp(f)
145+
i = f * 255.5
146+
if i > 255.0 then
147+
i = 255.0
148+
end
149+
if i < 0.0 then
150+
i = 0.0
151+
end
152+
i.to_i
153+
end
154+
155+
def otherBasis(basis, n)
156+
basis[2] = Vec.new(n.x, n.y, n.z)
157+
basis[1] = Vec.new(0.0, 0.0, 0.0)
158+
159+
if n.x < 0.6 and n.x > -0.6 then
160+
basis[1].x = 1.0
161+
elsif n.y < 0.6 and n.y > -0.6 then
162+
basis[1].y = 1.0
163+
elsif n.z < 0.6 and n.z > -0.6 then
164+
basis[1].z = 1.0
165+
else
166+
basis[1].x = 1.0
167+
end
168+
169+
basis[0] = basis[1].vcross(basis[2])
170+
basis[0] = basis[0].vnormalize
171+
172+
basis[1] = basis[2].vcross(basis[0])
173+
basis[1] = basis[1].vnormalize
174+
end
175+
176+
class Scene
177+
def initialize
178+
srand(0)
179+
@spheres = Array.new
180+
@spheres[0] = Sphere.new(Vec.new(-2.0, 0.0, -3.5), 0.5)
181+
@spheres[1] = Sphere.new(Vec.new(-0.5, 0.0, -3.0), 0.5)
182+
@spheres[2] = Sphere.new(Vec.new(1.0, 0.0, -2.2), 0.5)
183+
@plane = Plane.new(Vec.new(0.0, -0.5, 0.0), Vec.new(0.0, 1.0, 0.0))
184+
end
185+
186+
def ambient_occlusion(isect)
187+
basis = Array.new
188+
otherBasis(basis, isect.n)
189+
190+
ntheta = NAO_SAMPLES
191+
nphi = NAO_SAMPLES
192+
eps = 0.0001
193+
occlusion = 0.0
194+
195+
p0 = Vec.new(isect.pl.x + eps * isect.n.x,
196+
isect.pl.y + eps * isect.n.y,
197+
isect.pl.z + eps * isect.n.z)
198+
nphi.times do |j|
199+
ntheta.times do |i|
200+
r = rand
201+
phi = 2.0 * 3.14159265 * rand
202+
x = Math.cos(phi) * Math.sqrt(1.0 - r)
203+
y = Math.sin(phi) * Math.sqrt(1.0 - r)
204+
z = Math.sqrt(r)
205+
206+
rx = x * basis[0].x + y * basis[1].x + z * basis[2].x
207+
ry = x * basis[0].y + y * basis[1].y + z * basis[2].y
208+
rz = x * basis[0].z + y * basis[1].z + z * basis[2].z
209+
210+
raydir = Vec.new(rx, ry, rz)
211+
ray = Ray.new(p0, raydir)
212+
213+
occisect = Isect.new
214+
@spheres[0].intersect(ray, occisect)
215+
@spheres[1].intersect(ray, occisect)
216+
@spheres[2].intersect(ray, occisect)
217+
@plane.intersect(ray, occisect)
218+
if occisect.hit then
219+
occlusion = occlusion + 1.0
220+
else
221+
0.0
222+
end
223+
end
224+
end
225+
226+
occlusion = (ntheta.to_f * nphi.to_f - occlusion) / (ntheta.to_f * nphi.to_f)
227+
228+
Vec.new(occlusion, occlusion, occlusion)
229+
end
230+
231+
def render(w, h, nsubsamples, result)
232+
cnt = 0
233+
nsf = nsubsamples.to_f
234+
h.times do |y|
235+
w.times do |x|
236+
rad = Vec.new(0.0, 0.0, 0.0)
237+
238+
# Subsampling
239+
nsubsamples.times do |v|
240+
nsubsamples.times do |u|
241+
242+
cnt = cnt + 1
243+
wf = w.to_f
244+
hf = h.to_f
245+
xf = x.to_f
246+
yf = y.to_f
247+
uf = u.to_f
248+
vf = v.to_f
249+
250+
px = (xf + (uf / nsf) - (wf / 2.0)) / (wf / 2.0)
251+
py = -(yf + (vf / nsf) - (hf / 2.0)) / (hf / 2.0)
252+
253+
eye = Vec.new(px, py, -1.0).vnormalize
254+
255+
ray = Ray.new(Vec.new(0.0, 0.0, 0.0), eye)
256+
257+
isect = Isect.new
258+
@spheres[0].intersect(ray, isect)
259+
@spheres[1].intersect(ray, isect)
260+
@spheres[2].intersect(ray, isect)
261+
@plane.intersect(ray, isect)
262+
if isect.hit then
263+
col = ambient_occlusion(isect)
264+
rad.x = rad.x + col.x
265+
rad.y = rad.y + col.y
266+
rad.z = rad.z + col.z
267+
end
268+
end
269+
end
270+
271+
r = rad.x / (nsf * nsf)
272+
g = rad.y / (nsf * nsf)
273+
b = rad.z / (nsf * nsf)
274+
result << sprintf("%c", clamp(r))
275+
result << sprintf("%c", clamp(g))
276+
result << sprintf("%c", clamp(b))
277+
end
278+
nil
279+
end
280+
281+
nil
282+
end
283+
end
284+
285+
benchmark do
286+
result = "".b
287+
result << "P6\n"
288+
result << sprintf("%d %d\n", IMAGE_WIDTH, IMAGE_HEIGHT)
289+
result << "255\n"
290+
Scene.new.render(IMAGE_WIDTH, IMAGE_HEIGHT, NSUBSAMPLES, result)
291+
# File.write("ao.ppm", result)
292+
result
293+
end.verify do |result|
294+
result.sum == 41835
295+
end

mx.truffleruby/mx_truffleruby_benchmark.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ def runBenchmark(self, benchmark, bmSuiteArgs):
380380
}]
381381

382382
classic_benchmarks = [
383+
'aobench',
383384
'binary-trees',
384385
'deltablue',
385386
'fannkuch',

0 commit comments

Comments
 (0)