forked from Mirror/wren
Add a benchmark to test the Wren C API.
I've got some ideas on how to tweak the embedding API, but I want to see what performance impact they have first, so this adds a little benchmark that just calls a foreign method a ton of times.
This commit is contained in:
21
test/api/benchmark.c
Normal file
21
test/api/benchmark.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
|
||||
static void arguments(WrenVM* vm)
|
||||
{
|
||||
double result = 0;
|
||||
result += wrenGetArgumentDouble(vm, 1);
|
||||
result += wrenGetArgumentDouble(vm, 2);
|
||||
result += wrenGetArgumentDouble(vm, 3);
|
||||
result += wrenGetArgumentDouble(vm, 4);
|
||||
|
||||
wrenReturnDouble(vm, result);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn benchmarkBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Benchmark.arguments(_,_,_,_)") == 0) return arguments;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
3
test/api/benchmark.h
Normal file
3
test/api/benchmark.h
Normal file
@ -0,0 +1,3 @@
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn benchmarkBindMethod(const char* signature);
|
||||
@ -5,10 +5,10 @@
|
||||
|
||||
void callRunTests(WrenVM* vm)
|
||||
{
|
||||
WrenValue* noParams = wrenGetMethod(vm, "main", "Api", "noParams");
|
||||
WrenValue* zero = wrenGetMethod(vm, "main", "Api", "zero()");
|
||||
WrenValue* one = wrenGetMethod(vm, "main", "Api", "one(_)");
|
||||
WrenValue* two = wrenGetMethod(vm, "main", "Api", "two(_,_)");
|
||||
WrenValue* noParams = wrenGetMethod(vm, "main", "Call", "noParams");
|
||||
WrenValue* zero = wrenGetMethod(vm, "main", "Call", "zero()");
|
||||
WrenValue* one = wrenGetMethod(vm, "main", "Call", "one(_)");
|
||||
WrenValue* two = wrenGetMethod(vm, "main", "Call", "two(_,_)");
|
||||
|
||||
// Different arity.
|
||||
wrenCall(vm, noParams, NULL, "");
|
||||
@ -16,7 +16,7 @@ void callRunTests(WrenVM* vm)
|
||||
wrenCall(vm, one, NULL, "i", 1);
|
||||
wrenCall(vm, two, NULL, "ii", 1, 2);
|
||||
|
||||
WrenValue* getValue = wrenGetMethod(vm, "main", "Api", "getValue(_)");
|
||||
WrenValue* getValue = wrenGetMethod(vm, "main", "Call", "getValue(_)");
|
||||
|
||||
// Returning a value.
|
||||
WrenValue* value = NULL;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
class Api {
|
||||
class Call {
|
||||
static noParams {
|
||||
System.print("noParams")
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ static void resourceFinalize(WrenVM* vm)
|
||||
|
||||
WrenForeignMethodFn foreignClassBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.finalized") == 0) return apiFinalized;
|
||||
if (strcmp(signature, "static ForeignClass.finalized") == 0) return apiFinalized;
|
||||
if (strcmp(signature, "Counter.increment(_)") == 0) return counterIncrement;
|
||||
if (strcmp(signature, "Counter.value") == 0) return counterValue;
|
||||
if (strcmp(signature, "Point.translate(_,_,_)") == 0) return pointTranslate;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
class Api {
|
||||
class ForeignClass {
|
||||
foreign static finalized
|
||||
}
|
||||
|
||||
@ -64,14 +64,14 @@ var resources = [
|
||||
]
|
||||
|
||||
System.gc()
|
||||
System.print(Api.finalized) // expect: 0
|
||||
System.print(ForeignClass.finalized) // expect: 0
|
||||
|
||||
resources.removeAt(-1)
|
||||
|
||||
System.gc()
|
||||
System.print(Api.finalized) // expect: 1
|
||||
System.print(ForeignClass.finalized) // expect: 1
|
||||
|
||||
resources.clear()
|
||||
|
||||
System.gc()
|
||||
System.print(Api.finalized) // expect: 3
|
||||
System.print(ForeignClass.finalized) // expect: 3
|
||||
|
||||
@ -4,27 +4,19 @@
|
||||
#include "vm.h"
|
||||
#include "wren.h"
|
||||
|
||||
#include "benchmark.h"
|
||||
#include "call.h"
|
||||
#include "foreign_class.h"
|
||||
#include "returns.h"
|
||||
#include "value.h"
|
||||
|
||||
#define REGISTER_METHOD(name, camelCase) \
|
||||
if (strcmp(testName, #name) == 0) return camelCase##BindMethod(fullName)
|
||||
|
||||
#define REGISTER_CLASS(name, camelCase) \
|
||||
if (strcmp(testName, #name) == 0) \
|
||||
{ \
|
||||
camelCase##BindClass(className, &methods); \
|
||||
}
|
||||
|
||||
// The name of the currently executing API test.
|
||||
const char* testName;
|
||||
|
||||
static WrenForeignMethodFn bindForeignMethod(
|
||||
WrenVM* vm, const char* module, const char* className,
|
||||
bool isStatic, const char* signature)
|
||||
{
|
||||
{
|
||||
if (strcmp(module, "main") != 0) return NULL;
|
||||
|
||||
// For convenience, concatenate all of the method qualifiers into a single
|
||||
@ -35,10 +27,20 @@ static WrenForeignMethodFn bindForeignMethod(
|
||||
strcat(fullName, className);
|
||||
strcat(fullName, ".");
|
||||
strcat(fullName, signature);
|
||||
|
||||
REGISTER_METHOD(foreign_class, foreignClass);
|
||||
REGISTER_METHOD(returns, returns);
|
||||
REGISTER_METHOD(value, value);
|
||||
|
||||
WrenForeignMethodFn method = NULL;
|
||||
|
||||
method = benchmarkBindMethod(fullName);
|
||||
if (method != NULL) return method;
|
||||
|
||||
method = foreignClassBindMethod(fullName);
|
||||
if (method != NULL) return method;
|
||||
|
||||
method = returnsBindMethod(fullName);
|
||||
if (method != NULL) return method;
|
||||
|
||||
method = valueBindMethod(fullName);
|
||||
if (method != NULL) return method;
|
||||
|
||||
fprintf(stderr,
|
||||
"Unknown foreign method '%s' for test '%s'\n", fullName, testName);
|
||||
@ -52,13 +54,13 @@ static WrenForeignClassMethods bindForeignClass(
|
||||
WrenForeignClassMethods methods = { NULL, NULL };
|
||||
if (strcmp(module, "main") != 0) return methods;
|
||||
|
||||
REGISTER_CLASS(foreign_class, foreignClass);
|
||||
foreignClassBindClass(className, &methods);
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
static void afterLoad(WrenVM* vm) {
|
||||
if (strcmp(testName, "call") == 0) callRunTests(vm);
|
||||
if (strstr(testName, "call.wren") != NULL) callRunTests(vm);
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
@ -70,14 +72,7 @@ int main(int argc, const char* argv[])
|
||||
}
|
||||
|
||||
testName = argv[1];
|
||||
|
||||
// The test script is at "test/api/<test>.wren".
|
||||
char testPath[256];
|
||||
strcpy(testPath, "test/api/");
|
||||
strcat(testPath, testName);
|
||||
strcat(testPath, ".wren");
|
||||
|
||||
setTestCallbacks(bindForeignMethod, bindForeignClass, afterLoad);
|
||||
runFile(testPath);
|
||||
runFile(testName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -39,13 +39,13 @@ static void returnBytes(WrenVM* vm)
|
||||
|
||||
WrenForeignMethodFn returnsBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.implicitNull") == 0) return implicitNull;
|
||||
if (strcmp(signature, "static Api.returnInt") == 0) return returnInt;
|
||||
if (strcmp(signature, "static Api.returnFloat") == 0) return returnFloat;
|
||||
if (strcmp(signature, "static Api.returnTrue") == 0) return returnTrue;
|
||||
if (strcmp(signature, "static Api.returnFalse") == 0) return returnFalse;
|
||||
if (strcmp(signature, "static Api.returnString") == 0) return returnString;
|
||||
if (strcmp(signature, "static Api.returnBytes") == 0) return returnBytes;
|
||||
if (strcmp(signature, "static Returns.implicitNull") == 0) return implicitNull;
|
||||
if (strcmp(signature, "static Returns.returnInt") == 0) return returnInt;
|
||||
if (strcmp(signature, "static Returns.returnFloat") == 0) return returnFloat;
|
||||
if (strcmp(signature, "static Returns.returnTrue") == 0) return returnTrue;
|
||||
if (strcmp(signature, "static Returns.returnFalse") == 0) return returnFalse;
|
||||
if (strcmp(signature, "static Returns.returnString") == 0) return returnString;
|
||||
if (strcmp(signature, "static Returns.returnBytes") == 0) return returnBytes;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
class Api {
|
||||
class Returns {
|
||||
foreign static implicitNull
|
||||
|
||||
foreign static returnInt
|
||||
@ -11,13 +11,13 @@ class Api {
|
||||
foreign static returnBytes
|
||||
}
|
||||
|
||||
System.print(Api.implicitNull == null) // expect: true
|
||||
System.print(Returns.implicitNull == null) // expect: true
|
||||
|
||||
System.print(Api.returnInt) // expect: 123456
|
||||
System.print(Api.returnFloat) // expect: 123.456
|
||||
System.print(Returns.returnInt) // expect: 123456
|
||||
System.print(Returns.returnFloat) // expect: 123.456
|
||||
|
||||
System.print(Api.returnTrue) // expect: true
|
||||
System.print(Api.returnFalse) // expect: false
|
||||
System.print(Returns.returnTrue) // expect: true
|
||||
System.print(Returns.returnFalse) // expect: false
|
||||
|
||||
System.print(Api.returnString) // expect: a string
|
||||
System.print(Api.returnBytes.bytes.toList) // expect: [97, 0, 98, 0, 99]
|
||||
System.print(Returns.returnString) // expect: a string
|
||||
System.print(Returns.returnBytes.bytes.toList) // expect: [97, 0, 98, 0, 99]
|
||||
|
||||
@ -17,8 +17,8 @@ static void getValue(WrenVM* vm)
|
||||
|
||||
WrenForeignMethodFn valueBindMethod(const char* signature)
|
||||
{
|
||||
if (strcmp(signature, "static Api.value=(_)") == 0) return setValue;
|
||||
if (strcmp(signature, "static Api.value") == 0) return getValue;
|
||||
if (strcmp(signature, "static Value.value=(_)") == 0) return setValue;
|
||||
if (strcmp(signature, "static Value.value") == 0) return getValue;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
class Api {
|
||||
class Value {
|
||||
foreign static value=(value)
|
||||
foreign static value
|
||||
}
|
||||
|
||||
Api.value = ["list", "of", "strings"]
|
||||
Value.value = ["list", "of", "strings"]
|
||||
|
||||
// Do some stuff to trigger a GC (at least when GC stress testing enabled).
|
||||
var s = "string"
|
||||
@ -11,4 +11,4 @@ for (i in 1...10) {
|
||||
s = s + " more"
|
||||
}
|
||||
|
||||
System.print(Api.value) // expect: [list, of, strings]
|
||||
System.print(Value.value) // expect: [list, of, strings]
|
||||
|
||||
Reference in New Issue
Block a user