UncacheableExpressionsBenchmark.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using BenchmarkDotNet.Attributes;
  7. using Jint.Native;
  8. using Newtonsoft.Json;
  9. using Undefined = Jint.Native.Undefined;
  10. namespace Jint.Benchmark
  11. {
  12. /// <summary>
  13. /// Test case for situation where object is projected via filter and map, Jint deems code as uncacheable.
  14. /// </summary>
  15. [MemoryDiagnoser]
  16. public class UncacheableExpressionsBenchmark
  17. {
  18. private Document doc;
  19. private string targetObject;
  20. private JsValue[] targetJsObject;
  21. private const string NonArrowFunctionScript = @"
  22. function output(d) {
  23. var doc = d.SubDocuments.find(function(x){return x.Id==='testing';});
  24. return { Id : d.Id, Deleted : d.Deleted, SubTestId : (doc!==null&&doc!==undefined)?doc.Id:null, Values : d.SubDocuments.map(function(x){return {TargetId:x.TargetId,TargetValue:x.TargetValue,SubDocuments:x.SubDocuments.filter(function(s){return (s!==null&&s!==undefined);}).map(function(s){return {TargetId:s.TargetId,TargetValue:s.TargetValue};})};}) };
  25. }
  26. ";
  27. private const string ArrowFunctionScript = @"
  28. function output(d) {
  29. let doc = d.SubDocuments.find(x => x.Id==='testing');
  30. return { Id : d.Id, Deleted : d.Deleted, SubTestId : (doc!==null&&doc!==undefined)?doc.Id:null, Values : d.SubDocuments.map(x => ({ TargetId:x.TargetId,TargetValue:x.TargetValue,SubDocuments:x.SubDocuments.filter(s => (s!==null&&s!==undefined)).map(s => ({ TargetId: s.TargetId, TargetValue: s.TargetValue}))})) };
  31. }
  32. ";
  33. private Engine engine;
  34. public class Document
  35. {
  36. public string Id { get; set; }
  37. public string TargetId { get; set; }
  38. public decimal TargetValue { get; set; }
  39. public bool Deleted { get; set; }
  40. public IEnumerable<Document> SubDocuments { get; set; }
  41. }
  42. [GlobalSetup]
  43. public void Setup()
  44. {
  45. doc = new Document
  46. {
  47. Deleted = false,
  48. SubDocuments = new List<Document>
  49. {
  50. new Document
  51. {
  52. TargetId = "id1",
  53. SubDocuments = Enumerable.Range(1, 200).Select(x => new Document()).ToList()
  54. },
  55. new Document
  56. {
  57. TargetId = "id2",
  58. SubDocuments = Enumerable.Range(1, 200).Select(x => new Document()).ToList()
  59. }
  60. }
  61. };
  62. using (var stream = new MemoryStream())
  63. {
  64. using (var writer = new StreamWriter(stream))
  65. {
  66. JsonSerializer.CreateDefault().Serialize(writer, doc);
  67. writer.Flush();
  68. var targetObjectJson = Encoding.UTF8.GetString(stream.ToArray());
  69. targetObject = $"var d = {targetObjectJson};";
  70. }
  71. }
  72. CreateEngine(Arrow ? ArrowFunctionScript : NonArrowFunctionScript);
  73. }
  74. private static void InitializeEngine(Options options)
  75. {
  76. options
  77. .LimitRecursion(64)
  78. .MaxStatements(int.MaxValue)
  79. .Strict()
  80. .LocalTimeZone(TimeZoneInfo.Utc);
  81. }
  82. [Params(500)]
  83. public int N { get; set; }
  84. [Params(true, false)]
  85. public bool Arrow { get; set; }
  86. [Benchmark]
  87. public void Benchmark()
  88. {
  89. var call = engine.GetValue("output").TryCast<ICallable>();
  90. for (int i = 0; i < N; ++i)
  91. {
  92. call.Call(Undefined.Instance, targetJsObject);
  93. }
  94. }
  95. private void CreateEngine(string script)
  96. {
  97. engine = new Engine(InitializeEngine);
  98. engine.Execute(script);
  99. engine.Execute(targetObject);
  100. targetJsObject = new[] {engine.GetValue("d")};
  101. }
  102. }
  103. }