InteropBenchmark.cs 9.5 KB

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