UncacheableExpressionsBenchmark.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. using System.Text;
  2. using System.Text.Json;
  3. using BenchmarkDotNet.Attributes;
  4. using Jint.Native;
  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. JsonSerializer.Serialize(stream, doc);
  59. var targetObjectJson = Encoding.UTF8.GetString(stream.ToArray());
  60. targetObject = $"var d = {targetObjectJson};";
  61. }
  62. CreateEngine(Arrow ? ArrowFunctionScript : NonArrowFunctionScript);
  63. }
  64. private static void InitializeEngine(Options options)
  65. {
  66. options
  67. .LimitRecursion(64)
  68. .MaxStatements(int.MaxValue)
  69. .Strict()
  70. .LocalTimeZone(TimeZoneInfo.Utc);
  71. }
  72. [Params(500)]
  73. public int N { get; set; }
  74. [Params(true, false)]
  75. public bool Arrow { get; set; }
  76. [Benchmark]
  77. public void Benchmark()
  78. {
  79. var call = engine.GetValue("output").TryCast<ICallable>();
  80. for (int i = 0; i < N; ++i)
  81. {
  82. call.Call(JsValue.Undefined, targetJsObject);
  83. }
  84. }
  85. private void CreateEngine(string script)
  86. {
  87. engine = new Engine(InitializeEngine);
  88. engine.Execute(script);
  89. engine.Execute(targetObject);
  90. targetJsObject = [engine.GetValue("d")];
  91. }
  92. }