UncacheableExpressionsBenchmark.cs 3.5 KB

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