UncacheableExpressionsBenchmark.cs 3.9 KB

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