mirror of
https://github.com/godotengine/godot-benchmarks.git
synced 2026-01-05 10:10:08 +03:00
Add Mandelbrot set and Lua-ported algorithm benchmarks (#68)
* Port binary trees and merkle trees * Port nbody and spectral_norm * Format nbody * Create mandelbrot_set.gd * Add algorithm credits * Create hello_world.gd * Make some benchmark inputs smaller so they complete faster
This commit is contained in:
committed by
GitHub
parent
817de0bbd8
commit
b77d4b6414
49
benchmarks/gdscript/binary_trees.gd
Normal file
49
benchmarks/gdscript/binary_trees.gd
Normal file
@@ -0,0 +1,49 @@
|
||||
extends Benchmark
|
||||
|
||||
# Ported from
|
||||
# https://github.com/hanabi1224/Programming-Language-Benchmarks/blob/main/bench/algorithm/binarytrees/1.lua
|
||||
|
||||
|
||||
func bottom_up_tree(depth: int) -> Array:
|
||||
if depth > 0:
|
||||
depth -= 1
|
||||
var left = bottom_up_tree(depth)[0]
|
||||
var right = bottom_up_tree(depth)[1]
|
||||
return [left, right]
|
||||
return [null, null]
|
||||
|
||||
|
||||
func item_check(tree: Array) -> int:
|
||||
if tree[1]:
|
||||
return 1 + item_check(tree[0]) + item_check(tree[1])
|
||||
return 1
|
||||
|
||||
|
||||
func calculate_binary_trees(n: int) -> void:
|
||||
var min_depth := 4
|
||||
var max_depth := maxi(min_depth + 2, n)
|
||||
var stretch_depth := max_depth + 1
|
||||
var stretch_tree := bottom_up_tree(stretch_depth)
|
||||
print(
|
||||
"stretch tree of depth {0}\t check: {1}".format([stretch_depth, item_check(stretch_tree)])
|
||||
)
|
||||
|
||||
var long_lived_tree := bottom_up_tree(max_depth)
|
||||
var max_plus_min_depth := max_depth + min_depth
|
||||
for depth in range(min_depth, max_depth, 2):
|
||||
var iterations := pow(2, max_plus_min_depth - depth)
|
||||
var check := 0
|
||||
for i in iterations:
|
||||
check += item_check(bottom_up_tree(depth))
|
||||
print("{0}\t trees of depth {1}\t check: {2}".format([iterations, depth, check]))
|
||||
print(
|
||||
"long lived tree of depth {0}\t check: {1}".format([max_depth, item_check(long_lived_tree)])
|
||||
)
|
||||
|
||||
|
||||
func benchmark_binary_trees_15() -> void:
|
||||
calculate_binary_trees(15)
|
||||
|
||||
|
||||
func benchmark_binary_trees_18() -> void:
|
||||
calculate_binary_trees(18)
|
||||
5
benchmarks/gdscript/hello_world.gd
Normal file
5
benchmarks/gdscript/hello_world.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends Benchmark
|
||||
|
||||
|
||||
func benchmark_hello_world() -> void:
|
||||
print("Hello world!")
|
||||
60
benchmarks/gdscript/mandelbrot_set.gd
Normal file
60
benchmarks/gdscript/mandelbrot_set.gd
Normal file
@@ -0,0 +1,60 @@
|
||||
extends Benchmark
|
||||
|
||||
const WIDTH := 600
|
||||
const HEIGHT := 400
|
||||
const MAX_ITERATION := 1000
|
||||
|
||||
|
||||
# Method from https://github.com/bliepp/mandelbrot_set_godot/blob/master/shaders/mandelbrot.shader
|
||||
# Licensed under MIT
|
||||
func hsv(hue: float, sat: float, value: float) -> Color:
|
||||
hue = fposmod(hue, 360.0)
|
||||
var h := floori(hue) / 60
|
||||
var f := hue / 60.0 - h
|
||||
var p := value * (1.0 - sat)
|
||||
var q := value * (1.0 - sat * f)
|
||||
var t = value * (1.0 - sat * (1.0 - f))
|
||||
if h == 0 or h == 6:
|
||||
return Color(value, t, p)
|
||||
if h == 1:
|
||||
return Color(q, value, p)
|
||||
if h == 2:
|
||||
return Color(p, value, t)
|
||||
if h == 3:
|
||||
return Color(p, q, value)
|
||||
if h == 4:
|
||||
return Color(t, p, value)
|
||||
return Color(value, p, q)
|
||||
|
||||
|
||||
# Algorithm from
|
||||
# https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set#Optimized_escape_time_algorithms
|
||||
func mandelbrot_set(width: int, height: int, max_iteration: int) -> void:
|
||||
var image := Image.create(width, height, false, Image.FORMAT_RGB8)
|
||||
var ratio := float(width) / float(height)
|
||||
var x_range := 3.6
|
||||
var y_range := x_range / ratio
|
||||
var min_x := -x_range / 2
|
||||
var max_y := y_range / 2
|
||||
for x in image.get_width():
|
||||
for y in image.get_height():
|
||||
var iteration := 0
|
||||
var x0 := min_x + x_range * x / width
|
||||
var y0 := max_y - y_range * y / height
|
||||
var xx := 0.0
|
||||
var yy := 0.0
|
||||
var x2 := 0.0
|
||||
var y2 := 0.0
|
||||
while x2 + y2 <= 4 and iteration < max_iteration:
|
||||
yy = 2 * xx * yy + y0
|
||||
xx = x2 - y2 + x0
|
||||
x2 = xx * xx
|
||||
y2 = yy * yy
|
||||
iteration += 1
|
||||
var m := float(iteration) / float(max_iteration)
|
||||
var color := hsv(360.0 * m, 1.0, ceilf(1.0 - 1.1 * m))
|
||||
image.set_pixel(x, y, color)
|
||||
|
||||
|
||||
func benchmark_mandelbrot_set() -> void:
|
||||
mandelbrot_set(WIDTH, HEIGHT, MAX_ITERATION)
|
||||
79
benchmarks/gdscript/merkle_trees.gd
Normal file
79
benchmarks/gdscript/merkle_trees.gd
Normal file
@@ -0,0 +1,79 @@
|
||||
extends Benchmark
|
||||
|
||||
# Ported from
|
||||
# https://github.com/hanabi1224/Programming-Language-Benchmarks/blob/main/bench/algorithm/merkletrees/1.lua
|
||||
|
||||
|
||||
class TreeNode:
|
||||
var value := -1
|
||||
var left: TreeNode
|
||||
var right: TreeNode
|
||||
var hash_i := -1 # Named that way so it doesn't conflict with the hash method
|
||||
|
||||
func _init(_value: int, _left: TreeNode, _right: TreeNode) -> void:
|
||||
value = _value
|
||||
left = _left
|
||||
right = _right
|
||||
hash_i = -1
|
||||
|
||||
func check() -> bool:
|
||||
if hash_i != -1:
|
||||
if value != -1:
|
||||
return true
|
||||
if left and right:
|
||||
return left.check() and right.check()
|
||||
return false
|
||||
|
||||
func cal_hash() -> void:
|
||||
if hash_i == -1:
|
||||
if value != -1:
|
||||
hash_i = value
|
||||
elif left and right:
|
||||
left.cal_hash()
|
||||
right.cal_hash()
|
||||
hash_i = left.hash_i + right.hash_i
|
||||
|
||||
|
||||
func make_tree(depth: int) -> TreeNode:
|
||||
if depth > 0:
|
||||
depth -= 1
|
||||
return TreeNode.new(-1, make_tree(depth), make_tree(depth))
|
||||
return TreeNode.new(1, null, null)
|
||||
|
||||
|
||||
func calculate_merkle_trees(n: int) -> void:
|
||||
var min_depth := 4
|
||||
var max_depth := maxi(min_depth + 2, n)
|
||||
var stretch_depth := max_depth + 1
|
||||
var stretch_tree := make_tree(stretch_depth)
|
||||
stretch_tree.cal_hash()
|
||||
print(
|
||||
"stretch tree of depth {0}\t root hash: {1} check: {2}".format(
|
||||
[stretch_depth, stretch_tree.hash_i, stretch_tree.check()]
|
||||
)
|
||||
)
|
||||
|
||||
var long_lived_tree := make_tree(max_depth)
|
||||
var max_plus_min_depth := max_depth + min_depth
|
||||
for depth in range(min_depth, max_depth, 2):
|
||||
var iterations := pow(2, max_plus_min_depth - depth)
|
||||
var sum := 0
|
||||
for i in iterations:
|
||||
var tree := make_tree(depth)
|
||||
tree.cal_hash()
|
||||
sum += tree.hash_i
|
||||
print("{0}\t trees of depth {1}\t root hash sum: {2}".format([iterations, depth, sum]))
|
||||
long_lived_tree.cal_hash()
|
||||
print(
|
||||
"long lived tree of depth {0}\t root hash: {1} check: {2}".format(
|
||||
[n, long_lived_tree.hash_i, long_lived_tree.check()]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func benchmark_merkle_trees_13() -> void:
|
||||
calculate_merkle_trees(13)
|
||||
|
||||
|
||||
func benchmark_merkle_trees_15() -> void:
|
||||
calculate_merkle_trees(15)
|
||||
163
benchmarks/gdscript/nbody.gd
Normal file
163
benchmarks/gdscript/nbody.gd
Normal file
@@ -0,0 +1,163 @@
|
||||
extends Benchmark
|
||||
|
||||
# Ported from
|
||||
# https://github.com/hanabi1224/Programming-Language-Benchmarks/blob/main/bench/algorithm/nbody/4.lua
|
||||
|
||||
const SOLAR_MASS := 4 * PI * PI
|
||||
const DAYS_PER_YEAR := 365.24
|
||||
|
||||
|
||||
class Nbody:
|
||||
var x: float
|
||||
var y: float
|
||||
var z: float
|
||||
var vx: float
|
||||
var vy: float
|
||||
var vz: float
|
||||
var mass: float
|
||||
|
||||
func _init(
|
||||
_x: float, _y: float, _z: float, _vx: float, _vy: float, _vz: float, _mass: float
|
||||
) -> void:
|
||||
x = _x
|
||||
y = _y
|
||||
z = _z
|
||||
vx = _vx
|
||||
vy = _vy
|
||||
vz = _vz
|
||||
mass = _mass
|
||||
|
||||
|
||||
var sun := Nbody.new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS)
|
||||
var jupiter := Nbody.new(
|
||||
4.84143144246472090e+00,
|
||||
-1.16032004402742839e+00,
|
||||
-1.03622044471123109e-01,
|
||||
1.66007664274403694e-03 * DAYS_PER_YEAR,
|
||||
7.69901118419740425e-03 * DAYS_PER_YEAR,
|
||||
-6.90460016972063023e-05 * DAYS_PER_YEAR,
|
||||
9.54791938424326609e-04 * SOLAR_MASS
|
||||
)
|
||||
var saturn := (
|
||||
Nbody
|
||||
. new(
|
||||
8.34336671824457987e+00,
|
||||
4.12479856412430479e+00,
|
||||
-4.03523417114321381e-01,
|
||||
-2.76742510726862411e-03 * DAYS_PER_YEAR,
|
||||
4.99852801234917238e-03 * DAYS_PER_YEAR,
|
||||
2.30417297573763929e-05 * DAYS_PER_YEAR,
|
||||
2.85885980666130812e-04 * SOLAR_MASS,
|
||||
)
|
||||
)
|
||||
var uranus := (
|
||||
Nbody
|
||||
. new(
|
||||
1.28943695621391310e+01,
|
||||
-1.51111514016986312e+01,
|
||||
-2.23307578892655734e-01,
|
||||
2.96460137564761618e-03 * DAYS_PER_YEAR,
|
||||
2.37847173959480950e-03 * DAYS_PER_YEAR,
|
||||
-2.96589568540237556e-05 * DAYS_PER_YEAR,
|
||||
4.36624404335156298e-05 * SOLAR_MASS,
|
||||
)
|
||||
)
|
||||
var neptune := (
|
||||
Nbody
|
||||
. new(
|
||||
1.53796971148509165e+01,
|
||||
-2.59193146099879641e+01,
|
||||
1.79258772950371181e-01,
|
||||
2.68067772490389322e-03 * DAYS_PER_YEAR,
|
||||
1.62824170038242295e-03 * DAYS_PER_YEAR,
|
||||
-9.51592254519715870e-05 * DAYS_PER_YEAR,
|
||||
5.15138902046611451e-05 * SOLAR_MASS,
|
||||
)
|
||||
)
|
||||
var bodies: Array[Nbody] = [sun, jupiter, saturn, uranus, neptune]
|
||||
|
||||
|
||||
func advance(nbody: int, dt: float) -> void:
|
||||
for i in nbody:
|
||||
var bi := bodies[i]
|
||||
var bix := bi.x
|
||||
var biy := bi.y
|
||||
var biz := bi.z
|
||||
var bivx := bi.vx
|
||||
var bivy := bi.vy
|
||||
var bivz := bi.vz
|
||||
var bimass := bi.mass
|
||||
for j in range(i + 1, nbody):
|
||||
var bj := bodies[j]
|
||||
var dx := bix - bj.x
|
||||
var dy := biy - bj.y
|
||||
var dz := biz - bj.z
|
||||
var dist2 := dx * dx + dy * dy + dz * dz
|
||||
var mag := sqrt(dist2)
|
||||
mag = dt / (mag * dist2)
|
||||
var bm := bj.mass * mag
|
||||
bivx = bivx - (dx * bm)
|
||||
bivy = bivy - (dy * bm)
|
||||
bivz = bivz - (dz * bm)
|
||||
bm = bimass * mag
|
||||
bj.vx = bj.vx + (dx * bm)
|
||||
bj.vy = bj.vy + (dy * bm)
|
||||
bj.vz = bj.vz + (dz * bm)
|
||||
|
||||
bi.vx = bivx
|
||||
bi.vy = bivy
|
||||
bi.vz = bivz
|
||||
bi.x = bix + dt * bivx
|
||||
bi.y = biy + dt * bivy
|
||||
bi.z = biz + dt * bivz
|
||||
|
||||
|
||||
func energy(nbody: int) -> float:
|
||||
var e := 0.0
|
||||
for i in nbody:
|
||||
var bi := bodies[i]
|
||||
var vx := bi.vx
|
||||
var vy := bi.vy
|
||||
var vz := bi.vz
|
||||
var bim := bi.mass
|
||||
e = e + (0.5 * bim * (vx * vx + vy * vy + vz * vz))
|
||||
for j in range(i + 1, nbody):
|
||||
var bj := bodies[j]
|
||||
var dx := bi.x - bj.x
|
||||
var dy := bi.y - bj.y
|
||||
var dz := bi.z - bj.z
|
||||
var distance := sqrt(dx * dx + dy * dy + dz * dz)
|
||||
e = e - ((bim * bj.mass) / distance)
|
||||
return e
|
||||
|
||||
|
||||
func offset_momentum(b: Array[Nbody], nbody: int):
|
||||
var px := 0.0
|
||||
var py := 0.0
|
||||
var pz := 0.0
|
||||
for i in nbody:
|
||||
var bi := b[i]
|
||||
var bim := bi.mass
|
||||
px = px + (bi.vx * bim)
|
||||
py = py + (bi.vy * bim)
|
||||
pz = pz + (bi.vz * bim)
|
||||
|
||||
b[1].vx = -px / SOLAR_MASS
|
||||
b[1].vy = -py / SOLAR_MASS
|
||||
b[1].vz = -pz / SOLAR_MASS
|
||||
|
||||
|
||||
func calculate_nbody(n: int) -> void:
|
||||
offset_momentum(bodies, bodies.size())
|
||||
print("%.9f" % [energy(bodies.size())])
|
||||
for i in n:
|
||||
advance(bodies.size(), 0.01)
|
||||
print("%.9f" % [energy(bodies.size())])
|
||||
|
||||
|
||||
func benchmark_nbody_500_000() -> void:
|
||||
calculate_nbody(500_000)
|
||||
|
||||
|
||||
func benchmark_nbody_1_000_000() -> void:
|
||||
calculate_nbody(1_000_000)
|
||||
61
benchmarks/gdscript/spectral_norm.gd
Normal file
61
benchmarks/gdscript/spectral_norm.gd
Normal file
@@ -0,0 +1,61 @@
|
||||
extends Benchmark
|
||||
|
||||
# Ported from
|
||||
# https://github.com/hanabi1224/Programming-Language-Benchmarks/blob/main/bench/algorithm/spectral-norm/1.lua
|
||||
|
||||
|
||||
func eval_a(i: int, j: int) -> float:
|
||||
var ij := i + j - 1
|
||||
return 1.0 / (ij * (ij - 1) * 0.5 + i)
|
||||
|
||||
|
||||
func av(x, y, n: int) -> void:
|
||||
for i in n:
|
||||
var a := 0.0
|
||||
for j in n:
|
||||
a = a + x[j] * eval_a(i, j)
|
||||
y[i] = a
|
||||
|
||||
|
||||
func atv(x, y, n: int) -> void:
|
||||
for i in n:
|
||||
var a := 0.0
|
||||
for j in n:
|
||||
a = a + x[j] * eval_a(j, i)
|
||||
y[i] = a
|
||||
|
||||
|
||||
func at_av(x, y, t, n: int) -> void:
|
||||
av(x, t, n)
|
||||
atv(t, y, n)
|
||||
|
||||
|
||||
func calculate_spectral_norm(n: int) -> void:
|
||||
var u := {}
|
||||
var v := {}
|
||||
var t := {}
|
||||
for i in n:
|
||||
u[i] = 1
|
||||
for i in 10:
|
||||
at_av(u, v, t, n)
|
||||
at_av(v, u, t, n)
|
||||
var vbv := 0.0
|
||||
var vv := 0.0
|
||||
for i in n:
|
||||
var ui = u[i]
|
||||
var vi = v[i]
|
||||
vbv += ui * vi
|
||||
vv += vi * vi
|
||||
print("%.9f" % sqrt(vbv / vv))
|
||||
|
||||
|
||||
func benchmark_spectral_norm_100() -> void:
|
||||
calculate_spectral_norm(500)
|
||||
|
||||
|
||||
func benchmark_spectral_norm_500() -> void:
|
||||
calculate_spectral_norm(1000)
|
||||
|
||||
|
||||
func benchmark_spectral_norm_1000() -> void:
|
||||
calculate_spectral_norm(1000)
|
||||
Reference in New Issue
Block a user