Diff
Modified: trunk/Source/_javascript_Core/API/JSProfilerPrivate.cpp (175202 => 175203)
--- trunk/Source/_javascript_Core/API/JSProfilerPrivate.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/API/JSProfilerPrivate.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -34,7 +34,11 @@
void JSStartProfiling(JSContextRef ctx, JSStringRef title)
{
- LegacyProfiler::profiler()->startProfiling(toJS(ctx), title->string());
+ // Use an independent stopwatch for API-initiated profiling, since the user will expect it
+ // to be relative to when their command was issued.
+ RefPtr<Stopwatch> stopwatch = Stopwatch::create();
+ stopwatch->start();
+ LegacyProfiler::profiler()->startProfiling(toJS(ctx), title->string(), stopwatch.release());
}
void JSEndProfiling(JSContextRef ctx, JSStringRef title)
Modified: trunk/Source/_javascript_Core/ChangeLog (175202 => 175203)
--- trunk/Source/_javascript_Core/ChangeLog 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/ChangeLog 2014-10-25 22:05:57 UTC (rev 175203)
@@ -1,3 +1,52 @@
+2014-10-18 Brian J. Burg <[email protected]>
+
+ Web Inspector: timelines should not count time elapsed while paused in the debugger
+ https://bugs.webkit.org/show_bug.cgi?id=136351
+
+ Reviewed by Timothy Hatcher.
+
+ Now that we have a stopwatch to provide pause-aware timing data, we can remove the
+ profiler's handling of debugger pause/continue callbacks. The debugger agent accounts
+ for suspended execution by pausing and resuming the stopwatch.
+
+ * API/JSProfilerPrivate.cpp:
+ (JSStartProfiling): Use a fresh stopwatch when profiling from the JSC API.
+ * inspector/InspectorEnvironment.h:
+ * inspector/JSGlobalObjectInspectorController.cpp:
+ (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
+ (Inspector::JSGlobalObjectInspectorController::executionStopwatch):
+ * inspector/JSGlobalObjectInspectorController.h:
+ * inspector/ScriptDebugServer.cpp:
+ (Inspector::ScriptDebugServer::handlePause):
+ * inspector/agents/InspectorDebuggerAgent.cpp:
+ (Inspector::InspectorDebuggerAgent::didPause):
+ (Inspector::InspectorDebuggerAgent::breakpointActionProbe):
+ (Inspector::InspectorDebuggerAgent::didContinue):
+ * inspector/agents/InspectorDebuggerAgent.h:
+ * profiler/LegacyProfiler.cpp:
+ (JSC::LegacyProfiler::profiler): Use nullptr.
+ (JSC::LegacyProfiler::startProfiling): Hand off a stopwatch to the profile generator.
+ (JSC::LegacyProfiler::stopProfiling): Use nullptr.
+ (JSC::LegacyProfiler::didPause): Deleted.
+ (JSC::LegacyProfiler::didContinue): Deleted.
+ * profiler/LegacyProfiler.h:
+ * profiler/Profile.cpp: The root node should always have a start time of 0.0.
+ (JSC::Profile::Profile):
+ * profiler/ProfileGenerator.cpp: Remove debugger pause/continue callbacks and the
+ timestamp member that was used to track time elapsed by the debugger. Just use the
+ stopwatch's elapsed times to generate start/elapsed times for function calls.
+
+ (JSC::ProfileGenerator::create):
+ (JSC::ProfileGenerator::ProfileGenerator):
+ (JSC::AddParentForConsoleStartFunctor::operator()): The parent node of |console.profile|
+ should have a start time of 0.0, since it represents the starting node of profiling.
+
+ (JSC::ProfileGenerator::beginCallEntry):
+ (JSC::ProfileGenerator::endCallEntry):
+ (JSC::ProfileGenerator::didPause): Deleted.
+ (JSC::ProfileGenerator::didContinue): Deleted.
+ * profiler/ProfileGenerator.h:
+
2014-10-24 Mark Lam <[email protected]>
Simplified IndexingType's hasAnyArrayStorage().
Modified: trunk/Source/_javascript_Core/inspector/InspectorEnvironment.h (175202 => 175203)
--- trunk/Source/_javascript_Core/inspector/InspectorEnvironment.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/inspector/InspectorEnvironment.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -28,6 +28,10 @@
#include "CallData.h"
+namespace WTF {
+class Stopwatch;
+}
+
namespace JSC {
class SourceCode;
}
@@ -47,6 +51,7 @@
virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String& scriptName, int scriptLine) = 0;
virtual void didCallInjectedScriptFunction(JSC::ExecState*) = 0;
virtual void frontendInitialized() = 0;
+ virtual PassRefPtr<WTF::Stopwatch> executionStopwatch() = 0;
};
} // namespace Inspector
Modified: trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.cpp (175202 => 175203)
--- trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -43,6 +43,8 @@
#include "ScriptArguments.h"
#include "ScriptCallStack.h"
#include "ScriptCallStackFactory.h"
+#include <wtf/Stopwatch.h>
+
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
@@ -59,6 +61,7 @@
: m_globalObject(globalObject)
, m_injectedScriptManager(std::make_unique<InjectedScriptManager>(*this, InjectedScriptHost::create()))
, m_inspectorFrontendChannel(nullptr)
+ , m_executionStopwatch(Stopwatch::create())
, m_includeNativeCallStackWithExceptions(true)
, m_isAutomaticInspection(false)
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
@@ -79,6 +82,8 @@
m_agents.append(WTF::move(runtimeAgent));
m_agents.append(WTF::move(consoleAgent));
m_agents.append(WTF::move(debuggerAgent));
+
+ m_executionStopwatch->start();
}
JSGlobalObjectInspectorController::~JSGlobalObjectInspectorController()
@@ -213,6 +218,11 @@
#endif
}
+PassRefPtr<Stopwatch> JSGlobalObjectInspectorController::executionStopwatch()
+{
+ return m_executionStopwatch;
+}
+
} // namespace Inspector
#endif // ENABLE(INSPECTOR)
Modified: trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.h (175202 => 175203)
--- trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/inspector/JSGlobalObjectInspectorController.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -38,6 +38,11 @@
#include "AugmentableInspectorController.h"
#endif
+namespace WTF {
+class Stopwatch;
+}
+
+
namespace JSC {
class ConsoleClient;
class ExecState;
@@ -89,6 +94,7 @@
virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String&, int) override { }
virtual void didCallInjectedScriptFunction(JSC::ExecState*) override { }
virtual void frontendInitialized() override;
+ virtual PassRefPtr<WTF::Stopwatch> executionStopwatch() override;
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
virtual AugmentableInspectorControllerClient* augmentableInspectorControllerClient() const override { return m_augmentingClient; }
@@ -109,6 +115,7 @@
InspectorAgentRegistry m_agents;
InspectorFrontendChannel* m_inspectorFrontendChannel;
RefPtr<InspectorBackendDispatcher> m_inspectorBackendDispatcher;
+ RefPtr<WTF::Stopwatch> m_executionStopwatch;
bool m_includeNativeCallStackWithExceptions;
bool m_isAutomaticInspection;
Modified: trunk/Source/_javascript_Core/inspector/ScriptDebugServer.cpp (175202 => 175203)
--- trunk/Source/_javascript_Core/inspector/ScriptDebugServer.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/inspector/ScriptDebugServer.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -38,7 +38,6 @@
#include "JSJavaScriptCallFrame.h"
#include "JSLock.h"
#include "_javascript_CallFrame.h"
-#include "LegacyProfiler.h"
#include "ScriptValue.h"
#include "SourceProvider.h"
#include <wtf/NeverDestroyed.h>
@@ -307,14 +306,12 @@
void ScriptDebugServer::handlePause(Debugger::ReasonForPause, JSGlobalObject* vmEntryGlobalObject)
{
dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidPause);
- LegacyProfiler::profiler()->didPause(currentDebuggerCallFrame());
didPause(vmEntryGlobalObject);
m_doneProcessingDebuggerEvents = false;
runEventLoopWhilePaused();
didContinue(vmEntryGlobalObject);
- LegacyProfiler::profiler()->didContinue(currentDebuggerCallFrame());
dispatchFunctionToListeners(&ScriptDebugServer::dispatchDidContinue);
}
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp (175202 => 175203)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -40,6 +40,7 @@
#include "ScriptDebugServer.h"
#include "ScriptObject.h"
#include "ScriptValue.h"
+#include <wtf/Stopwatch.h>
#include <wtf/text/WTFString.h>
namespace Inspector {
@@ -652,6 +653,8 @@
if (m_listener)
m_listener->didPause();
+
+ m_injectedScriptManager->inspectorEnvironment().executionStopwatch()->stop();
}
void InspectorDebuggerAgent::breakpointActionSound(int breakpointActionIdentifier)
@@ -669,7 +672,7 @@
.setProbeId(action.identifier)
.setSampleId(sampleId)
.setBatchId(hitCount)
- .setTimestamp(monotonicallyIncreasingTime())
+ .setTimestamp(m_injectedScriptManager->inspectorEnvironment().executionStopwatch()->elapsedTime())
.setPayload(payload.release());
m_frontendDispatcher->didSampleProbe(result.release());
@@ -679,6 +682,7 @@
{
m_pausedScriptState = nullptr;
m_currentCallStack = Deprecated::ScriptValue();
+ m_injectedScriptManager->inspectorEnvironment().executionStopwatch()->start();
clearBreakDetails();
m_frontendDispatcher->resumed();
@@ -745,7 +749,6 @@
m_breakAuxData = nullptr;
}
-
} // namespace Inspector
#endif // ENABLE(INSPECTOR)
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h (175202 => 175203)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorDebuggerAgent.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -47,6 +47,10 @@
#include <wtf/Vector.h>
#include <wtf/text/StringHash.h>
+namespace WTF {
+class Stopwatch;
+}
+
namespace Inspector {
class InjectedScript;
@@ -163,6 +167,7 @@
RefPtr<InspectorObject> m_breakAuxData;
bool m_enabled;
bool m_javaScriptPauseScheduled;
+ RefPtr<WTF::Stopwatch> m_stopwatch;
int m_nextProbeSampleId;
};
Modified: trunk/Source/_javascript_Core/profiler/LegacyProfiler.cpp (175202 => 175203)
--- trunk/Source/_javascript_Core/profiler/LegacyProfiler.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/profiler/LegacyProfiler.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -32,7 +32,6 @@
#include "CallFrame.h"
#include "CodeBlock.h"
#include "CommonIdentifiers.h"
-#include "DebuggerCallFrame.h"
#include "InternalFunction.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
@@ -50,16 +49,16 @@
static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber);
-LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = 0;
+LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = nullptr;
LegacyProfiler* LegacyProfiler::profiler()
{
if (!s_sharedLegacyProfiler)
s_sharedLegacyProfiler = new LegacyProfiler();
return s_sharedLegacyProfiler;
-}
+}
-void LegacyProfiler::startProfiling(ExecState* exec, const String& title)
+void LegacyProfiler::startProfiling(ExecState* exec, const String& title, PassRefPtr<Stopwatch> stopwatch)
{
if (!exec)
return;
@@ -75,14 +74,14 @@
}
exec->vm().setEnabledProfiler(this);
- RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID);
+ RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID, stopwatch);
m_currentProfiles.append(profileGenerator);
}
PassRefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title)
{
if (!exec)
- return 0;
+ return nullptr;
JSGlobalObject* origin = exec->lexicalGlobalObject();
for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
@@ -94,12 +93,12 @@
m_currentProfiles.remove(i);
if (!m_currentProfiles.size())
exec->vm().setEnabledProfiler(nullptr);
-
+
return returnProfile;
}
}
- return 0;
+ return nullptr;
}
void LegacyProfiler::stopProfiling(JSGlobalObject* origin)
@@ -184,28 +183,6 @@
callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::exceptionUnwind, std::placeholders::_1, handlerCallFrame, callIdentifier), m_currentProfiles, handlerCallFrame->lexicalGlobalObject()->profileGroup());
}
-void LegacyProfiler::didPause(PassRefPtr<DebuggerCallFrame> prpCallFrame)
-{
- if (m_currentProfiles.isEmpty())
- return;
-
- RefPtr<DebuggerCallFrame> callFrame = prpCallFrame;
- CallIdentifier callIdentifier = createCallIdentifier(callFrame->exec(), JSValue(), StringImpl::empty(), 0, 0);
-
- callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didPause, std::placeholders::_1, callFrame, callIdentifier), m_currentProfiles, callFrame->vmEntryGlobalObject()->profileGroup());
-}
-
-void LegacyProfiler::didContinue(PassRefPtr<DebuggerCallFrame> prpCallFrame)
-{
- if (m_currentProfiles.isEmpty())
- return;
-
- RefPtr<DebuggerCallFrame> callFrame = prpCallFrame;
- CallIdentifier callIdentifier = createCallIdentifier(callFrame->exec(), JSValue(), StringImpl::empty(), 0, 0);
-
- callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didContinue, std::placeholders::_1, callFrame, callIdentifier), m_currentProfiles, callFrame->vmEntryGlobalObject()->profileGroup());
-}
-
CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber)
{
if (!functionValue)
Modified: trunk/Source/_javascript_Core/profiler/LegacyProfiler.h (175202 => 175203)
--- trunk/Source/_javascript_Core/profiler/LegacyProfiler.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/profiler/LegacyProfiler.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -32,13 +32,12 @@
#include "Profile.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
+#include <wtf/Stopwatch.h>
#include <wtf/Vector.h>
namespace JSC {
-class DebuggerCallFrame;
class ExecState;
-class VM;
class JSGlobalObject;
class JSObject;
class JSValue;
@@ -48,10 +47,10 @@
class LegacyProfiler {
WTF_MAKE_FAST_ALLOCATED;
public:
- JS_EXPORT_PRIVATE static LegacyProfiler* profiler();
+ JS_EXPORT_PRIVATE static LegacyProfiler* profiler();
static CallIdentifier createCallIdentifier(ExecState*, JSValue, const WTF::String& sourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber);
- JS_EXPORT_PRIVATE void startProfiling(ExecState*, const WTF::String& title);
+ JS_EXPORT_PRIVATE void startProfiling(ExecState*, const WTF::String& title, PassRefPtr<Stopwatch>);
JS_EXPORT_PRIVATE PassRefPtr<Profile> stopProfiling(ExecState*, const WTF::String& title);
void stopProfiling(JSGlobalObject*);
@@ -66,9 +65,6 @@
void exceptionUnwind(ExecState* handlerCallFrame);
- void didPause(PassRefPtr<DebuggerCallFrame>);
- void didContinue(PassRefPtr<DebuggerCallFrame>);
-
const Vector<RefPtr<ProfileGenerator>>& currentProfiles() { return m_currentProfiles; };
private:
Modified: trunk/Source/_javascript_Core/profiler/Profile.cpp (175202 => 175203)
--- trunk/Source/_javascript_Core/profiler/Profile.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/profiler/Profile.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -44,7 +44,7 @@
// FIXME: When multi-threading is supported this will be a vector and calls
// into the profiler will need to know which thread it is executing on.
m_rootNode = ProfileNode::create(nullptr, CallIdentifier(ASCIILiteral("Thread_1"), String(), 0, 0), nullptr);
- m_rootNode->appendCall(ProfileNode::Call(currentTime()));
+ m_rootNode->appendCall(ProfileNode::Call(0.0));
}
Profile::~Profile()
Modified: trunk/Source/_javascript_Core/profiler/ProfileGenerator.cpp (175202 => 175203)
--- trunk/Source/_javascript_Core/profiler/ProfileGenerator.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/profiler/ProfileGenerator.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -28,7 +28,6 @@
#include "CallFrame.h"
#include "CodeBlock.h"
-#include "Debugger.h"
#include "JSGlobalObject.h"
#include "JSStringRef.h"
#include "JSFunction.h"
@@ -40,21 +39,18 @@
namespace JSC {
-PassRefPtr<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const String& title, unsigned uid)
+PassRefPtr<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const String& title, unsigned uid, PassRefPtr<Stopwatch> stopwatch)
{
- return adoptRef(new ProfileGenerator(exec, title, uid));
+ return adoptRef(new ProfileGenerator(exec, title, uid, stopwatch));
}
-ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid)
+ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid, PassRefPtr<Stopwatch> stopwatch)
: m_origin(exec ? exec->lexicalGlobalObject() : nullptr)
, m_profileGroup(exec ? exec->lexicalGlobalObject()->profileGroup() : 0)
- , m_debuggerPausedTimestamp(NAN)
+ , m_stopwatch(stopwatch)
, m_foundConsoleStartParent(false)
, m_suspended(false)
{
- if (Debugger* debugger = exec->lexicalGlobalObject()->debugger())
- m_debuggerPausedTimestamp = debugger->isPaused() ? currentTime() : NAN;
-
m_profile = Profile::create(title, uid);
m_currentNode = m_rootNode = m_profile->rootNode();
if (exec)
@@ -85,7 +81,9 @@
unsigned column = 0;
visitor->computeLineAndColumn(line, column);
m_currentNode = ProfileNode::create(m_exec, LegacyProfiler::createCallIdentifier(m_exec, visitor->callee(), visitor->sourceURL(), line, column), m_rootNode.get());
- m_currentNode->appendCall(ProfileNode::Call(currentTime()));
+ // Assume that profile times are relative to when the |console.profile| command is evaluated.
+ // This matches the logic in JSStartProfiling() and InspectorTimelineAgent::startFromConsole().
+ m_currentNode->appendCall(ProfileNode::Call(0.0));
m_rootNode->spliceNode(m_currentNode.get());
m_foundParent = true;
@@ -118,13 +116,8 @@
ASSERT_ARG(node, node);
if (std::isnan(startTime))
- startTime = currentTime();
+ startTime = m_stopwatch->elapsedTime();
- // If the debugger is paused when beginning, then don't set the start time. It
- // will be fixed up when the debugger unpauses or the call entry ends.
- if (!std::isnan(m_debuggerPausedTimestamp))
- startTime = NAN;
-
node->appendCall(ProfileNode::Call(startTime));
}
@@ -134,21 +127,8 @@
ProfileNode::Call& last = node->lastCall();
- // If the debugger is paused, ignore the interval that ends now.
- if (!std::isnan(m_debuggerPausedTimestamp) && !std::isnan(last.elapsedTime()))
- return;
-
- // If paused and no time was accrued then the debugger was never unpaused. The call will
- // have no time accrued and appear to have started when the debugger was paused.
- if (!std::isnan(m_debuggerPausedTimestamp)) {
- last.setStartTime(m_debuggerPausedTimestamp);
- last.setElapsedTime(0.0);
- return;
- }
-
- // Otherwise, add the interval ending now to elapsed time.
double previousElapsedTime = std::isnan(last.elapsedTime()) ? 0.0 : last.elapsedTime();
- double newlyElapsedTime = currentTime() - last.startTime();
+ double newlyElapsedTime = m_stopwatch->elapsedTime() - last.startTime();
last.setElapsedTime(previousElapsedTime + newlyElapsedTime);
}
@@ -180,7 +160,7 @@
}
m_currentNode = calleeNode;
- beginCallEntry(calleeNode.get());
+ beginCallEntry(calleeNode.get(), m_stopwatch->elapsedTime());
}
void ProfileGenerator::didExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
@@ -223,33 +203,6 @@
}
}
-void ProfileGenerator::didPause(PassRefPtr<DebuggerCallFrame>, const CallIdentifier&)
-{
- ASSERT(std::isnan(m_debuggerPausedTimestamp));
-
- m_debuggerPausedTimestamp = currentTime();
-
- for (ProfileNode* node = m_currentNode.get(); node != m_profile->rootNode(); node = node->parent()) {
- ProfileNode::Call& last = node->lastCall();
- ASSERT(!std::isnan(last.startTime()));
-
- double previousElapsedTime = std::isnan(last.elapsedTime()) ? 0.0 : last.elapsedTime();
- double additionalElapsedTime = m_debuggerPausedTimestamp - last.startTime();
- last.setStartTime(NAN);
- last.setElapsedTime(previousElapsedTime + additionalElapsedTime);
- }
-}
-
-void ProfileGenerator::didContinue(PassRefPtr<DebuggerCallFrame>, const CallIdentifier&)
-{
- ASSERT(!std::isnan(m_debuggerPausedTimestamp));
-
- for (ProfileNode* node = m_currentNode.get(); node != m_profile->rootNode(); node = node->parent())
- node->lastCall().setStartTime(m_debuggerPausedTimestamp);
-
- m_debuggerPausedTimestamp = NAN;
-}
-
void ProfileGenerator::stopProfiling()
{
for (ProfileNode* node = m_currentNode.get(); node != m_profile->rootNode(); node = node->parent())
Modified: trunk/Source/_javascript_Core/profiler/ProfileGenerator.h (175202 => 175203)
--- trunk/Source/_javascript_Core/profiler/ProfileGenerator.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/_javascript_Core/profiler/ProfileGenerator.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -29,6 +29,7 @@
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include <wtf/Stopwatch.h>
#include <wtf/text/WTFString.h>
namespace JSC {
@@ -42,7 +43,7 @@
class ProfileGenerator : public RefCounted<ProfileGenerator> {
public:
- static PassRefPtr<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid);
+ static PassRefPtr<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid, PassRefPtr<Stopwatch>);
// Members
const WTF::String& title() const;
@@ -54,28 +55,24 @@
void didExecute(ExecState* callerCallFrame, const CallIdentifier&);
void exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&);
- void didPause(PassRefPtr<DebuggerCallFrame>, const CallIdentifier&);
- void didContinue(PassRefPtr<DebuggerCallFrame>, const CallIdentifier&);
-
void setIsSuspended(bool suspended) { ASSERT(m_suspended != suspended); m_suspended = suspended; }
void stopProfiling();
private:
- ProfileGenerator(ExecState*, const WTF::String& title, unsigned uid);
+ ProfileGenerator(ExecState*, const WTF::String& title, unsigned uid, PassRefPtr<Stopwatch>);
void addParentForConsoleStart(ExecState*);
void removeProfileStart();
void removeProfileEnd();
- void beginCallEntry(ProfileNode*, double startTime = NAN);
+ void beginCallEntry(ProfileNode*, double startTime);
void endCallEntry(ProfileNode*);
RefPtr<Profile> m_profile;
JSGlobalObject* m_origin;
unsigned m_profileGroup;
- // Timestamp is set to NAN when the debugger is not currently paused.
- double m_debuggerPausedTimestamp;
+ RefPtr<Stopwatch> m_stopwatch;
RefPtr<ProfileNode> m_rootNode;
RefPtr<ProfileNode> m_currentNode;
bool m_foundConsoleStartParent;
Modified: trunk/Source/WTF/ChangeLog (175202 => 175203)
--- trunk/Source/WTF/ChangeLog 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WTF/ChangeLog 2014-10-25 22:05:57 UTC (rev 175203)
@@ -1,3 +1,22 @@
+2014-10-18 Brian J. Burg <[email protected]>
+
+ Web Inspector: timelines should not count time elapsed while paused in the debugger
+ https://bugs.webkit.org/show_bug.cgi?id=136351
+
+ Reviewed by Timothy Hatcher.
+
+ * WTF.vcxproj/WTF.vcxproj:
+ * WTF.vcxproj/WTF.vcxproj.filters:
+ * WTF.xcodeproj/project.pbxproj:
+ * wtf/CMakeLists.txt:
+ * wtf/Stopwatch.h: Added. This implements a refcounted monotonic stopwatch.
+ (WTF::Stopwatch::create):
+ (WTF::Stopwatch::Stopwatch):
+ (WTF::Stopwatch::reset):
+ (WTF::Stopwatch::start):
+ (WTF::Stopwatch::stop):
+ (WTF::Stopwatch::elapsedTime):
+
2014-10-23 Joseph Pecoraro <[email protected]>
Web Inspector: Provide a way to have alternate inspector agents
Modified: trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj (175202 => 175203)
--- trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj 2014-10-25 22:05:57 UTC (rev 175203)
@@ -270,6 +270,7 @@
<ClInclude Include="..\wtf\StackBounds.h" />
<ClInclude Include="..\wtf\StaticConstructors.h" />
<ClInclude Include="..\wtf\StdLibExtras.h" />
+ <ClInclude Include="..\wtf\Stopwatch.h" />
<ClInclude Include="..\wtf\StringExtras.h" />
<ClInclude Include="..\wtf\StringHasher.h" />
<ClInclude Include="..\wtf\StringPrintStream.h" />
Modified: trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj.filters (175202 => 175203)
--- trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj.filters 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj.filters 2014-10-25 22:05:57 UTC (rev 175203)
@@ -614,6 +614,9 @@
<ClInclude Include="..\wtf\StdLibExtras.h">
<Filter>wtf</Filter>
</ClInclude>
+ <ClInclude Include="..\wtf\Stopwatch.h">
+ <Filter>wtf</Filter>
+ </ClInclude>
<ClInclude Include="..\wtf\StringExtras.h">
<Filter>wtf</Filter>
</ClInclude>
Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (175202 => 175203)
--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj 2014-10-25 22:05:57 UTC (rev 175203)
@@ -273,6 +273,7 @@
A8A47487151A825B004123FF /* WTFThreadData.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4737B151A825B004123FF /* WTFThreadData.h */; };
A8A4748C151A8264004123FF /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = A8A4748B151A8264004123FF /* config.h */; };
B38FD7BD168953E80065C969 /* FeatureDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = B38FD7BC168953E80065C969 /* FeatureDefines.h */; };
+ C4F8A93719C65EB400B2B15D /* Stopwatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C4F8A93619C65EB400B2B15D /* Stopwatch.h */; };
CD5497AC15857D0300B5BC30 /* MediaTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD5497AA15857D0300B5BC30 /* MediaTime.cpp */; };
CD5497AD15857D0300B5BC30 /* MediaTime.h in Headers */ = {isa = PBXBuildFile; fileRef = CD5497AB15857D0300B5BC30 /* MediaTime.h */; };
CE46516E19DB1FB4003ECA05 /* NSMapTableSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = CE46516D19DB1FB4003ECA05 /* NSMapTableSPI.h */; };
@@ -566,6 +567,7 @@
A8A4737B151A825B004123FF /* WTFThreadData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFThreadData.h; sourceTree = "<group>"; };
A8A4748B151A8264004123FF /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
B38FD7BC168953E80065C969 /* FeatureDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FeatureDefines.h; sourceTree = "<group>"; };
+ C4F8A93619C65EB400B2B15D /* Stopwatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stopwatch.h; sourceTree = "<group>"; };
CD5497AA15857D0300B5BC30 /* MediaTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaTime.cpp; sourceTree = "<group>"; };
CD5497AB15857D0300B5BC30 /* MediaTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaTime.h; sourceTree = "<group>"; };
CE46516D19DB1FB4003ECA05 /* NSMapTableSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSMapTableSPI.h; sourceTree = "<group>"; };
@@ -858,6 +860,7 @@
FEDACD3C1630F83F00C69634 /* StackStats.h */,
A8A47310151A825B004123FF /* StaticConstructors.h */,
A8A47311151A825B004123FF /* StdLibExtras.h */,
+ C4F8A93619C65EB400B2B15D /* Stopwatch.h */,
1A6BB768162F300500DD16DB /* StreamBuffer.h */,
A8A47313151A825B004123FF /* StringExtras.h */,
A748745117A0BDAE00FA04CB /* StringHashDumpContext.h */,
@@ -1078,6 +1081,7 @@
A8A473A3151A825B004123FF /* DecimalNumber.h in Headers */,
0F2B66A617B6B4FB00A7AE3F /* DeferrableRefCounted.h in Headers */,
A8A473A5151A825B004123FF /* Deque.h in Headers */,
+ C4F8A93719C65EB400B2B15D /* Stopwatch.h in Headers */,
A8A473A6151A825B004123FF /* DisallowCType.h in Headers */,
A8A473AF151A825B004123FF /* diy-fp.h in Headers */,
A8A473B1151A825B004123FF /* double-conversion.h in Headers */,
Modified: trunk/Source/WTF/wtf/CMakeLists.txt (175202 => 175203)
--- trunk/Source/WTF/wtf/CMakeLists.txt 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WTF/wtf/CMakeLists.txt 2014-10-25 22:05:57 UTC (rev 175203)
@@ -92,6 +92,7 @@
StackStats.h
StaticConstructors.h
StdLibExtras.h
+ Stopwatch.h
StringExtras.h
StringHasher.h
StringPrintStream.h
Added: trunk/Source/WTF/wtf/Stopwatch.h (0 => 175203)
--- trunk/Source/WTF/wtf/Stopwatch.h (rev 0)
+++ trunk/Source/WTF/wtf/Stopwatch.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 University of Washington. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Stopwatch_h
+#define Stopwatch_h
+
+#include <cmath>
+#include <wtf/CurrentTime.h>
+#include <wtf/RefCounted.h>
+
+namespace WTF {
+
+class Stopwatch : public RefCounted<Stopwatch> {
+public:
+ static PassRefPtr<Stopwatch> create()
+ {
+ return adoptRef(new Stopwatch());
+ }
+
+ void reset();
+ void start();
+ void stop();
+
+ double elapsedTime();
+
+private:
+ Stopwatch()
+ : m_elapsedTime(0.0)
+ , m_lastStartTime(NAN)
+ {
+ }
+
+ double m_elapsedTime;
+ double m_lastStartTime;
+};
+
+inline void Stopwatch::reset()
+{
+ m_elapsedTime = 0.0;
+ m_lastStartTime = NAN;
+}
+
+inline void Stopwatch::start()
+{
+ ASSERT(isnan(m_lastStartTime));
+
+ m_lastStartTime = monotonicallyIncreasingTime();
+}
+
+inline void Stopwatch::stop()
+{
+ ASSERT(!isnan(m_lastStartTime));
+
+ m_elapsedTime += monotonicallyIncreasingTime() - m_lastStartTime;
+ m_lastStartTime = NAN;
+}
+
+inline double Stopwatch::elapsedTime()
+{
+ bool shouldSuspend = !isnan(m_lastStartTime);
+ if (shouldSuspend)
+ stop();
+
+ double elapsedTime = m_elapsedTime;
+
+ if (shouldSuspend)
+ start();
+ return elapsedTime;
+}
+
+} // namespace WTF
+
+using WTF::Stopwatch;
+
+#endif // Stopwatch_h
Modified: trunk/Source/WebCore/ChangeLog (175202 => 175203)
--- trunk/Source/WebCore/ChangeLog 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/ChangeLog 2014-10-25 22:05:57 UTC (rev 175203)
@@ -1,3 +1,67 @@
+2014-10-18 Brian J. Burg <[email protected]>
+
+ Web Inspector: timelines should not count time elapsed while paused in the debugger
+ https://bugs.webkit.org/show_bug.cgi?id=136351
+
+ Reviewed by Timothy Hatcher.
+
+ To avoid counting time elapsed while the debugger is paused, timeline records should
+ keep track of time elapsed since the start of timeline capturing, rather than wall clock
+ timestamps. We can easily compute elapsed time by sharing a Stopwatch instance through the
+ inspector environment. The stopwatch runs with timelines and is paused with the debugger,
+ so subsequent time measurements will not include time elapsed while the debugger is paused.
+
+ This refactoring is safe because start and end times are only used to graph records; the
+ timestamp's actual value is irrelevant and is not displayed in the user interface. Date
+ timestamps are still included with network-related records as part of their header data.
+
+ No new tests, because we cannot reliably test timing changes induced by debugger pauses.
+ It is possible for records to accrue time before the debugger pauses or after it resumes.
+
+ * inspector/InspectorCSSAgent.cpp: Remove unnecessary include.
+ * inspector/InspectorController.cpp:
+ (WebCore::InspectorController::InspectorController):
+ (WebCore::InspectorController::executionStopwatch): Add a shared stopwatch.
+ * inspector/InspectorController.h:
+ * inspector/InspectorPageAgent.cpp:
+ (WebCore::InspectorPageAgent::timestamp): Redirect to the shared stopwatch.
+ (WebCore::InspectorPageAgent::domContentEventFired):
+ (WebCore::InspectorPageAgent::loadEventFired):
+ * inspector/InspectorPageAgent.h:
+ * inspector/InspectorResourceAgent.cpp:
+ (WebCore::InspectorResourceAgent::timestamp): Redirect to the shared stopwatch.
+ (WebCore::InspectorResourceAgent::willSendRequest):
+ (WebCore::InspectorResourceAgent::didReceiveResponse):
+ (WebCore::InspectorResourceAgent::didReceiveData):
+ (WebCore::InspectorResourceAgent::didFinishLoading):
+ (WebCore::InspectorResourceAgent::didFailLoading):
+ (WebCore::InspectorResourceAgent::didLoadResourceFromMemoryCache):
+ (WebCore::InspectorResourceAgent::willSendWebSocketHandshakeRequest):
+ (WebCore::InspectorResourceAgent::didReceiveWebSocketHandshakeResponse):
+ (WebCore::InspectorResourceAgent::didCloseWebSocket):
+ (WebCore::InspectorResourceAgent::didReceiveWebSocketFrame):
+ (WebCore::InspectorResourceAgent::didSendWebSocketFrame):
+ (WebCore::InspectorResourceAgent::didReceiveWebSocketFrameError):
+ * inspector/InspectorResourceAgent.h:
+ * inspector/InspectorTimelineAgent.cpp:
+ (WebCore::InspectorTimelineAgent::internalStart): Start and stop the stopwatch with timelines.
+ (WebCore::InspectorTimelineAgent::internalStop):
+ (WebCore::InspectorTimelineAgent::timestamp): Redirect to the shared stopwatch.
+ (WebCore::startProfiling):
+ (WebCore::InspectorTimelineAgent::startFromConsole):
+ (WebCore::InspectorTimelineAgent::willCallFunction):
+ (WebCore::InspectorTimelineAgent::willEvaluateScript):
+ (WebCore::TimelineTimeConverter::reset): Deleted.
+ * inspector/InspectorTimelineAgent.h:
+ (WebCore::TimelineTimeConverter::TimelineTimeConverter): Deleted.
+ (WebCore::TimelineTimeConverter::fromMonotonicallyIncreasingTime): Deleted.
+ (WebCore::InspectorTimelineAgent::timeConverter): Deleted.
+ * inspector/TimelineRecordFactory.cpp:
+ * inspector/WorkerInspectorController.cpp:
+ (WebCore::WorkerInspectorController::WorkerInspectorController):
+ (WebCore::WorkerInspectorController::executionStopwatch): Add a shared stopwatch.
+ * inspector/WorkerInspectorController.h:
+
2014-10-25 Dan Bernstein <[email protected]>
Fix builds using the public SDK.
Modified: trunk/Source/WebCore/inspector/InspectorCSSAgent.cpp (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorCSSAgent.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorCSSAgent.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -56,7 +56,6 @@
#include "StyleSheetList.h"
#include "WebKitNamedFlow.h"
#include <inspector/InspectorProtocolObjects.h>
-#include <wtf/CurrentTime.h>
#include <wtf/HashSet.h>
#include <wtf/Ref.h>
#include <wtf/Vector.h>
Modified: trunk/Source/WebCore/inspector/InspectorController.cpp (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorController.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorController.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -73,6 +73,7 @@
#include <inspector/agents/InspectorAgent.h>
#include <profiler/LegacyProfiler.h>
#include <runtime/JSLock.h>
+#include <wtf/Stopwatch.h>
#if ENABLE(REMOTE_INSPECTOR)
#include "PageDebuggable.h"
@@ -88,6 +89,7 @@
, m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
, m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
, m_inspectorFrontendChannel(nullptr)
+ , m_executionStopwatch(Stopwatch::create())
, m_page(page)
, m_inspectorClient(inspectorClient)
, m_inspectorFrontendClient(nullptr)
@@ -452,6 +454,11 @@
#endif
}
+PassRefPtr<Stopwatch> InspectorController::executionStopwatch()
+{
+ return m_executionStopwatch;
+}
+
} // namespace WebCore
#endif // ENABLE(INSPECTOR)
Modified: trunk/Source/WebCore/inspector/InspectorController.h (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorController.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorController.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -130,6 +130,7 @@
virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String& scriptName, int scriptLine) override;
virtual void didCallInjectedScriptFunction(JSC::ExecState*) override;
virtual void frontendInitialized() override;
+ virtual PassRefPtr<WTF::Stopwatch> executionStopwatch() override;
private:
friend InstrumentingAgents* instrumentationForPage(Page*);
@@ -148,6 +149,7 @@
RefPtr<Inspector::InspectorBackendDispatcher> m_inspectorBackendDispatcher;
Inspector::InspectorFrontendChannel* m_inspectorFrontendChannel;
+ RefPtr<WTF::Stopwatch> m_executionStopwatch;
Page& m_page;
InspectorClient* m_inspectorClient;
InspectorFrontendClient* m_inspectorFrontendClient;
Modified: trunk/Source/WebCore/inspector/InspectorPageAgent.cpp (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorPageAgent.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorPageAgent.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -57,6 +57,7 @@
#include "InspectorDOMAgent.h"
#include "InspectorInstrumentation.h"
#include "InspectorOverlay.h"
+#include "InspectorTimelineAgent.h"
#include "InstrumentingAgents.h"
#include "MainFrame.h"
#include "MemoryCache.h"
@@ -72,7 +73,6 @@
#include <inspector/ContentSearchUtilities.h>
#include <inspector/IdentifiersFactory.h>
#include <inspector/InspectorValues.h>
-#include <wtf/CurrentTime.h>
#include <wtf/ListHashSet.h>
#include <wtf/text/Base64.h>
#include <wtf/text/StringBuilder.h>
@@ -359,6 +359,11 @@
#endif
}
+double InspectorPageAgent::timestamp()
+{
+ return m_instrumentingAgents->inspectorEnvironment().executionStopwatch()->elapsedTime();
+}
+
void InspectorPageAgent::enable(ErrorString&)
{
m_enabled = true;
@@ -709,12 +714,12 @@
void InspectorPageAgent::domContentEventFired()
{
m_isFirstLayoutAfterOnLoad = true;
- m_frontendDispatcher->domContentEventFired(currentTime());
+ m_frontendDispatcher->domContentEventFired(timestamp());
}
void InspectorPageAgent::loadEventFired()
{
- m_frontendDispatcher->loadEventFired(currentTime());
+ m_frontendDispatcher->loadEventFired(timestamp());
}
void InspectorPageAgent::frameNavigated(DocumentLoader* loader)
Modified: trunk/Source/WebCore/inspector/InspectorPageAgent.h (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorPageAgent.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorPageAgent.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -161,6 +161,8 @@
void updateTouchEventEmulationInPage(bool);
#endif
+ double timestamp();
+
static bool mainResourceContent(Frame*, bool withBase64Encode, String* result);
static bool dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result);
Modified: trunk/Source/WebCore/inspector/InspectorResourceAgent.cpp (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorResourceAgent.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorResourceAgent.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -47,6 +47,7 @@
#include "IconController.h"
#include "InspectorClient.h"
#include "InspectorPageAgent.h"
+#include "InspectorTimelineAgent.h"
#include "InstrumentingAgents.h"
#include "JSMainThreadExecState.h"
#include "MemoryCache.h"
@@ -68,7 +69,6 @@
#include <inspector/InspectorValues.h>
#include <inspector/ScriptCallStack.h>
#include <inspector/ScriptCallStackFactory.h>
-#include <wtf/CurrentTime.h>
#include <wtf/RefPtr.h>
#include <wtf/text/StringBuilder.h>
@@ -275,6 +275,11 @@
ASSERT(!m_instrumentingAgents->inspectorResourceAgent());
}
+double InspectorResourceAgent::timestamp()
+{
+ return m_instrumentingAgents->inspectorEnvironment().executionStopwatch()->elapsedTime();
+}
+
void InspectorResourceAgent::willSendRequest(unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
if (request.hiddenFromInspector()) {
@@ -319,7 +324,7 @@
Inspector::Protocol::Page::ResourceType resourceType = InspectorPageAgent::resourceTypeJson(type);
RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : nullptr);
- m_frontendDispatcher->requestWillBeSent(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), loader->url().string(), buildObjectForResourceRequest(request), currentTime(), initiatorObject, buildObjectForResourceResponse(redirectResponse, loader), type != InspectorPageAgent::OtherResource ? &resourceType : nullptr);
+ m_frontendDispatcher->requestWillBeSent(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), loader->url().string(), buildObjectForResourceRequest(request), timestamp(), initiatorObject, buildObjectForResourceResponse(redirectResponse, loader), type != InspectorPageAgent::OtherResource ? &resourceType : nullptr);
}
void InspectorResourceAgent::markResourceAsCached(unsigned long identifier)
@@ -364,7 +369,7 @@
m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), response);
m_resourcesData->setResourceType(requestId, type);
- m_frontendDispatcher->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), currentTime(), InspectorPageAgent::resourceTypeJson(type), resourceResponse);
+ m_frontendDispatcher->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), timestamp(), InspectorPageAgent::resourceTypeJson(type), resourceResponse);
// If we revalidated the resource and got Not modified, send content length following didReceiveResponse
// as there will be no calls to didReceiveData from the network stack.
@@ -390,7 +395,7 @@
m_resourcesData->maybeAddResourceData(requestId, data, dataLength);
}
- m_frontendDispatcher->dataReceived(requestId, currentTime(), dataLength, encodedDataLength);
+ m_frontendDispatcher->dataReceived(requestId, timestamp(), dataLength, encodedDataLength);
}
void InspectorResourceAgent::didFinishLoading(unsigned long identifier, DocumentLoader* loader, double finishTime)
@@ -410,7 +415,7 @@
// However, all other times passed to the Inspector are generated from the web process. Mixing
// times from different processes can cause the finish time to be earlier than the response
// received time due to inter-process communication lag.
- finishTime = currentTime();
+ finishTime = timestamp();
String sourceMappingURL;
NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
@@ -436,7 +441,7 @@
}
bool canceled = error.isCancellation();
- m_frontendDispatcher->loadingFailed(requestId, currentTime(), error.localizedDescription(), canceled ? &canceled : nullptr);
+ m_frontendDispatcher->loadingFailed(requestId, timestamp(), error.localizedDescription(), canceled ? &canceled : nullptr);
}
void InspectorResourceAgent::didLoadResourceFromMemoryCache(DocumentLoader* loader, CachedResource* resource)
@@ -454,7 +459,7 @@
RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : nullptr);
- m_frontendDispatcher->requestServedFromMemoryCache(requestId, frameId, loaderId, loader->url().string(), currentTime(), initiatorObject, buildObjectForCachedResource(resource, loader));
+ m_frontendDispatcher->requestServedFromMemoryCache(requestId, frameId, loaderId, loader->url().string(), timestamp(), initiatorObject, buildObjectForCachedResource(resource, loader));
}
void InspectorResourceAgent::setInitialScriptContent(unsigned long identifier, const String& sourceString)
@@ -586,7 +591,7 @@
{
RefPtr<Inspector::Protocol::Network::WebSocketRequest> requestObject = Inspector::Protocol::Network::WebSocketRequest::create()
.setHeaders(buildObjectForHeaders(request.httpHeaderFields()));
- m_frontendDispatcher->webSocketWillSendHandshakeRequest(IdentifiersFactory::requestId(identifier), currentTime(), requestObject);
+ m_frontendDispatcher->webSocketWillSendHandshakeRequest(IdentifiersFactory::requestId(identifier), timestamp(), requestObject);
}
void InspectorResourceAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const ResourceResponse& response)
@@ -595,12 +600,12 @@
.setStatus(response.httpStatusCode())
.setStatusText(response.httpStatusText())
.setHeaders(buildObjectForHeaders(response.httpHeaderFields()));
- m_frontendDispatcher->webSocketHandshakeResponseReceived(IdentifiersFactory::requestId(identifier), currentTime(), responseObject);
+ m_frontendDispatcher->webSocketHandshakeResponseReceived(IdentifiersFactory::requestId(identifier), timestamp(), responseObject);
}
void InspectorResourceAgent::didCloseWebSocket(unsigned long identifier)
{
- m_frontendDispatcher->webSocketClosed(IdentifiersFactory::requestId(identifier), currentTime());
+ m_frontendDispatcher->webSocketClosed(IdentifiersFactory::requestId(identifier), timestamp());
}
void InspectorResourceAgent::didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
@@ -609,7 +614,7 @@
.setOpcode(frame.opCode)
.setMask(frame.masked)
.setPayloadData(String(frame.payload, frame.payloadLength));
- m_frontendDispatcher->webSocketFrameReceived(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
+ m_frontendDispatcher->webSocketFrameReceived(IdentifiersFactory::requestId(identifier), timestamp(), frameObject);
}
void InspectorResourceAgent::didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
@@ -618,12 +623,12 @@
.setOpcode(frame.opCode)
.setMask(frame.masked)
.setPayloadData(String(frame.payload, frame.payloadLength));
- m_frontendDispatcher->webSocketFrameSent(IdentifiersFactory::requestId(identifier), currentTime(), frameObject);
+ m_frontendDispatcher->webSocketFrameSent(IdentifiersFactory::requestId(identifier), timestamp(), frameObject);
}
void InspectorResourceAgent::didReceiveWebSocketFrameError(unsigned long identifier, const String& errorMessage)
{
- m_frontendDispatcher->webSocketFrameError(IdentifiersFactory::requestId(identifier), currentTime(), errorMessage);
+ m_frontendDispatcher->webSocketFrameError(IdentifiersFactory::requestId(identifier), timestamp(), errorMessage);
}
#endif // ENABLE(WEB_SOCKETS)
Modified: trunk/Source/WebCore/inspector/InspectorResourceAgent.h (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorResourceAgent.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorResourceAgent.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -138,6 +138,8 @@
private:
void enable();
+ double timestamp();
+
InspectorPageAgent* m_pageAgent;
InspectorClient* m_client;
std::unique_ptr<Inspector::InspectorNetworkFrontendDispatcher> m_frontendDispatcher;
Modified: trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -60,11 +60,6 @@
namespace WebCore {
-void TimelineTimeConverter::reset()
-{
- m_startOffset = monotonicallyIncreasingTime() - currentTime();
-}
-
InspectorTimelineAgent::~InspectorTimelineAgent()
{
}
@@ -117,7 +112,7 @@
else
m_maxCallStackDepth = 5;
- m_timeConverter.reset();
+ m_instrumentingAgents->inspectorEnvironment().executionStopwatch()->start();
m_instrumentingAgents->setInspectorTimelineAgent(this);
@@ -135,6 +130,8 @@
if (!m_enabled)
return;
+ m_instrumentingAgents->inspectorEnvironment().executionStopwatch()->stop();
+
m_instrumentingAgents->setInspectorTimelineAgent(nullptr);
if (m_scriptDebugServer)
@@ -148,6 +145,11 @@
m_frontendDispatcher->recordingStopped();
}
+double InspectorTimelineAgent::timestamp()
+{
+ return m_instrumentingAgents->inspectorEnvironment().executionStopwatch()->elapsedTime();
+}
+
void InspectorTimelineAgent::setPageScriptDebugServer(PageScriptDebugServer* scriptDebugServer)
{
ASSERT(!m_enabled);
@@ -156,9 +158,9 @@
m_scriptDebugServer = scriptDebugServer;
}
-static inline void startProfiling(JSC::ExecState* exec, const String& title)
+static inline void startProfiling(JSC::ExecState* exec, const String& title, PassRefPtr<Stopwatch> stopwatch)
{
- JSC::LegacyProfiler::profiler()->startProfiling(exec, title);
+ JSC::LegacyProfiler::profiler()->startProfiling(exec, title, stopwatch);
}
static inline PassRefPtr<JSC::Profile> stopProfiling(JSC::ExecState* exec, const String& title)
@@ -166,9 +168,9 @@
return JSC::LegacyProfiler::profiler()->stopProfiling(exec, title);
}
-static inline void startProfiling(Frame* frame, const String& title)
+static inline void startProfiling(Frame* frame, const String& title, PassRefPtr<Stopwatch> stopwatch)
{
- startProfiling(toJSDOMWindow(frame, debuggerWorld())->globalExec(), title);
+ startProfiling(toJSDOMWindow(frame, debuggerWorld())->globalExec(), title, stopwatch);
}
static inline PassRefPtr<JSC::Profile> stopProfiling(Frame* frame, const String& title)
@@ -192,7 +194,11 @@
if (!m_enabled && m_pendingConsoleProfileRecords.isEmpty())
internalStart();
- startProfiling(exec, title);
+ // Use an independent stopwatch for console-initiated profiling, since the user will expect it
+ // to be relative to when their command was issued.
+ RefPtr<Stopwatch> profilerStopwatch = Stopwatch::create();
+ profilerStopwatch->start();
+ startProfiling(exec, title, profilerStopwatch.release());
m_pendingConsoleProfileRecords.append(createRecordEntry(TimelineRecordFactory::createConsoleProfileData(title), TimelineRecordType::ConsoleProfile, true, frameFromExecState(exec)));
}
@@ -231,7 +237,7 @@
pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frame);
if (frame && !m_callStackDepth)
- startProfiling(frame, ASCIILiteral("Timeline FunctionCall"));
+ startProfiling(frame, ASCIILiteral("Timeline FunctionCall"), m_instrumentingAgents->inspectorEnvironment().executionStopwatch());
++m_callStackDepth;
}
@@ -406,7 +412,7 @@
if (frame && !m_callStackDepth) {
++m_callStackDepth;
- startProfiling(frame, ASCIILiteral("Timeline EvaluateScript"));
+ startProfiling(frame, ASCIILiteral("Timeline EvaluateScript"), m_instrumentingAgents->inspectorEnvironment().executionStopwatch());
}
}
@@ -745,11 +751,6 @@
quad->setP4(frameView.contentsToRootView(roundedIntPoint(absolute.p4())));
}
-double InspectorTimelineAgent::timestamp()
-{
- return m_timeConverter.fromMonotonicallyIncreasingTime(monotonicallyIncreasingTime());
-}
-
Page* InspectorTimelineAgent::page()
{
return m_pageAgent ? m_pageAgent->page() : nullptr;
Modified: trunk/Source/WebCore/inspector/InspectorTimelineAgent.h (175202 => 175203)
--- trunk/Source/WebCore/inspector/InspectorTimelineAgent.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/InspectorTimelineAgent.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -40,6 +40,7 @@
#include <inspector/InspectorFrontendDispatchers.h>
#include <inspector/InspectorValues.h>
#include <inspector/ScriptDebugListener.h>
+#include <wtf/Stopwatch.h>
#include <wtf/Vector.h>
#include <wtf/WeakPtr.h>
@@ -113,19 +114,6 @@
WebSocketDestroy
};
-class TimelineTimeConverter {
-public:
- TimelineTimeConverter()
- : m_startOffset(0)
- {
- }
- double fromMonotonicallyIncreasingTime(double time) const { return (time - m_startOffset) * 1000.0; }
- void reset();
-
-private:
- double m_startOffset;
-};
-
class InspectorTimelineAgent
: public InspectorAgentBase
, public Inspector::InspectorTimelineBackendDispatcherHandler
@@ -218,7 +206,7 @@
#endif
protected:
- // ScriptDebugListener. This is only used to create records for probe samples.
+ // ScriptDebugListener
virtual void didParseSource(JSC::SourceID, const Script&) override { }
virtual void failedToParseSource(const String&, const String&, int, int, const String&) override { }
virtual void didPause(JSC::ExecState*, const Deprecated::ScriptValue&, const Deprecated::ScriptValue&) override { }
@@ -247,6 +235,7 @@
void internalStart(const int* maxCallStackDepth = nullptr);
void internalStop();
+ double timestamp();
void sendEvent(PassRefPtr<Inspector::InspectorObject>);
void appendRecord(PassRefPtr<Inspector::InspectorObject> data, TimelineRecordType, bool captureCallStack, Frame*);
@@ -264,17 +253,13 @@
void clearRecordStack();
void localToPageQuad(const RenderObject&, const LayoutRect&, FloatQuad*);
- const TimelineTimeConverter& timeConverter() const { return m_timeConverter; }
- double timestamp();
Page* page();
InspectorPageAgent* m_pageAgent;
PageScriptDebugServer* m_scriptDebugServer;
- TimelineTimeConverter m_timeConverter;
std::unique_ptr<Inspector::InspectorTimelineFrontendDispatcher> m_frontendDispatcher;
RefPtr<Inspector::InspectorTimelineBackendDispatcher> m_backendDispatcher;
- double m_timestampOffset;
Vector<TimelineRecordEntry> m_recordStack;
Modified: trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp (175202 => 175203)
--- trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -47,7 +47,6 @@
#include <inspector/ScriptCallStack.h>
#include <inspector/ScriptCallStackFactory.h>
#include <profiler/Profile.h>
-#include <wtf/CurrentTime.h>
using namespace Inspector;
Modified: trunk/Source/WebCore/inspector/WorkerInspectorController.cpp (175202 => 175203)
--- trunk/Source/WebCore/inspector/WorkerInspectorController.cpp 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/WorkerInspectorController.cpp 2014-10-25 22:05:57 UTC (rev 175203)
@@ -51,6 +51,7 @@
#include "WorkerThread.h"
#include <inspector/InspectorBackendDispatcher.h>
#include <inspector/InspectorFrontendDispatchers.h>
+#include <wtf/Stopwatch.h>
using namespace Inspector;
@@ -80,6 +81,7 @@
, m_instrumentingAgents(InstrumentingAgents::create(*this))
, m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
, m_runtimeAgent(nullptr)
+ , m_executionStopwatch(Stopwatch::create())
{
auto runtimeAgent = std::make_unique<WorkerRuntimeAgent>(m_injectedScriptManager.get(), &workerGlobalScope);
m_runtimeAgent = runtimeAgent.get();
@@ -170,6 +172,11 @@
InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext);
}
+PassRefPtr<Stopwatch> WorkerInspectorController::executionStopwatch()
+{
+ return m_executionStopwatch;
+}
+
} // namespace WebCore
#endif // ENABLE(INSPECTOR)
Modified: trunk/Source/WebCore/inspector/WorkerInspectorController.h (175202 => 175203)
--- trunk/Source/WebCore/inspector/WorkerInspectorController.h 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebCore/inspector/WorkerInspectorController.h 2014-10-25 22:05:57 UTC (rev 175203)
@@ -74,6 +74,7 @@
virtual void willCallInjectedScriptFunction(JSC::ExecState*, const String& scriptName, int scriptLine) override;
virtual void didCallInjectedScriptFunction(JSC::ExecState*) override;
virtual void frontendInitialized() override { }
+ virtual PassRefPtr<WTF::Stopwatch> executionStopwatch() override;
private:
friend InstrumentingAgents* instrumentationForWorkerGlobalScope(WorkerGlobalScope*);
@@ -84,6 +85,7 @@
WorkerRuntimeAgent* m_runtimeAgent;
Inspector::InspectorAgentRegistry m_agents;
std::unique_ptr<InspectorFrontendChannel> m_frontendChannel;
+ RefPtr<WTF::Stopwatch> m_executionStopwatch;
RefPtr<Inspector::InspectorBackendDispatcher> m_backendDispatcher;
Vector<InspectorInstrumentationCookie, 2> m_injectedScriptInstrumentationCookies;
};
Modified: trunk/Source/WebInspectorUI/ChangeLog (175202 => 175203)
--- trunk/Source/WebInspectorUI/ChangeLog 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebInspectorUI/ChangeLog 2014-10-25 22:05:57 UTC (rev 175203)
@@ -1,3 +1,50 @@
+2014-10-10 Brian J. Burg <[email protected]>
+
+ Web Inspector: timelines should not count time elapsed while paused in the debugger
+ https://bugs.webkit.org/show_bug.cgi?id=136351
+
+ Reviewed by Timothy Hatcher.
+
+ Don't update the timeline's current time when the debugger is paused.
+
+ Start and end times for timeline records are now in seconds elapsed since timeline
+ recording started, rather than milliseconds since the epoch. Also convert code that
+ tracks page/resource load timings to use elapsed times rather than timestamps.
+
+ Add a workaround to preserve compatibility with old backends. Convert legacy timestamps
+ in multiple agents to elapsed times.
+
+ * UserInterface/Controllers/FrameResourceManager.js:
+ (WebInspector.FrameResourceManager.prototype.resourceRequestWillBeSent):
+ (WebInspector.FrameResourceManager.prototype.resourceRequestWasServedFromMemoryCache):
+ (WebInspector.FrameResourceManager.prototype.resourceRequestDidReceiveResponse):
+ (WebInspector.FrameResourceManager.prototype.resourceRequestDidReceiveData):
+ (WebInspector.FrameResourceManager.prototype.resourceRequestDidFinishLoading):
+ (WebInspector.FrameResourceManager.prototype.resourceRequestDidFailLoading):
+ (WebInspector.FrameResourceManager.prototype._addNewResourceToFrame):
+ * UserInterface/Controllers/ProbeManager.js:
+ * UserInterface/Controllers/TimelineManager.js:
+ (WebInspector.TimelineManager.prototype.computeElapsedTime): Forward to the active TimelineRecording.
+ (WebInspector.TimelineManager.prototype.eventRecorded.processRecord):
+ (WebInspector.TimelineManager.prototype.eventRecorded):
+ (WebInspector.TimelineManager.prototype.pageDidLoad):
+ (WebInspector.TimelineManager.prototype._loadNewRecording):
+ * UserInterface/Models/Probe.js:
+ (WebInspector.ProbeSample):
+ * UserInterface/Models/Resource.js:
+ (WebInspector.Resource.prototype.updateForRedirectResponse):
+ (WebInspector.Resource.prototype.updateForResponse):
+ (WebInspector.Resource.prototype.increaseSize):
+ (WebInspector.Resource.prototype.markAsFinished):
+ (WebInspector.Resource.prototype.markAsFailed):
+ (WebInspector.Resource.prototype.revertMarkAsFinished):
+ * UserInterface/Models/TimelineRecording.js:
+ (WebInspector.TimelineRecording.prototype.computeElapsedTime):
+ * UserInterface/Views/TimelineContentView.js:
+ (WebInspector.TimelineContentView.prototype._debuggerPaused):
+ (WebInspector.TimelineContentView.prototype._debuggerResumed):
+
+
2014-10-23 Jono Wells <[email protected]>
Web Inspector: Double border appearing in node sidebar in expanded items in OS X Mavericks.
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js (175202 => 175203)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js 2014-10-25 22:05:57 UTC (rev 175203)
@@ -184,18 +184,19 @@
if (this._waitingForMainFrameResourceTreePayload)
return;
+ var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
var resource = this._resourceRequestIdentifierMap[requestIdentifier];
if (resource) {
// This is an existing request which is being redirected, update the resource.
console.assert(redirectResponse);
- resource.updateForRedirectResponse(request.url, request.headers, timestamp);
+ resource.updateForRedirectResponse(request.url, request.headers, elapsedTime);
return;
}
var initiatorSourceCodeLocation = this._initiatorSourceCodeLocationFromPayload(initiator);
// This is a new request, make a new resource and add it to the right frame.
- resource = this._addNewResourceToFrame(requestIdentifier, frameIdentifier, loaderIdentifier, request.url, type, request.method, request.headers, request.postData, timestamp, null, null, initiatorSourceCodeLocation);
+ resource = this._addNewResourceToFrame(requestIdentifier, frameIdentifier, loaderIdentifier, request.url, type, request.method, request.headers, request.postData, elapsedTime, null, null, initiatorSourceCodeLocation);
// Associate the resource with the requestIdentifier so it can be found in future loading events.
this._resourceRequestIdentifierMap[requestIdentifier] = resource;
@@ -230,13 +231,13 @@
console.assert(!(requestIdentifier in this._resourceRequestIdentifierMap));
+ var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
var initiatorSourceCodeLocation = this._initiatorSourceCodeLocationFromPayload(initiator);
-
var response = cachedResourcePayload.response;
- var resource = this._addNewResourceToFrame(requestIdentifier, frameIdentifier, loaderIdentifier, cachedResourcePayload.url, cachedResourcePayload.type, null, null, timestamp, null, null, initiatorSourceCodeLocation);
+ var resource = this._addNewResourceToFrame(requestIdentifier, frameIdentifier, loaderIdentifier, cachedResourcePayload.url, cachedResourcePayload.type, null, null, elapsedTime, null, null, initiatorSourceCodeLocation);
resource.markAsCached();
- resource.updateForResponse(cachedResourcePayload.url, response.mimeType, cachedResourcePayload.type, response.headers, response.status, response.statusText, timestamp);
- resource.markAsFinished(timestamp);
+ resource.updateForResponse(cachedResourcePayload.url, response.mimeType, cachedResourcePayload.type, response.headers, response.status, response.statusText, elapsedTime);
+ resource.markAsFinished(elapsedTime);
if (cachedResourcePayload.sourceMapURL)
WebInspector.sourceMapManager.downloadSourceMap(cachedResourcePayload.sourceMapURL, resource.url, resource);
@@ -253,6 +254,7 @@
if (this._waitingForMainFrameResourceTreePayload)
return;
+ var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
var resource = this._resourceRequestIdentifierMap[requestIdentifier];
// We might not have a resource if the inspector was opened during the page load (after resourceRequestWillBeSent is called).
@@ -275,7 +277,7 @@
// If we haven't found an existing Resource by now, then it is a resource that was loading when the inspector
// opened and we just missed the resourceRequestWillBeSent for it. So make a new resource and add it.
if (!resource) {
- resource = this._addNewResourceToFrame(requestIdentifier, frameIdentifier, loaderIdentifier, response.url, type, null, response.requestHeaders, timestamp, null, null);
+ resource = this._addNewResourceToFrame(requestIdentifier, frameIdentifier, loaderIdentifier, response.url, type, null, response.requestHeaders, elapsedTime, null, null);
// Associate the resource with the requestIdentifier so it can be found in future loading events.
this._resourceRequestIdentifierMap[requestIdentifier] = resource;
@@ -284,7 +286,7 @@
if (response.fromDiskCache)
resource.markAsCached();
- resource.updateForResponse(response.url, response.mimeType, type, response.headers, response.status, response.statusText, timestamp);
+ resource.updateForResponse(response.url, response.mimeType, type, response.headers, response.status, response.statusText, elapsedTime);
},
resourceRequestDidReceiveData: function(requestIdentifier, dataLength, encodedDataLength, timestamp)
@@ -296,6 +298,7 @@
return;
var resource = this._resourceRequestIdentifierMap[requestIdentifier];
+ var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
// We might not have a resource if the inspector was opened during the page load (after resourceRequestWillBeSent is called).
// We don't want to assert in this case since we do likely have the resource, via PageAgent.getResourceTree. The Resource
@@ -303,7 +306,7 @@
if (!resource)
return;
- resource.increaseSize(dataLength, timestamp);
+ resource.increaseSize(dataLength, elapsedTime);
if (encodedDataLength !== -1)
resource.increaseTransferSize(encodedDataLength);
@@ -324,7 +327,8 @@
if (!resource)
return;
- resource.markAsFinished(timestamp);
+ var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
+ resource.markAsFinished(elapsedTime);
if (sourceMapURL)
WebInspector.sourceMapManager.downloadSourceMap(sourceMapURL, resource.url, resource);
@@ -347,7 +351,8 @@
if (!resource)
return;
- resource.markAsFailed(canceled, timestamp);
+ var elapsedTime = WebInspector.timelineManager.computeElapsedTime(timestamp);
+ resource.markAsFailed(canceled, elapsedTime);
if (resource === resource.parentFrame.provisionalMainResource)
resource.parentFrame.clearProvisionalLoad();
@@ -382,7 +387,7 @@
// Private
- _addNewResourceToFrame: function(requestIdentifier, frameIdentifier, loaderIdentifier, url, type, requestMethod, requestHeaders, requestData, timestamp, frameName, frameSecurityOrigin, initiatorSourceCodeLocation)
+ _addNewResourceToFrame: function(requestIdentifier, frameIdentifier, loaderIdentifier, url, type, requestMethod, requestHeaders, requestData, elapsedTime, frameName, frameSecurityOrigin, initiatorSourceCodeLocation)
{
console.assert(!this._waitingForMainFrameResourceTreePayload);
@@ -396,12 +401,12 @@
else if (frame.provisionalMainResource && frame.provisionalMainResource.url ="" url && frame.provisionalLoaderIdentifier === loaderIdentifier)
resource = frame.provisionalMainResource;
else {
- resource = new WebInspector.Resource(url, null, type, loaderIdentifier, requestIdentifier, requestMethod, requestHeaders, requestData, timestamp, initiatorSourceCodeLocation);
+ resource = new WebInspector.Resource(url, null, type, loaderIdentifier, requestIdentifier, requestMethod, requestHeaders, requestData, elapsedTime, initiatorSourceCodeLocation);
this._addResourceToFrame(frame, resource);
}
} else {
// This is a new request for a new frame, which is always the main resource.
- resource = new WebInspector.Resource(url, null, type, loaderIdentifier, requestIdentifier, requestMethod, requestHeaders, requestData, timestamp, initiatorSourceCodeLocation);
+ resource = new WebInspector.Resource(url, null, type, loaderIdentifier, requestIdentifier, requestMethod, requestHeaders, requestData, elapsedTime, initiatorSourceCodeLocation);
frame = new WebInspector.Frame(frameIdentifier, frameName, frameSecurityOrigin, loaderIdentifier, resource);
this._frameIdentifierMap[frame.id] = frame;
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/ProbeManager.js (175202 => 175203)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/ProbeManager.js 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/ProbeManager.js 2014-10-25 22:05:57 UTC (rev 175203)
@@ -75,7 +75,8 @@
{
console.assert(this._probesByIdentifier.has(sample.probeId), "Unknown probe identifier specified for sample: ", sample);
var probe = this._probesByIdentifier.get(sample.probeId);
- probe.addSample(new WebInspector.ProbeSample(sample.sampleId, sample.batchId, sample.timestamp, sample.payload));
+ var elapsedTime = WebInspector.timelineManager.computeElapsedTime(sample.timestamp);
+ probe.addSample(new WebInspector.ProbeSample(sample.sampleId, sample.batchId, elapsedTime, sample.payload));
},
// Private
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (175202 => 175203)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js 2014-10-25 22:05:57 UTC (rev 175203)
@@ -121,6 +121,14 @@
this._activeRecording = null;
},
+ computeElapsedTime: function(timestamp)
+ {
+ if (!this._activeRecording)
+ return 0;
+
+ return this._activeRecording.computeElapsedTime(timestamp);
+ },
+
// Protected
capturingStarted: function()
@@ -163,10 +171,8 @@
function processRecord(recordPayload, parentRecordPayload)
{
- // Convert the timestamps to seconds to match the resource timestamps.
- var startTime = recordPayload.startTime / 1000;
- var endTime = recordPayload.endTime / 1000;
-
+ var startTime = this.activeRecording.computeElapsedTime(recordPayload.startTime);
+ var endTime = this.activeRecording.computeElapsedTime(recordPayload.endTime);
var callFrames = this._callFramesFromPayload(recordPayload.stackTrace);
var significantCallFrame = null;
@@ -393,7 +399,7 @@
pageDidLoad: function(timestamp)
{
if (isNaN(WebInspector.frameResourceManager.mainFrame.loadEventTimestamp))
- WebInspector.frameResourceManager.mainFrame.markLoadEvent(timestamp);
+ WebInspector.frameResourceManager.mainFrame.markLoadEvent(this.activeRecording.computeElapsedTime(timestamp));
},
// Private
@@ -417,6 +423,7 @@
if (oldRecording)
oldRecording.unloaded();
+ this._legacyFirstRecordedTimestamp = NaN;
this._activeRecording = newRecording;
this.dispatchEventToListeners(WebInspector.TimelineManager.Event.RecordingLoaded, {oldRecording: oldRecording});
},
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Probe.js (175202 => 175203)
--- trunk/Source/WebInspectorUI/UserInterface/Models/Probe.js 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Probe.js 2014-10-25 22:05:57 UTC (rev 175203)
@@ -24,11 +24,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-WebInspector.ProbeSample = function(sampleId, batchId, timestamp, payload)
+WebInspector.ProbeSample = function(sampleId, batchId, elapsedTime, payload)
{
this.sampleId = sampleId;
this.batchId = batchId;
- this.timestamp = timestamp;
+ this.timestamp = elapsedTime;
this.object = WebInspector.RemoteObject.fromPayload(payload);
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js (175202 => 175203)
--- trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Resource.js 2014-10-25 22:05:57 UTC (rev 175203)
@@ -459,7 +459,7 @@
return null;
},
- updateForRedirectResponse: function(url, requestHeaders, timestamp)
+ updateForRedirectResponse: function(url, requestHeaders, elapsedTime)
{
console.assert(!this._finished);
console.assert(!this._failed);
@@ -469,7 +469,7 @@
this._url = url;
this._requestHeaders = requestHeaders || {};
- this._lastRedirectReceivedTimestamp = timestamp || NaN;
+ this._lastRedirectReceivedTimestamp = elapsedTime || NaN;
if (oldURL !== url) {
// Delete the URL components so the URL is re-parsed the next time it is requested.
@@ -482,7 +482,7 @@
this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
},
- updateForResponse: function(url, mimeType, type, responseHeaders, statusCode, statusText, timestamp)
+ updateForResponse: function(url, mimeType, type, responseHeaders, statusCode, statusText, elapsedTime)
{
console.assert(!this._finished);
console.assert(!this._failed);
@@ -501,7 +501,7 @@
this._statusCode = statusCode;
this._statusText = statusText;
this._responseHeaders = responseHeaders || {};
- this._responseReceivedTimestamp = timestamp || NaN;
+ this._responseReceivedTimestamp = elapsedTime || NaN;
this._responseHeadersSize = String(this._statusCode).length + this._statusText.length + 12; // Extra length is for "HTTP/1.1 ", " ", and "\r\n".
for (var name in this._responseHeaders)
@@ -563,7 +563,7 @@
return false;
},
- increaseSize: function(dataLength, timestamp)
+ increaseSize: function(dataLength, elapsedTime)
{
console.assert(dataLength >= 0);
@@ -574,7 +574,7 @@
this._size += dataLength;
- this._lastDataReceivedTimestamp = timestamp || NaN;
+ this._lastDataReceivedTimestamp = elapsedTime || NaN;
this.dispatchEventToListeners(WebInspector.Resource.Event.SizeDidChange, {previousSize: previousSize});
@@ -605,13 +605,13 @@
this.dispatchEventToListeners(WebInspector.Resource.Event.TransferSizeDidChange);
},
- markAsFinished: function(timestamp)
+ markAsFinished: function(elapsedTime)
{
console.assert(!this._failed);
console.assert(!this._canceled);
this._finished = true;
- this._finishedOrFailedTimestamp = timestamp || NaN;
+ this._finishedOrFailedTimestamp = elapsedTime || NaN;
this.dispatchEventToListeners(WebInspector.Resource.Event.LoadingDidFinish);
this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
@@ -620,13 +620,13 @@
this.requestContentFromBackendIfNeeded();
},
- markAsFailed: function(canceled, timestamp)
+ markAsFailed: function(canceled, elapsedTime)
{
console.assert(!this._finished);
this._failed = true;
this._canceled = canceled;
- this._finishedOrFailedTimestamp = timestamp || NaN;
+ this._finishedOrFailedTimestamp = elapsedTime || NaN;
this.dispatchEventToListeners(WebInspector.Resource.Event.LoadingDidFail);
this.dispatchEventToListeners(WebInspector.Resource.Event.TimestampsDidChange);
@@ -635,7 +635,7 @@
this.servicePendingContentRequests(true);
},
- revertMarkAsFinished: function(timestamp)
+ revertMarkAsFinished: function()
{
console.assert(!this._failed);
console.assert(!this._canceled);
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js (175202 => 175203)
--- trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js 2014-10-25 22:05:57 UTC (rev 175203)
@@ -32,6 +32,9 @@
this._displayName = displayName;
this._isWritable = true;
+ // For legacy backends, we compute the elapsed time of records relative to this timestamp.
+ this._legacyFirstRecordedTimestamp = NaN;
+
for (var key of Object.keys(WebInspector.TimelineRecord.Type)) {
var type = WebInspector.TimelineRecord.Type[key];
var timeline = new WebInspector.Timeline(type);
@@ -49,6 +52,8 @@
TimesUpdated: "timeline-recording-times-updated"
};
+WebInspector.TimelineRecording.TimestampThresholdForLegacyRecordConversion = 28800000; // Date.parse("Jan 1, 1970")
+
WebInspector.TimelineRecording.prototype = {
constructor: WebInspector.TimelineRecording,
__proto__: WebInspector.Object.prototype,
@@ -175,6 +180,24 @@
this.dispatchEventToListeners(WebInspector.TimelineRecording.Event.SourceCodeTimelineAdded, {sourceCodeTimeline: sourceCodeTimeline});
},
+ computeElapsedTime: function(timestamp)
+ {
+ if (!timestamp || isNaN(timestamp))
+ return NaN;
+
+ // COMPATIBILITY (iOS8): old backends send timestamps (milliseconds since the epoch), rather
+ // than seconds elapsed since timeline capturing started. We approximate the latter by
+ // subtracting the start timestamp, as old versions did not use monotonic times.
+ if (isNaN(this._legacyFirstRecordedTimestamp))
+ this._legacyFirstRecordedTimestamp = timestamp;
+
+ // If the record's start time sems unreasonably large, treat it as a legacy timestamp.
+ if (timestamp > WebInspector.TimelineRecording.TimestampThresholdForLegacyRecordConversion)
+ return (timestamp - this._legacyFirstRecordedTimestamp) / 1000.0;
+
+ return timestamp;
+ },
+
// Private
_keyForRecord: function(record)
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TimelineContentView.js (175202 => 175203)
--- trunk/Source/WebInspectorUI/UserInterface/Views/TimelineContentView.js 2014-10-25 19:58:14 UTC (rev 175202)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TimelineContentView.js 2014-10-25 22:05:57 UTC (rev 175203)
@@ -98,6 +98,9 @@
WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.Event.CapturingStarted, this._capturingStarted, this);
WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.Event.CapturingStopped, this._capturingStopped, this);
+ WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Paused, this._debuggerPaused, this);
+ WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.Resumed, this._debuggerResumed, this);
+
this.showOverviewTimelineView();
};
@@ -407,6 +410,22 @@
this._stopUpdatingCurrentTime();
},
+ _debuggerPaused: function(event)
+ {
+ if (WebInspector.replayManager.sessionState === WebInspector.ReplayManager.SessionState.Replaying)
+ return;
+
+ this._stopUpdatingCurrentTime();
+ },
+
+ _debuggerResumed: function(event)
+ {
+ if (WebInspector.replayManager.sessionState === WebInspector.ReplayManager.SessionState.Replaying)
+ return;
+
+ this._startUpdatingCurrentTime();
+ },
+
_recordingTimesUpdated: function(event)
{
if (!this._waitingToResetCurrentTime)