Commit 5796ae9d authored by ishell's avatar ishell Committed by Commit bot

[js-perf-test] Add microbenchmarks for in operator and Object.prototype.hasOwnProperty().

BUG=v8:2472, v8:2743
LOG=N

Review URL: https://codereview.chromium.org/1913813003

Cr-Commit-Position: refs/heads/master@{#35789}
parent c514cf1f
...@@ -163,6 +163,71 @@ ...@@ -163,6 +163,71 @@
{"name": "for (i < array.length)"}, {"name": "for (i < array.length)"},
{"name": "for (i < length)"} {"name": "for (i < length)"}
] ]
},
{
"name": "PropertyQueries",
"path": ["PropertyQueries"],
"main": "run.js",
"resources": ["property-queries.js"],
"results_regexp": "^%s\\-PropertyQueries\\(Score\\): (.+)$",
"tests": [
{"name": "in--query-internalized-prop--fast-obj"},
{"name": "in--query-internalized-prop--slow-obj"},
{"name": "in--query-internalized-prop--fast-obj-with-slow-proto"},
{"name": "in--query-internalized-prop--slow-obj-with-slow-proto"},
{"name": "in--query-deinternalized-prop--fast-obj"},
{"name": "in--query-deinternalized-prop--slow-obj"},
{"name": "in--query-deinternalized-prop--fast-obj-with-slow-proto"},
{"name": "in--query-deinternalized-prop--slow-obj-with-slow-proto"},
{"name": "in--query-non-existing-internalized-prop--fast-obj"},
{"name": "in--query-non-existing-internalized-prop--slow-obj"},
{"name": "in--query-non-existing-internalized-prop--fast-obj-with-slow-proto"},
{"name": "in--query-non-existing-internalized-prop--slow-obj-with-slow-proto"},
{"name": "in--query-non-existing-deinternalized-prop--fast-obj"},
{"name": "in--query-non-existing-deinternalized-prop--slow-obj"},
{"name": "in--query-non-existing-deinternalized-prop--fast-obj-with-slow-proto"},
{"name": "in--query-non-existing-deinternalized-prop--slow-obj-with-slow-proto"},
{"name": "in--query-element--fast-obj"},
{"name": "in--query-element--slow-obj"},
{"name": "in--query-element--fast-obj-with-slow-proto"},
{"name": "in--query-element--slow-obj-with-slow-proto"},
{"name": "in--query-element-as-string--fast-obj"},
{"name": "in--query-element-as-string--slow-obj"},
{"name": "in--query-element-as-string--fast-obj-with-slow-proto"},
{"name": "in--query-element-as-string--slow-obj-with-slow-proto"},
{"name": "in--query-non-existing-element--fast-obj"},
{"name": "in--query-non-existing-element--slow-obj"},
{"name": "in--query-non-existing-element--fast-obj-with-slow-proto"},
{"name": "in--query-non-existing-element--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-internalized-prop--fast-obj"},
{"name": "Object.hasOwnProperty--query-internalized-prop--slow-obj"},
{"name": "Object.hasOwnProperty--query-internalized-prop--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-internalized-prop--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-deinternalized-prop--fast-obj"},
{"name": "Object.hasOwnProperty--query-deinternalized-prop--slow-obj"},
{"name": "Object.hasOwnProperty--query-deinternalized-prop--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-deinternalized-prop--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-internalized-prop--fast-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-internalized-prop--slow-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-internalized-prop--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-internalized-prop--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-deinternalized-prop--fast-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-deinternalized-prop--slow-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-deinternalized-prop--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-deinternalized-prop--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-element--fast-obj"},
{"name": "Object.hasOwnProperty--query-element--slow-obj"},
{"name": "Object.hasOwnProperty--query-element--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-element--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-element-as-string--fast-obj"},
{"name": "Object.hasOwnProperty--query-element-as-string--slow-obj"},
{"name": "Object.hasOwnProperty--query-element-as-string--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-element-as-string--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-element--fast-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-element--slow-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-element--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-element--slow-obj-with-slow-proto"}
]
} }
] ]
} }
{
"name": "PropertyQueriesTests",
"run_count": 5,
"run_count_android_arm": 3,
"run_count_android_arm64": 3,
"timeout": 120,
"units": "score",
"total": true,
"resources": ["base.js"],
"tests": [
{
"name": "PropertyQueries",
"path": ["."],
"main": "run.js",
"flags": [""],
"resources": [
"property-queries.js"
],
"results_regexp": "^%s\\-PropertyQueries\\(Score\\): (.+)$",
"tests": [
{"name": "in--query-internalized-prop--fast-obj"},
{"name": "in--query-internalized-prop--slow-obj"},
{"name": "in--query-internalized-prop--fast-obj-with-slow-proto"},
{"name": "in--query-internalized-prop--slow-obj-with-slow-proto"},
{"name": "in--query-deinternalized-prop--fast-obj"},
{"name": "in--query-deinternalized-prop--slow-obj"},
{"name": "in--query-deinternalized-prop--fast-obj-with-slow-proto"},
{"name": "in--query-deinternalized-prop--slow-obj-with-slow-proto"},
{"name": "in--query-non-existing-internalized-prop--fast-obj"},
{"name": "in--query-non-existing-internalized-prop--slow-obj"},
{"name": "in--query-non-existing-internalized-prop--fast-obj-with-slow-proto"},
{"name": "in--query-non-existing-internalized-prop--slow-obj-with-slow-proto"},
{"name": "in--query-non-existing-deinternalized-prop--fast-obj"},
{"name": "in--query-non-existing-deinternalized-prop--slow-obj"},
{"name": "in--query-non-existing-deinternalized-prop--fast-obj-with-slow-proto"},
{"name": "in--query-non-existing-deinternalized-prop--slow-obj-with-slow-proto"},
{"name": "in--query-element--fast-obj"},
{"name": "in--query-element--slow-obj"},
{"name": "in--query-element--fast-obj-with-slow-proto"},
{"name": "in--query-element--slow-obj-with-slow-proto"},
{"name": "in--query-element-as-string--fast-obj"},
{"name": "in--query-element-as-string--slow-obj"},
{"name": "in--query-element-as-string--fast-obj-with-slow-proto"},
{"name": "in--query-element-as-string--slow-obj-with-slow-proto"},
{"name": "in--query-non-existing-element--fast-obj"},
{"name": "in--query-non-existing-element--slow-obj"},
{"name": "in--query-non-existing-element--fast-obj-with-slow-proto"},
{"name": "in--query-non-existing-element--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-internalized-prop--fast-obj"},
{"name": "Object.hasOwnProperty--query-internalized-prop--slow-obj"},
{"name": "Object.hasOwnProperty--query-internalized-prop--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-internalized-prop--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-deinternalized-prop--fast-obj"},
{"name": "Object.hasOwnProperty--query-deinternalized-prop--slow-obj"},
{"name": "Object.hasOwnProperty--query-deinternalized-prop--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-deinternalized-prop--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-internalized-prop--fast-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-internalized-prop--slow-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-internalized-prop--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-internalized-prop--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-deinternalized-prop--fast-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-deinternalized-prop--slow-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-deinternalized-prop--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-deinternalized-prop--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-element--fast-obj"},
{"name": "Object.hasOwnProperty--query-element--slow-obj"},
{"name": "Object.hasOwnProperty--query-element--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-element--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-element-as-string--fast-obj"},
{"name": "Object.hasOwnProperty--query-element-as-string--slow-obj"},
{"name": "Object.hasOwnProperty--query-element-as-string--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-element-as-string--slow-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-element--fast-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-element--slow-obj"},
{"name": "Object.hasOwnProperty--query-non-existing-element--fast-obj-with-slow-proto"},
{"name": "Object.hasOwnProperty--query-non-existing-element--slow-obj-with-slow-proto"}
]
}
]
}
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function ObjectWithKeys(count, keyOffset = 0, keyGen) {
var o = {};
for (var i = 0; i < count; i++) {
var key = keyGen(i + keyOffset);
o[key] = "value";
}
return o;
}
function ObjectWithProperties(count, keyOffset) {
return ObjectWithKeys(count, keyOffset, (key) => "key" + key );
}
function ObjectWithElements(count, keyOffset) {
return ObjectWithKeys(count, keyOffset, (key) => key );
}
function ObjectWithMixedKeys(count, keyOffset) {
return ObjectWithKeys(count, keyOffset, (key) => {
if (key % 2 == 0) return (key / 2);
return "key" + ((key - 1) / 2);
});
}
// Create an object with #depth prototypes each having #keys properties
// generated by given keyGen.
function ObjectWithProtoKeys(depth, keys, cacheable,
keyGen = ObjectWithProperties) {
var o = keyGen(keys);
var current = o;
var keyOffset = 0;
for (var i = 0; i < depth; i++) {
keyOffset += keys;
current.__proto__ = keyGen(keys, keyOffset);
current = current.__proto__;
}
if (cacheable === false) {
// Add an empty proxy at the prototype chain to make caching properties
// impossible.
current.__proto__ = new Proxy({}, {});
}
return o;
}
function HoleyIntArray(size) {
var array = new Array(size);
for (var i = 0; i < size; i += 3) {
array[i] = i;
}
return array
}
function IntArray(size) {
var array = new Array(size);
for (var i = 0; i < size; i++) {
array[i] = i;
}
return array;
}
// Switch object's properties and elements to dictionary mode.
function MakeDictionaryMode(obj) {
obj.foo = 0;
delete obj.foo;
obj[1e9] = 0;
return obj;
}
function Internalize(s) {
return Object.keys({[s]:0})[0];
}
function Deinternalize(s) {
return [...s].join("");
}
// ============================================================================
const QUERY_INTERNALIZED_PROP = "query-internalized-prop";
const QUERY_DEINTERNALIZED_PROP = "query-deinternalized-prop";
const QUERY_NON_EXISTING_INTERNALIZED_PROP =
"query-non-existing-internalized-prop";
const QUERY_NON_EXISTING_DEINTERNALIZED_PROP =
"query-non-existing-deinternalized-prop";
const QUERY_ELEMENT = "query-element";
const QUERY_ELEMENT_AS_STRING = "query-element-as-string";
const QUERY_NON_EXISTING_ELEMENT = "query-non-existing-element";
const OBJ_MODE_FAST = "fast";
const OBJ_MODE_SLOW = "slow";
var TestQueries = [
QUERY_INTERNALIZED_PROP,
QUERY_DEINTERNALIZED_PROP,
QUERY_NON_EXISTING_INTERNALIZED_PROP,
QUERY_NON_EXISTING_DEINTERNALIZED_PROP,
QUERY_ELEMENT,
QUERY_ELEMENT_AS_STRING,
QUERY_NON_EXISTING_ELEMENT,
];
const QUERIES_PER_OBJECT_NUMBER = 10;
// Leave only every "count"th keys.
function FilterKeys(keys, count) {
var len = keys.length;
if (len < count) throw new Error("Keys array is too short: " + len);
var step = len / count;
if (step == 0) throw new Error("Bad count specified: " + count);
return keys.filter((element, index) => index % step == 0);
}
function MakeKeyQueries(keys, query_kind) {
var properties = keys.filter((element) => isNaN(Number(element)));
var elements = keys.filter((element) => !isNaN(Number(element)));
properties = FilterKeys(properties, QUERIES_PER_OBJECT_NUMBER);
elements = FilterKeys(elements, QUERIES_PER_OBJECT_NUMBER);
switch (query_kind) {
case QUERY_INTERNALIZED_PROP:
return properties;
case QUERY_DEINTERNALIZED_PROP:
return properties.map(Deinternalize);
case QUERY_NON_EXISTING_INTERNALIZED_PROP:
case QUERY_NON_EXISTING_DEINTERNALIZED_PROP:
var non_existing = [];
for (var i = 0; i < QUERIES_PER_OBJECT_NUMBER; i++) {
non_existing.push("non-existing" + i);
}
if (query_kind == QUERY_NON_EXISTING_INTERNALIZED_PROP) {
return non_existing.map(Internalize);
} else {
return non_existing.map(Deinternalize);
}
case QUERY_ELEMENT:
return elements.map(Number);
case QUERY_ELEMENT_AS_STRING:
return elements.map(String);
case QUERY_NON_EXISTING_ELEMENT:
var non_existing = [];
for (var i = 0; i < QUERIES_PER_OBJECT_NUMBER; i++) {
non_existing.push(1200 + 100*i);
}
return non_existing;
default:
throw new Error("Bad query_kind: " + query_kind);
}
}
var TestData = [];
[true, false].forEach((cachable) => {
[OBJ_MODE_FAST, OBJ_MODE_SLOW].forEach((obj_mode) => {
var proto_mode = cachable ? "" : "-with-slow-proto";
var name = `${obj_mode}-obj${proto_mode}`;
var objects = [];
[10, 50, 100, 200, 500, 1000].forEach((prop_count) => {
// Create object with prop_count properties and prop_count elements.
obj = ObjectWithProtoKeys(5, prop_count * 2, cachable,
ObjectWithMixedKeys);
if (obj_mode == OBJ_MODE_SLOW) {
obj = MakeDictionaryMode(obj);
}
objects.push(obj);
});
TestData.push({name, objects});
});
});
// ============================================================================
function CreateTestFunction(template, object, keys) {
// Force a new function for each test-object to avoid side-effects due to ICs.
var text = "// random comment " + Math.random() + "\n" +
template(object, keys);
var func = new Function("object", "keys", text);
return () => func(object, keys);
}
var TestFunctions = [
{
name: "in",
// Query all keys.
keys: (object) => Object.keys(object),
template: (object, keys) => {
var lines = [
`var result = true;`,
`for (var i = 0; i < keys.length; i++) {`,
` var key = keys[i];`,
` result = (key in object) && result;`,
`}`,
`return result;`,
];
return lines.join("\n");
},
},
{
name: "Object.hasOwnProperty",
// Query only own keys.
keys: (object) => Object.getOwnPropertyNames(object),
template: (object, keys) => {
var lines = [
`var result = true;`,
`for (var i = 0; i < keys.length; i++) {`,
` var key = keys[i];`,
` result = object.hasOwnProperty(key) && result;`,
`}`,
`return result;`,
];
return lines.join("\n");
},
},
];
// ============================================================================
// Create the benchmark suites. We create a suite for each pair of the test
// functions above and query kind. Each suite contains benchmarks for each
// object type.
var Benchmarks = [];
for (var test_function_desc of TestFunctions) {
var test_function_name = test_function_desc.name;
for (var query_kind of TestQueries) {
for (var test_data of TestData) {
var benchmarks = [];
var name = test_function_name + "--" + query_kind + "--" + test_data.name;
for (var object of test_data.objects) {
var keys = test_function_desc.keys(object);
keys = MakeKeyQueries(keys, query_kind);
var test_function = CreateTestFunction(test_function_desc.template,
object, keys);
var benchmark = new Benchmark(name, false, true, 400, test_function);
benchmarks.push(benchmark);
}
Benchmarks.push(new BenchmarkSuite(name, [100], benchmarks));
}
}
}
// ============================================================================
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
load('../base.js');
load('property-queries.js');
var success = true;
function PrintResult(name, result) {
print(name + '-PropertyQueries(Score): ' + result);
}
function PrintError(name, error) {
PrintResult(name, error);
success = false;
}
BenchmarkSuite.config.doWarmup = undefined;
BenchmarkSuite.config.doDeterministic = undefined;
BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
NotifyError: PrintError });
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment