-
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Port GDScript benchmarks to C# (#84)
- Loading branch information
1 parent
b8827a4
commit bfd8458
Showing
11 changed files
with
1,091 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
using Godot; | ||
|
||
public partial class Alloc : Benchmark | ||
{ | ||
const int ITERATIONS = 100_000; | ||
|
||
void BenchmarkDeepTree() | ||
{ | ||
Node rt = new Node(); | ||
for (int i = 0; i < ITERATIONS; i++) | ||
{ | ||
Node n = new Node(); | ||
n.AddChild(rt); | ||
rt = n; | ||
} | ||
|
||
// Avoid triggering a stack overflow with rt.Free() | ||
while (rt.GetChildCount() != 0) | ||
{ | ||
Node n = rt.GetChild(0); | ||
rt.RemoveChild(n); | ||
rt.Free(); | ||
rt = n; | ||
} | ||
rt.Free(); | ||
} | ||
|
||
void BenchmarkWideTree() | ||
{ | ||
Node rt = new Node(); | ||
for (int i = 0; i < ITERATIONS; i++) | ||
{ | ||
rt.AddChild(new Node()); | ||
} | ||
rt.Free(); | ||
} | ||
|
||
void BenchmarkFragmentation() | ||
{ | ||
Node top = new Node(); | ||
for (int i = 0; i < 5; i++) | ||
{ | ||
top.AddChild(new Node()); | ||
} | ||
|
||
for (int k = 0; k < 10; k++) { | ||
for (int i = 0; i < ITERATIONS; i++) | ||
{ | ||
// Attempt to scatter children in memory by assigning newly created nodes to a random parent | ||
int idx = (int)GD.Randi() % top.GetChildCount(); | ||
top.GetChild(idx).AddChild(new Node()); | ||
} | ||
|
||
Node tmp = top.GetChild(0); | ||
top.RemoveChild(tmp); | ||
// Since nodes in the tree are scattered in memory, | ||
// freeing subtrees this way should maximize fragmentation. | ||
tmp.Free(); | ||
top.AddChild(new Node()); | ||
//GD.Print("Iteration %d: %.3f MB" % [k, Performance.get_monitor(Performance.MEMORY_STATIC) / 1e6]) | ||
} | ||
|
||
top.Free(); | ||
} | ||
|
||
void BenchmarkDuplicate() | ||
{ | ||
Node rt = new Node(); | ||
for (int i = 0; i < 16; i++) | ||
{ | ||
Node n = new Node(); | ||
n.AddChild(rt.Duplicate()); | ||
n.AddChild(rt.Duplicate()); | ||
rt.Free(); | ||
rt = n; | ||
//GD.Print("Iteration %d: %.3f MB" % [i, Performance.get_monitor(Performance.MEMORY_STATIC) / 1e6]) | ||
} | ||
rt.Free(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
using Godot; | ||
|
||
public partial class BinaryTrees : Benchmark | ||
{ | ||
// Based on https://github.com/hanabi1224/Programming-Language-Benchmarks/blob/main/bench/algorithm/binarytrees/1.cs | ||
class TreeNode | ||
{ | ||
public TreeNode left; | ||
public TreeNode right; | ||
|
||
TreeNode(TreeNode left = null, TreeNode right = null) | ||
{ | ||
this.left = left; | ||
this.right = right; | ||
} | ||
|
||
internal static TreeNode Create(int d) | ||
{ | ||
return d == 0 ? new TreeNode() | ||
: new TreeNode(Create(d - 1), Create(d - 1)); | ||
} | ||
|
||
internal int Check() | ||
{ | ||
int c = 1; | ||
if (right != null) | ||
{ | ||
c += right.Check(); | ||
} | ||
if (left != null) | ||
{ | ||
c += left.Check(); | ||
} | ||
return c; | ||
} | ||
} | ||
|
||
const int MinDepth = 4; | ||
public void CalculateBinaryTrees(int input) | ||
{ | ||
int maxDepth = Mathf.Max(MinDepth + 2, input); | ||
|
||
int stretchDepth = maxDepth + 1; | ||
GD.Print($"stretch tree of depth {stretchDepth}\t check: {TreeNode.Create(stretchDepth).Check()}"); | ||
|
||
TreeNode longLivedTree = TreeNode.Create(maxDepth); | ||
int maxPlusMinDepth = maxDepth + MinDepth; | ||
for (int depth = MinDepth; depth < maxDepth; depth += 2) | ||
{ | ||
int iterations = 1 << (maxPlusMinDepth - depth); | ||
int check = 0; | ||
for (int i = 0; i < iterations; i++) | ||
{ | ||
check += TreeNode.Create(depth).Check(); | ||
} | ||
|
||
GD.Print($"{iterations}\t trees of depth {depth}\t check: {check}"); | ||
} | ||
|
||
GD.Print($"long lived tree of depth {maxDepth}\t check: {longLivedTree.Check()}"); | ||
} | ||
|
||
public void BenchmarkBinaryTrees13() | ||
{ | ||
CalculateBinaryTrees(13); | ||
} | ||
|
||
public void BenchmarkBinaryTrees15() | ||
{ | ||
CalculateBinaryTrees(15); | ||
} | ||
|
||
public void BenchmarkBinaryTrees18() | ||
{ | ||
CalculateBinaryTrees(18); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using Godot; | ||
|
||
public partial class HelloWorld : Benchmark | ||
{ | ||
public void BenchmarkHelloWorld() | ||
{ | ||
GD.Print("Hello world!"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
|
||
public partial class LambdaPerformance : Benchmark | ||
{ | ||
const int ITERATIONS = 1_000_000; | ||
Action lambda = () => { }; | ||
|
||
public void BenchmarkLambdaCall() | ||
{ | ||
for(int i = 0; i < ITERATIONS; i++) | ||
{ | ||
lambda(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using Godot; | ||
|
||
public partial class MandelbrotSet : Benchmark | ||
{ | ||
const int WIDTH = 600; | ||
const int HEIGHT = 400; | ||
const int MAX_ITERATION = 1000; | ||
|
||
private Color HSV(float hue, float sat, float value) | ||
{ | ||
hue = Mathf.PosMod(hue, 360.0f); | ||
int h = Mathf.FloorToInt(hue) / 60; | ||
float f = hue / 60.0f - h; | ||
float p = value * (1.0f - sat); | ||
float q = value * (1.0f - sat * f); | ||
float t = value * (1.0f - sat * (1.0f - f)); | ||
if (h == 0 || h == 6) | ||
return new Color(value, t, p); | ||
if (h == 1) | ||
return new Color(q, value, p); | ||
if (h == 2) | ||
return new Color(p, value, t); | ||
if (h == 3) | ||
return new Color(p, q, value); | ||
if (h == 4) | ||
return new Color(t, p, value); | ||
return new Color(value, p, q); | ||
} | ||
|
||
// Algorithm from | ||
// https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set#Optimized_escape_time_algorithms | ||
private void mandelbrot_set(int width, int height, int maxIteration) | ||
{ | ||
Image image = Image.CreateEmpty(width, height, false, Image.Format.Rgb8); | ||
float ratio = (float)width / (float)height; | ||
float xRange = 3.6f; | ||
float yRange = xRange / ratio; | ||
float minX = -xRange / 2.0f; | ||
float maxY = yRange / 2.0f; | ||
for (int x = 0; x < image.GetWidth(); x++) | ||
{ | ||
for (int y = 0; y < image.GetHeight(); y++) | ||
{ | ||
int iteration = 0; | ||
float x0 = minX + xRange * x / width; | ||
float y0 = maxY - yRange * y / height; | ||
float xx = 0.0f; | ||
float yy = 0.0f; | ||
float x2 = 0.0f; | ||
float y2 = 0.0f; | ||
while (x2 + y2 <= 4 && iteration < maxIteration) | ||
{ | ||
yy = 2 * xx * yy + y0; | ||
xx = x2 - y2 + x0; | ||
x2 = xx * xx; | ||
y2 = yy * yy; | ||
iteration += 1; | ||
} | ||
float m = (float)iteration / (float)maxIteration; | ||
Color color = HSV(360.0f * m, 1.0f, Mathf.Ceil(1.0f - 1.1f * m)); | ||
image.SetPixel(x, y, color); | ||
} | ||
} | ||
} | ||
|
||
public void BenchmarkMandelbrotSet() | ||
{ | ||
mandelbrot_set(WIDTH, HEIGHT, MAX_ITERATION); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
using Godot; | ||
|
||
public partial class MerkleTrees : Benchmark | ||
{ | ||
// Based on https://github.com/hanabi1224/Programming-Language-Benchmarks/blob/main/bench/algorithm/merkletrees/1.cs | ||
class TreeNode | ||
{ | ||
public long? value; | ||
public long? hash; | ||
public TreeNode left; | ||
public TreeNode right; | ||
|
||
public TreeNode(long? value, TreeNode left = null, TreeNode right = null) | ||
{ | ||
this.value = value; | ||
this.left = left; | ||
this.right = right; | ||
} | ||
|
||
public static TreeNode Create(int d) | ||
{ | ||
return d == 0 ? new TreeNode(1L, null, null) | ||
: new TreeNode(null, Create(d - 1), Create(d - 1)); | ||
} | ||
|
||
public bool Check() | ||
{ | ||
if (hash != null) | ||
{ | ||
if (value != null) | ||
{ | ||
return true; | ||
} | ||
else if (left != null && right != null) | ||
{ | ||
return left.Check() && right.Check(); | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
public long GetHash() | ||
{ | ||
if (hash.Value is long v) | ||
{ | ||
return v; | ||
} | ||
return default; | ||
} | ||
|
||
public void CalHash() | ||
{ | ||
if (hash == null) | ||
{ | ||
if (value.HasValue) | ||
{ | ||
hash = value; | ||
} | ||
else if (left != null && right != null) | ||
{ | ||
left.CalHash(); | ||
right.CalHash(); | ||
hash = left.GetHash() + right.GetHash(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
const int MinDepth = 4; | ||
public static void CalculateMerkleTrees(int input) | ||
{ | ||
int maxDepth = Mathf.Max(MinDepth + 2, input); | ||
|
||
int stretchDepth = maxDepth + 1; | ||
TreeNode stretchTree = TreeNode.Create(stretchDepth); | ||
stretchTree.CalHash(); | ||
GD.Print($"stretch tree of depth {stretchDepth}\t root hash: {stretchTree.GetHash()} check: {stretchTree.Check().ToString().ToLowerInvariant()}"); | ||
|
||
TreeNode longLivedTree = TreeNode.Create(maxDepth); | ||
int maxPlusMinDepth = maxDepth + MinDepth; | ||
for (int depth = MinDepth; depth < maxDepth; depth += 2) | ||
{ | ||
int iterations = 1 << (maxPlusMinDepth - depth); | ||
long sum = 0; | ||
for (int i = 0; i < iterations; i++) | ||
{ | ||
TreeNode tree = TreeNode.Create(depth); | ||
tree.CalHash(); | ||
sum += tree.GetHash(); | ||
} | ||
GD.Print($"{iterations}\t trees of depth {depth}\t root hash sum: {sum}"); | ||
} | ||
|
||
longLivedTree.CalHash(); | ||
GD.Print($"long lived tree of depth {maxDepth}\t root hash: {longLivedTree.GetHash()} check: {longLivedTree.Check().ToString().ToLowerInvariant()}"); | ||
} | ||
|
||
public void BenchmarkMerkleTrees13() | ||
{ | ||
CalculateMerkleTrees(13); | ||
} | ||
|
||
public void BenchmarkMerkleTrees15() | ||
{ | ||
CalculateMerkleTrees(15); | ||
} | ||
|
||
public void BenchmarkMerkleTrees18() | ||
{ | ||
CalculateMerkleTrees(18); | ||
} | ||
} |
Oops, something went wrong.