2
0

InteropBenchmark.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. using System.Reflection;
  2. using BenchmarkDotNet.Attributes;
  3. using Jint.Native;
  4. using Jint.Native.Array;
  5. namespace Jint.Benchmark;
  6. [MemoryDiagnoser]
  7. public class InteropBenchmark
  8. {
  9. private const int OperationsPerInvoke = 1_000;
  10. public class Person
  11. {
  12. public string Name { get; set; }
  13. public int Age { get; set; }
  14. }
  15. private Engine _engine;
  16. [GlobalSetup]
  17. public void Setup()
  18. {
  19. _engine = new Engine(cfg => cfg.AllowClr(
  20. typeof(Person).GetTypeInfo().Assembly,
  21. typeof(Console).GetTypeInfo().Assembly,
  22. typeof(System.IO.File).GetTypeInfo().Assembly))
  23. .SetValue("log", new Action<object>(Console.WriteLine))
  24. .SetValue("assert", new Action<bool>(x => { }))
  25. .SetValue("equal", new Action<object, object>((x, y) => { }));
  26. }
  27. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  28. public void DelegatesCanBeSet()
  29. {
  30. for (int i = 0; i < OperationsPerInvoke; ++i)
  31. {
  32. _engine.SetValue("square", new Func<double, double>(x => x * x));
  33. _engine.Execute("assert(square(10) === 100);");
  34. }
  35. }
  36. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  37. public void ExtraParametersAreIgnored()
  38. {
  39. for (int i = 0; i < OperationsPerInvoke; ++i)
  40. {
  41. _engine.SetValue("passNumber", new Func<int, int>(x => x));
  42. _engine.Execute("assert(passNumber(123,'test',{},[],null) === 123);");
  43. }
  44. }
  45. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  46. public void GetObjectProperties()
  47. {
  48. var p = new Person
  49. {
  50. Name = "Mickey Mouse"
  51. };
  52. for (int i = 0; i < OperationsPerInvoke; ++i)
  53. {
  54. _engine.SetValue("p", p);
  55. _engine.Execute("assert(p.Name === 'Mickey Mouse');");
  56. }
  57. }
  58. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  59. public void InvokeObjectMethods()
  60. {
  61. var p = new Person
  62. {
  63. Name = "Mickey Mouse"
  64. };
  65. for (int i = 0; i < OperationsPerInvoke; ++i)
  66. {
  67. _engine.SetValue("p", p);
  68. _engine.Execute(@"assert(p.ToString() === 'Mickey Mouse');");
  69. }
  70. }
  71. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  72. public void SetObjectProperties()
  73. {
  74. var p = new Person
  75. {
  76. Name = "Mickey Mouse"
  77. };
  78. for (int i = 0; i < OperationsPerInvoke; ++i)
  79. {
  80. _engine.SetValue("p", p);
  81. _engine.Execute("p.Name = 'Donald Duck'; assert(p.Name === 'Donald Duck');");
  82. }
  83. }
  84. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  85. public void GetIndexUsingStringKey()
  86. {
  87. var dictionary = new Dictionary<string, Person>();
  88. dictionary.Add("person1", new Person {Name = "Mickey Mouse"});
  89. dictionary.Add("person2", new Person {Name = "Goofy"});
  90. for (int i = 0; i < OperationsPerInvoke; ++i)
  91. {
  92. _engine.SetValue("dictionary", dictionary);
  93. _engine.Execute("assert(dictionary['person1'].Name === 'Mickey Mouse'); assert(dictionary['person2'].Name === 'Goofy');");
  94. }
  95. }
  96. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  97. public void GenericMethods()
  98. {
  99. var dictionary = new Dictionary<int, string>
  100. {
  101. {1, "Mickey Mouse"}
  102. };
  103. for (int i = 0; i < OperationsPerInvoke; ++i)
  104. {
  105. _engine.SetValue("dictionary", dictionary);
  106. _engine.Execute("dictionary.Clear(); dictionary.Add(2, 'Goofy'); assert(dictionary[2] === 'Goofy');");
  107. }
  108. }
  109. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  110. public void MultiGenericTypes()
  111. {
  112. for (int i = 0; i < OperationsPerInvoke; ++i)
  113. {
  114. _engine.Execute(@"
  115. var type = System.Collections.Generic.Dictionary(System.Int32, System.String);
  116. var dictionary = new type();
  117. dictionary.Add(1, 'Mickey Mouse');
  118. dictionary.Add(2, 'Goofy');
  119. assert(dictionary[2] === 'Goofy');
  120. ");
  121. }
  122. }
  123. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  124. public void IndexOnList()
  125. {
  126. var list = new List<object>(2);
  127. list.Add("Mickey Mouse");
  128. list.Add("Goofy");
  129. for (int i = 0; i < OperationsPerInvoke; ++i)
  130. {
  131. _engine.SetValue("list", list);
  132. _engine.Execute("list[1] = 'Donald Duck'; assert(list[1] === 'Donald Duck');");
  133. }
  134. }
  135. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  136. public void EcmaValuesAreAutomaticallyConvertedWhenSetInPoco()
  137. {
  138. var p = new Person
  139. {
  140. Name = "foo",
  141. };
  142. for (int i = 0; i < OperationsPerInvoke; ++i)
  143. {
  144. _engine.SetValue("p", p);
  145. _engine.Execute(@"
  146. assert(p.Name === 'foo');
  147. assert(p.Age === 0);
  148. p.Name = 'bar';
  149. p.Age = 10;
  150. ");
  151. }
  152. }
  153. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  154. public void Trim()
  155. {
  156. var p = new Person
  157. {
  158. Name = "Mickey Mouse "
  159. };
  160. for (int i = 0; i < OperationsPerInvoke; ++i)
  161. {
  162. _engine.SetValue("p", p);
  163. _engine.Execute(@"
  164. assert(p.Name === 'Mickey Mouse ');
  165. p.Name = p.Name.trim();
  166. assert(p.Name === 'Mickey Mouse');
  167. ");
  168. }
  169. }
  170. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  171. public void MathFloor()
  172. {
  173. var p = new Person();
  174. for (int i = 0; i < OperationsPerInvoke; ++i)
  175. {
  176. _engine.SetValue("p", p);
  177. _engine.Execute("p.Age = Math.floor(1.6); assert(p.Age === 1);");
  178. }
  179. }
  180. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  181. public void DelegateAsFunction()
  182. {
  183. var even = new Func<int, bool>(x => x % 2 == 0);
  184. for (int i = 0; i < OperationsPerInvoke; ++i)
  185. {
  186. _engine.SetValue("even", even);
  187. _engine.Execute("assert(even(2) === true);");
  188. }
  189. }
  190. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  191. public void ConvertArrayToArrayInstance()
  192. {
  193. var ints = new[] {1, 2, 3, 4, 5, 6};
  194. for (int i = 0; i < OperationsPerInvoke; ++i)
  195. {
  196. _engine
  197. .SetValue("values", ints)
  198. .Execute("values.filter(function(x){ return x % 2 == 0; })");
  199. }
  200. }
  201. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  202. public void ConvertListsToArrayInstance()
  203. {
  204. var ints = new List<object> {1, 2, 3, 4, 5, 6};
  205. for (int i = 0; i < OperationsPerInvoke; ++i)
  206. {
  207. _engine
  208. .SetValue("values", ints)
  209. .Execute("new Array(values).filter(function(x){ return x % 2 == 0; })");
  210. }
  211. }
  212. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  213. public void ConvertArrayInstanceToArray()
  214. {
  215. for (int i = 0; i < OperationsPerInvoke; ++i)
  216. {
  217. _engine.Execute("'[email protected]'.split('@');");
  218. }
  219. }
  220. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  221. public void ResolvingConsoleWriteLine()
  222. {
  223. var originalOut = Console.Out;
  224. Console.SetOut(TextWriter.Null);
  225. for (int i = 0; i < OperationsPerInvoke; ++i)
  226. {
  227. _engine.Execute("System.Console.WriteLine('value to write');");
  228. }
  229. Console.SetOut(originalOut);
  230. }
  231. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  232. public void Setter()
  233. {
  234. var p = new Person();
  235. _engine.SetValue("p", p);
  236. for (int i = 0; i < OperationsPerInvoke; ++i)
  237. {
  238. _engine.Execute("p.Age = 42;");
  239. }
  240. }
  241. [Benchmark(OperationsPerInvoke = OperationsPerInvoke)]
  242. public void LoopWithNativeEnumerator()
  243. {
  244. JsValue Adder(JsValue argValue)
  245. {
  246. ArrayInstance args = argValue.AsArray();
  247. double sum = 0;
  248. foreach (var item in args)
  249. {
  250. if (item.IsNumber())
  251. {
  252. sum += item.AsNumber();
  253. }
  254. }
  255. return sum;
  256. }
  257. for (int i = 0; i < OperationsPerInvoke; ++i)
  258. {
  259. _engine.SetValue("getSum", new Func<JsValue, JsValue>(Adder));
  260. _engine.Execute("getSum([1,2,3]);");
  261. }
  262. }
  263. }