feat: add wrenGetValueDouble API and benchmark for wrenCall() performance

Add a new public API function wrenGetValueDouble() to extract numeric values from WrenValue handles, with proper assertions for NULL and type checking. Introduce a comprehensive benchmark test for wrenCall() that measures invocation overhead by calling a foreign method 1,000,000 times across a separate VM instance, validating result correctness and reporting elapsed time. Include the benchmark script api_call.wren and register it in the Python benchmarking harness. Also fix minor assertion message typos in wren_vm.c for consistency.
This commit is contained in:
Bob Nystrom
2015-12-24 01:29:53 +00:00
parent 5865f534fc
commit 51bc3a828c
6 changed files with 76 additions and 3 deletions
+48
View File
@@ -1,4 +1,5 @@
#include <string.h>
#include <time.h>
#include "benchmark.h"
@@ -14,9 +15,56 @@ static void arguments(WrenVM* vm)
wrenSetSlotDouble(vm, 0, result);
}
const char* testScript =
"class Test {\n"
" static method(a, b, c, d) { a + b + c + d }\n"
"}\n";
static void call(WrenVM* vm)
{
int iterations = (int)wrenGetSlotDouble(vm, 1);
// Since the VM is not re-entrant, we can't call from within this foreign
// method. Instead, make a new VM to run the call test in.
WrenConfiguration config;
wrenInitConfiguration(&config);
WrenVM* otherVM = wrenNewVM(&config);
wrenInterpret(otherVM, testScript);
WrenValue* method = wrenGetMethod(otherVM, "main", "Test", "method(_,_,_,_)");
double startTime = (double)clock() / CLOCKS_PER_SEC;
double result = 0;
for (int i = 0; i < iterations; i++)
{
WrenValue* resultValue;
wrenCall(otherVM, method, &resultValue, "dddd", 1.0, 2.0, 3.0, 4.0);
result += wrenGetValueDouble(otherVM, resultValue);
wrenReleaseValue(otherVM, resultValue);
}
double elapsed = (double)clock() / CLOCKS_PER_SEC - startTime;
wrenReleaseValue(otherVM, method);
wrenFreeVM(otherVM);
if (result == (1.0 + 2.0 + 3.0 + 4.0) * iterations)
{
wrenSetSlotDouble(vm, 0, elapsed);
}
else
{
// Got the wrong result.
wrenSetSlotBool(vm, 0, false);
}
}
WrenForeignMethodFn benchmarkBindMethod(const char* signature)
{
if (strcmp(signature, "static Benchmark.arguments(_,_,_,_)") == 0) return arguments;
if (strcmp(signature, "static Benchmark.call(_)") == 0) return call;
return NULL;
}
+1 -1
View File
@@ -64,7 +64,7 @@ static WrenForeignClassMethods bindForeignClass(
}
static void afterLoad(WrenVM* vm) {
if (strstr(testName, "call.wren") != NULL) callRunTests(vm);
if (strstr(testName, "/call.wren") != NULL) callRunTests(vm);
}
int main(int argc, const char* argv[])
+9
View File
@@ -0,0 +1,9 @@
class Benchmark {
foreign static call(iterations)
}
var result = Benchmark.call(1000000)
// Returns false if it didn't calculate the right value. Otherwise returns the
// elapsed time.
System.print(result is Num)
System.print("elapsed: %(result)")