Port GDScript benchmarks to C++ (#86)

Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
This commit is contained in:
Emmanouil Papadeas
2024-08-05 00:13:59 +03:00
committed by GitHub
parent bfd8458b7a
commit 460494848a
42 changed files with 306064 additions and 8 deletions

2
.gitignore vendored
View File

@@ -32,7 +32,7 @@ __pycache__/
venv
# Godot Git repository clone (run-benchmarks.sh)
godot/
/godot/
# Output HTML files
web/public/

4
.gitmodules vendored Normal file
View File

@@ -0,0 +1,4 @@
[submodule "gdextension/godot-cpp"]
path = gdextension/godot-cpp
url = https://github.com/godotengine/godot-cpp.git
branch = master

View File

@@ -8,6 +8,26 @@ such as rendering and scripting.
## Running benchmarks
### Setup
To be able to run C# benchmarks, you need to use a .NET build of Godot. If not
using a .NET build, the project will still be able to run GDScript and C++
benchmarks (if compiled), but C# benchmarks won't run.
To be able to run C++ benchmarks, you need to compile the GDExtension for your
platform in the [`gdextension/`](gdextension/) folder. To do so, run the
following commands in that folder:
```bash
cd gdextension/
git submodule update --init --recursive
scons
scons target=template_release
```
Remember to recompile the extension after any changes to the C++ code have been
made, so that the changes are reflected when running benchmarks.
### Using a graphical interface
Open the project in the editor, then run it from the editor or from an export
@@ -17,7 +37,7 @@ in the bottom-right corner.
Once benchmarks are run, you can copy the results JSON using the
**Copy JSON to Clipboard** button at the bottom. The results JSON is also printed to
standard output, which you can see if you're running the project from a terminal.
v
### Using the command line
After opening the project in the editor (required so that resources can be imported),

19
gdextension/.gitignore vendored Normal file
View File

@@ -0,0 +1,19 @@
# Compiled binaries from the GDExtension used for C++ benchmarks
*.o
*.os
*.so
*.dll
*.framework
*.dylib
*.obj
*.bc
*.pyc
*.dblite
*.pdb
*.lib
*.config
*.creator
*.creator.user
*.files
*.includes
*.idb

33
gdextension/SConstruct Normal file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env python
import os
import sys
env = SConscript("godot-cpp/SConstruct")
# For reference:
# - CCFLAGS are compilation flags shared between C and C++
# - CFLAGS are for C-specific compilation flags
# - CXXFLAGS are for C++-specific compilation flags
# - CPPFLAGS are for pre-processor flags
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags
# tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPPATH=["src/"])
sources = Glob("src/*.cpp")
sources.extend(Glob("src/benchmarks/*.cpp"))
if env["platform"] == "macos":
library = env.SharedLibrary(
"bin/libcppbenchmarks.{}.{}.framework/libcppbenchmarks.{}.{}".format(
env["platform"], env["target"], env["platform"], env["target"]
),
source=sources,
)
else:
library = env.SharedLibrary(
"bin/libcppbenchmarks{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)
Default(library)

View File

@@ -0,0 +1,23 @@
[configuration]
entry_symbol = "benchmark_library_init"
compatibility_minimum = "4.3"
[libraries]
macos.debug = "res://gdextension/bin/libcppbenchmarks.macos.template_debug.framework"
macos.release = "res://gdextension/bin/libcppbenchmarks.macos.template_release.framework"
windows.debug.x86_32 = "res://gdextension/bin/libcppbenchmarks.windows.template_debug.x86_32.dll"
windows.release.x86_32 = "res://gdextension/bin/libcppbenchmarks.windows.template_release.x86_32.dll"
windows.debug.x86_64 = "res://gdextension/bin/libcppbenchmarks.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://gdextension/bin/libcppbenchmarks.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "res://gdextension/bin/libcppbenchmarks.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://gdextension/bin/libcppbenchmarks.linux.template_release.x86_64.so"
linux.debug.arm64 = "res://gdextension/bin/libcppbenchmarks.linux.template_debug.arm64.so"
linux.release.arm64 = "res://gdextension/bin/libcppbenchmarks.linux.template_release.arm64.so"
linux.debug.rv64 = "res://gdextension/bin/libcppbenchmarks.linux.template_debug.rv64.so"
linux.release.rv64 = "res://gdextension/bin/libcppbenchmarks.linux.template_release.rv64.so"
android.debug.x86_64 = "res://gdextension/bin/libcppbenchmarks.android.template_debug.x86_64.so"
android.release.x86_64 = "res://gdextension/bin/libcppbenchmarks.android.template_release.x86_64.so"
android.debug.arm64 = "res://gdextension/bin/libcppbenchmarks.android.template_debug.arm64.so"
android.release.arm64 = "res://gdextension/bin/libcppbenchmarks.android.template_release.arm64.so"

304091
gdextension/extension_api.json Normal file

File diff suppressed because it is too large Load Diff

1
gdextension/godot-cpp Submodule

Submodule gdextension/godot-cpp added at 99926d8e20

View File

@@ -0,0 +1,79 @@
#include "alloc.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/classes/random_number_generator.hpp>
using namespace godot;
void CPPBenchmarkAlloc::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_deep_tree"), &CPPBenchmarkAlloc::benchmark_deep_tree);
ClassDB::bind_method(D_METHOD("benchmark_wide_tree"), &CPPBenchmarkAlloc::benchmark_wide_tree);
ClassDB::bind_method(D_METHOD("benchmark_fragmentation"), &CPPBenchmarkAlloc::benchmark_fragmentation);
ClassDB::bind_method(D_METHOD("benchmark_duplicate"), &CPPBenchmarkAlloc::benchmark_duplicate);
}
void CPPBenchmarkAlloc::benchmark_deep_tree() {
Node *rt = memnew(Node);
for (int i = 0; i < iterations; i++) {
Node *n = memnew(Node);
n->add_child(rt);
rt = n;
}
// Avoid triggering a stack overflow with memdelete(rt)
while (rt->get_child_count() != 0) {
Node *n = rt->get_child(0);
rt->remove_child(n);
memdelete(rt);
rt = n;
}
memdelete(rt);
}
void CPPBenchmarkAlloc::benchmark_wide_tree() {
Node *rt = memnew(Node);
for (int i = 0; i < iterations; i++) {
rt->add_child(memnew(Node));
}
memdelete(rt);
}
void CPPBenchmarkAlloc::benchmark_fragmentation() {
Node *top = memnew(Node);
for (int i = 0; i < 5; i++) {
top->add_child(memnew(Node));
}
Ref<RandomNumberGenerator> rand;
rand.instantiate();
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 = rand->randi() % top->get_child_count();
top->get_child(idx)->add_child(memnew(Node));
}
Node *tmp = top->get_child(0);
top->remove_child(tmp);
// Since nodes in the tree are scattered in memory,
// freeing subtrees this way should maximize fragmentation.
memdelete(tmp);
top->add_child(memnew(Node));
}
memdelete(top);
}
void CPPBenchmarkAlloc::benchmark_duplicate() {
Node *rt = memnew(Node);
for (int i = 0; i < 16; i++) {
Node *n = memnew(Node);
n->add_child(rt->duplicate());
n->add_child(rt->duplicate());
memdelete(rt);
rt = n;
}
memdelete(rt);
}
CPPBenchmarkAlloc::CPPBenchmarkAlloc() {}
CPPBenchmarkAlloc::~CPPBenchmarkAlloc() {}

View File

@@ -0,0 +1,22 @@
#ifndef CPP_BENCHMARK_ALLOC_H
#define CPP_BENCHMARK_ALLOC_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkAlloc : public CPPBenchmark {
GDCLASS(CPPBenchmarkAlloc, CPPBenchmark)
protected:
static void _bind_methods();
public:
unsigned int iterations = 100000;
void benchmark_deep_tree();
void benchmark_wide_tree();
void benchmark_fragmentation();
void benchmark_duplicate();
CPPBenchmarkAlloc();
~CPPBenchmarkAlloc();
};
}
#endif

View File

@@ -0,0 +1,146 @@
#include "array.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void CPPBenchmarkArray::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_fill_loop"), &CPPBenchmarkArray::benchmark_fill_loop);
ClassDB::bind_method(D_METHOD("benchmark_int32_array"), &CPPBenchmarkArray::benchmark_int32_array);
ClassDB::bind_method(D_METHOD("benchmark_int64_array"), &CPPBenchmarkArray::benchmark_int64_array);
ClassDB::bind_method(D_METHOD("benchmark_float32_array"), &CPPBenchmarkArray::benchmark_float32_array);
ClassDB::bind_method(D_METHOD("benchmark_float64_array"), &CPPBenchmarkArray::benchmark_float64_array);
ClassDB::bind_method(D_METHOD("benchmark_vector2_array"), &CPPBenchmarkArray::benchmark_vector2_array);
ClassDB::bind_method(D_METHOD("benchmark_vector3_array"), &CPPBenchmarkArray::benchmark_vector3_array);
ClassDB::bind_method(D_METHOD("benchmark_vector4_array"), &CPPBenchmarkArray::benchmark_vector4_array);
ClassDB::bind_method(D_METHOD("benchmark_color_array"), &CPPBenchmarkArray::benchmark_color_array);
ClassDB::bind_method(D_METHOD("benchmark_string_array"), &CPPBenchmarkArray::benchmark_string_array);
}
void CPPBenchmarkArray::benchmark_fill_loop() {
int length = 10000000;
int array[length];
for (int i = 0; i < length; i++) {
array[i] = 1234;
}
}
void CPPBenchmarkArray::benchmark_int32_array() {
TypedArray<int> array;
for(int i = 0; i < iterations; i++)
array.push_back(i);
for(int i = 0; i < iterations; i++)
array[i] = 0;
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
void CPPBenchmarkArray::benchmark_int64_array() {
TypedArray<long> array;
for(int i = 0; i < iterations; i++)
array.push_back(i);
for(int i = 0; i < iterations; i++)
array[i] = 0;
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
void CPPBenchmarkArray::benchmark_float32_array() {
TypedArray<float> array;
for(int i = 0; i < iterations; i++)
array.push_back(i);
for(int i = 0; i < iterations; i++)
array[i] = 0.0;
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
void CPPBenchmarkArray::benchmark_float64_array() {
TypedArray<double> array;
for(int i = 0; i < iterations; i++)
array.push_back(i);
for(int i = 0; i < iterations; i++)
array[i] = 0.0;
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
void CPPBenchmarkArray::benchmark_vector2_array() {
TypedArray<Vector2> array;
for(int i = 0; i < iterations; i++)
array.push_back(Vector2(i, i));
for(int i = 0; i < iterations; i++)
array[i] = Vector2(0, 0);
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
void CPPBenchmarkArray::benchmark_vector3_array() {
TypedArray<Vector3> array;
for(int i = 0; i < iterations; i++)
array.push_back(Vector3(i, i, i));
for(int i = 0; i < iterations; i++)
array[i] = Vector3(0, 0, 0);
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
void CPPBenchmarkArray::benchmark_vector4_array() {
TypedArray<Vector4> array;
for(int i = 0; i < iterations; i++)
array.push_back(Vector4(i, i, i, i));
for(int i = 0; i < iterations; i++)
array[i] = Vector4(0, 0, 0, 0);
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
void CPPBenchmarkArray::benchmark_color_array() {
TypedArray<Color> array;
for(int i = 0; i < iterations; i++)
array.push_back(Color(i, i, i, 1.0));
for(int i = 0; i < iterations; i++)
array[i] = Color(0, 0, 0, 0);
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
void CPPBenchmarkArray::benchmark_string_array() {
TypedArray<String> array;
for(int64_t i = 0; i < iterations; i++) // i needs to be int64_t for string formatting to work, as the String::% operator is not overloaded for int
array.push_back(String("Godot %d") % i);
for(int i = 0; i < iterations; i++)
array[i] = "";
for(int i = 0; i < iterations; i++)
array.remove_at(array.size() - 1);
}
CPPBenchmarkArray::CPPBenchmarkArray() {}
CPPBenchmarkArray::~CPPBenchmarkArray() {}

View File

@@ -0,0 +1,28 @@
#ifndef CPP_BENCHMARK_ARRAY_H
#define CPP_BENCHMARK_ARRAY_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkArray : public CPPBenchmark {
GDCLASS(CPPBenchmarkArray, CPPBenchmark)
protected:
static void _bind_methods();
public:
unsigned int iterations = 2000000;
void benchmark_fill_loop();
void benchmark_int32_array();
void benchmark_int64_array();
void benchmark_float32_array();
void benchmark_float64_array();
void benchmark_vector2_array();
void benchmark_vector3_array();
void benchmark_vector4_array();
void benchmark_color_array();
void benchmark_string_array();
CPPBenchmarkArray();
~CPPBenchmarkArray();
};
}
#endif

View File

@@ -0,0 +1,54 @@
#include "binary_trees.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void CPPBenchmarkBinaryTrees::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_binary_trees_13"), &CPPBenchmarkBinaryTrees::benchmark_binary_trees_13);
ClassDB::bind_method(D_METHOD("benchmark_binary_trees_15"), &CPPBenchmarkBinaryTrees::benchmark_binary_trees_15);
ClassDB::bind_method(D_METHOD("benchmark_binary_trees_18"), &CPPBenchmarkBinaryTrees::benchmark_binary_trees_18);
}
void CPPBenchmarkBinaryTrees::calculate_binary_trees(int input) {
int max_depth = godot::Math::max(min_depth + 2, input);
int stretch_depth = max_depth + 1;
TreeNode* stretch_tree = TreeNode::create(stretch_depth);
godot::UtilityFunctions::print("stretch tree of depth ", stretch_depth, "\t check: ", stretch_tree->check());
delete stretch_tree;
TreeNode* long_lived_tree = TreeNode::create(max_depth);
int max_plus_min_depth = max_depth + min_depth;
for (int depth = min_depth; depth < max_depth; depth += 2) {
int iterations = 1 << (max_plus_min_depth - depth);
int check = 0;
for (int i = 0; i < iterations; i++) {
TreeNode* check_tree = TreeNode::create(depth);
check += check_tree->check();
delete check_tree;
}
godot::UtilityFunctions::print(iterations, "\t trees of depth ", depth, "\t check: ", check);
}
godot::UtilityFunctions::print("long lived tree of depth ", max_depth, "\t check: ", long_lived_tree->check());
delete long_lived_tree;
}
void CPPBenchmarkBinaryTrees::benchmark_binary_trees_13() {
calculate_binary_trees(13);
}
void CPPBenchmarkBinaryTrees::benchmark_binary_trees_15() {
calculate_binary_trees(15);
}
void CPPBenchmarkBinaryTrees::benchmark_binary_trees_18() {
calculate_binary_trees(18);
}
CPPBenchmarkBinaryTrees::CPPBenchmarkBinaryTrees() {}
CPPBenchmarkBinaryTrees::~CPPBenchmarkBinaryTrees() {}

View File

@@ -0,0 +1,59 @@
#ifndef CPP_BENCHMARK_BINARY_TREES_H
#define CPP_BENCHMARK_BINARY_TREES_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkBinaryTrees : public CPPBenchmark {
GDCLASS(CPPBenchmarkBinaryTrees, CPPBenchmark)
private:
class TreeNode {
private:
TreeNode* left;
TreeNode* right;
public:
TreeNode() {
left = nullptr;
right = nullptr;
};
TreeNode(TreeNode* p_left, TreeNode* p_right) {
left = p_left;
right = p_right;
};
~TreeNode() {
delete left;
delete right;
};
static TreeNode* create(int d){
if (d == 0)
return new TreeNode();
return new TreeNode(create(d - 1), create(d - 1));
};
int check() {
int c = 1;
if (right != nullptr)
{
c += right->check();
}
if (left != nullptr)
{
c += left->check();
}
return c;
};
};
const int min_depth = 4;
void calculate_binary_trees(int input);
protected:
static void _bind_methods();
public:
void benchmark_binary_trees_13();
void benchmark_binary_trees_15();
void benchmark_binary_trees_18();
CPPBenchmarkBinaryTrees();
~CPPBenchmarkBinaryTrees();
};
}
#endif

View File

@@ -0,0 +1,16 @@
#include "control.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
// An empty test, to act as a control
void CPPBenchmarkControl::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_control"), &CPPBenchmarkControl::benchmark_control);
}
void CPPBenchmarkControl::benchmark_control() {}
CPPBenchmarkControl::CPPBenchmarkControl() {}
CPPBenchmarkControl::~CPPBenchmarkControl() {}

View File

@@ -0,0 +1,18 @@
#ifndef CPP_BENCHMARK_CONTROL_H
#define CPP_BENCHMARK_CONTROL_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkControl : public CPPBenchmark {
GDCLASS(CPPBenchmarkControl, CPPBenchmark)
protected:
static void _bind_methods();
public:
void benchmark_control();
CPPBenchmarkControl();
~CPPBenchmarkControl();
};
}
#endif

View File

@@ -0,0 +1,26 @@
#include "forloop.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void CPPBenchmarkForLoop::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_loop_add"), &CPPBenchmarkForLoop::benchmark_loop_add);
ClassDB::bind_method(D_METHOD("benchmark_loop_call"), &CPPBenchmarkForLoop::benchmark_loop_call);
}
void CPPBenchmarkForLoop::function() {}
void CPPBenchmarkForLoop::benchmark_loop_add() {
int number = 0;
for(int i = 0; i < iterations; i++)
number++;
}
void CPPBenchmarkForLoop::benchmark_loop_call() {
for(int i = 0; i < iterations; i++)
function();
}
CPPBenchmarkForLoop::CPPBenchmarkForLoop() {}
CPPBenchmarkForLoop::~CPPBenchmarkForLoop() {}

View File

@@ -0,0 +1,22 @@
#ifndef CPP_BENCHMARK_FOR_LOOP_H
#define CPP_BENCHMARK_FOR_LOOP_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkForLoop : public CPPBenchmark {
GDCLASS(CPPBenchmarkForLoop, CPPBenchmark)
private:
void function();
protected:
static void _bind_methods();
public:
unsigned int iterations = 1000000;
void benchmark_loop_add();
void benchmark_loop_call();
CPPBenchmarkForLoop();
~CPPBenchmarkForLoop();
};
}
#endif

View File

@@ -0,0 +1,18 @@
#include "hello_world.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void CPPBenchmarkHelloWorld::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_hello_world"), &CPPBenchmarkHelloWorld::benchmark_hello_world);
}
void CPPBenchmarkHelloWorld::benchmark_hello_world() {
godot::UtilityFunctions::print("Hello world!");
}
CPPBenchmarkHelloWorld::CPPBenchmarkHelloWorld() {}
CPPBenchmarkHelloWorld::~CPPBenchmarkHelloWorld() {}

View File

@@ -0,0 +1,18 @@
#ifndef CPP_BENCHMARK_HELLOWORLD_H
#define CPP_BENCHMARK_HELLOWORLD_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkHelloWorld : public CPPBenchmark {
GDCLASS(CPPBenchmarkHelloWorld, CPPBenchmark)
protected:
static void _bind_methods();
public:
void benchmark_hello_world();
CPPBenchmarkHelloWorld();
~CPPBenchmarkHelloWorld();
};
}
#endif

View File

@@ -0,0 +1,18 @@
#include "lambda_performance.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void CPPBenchmarkLambdaPerformance::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_lambda_call"), &CPPBenchmarkLambdaPerformance::benchmark_lambda_call);
}
void CPPBenchmarkLambdaPerformance::benchmark_lambda_call() {
auto lambda = [](){};
for(int i = 0; i < iterations; i++)
lambda();
}
CPPBenchmarkLambdaPerformance::CPPBenchmarkLambdaPerformance() {}
CPPBenchmarkLambdaPerformance::~CPPBenchmarkLambdaPerformance() {}

View File

@@ -0,0 +1,19 @@
#ifndef CPP_BENCHMARK_LAMBDA_PERFORMANCE_H
#define CPP_BENCHMARK_LAMBDA_PERFORMANCE_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkLambdaPerformance : public CPPBenchmark {
GDCLASS(CPPBenchmarkLambdaPerformance, CPPBenchmark)
protected:
static void _bind_methods();
public:
unsigned int iterations = 1000000;
void benchmark_lambda_call();
CPPBenchmarkLambdaPerformance();
~CPPBenchmarkLambdaPerformance();
};
}
#endif

View File

@@ -0,0 +1,69 @@
#include "mandelbrot_set.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/classes/image.hpp>
using namespace godot;
void CPPBenchmarkMandelbrotSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_mandelbrot_set"), &CPPBenchmarkMandelbrotSet::benchmark_mandelbrot_set);
}
Color CPPBenchmarkMandelbrotSet::hsv(float hue, float sat, float value) {
hue = godot::Math::fposmod(hue, 360.0f);
int h = godot::Math::floor(hue) / 60;
float f = hue / 60.0 - h;
float p = value * (1.0 - sat);
float q = value * (1.0 - sat * f);
float t = value * (1.0 - sat * (1.0 - f));
if (h == 0 || 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);
}
void CPPBenchmarkMandelbrotSet::mandelbrot_set(int p_width, int p_height, int p_max_iteration) {
Ref<Image> image = memnew(Image);
image = Image::create_empty(p_width, p_height, false, Image::Format::FORMAT_RGB8);
float ratio = float(p_width) / float(p_height);
float x_range = 3.6;
float y_range = x_range / ratio;
float min_x = -x_range / 2.0;
float max_y = y_range / 2.0;
for (int x = 0; x < image->get_width(); x++) {
for (int y = 0; y < image->get_height(); y++) {
int iteration = 0;
float x0 = min_x + x_range * x / p_width;
float y0 = max_y - y_range * y / p_height;
float xx = 0.0;
float yy = 0.0;
float x2 = 0.0;
float y2 = 0.0;
while (x2 + y2 <= 4 && iteration < p_max_iteration) {
yy = 2 * xx * yy + y0;
xx = x2 - y2 + x0;
x2 = xx * xx;
y2 = yy * yy;
iteration += 1;
}
float m = float(iteration) / float(p_max_iteration);
Color color = hsv(360.0 * m, 1.0, ceilf(1.0 - 1.1 * m));
image->set_pixel(x, y, color);
}
}
}
void CPPBenchmarkMandelbrotSet::benchmark_mandelbrot_set() {
mandelbrot_set(width, height, max_iteration);
}
CPPBenchmarkMandelbrotSet::CPPBenchmarkMandelbrotSet() {}
CPPBenchmarkMandelbrotSet::~CPPBenchmarkMandelbrotSet() {}

View File

@@ -0,0 +1,24 @@
#ifndef CPP_BENCHMARK_MANDELBROT_SET_H
#define CPP_BENCHMARK_MANDELBROT_SET_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkMandelbrotSet : public CPPBenchmark {
GDCLASS(CPPBenchmarkMandelbrotSet, CPPBenchmark)
private:
int width = 600;
int height = 400;
int max_iteration = 1000;
Color hsv(float hue, float sat, float value);
void mandelbrot_set(int p_width, int p_height, int p_max_iteration);
protected:
static void _bind_methods();
public:
void benchmark_mandelbrot_set();
CPPBenchmarkMandelbrotSet();
~CPPBenchmarkMandelbrotSet();
};
}
#endif

View File

@@ -0,0 +1,64 @@
#include "merkle_trees.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void CPPBenchmarkMerkleTrees::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_merkle_trees_13"), &CPPBenchmarkMerkleTrees::benchmark_merkle_trees_13);
ClassDB::bind_method(D_METHOD("benchmark_merkle_trees_15"), &CPPBenchmarkMerkleTrees::benchmark_merkle_trees_15);
ClassDB::bind_method(D_METHOD("benchmark_merkle_trees_18"), &CPPBenchmarkMerkleTrees::benchmark_merkle_trees_18);
}
CPPBenchmarkMerkleTrees::TreeNode* CPPBenchmarkMerkleTrees::make_tree(int depth) {
if (depth > 0) {
depth -= 1;
return new TreeNode(-1, make_tree(depth), make_tree(depth));
}
return new TreeNode(1, nullptr, nullptr);
}
void CPPBenchmarkMerkleTrees::calculate_merkle_trees(int input) {
int max_depth = godot::Math::max(min_depth + 2, input);
int stretch_depth = max_depth + 1;
TreeNode* stretch_tree = make_tree(stretch_depth);
stretch_tree->cal_hash();
godot::UtilityFunctions::print("stretch tree of depth ", stretch_depth, "\t root hash: ", stretch_tree->hash, "\t check: ", stretch_tree->check());
delete stretch_tree;
TreeNode* long_lived_tree = make_tree(max_depth);
int max_plus_min_depth = max_depth + min_depth;
for (int depth = min_depth; depth < max_depth; depth += 2) {
int iterations = 1 << (max_plus_min_depth - depth);
int sum = 0;
for (int i = 0; i < iterations; i++) {
TreeNode* tree = make_tree(depth);
tree->cal_hash();
sum += tree->hash;
delete tree;
}
godot::UtilityFunctions::print(iterations, "\t trees of depth ", depth, "\t root hash sum: ", sum);
}
long_lived_tree->cal_hash();
godot::UtilityFunctions::print("long lived tree of depth ", input, "\t root hash: ", long_lived_tree->hash, "\t check: ", long_lived_tree->check());
delete long_lived_tree;
}
void CPPBenchmarkMerkleTrees::benchmark_merkle_trees_13() {
calculate_merkle_trees(13);
}
void CPPBenchmarkMerkleTrees::benchmark_merkle_trees_15() {
calculate_merkle_trees(15);
}
void CPPBenchmarkMerkleTrees::benchmark_merkle_trees_18() {
calculate_merkle_trees(18);
}
CPPBenchmarkMerkleTrees::CPPBenchmarkMerkleTrees() {}
CPPBenchmarkMerkleTrees::~CPPBenchmarkMerkleTrees() {}

View File

@@ -0,0 +1,72 @@
#ifndef CPP_BENCHMARK_MERKLE_TREES_H
#define CPP_BENCHMARK_MERKLE_TREES_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkMerkleTrees : public CPPBenchmark {
GDCLASS(CPPBenchmarkMerkleTrees, CPPBenchmark)
private:
class TreeNode {
private:
int value;
TreeNode* left;
TreeNode* right;
public:
TreeNode() {
value = -1;
left = nullptr;
right = nullptr;
hash = -1;
};
TreeNode(int p_value, TreeNode* p_left, TreeNode* p_right) {
value = p_value;
left = p_left;
right = p_right;
hash = -1;
};
~TreeNode() {
delete left;
delete right;
};
bool check() {
if (hash != -1) {
if (value != -1) {
return true;
}
if (left != nullptr && right != nullptr) {
return left->check() && right->check();
}
}
return false;
};
void cal_hash() {
if (hash == -1) {
if (value != -1) {
hash = value;
}
else if (left != nullptr && right != nullptr) {
left->cal_hash();
right->cal_hash();
hash = left->hash + right->hash;
}
}
};
int hash;
};
const int min_depth = 4;
TreeNode* make_tree(int depth);
void calculate_merkle_trees(int input);
protected:
static void _bind_methods();
public:
void benchmark_merkle_trees_13();
void benchmark_merkle_trees_15();
void benchmark_merkle_trees_18();
CPPBenchmarkMerkleTrees();
~CPPBenchmarkMerkleTrees();
};
}
#endif

View File

@@ -0,0 +1,93 @@
#include "nbody.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void CPPBenchmarkNbody::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_nbody_500_000"), &CPPBenchmarkNbody::benchmark_nbody_500_000);
ClassDB::bind_method(D_METHOD("benchmark_nbody_1_000_000"), &CPPBenchmarkNbody::benchmark_nbody_1_000_000);
}
void CPPBenchmarkNbody::offset_momentum() {
double px, py, pz = 0;
for(char i = 0; i < body_count; i++) {
Body b = bodies[i];
px -= b.vx * b.mass;
py -= b.vy * b.mass;
pz -= b.vz * b.mass;
}
Body sol = bodies[0];
bodies[0].vx = px / Solarmass;
bodies[0].vy = py / Solarmass;
bodies[0].vz = pz / Solarmass;
}
void CPPBenchmarkNbody::advance(double dt) {
for (char i = 0; i < body_count; i++) {
double x = bodies[i].x;
double y = bodies[i].y;
double z = bodies[i].z;
double vx = bodies[i].vx;
double vy = bodies[i].vy;
double vz = bodies[i].vz;
double mi = bodies[i].mass;
for (char j = i + 1; j < body_count; j++) {
double dx = x - bodies[j].x;
double dy = y - bodies[j].y;
double dz = z - bodies[j].z;
double d2 = dx * dx + dy * dy + dz * dz;
double mag = dt / (d2 * godot::Math::sqrt(d2));
double bj_m_mag = bodies[j].mass * mag;
vx -= dx * bj_m_mag;
vy -= dy * bj_m_mag;
vz -= dz * bj_m_mag;
double bi_m_mag = mi * mag;
bodies[j].vx += dx * bi_m_mag;
bodies[j].vy += dy * bi_m_mag;
bodies[j].vz += dz * bi_m_mag;
}
bodies[i].vx = vx;
bodies[i].vy = vy;
bodies[i].vz = vz;
bodies[i].x += vx * dt;
bodies[i].y += vy * dt;
bodies[i].z += vz * dt;
}
}
double CPPBenchmarkNbody::energy() {
double e = 0.0;
for (int i = 0; i < body_count; i++) {
e += 0.5 * bodies[i].mass * (bodies[i].vx * bodies[i].vx + bodies[i].vy * bodies[i].vy + bodies[i].vz * bodies[i].vz);
for (int j = i + 1; j < body_count; j++) {
double dx = bodies[i].x - bodies[j].x, dy = bodies[i].y - bodies[j].y, dz = bodies[i].z - bodies[j].z;
e -= (bodies[i].mass * bodies[j].mass) / godot::Math::sqrt(dx * dx + dy * dy + dz * dz);
}
}
return e;
}
void CPPBenchmarkNbody::calculate_nbody(int n) {
offset_momentum();
godot::UtilityFunctions::print(energy());
for (int i = 0; i < n; i++) {
advance(0.01);
}
godot::UtilityFunctions::print(energy());
}
void CPPBenchmarkNbody::benchmark_nbody_500_000() {
calculate_nbody(500000);
}
void CPPBenchmarkNbody::benchmark_nbody_1_000_000() {
calculate_nbody(1000000);
}
CPPBenchmarkNbody::CPPBenchmarkNbody() {}
CPPBenchmarkNbody::~CPPBenchmarkNbody() {}

View File

@@ -0,0 +1,71 @@
#ifndef CPP_BENCHMARK_NBODY_H
#define CPP_BENCHMARK_NBODY_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkNbody : public CPPBenchmark {
GDCLASS(CPPBenchmarkNbody, CPPBenchmark)
private:
const double Pi = 3.141592653589793;
const double Solarmass = 4 * Pi * Pi;
const double DaysPeryear = 365.24;
struct Body { double x, y, z, vx, vy, vz, mass; };
const char body_count = 5; // We can use char since this value is small
Body bodies[5] {
{ // Sun
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Solarmass
},
{ // Jupiter
4.84143144246472090e+00,
-1.16032004402742839e+00,
-1.03622044471123109e-01,
1.66007664274403694e-03*DaysPeryear,
7.69901118419740425e-03*DaysPeryear,
-6.90460016972063023e-05*DaysPeryear,
9.54791938424326609e-04*Solarmass
},
{ // Saturn
8.34336671824457987e+00,
4.12479856412430479e+00,
-4.03523417114321381e-01,
-2.76742510726862411e-03*DaysPeryear,
4.99852801234917238e-03*DaysPeryear,
2.30417297573763929e-05*DaysPeryear,
2.85885980666130812e-04*Solarmass,
},
{ // Uranus
1.28943695621391310e+01,
-1.51111514016986312e+01,
-2.23307578892655734e-01,
2.96460137564761618e-03*DaysPeryear,
2.37847173959480950e-03*DaysPeryear,
-2.96589568540237556e-05*DaysPeryear,
4.36624404335156298e-05*Solarmass,
},
{ // Neptune
1.53796971148509165e+01,
-2.59193146099879641e+01,
1.79258772950371181e-01,
2.68067772490389322e-03*DaysPeryear,
1.62824170038242295e-03*DaysPeryear,
-9.51592254519715870e-05*DaysPeryear,
5.15138902046611451e-05*Solarmass,
},
};
void offset_momentum();
void advance(double dt);
double energy();
void calculate_nbody(int n);
protected:
static void _bind_methods();
public:
void benchmark_nbody_500_000();
void benchmark_nbody_1_000_000();
CPPBenchmarkNbody();
~CPPBenchmarkNbody();
};
}
#endif

View File

@@ -0,0 +1,84 @@
#include "spectral_norm.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void CPPBenchmarkSpectralNorm::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_spectral_norm_100"), &CPPBenchmarkSpectralNorm::benchmark_spectral_norm_100);
ClassDB::bind_method(D_METHOD("benchmark_spectral_norm_500"), &CPPBenchmarkSpectralNorm::benchmark_spectral_norm_500);
ClassDB::bind_method(D_METHOD("benchmark_spectral_norm_1000"), &CPPBenchmarkSpectralNorm::benchmark_spectral_norm_1000);
}
double CPPBenchmarkSpectralNorm::eval_a(int i, int j) {
return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1);
}
/* multiply vector v by matrix A, each thread evaluate its range only */
void CPPBenchmarkSpectralNorm::multiply_av(double v[], double av[], int n) {
for (int i = 0; i < n; i++) {
double sum = 0;
for (int j = 0; j < n; j++)
sum += eval_a(i, j) * v[j];
av[i] = sum;
}
}
/* multiply vector v by matrix A transposed */
void CPPBenchmarkSpectralNorm::multiply_atv(double v[], double atv[], int n) {
for (int i = 0; i < n; i++) {
double sum = 0;
for (int j = 0; j < n; j++)
sum += eval_a(j, i) * v[j];
atv[i] = sum;
}
}
/* multiply vector v by matrix A and then by matrix A transposed */
void CPPBenchmarkSpectralNorm::multiply_at_av(double v[], double tmp[], double at_av[], int n) {
multiply_av(v, tmp, n);
multiply_atv(tmp, at_av, n);
}
void CPPBenchmarkSpectralNorm::calculate_spectral_norm(int n) {
double u[n];
double v[n];
double tmp[n];
// create unit vector
for (int i = 0; i < n; i++)
u[i] = 1.0;
for (int i = 0; i < 10; i++) {
multiply_at_av(u, v, tmp, n);
multiply_at_av(v, u, tmp, n);
}
double vbv = 0, vv = 0;
for (int i = 0; i < n; i++) {
vbv += u[i] * v[i];
vv += v[i] * v[i];
}
double square_root = godot::Math::sqrt(vbv / vv);
godot::UtilityFunctions::print(square_root);
}
void CPPBenchmarkSpectralNorm::benchmark_spectral_norm_100() {
calculate_spectral_norm(100);
}
void CPPBenchmarkSpectralNorm::benchmark_spectral_norm_500() {
calculate_spectral_norm(500);
}
void CPPBenchmarkSpectralNorm::benchmark_spectral_norm_1000() {
calculate_spectral_norm(1000);
}
CPPBenchmarkSpectralNorm::CPPBenchmarkSpectralNorm() {}
CPPBenchmarkSpectralNorm::~CPPBenchmarkSpectralNorm() {}

View File

@@ -0,0 +1,26 @@
#ifndef CPP_BENCHMARK_SPECTRAL_NORM_H
#define CPP_BENCHMARK_SPECTRAL_NORM_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkSpectralNorm : public CPPBenchmark {
GDCLASS(CPPBenchmarkSpectralNorm, CPPBenchmark)
private:
double eval_a(int i, int j);
void multiply_av(double v[], double av[], int n);
void multiply_atv(double v[], double atv[], int n);
void multiply_at_av(double v[], double tmp[], double at_av[], int n);
void calculate_spectral_norm(int input);
protected:
static void _bind_methods();
public:
void benchmark_spectral_norm_100();
void benchmark_spectral_norm_500();
void benchmark_spectral_norm_1000();
CPPBenchmarkSpectralNorm();
~CPPBenchmarkSpectralNorm();
};
}
#endif

View File

@@ -0,0 +1,84 @@
#include "string_checksum.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void CPPBenchmarkStringChecksum::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_md5_buffer_empty"), &CPPBenchmarkStringChecksum::benchmark_md5_buffer_empty);
ClassDB::bind_method(D_METHOD("benchmark_md5_buffer_non_empty"), &CPPBenchmarkStringChecksum::benchmark_md5_buffer_non_empty);
ClassDB::bind_method(D_METHOD("benchmark_sha1_buffer_empty"), &CPPBenchmarkStringChecksum::benchmark_sha1_buffer_empty);
ClassDB::bind_method(D_METHOD("benchmark_sha1_buffer_non_empty"), &CPPBenchmarkStringChecksum::benchmark_sha1_buffer_non_empty);
ClassDB::bind_method(D_METHOD("benchmark_sha256_buffer_empty"), &CPPBenchmarkStringChecksum::benchmark_sha256_buffer_empty);
ClassDB::bind_method(D_METHOD("benchmark_sha256_buffer_non_empty"), &CPPBenchmarkStringChecksum::benchmark_sha256_buffer_non_empty);
ClassDB::bind_method(D_METHOD("benchmark_md5_text_empty"), &CPPBenchmarkStringChecksum::benchmark_md5_text_empty);
ClassDB::bind_method(D_METHOD("benchmark_md5_text_non_empty"), &CPPBenchmarkStringChecksum::benchmark_md5_text_non_empty);
ClassDB::bind_method(D_METHOD("benchmark_sha1_text_empty"), &CPPBenchmarkStringChecksum::benchmark_sha1_text_empty);
ClassDB::bind_method(D_METHOD("benchmark_sha1_text_non_empty"), &CPPBenchmarkStringChecksum::benchmark_sha1_text_non_empty);
ClassDB::bind_method(D_METHOD("benchmark_sha256_text_empty"), &CPPBenchmarkStringChecksum::benchmark_sha256_text_empty);
ClassDB::bind_method(D_METHOD("benchmark_sha256_text_non_empty"), &CPPBenchmarkStringChecksum::benchmark_sha256_text_non_empty);
}
void CPPBenchmarkStringChecksum::benchmark_md5_buffer_empty() {
for (int i = 0; i < iterations; i++)
String("").md5_buffer();
}
void CPPBenchmarkStringChecksum::benchmark_md5_buffer_non_empty() {
for (int i = 0; i < iterations; i++)
LOREM_IPSUM.md5_buffer();
}
void CPPBenchmarkStringChecksum::benchmark_sha1_buffer_empty() {
for (int i = 0; i < iterations; i++)
String("").sha1_buffer();
}
void CPPBenchmarkStringChecksum::benchmark_sha1_buffer_non_empty() {
for (int i = 0; i < iterations; i++)
LOREM_IPSUM.sha1_buffer();
}
void CPPBenchmarkStringChecksum::benchmark_sha256_buffer_empty() {
for (int i = 0; i < iterations; i++)
String("").sha256_buffer();
}
void CPPBenchmarkStringChecksum::benchmark_sha256_buffer_non_empty() {
for (int i = 0; i < iterations; i++)
LOREM_IPSUM.sha256_buffer();
}
void CPPBenchmarkStringChecksum::benchmark_md5_text_empty() {
for (int i = 0; i < iterations; i++)
String("").md5_text();
}
void CPPBenchmarkStringChecksum::benchmark_md5_text_non_empty() {
for (int i = 0; i < iterations; i++)
LOREM_IPSUM.md5_text();
}
void CPPBenchmarkStringChecksum::benchmark_sha1_text_empty() {
for (int i = 0; i < iterations; i++)
String("").sha1_text();
}
void CPPBenchmarkStringChecksum::benchmark_sha1_text_non_empty() {
for (int i = 0; i < iterations; i++)
LOREM_IPSUM.sha1_text();
}
void CPPBenchmarkStringChecksum::benchmark_sha256_text_empty() {
for (int i = 0; i < iterations; i++)
String("").sha256_text();
}
void CPPBenchmarkStringChecksum::benchmark_sha256_text_non_empty() {
for (int i = 0; i < iterations; i++)
LOREM_IPSUM.sha256_text();
}
CPPBenchmarkStringChecksum::CPPBenchmarkStringChecksum() {}
CPPBenchmarkStringChecksum::~CPPBenchmarkStringChecksum() {}

View File

@@ -0,0 +1,32 @@
#ifndef CPP_BENCHMARK_STRING_CHECKSUM_H
#define CPP_BENCHMARK_STRING_CHECKSUM_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkStringChecksum : public CPPBenchmark {
GDCLASS(CPPBenchmarkStringChecksum, CPPBenchmark)
private:
const String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.";
protected:
static void _bind_methods();
public:
unsigned int iterations = 1000000;
void benchmark_md5_buffer_empty();
void benchmark_md5_buffer_non_empty();
void benchmark_sha1_buffer_empty();
void benchmark_sha1_buffer_non_empty();
void benchmark_sha256_buffer_empty();
void benchmark_sha256_buffer_non_empty();
void benchmark_md5_text_empty();
void benchmark_md5_text_non_empty();
void benchmark_sha1_text_empty();
void benchmark_sha1_text_non_empty();
void benchmark_sha256_text_empty();
void benchmark_sha256_text_non_empty();
CPPBenchmarkStringChecksum();
~CPPBenchmarkStringChecksum();
};
}
#endif

View File

@@ -0,0 +1,96 @@
#include "string_format.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void CPPBenchmarkStringFormat::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_no_op_constant_method"), &CPPBenchmarkStringFormat::benchmark_no_op_constant_method);
ClassDB::bind_method(D_METHOD("benchmark_simple_constant_concatenate"), &CPPBenchmarkStringFormat::benchmark_simple_constant_concatenate);
ClassDB::bind_method(D_METHOD("benchmark_simple_constant_percent"), &CPPBenchmarkStringFormat::benchmark_simple_constant_percent);
ClassDB::bind_method(D_METHOD("benchmark_simple_constant_method"), &CPPBenchmarkStringFormat::benchmark_simple_constant_method);
ClassDB::bind_method(D_METHOD("benchmark_simple_constant_method_constant_dict"), &CPPBenchmarkStringFormat::benchmark_simple_constant_method_constant_dict);
ClassDB::bind_method(D_METHOD("benchmark_simple_variable_concatenate"), &CPPBenchmarkStringFormat::benchmark_simple_variable_concatenate);
ClassDB::bind_method(D_METHOD("benchmark_simple_variable_percent"), &CPPBenchmarkStringFormat::benchmark_simple_variable_percent);
ClassDB::bind_method(D_METHOD("benchmark_simple_variable_method"), &CPPBenchmarkStringFormat::benchmark_simple_variable_method);
ClassDB::bind_method(D_METHOD("benchmark_complex_variable_concatenate"), &CPPBenchmarkStringFormat::benchmark_complex_variable_concatenate);
ClassDB::bind_method(D_METHOD("benchmark_complex_variable_percent"), &CPPBenchmarkStringFormat::benchmark_complex_variable_percent);
ClassDB::bind_method(D_METHOD("benchmark_complex_variable_method"), &CPPBenchmarkStringFormat::benchmark_complex_variable_method);
}
void CPPBenchmarkStringFormat::benchmark_no_op_constant_method() {
for (int i = 0; i < iterations; i++) {
Dictionary dict;
String("Hello nothing!").format(dict);
}
}
void CPPBenchmarkStringFormat::benchmark_simple_constant_concatenate() {
for (int i = 0; i < iterations; i++)
"Hello " + ENGINE_NAME + "!";
}
void CPPBenchmarkStringFormat::benchmark_simple_constant_percent() {
for (int i = 0; i < iterations; i++)
String("Hello %s!") % ENGINE_NAME;
}
void CPPBenchmarkStringFormat::benchmark_simple_constant_method() {
for (int i = 0; i < iterations; i++) {
Dictionary dict;
dict["engine"] = ENGINE_NAME;
String("Hello {engine}!").format(dict);
}
}
void CPPBenchmarkStringFormat::benchmark_simple_constant_method_constant_dict() {
for (int i = 0; i < iterations; i++)
String("Hello {engine}!").format(FORMAT_DICT);
}
void CPPBenchmarkStringFormat::benchmark_simple_variable_concatenate() {
for (int i = 0; i < iterations; i++)
"Hello " + engine_name + "!";
}
void CPPBenchmarkStringFormat::benchmark_simple_variable_percent() {
for (int i = 0; i < iterations; i++)
String("Hello %s!") % engine_name;
}
void CPPBenchmarkStringFormat::benchmark_simple_variable_method() {
for (int i = 0; i < iterations; i++) {
Dictionary dict;
dict["engine"] = engine_name;
String("Hello {engine}!").format(dict);
}
}
void CPPBenchmarkStringFormat::benchmark_complex_variable_concatenate() {
for (int i = 0; i < iterations; i++)
"Hello " + engine_name + "!\nA few examples of formatting: " + godot::UtilityFunctions::str(some_integer) + ", " + godot::UtilityFunctions::str(some_float).pad_decimals(2) + ", " + godot::UtilityFunctions::str(some_vector2i);
}
void CPPBenchmarkStringFormat::benchmark_complex_variable_percent() {
for (int i = 0; i < iterations; i++) {
Array arr = Array::make(engine_name, some_integer, some_float, some_vector2i);
String("Hello %s!\nA few examples of formatting: %d, %.2f, %v") % arr;
}
}
void CPPBenchmarkStringFormat::benchmark_complex_variable_method() {
for (int i = 0; i < iterations; i++) {
Dictionary dict;
dict["engine"] = engine_name;
dict["an_integer"] = some_integer;
dict["a_float"] = godot::UtilityFunctions::str(some_float).pad_decimals(2);
dict["a_vector2i"] = some_vector2i;
String("Hello {engine}!\nA few examples of formatting: {an_integer}, {a_float}, {a_vector2i}").format(dict);
}
}
CPPBenchmarkStringFormat::CPPBenchmarkStringFormat() {
FORMAT_DICT["engine"] = ENGINE_NAME;
}
CPPBenchmarkStringFormat::~CPPBenchmarkStringFormat() {}

View File

@@ -0,0 +1,37 @@
#ifndef CPP_BENCHMARK_STRING_FORMAT_H
#define CPP_BENCHMARK_STRING_FORMAT_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkStringFormat : public CPPBenchmark {
GDCLASS(CPPBenchmarkStringFormat, CPPBenchmark)
private:
const String ENGINE_NAME = "Godot";
Dictionary FORMAT_DICT;
String engine_name = "Godot";
int some_integer = 123456;
float some_float = 1.2;
Vector2i some_vector2i = Vector2i(12, 34);
protected:
static void _bind_methods();
public:
unsigned int iterations = 1000000;
void benchmark_no_op_constant_method();
void benchmark_simple_constant_concatenate();
void benchmark_simple_constant_percent();
void benchmark_simple_constant_method();
void benchmark_simple_constant_method_constant_dict();
void benchmark_simple_variable_concatenate();
void benchmark_simple_variable_percent();
void benchmark_simple_variable_method();
void benchmark_complex_variable_concatenate();
void benchmark_complex_variable_percent();
void benchmark_complex_variable_method();
CPPBenchmarkStringFormat();
~CPPBenchmarkStringFormat();
};
}
#endif

View File

@@ -0,0 +1,282 @@
#include "string_manipulation.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
using namespace godot;
void CPPBenchmarkStringManipulation::_bind_methods() {
ClassDB::bind_method(D_METHOD("benchmark_begins_with"), &CPPBenchmarkStringManipulation::benchmark_begins_with);
ClassDB::bind_method(D_METHOD("benchmark_ends_with"), &CPPBenchmarkStringManipulation::benchmark_ends_with);
ClassDB::bind_method(D_METHOD("benchmark_count"), &CPPBenchmarkStringManipulation::benchmark_count);
ClassDB::bind_method(D_METHOD("benchmark_countn"), &CPPBenchmarkStringManipulation::benchmark_countn);
ClassDB::bind_method(D_METHOD("benchmark_contains"), &CPPBenchmarkStringManipulation::benchmark_contains);
ClassDB::bind_method(D_METHOD("benchmark_find"), &CPPBenchmarkStringManipulation::benchmark_find);
ClassDB::bind_method(D_METHOD("benchmark_findn"), &CPPBenchmarkStringManipulation::benchmark_findn);
ClassDB::bind_method(D_METHOD("benchmark_rfind"), &CPPBenchmarkStringManipulation::benchmark_rfind);
ClassDB::bind_method(D_METHOD("benchmark_rfindn"), &CPPBenchmarkStringManipulation::benchmark_rfindn);
ClassDB::bind_method(D_METHOD("benchmark_substr"), &CPPBenchmarkStringManipulation::benchmark_substr);
ClassDB::bind_method(D_METHOD("benchmark_insert"), &CPPBenchmarkStringManipulation::benchmark_insert);
ClassDB::bind_method(D_METHOD("benchmark_get_slice"), &CPPBenchmarkStringManipulation::benchmark_get_slice);
ClassDB::bind_method(D_METHOD("benchmark_get_slice_count"), &CPPBenchmarkStringManipulation::benchmark_get_slice_count);
ClassDB::bind_method(D_METHOD("benchmark_bigrams"), &CPPBenchmarkStringManipulation::benchmark_bigrams);
ClassDB::bind_method(D_METHOD("benchmark_split"), &CPPBenchmarkStringManipulation::benchmark_split);
ClassDB::bind_method(D_METHOD("benchmark_rsplit"), &CPPBenchmarkStringManipulation::benchmark_rsplit);
ClassDB::bind_method(D_METHOD("benchmark_split_floats"), &CPPBenchmarkStringManipulation::benchmark_split_floats);
ClassDB::bind_method(D_METHOD("benchmark_pad_zeros_pre_constructed"), &CPPBenchmarkStringManipulation::benchmark_pad_zeros_pre_constructed);
ClassDB::bind_method(D_METHOD("benchmark_pad_zeros"), &CPPBenchmarkStringManipulation::benchmark_pad_zeros);
ClassDB::bind_method(D_METHOD("benchmark_pad_decimals_pre_constructed"), &CPPBenchmarkStringManipulation::benchmark_pad_decimals_pre_constructed);
ClassDB::bind_method(D_METHOD("benchmark_pad_decimals"), &CPPBenchmarkStringManipulation::benchmark_pad_decimals);
ClassDB::bind_method(D_METHOD("benchmark_lpad"), &CPPBenchmarkStringManipulation::benchmark_lpad);
ClassDB::bind_method(D_METHOD("benchmark_rpad"), &CPPBenchmarkStringManipulation::benchmark_rpad);
ClassDB::bind_method(D_METHOD("benchmark_similarity"), &CPPBenchmarkStringManipulation::benchmark_similarity);
ClassDB::bind_method(D_METHOD("benchmark_simplify_path"), &CPPBenchmarkStringManipulation::benchmark_simplify_path);
ClassDB::bind_method(D_METHOD("benchmark_capitalize"), &CPPBenchmarkStringManipulation::benchmark_capitalize);
ClassDB::bind_method(D_METHOD("benchmark_to_snake_case"), &CPPBenchmarkStringManipulation::benchmark_to_snake_case);
ClassDB::bind_method(D_METHOD("benchmark_to_camel_case"), &CPPBenchmarkStringManipulation::benchmark_to_camel_case);
ClassDB::bind_method(D_METHOD("benchmark_to_pascal_case"), &CPPBenchmarkStringManipulation::benchmark_to_pascal_case);
ClassDB::bind_method(D_METHOD("benchmark_to_lower"), &CPPBenchmarkStringManipulation::benchmark_to_lower);
ClassDB::bind_method(D_METHOD("benchmark_uri_decode"), &CPPBenchmarkStringManipulation::benchmark_uri_decode);
ClassDB::bind_method(D_METHOD("benchmark_uri_encode"), &CPPBenchmarkStringManipulation::benchmark_uri_encode);
ClassDB::bind_method(D_METHOD("benchmark_xml_escape"), &CPPBenchmarkStringManipulation::benchmark_xml_escape);
ClassDB::bind_method(D_METHOD("benchmark_xml_unescape"), &CPPBenchmarkStringManipulation::benchmark_xml_unescape);
ClassDB::bind_method(D_METHOD("benchmark_humanize_size"), &CPPBenchmarkStringManipulation::benchmark_humanize_size);
ClassDB::bind_method(D_METHOD("benchmark_is_valid_filename"), &CPPBenchmarkStringManipulation::benchmark_is_valid_filename);
ClassDB::bind_method(D_METHOD("benchmark_validate_filename"), &CPPBenchmarkStringManipulation::benchmark_validate_filename);
ClassDB::bind_method(D_METHOD("benchmark_validate_node_name"), &CPPBenchmarkStringManipulation::benchmark_validate_node_name);
ClassDB::bind_method(D_METHOD("benchmark_casecmp_to"), &CPPBenchmarkStringManipulation::benchmark_casecmp_to);
ClassDB::bind_method(D_METHOD("benchmark_nocasecmp_to"), &CPPBenchmarkStringManipulation::benchmark_nocasecmp_to);
ClassDB::bind_method(D_METHOD("benchmark_naturalnocasecmp_to"), &CPPBenchmarkStringManipulation::benchmark_naturalnocasecmp_to);
ClassDB::bind_method(D_METHOD("benchmark_to_utf8_buffer"), &CPPBenchmarkStringManipulation::benchmark_to_utf8_buffer);
ClassDB::bind_method(D_METHOD("benchmark_to_utf16_buffer"), &CPPBenchmarkStringManipulation::benchmark_to_utf16_buffer);
ClassDB::bind_method(D_METHOD("benchmark_to_utf32_buffer"), &CPPBenchmarkStringManipulation::benchmark_to_utf32_buffer);
ClassDB::bind_method(D_METHOD("benchmark_to_wchar_buffer"), &CPPBenchmarkStringManipulation::benchmark_to_wchar_buffer);
}
void CPPBenchmarkStringManipulation::benchmark_begins_with() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").begins_with("Godot"); // true
}
void CPPBenchmarkStringManipulation::benchmark_ends_with() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").ends_with("Engine"); // true
}
void CPPBenchmarkStringManipulation::benchmark_count() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").count("o"); // 2
}
void CPPBenchmarkStringManipulation::benchmark_countn() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").countn("o"); // 2
}
void CPPBenchmarkStringManipulation::benchmark_contains() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").contains("o"); // tr
}
void CPPBenchmarkStringManipulation::benchmark_find() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").find("o"); // 1
}
void CPPBenchmarkStringManipulation::benchmark_findn() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").findn("o"); // 1
}
void CPPBenchmarkStringManipulation::benchmark_rfind() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").rfind("o"); // 3
}
void CPPBenchmarkStringManipulation::benchmark_rfindn() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").rfindn("o"); // 3
}
void CPPBenchmarkStringManipulation::benchmark_substr() {
for (int i = 0; i < iterations; i++)
String("Hello Godot!").substr(6, 5); // "Godot"
}
void CPPBenchmarkStringManipulation::benchmark_insert() {
for (int i = 0; i < iterations; i++)
String("Hello !").insert(6, "Godot"); // "Hello Godot!"
}
void CPPBenchmarkStringManipulation::benchmark_get_slice() {
for (int i = 0; i < iterations; i++)
String("1234,5678,90.12").get_slice(",", 1); // "5678"
}
void CPPBenchmarkStringManipulation::benchmark_get_slice_count() {
for (int i = 0; i < iterations; i++)
String("1234,5678,90.12").get_slice_count(","); // 3
}
void CPPBenchmarkStringManipulation::benchmark_bigrams() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").bigrams(); // ["Go", "od", "do", "ot", "t ", " E", "En", "ng", "gi", "in", "ne"]
}
void CPPBenchmarkStringManipulation::benchmark_split() {
for (int i = 0; i < iterations; i++)
String("1234,5678,90.12").split(","); // ["1234", "5678", "90.12"]
}
void CPPBenchmarkStringManipulation::benchmark_rsplit() {
for (int i = 0; i < iterations; i++)
String("1234,5678,90.12").rsplit(","); // ["1234", "5678", "90.12"]
}
void CPPBenchmarkStringManipulation::benchmark_split_floats() {
for (int i = 0; i < iterations; i++)
String("1234,5678,90.12").split_floats(","); // [1234.0, 5678.0, 90.12]
}
void CPPBenchmarkStringManipulation::benchmark_pad_zeros_pre_constructed() {
for (int i = 0; i < iterations; i++)
String("12345").pad_zeros(7); // "0012345"
}
void CPPBenchmarkStringManipulation::benchmark_pad_zeros() {
for (int i = 0; i < iterations; i++)
godot::UtilityFunctions::str(12345).pad_zeros(7); // "0012345"
}
void CPPBenchmarkStringManipulation::benchmark_pad_decimals_pre_constructed() {
for (int i = 0; i < iterations; i++)
String("1234.5678").pad_decimals(2); // "1234.56"
}
void CPPBenchmarkStringManipulation::benchmark_pad_decimals() {
for (int i = 0; i < iterations; i++)
godot::UtilityFunctions::str(1234.5678).pad_decimals(2); // "1234.56"
}
void CPPBenchmarkStringManipulation::benchmark_lpad() {
for (int i = 0; i < iterations; i++)
String("Godot").lpad(7, "+"); // "++Godot"
}
void CPPBenchmarkStringManipulation::benchmark_rpad() {
for (int i = 0; i < iterations; i++)
String("Godot").rpad(7, "+"); // "Godot++"
}
void CPPBenchmarkStringManipulation::benchmark_similarity() {
for (int i = 0; i < iterations; i++)
String("Godot").similarity("Engine");
}
void CPPBenchmarkStringManipulation::benchmark_simplify_path() {
for (int i = 0; i < iterations; i++)
String("./path/to///../file").simplify_path(); // "path/file"
}
void CPPBenchmarkStringManipulation::benchmark_capitalize() {
for (int i = 0; i < iterations; i++)
String("godot_engine_demo").capitalize(); // "Godot Engine Demo"
}
void CPPBenchmarkStringManipulation::benchmark_to_snake_case() {
for (int i = 0; i < iterations; i++)
String("GodotEngineDemo").to_snake_case(); // "godot_engine_demo"
}
void CPPBenchmarkStringManipulation::benchmark_to_camel_case() {
for (int i = 0; i < iterations; i++)
String("godot_engine_demo").to_snake_case(); // "godotEngineDemo"
}
void CPPBenchmarkStringManipulation::benchmark_to_pascal_case() {
for (int i = 0; i < iterations; i++)
String("godot_engine_demo").to_pascal_case(); // "GodotEngineDemo"
}
void CPPBenchmarkStringManipulation::benchmark_to_lower() {
for (int i = 0; i < iterations; i++)
String("Godot Engine Demo").to_lower(); // "godot engine demo"
}
void CPPBenchmarkStringManipulation::benchmark_uri_decode() {
for (int i = 0; i < iterations; i++)
String("Godot%20Engine%3Adocs").uri_decode(); // "Godot Engine:docs"
}
void CPPBenchmarkStringManipulation::benchmark_uri_encode() {
for (int i = 0; i < iterations; i++)
String("Godot Engine:docs").uri_encode(); // "Godot%20Engine%3Adocs"
}
void CPPBenchmarkStringManipulation::benchmark_xml_escape() {
for (int i = 0; i < iterations; i++)
String("Godot Engine <&>").xml_escape(); // "Godot Engine &lt;&amp;&gt;"
}
void CPPBenchmarkStringManipulation::benchmark_xml_unescape() {
for (int i = 0; i < iterations; i++)
String("Godot Engine &lt;&amp;&gt;").xml_unescape(); // "Godot Engine <&>"
}
void CPPBenchmarkStringManipulation::benchmark_humanize_size() {
for (int i = 0; i < iterations; i++)
String::humanize_size(123456); // 120.5 KB
}
void CPPBenchmarkStringManipulation::benchmark_is_valid_filename() {
for (int i = 0; i < iterations; i++)
String("Godot Engine: Demo.exe").is_valid_filename(); // false
}
void CPPBenchmarkStringManipulation::benchmark_validate_filename() {
for (int i = 0; i < iterations; i++)
String("Godot Engine: Demo.exe").validate_filename(); // "Godot Engine_ Demo.exe"
}
void CPPBenchmarkStringManipulation::benchmark_validate_node_name() {
for (int i = 0; i < iterations; i++)
String("TestNode:123456").validate_node_name(); // "TestNode123456"
}
void CPPBenchmarkStringManipulation::benchmark_casecmp_to() {
for (int i = 0; i < iterations; i++)
String("2 Example").casecmp_to("10 Example"); // 1
}
void CPPBenchmarkStringManipulation::benchmark_nocasecmp_to() {
for (int i = 0; i < iterations; i++)
String("2 Example").nocasecmp_to("10 Example"); // 1
}
void CPPBenchmarkStringManipulation::benchmark_naturalnocasecmp_to() {
for (int i = 0; i < iterations; i++)
String("2 Example").naturalnocasecmp_to("10 Example"); // -1
}
void CPPBenchmarkStringManipulation::benchmark_to_utf8_buffer() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").to_utf8_buffer();
}
void CPPBenchmarkStringManipulation::benchmark_to_utf16_buffer() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").to_utf16_buffer();
}
void CPPBenchmarkStringManipulation::benchmark_to_utf32_buffer() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").to_utf32_buffer();
}
void CPPBenchmarkStringManipulation::benchmark_to_wchar_buffer() {
for (int i = 0; i < iterations; i++)
String("Godot Engine").to_wchar_buffer();
}
CPPBenchmarkStringManipulation::CPPBenchmarkStringManipulation() {}
CPPBenchmarkStringManipulation::~CPPBenchmarkStringManipulation() {}

View File

@@ -0,0 +1,63 @@
#ifndef CPP_BENCHMARK_STRING_MANIPULATION_H
#define CPP_BENCHMARK_STRING_MANIPULATION_H
#include "../cppbenchmark.h"
namespace godot {
class CPPBenchmarkStringManipulation : public CPPBenchmark {
GDCLASS(CPPBenchmarkStringManipulation, CPPBenchmark)
protected:
static void _bind_methods();
public:
unsigned int iterations = 1000000;
void benchmark_begins_with();
void benchmark_ends_with();
void benchmark_count();
void benchmark_countn();
void benchmark_contains();
void benchmark_find();
void benchmark_findn();
void benchmark_rfind();
void benchmark_rfindn();
void benchmark_substr();
void benchmark_insert();
void benchmark_get_slice();
void benchmark_get_slice_count();
void benchmark_bigrams();
void benchmark_split();
void benchmark_rsplit();
void benchmark_split_floats();
void benchmark_pad_zeros_pre_constructed();
void benchmark_pad_zeros();
void benchmark_pad_decimals_pre_constructed();
void benchmark_pad_decimals();
void benchmark_lpad();
void benchmark_rpad();
void benchmark_similarity();
void benchmark_simplify_path();
void benchmark_capitalize();
void benchmark_to_snake_case();
void benchmark_to_camel_case();
void benchmark_to_pascal_case();
void benchmark_to_lower();
void benchmark_uri_decode();
void benchmark_uri_encode();
void benchmark_xml_escape();
void benchmark_xml_unescape();
void benchmark_humanize_size();
void benchmark_is_valid_filename();
void benchmark_validate_filename();
void benchmark_validate_node_name();
void benchmark_casecmp_to();
void benchmark_nocasecmp_to();
void benchmark_naturalnocasecmp_to();
void benchmark_to_utf8_buffer();
void benchmark_to_utf16_buffer();
void benchmark_to_utf32_buffer();
void benchmark_to_wchar_buffer();
CPPBenchmarkStringManipulation();
~CPPBenchmarkStringManipulation();
};
}
#endif

View File

@@ -0,0 +1,77 @@
#include "cppbenchmark.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void CPPBenchmark::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_benchmark_time"), &CPPBenchmark::get_benchmark_time);
ClassDB::bind_method(D_METHOD("set_benchmark_time", "p_benchmark_time"), &CPPBenchmark::set_benchmark_time);
ClassDB::add_property("CPPBenchmark", PropertyInfo(Variant::INT, "benchmark_time"), "set_benchmark_time", "get_benchmark_time");
ClassDB::bind_method(D_METHOD("get_test_render_cpu"), &CPPBenchmark::get_test_render_cpu);
ClassDB::bind_method(D_METHOD("set_test_render_cpu", "p_test_render_cpu"), &CPPBenchmark::set_test_render_cpu);
ClassDB::add_property("CPPBenchmark", PropertyInfo(Variant::BOOL, "test_render_cpu"), "set_test_render_cpu", "get_test_render_cpu");
ClassDB::bind_method(D_METHOD("get_test_render_gpu"), &CPPBenchmark::get_test_render_gpu);
ClassDB::bind_method(D_METHOD("set_test_render_gpu", "p_test_render_gpu"), &CPPBenchmark::set_test_render_gpu);
ClassDB::add_property("CPPBenchmark", PropertyInfo(Variant::BOOL, "test_render_gpu"), "set_test_render_gpu", "get_test_render_gpu");
ClassDB::bind_method(D_METHOD("get_test_idle"), &CPPBenchmark::get_test_idle);
ClassDB::bind_method(D_METHOD("set_test_idle", "p_test_idle"), &CPPBenchmark::set_test_idle);
ClassDB::add_property("CPPBenchmark", PropertyInfo(Variant::BOOL, "test_idle"), "set_test_idle", "get_test_idle");
ClassDB::bind_method(D_METHOD("get_test_physics"), &CPPBenchmark::get_test_physics);
ClassDB::bind_method(D_METHOD("set_test_physics", "p_test_physics"), &CPPBenchmark::set_test_physics);
ClassDB::add_property("CPPBenchmark", PropertyInfo(Variant::BOOL, "test_physics"), "set_test_physics", "get_test_physics");
}
CPPBenchmark::CPPBenchmark() {
// Initialize any variables here.
}
CPPBenchmark::~CPPBenchmark() {
// Add your cleanup here.
}
void CPPBenchmark::set_benchmark_time(const int p_benchmark_time) {
benchmark_time = p_benchmark_time;
}
int CPPBenchmark::get_benchmark_time() const {
return test_render_cpu;
}
void CPPBenchmark::set_test_render_cpu(const bool p_test_render_cpu) {
test_render_cpu = p_test_render_cpu;
}
bool CPPBenchmark::get_test_render_cpu() const {
return test_render_cpu;
}
void CPPBenchmark::set_test_render_gpu(const bool p_test_render_gpu) {
test_render_gpu = p_test_render_gpu;
}
bool CPPBenchmark::get_test_render_gpu() const {
return test_render_gpu;
}
void CPPBenchmark::set_test_idle(const bool p_test_idle) {
test_idle = p_test_idle;
}
bool CPPBenchmark::get_test_idle() const {
return test_idle;
}
void CPPBenchmark::set_test_physics(const bool p_test_physics) {
test_physics = p_test_physics;
}
bool CPPBenchmark::get_test_physics() const {
return test_physics;
}

View File

@@ -0,0 +1,32 @@
#ifndef CPP_BENCHMARK_H
#define CPP_BENCHMARK_H
#include <godot_cpp/classes/ref_counted.hpp>
namespace godot {
class CPPBenchmark : public RefCounted {
GDCLASS(CPPBenchmark, RefCounted)
protected:
static void _bind_methods();
int benchmark_time = 5e6;
bool test_render_cpu = false;
bool test_render_gpu = false;
bool test_idle = false;
bool test_physics = false;
public:
void set_benchmark_time(const int p_benchmark_time);
int get_benchmark_time() const;
void set_test_render_cpu(const bool p_test_render_cpu);
bool get_test_render_cpu() const;
void set_test_render_gpu(const bool p_test_render_gpu);
bool get_test_render_gpu() const;
void set_test_idle(const bool p_test_idle);
bool get_test_idle() const;
void set_test_physics(const bool p_test_physics);
bool get_test_physics() const;
CPPBenchmark();
~CPPBenchmark();
};
}
#endif

View File

@@ -0,0 +1,63 @@
#include "register_types.h"
#include "benchmarks/alloc.h"
#include "benchmarks/array.h"
#include "benchmarks/binary_trees.h"
#include "benchmarks/control.h"
#include "benchmarks/forloop.h"
#include "benchmarks/hello_world.h"
#include "benchmarks/lambda_performance.h"
#include "benchmarks/mandelbrot_set.h"
#include "benchmarks/merkle_trees.h"
#include "benchmarks/nbody.h"
#include "benchmarks/spectral_norm.h"
#include "benchmarks/string_checksum.h"
#include "benchmarks/string_format.h"
#include "benchmarks/string_manipulation.h"
#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>
using namespace godot;
void initialize_benchmark_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
ClassDB::register_class<CPPBenchmark>();
ClassDB::register_class<CPPBenchmarkAlloc>();
ClassDB::register_class<CPPBenchmarkArray>();
ClassDB::register_class<CPPBenchmarkBinaryTrees>();
ClassDB::register_class<CPPBenchmarkControl>();
ClassDB::register_class<CPPBenchmarkForLoop>();
ClassDB::register_class<CPPBenchmarkHelloWorld>();
ClassDB::register_class<CPPBenchmarkLambdaPerformance>();
ClassDB::register_class<CPPBenchmarkMandelbrotSet>();
ClassDB::register_class<CPPBenchmarkMerkleTrees>();
ClassDB::register_class<CPPBenchmarkNbody>();
ClassDB::register_class<CPPBenchmarkSpectralNorm>();
ClassDB::register_class<CPPBenchmarkStringChecksum>();
ClassDB::register_class<CPPBenchmarkStringFormat>();
ClassDB::register_class<CPPBenchmarkStringManipulation>();
}
void uninitialize_benchmark_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
}
extern "C" {
// Initialization.
GDExtensionBool GDE_EXPORT benchmark_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_benchmark_module);
init_obj.register_terminator(uninitialize_benchmark_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}

View File

@@ -0,0 +1,11 @@
#ifndef BENCHMARK_REGISTER_TYPES_H
#define BENCHMARK_REGISTER_TYPES_H
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void initialize_benchmark_module(ModuleInitializationLevel p_level);
void uninitialize_benchmark_module(ModuleInitializationLevel p_level);
#endif // BENCHMARK_REGISTER_TYPES_H

View File

@@ -1,6 +1,22 @@
extends Node
const RANDOM_SEED = 0x60d07
const RANDOM_SEED := 0x60d07
const CPP_CLASS_NAMES: Array[StringName] = [
&"CPPBenchmarkAlloc",
&"CPPBenchmarkArray",
&"CPPBenchmarkBinaryTrees",
&"CPPBenchmarkControl",
&"CPPBenchmarkForLoop",
&"CPPBenchmarkHelloWorld",
&"CPPBenchmarkLambdaPerformance",
&"CPPBenchmarkMandelbrotSet",
&"CPPBenchmarkMerkleTrees",
&"CPPBenchmarkNbody",
&"CPPBenchmarkSpectralNorm",
&"CPPBenchmarkStringChecksum",
&"CPPBenchmarkStringFormat",
&"CPPBenchmarkStringManipulation",
]
class Results:
var render_cpu := 0.0
@@ -49,10 +65,11 @@ func test_ids_from_path(path: String) -> Array[TestID]:
# List of supported languages and their styles.
var languages := {".gd": {"test_prefix": "benchmark_"}}
var languages := {".gd": {"test_prefix": "benchmark_"}, ".cpp": {"test_prefix": "benchmark_"}}
# List of benchmarks populated in `_ready()`.
var test_results := {}
var cpp_classes: Array[RefCounted] = []
var save_json_to_path := ""
var json_results_prefix := ""
@@ -78,7 +95,7 @@ func dir_contents(path: String, contents: PackedStringArray = PackedStringArray(
return contents
func _ready():
func _ready() -> void:
RenderingServer.viewport_set_measure_render_time(get_tree().root.get_viewport_rid(),true)
set_process(false)
@@ -91,6 +108,21 @@ func _ready():
for test_id in test_ids_from_path(benchmark_path):
test_results[test_id] = null
# Load GDExtension (C++) benchmarks
for cpp_class_name in CPP_CLASS_NAMES:
if not ClassDB.class_exists(cpp_class_name):
continue
var cpp_class = ClassDB.instantiate(cpp_class_name)
cpp_classes.append(cpp_class)
for method in cpp_class.get_method_list():
if not method.name.begins_with(languages[".cpp"]["test_prefix"]):
continue
var test_id := TestID.new()
test_id.name = method.name.trim_prefix(languages[".cpp"]["test_prefix"])
test_id.category = "C++/" + cpp_class.get_class().replace("CPPBenchmark", "")
test_id.language = ".cpp"
test_results[test_id] = null
func get_test_ids() -> Array[TestID]:
var rv : Array[TestID] = []
@@ -148,7 +180,19 @@ func run_test(test_id: TestID) -> void:
# Add a dummy child so that the above check works for subsequent reloads
get_tree().current_scene.add_child(Node.new())
var bench_script = load("res://benchmarks/%s%s" % [test_id.category, test_id.language]).new()
var language := test_id.language
var bench_script
if language != ".cpp":
bench_script = load("res://benchmarks/%s%s" % [test_id.category, language]).new()
else:
var cpp_class_name := "CPPBenchmark" + test_id.category.replace("C++", "").replace("/", "")
for cpp_class in cpp_classes:
if cpp_class_name == cpp_class.get_class():
bench_script = ClassDB.instantiate(cpp_class_name)
break
if not is_instance_valid(bench_script):
printerr("Benchmark not found!")
return
var results := Results.new()
# Call and time the function to be tested

View File

@@ -35,5 +35,3 @@ _subresources={}
fbx/importer=0
fbx/allow_geometry_helper_nodes=false
fbx/embedded_image_handling=1
gltf/naming_version=1
gltf/embedded_image_handling=1