mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
c95dc46546
@ -749,3 +749,7 @@ netmonitor.custom.cancel=Cancel
|
||||
# LOCALIZATION NOTE (netmonitor.backButton): This is the label displayed
|
||||
# on the button which exists the performance statistics view
|
||||
netmonitor.backButton=Back
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.headers.learnMore): This is the label displayed
|
||||
# next to a header list item, with a link to external documentation
|
||||
netmonitor.headers.learnMore=Learn More
|
||||
|
119
devtools/client/netmonitor/shared/components/headers-mdn.js
Normal file
119
devtools/client/netmonitor/shared/components/headers-mdn.js
Normal file
@ -0,0 +1,119 @@
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* A mapping of header names to external documentation. Any header included
|
||||
* here will show a "Learn More" link alongside it.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var URL_DOMAIN = "https://developer.mozilla.org";
|
||||
const URL_PATH = "/en-US/docs/Web/HTTP/Headers/";
|
||||
const URL_PARAMS =
|
||||
"?utm_source=mozilla&utm_medium=devtools-netmonitor&utm_campaign=default";
|
||||
|
||||
var SUPPORTED_HEADERS = [
|
||||
"Accept",
|
||||
"Accept-Charset",
|
||||
"Accept-Encoding",
|
||||
"Accept-Language",
|
||||
"Accept-Ranges",
|
||||
"Access-Control-Allow-Credentials",
|
||||
"Access-Control-Allow-Headers",
|
||||
"Access-Control-Allow-Methods",
|
||||
"Access-Control-Allow-Origin",
|
||||
"Access-Control-Expose-Headers",
|
||||
"Access-Control-Max-Age",
|
||||
"Access-Control-Request-Headers",
|
||||
"Access-Control-Request-Method",
|
||||
"Age",
|
||||
"Cache-Control",
|
||||
"Connection",
|
||||
"Content-Disposition",
|
||||
"Content-Encoding",
|
||||
"Content-Language",
|
||||
"Content-Length",
|
||||
"Content-Location",
|
||||
"Content-Security-Policy",
|
||||
"Content-Security-Policy-Report-Only",
|
||||
"Content-Type",
|
||||
"Cookie",
|
||||
"Cookie2",
|
||||
"DNT",
|
||||
"Date",
|
||||
"ETag",
|
||||
"Expires",
|
||||
"From",
|
||||
"Host",
|
||||
"If-Match",
|
||||
"If-Modified-Since",
|
||||
"If-None-Match",
|
||||
"If-Range",
|
||||
"If-Unmodified-Since",
|
||||
"Keep-Alive",
|
||||
"Last-Modified",
|
||||
"Location",
|
||||
"Origin",
|
||||
"Pragma",
|
||||
"Public-Key-Pins",
|
||||
"Public-Key-Pins-Report-Only",
|
||||
"Referer",
|
||||
"Referrer-Policy",
|
||||
"Retry-After",
|
||||
"Server",
|
||||
"Set-Cookie",
|
||||
"Set-Cookie2",
|
||||
"Strict-Transport-Security",
|
||||
"TE",
|
||||
"Tk",
|
||||
"Trailer",
|
||||
"Transfer-Encoding",
|
||||
"Upgrade-Insecure-Requests",
|
||||
"User-Agent",
|
||||
"Vary",
|
||||
"Via",
|
||||
"Warning",
|
||||
"X-Content-Type-Options",
|
||||
"X-DNS-Prefetch-Control",
|
||||
"X-Frame-Options",
|
||||
"X-XSS-Protection"
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the MDN URL for the specified header
|
||||
*
|
||||
* @param {string} Name of the header
|
||||
* The baseURL to use.
|
||||
*
|
||||
* @return {string}
|
||||
* The MDN URL for the header, or null if not available.
|
||||
*/
|
||||
exports.getURL = (header) => {
|
||||
if (SUPPORTED_HEADERS.indexOf(header) === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return URL_DOMAIN + URL_PATH + header + URL_PARAMS;
|
||||
};
|
||||
|
||||
/**
|
||||
* Use a different domain for the URLs. Used only for testing.
|
||||
*
|
||||
* @param {string} domain
|
||||
* The domain to use.
|
||||
*/
|
||||
exports.setDomain = (domain) => {
|
||||
URL_DOMAIN = domain;
|
||||
};
|
||||
|
||||
/**
|
||||
* Use a different list of supported headers. Used only for testing.
|
||||
*
|
||||
* @param {array} headers
|
||||
* The supported headers to use.
|
||||
*/
|
||||
exports.setSupportedHeaders = (headers) => {
|
||||
SUPPORTED_HEADERS = headers;
|
||||
};
|
@ -15,11 +15,16 @@ const {
|
||||
const { L10N } = require("../../l10n");
|
||||
const { writeHeaderText } = require("../../request-utils");
|
||||
const { getFormattedSize } = require("../../utils/format-utils");
|
||||
const Services = require("Services");
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const HeadersMDN = require("devtools/client/netmonitor/shared/components/headers-mdn");
|
||||
const { REPS, MODE } = require("devtools/client/shared/components/reps/load-reps");
|
||||
const Rep = createFactory(REPS.Rep);
|
||||
|
||||
// Components
|
||||
const PropertiesView = createFactory(require("./properties-view"));
|
||||
|
||||
const { div, input, textarea } = DOM;
|
||||
const { a, div, input, textarea } = DOM;
|
||||
const EDIT_AND_RESEND = L10N.getStr("netmonitor.summary.editAndResend");
|
||||
const RAW_HEADERS = L10N.getStr("netmonitor.summary.rawHeaders");
|
||||
const RAW_HEADERS_REQUEST = L10N.getStr("netmonitor.summary.rawHeaders.requestHeaders");
|
||||
@ -45,6 +50,7 @@ const HeadersPanel = createClass({
|
||||
propTypes: {
|
||||
cloneSelectedRequest: PropTypes.func.isRequired,
|
||||
request: PropTypes.object.isRequired,
|
||||
renderValue: PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
@ -213,10 +219,49 @@ const HeadersPanel = createClass({
|
||||
object,
|
||||
filterPlaceHolder: HEADERS_FILTER_TEXT,
|
||||
sectionNames: Object.keys(object),
|
||||
renderValue
|
||||
}),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
function onLearnMoreClick(e, headerDocURL) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
|
||||
win.openUILinkIn(headerDocURL, "tab");
|
||||
}
|
||||
|
||||
function renderValue(props) {
|
||||
const { member, value } = props;
|
||||
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
let headerDocURL = HeadersMDN.getURL(member.name);
|
||||
|
||||
return (
|
||||
div({ className: "treeValueCellDivider" },
|
||||
Rep(Object.assign(props, {
|
||||
// FIXME: A workaround for the issue in StringRep
|
||||
// Force StringRep to crop the text everytime
|
||||
member: Object.assign({}, member, { open: false }),
|
||||
mode: MODE.TINY,
|
||||
cropLimit: 60,
|
||||
})),
|
||||
headerDocURL ?
|
||||
a({
|
||||
className: "learn-more-link",
|
||||
title: headerDocURL,
|
||||
onClick: (e) => onLearnMoreClick(e, headerDocURL),
|
||||
}, `[${L10N.getStr("netmonitor.headers.learnMore")}]`)
|
||||
:
|
||||
null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = HeadersPanel;
|
||||
|
@ -6,6 +6,7 @@ DevToolsModules(
|
||||
'cookies-panel.js',
|
||||
'details-panel.js',
|
||||
'editor.js',
|
||||
'headers-mdn.js',
|
||||
'headers-panel.js',
|
||||
'params-panel.js',
|
||||
'preview-panel.js',
|
||||
|
@ -98,6 +98,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
||||
[browser_net_cyrillic-01.js]
|
||||
[browser_net_cyrillic-02.js]
|
||||
[browser_net_frame.js]
|
||||
[browser_net_header-docs.js]
|
||||
skip-if = (os == 'linux' && debug && bits == 32) # Bug 1321434
|
||||
[browser_net_filter-01.js]
|
||||
skip-if = (os == 'linux' && debug && bits == 32) # Bug 1303439
|
||||
|
56
devtools/client/netmonitor/test/browser_net_header-docs.js
Normal file
56
devtools/client/netmonitor/test/browser_net_header-docs.js
Normal file
@ -0,0 +1,56 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const HeadersMDN = require("devtools/client/netmonitor/shared/components/headers-mdn");
|
||||
|
||||
/**
|
||||
* Tests if "Learn More" links are correctly displayed
|
||||
* next to headers.
|
||||
*/
|
||||
add_task(function* () {
|
||||
let { tab, monitor } = yield initNetMonitor(POST_DATA_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
let wait = waitForNetworkEvents(monitor, 0, 2);
|
||||
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
|
||||
content.wrappedJSObject.performRequests();
|
||||
});
|
||||
yield wait;
|
||||
|
||||
let origItem = RequestsMenu.getItemAtIndex(0);
|
||||
RequestsMenu.selectedItem = origItem;
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelectorAll(".request-list-item")[0]);
|
||||
|
||||
testShowLearnMore(origItem);
|
||||
|
||||
return teardown(monitor);
|
||||
|
||||
/*
|
||||
* Tests that a "Learn More" button is only shown if
|
||||
* and only if a header is documented in MDN.
|
||||
*/
|
||||
function testShowLearnMore(data) {
|
||||
document.querySelectorAll(".properties-view .treeRow.stringRow").forEach((rowEl, index) => {
|
||||
let headerName = rowEl.querySelectorAll(".treeLabelCell .treeLabel")[0].textContent;
|
||||
let headerDocURL = HeadersMDN.getURL(headerName);
|
||||
let learnMoreEl = rowEl.querySelectorAll(".treeValueCell .learn-more-link");
|
||||
|
||||
if (headerDocURL === null) {
|
||||
ok(learnMoreEl.length === 0,
|
||||
"undocumented header does not include a \"Learn More\" button");
|
||||
} else {
|
||||
ok(learnMoreEl[0].getAttribute("title") === headerDocURL,
|
||||
"documented header includes a \"Learn More\" button with a link to MDN");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -77,6 +77,23 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.treeTable .treeValueCellDivider {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* Learn More link */
|
||||
.treeTable .treeValueCell .learn-more-link {
|
||||
color: var(--theme-highlight-blue);
|
||||
cursor: pointer;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.treeTable .treeValueCell .learn-more-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Toggle Icon */
|
||||
|
||||
|
@ -67,24 +67,28 @@ namespace {
|
||||
|
||||
// The number of queued runnables within the TabGroup ThrottledEventQueue
|
||||
// at which to begin applying back pressure to the window.
|
||||
const uint32_t kThrottledEventQueueBackPressure = 5000;
|
||||
#define DEFAULT_THROTTLED_EVENT_QUEUE_BACK_PRESSURE 5000
|
||||
static uint32_t gThrottledEventQueueBackPressure;
|
||||
|
||||
// The amount of delay to apply to timers when back pressure is triggered.
|
||||
// As the length of the ThrottledEventQueue grows delay is increased. The
|
||||
// delay is scaled such that every kThrottledEventQueueBackPressure runnables
|
||||
// in the queue equates to an additional kBackPressureDelayMS.
|
||||
const double kBackPressureDelayMS = 500;
|
||||
#define DEFAULT_BACK_PRESSURE_DELAY_MS 250
|
||||
static uint32_t gBackPressureDelayMS;
|
||||
|
||||
// This defines a limit for how much the delay must drop before we actually
|
||||
// reduce back pressure throttle amount. This makes the throttle delay
|
||||
// a bit "sticky" once we enter back pressure.
|
||||
const double kBackPressureDelayReductionThresholdMS = 400;
|
||||
#define DEFAULT_BACK_PRESSURE_DELAY_REDUCTION_THRESHOLD_MS 1000
|
||||
static uint32_t gBackPressureDelayReductionThresholdMS;
|
||||
|
||||
// The minimum delay we can reduce back pressure to before we just floor
|
||||
// the value back to zero. This allows us to ensure that we can exit
|
||||
// back pressure event if there are always a small number of runnables
|
||||
// queued up.
|
||||
const double kBackPressureDelayMinimumMS = 100;
|
||||
#define DEFAULT_BACK_PRESSURE_DELAY_MINIMUM_MS 100
|
||||
static uint32_t gBackPressureDelayMinimumMS;
|
||||
|
||||
// Convert a ThrottledEventQueue length to a timer delay in milliseconds.
|
||||
// This will return a value between 0 and INT32_MAX.
|
||||
@ -92,8 +96,8 @@ int32_t
|
||||
CalculateNewBackPressureDelayMS(uint32_t aBacklogDepth)
|
||||
{
|
||||
double multiplier = static_cast<double>(aBacklogDepth) /
|
||||
static_cast<double>(kThrottledEventQueueBackPressure);
|
||||
double value = kBackPressureDelayMS * multiplier;
|
||||
static_cast<double>(gThrottledEventQueueBackPressure);
|
||||
double value = static_cast<double>(gBackPressureDelayMS) * multiplier;
|
||||
// Avoid overflow
|
||||
if (value > INT32_MAX) {
|
||||
value = INT32_MAX;
|
||||
@ -102,7 +106,7 @@ CalculateNewBackPressureDelayMS(uint32_t aBacklogDepth)
|
||||
// Once we get close to an empty queue just floor the delay back to zero.
|
||||
// We want to ensure we don't get stuck in a condition where there is a
|
||||
// small amount of delay remaining due to an active, but reasonable, queue.
|
||||
else if (value < kBackPressureDelayMinimumMS) {
|
||||
else if (value < static_cast<double>(gBackPressureDelayMinimumMS)) {
|
||||
value = 0;
|
||||
}
|
||||
return static_cast<int32_t>(value);
|
||||
@ -153,6 +157,19 @@ TimeoutManager::Initialize()
|
||||
Preferences::AddBoolVarCache(&gAnnotateTrackingChannels,
|
||||
"privacy.trackingprotection.annotate_channels",
|
||||
false);
|
||||
|
||||
Preferences::AddUintVarCache(&gThrottledEventQueueBackPressure,
|
||||
"dom.timeout.throttled_event_queue_back_pressure",
|
||||
DEFAULT_THROTTLED_EVENT_QUEUE_BACK_PRESSURE);
|
||||
Preferences::AddUintVarCache(&gBackPressureDelayMS,
|
||||
"dom.timeout.back_pressure_delay_ms",
|
||||
DEFAULT_BACK_PRESSURE_DELAY_MS);
|
||||
Preferences::AddUintVarCache(&gBackPressureDelayReductionThresholdMS,
|
||||
"dom.timeout.back_pressure_delay_reduction_threshold_ms",
|
||||
DEFAULT_BACK_PRESSURE_DELAY_REDUCTION_THRESHOLD_MS);
|
||||
Preferences::AddUintVarCache(&gBackPressureDelayMinimumMS,
|
||||
"dom.timeout.back_pressure_delay_minimum_ms",
|
||||
DEFAULT_BACK_PRESSURE_DELAY_MINIMUM_MS);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@ -654,7 +671,7 @@ TimeoutManager::MaybeApplyBackPressure()
|
||||
// rarely fire under normaly circumstances. Its low enough, though,
|
||||
// that we should have time to slow new runnables from being added before an
|
||||
// OOM occurs.
|
||||
if (queue->Length() < kThrottledEventQueueBackPressure) {
|
||||
if (queue->Length() < gThrottledEventQueueBackPressure) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -712,8 +729,8 @@ TimeoutManager::CancelOrUpdateBackPressure(nsGlobalWindow* aWindow)
|
||||
// can be quite expensive. We only want to call that method if the back log
|
||||
// is really clearing.
|
||||
else if (newBackPressureDelayMS == 0 ||
|
||||
(newBackPressureDelayMS <=
|
||||
(mBackPressureDelayMS - kBackPressureDelayReductionThresholdMS))) {
|
||||
(static_cast<uint32_t>(mBackPressureDelayMS) >
|
||||
(newBackPressureDelayMS + gBackPressureDelayReductionThresholdMS))) {
|
||||
int32_t oldBackPressureDelayMS = mBackPressureDelayMS;
|
||||
mBackPressureDelayMS = newBackPressureDelayMS;
|
||||
|
||||
|
@ -147,7 +147,6 @@ class ImageClient;
|
||||
class ImageCompositeNotification;
|
||||
class ImageContainer;
|
||||
class ImageContainerChild;
|
||||
class PImageContainerChild;
|
||||
class SharedPlanarYCbCrImage;
|
||||
class PlanarYCbCrImage;
|
||||
class TextureClient;
|
||||
@ -583,8 +582,6 @@ public:
|
||||
|
||||
void NotifyComposite(const ImageCompositeNotification& aNotification);
|
||||
|
||||
PImageContainerChild* GetPImageContainerChild();
|
||||
|
||||
ImageContainerListener* GetImageContainerListener()
|
||||
{
|
||||
return mNotifyCompositeListener;
|
||||
|
@ -32,7 +32,6 @@ namespace layers {
|
||||
class ClientPaintedLayer;
|
||||
class CompositorBridgeChild;
|
||||
class ImageLayer;
|
||||
class PLayerChild;
|
||||
class FrameUniformityData;
|
||||
|
||||
class ClientLayerManager final : public LayerManager
|
||||
@ -380,9 +379,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Create a shadow layer (PLayerChild) for aLayer, if we're forwarding
|
||||
// our layer tree to a parent process. Record the new layer creation
|
||||
// in the current open transaction as a side effect.
|
||||
// Create a LayerHandle for aLayer, if we're forwarding our layer tree
|
||||
// to a parent process. Record the new layer creation in the current
|
||||
// open transaction as a side effect.
|
||||
template<typename CreatedMethod> void
|
||||
CreateShadowFor(ClientLayer* aLayer,
|
||||
ClientLayerManager* aMgr,
|
||||
|
@ -25,7 +25,6 @@ class ImageBridgeChild;
|
||||
class ImageContainer;
|
||||
class CompositableForwarder;
|
||||
class CompositableChild;
|
||||
class PCompositableChild;
|
||||
class TextureClientRecycleAllocator;
|
||||
class ContentClientRemote;
|
||||
|
||||
|
@ -37,7 +37,6 @@ class EditReply;
|
||||
class FixedSizeSmallShmemSectionAllocator;
|
||||
class ImageContainer;
|
||||
class Layer;
|
||||
class PLayerChild;
|
||||
class PLayerTransactionChild;
|
||||
class LayerTransactionChild;
|
||||
class ShadowableLayer;
|
||||
|
@ -23,7 +23,6 @@ class VRDisplay;
|
||||
class VREventObserver;
|
||||
} // namespace dom
|
||||
namespace layers {
|
||||
class PCompositableChild;
|
||||
class TextureClient;
|
||||
}
|
||||
namespace gfx {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "vm/TypeInference-inl.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/SizePrintfMacros.h"
|
||||
@ -2606,6 +2607,20 @@ TypeZone::addPendingRecompile(JSContext* cx, JSScript* script)
|
||||
ObjectStateChange(cx, script->functionNonDelazifying()->group(), false);
|
||||
}
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
static char sCrashReason[256];
|
||||
|
||||
MOZ_NORETURN MOZ_COLD MOZ_NEVER_INLINE void
|
||||
js::ReportMagicWordFailure(uintptr_t actual, uintptr_t expected)
|
||||
{
|
||||
SprintfLiteral(sCrashReason,
|
||||
"MOZ_CRASH(Got 0x%" PRIxPTR " expected magic word 0x%" PRIxPTR ")",
|
||||
actual, expected);
|
||||
MOZ_CRASH_ANNOTATE(sCrashReason);
|
||||
MOZ_REALLY_CRASH();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
js::PrintTypes(JSContext* cx, JSCompartment* comp, bool force)
|
||||
{
|
||||
|
@ -543,6 +543,11 @@ static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4c5c6d7d8;
|
||||
static const uintptr_t TypeConstraintMagic = BaseTypeInferenceMagic + 1;
|
||||
static const uintptr_t ConstraintTypeSetMagic = BaseTypeInferenceMagic + 2;
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
extern MOZ_NORETURN MOZ_COLD MOZ_NEVER_INLINE void
|
||||
ReportMagicWordFailure(uintptr_t actual, uintptr_t expected);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A constraint which listens to additions to a type set and propagates those
|
||||
* changes to other type sets.
|
||||
@ -567,7 +572,8 @@ class TypeConstraint
|
||||
|
||||
void checkMagic() const {
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
MOZ_RELEASE_ASSERT(magic_ == TypeConstraintMagic);
|
||||
if (MOZ_UNLIKELY(magic_ != TypeConstraintMagic))
|
||||
ReportMagicWordFailure(magic_, TypeConstraintMagic);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -669,7 +675,8 @@ class ConstraintTypeSet : public TypeSet
|
||||
|
||||
void checkMagic() const {
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
MOZ_RELEASE_ASSERT(magic_ == ConstraintTypeSetMagic);
|
||||
if (MOZ_UNLIKELY(magic_ != ConstraintTypeSetMagic))
|
||||
ReportMagicWordFailure(magic_, ConstraintTypeSetMagic);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1717,7 +1717,7 @@ needs-focus != 703186-1.html 703186-2.html
|
||||
fuzzy-if(true,1,21) fuzzy-if(d2d,68,173) fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html # bug 773482
|
||||
== 720987.html 720987-ref.html
|
||||
== 722888-1.html 722888-1-ref.html
|
||||
== 722923-1.html 722923-1-ref.html
|
||||
fuzzy-if(Android,1,40000) == 722923-1.html 722923-1-ref.html
|
||||
== 723484-1.html 723484-1-ref.html
|
||||
random-if(Android) == 728983-1.html 728983-1-ref.html
|
||||
== 729143-1.html 729143-1-ref.html
|
||||
|
@ -3,7 +3,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import base64
|
||||
import copy
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
@ -545,7 +544,7 @@ class Marionette(object):
|
||||
|
||||
CONTEXT_CHROME = "chrome" # non-browser content: windows, dialogs, etc.
|
||||
CONTEXT_CONTENT = "content" # browser content: iframes, divs, etc.
|
||||
DEFAULT_SOCKET_TIMEOUT = 65
|
||||
DEFAULT_SOCKET_TIMEOUT = 60
|
||||
DEFAULT_STARTUP_TIMEOUT = 120
|
||||
DEFAULT_SHUTDOWN_TIMEOUT = 65 # Firefox will kill hanging threads after 60s
|
||||
|
||||
@ -1248,12 +1247,13 @@ class Marionette(object):
|
||||
return "{0}{1}".format(self.baseurl, relative_url)
|
||||
|
||||
@do_process_check
|
||||
def start_session(self, capabilities=None, session_id=None, timeout=60):
|
||||
def start_session(self, desired_capabilities=None, session_id=None, timeout=60):
|
||||
"""Create a new Marionette session.
|
||||
|
||||
This method must be called before performing any other action.
|
||||
|
||||
:param capabilities: An optional dict of desired or required capabilities.
|
||||
:param desired_capabilities: An optional dict of desired
|
||||
capabilities. This is currently ignored.
|
||||
:param timeout: Timeout in seconds for the server to be ready.
|
||||
:param session_id: unique identifier for the session. If no session id is
|
||||
passed in then one will be generated by the marionette server.
|
||||
@ -1279,25 +1279,7 @@ class Marionette(object):
|
||||
self.wait_for_port(timeout=timeout)
|
||||
self.protocol, _ = self.client.connect()
|
||||
|
||||
if capabilities is not None:
|
||||
caps = copy.deepcopy(capabilities)
|
||||
else:
|
||||
caps = {}
|
||||
|
||||
# Bug 1322277 - Override some default capabilities which are defined by
|
||||
# the Webdriver spec but which don't really apply to tests executed with
|
||||
# the Marionette client. Using "desiredCapabilities" here will allow tests
|
||||
# to override the settings via "desiredCapabilities" and requiredCapabilities".
|
||||
if "desiredCapabilities" not in caps:
|
||||
caps.update({
|
||||
"desiredCapabilities": {
|
||||
"timeouts": {
|
||||
"page load": 60000, # webdriver specifies 300000ms
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
body = {"capabilities": caps, "sessionId": session_id}
|
||||
body = {"capabilities": desired_capabilities, "sessionId": session_id}
|
||||
resp = self._send_message("newSession", body)
|
||||
|
||||
self.session_id = resp["sessionId"]
|
||||
|
@ -240,7 +240,7 @@ class MarionetteTextTestRunner(StructuredTestRunner):
|
||||
|
||||
|
||||
class BaseMarionetteArguments(ArgumentParser):
|
||||
socket_timeout_default = 65.0
|
||||
socket_timeout_default = 60.0
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
ArgumentParser.__init__(self, **kwargs)
|
||||
@ -347,8 +347,7 @@ class BaseMarionetteArguments(ArgumentParser):
|
||||
self.add_argument('--socket-timeout',
|
||||
type=float,
|
||||
default=self.socket_timeout_default,
|
||||
help='Set the global timeout for marionette socket operations.'
|
||||
' Default: %(default)ss.')
|
||||
help='Set the global timeout for marionette socket operations.')
|
||||
self.add_argument('--disable-e10s',
|
||||
action='store_false',
|
||||
dest='e10s',
|
||||
|
@ -11,14 +11,7 @@ class TestCapabilities(MarionetteTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCapabilities, self).setUp()
|
||||
|
||||
# Force default webdriver capabilities by default to test
|
||||
# Marionette server.
|
||||
self.marionette.delete_session()
|
||||
self.marionette.start_session({"desiredCapabilities": {}})
|
||||
|
||||
self.caps = self.marionette.session_capabilities
|
||||
|
||||
with self.marionette.using_context("chrome"):
|
||||
self.appinfo = self.marionette.execute_script(
|
||||
"return Services.appinfo")
|
||||
@ -40,8 +33,10 @@ class TestCapabilities(MarionetteTestCase):
|
||||
self.assertEqual(self.caps["platformName"], self.os_name)
|
||||
self.assertEqual(self.caps["platformVersion"], self.os_version)
|
||||
self.assertFalse(self.caps["acceptInsecureCerts"])
|
||||
self.assertEqual(self.caps["timeouts"],
|
||||
{"implicit": 0, "page load": 300000, "script": 30000})
|
||||
self.assertDictEqual(self.caps["timeouts"],
|
||||
{"implicit": 0,
|
||||
"page load": 300000,
|
||||
"script": 30000})
|
||||
|
||||
def test_supported_features(self):
|
||||
self.assertIn("rotatable", self.caps)
|
||||
@ -65,14 +60,6 @@ class TestCapabilities(MarionetteTestCase):
|
||||
self.assertIn("specificationLevel", self.caps)
|
||||
self.assertEqual(self.caps["specificationLevel"], 0)
|
||||
|
||||
def test_default_client_capabilities(self):
|
||||
self.marionette.delete_session()
|
||||
self.marionette.start_session()
|
||||
caps = self.marionette.session_capabilities
|
||||
|
||||
self.assertEqual(caps["timeouts"],
|
||||
{"implicit": 0, "page load": 60000, "script": 30000})
|
||||
|
||||
def test_set_specification_level(self):
|
||||
self.marionette.delete_session()
|
||||
self.marionette.start_session({"desiredCapabilities": {"specificationLevel": 2}})
|
||||
@ -135,8 +122,7 @@ class TestCapabilityMatching(MarionetteTestCase):
|
||||
for typ in self.allowed:
|
||||
self.marionette.delete_session()
|
||||
self.marionette.start_session({"desiredCapabilities": {"browserName": typ}})
|
||||
self.assertEqual(self.marionette.session_capabilities["browserName"],
|
||||
self.browser_name)
|
||||
self.assertEqual(self.marionette.session_capabilities["browserName"], self.browser_name)
|
||||
|
||||
def test_browser_name_desired_disallowed_types(self):
|
||||
for typ in self.disallowed:
|
||||
@ -147,8 +133,7 @@ class TestCapabilityMatching(MarionetteTestCase):
|
||||
for typ in self.allowed:
|
||||
self.marionette.delete_session()
|
||||
self.marionette.start_session({"requiredCapabilities": {"browserName": typ}})
|
||||
self.assertEqual(self.marionette.session_capabilities["browserName"],
|
||||
self.browser_name)
|
||||
self.assertEqual(self.marionette.session_capabilities["browserName"], self.browser_name)
|
||||
|
||||
def test_browser_name_requried_disallowed_types(self):
|
||||
for typ in self.disallowed:
|
||||
@ -157,33 +142,30 @@ class TestCapabilityMatching(MarionetteTestCase):
|
||||
|
||||
def test_browser_name_prefers_required(self):
|
||||
caps = {"desiredCapabilities": {"browserName": "invalid"},
|
||||
"requiredCapabilities": {"browserName": "*"}}
|
||||
"requiredCapabilities": {"browserName": "*"}}
|
||||
self.marionette.start_session(caps)
|
||||
|
||||
def test_browser_name_error_on_invalid_required(self):
|
||||
with self.assertRaises(SessionNotCreatedException):
|
||||
caps = {"desiredCapabilities": {"browserName": "*"},
|
||||
"requiredCapabilities": {"browserName": "invalid"}}
|
||||
"requiredCapabilities": {"browserName": "invalid"}}
|
||||
self.marionette.start_session(caps)
|
||||
|
||||
# TODO(ato): browser version comparison not implemented yet
|
||||
|
||||
def test_platform_name_desired(self):
|
||||
self.marionette.start_session(
|
||||
{"desiredCapabilities": {"platformName": self.platform_name}})
|
||||
self.marionette.start_session({"desiredCapabilities": {"platformName": self.platform_name}})
|
||||
self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
|
||||
|
||||
def test_platform_name_required(self):
|
||||
self.marionette.start_session(
|
||||
{"requiredCapabilities": {"platformName": self.platform_name}})
|
||||
self.marionette.start_session({"requiredCapabilities": {"platformName": self.platform_name}})
|
||||
self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
|
||||
|
||||
def test_platform_name_desired_allowed_types(self):
|
||||
for typ in self.allowed:
|
||||
self.marionette.delete_session()
|
||||
self.marionette.start_session({"desiredCapabilities": {"platformName": typ}})
|
||||
self.assertEqual(self.marionette.session_capabilities["platformName"],
|
||||
self.platform_name)
|
||||
self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
|
||||
|
||||
def test_platform_name_desired_disallowed_types(self):
|
||||
for typ in self.disallowed:
|
||||
@ -194,8 +176,7 @@ class TestCapabilityMatching(MarionetteTestCase):
|
||||
for typ in self.allowed:
|
||||
self.marionette.delete_session()
|
||||
self.marionette.start_session({"requiredCapabilities": {"platformName": typ}})
|
||||
self.assertEqual(self.marionette.session_capabilities["platformName"],
|
||||
self.platform_name)
|
||||
self.assertEqual(self.marionette.session_capabilities["platformName"], self.platform_name)
|
||||
|
||||
def test_platform_name_requried_disallowed_types(self):
|
||||
for typ in self.disallowed:
|
||||
@ -204,13 +185,13 @@ class TestCapabilityMatching(MarionetteTestCase):
|
||||
|
||||
def test_platform_name_prefers_required(self):
|
||||
caps = {"desiredCapabilities": {"platformName": "invalid"},
|
||||
"requiredCapabilities": {"platformName": "*"}}
|
||||
"requiredCapabilities": {"platformName": "*"}}
|
||||
self.marionette.start_session(caps)
|
||||
|
||||
def test_platform_name_error_on_invalid_required(self):
|
||||
with self.assertRaises(SessionNotCreatedException):
|
||||
caps = {"desiredCapabilities": {"platformName": "*"},
|
||||
"requiredCapabilities": {"platformName": "invalid"}}
|
||||
"requiredCapabilities": {"platformName": "invalid"}}
|
||||
self.marionette.start_session(caps)
|
||||
|
||||
# TODO(ato): platform version comparison not imlpemented yet
|
||||
@ -221,8 +202,7 @@ class TestCapabilityMatching(MarionetteTestCase):
|
||||
for value in ["", 42, {}, []]:
|
||||
print(" type {}".format(type(value)))
|
||||
with self.assertRaises(SessionNotCreatedException):
|
||||
self.marionette.start_session(
|
||||
{capability_type: {"acceptInsecureCerts": value}})
|
||||
self.marionette.start_session({capability_type: {"acceptInsecureCerts": value}})
|
||||
|
||||
self.marionette.delete_session()
|
||||
self.marionette.start_session({"desiredCapabilities": {"acceptInsecureCerts": True}})
|
||||
@ -261,9 +241,9 @@ class TestCapabilityMatching(MarionetteTestCase):
|
||||
self.assertEqual(self.marionette.get_pref("network.proxy.type"), 1)
|
||||
|
||||
def test_timeouts(self):
|
||||
timeouts = {"implicit": 123, "page load": 456, "script": 789}
|
||||
timeouts = {u"implicit": 123, u"page load": 456, u"script": 789}
|
||||
caps = {"desiredCapabilities": {"timeouts": timeouts}}
|
||||
self.marionette.start_session(caps)
|
||||
self.assertIn("timeouts", self.marionette.session_capabilities)
|
||||
self.assertEqual(self.marionette.session_capabilities["timeouts"], timeouts)
|
||||
self.assertEqual(self.marionette._send_message("getTimeouts"), timeouts)
|
||||
self.assertDictEqual(self.marionette.session_capabilities["timeouts"], timeouts)
|
||||
self.assertDictEqual(self.marionette._send_message("getTimeouts"), timeouts)
|
||||
|
@ -1,5 +1,6 @@
|
||||
[idlharness.html]
|
||||
type: testharness
|
||||
prefs: [dom.vr.enabled:true]
|
||||
[Window interface: attribute onvrdisplayblur]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -199,7 +199,7 @@ hasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature)
|
||||
}
|
||||
|
||||
std::vector<ThreadInfo*>* Sampler::sRegisteredThreads = nullptr;
|
||||
mozilla::UniquePtr<mozilla::Mutex> Sampler::sRegisteredThreadsMutex;
|
||||
StaticMutex Sampler::sRegisteredThreadsMutex;
|
||||
|
||||
Sampler::Sampler(double aInterval, int aEntrySize,
|
||||
const char** aFeatures, uint32_t aFeatureCount,
|
||||
@ -251,7 +251,7 @@ Sampler::Sampler(double aInterval, int aEntrySize,
|
||||
sStartTime = mozilla::TimeStamp::ProcessCreation(ignore);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
// Set up profiling for each registered thread, if appropriate
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
@ -279,7 +279,7 @@ Sampler::~Sampler()
|
||||
|
||||
// Destroy ThreadInfo for all threads
|
||||
{
|
||||
MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = sRegisteredThreads->at(i);
|
||||
@ -307,8 +307,9 @@ Sampler::~Sampler()
|
||||
void
|
||||
Sampler::Startup()
|
||||
{
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
sRegisteredThreads = new std::vector<ThreadInfo*>();
|
||||
sRegisteredThreadsMutex = MakeUnique<Mutex>("sRegisteredThreadsMutex");
|
||||
|
||||
// We could create the sLUL object and read unwind info into it at
|
||||
// this point. That would match the lifetime implied by destruction
|
||||
@ -321,17 +322,16 @@ Sampler::Startup()
|
||||
void
|
||||
Sampler::Shutdown()
|
||||
{
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
while (sRegisteredThreads->size() > 0) {
|
||||
delete sRegisteredThreads->back();
|
||||
sRegisteredThreads->pop_back();
|
||||
}
|
||||
|
||||
sRegisteredThreadsMutex = nullptr;
|
||||
delete sRegisteredThreads;
|
||||
|
||||
// UnregisterThread can be called after shutdown in XPCShell. Thus
|
||||
// we need to point to null to ignore such a call after shutdown.
|
||||
sRegisteredThreadsMutex = nullptr;
|
||||
delete sRegisteredThreads;
|
||||
sRegisteredThreads = nullptr;
|
||||
|
||||
#if defined(USE_LUL_STACKWALK)
|
||||
@ -348,12 +348,12 @@ Sampler::RegisterCurrentThread(const char* aName,
|
||||
PseudoStack* aPseudoStack,
|
||||
bool aIsMainThread, void* stackTop)
|
||||
{
|
||||
if (!sRegisteredThreadsMutex) {
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
if (!sRegisteredThreads) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
Thread::tid_t id = Thread::GetCurrentId();
|
||||
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
@ -382,12 +382,12 @@ Sampler::RegisterCurrentThread(const char* aName,
|
||||
void
|
||||
Sampler::UnregisterCurrentThread()
|
||||
{
|
||||
if (!sRegisteredThreadsMutex) {
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
if (!sRegisteredThreads) {
|
||||
return;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
Thread::tid_t id = Thread::GetCurrentId();
|
||||
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
@ -426,11 +426,14 @@ Sampler::StreamTaskTracer(SpliceableJSONWriter& aWriter)
|
||||
aWriter.EndArray();
|
||||
|
||||
aWriter.StartArrayProperty("threads");
|
||||
MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
{
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
// Thread meta data
|
||||
ThreadInfo* info = sRegisteredThreads->at(i);
|
||||
aWriter.StartObjectElement();
|
||||
{
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Plugin) {
|
||||
// TODO Add the proper plugin name
|
||||
aWriter.StringProperty("name", "Plugin");
|
||||
@ -438,8 +441,10 @@ Sampler::StreamTaskTracer(SpliceableJSONWriter& aWriter)
|
||||
aWriter.StringProperty("name", info->Name());
|
||||
}
|
||||
aWriter.IntProperty("tid", static_cast<int>(info->ThreadId()));
|
||||
}
|
||||
aWriter.EndObject();
|
||||
}
|
||||
}
|
||||
aWriter.EndArray();
|
||||
|
||||
aWriter.DoubleProperty("start", static_cast<double>(mozilla::tasktracer::GetStartTime()));
|
||||
@ -665,7 +670,7 @@ Sampler::StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime)
|
||||
SetPaused(true);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
// Thread not being profiled, skip it
|
||||
@ -721,7 +726,7 @@ Sampler::FlushOnJSShutdown(JSContext* aContext)
|
||||
SetPaused(true);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
StaticMutexAutoLock lock(sRegisteredThreadsMutex);
|
||||
|
||||
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
// Thread not being profiled, skip it.
|
||||
|
@ -161,19 +161,6 @@ static void* setup_atfork() {
|
||||
}
|
||||
#endif /* !defined(ANDROID) */
|
||||
|
||||
struct SamplerRegistry {
|
||||
static void AddActiveSampler(Sampler *sampler) {
|
||||
MOZ_ASSERT(!SamplerRegistry::sampler);
|
||||
SamplerRegistry::sampler = sampler;
|
||||
}
|
||||
static void RemoveActiveSampler(Sampler *sampler) {
|
||||
SamplerRegistry::sampler = NULL;
|
||||
}
|
||||
static Sampler *sampler;
|
||||
};
|
||||
|
||||
Sampler *SamplerRegistry::sampler = NULL;
|
||||
|
||||
static mozilla::Atomic<ThreadInfo*> sCurrentThreadInfo;
|
||||
static sem_t sSignalHandlingDone;
|
||||
|
||||
@ -304,18 +291,16 @@ static void* SignalSender(void* arg) {
|
||||
|
||||
TimeDuration lastSleepOverhead = 0;
|
||||
TimeStamp sampleStart = TimeStamp::Now();
|
||||
while (SamplerRegistry::sampler->IsActive()) {
|
||||
// XXX: this loop is an off-main-thread use of gSampler
|
||||
while (gSampler->IsActive()) {
|
||||
gSampler->DeleteExpiredMarkers();
|
||||
|
||||
SamplerRegistry::sampler->DeleteExpiredMarkers();
|
||||
|
||||
if (!SamplerRegistry::sampler->IsPaused()) {
|
||||
MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
|
||||
const std::vector<ThreadInfo*>& threads =
|
||||
SamplerRegistry::sampler->GetRegisteredThreads();
|
||||
if (!gSampler->IsPaused()) {
|
||||
StaticMutexAutoLock lock(Sampler::sRegisteredThreadsMutex);
|
||||
|
||||
bool isFirstProfiledThread = true;
|
||||
for (uint32_t i = 0; i < threads.size(); i++) {
|
||||
ThreadInfo* info = threads[i];
|
||||
for (uint32_t i = 0; i < Sampler::sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = (*Sampler::sRegisteredThreads)[i];
|
||||
|
||||
// This will be null if we're not interested in profiling this thread.
|
||||
if (!info->hasProfile() || info->IsPendingDelete()) {
|
||||
@ -371,7 +356,8 @@ static void* SignalSender(void* arg) {
|
||||
}
|
||||
}
|
||||
|
||||
TimeStamp targetSleepEndTime = sampleStart + TimeDuration::FromMicroseconds(SamplerRegistry::sampler->interval() * 1000);
|
||||
TimeStamp targetSleepEndTime =
|
||||
sampleStart + TimeDuration::FromMicroseconds(gSampler->interval() * 1000);
|
||||
TimeStamp beforeSleep = TimeStamp::Now();
|
||||
TimeDuration targetSleepDuration = targetSleepEndTime - beforeSleep;
|
||||
double sleepTime = std::max(0.0, (targetSleepDuration - lastSleepOverhead).ToMicroseconds());
|
||||
@ -395,8 +381,6 @@ void Sampler::Start() {
|
||||
}
|
||||
#endif
|
||||
|
||||
SamplerRegistry::AddActiveSampler(this);
|
||||
|
||||
// Initialize signal handler communication
|
||||
sCurrentThreadInfo = nullptr;
|
||||
if (sem_init(&sSignalHandlingDone, /* pshared: */ 0, /* value: */ 0) != 0) {
|
||||
@ -452,8 +436,6 @@ void Sampler::Stop() {
|
||||
signal_sender_launched_ = false;
|
||||
}
|
||||
|
||||
SamplerRegistry::RemoveActiveSampler(this);
|
||||
|
||||
// Restore old signal handler
|
||||
if (signal_handler_installed_) {
|
||||
sigaction(SIGPROF, &old_sigprof_signal_handler_, 0);
|
||||
|
@ -43,21 +43,6 @@ using mozilla::TimeDuration;
|
||||
|
||||
// this port is based off of v8 svn revision 9837
|
||||
|
||||
// XXX: this is a very stubbed out implementation
|
||||
// that only supports a single Sampler
|
||||
struct SamplerRegistry {
|
||||
static void AddActiveSampler(Sampler *sampler) {
|
||||
MOZ_ASSERT(!SamplerRegistry::sampler);
|
||||
SamplerRegistry::sampler = sampler;
|
||||
}
|
||||
static void RemoveActiveSampler(Sampler *sampler) {
|
||||
SamplerRegistry::sampler = NULL;
|
||||
}
|
||||
static Sampler *sampler;
|
||||
};
|
||||
|
||||
Sampler *SamplerRegistry::sampler = NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
// 0 is never a valid thread id on MacOSX since a pthread_t is a pointer.
|
||||
static const pthread_t kNoThread = (pthread_t) 0;
|
||||
@ -153,19 +138,17 @@ public:
|
||||
pthread_join(mThread, NULL);
|
||||
}
|
||||
|
||||
static void AddActiveSampler(Sampler* sampler) {
|
||||
SamplerRegistry::AddActiveSampler(sampler);
|
||||
static void AddActiveSampler() {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mInstance == NULL) {
|
||||
mInstance = new SamplerThread(sampler->interval());
|
||||
mInstance = new SamplerThread(gSampler->interval());
|
||||
mInstance->Start();
|
||||
}
|
||||
}
|
||||
|
||||
static void RemoveActiveSampler(Sampler* sampler) {
|
||||
static void RemoveActiveSampler() {
|
||||
mInstance->Join();
|
||||
//XXX: unlike v8 we need to remove the active sampler after doing the Join
|
||||
// because we drop the sampler immediately
|
||||
SamplerRegistry::RemoveActiveSampler(sampler);
|
||||
delete mInstance;
|
||||
mInstance = NULL;
|
||||
}
|
||||
@ -173,15 +156,17 @@ public:
|
||||
void Run() {
|
||||
TimeDuration lastSleepOverhead = 0;
|
||||
TimeStamp sampleStart = TimeStamp::Now();
|
||||
while (SamplerRegistry::sampler->IsActive()) {
|
||||
SamplerRegistry::sampler->DeleteExpiredMarkers();
|
||||
if (!SamplerRegistry::sampler->IsPaused()) {
|
||||
MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
|
||||
const std::vector<ThreadInfo*>& threads =
|
||||
SamplerRegistry::sampler->GetRegisteredThreads();
|
||||
|
||||
// XXX: this loop is an off-main-thread use of gSampler
|
||||
while (gSampler->IsActive()) {
|
||||
gSampler->DeleteExpiredMarkers();
|
||||
|
||||
if (!gSampler->IsPaused()) {
|
||||
StaticMutexAutoLock lock(Sampler::sRegisteredThreadsMutex);
|
||||
|
||||
bool isFirstProfiledThread = true;
|
||||
for (uint32_t i = 0; i < threads.size(); i++) {
|
||||
ThreadInfo* info = threads[i];
|
||||
for (uint32_t i = 0; i < Sampler::sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = (*Sampler::sRegisteredThreads)[i];
|
||||
|
||||
// This will be null if we're not interested in profiling this thread.
|
||||
if (!info->hasProfile() || info->IsPendingDelete()) {
|
||||
@ -196,7 +181,7 @@ public:
|
||||
|
||||
info->UpdateThreadResponsiveness();
|
||||
|
||||
SampleContext(SamplerRegistry::sampler, info, isFirstProfiledThread);
|
||||
SampleContext(info, isFirstProfiledThread);
|
||||
isFirstProfiledThread = false;
|
||||
}
|
||||
}
|
||||
@ -211,8 +196,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SampleContext(Sampler* sampler, ThreadInfo* aThreadInfo,
|
||||
bool isFirstProfiledThread)
|
||||
void SampleContext(ThreadInfo* aThreadInfo, bool isFirstProfiledThread)
|
||||
{
|
||||
thread_act_t profiled_thread =
|
||||
aThreadInfo->GetPlatformData()->profiled_thread();
|
||||
@ -267,7 +251,8 @@ public:
|
||||
sample->timestamp = mozilla::TimeStamp::Now();
|
||||
sample->threadInfo = aThreadInfo;
|
||||
|
||||
sampler->Tick(sample);
|
||||
// XXX: this is an off-main-thread use of gSampler
|
||||
gSampler->Tick(sample);
|
||||
}
|
||||
thread_resume(profiled_thread);
|
||||
}
|
||||
@ -289,13 +274,13 @@ SamplerThread* SamplerThread::mInstance = NULL;
|
||||
void Sampler::Start() {
|
||||
MOZ_ASSERT(!IsActive());
|
||||
SetActive(true);
|
||||
SamplerThread::AddActiveSampler(this);
|
||||
SamplerThread::AddActiveSampler();
|
||||
}
|
||||
|
||||
void Sampler::Stop() {
|
||||
MOZ_ASSERT(IsActive());
|
||||
SetActive(false);
|
||||
SamplerThread::RemoveActiveSampler(this);
|
||||
SamplerThread::RemoveActiveSampler();
|
||||
}
|
||||
|
||||
/* static */ Thread::tid_t
|
||||
|
@ -96,10 +96,9 @@ class SamplerThread
|
||||
public:
|
||||
// Initialize a Win32 thread object. The thread has an invalid thread
|
||||
// handle until it is started.
|
||||
SamplerThread(double interval, Sampler* sampler)
|
||||
explicit SamplerThread(double interval)
|
||||
: mStackSize(0)
|
||||
, mThread(kNoThread)
|
||||
, mSampler(sampler)
|
||||
, mInterval(interval)
|
||||
{
|
||||
mInterval = floor(interval + 0.5);
|
||||
@ -140,12 +139,14 @@ class SamplerThread
|
||||
}
|
||||
}
|
||||
|
||||
static void StartSampler(Sampler* sampler) {
|
||||
static void StartSampler() {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mInstance == NULL) {
|
||||
mInstance = new SamplerThread(sampler->interval(), sampler);
|
||||
mInstance = new SamplerThread(gSampler->interval());
|
||||
mInstance->Start();
|
||||
} else {
|
||||
MOZ_ASSERT(mInstance->mInterval == sampler->interval());
|
||||
MOZ_ASSERT(mInstance->mInterval == gSampler->interval());
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,16 +163,16 @@ class SamplerThread
|
||||
if (mInterval < 10)
|
||||
::timeBeginPeriod(mInterval);
|
||||
|
||||
while (mSampler->IsActive()) {
|
||||
mSampler->DeleteExpiredMarkers();
|
||||
// XXX: this loop is an off-main-thread use of gSampler
|
||||
while (gSampler->IsActive()) {
|
||||
gSampler->DeleteExpiredMarkers();
|
||||
|
||||
if (!gSampler->IsPaused()) {
|
||||
mozilla::StaticMutexAutoLock lock(Sampler::sRegisteredThreadsMutex);
|
||||
|
||||
if (!mSampler->IsPaused()) {
|
||||
mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
|
||||
const std::vector<ThreadInfo*>& threads =
|
||||
mSampler->GetRegisteredThreads();
|
||||
bool isFirstProfiledThread = true;
|
||||
for (uint32_t i = 0; i < threads.size(); i++) {
|
||||
ThreadInfo* info = threads[i];
|
||||
for (uint32_t i = 0; i < Sampler::sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = (*Sampler::sRegisteredThreads)[i];
|
||||
|
||||
// This will be null if we're not interested in profiling this thread.
|
||||
if (!info->hasProfile() || info->IsPendingDelete()) {
|
||||
@ -186,7 +187,7 @@ class SamplerThread
|
||||
|
||||
info->UpdateThreadResponsiveness();
|
||||
|
||||
SampleContext(mSampler, info, isFirstProfiledThread);
|
||||
SampleContext(info, isFirstProfiledThread);
|
||||
isFirstProfiledThread = false;
|
||||
}
|
||||
}
|
||||
@ -198,8 +199,7 @@ class SamplerThread
|
||||
::timeEndPeriod(mInterval);
|
||||
}
|
||||
|
||||
void SampleContext(Sampler* sampler, ThreadInfo* aThreadInfo,
|
||||
bool isFirstProfiledThread)
|
||||
void SampleContext(ThreadInfo* aThreadInfo, bool isFirstProfiledThread)
|
||||
{
|
||||
uintptr_t thread = Sampler::GetThreadHandle(aThreadInfo->GetPlatformData());
|
||||
HANDLE profiled_thread = reinterpret_cast<HANDLE>(thread);
|
||||
@ -281,7 +281,9 @@ class SamplerThread
|
||||
#endif
|
||||
|
||||
sample->context = &context;
|
||||
sampler->Tick(sample);
|
||||
|
||||
// XXX: this is an off-main-thread use of gSampler
|
||||
gSampler->Tick(sample);
|
||||
|
||||
ResumeThread(profiled_thread);
|
||||
}
|
||||
@ -291,7 +293,6 @@ private:
|
||||
HANDLE mThread;
|
||||
Thread::tid_t mThreadId;
|
||||
|
||||
Sampler* mSampler;
|
||||
int mInterval; // units: ms
|
||||
|
||||
// Protects the process wide state below.
|
||||
@ -305,7 +306,7 @@ SamplerThread* SamplerThread::mInstance = NULL;
|
||||
void Sampler::Start() {
|
||||
MOZ_ASSERT(!IsActive());
|
||||
SetActive(true);
|
||||
SamplerThread::StartSampler(this);
|
||||
SamplerThread::StartSampler();
|
||||
}
|
||||
|
||||
void Sampler::Stop() {
|
||||
|
@ -744,11 +744,10 @@ profiler_start(int aProfileEntries, double aInterval,
|
||||
|
||||
gSampler->Start();
|
||||
if (gSampler->ProfileJS() || gSampler->InPrivacyMode()) {
|
||||
mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
|
||||
const std::vector<ThreadInfo*>& threads = gSampler->GetRegisteredThreads();
|
||||
mozilla::StaticMutexAutoLock lock(Sampler::sRegisteredThreadsMutex);
|
||||
|
||||
for (uint32_t i = 0; i < threads.size(); i++) {
|
||||
ThreadInfo* info = threads[i];
|
||||
for (uint32_t i = 0; i < Sampler::sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = (*Sampler::sRegisteredThreads)[i];
|
||||
if (info->IsPendingDelete() || !info->hasProfile()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "ThreadResponsiveness.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
@ -297,10 +297,6 @@ public:
|
||||
static uintptr_t GetThreadHandle(PlatformData*);
|
||||
#endif
|
||||
|
||||
static const std::vector<ThreadInfo*>& GetRegisteredThreads() {
|
||||
return *sRegisteredThreads;
|
||||
}
|
||||
|
||||
static bool RegisterCurrentThread(const char* aName,
|
||||
PseudoStack* aPseudoStack,
|
||||
bool aIsMainThread, void* stackTop);
|
||||
@ -310,7 +306,8 @@ public:
|
||||
// Should only be called on shutdown
|
||||
static void Shutdown();
|
||||
|
||||
static mozilla::UniquePtr<mozilla::Mutex> sRegisteredThreadsMutex;
|
||||
static mozilla::StaticMutex sRegisteredThreadsMutex;
|
||||
static std::vector<ThreadInfo*>* sRegisteredThreads;
|
||||
|
||||
static bool CanNotifyObservers() {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
@ -365,8 +362,6 @@ private:
|
||||
|
||||
void SetActive(bool value) { NoBarrier_Store(&active_, value); }
|
||||
|
||||
static std::vector<ThreadInfo*>* sRegisteredThreads;
|
||||
|
||||
const double interval_;
|
||||
Atomic32 paused_;
|
||||
Atomic32 active_;
|
||||
|
Loading…
Reference in New Issue
Block a user