UncacheableExpressionsBenchmark.cs 3.6 KB

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