author | Brian Hackett <bhackett1024@gmail.com> |
Wed, 17 Oct 2018 10:10:22 -0600 | |
changeset 497793 | 0fa982d6f06a2739f7667e462946b9c80739c3a8 |
parent 497792 | ed0463d80c34acd808558758e8a5467cb59e8ab1 |
child 497794 | 09a979b6e583eab5833722f358c3a26e0b89a3a2 |
push id | 10002 |
push user | archaeopteryx@coole-files.de |
push date | Fri, 19 Oct 2018 23:09:29 +0000 |
treeherder | mozilla-beta@01378c910610 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mccr8 |
bugs | 1488808 |
milestone | 64.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/toolkit/recordreplay/ProcessRewind.cpp +++ b/toolkit/recordreplay/ProcessRewind.cpp @@ -3,16 +3,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ProcessRewind.h" #include "nsString.h" #include "ipc/ChildInternal.h" +#include "ipc/ParentInternal.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/StaticMutex.h" #include "InfallibleVector.h" #include "MemorySnapshot.h" #include "Monitor.h" #include "ProcessRecordReplay.h" #include "ThreadSnapshot.h" @@ -220,19 +221,28 @@ DisallowUnhandledDivergeFromRecording() { MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread()); gUnhandledDivergeAllowed = false; } void EnsureNotDivergedFromRecording() { + // If we have diverged from the recording and encounter an operation we can't + // handle, rewind to the last checkpoint. AssertEventsAreNotPassedThrough(); if (HasDivergedFromRecording()) { MOZ_RELEASE_ASSERT(gUnhandledDivergeAllowed); + + // Crash instead of rewinding in the painting stress mode, for finding + // areas where middleman calls do not cover all painting logic. + if (parent::InRepaintStressMode()) { + MOZ_CRASH("Recording divergence in repaint stress mode"); + } + PrintSpew("Unhandled recording divergence, restoring checkpoint...\n"); RestoreCheckpointAndResume(gRewindInfo->mSavedCheckpoints.back().mCheckpoint); Unreachable(); } } bool HasSavedCheckpoint()
--- a/toolkit/recordreplay/ipc/ChildIPC.cpp +++ b/toolkit/recordreplay/ipc/ChildIPC.cpp @@ -415,16 +415,28 @@ SetVsyncObserver(VsyncObserver* aObserve static void NotifyVsyncObserver() { if (gVsyncObserver) { gVsyncObserver->NotifyVsync(TimeStamp::Now()); } } +void +OnVsync() +{ + // In the repainting stress mode, we create a new checkpoint on every vsync + // message received from the UI process. When we notify the parent about the + // new checkpoint it will trigger a repaint to make sure that all layout and + // painting activity can occur when diverged from the recording. + if (parent::InRepaintStressMode()) { + CreateCheckpoint(); + } +} + /////////////////////////////////////////////////////////////////////////////// // Painting /////////////////////////////////////////////////////////////////////////////// // Graphics memory is only written on the compositor thread and read on the // main thread and by the middleman. The gNumPendingPaints counter is used to // synchronize access, so that data is not read until the paint has completed. static Maybe<PaintMessage> gPaintMessage;
--- a/toolkit/recordreplay/ipc/ChildIPC.h +++ b/toolkit/recordreplay/ipc/ChildIPC.h @@ -36,16 +36,19 @@ void CreateCheckpoint(); // Painting Coordination /////////////////////////////////////////////////////////////////////////////// // Tell the child code about any singleton vsync observer that currently // exists. This is used to trigger artifical vsyncs that paint the current // graphics when paused. void SetVsyncObserver(VsyncObserver* aObserver); +// Called before processing incoming vsyncs from the UI process. +void OnVsync(); + // Tell the child code about any ongoing painting activity. When a paint is // about to happen, the main thread calls NotifyPaintStart, and when the // compositor thread finishes the paint it calls NotifyPaintComplete. void NotifyPaintStart(); void NotifyPaintComplete(); // Get a draw target which the compositor thread can paint to. already_AddRefed<gfx::DrawTarget> DrawTargetForRemoteDrawing(LayoutDeviceIntSize aSize);
--- a/toolkit/recordreplay/ipc/DisabledIPC.cpp +++ b/toolkit/recordreplay/ipc/DisabledIPC.cpp @@ -47,16 +47,22 @@ void CreateCheckpoint() void SetVsyncObserver(VsyncObserver* aObserver) { MOZ_CRASH(); } void +OnVsync() +{ + MOZ_CRASH(); +} + +void NotifyPaintStart() { MOZ_CRASH(); } void NotifyPaintComplete() {
--- a/toolkit/recordreplay/ipc/ParentForwarding.cpp +++ b/toolkit/recordreplay/ipc/ParentForwarding.cpp @@ -105,16 +105,23 @@ HandleMessageInMiddleman(ipc::Side aSide return false; } // Return whether a message should be sent to the recording child, even if it // is not currently active. static bool AlwaysForwardMessage(const IPC::Message& aMessage) { + // Always forward messages in repaint stress mode, as the active child is + // almost always a replaying child and lost messages make it hard to load + // pages completely. + if (InRepaintStressMode()) { + return true; + } + IPC::Message::msgid_t type = aMessage.type(); // Forward close messages so that the tab shuts down properly even if it is // currently replaying. return type == dom::PBrowser::Msg_Destroy__ID; } static bool gMainThreadIsWaitingForIPDLReply = false;
--- a/toolkit/recordreplay/ipc/ParentGraphics.cpp +++ b/toolkit/recordreplay/ipc/ParentGraphics.cpp @@ -170,11 +170,24 @@ UpdateGraphicsInUIProcess(const PaintMes // Call into the graphics module to update the canvas it manages. RootedValue rval(cx); if (!JS_CallFunctionName(cx, *gGraphicsSandbox, "Update", args, &rval)) { MOZ_CRASH("UpdateGraphicsInUIProcess"); } } +bool +InRepaintStressMode() +{ + static bool checked = false; + static bool rv; + if (!checked) { + AutoEnsurePassThroughThreadEvents pt; + rv = TestEnv("MOZ_RECORD_REPLAY_REPAINT_STRESS"); + checked = true; + } + return rv; +} + } // namespace parent } // namespace recordreplay } // namespace mozilla
--- a/toolkit/recordreplay/ipc/ParentIPC.cpp +++ b/toolkit/recordreplay/ipc/ParentIPC.cpp @@ -972,21 +972,55 @@ static bool gChildExecuteBackward = fals // Whether there is a ResumeForwardOrBackward task which should execute on the // main thread. This will continue execution in the preferred direction. static bool gResumeForwardOrBackward = false; // Hit any breakpoints installed for forced pauses. static void HitForcedPauseBreakpoints(bool aRecordingBoundary); +static void +MaybeSendRepaintMessage() +{ + // In repaint stress mode, we want to trigger a repaint at every checkpoint, + // so before resuming after the child pauses at each checkpoint, send it a + // repaint message. There might not be a debugger open, so manually craft the + // same message which the debugger would send to trigger a repaint and parse + // the result. + if (InRepaintStressMode()) { + MaybeSwitchToReplayingChild(); + + const char16_t contents[] = u"{\"type\":\"repaint\"}"; + + js::CharBuffer request, response; + request.append(contents, ArrayLength(contents) - 1); + SendRequest(request, &response); + + AutoSafeJSContext cx; + JS::RootedValue value(cx); + if (JS_ParseJSON(cx, response.begin(), response.length(), &value)) { + MOZ_RELEASE_ASSERT(value.isObject()); + JS::RootedObject obj(cx, &value.toObject()); + RootedValue width(cx), height(cx); + if (JS_GetProperty(cx, obj, "width", &width) && width.isNumber() && width.toNumber() && + JS_GetProperty(cx, obj, "height", &height) && height.isNumber() && height.toNumber()) { + PaintMessage message(width.toNumber(), height.toNumber()); + UpdateGraphicsInUIProcess(&message); + } + } + } +} + void Resume(bool aForward) { gActiveChild->WaitUntilPaused(); + MaybeSendRepaintMessage(); + // Set the preferred direction of travel. gResumeForwardOrBackward = false; gChildExecuteForward = aForward; gChildExecuteBackward = !aForward; // When rewinding, make sure the active child can rewind to the previous // checkpoint. if (!aForward && !gActiveChild->HasSavedCheckpoint(gActiveChild->RewindTargetCheckpoint())) {
--- a/toolkit/recordreplay/ipc/ParentInternal.h +++ b/toolkit/recordreplay/ipc/ParentInternal.h @@ -96,16 +96,23 @@ static const int32_t GraphicsHandshakeMe // ID for the mach message sent from the middleman to a child process with the // requested memory for. static const int32_t GraphicsMemoryMessageId = 43; // Fixed size of the graphics shared memory buffer. static const size_t GraphicsMemorySize = 4096 * 4096 * 4; +// Return whether the environment variable activating repaint stress mode is +// set. This makes various changes in both the middleman and child processes to +// trigger a child to diverge from the recording and repaint on every vsync, +// making sure that repainting can handle all the system interactions that +// occur while painting the current tab. +bool InRepaintStressMode(); + /////////////////////////////////////////////////////////////////////////////// // Child Processes /////////////////////////////////////////////////////////////////////////////// // Information about the role which a child process is fulfilling, and governs // how the process responds to incoming messages. class ChildRole {