|
@@ -3,298 +3,297 @@ using BenchmarkDotNet.Attributes;
|
|
|
using Jint.Native;
|
|
|
using Jint.Native.Array;
|
|
|
|
|
|
-namespace Jint.Benchmark
|
|
|
+namespace Jint.Benchmark;
|
|
|
+
|
|
|
+[MemoryDiagnoser]
|
|
|
+public class InteropBenchmark
|
|
|
{
|
|
|
- [MemoryDiagnoser]
|
|
|
- public class InteropBenchmark
|
|
|
+ private const int OperationsPerInvoke = 1_000;
|
|
|
+
|
|
|
+ public class Person
|
|
|
{
|
|
|
- private const int OperationsPerInvoke = 1_000;
|
|
|
+ public string Name { get; set; }
|
|
|
+ public int Age { get; set; }
|
|
|
+ }
|
|
|
|
|
|
- public class Person
|
|
|
- {
|
|
|
- public string Name { get; set; }
|
|
|
- public int Age { get; set; }
|
|
|
- }
|
|
|
+ private Engine _engine;
|
|
|
|
|
|
- private Engine _engine;
|
|
|
+ [GlobalSetup]
|
|
|
+ public void Setup()
|
|
|
+ {
|
|
|
+ _engine = new Engine(cfg => cfg.AllowClr(
|
|
|
+ typeof(Person).GetTypeInfo().Assembly,
|
|
|
+ typeof(Console).GetTypeInfo().Assembly,
|
|
|
+ typeof(System.IO.File).GetTypeInfo().Assembly))
|
|
|
+ .SetValue("log", new Action<object>(Console.WriteLine))
|
|
|
+ .SetValue("assert", new Action<bool>(x => { }))
|
|
|
+ .SetValue("equal", new Action<object, object>((x, y) => { }));
|
|
|
+ }
|
|
|
|
|
|
- [GlobalSetup]
|
|
|
- public void Setup()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void DelegatesCanBeSet()
|
|
|
+ {
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- _engine = new Engine(cfg => cfg.AllowClr(
|
|
|
- typeof(Person).GetTypeInfo().Assembly,
|
|
|
- typeof(Console).GetTypeInfo().Assembly,
|
|
|
- typeof(System.IO.File).GetTypeInfo().Assembly))
|
|
|
- .SetValue("log", new Action<object>(Console.WriteLine))
|
|
|
- .SetValue("assert", new Action<bool>(x => { }))
|
|
|
- .SetValue("equal", new Action<object, object>((x, y) => { }));
|
|
|
+ _engine.SetValue("square", new Func<double, double>(x => x * x));
|
|
|
+ _engine.Execute("assert(square(10) === 100);");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void DelegatesCanBeSet()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void ExtraParametersAreIgnored()
|
|
|
+ {
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("square", new Func<double, double>(x => x * x));
|
|
|
- _engine.Execute("assert(square(10) === 100);");
|
|
|
- }
|
|
|
+ _engine.SetValue("passNumber", new Func<int, int>(x => x));
|
|
|
+ _engine.Execute("assert(passNumber(123,'test',{},[],null) === 123);");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void ExtraParametersAreIgnored()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void GetObjectProperties()
|
|
|
+ {
|
|
|
+ var p = new Person
|
|
|
{
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("passNumber", new Func<int, int>(x => x));
|
|
|
- _engine.Execute("assert(passNumber(123,'test',{},[],null) === 123);");
|
|
|
- }
|
|
|
- }
|
|
|
+ Name = "Mickey Mouse"
|
|
|
+ };
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void GetObjectProperties()
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- var p = new Person
|
|
|
- {
|
|
|
- Name = "Mickey Mouse"
|
|
|
- };
|
|
|
-
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("p", p);
|
|
|
- _engine.Execute("assert(p.Name === 'Mickey Mouse');");
|
|
|
- }
|
|
|
+ _engine.SetValue("p", p);
|
|
|
+ _engine.Execute("assert(p.Name === 'Mickey Mouse');");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void InvokeObjectMethods()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void InvokeObjectMethods()
|
|
|
+ {
|
|
|
+ var p = new Person
|
|
|
{
|
|
|
- var p = new Person
|
|
|
- {
|
|
|
- Name = "Mickey Mouse"
|
|
|
- };
|
|
|
+ Name = "Mickey Mouse"
|
|
|
+ };
|
|
|
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("p", p);
|
|
|
- _engine.Execute(@"assert(p.ToString() === 'Mickey Mouse');");
|
|
|
- }
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("p", p);
|
|
|
+ _engine.Execute(@"assert(p.ToString() === 'Mickey Mouse');");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void SetObjectProperties()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void SetObjectProperties()
|
|
|
+ {
|
|
|
+ var p = new Person
|
|
|
{
|
|
|
- var p = new Person
|
|
|
- {
|
|
|
- Name = "Mickey Mouse"
|
|
|
- };
|
|
|
+ Name = "Mickey Mouse"
|
|
|
+ };
|
|
|
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("p", p);
|
|
|
- _engine.Execute("p.Name = 'Donald Duck'; assert(p.Name === 'Donald Duck');");
|
|
|
- }
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("p", p);
|
|
|
+ _engine.Execute("p.Name = 'Donald Duck'; assert(p.Name === 'Donald Duck');");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void GetIndexUsingStringKey()
|
|
|
- {
|
|
|
- var dictionary = new Dictionary<string, Person>();
|
|
|
- dictionary.Add("person1", new Person {Name = "Mickey Mouse"});
|
|
|
- dictionary.Add("person2", new Person {Name = "Goofy"});
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void GetIndexUsingStringKey()
|
|
|
+ {
|
|
|
+ var dictionary = new Dictionary<string, Person>();
|
|
|
+ dictionary.Add("person1", new Person {Name = "Mickey Mouse"});
|
|
|
+ dictionary.Add("person2", new Person {Name = "Goofy"});
|
|
|
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("dictionary", dictionary);
|
|
|
- _engine.Execute("assert(dictionary['person1'].Name === 'Mickey Mouse'); assert(dictionary['person2'].Name === 'Goofy');");
|
|
|
- }
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("dictionary", dictionary);
|
|
|
+ _engine.Execute("assert(dictionary['person1'].Name === 'Mickey Mouse'); assert(dictionary['person2'].Name === 'Goofy');");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void GenericMethods()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void GenericMethods()
|
|
|
+ {
|
|
|
+ var dictionary = new Dictionary<int, string>
|
|
|
{
|
|
|
- var dictionary = new Dictionary<int, string>
|
|
|
- {
|
|
|
- {1, "Mickey Mouse"}
|
|
|
- };
|
|
|
+ {1, "Mickey Mouse"}
|
|
|
+ };
|
|
|
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("dictionary", dictionary);
|
|
|
- _engine.Execute("dictionary.Clear(); dictionary.Add(2, 'Goofy'); assert(dictionary[2] === 'Goofy');");
|
|
|
- }
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("dictionary", dictionary);
|
|
|
+ _engine.Execute("dictionary.Clear(); dictionary.Add(2, 'Goofy'); assert(dictionary[2] === 'Goofy');");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void MultiGenericTypes()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void MultiGenericTypes()
|
|
|
+ {
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.Execute(@"
|
|
|
+ _engine.Execute(@"
|
|
|
var type = System.Collections.Generic.Dictionary(System.Int32, System.String);
|
|
|
var dictionary = new type();
|
|
|
dictionary.Add(1, 'Mickey Mouse');
|
|
|
dictionary.Add(2, 'Goofy');
|
|
|
assert(dictionary[2] === 'Goofy');
|
|
|
");
|
|
|
- }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void IndexOnList()
|
|
|
- {
|
|
|
- var list = new List<object>(2);
|
|
|
- list.Add("Mickey Mouse");
|
|
|
- list.Add("Goofy");
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void IndexOnList()
|
|
|
+ {
|
|
|
+ var list = new List<object>(2);
|
|
|
+ list.Add("Mickey Mouse");
|
|
|
+ list.Add("Goofy");
|
|
|
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("list", list);
|
|
|
- _engine.Execute("list[1] = 'Donald Duck'; assert(list[1] === 'Donald Duck');");
|
|
|
- }
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("list", list);
|
|
|
+ _engine.Execute("list[1] = 'Donald Duck'; assert(list[1] === 'Donald Duck');");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void EcmaValuesAreAutomaticallyConvertedWhenSetInPoco()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void EcmaValuesAreAutomaticallyConvertedWhenSetInPoco()
|
|
|
+ {
|
|
|
+ var p = new Person
|
|
|
{
|
|
|
- var p = new Person
|
|
|
- {
|
|
|
- Name = "foo",
|
|
|
- };
|
|
|
+ Name = "foo",
|
|
|
+ };
|
|
|
|
|
|
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("p", p);
|
|
|
- _engine.Execute(@"
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("p", p);
|
|
|
+ _engine.Execute(@"
|
|
|
assert(p.Name === 'foo');
|
|
|
assert(p.Age === 0);
|
|
|
p.Name = 'bar';
|
|
|
p.Age = 10;
|
|
|
");
|
|
|
- }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void Trim()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void Trim()
|
|
|
+ {
|
|
|
+ var p = new Person
|
|
|
{
|
|
|
- var p = new Person
|
|
|
- {
|
|
|
- Name = "Mickey Mouse "
|
|
|
- };
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("p", p);
|
|
|
- _engine.Execute(@"
|
|
|
+ Name = "Mickey Mouse "
|
|
|
+ };
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("p", p);
|
|
|
+ _engine.Execute(@"
|
|
|
assert(p.Name === 'Mickey Mouse ');
|
|
|
p.Name = p.Name.trim();
|
|
|
assert(p.Name === 'Mickey Mouse');
|
|
|
");
|
|
|
- }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void MathFloor()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void MathFloor()
|
|
|
+ {
|
|
|
+ var p = new Person();
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- var p = new Person();
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("p", p);
|
|
|
- _engine.Execute("p.Age = Math.floor(1.6); assert(p.Age === 1);");
|
|
|
- }
|
|
|
+ _engine.SetValue("p", p);
|
|
|
+ _engine.Execute("p.Age = Math.floor(1.6); assert(p.Age === 1);");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void DelegateAsFunction()
|
|
|
- {
|
|
|
- var even = new Func<int, bool>(x => x % 2 == 0);
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void DelegateAsFunction()
|
|
|
+ {
|
|
|
+ var even = new Func<int, bool>(x => x % 2 == 0);
|
|
|
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("even", even);
|
|
|
- _engine.Execute("assert(even(2) === true);");
|
|
|
- }
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("even", even);
|
|
|
+ _engine.Execute("assert(even(2) === true);");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void ConvertArrayToArrayInstance()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void ConvertArrayToArrayInstance()
|
|
|
+ {
|
|
|
+ var ints = new[] {1, 2, 3, 4, 5, 6};
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- var ints = new[] {1, 2, 3, 4, 5, 6};
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine
|
|
|
- .SetValue("values", ints)
|
|
|
- .Execute("values.filter(function(x){ return x % 2 == 0; })");
|
|
|
- }
|
|
|
+ _engine
|
|
|
+ .SetValue("values", ints)
|
|
|
+ .Execute("values.filter(function(x){ return x % 2 == 0; })");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void ConvertListsToArrayInstance()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void ConvertListsToArrayInstance()
|
|
|
+ {
|
|
|
+ var ints = new List<object> {1, 2, 3, 4, 5, 6};
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- var ints = new List<object> {1, 2, 3, 4, 5, 6};
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine
|
|
|
- .SetValue("values", ints)
|
|
|
- .Execute("new Array(values).filter(function(x){ return x % 2 == 0; })");
|
|
|
- }
|
|
|
+ _engine
|
|
|
+ .SetValue("values", ints)
|
|
|
+ .Execute("new Array(values).filter(function(x){ return x % 2 == 0; })");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void ConvertArrayInstanceToArray()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void ConvertArrayInstanceToArray()
|
|
|
+ {
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.Execute("'[email protected]'.split('@');");
|
|
|
- }
|
|
|
+ _engine.Execute("'[email protected]'.split('@');");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void ResolvingConsoleWriteLine()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void ResolvingConsoleWriteLine()
|
|
|
+ {
|
|
|
+ var originalOut = Console.Out;
|
|
|
+ Console.SetOut(TextWriter.Null);
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- var originalOut = Console.Out;
|
|
|
- Console.SetOut(TextWriter.Null);
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.Execute("System.Console.WriteLine('value to write');");
|
|
|
- }
|
|
|
- Console.SetOut(originalOut);
|
|
|
+ _engine.Execute("System.Console.WriteLine('value to write');");
|
|
|
}
|
|
|
+ Console.SetOut(originalOut);
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void Setter()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void Setter()
|
|
|
+ {
|
|
|
+ var p = new Person();
|
|
|
+ _engine.SetValue("p", p);
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
{
|
|
|
- var p = new Person();
|
|
|
- _engine.SetValue("p", p);
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.Execute("p.Age = 42;");
|
|
|
- }
|
|
|
+ _engine.Execute("p.Age = 42;");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
- public void LoopWithNativeEnumerator()
|
|
|
+ [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
|
|
|
+ public void LoopWithNativeEnumerator()
|
|
|
+ {
|
|
|
+ JsValue Adder(JsValue argValue)
|
|
|
{
|
|
|
- JsValue Adder(JsValue argValue)
|
|
|
+ ArrayInstance args = argValue.AsArray();
|
|
|
+ double sum = 0;
|
|
|
+ foreach (var item in args)
|
|
|
{
|
|
|
- ArrayInstance args = argValue.AsArray();
|
|
|
- double sum = 0;
|
|
|
- foreach (var item in args)
|
|
|
+ if (item.IsNumber())
|
|
|
{
|
|
|
- if (item.IsNumber())
|
|
|
- {
|
|
|
- sum += item.AsNumber();
|
|
|
- }
|
|
|
+ sum += item.AsNumber();
|
|
|
}
|
|
|
-
|
|
|
- return sum;
|
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
- {
|
|
|
- _engine.SetValue("getSum", new Func<JsValue, JsValue>(Adder));
|
|
|
- _engine.Execute("getSum([1,2,3]);");
|
|
|
- }
|
|
|
+ return sum;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < OperationsPerInvoke; ++i)
|
|
|
+ {
|
|
|
+ _engine.SetValue("getSum", new Func<JsValue, JsValue>(Adder));
|
|
|
+ _engine.Execute("getSum([1,2,3]);");
|
|
|
}
|
|
|
}
|
|
|
-}
|
|
|
+}
|