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

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

Replace all of the various non-working and non-compiling sampling profiler hacks with a single super hack
https://bugs.webkit.org/show_bug.cgi?id=155561

Reviewed by Saam Barati.

Source/JavaScriptCore:

A VM needs some internal profiling hacks in addition to the profiler(s) that the user sees, because
you can squeeze out more fidelity if you're willing to make some kind of deal with the devil. Prior
to this change JSC had a bunch of these:

  • CodeBlock sampling profiler
  • Bytecode sampling profiler
  • Sampling flags
  • Sampling regions
  • Some other stuff

I tried using these recently. They didn't even build. Initially I fixed that, but then I found that
these profilers had some serious bugs that made them report bogus results - like underreporting the
time spent in regions of code by more than 2x.

Part of the problem here is that a profiler loses fidelity as it gains power. The more general it
tries to be, the more code gets executed on the hot path for the profiler, which increasingly
perturbs the results. I believe that's the reason for the underreporting - code ran sufficiently
slower, and in a sufficiently different way when profiling, that the results were just wrong.

This change attacks this problem directly by replacing all of the diverse profiling hacks with just
one, which I call the SuperSampler. It consists of exactly one counter. When enabled, the sampler
will periodically print (via dataLog()) the percentage of samples that saw a non-zero count. Because
it's so simple, it gives better accuracy. This comes about in two ways:

  • It runs at a lower rate. That's fine since it's only checking one flag. You don't need a high rate for just one flag.


  • The fact that there is only *one* flag means that the user must choose a hypothesis about what is slow. This turns the problem of profiling into a hypothesis testing problem, which is an inherently less flaky kind of experiment to run.


The SuperSampler is enabled with a runtime flag rather than a compile-time flag, so it's much less
likely to break. That also means that you can enable it without rebuilding the universe. The old
samplers all had ENABLE flags in Platform.h, which was rather unfortunate for compile times.

SuperSampler supports both JIT and C++ users. C++ users should use SuperSamplerScope. The default
idiom is to create one and pass "true" to it. You can disable a scope by passing "false" instead.
This patch puts a bunch of scopes in places I care about. I think it's probably OK if people check in
these deactivated scopes. That makes it convenient to retest things we've tested previously.

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/SamplingTool.cpp: Removed.
  • bytecode/SamplingTool.h: Removed.
  • bytecode/SuperSampler.cpp: Added.

(JSC::initializeSuperSampler):
(JSC::printSuperSamplerState):

  • bytecode/SuperSampler.h: Added.

(JSC::SuperSamplerScope::SuperSamplerScope):
(JSC::SuperSamplerScope::~SuperSamplerScope):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):

  • bytecompiler/NodesCodegen.cpp:
  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::forAllValues):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::clobberStructures):

  • dfg/DFGArgumentsEliminationPhase.cpp:

(JSC::DFG::performArgumentsElimination):

  • dfg/DFGBackwardsPropagationPhase.cpp:

(JSC::DFG::performBackwardsPropagation):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::parse):

  • dfg/DFGCFAPhase.cpp:

(JSC::DFG::performCFA):

  • dfg/DFGCFGSimplificationPhase.cpp:

(JSC::DFG::performCFGSimplification):

  • dfg/DFGCPSRethreadingPhase.cpp:

(JSC::DFG::CPSRethreadingPhase::freeUnnecessaryNodes):
(JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlocks):
(JSC::DFG::CPSRethreadingPhase::propagatePhis):
(JSC::DFG::performCPSRethreading):

  • dfg/DFGCSEPhase.cpp:

(JSC::DFG::performLocalCSE):
(JSC::DFG::performGlobalCSE):

  • dfg/DFGCleanUpPhase.cpp:

(JSC::DFG::performCleanUp):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::performConstantFolding):

  • dfg/DFGConstantHoistingPhase.cpp:

(JSC::DFG::performConstantHoisting):

  • dfg/DFGCriticalEdgeBreakingPhase.cpp:

(JSC::DFG::performCriticalEdgeBreaking):

  • dfg/DFGDCEPhase.cpp:

(JSC::DFG::performDCE):

  • dfg/DFGDriver.cpp:

(JSC::DFG::compileImpl):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::performFixup):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dethread):

  • dfg/DFGIntegerCheckCombiningPhase.cpp:

(JSC::DFG::performIntegerCheckCombining):

  • dfg/DFGIntegerRangeOptimizationPhase.cpp:

(JSC::DFG::performIntegerRangeOptimization):

  • dfg/DFGInvalidationPointInjectionPhase.cpp:

(JSC::DFG::performInvalidationPointInjection):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):

  • dfg/DFGLICMPhase.cpp:

(JSC::DFG::performLICM):

  • dfg/DFGLiveCatchVariablePreservationPhase.cpp:

(JSC::DFG::performLiveCatchVariablePreservationPhase):

  • dfg/DFGLivenessAnalysisPhase.cpp:

(JSC::DFG::performLivenessAnalysis):

  • dfg/DFGLoopPreHeaderCreationPhase.cpp:

(JSC::DFG::performLoopPreHeaderCreation):

  • dfg/DFGMaximalFlushInsertionPhase.cpp:

(JSC::DFG::performMaximalFlushInsertion):

  • dfg/DFGMovHintRemovalPhase.cpp:

(JSC::DFG::performMovHintRemoval):

  • dfg/DFGOSRAvailabilityAnalysisPhase.cpp:

(JSC::DFG::performOSRAvailabilityAnalysis):

  • dfg/DFGOSREntrypointCreationPhase.cpp:

(JSC::DFG::performOSREntrypointCreation):

  • dfg/DFGOSRExitCompiler.cpp:
  • dfg/DFGObjectAllocationSinkingPhase.cpp:

(JSC::DFG::performObjectAllocationSinking):

  • dfg/DFGOperations.cpp:
  • dfg/DFGPhantomInsertionPhase.cpp:

(JSC::DFG::performPhantomInsertion):

  • dfg/DFGPlan.cpp:

(JSC::DFG::Plan::compileInThread):

  • dfg/DFGPredictionInjectionPhase.cpp:

(JSC::DFG::performPredictionInjection):

  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::performPredictionPropagation):

  • dfg/DFGPutStackSinkingPhase.cpp:

(JSC::DFG::performPutStackSinking):

  • dfg/DFGSSAConversionPhase.cpp:

(JSC::DFG::performSSAConversion):

  • dfg/DFGSSALoweringPhase.cpp:

(JSC::DFG::performSSALowering):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGStackLayoutPhase.cpp:

(JSC::DFG::performStackLayout):

  • dfg/DFGStaticExecutionCountEstimationPhase.cpp:

(JSC::DFG::performStaticExecutionCountEstimation):

  • dfg/DFGStoreBarrierInsertionPhase.cpp:

(JSC::DFG::performFastStoreBarrierInsertion):
(JSC::DFG::performGlobalStoreBarrierInsertion):

  • dfg/DFGStrengthReductionPhase.cpp:

(JSC::DFG::performStrengthReduction):

  • dfg/DFGStructureAbstractValue.cpp:

(JSC::DFG::StructureAbstractValue::assertIsRegistered):
(JSC::DFG::StructureAbstractValue::clobber):
(JSC::DFG::StructureAbstractValue::observeTransition):
(JSC::DFG::StructureAbstractValue::observeTransitions):
(JSC::DFG::StructureAbstractValue::add):
(JSC::DFG::StructureAbstractValue::merge):
(JSC::DFG::StructureAbstractValue::mergeSlow):
(JSC::DFG::StructureAbstractValue::mergeNotTop):
(JSC::DFG::StructureAbstractValue::filter):
(JSC::DFG::StructureAbstractValue::filterSlow):
(JSC::DFG::StructureAbstractValue::contains):
(JSC::DFG::StructureAbstractValue::isSubsetOf):
(JSC::DFG::StructureAbstractValue::isSupersetOf):
(JSC::DFG::StructureAbstractValue::overlaps):
(JSC::DFG::StructureAbstractValue::equalsSlow):

  • dfg/DFGStructureRegistrationPhase.cpp:

(JSC::DFG::performStructureRegistration):

  • dfg/DFGTierUpCheckInjectionPhase.cpp:

(JSC::DFG::performTierUpCheckInjection):

  • dfg/DFGTypeCheckHoistingPhase.cpp:

(JSC::DFG::performTypeCheckHoisting):

  • dfg/DFGUnificationPhase.cpp:

(JSC::DFG::performUnification):

  • dfg/DFGVarargsForwardingPhase.cpp:

(JSC::DFG::performVarargsForwarding):

  • dfg/DFGVirtualRegisterAllocationPhase.cpp:

(JSC::DFG::performVirtualRegisterAllocation):

  • dfg/DFGWatchpointCollectionPhase.cpp:

(JSC::DFG::performWatchpointCollection):

  • dynbench.cpp:
  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileRegExpExec):
(JSC::FTL::DFG::LowerDFGToB3::compileRegExpTest):
(JSC::FTL::DFG::LowerDFGToB3::compileStringReplace):
(JSC::FTL::DFG::LowerDFGToB3::compileGetRegExpObjectLastIndex):

  • ftl/FTLOSRExitCompiler.cpp:

(JSC::FTL::compileFTLOSRExit):

  • ftl/FTLOutput.cpp:

(JSC::FTL::Output::store):
(JSC::FTL::Output::absolute):
(JSC::FTL::Output::incrementSuperSamplerCount):
(JSC::FTL::Output::decrementSuperSamplerCount):

  • ftl/FTLOutput.h:

(JSC::FTL::Output::baseIndex):
(JSC::FTL::Output::load8SignExt32):
(JSC::FTL::Output::load8ZeroExt32):
(JSC::FTL::Output::anchor):
(JSC::FTL::Output::absolute): Deleted.

  • heap/Heap.cpp:

(JSC::Heap::markRoots):
(JSC::Heap::collectAndSweep):
(JSC::Heap::collectImpl):
(JSC::Heap::zombifyDeadObjects):

  • heap/MarkedBlock.cpp:

(JSC::MarkedBlock::specializedSweep):

  • interpreter/Interpreter.cpp:

(JSC::setupVarargsFrameAndSetThis):
(JSC::Interpreter::Interpreter):
(JSC::Interpreter::initialize):
(JSC::checkedReturn):
(JSC::Interpreter::execute):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::debug):
(JSC::SamplingScope::SamplingScope): Deleted.
(JSC::SamplingScope::~SamplingScope): Deleted.
(JSC::Interpreter::enableSampler): Deleted.
(JSC::Interpreter::dumpSampleData): Deleted.
(JSC::Interpreter::startSampling): Deleted.
(JSC::Interpreter::stopSampling): Deleted.

  • interpreter/Interpreter.h:

(JSC::Interpreter::isCallBytecode):
(JSC::Interpreter::sampler): Deleted.

  • jit/AssemblyHelpers.cpp:

(JSC::AssemblyHelpers::branchIfNotFastTypedArray):
(JSC::AssemblyHelpers::incrementSuperSamplerCount):
(JSC::AssemblyHelpers::decrementSuperSamplerCount):
(JSC::AssemblyHelpers::purifyNaN):

  • jit/AssemblyHelpers.h:
  • jit/JIT.cpp:
  • jit/JIT.h:
  • jit/JITArithmetic.cpp:
  • jit/JITArithmetic32_64.cpp:
  • jit/JITCall.cpp:
  • jit/JITCall32_64.cpp:
  • jit/JITOperations.cpp:
  • jit/JITPropertyAccess.cpp:
  • jit/JITPropertyAccess32_64.cpp:
  • jsc.cpp:

(runWithScripts):
(jscmain):

  • parser/Nodes.cpp:
  • parser/Parser.h:

(JSC::parse):

  • runtime/Executable.h:
  • runtime/InitializeThreading.cpp:

(JSC::initializeThreading):

  • runtime/Options.h:
  • runtime/RegExpCachedResult.h:
  • runtime/RegExpMatchesArray.h:

(JSC::createRegExpMatchesArray):

  • runtime/StringPrototype.cpp:

(JSC::removeUsingRegExpSearch):
(JSC::stringProtoFuncSubstring):

  • runtime/VM.cpp:

(JSC::VM::resetDateCache):
(JSC::VM::whenIdle):
(JSC::VM::deleteAllCode):
(JSC::VM::addSourceProviderCache):
(JSC::VM::startSampling): Deleted.
(JSC::VM::stopSampling): Deleted.
(JSC::VM::dumpSampleData): Deleted.

  • runtime/VM.h:

(JSC::VM::regExpCache):

  • testRegExp.cpp:

(runFromFiles):

  • yarr/YarrInterpreter.cpp:

(JSC::Yarr::interpret):

Source/WebCore:

No new tests because no new behavior.

  • platform/audio/ios/MediaSessionManagerIOS.mm:
  • platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:

Source/WTF:

This patch replaces all of our various ad hoc profiling hacks with a single ad hoc profiling hack.
That needs to be able to sleep a thread, so I added a portable way to do it.

This also removes a bunch of ENABLE flags for all of the old non-working hacks.

  • wtf/CurrentTime.cpp:

(WTF::currentCPUTime):
(WTF::sleep):

  • wtf/CurrentTime.h:

(WTF::sleepMS):

  • wtf/Platform.h:
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#include <wtf/MainThread.h>
37
38using namespace JSC;
39
40namespace {
41
42StaticLock crashLock;
43const char* nameFilter;
44unsigned requestedIterationCount;
45
46#define CHECK(x) do { \
47 if (!!(x)) \
48 break; \
49 crashLock.lock(); \
50 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
51 CRASH(); \
52 } while (false)
53
54template<typename Callback>
55NEVER_INLINE void benchmarkImpl(const char* name, unsigned iterationCount, const Callback& callback)
56{
57 if (nameFilter && !strcasestr(name, nameFilter))
58 return;
59
60 if (requestedIterationCount)
61 iterationCount = requestedIterationCount;
62
63 double before = monotonicallyIncreasingTimeMS();
64 callback(iterationCount);
65 double after = monotonicallyIncreasingTimeMS();
66 dataLog(name, ": ", after - before, " ms.\n");
67}
68
69} // anonymous namespace
70
71int main(int argc, char** argv)
72{
73 if (argc >= 2) {
74 if (argv[1][0] == '-') {
75 dataLog("Usage: dynbench [<filter> [<iteration count>]]\n");
76 return 1;
77 }
78
79 nameFilter = argv[1];
80
81 if (argc >= 3) {
82 if (sscanf(argv[2], "%u", &requestedIterationCount) != 1) {
83 dataLog("Could not parse iteration count ", argv[2], "\n");
84 return 1;
85 }
86 }
87 }
88
89 WTF::initializeMainThread();
90 JSC::initializeThreading();
91
92 VM* vm = &VM::create(LargeHeap).leakRef();
93 {
94 JSLockHolder locker(vm);
95
96 JSGlobalObject* globalObject =
97 JSGlobalObject::create(*vm, JSGlobalObject::createStructure(*vm, jsNull()));
98 ExecState* exec = globalObject->globalExec();
99
100 Identifier identF = Identifier::fromString(exec, "f");
101 Identifier identG = Identifier::fromString(exec, "g");
102
103 Structure* objectStructure =
104 JSFinalObject::createStructure(*vm, globalObject, globalObject->objectPrototype(), 2);
105
106 // Non-strict dynamic get by id:
107 JSValue object = JSFinalObject::create(*vm, objectStructure);
108 {
109 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
110 object.putInline(exec, identF, jsNumber(42), slot);
111 }
112 {
113 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
114 object.putInline(exec, identG, jsNumber(43), slot);
115 }
116 benchmarkImpl(
117 "Non Strict Dynamic Get By Id",
118 1000000,
119 [&] (unsigned iterationCount) {
120 for (unsigned i = iterationCount; i--;) {
121 JSValue result = object.get(exec, identF);
122 CHECK(result == jsNumber(42));
123 result = object.get(exec, identG);
124 CHECK(result == jsNumber(43));
125 }
126 });
127
128 // Non-strict dynamic put by id replace:
129 object = JSFinalObject::create(*vm, objectStructure);
130 {
131 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
132 object.putInline(exec, identF, jsNumber(42), slot);
133 }
134 {
135 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
136 object.putInline(exec, identG, jsNumber(43), slot);
137 }
138 benchmarkImpl(
139 "Non Strict Dynamic Put By Id Replace",
140 1000000,
141 [&] (unsigned iterationCount) {
142 for (unsigned i = iterationCount; i--;) {
143 {
144 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
145 object.putInline(exec, identF, jsNumber(i), slot);
146 }
147 {
148 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
149 object.putInline(exec, identG, jsNumber(i), slot);
150 }
151 }
152 });
153
154 // Non-strict dynamic put by id transition with object allocation:
155 benchmarkImpl(
156 "Non Strict Dynamic Allocation and Put By Id Transition",
157 1000000,
158 [&] (unsigned iterationCount) {
159 for (unsigned i = iterationCount; i--;) {
160 JSValue object = JSFinalObject::create(*vm, objectStructure);
161 {
162 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
163 object.putInline(exec, identF, jsNumber(i), slot);
164 }
165 {
166 PutPropertySlot slot(object, false, PutPropertySlot::PutById);
167 object.putInline(exec, identG, jsNumber(i), slot);
168 }
169 }
170 });
171
172 // Non-strict dynamic get by id with dynamic store context:
173 object = JSFinalObject::create(*vm, objectStructure);
174 {
175 PutPropertySlot slot(object, false);
176 object.putInline(exec, identF, jsNumber(42), slot);
177 }
178 {
179 PutPropertySlot slot(object, false);
180 object.putInline(exec, identG, jsNumber(43), slot);
181 }
182 benchmarkImpl(
183 "Non Strict Dynamic Get By Id With Dynamic Store Context",
184 1000000,
185 [&] (unsigned iterationCount) {
186 for (unsigned i = iterationCount; i--;) {
187 JSValue result = object.get(exec, identF);
188 CHECK(result == jsNumber(42));
189 result = object.get(exec, identG);
190 CHECK(result == jsNumber(43));
191 }
192 });
193
194 // Non-strict dynamic put by id replace with dynamic store context:
195 object = JSFinalObject::create(*vm, objectStructure);
196 {
197 PutPropertySlot slot(object, false);
198 object.putInline(exec, identF, jsNumber(42), slot);
199 }
200 {
201 PutPropertySlot slot(object, false);
202 object.putInline(exec, identG, jsNumber(43), slot);
203 }
204 benchmarkImpl(
205 "Non Strict Dynamic Put By Id Replace With Dynamic Store Context",
206 1000000,
207 [&] (unsigned iterationCount) {
208 for (unsigned i = iterationCount; i--;) {
209 {
210 PutPropertySlot slot(object, false);
211 object.putInline(exec, identF, jsNumber(i), slot);
212 }
213 {
214 PutPropertySlot slot(object, false);
215 object.putInline(exec, identG, jsNumber(i), slot);
216 }
217 }
218 });
219
220 // Non-strict dynamic put by id transition with object allocation with dynamic store context:
221 benchmarkImpl(
222 "Non Strict Dynamic Allocation and Put By Id Transition With Dynamic Store Context",
223 1000000,
224 [&] (unsigned iterationCount) {
225 for (unsigned i = iterationCount; i--;) {
226 JSValue object = JSFinalObject::create(*vm, objectStructure);
227 {
228 PutPropertySlot slot(object, false);
229 object.putInline(exec, identF, jsNumber(i), slot);
230 }
231 {
232 PutPropertySlot slot(object, false);
233 object.putInline(exec, identG, jsNumber(i), slot);
234 }
235 }
236 });
237 }
238
239 crashLock.lock();
240 return 0;
241}
242
Note: See TracBrowser for help on using the repository browser.