source: webkit/trunk/Source/JavaScriptCore/dynbench.cpp@ 194175

Last change on this file since 194175 was 194175, checked in by [email protected], 9 years ago

Improve JSObject::put performance
https://bugs.webkit.org/show_bug.cgi?id=152347

Reviewed by Geoffrey Garen.

This adds a new benchmark called dynbench, which just uses the C++ API to create, modify, and
query objects. This also adds some optimizations to make the JSObject::put code faster by making
it inlinable in places that really need the performance, like JITOperations and LLIntSlowPaths.
Inlining it is optional because the put() method is large. If you want it inlined, call
putInline(). There's a putInline() variant of both JSObject::put() and JSValue::put().

This is up to a 20% improvement for JSObject::put calls that get inlined all the way (like from
JITOperations and the new benchmark) and it's also a speed-up, albeit a smaller one, for
JSObject::put calls that don't get inlined (i.e. those from the DOM and the JSC C++ library code).
Specific speed-ups are as follows. Note that "dynamic context" means that we told PutPropertySlot
that we're not a static put_by_id, which turns off some type inference.

Get By Id: 2% faster
Put By Id Replace: 23% faster
Put By Id Transition + object allocation: 11% faster
Get By Id w/ dynamic context: 5% faster
Put By Id Replace w/ dynamic context: 25% faster
Put By Id Transition + object allocation w/ dynamic context: 10% faster

(JSC::benchmarkImpl):
(main):

  • jit/CallFrameShuffler32_64.cpp:
  • jit/CallFrameShuffler64.cpp:
  • jit/JITOperations.cpp:
  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/ClassInfo.h:

(JSC::ClassInfo::hasStaticProperties):

  • runtime/ConsoleClient.cpp:
  • runtime/CustomGetterSetter.h:
  • runtime/ErrorInstance.cpp:

(JSC::ErrorInstance::finishCreation):
(JSC::addErrorInfoAndGetBytecodeOffset): Deleted.

  • runtime/GetterSetter.h:

(JSC::asGetterSetter):

  • runtime/JSCInlines.h:
  • runtime/JSCJSValue.h:
  • runtime/JSCJSValueInlines.h:

(JSC::JSValue::put):
(JSC::JSValue::putInternal):
(JSC::JSValue::putByIndex):

  • runtime/JSObject.cpp:

(JSC::JSObject::put):
(JSC::JSObject::putByIndex):

  • runtime/JSObject.h:

(JSC::JSObject::getVectorLength):
(JSC::JSObject::inlineGetOwnPropertySlot):
(JSC::JSObject::get):
(JSC::JSObject::putDirectInternal):

File size: 9.0 KB
Line 
1/*
2 * Copyright (C) 2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "Identifier.h"
29#include "InitializeThreading.h"
30#include "JSCInlines.h"
31#include "JSCJSValue.h"
32#include "JSGlobalObject.h"
33#include "JSLock.h"
34#include "JSObject.h"
35#include "VM.h"
36
37using namespace JSC;
38
39namespace {
40
41StaticLock crashLock;
42const char* nameFilter;
43unsigned requestedIterationCount;
44
45#define CHECK(x) do { \
46 if (!!(x)) \
47 break; \
48 crashLock.lock(); \
49 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
50 CRASH(); \
51 } while (false)
52
53template<typename Callback>
54NEVER_INLINE void benchmarkImpl(const char* name, unsigned iterationCount, const Callback& callback)
55{
56 if (nameFilter && !strcasestr(name, nameFilter))
57 return;
58
59 if (requestedIterationCount)
60 iterationCount = requestedIterationCount;
61
62 double before = monotonicallyIncreasingTimeMS();
63 callback(iterationCount);
64 double after = monotonicallyIncreasingTimeMS();
65 dataLog(name, ": ", after - before, " ms.\n");
66}
67
68} // anonymous namespace
69
70int main(int argc, char** argv)
71{
72 if (argc >= 2) {
73 if (argv[1][0] == '-') {
74 dataLog("Usage: dynbench [<filter> [<iteration count>]]\n");
75 return 1;
76 }
77
78 nameFilter = argv[1];
79
80 if (argc >= 3) {
81 if (sscanf(argv[2], "%u", &requestedIterationCount) != 1) {
82 dataLog("Could not parse iteration count ", argv[2], "\n");
83 return 1;
84 }
85 }
86 }
87
88 WTF::initializeMainThread();
89 JSC::initializeThreading();
90
91 VM* vm = &VM::create(LargeHeap).leakRef();
92 {
93 JSLockHolder locker(vm);
94
95 JSGlobalObject* globalObject =
96 JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
97 ExecState* exec = globalObject->globalExec();
98
99 Identifier identF = Identifier::fromString(exec, "f");
100 Identifier identG = Identifier::fromString(exec, "g");
101
102 Structure* objectStructure =
103 JSFinalObject::createStructure(*vm, globalObject, globalObject->objectPrototype(), 2);
104
105 // Non-strict dynamic get by id:
106 JSValue object = JSFinalObject::create(*vm, objectStructure);
107 {
108 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
109 object.putInline(exec, identF, jsNumber(42), slot);
110 }
111 {
112 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
113 object.putInline(exec, identG, jsNumber(43), slot);
114 }
115 benchmarkImpl(
116 "Non Strict Dynamic Get By Id",
117 1000000,
118 [&] (unsigned iterationCount) {
119 for (unsigned i = iterationCount; i--;) {
120 JSValue result = object.get(exec, identF);
121 CHECK(result == jsNumber(42));
122 result = object.get(exec, identG);
123 CHECK(result == jsNumber(43));
124 }
125 });
126
127 // Non-strict dynamic put by id replace:
128 object = JSFinalObject::create(*vm, objectStructure);
129 {
130 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
131 object.putInline(exec, identF, jsNumber(42), slot);
132 }
133 {
134 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
135 object.putInline(exec, identG, jsNumber(43), slot);
136 }
137 benchmarkImpl(
138 "Non Strict Dynamic Put By Id Replace",
139 1000000,
140 [&] (unsigned iterationCount) {
141 for (unsigned i = iterationCount; i--;) {
142 {
143 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
144 object.putInline(exec, identF, jsNumber(i), slot);
145 }
146 {
147 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
148 object.putInline(exec, identG, jsNumber(i), slot);
149 }
150 }
151 });
152
153 // Non-strict dynamic put by id transition with object allocation:
154 benchmarkImpl(
155 "Non Strict Dynamic Allocation and Put By Id Transition",
156 1000000,
157 [&] (unsigned iterationCount) {
158 for (unsigned i = iterationCount; i--;) {
159 JSValue object = JSFinalObject::create(*vm, objectStructure);
160 {
161 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
162 object.putInline(exec, identF, jsNumber(i), slot);
163 }
164 {
165 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
166 object.putInline(exec, identG, jsNumber(i), slot);
167 }
168 }
169 });
170
171 // Non-strict dynamic get by id with dynamic store context:
172 object = JSFinalObject::create(*vm, objectStructure);
173 {
174 PutPropertySlot slot(object, false);
175 object.putInline(exec, identF, jsNumber(42), slot);
176 }
177 {
178 PutPropertySlot slot(object, false);
179 object.putInline(exec, identG, jsNumber(43), slot);
180 }
181 benchmarkImpl(
182 "Non Strict Dynamic Get By Id With Dynamic Store Context",
183 1000000,
184 [&] (unsigned iterationCount) {
185 for (unsigned i = iterationCount; i--;) {
186 JSValue result = object.get(exec, identF);
187 CHECK(result == jsNumber(42));
188 result = object.get(exec, identG);
189 CHECK(result == jsNumber(43));
190 }
191 });
192
193 // Non-strict dynamic put by id replace with dynamic store context:
194 object = JSFinalObject::create(*vm, objectStructure);
195 {
196 PutPropertySlot slot(object, false);
197 object.putInline(exec, identF, jsNumber(42), slot);
198 }
199 {
200 PutPropertySlot slot(object, false);
201 object.putInline(exec, identG, jsNumber(43), slot);
202 }
203 benchmarkImpl(
204 "Non Strict Dynamic Put By Id Replace With Dynamic Store Context",
205 1000000,
206 [&] (unsigned iterationCount) {
207 for (unsigned i = iterationCount; i--;) {
208 {
209 PutPropertySlot slot(object, false);
210 object.putInline(exec, identF, jsNumber(i), slot);
211 }
212 {
213 PutPropertySlot slot(object, false);
214 object.putInline(exec, identG, jsNumber(i), slot);
215 }
216 }
217 });
218
219 // Non-strict dynamic put by id transition with object allocation with dynamic store context:
220 benchmarkImpl(
221 "Non Strict Dynamic Allocation and Put By Id Transition With Dynamic Store Context",
222 1000000,
223 [&] (unsigned iterationCount) {
224 for (unsigned i = iterationCount; i--;) {
225 JSValue object = JSFinalObject::create(*vm, objectStructure);
226 {
227 PutPropertySlot slot(object, false);
228 object.putInline(exec, identF, jsNumber(i), slot);
229 }
230 {
231 PutPropertySlot slot(object, false);
232 object.putInline(exec, identG, jsNumber(i), slot);
233 }
234 }
235 });
236 }
237
238 crashLock.lock();
239 return 0;
240}
241
Note: See TracBrowser for help on using the repository browser.