Przeglądaj źródła

add benchmark that imitates RavenDB projection

Marko Lahma 7 lat temu
rodzic
commit
1e705658a3
1 zmienionych plików z 192 dodań i 0 usunięć
  1. 192 0
      Jint.Benchmark/UncacheableExpressionsBenchmark.cs

+ 192 - 0
Jint.Benchmark/UncacheableExpressionsBenchmark.cs

@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Diagnosers;
+using BenchmarkDotNet.Jobs;
+using Jint.Native;
+using Newtonsoft.Json;
+using Undefined = Jint.Native.Undefined;
+
+namespace Jint.Benchmark
+{
+    /// <summary>
+    /// Test case for situation where object is projected via filter and map, Jint deems code as uncacheable.
+    /// </summary>
+    [Config(typeof(Config))]
+    public class UncacheableExpressionsBenchmark
+    {
+        private class Config : ManualConfig
+        {
+            public Config()
+            {
+                Add(Job.MediumRun);
+                Add(MemoryDiagnoser.Default);
+            }
+        }
+
+        private Document doc;
+
+        private string targetObject;
+        private JsValue[] targetJsObject;
+
+        private const string script = @"
+function output(d) {
+    var doc = d.SubDocuments.find(function(x){return x.Id==='testing';});
+    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};})};}) };
+}
+";
+
+        private Engine engine;
+
+        public class Document
+        {
+            public string Id { get; set; }
+            public string TargetId { get; set; }
+            public decimal TargetValue { get; set; }
+            public bool Deleted { get; set; }
+            public IEnumerable<Document> SubDocuments { get; set; }
+        }
+
+        [GlobalSetup]
+        public void Setup()
+        {
+            doc = new Document
+            {
+                Deleted = false,
+                SubDocuments = new List<Document>
+                {
+                    new Document
+                    {
+                        TargetId = "id1",
+                        SubDocuments = Enumerable.Range(1, 200).Select(x => new Document()).ToList()
+                    },
+                    new Document
+                    {
+                        TargetId = "id2",
+                        SubDocuments = Enumerable.Range(1, 200).Select(x => new Document()).ToList()
+                    }
+                }
+            };
+
+            using (var stream = new MemoryStream())
+            {
+                using (var writer = new StreamWriter(stream))
+                {
+                    JsonSerializer.CreateDefault().Serialize(writer, doc);
+                    writer.Flush();
+
+                    var targetObjectJson = Encoding.UTF8.GetString(stream.ToArray());
+                    targetObject = $"var d = {targetObjectJson};";
+                }
+            }
+
+            CreateEngine();
+        }
+
+        private static void InitializeEngine(Options options)
+        {
+            options
+                .LimitRecursion(64)
+                .MaxStatements(int.MaxValue)
+                .Strict()
+                .LocalTimeZone(TimeZoneInfo.Utc);
+        }
+
+        [Params(500)]
+        public int N { get; set; }
+
+        [Benchmark]
+        public void Benchmark()
+        {
+            var call = engine.GetValue("output").TryCast<ICallable>();
+            for (int i = 0; i < N; ++i)
+            {
+                call.Call(Undefined.Instance, targetJsObject);
+            }
+        }
+
+        private void CreateEngine()
+        {
+            engine = new Engine(InitializeEngine);
+            engine.Execute(Polyfills);
+            engine.Execute(script);
+            engine.Execute(targetObject);
+            targetJsObject = new[] {engine.GetValue("d")};
+        }
+
+        private const string Polyfills = @"
+//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
+if (!String.prototype.endsWith) {
+    String.prototype.endsWith = function (searchStr, position) {
+        if (!(position < this.length))
+            position = this.length;
+        else
+            position |= 0; // round position
+        return this.substr(position - searchStr.length,
+            searchStr.length) === searchStr;
+    };
+}
+//https://github.com/jsPolyfill/Array.prototype.find/blob/master/find.js
+if (!Array.prototype.find) {
+    Array.prototype.find = Array.prototype.find || function(callback) {
+        if (this === null) {
+            throw new TypeError('Array.prototype.find called on null or undefined');
+        } else if (typeof callback !== 'function') {
+            throw new TypeError('callback must be a function');
+        }
+        var list = Object(this);
+        // Makes sures is always has an positive integer as length.
+        var length = list.length >>> 0;
+        var thisArg = arguments[1];
+        for (var i = 0; i < length; i++) {
+            var element = list[i];
+            if ( callback.call(thisArg, element, i, list) ) {
+                return element;
+            }
+        }
+    };
+}
+
+if (!Array.prototype.fastFilter) {
+    Array.prototype.fastFilter = function(callback) {
+        var results = [];
+        var item;
+        var len = this.length;
+        for (var i = 0, len = len; i < len; i++) {
+            item = this[i];
+            if (callback(item)) results.push(item);
+        }
+        return results;
+    }
+}
+
+if (!Array.prototype.fastMap) {
+    Array.prototype.fastMap = function(callback) {
+        var h = [];
+        var len = this.length;
+        for (var i = 0, len = len; i < len; i++) {
+            h.push(callback(this[i]));
+        }
+        return h;
+    }
+}
+
+
+if (!Array.prototype.fastFind) {
+    Array.prototype.fastFind = function(callback) {
+        var item;
+        var len = this.length;
+        for (var i = 0, len = len; i < len; i++) {
+            item = this[i];
+            if (callback(item)) return item;
+        }
+    }
+}
+
+";
+    }
+}