InteropBenchmark.cs 9.4 KB

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