Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
The Tor Project
Applications
Tor Browser
Commits
31eced36
Commit
31eced36
authored
Aug 23, 2019
by
Csoregi Natalia
Browse files
Merge mozilla-central to autoland. CLOSED TREE
parents
41dfa283
4cb4d652
Changes
17
Hide whitespace changes
Inline
Side-by-side
devtools/client/performance-new/components/Settings.js
View file @
31eced36
...
...
@@ -181,6 +181,11 @@ const featureCheckboxes = [
value
:
"
jstracer
"
,
title
:
"
Trace JS engine (Experimental, requires custom build.)
"
,
},
{
name
:
"
Preference Read
"
,
value
:
"
preferencereads
"
,
title
:
"
Track Preference Reads
"
,
},
];
/**
...
...
devtools/client/performance-new/popup/background.jsm
View file @
31eced36
...
...
@@ -245,6 +245,7 @@ function intializeState() {
tasktracer
:
false
,
trackopts
:
false
,
jstracer
:
false
,
preferencereads
:
false
,
jsallocations
:
false
,
};
...
...
devtools/client/performance-new/popup/popup.html
View file @
31eced36
...
...
@@ -168,7 +168,12 @@
id=
"perf-settings-feature-checkbox-jsallocations"
type=
"checkbox"
value=
"jsallocations"
/>
<div
class=
"perf-settings-feature-name"
>
JS Allocations
</div>
<div
class=
"perf-settings-feature-title"
>
Track JavaScript allocations (Experimental.)
</div>
</label><label
class=
"perf-settings-checkbox-label perf-settings-feature-label"
><input
class=
"perf-settings-checkbox"
id=
"perf-settings-feature-checkbox-preferencereads"
type=
"checkbox"
value=
"preferencereads"
/>
<div
class=
"perf-settings-feature-name"
>
Preference Reads
</div>
<div
class=
"perf-settings-feature-title"
>
Track Preference Reads
</div>
</label>
</div>
</div>
</section>
...
...
devtools/client/performance-new/popup/popup.js
View file @
31eced36
...
...
@@ -33,6 +33,7 @@ const features = [
"
tasktracer
"
,
"
jstracer
"
,
"
jsallocations
"
,
"
preferencereads
"
,
"
trackopts
"
,
];
const
threadPrefix
=
"
perf-settings-thread-checkbox-
"
;
...
...
devtools/client/themes/rules.css
View file @
31eced36
...
...
@@ -398,7 +398,7 @@
margin-left
:
-6px
;
}
.ruleview-
expander.theme-twisty
:dir
(
rtl
)
:not
([
open
])
{
.ruleview-
propertycontainer
.ruleview-expander
:dir
(
rtl
)
:not
([
open
])
{
/* for preventing .theme-twisty's wrong direction in rtl; Bug 1296648 */
transform
:
rotate
(
-90deg
);
}
...
...
devtools/server/tests/unit/test_extension_storage_actor.js
View file @
31eced36
...
...
@@ -246,26 +246,35 @@ add_task(async function test_extension_store_exists() {
await
shutdown
(
extension
,
target
);
});
add_task
(
async
function
test_extension_origin_matches_debugger_target
()
{
async
function
background
()
{
browser
.
test
.
sendMessage
(
"
extension-origin
"
,
window
.
location
.
origin
);
}
add_task
(
{
// This test currently fails if the extension runs in the main process
// like in Thunderbird (see bug 1575183 comment #15 for details).
skip_if
:
()
=>
!
WebExtensionPolicy
.
useRemoteWebExtensions
,
},
async
function
test_extension_origin_matches_debugger_target
()
{
async
function
background
()
{
browser
.
test
.
sendMessage
(
"
extension-origin
"
,
window
.
location
.
origin
);
}
const
extension
=
await
startupExtension
(
getExtensionConfig
({
background
}));
const
extension
=
await
startupExtension
(
getExtensionConfig
({
background
})
);
const
{
target
,
extensionStorage
}
=
await
openAddonStoragePanel
(
extension
.
id
);
const
{
target
,
extensionStorage
}
=
await
openAddonStoragePanel
(
extension
.
id
);
const
{
hosts
}
=
extensionStorage
;
const
expectedHost
=
await
extension
.
awaitMessage
(
"
extension-origin
"
);
ok
(
expectedHost
in
hosts
,
"
Should have the expected extension host in the extensionStorage store
"
);
const
{
hosts
}
=
extensionStorage
;
const
expectedHost
=
await
extension
.
awaitMessage
(
"
extension-origin
"
);
ok
(
expectedHost
in
hosts
,
"
Should have the expected extension host in the extensionStorage store
"
);
await
shutdown
(
extension
,
target
);
});
await
shutdown
(
extension
,
target
);
}
);
/**
* Test case: Background page modifies items while storage panel is open.
...
...
@@ -843,19 +852,26 @@ add_task(
* storage actor. Since this pref is set at the beginning of the file, it
* already will be cleared via registerCleanupFunction when the test finishes.
*/
add_task
(
async
function
test_extensionStorage_store_disabled_on_pref
()
{
Services
.
prefs
.
setBoolPref
(
EXTENSION_STORAGE_ENABLED_PREF
,
false
);
add_task
(
{
// This test fails if the extension runs in the main process
// like in Thunderbird (see bug 1575183 comment #15 for details).
skip_if
:
()
=>
!
WebExtensionPolicy
.
useRemoteWebExtensions
,
},
async
function
test_extensionStorage_store_disabled_on_pref
()
{
Services
.
prefs
.
setBoolPref
(
EXTENSION_STORAGE_ENABLED_PREF
,
false
);
const
extension
=
await
startupExtension
(
getExtensionConfig
());
const
extension
=
await
startupExtension
(
getExtensionConfig
());
const
{
target
,
extensionStorage
}
=
await
openAddonStoragePanel
(
extension
.
id
);
const
{
target
,
extensionStorage
}
=
await
openAddonStoragePanel
(
extension
.
id
);
ok
(
extensionStorage
===
null
,
"
Should not have an extensionStorage store when pref disabled
"
);
ok
(
extensionStorage
===
null
,
"
Should not have an extensionStorage store when pref disabled
"
);
await
shutdown
(
extension
,
target
);
});
await
shutdown
(
extension
,
target
);
}
);
js/public/ProfilingCategory.h
View file @
31eced36
...
...
@@ -35,6 +35,7 @@
SUBCATEGORY(IDLE, IDLE, "Other") \
END_CATEGORY \
BEGIN_CATEGORY(OTHER, "Other", "grey") \
SUBCATEGORY(OTHER, OTHER_PreferenceRead, "Preference Read") \
SUBCATEGORY(OTHER, OTHER, "Other") \
END_CATEGORY \
BEGIN_CATEGORY(LAYOUT, "Layout", "purple") \
...
...
modules/libpref/Preferences.cpp
View file @
31eced36
...
...
@@ -14,6 +14,7 @@
#include
"base/basictypes.h"
#include
"GeckoProfiler.h"
#include
"ProfilerMarkerPayload.h"
#include
"MainThreadUtils.h"
#include
"mozilla/ArenaAllocatorExtensions.h"
#include
"mozilla/ArenaAllocator.h"
...
...
@@ -4324,6 +4325,22 @@ static nsresult pref_ReadDefaultPrefs(const RefPtr<nsZipArchive> jarReader,
return
NS_OK
;
}
static
void
PrefValueToString
(
const
bool
*
b
,
nsCString
&
value
)
{
value
=
nsCString
(
*
b
?
"true"
:
"false"
);
}
static
void
PrefValueToString
(
const
int
*
i
,
nsCString
&
value
)
{
value
=
nsPrintfCString
(
"%d"
,
*
i
);
}
static
void
PrefValueToString
(
const
uint32_t
*
u
,
nsCString
&
value
)
{
value
=
nsPrintfCString
(
"%d"
,
*
u
);
}
static
void
PrefValueToString
(
const
float
*
f
,
nsCString
&
value
)
{
value
=
nsPrintfCString
(
"%f"
,
*
f
);
}
static
void
PrefValueToString
(
const
nsACString
&
s
,
nsCString
&
value
)
{
value
=
s
;
}
// These preference getter wrappers allow us to look up the value for static
// preferences based on their native types, rather than manually mapping them to
// the appropriate Preferences::Get* functions.
...
...
@@ -4333,20 +4350,54 @@ struct Internals {
template
<
typename
T
>
static
nsresult
GetPrefValue
(
const
char
*
aPrefName
,
T
&&
aResult
,
PrefValueKind
aKind
)
{
nsresult
rv
=
NS_ERROR_UNEXPECTED
;
NS_ENSURE_TRUE
(
Preferences
::
InitStaticMembers
(),
NS_ERROR_NOT_AVAILABLE
);
TimeStamp
prefAccessTime
=
TimeStamp
::
Now
();
Maybe
<
PrefType
>
prefType
=
Nothing
();
nsCString
prefValue
{
""
};
if
(
Maybe
<
PrefWrapper
>
pref
=
pref_Lookup
(
aPrefName
))
{
return
pref
->
GetValue
(
aKind
,
std
::
forward
<
T
>
(
aResult
));
rv
=
pref
->
GetValue
(
aKind
,
std
::
forward
<
T
>
(
aResult
));
if
(
profiler_feature_active
(
ProfilerFeature
::
PreferenceReads
))
{
prefType
=
Some
(
pref
->
Type
());
PrefValueToString
(
aResult
,
prefValue
);
}
}
return
NS_ERROR_UNEXPECTED
;
if
(
profiler_feature_active
(
ProfilerFeature
::
PreferenceReads
))
{
profiler_add_marker
(
"PreferenceRead"
,
JS
::
ProfilingCategoryPair
::
OTHER_PreferenceRead
,
MakeUnique
<
PrefMarkerPayload
>
(
aPrefName
,
Some
(
aKind
),
prefType
,
prefValue
,
prefAccessTime
));
}
return
rv
;
}
template
<
typename
T
>
static
nsresult
GetSharedPrefValue
(
const
char
*
aName
,
T
*
aResult
)
{
nsresult
rv
=
NS_ERROR_UNEXPECTED
;
TimeStamp
prefAccessTime
=
TimeStamp
::
Now
();
Maybe
<
PrefType
>
prefType
=
Nothing
();
nsCString
prefValue
{
""
};
if
(
Maybe
<
PrefWrapper
>
pref
=
pref_SharedLookup
(
aName
))
{
return
pref
->
GetValue
(
PrefValueKind
::
User
,
aResult
);
rv
=
pref
->
GetValue
(
PrefValueKind
::
User
,
aResult
);
if
(
profiler_feature_active
(
ProfilerFeature
::
PreferenceReads
))
{
prefType
=
Some
(
pref
->
Type
());
PrefValueToString
(
aResult
,
prefValue
);
}
}
if
(
profiler_feature_active
(
ProfilerFeature
::
PreferenceReads
))
{
profiler_add_marker
(
"PreferenceRead"
,
JS
::
ProfilingCategoryPair
::
OTHER_PreferenceRead
,
MakeUnique
<
PrefMarkerPayload
>
(
aName
,
Nothing
()
/* indicates Shared */
,
prefType
,
prefValue
,
prefAccessTime
));
}
return
NS_ERROR_UNEXPECTED
;
return
rv
;
}
template
<
typename
T
>
...
...
toolkit/components/extensions/schemas/geckoProfiler.json
View file @
31eced36
...
...
@@ -36,7 +36,8 @@
"threads"
,
"trackopts"
,
"jstracer"
,
"jsallocations"
"jsallocations"
,
"preferencereads"
]
},
{
...
...
tools/profiler/core/ProfilerMarkerPayload.cpp
View file @
31eced36
...
...
@@ -14,6 +14,7 @@
#include
"Layers.h"
#include
"mozilla/Maybe.h"
#include
"mozilla/net/HttpBaseChannel.h"
#include
"mozilla/Preferences.h"
#include
"mozilla/Sprintf.h"
#include
<inttypes.h>
...
...
@@ -127,6 +128,44 @@ void DOMEventMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
aWriter
.
StringProperty
(
"eventType"
,
NS_ConvertUTF16toUTF8
(
mEventType
).
get
());
}
static
const
char
*
PrefValueKindToString
(
const
mozilla
::
Maybe
<
PrefValueKind
>&
aKind
)
{
if
(
aKind
)
{
return
*
aKind
==
PrefValueKind
::
Default
?
"Default"
:
"User"
;
}
return
"Shared"
;
}
static
const
char
*
PrefTypeToString
(
const
mozilla
::
Maybe
<
PrefType
>&
type
)
{
if
(
type
)
{
switch
(
*
type
)
{
case
PrefType
::
None
:
return
"None"
;
case
PrefType
::
Int
:
return
"Int"
;
case
PrefType
::
Bool
:
return
"Bool"
;
case
PrefType
::
String
:
return
"String"
;
default:
MOZ_ASSERT_UNREACHABLE
(
"Unknown preference type."
);
}
}
return
"Preference not found"
;
}
void
PrefMarkerPayload
::
StreamPayload
(
SpliceableJSONWriter
&
aWriter
,
const
TimeStamp
&
aProcessStartTime
,
UniqueStacks
&
aUniqueStacks
)
{
StreamCommonProps
(
"PreferenceRead"
,
aWriter
,
aProcessStartTime
,
aUniqueStacks
);
WriteTime
(
aWriter
,
aProcessStartTime
,
mPrefAccessTime
,
"prefAccessTime"
);
aWriter
.
StringProperty
(
"prefName"
,
mPrefName
.
get
());
aWriter
.
StringProperty
(
"prefKind"
,
PrefValueKindToString
(
mPrefKind
));
aWriter
.
StringProperty
(
"prefType"
,
PrefTypeToString
(
mPrefType
));
aWriter
.
StringProperty
(
"prefValue"
,
mPrefValue
.
get
());
}
void
LayerTranslationMarkerPayload
::
StreamPayload
(
SpliceableJSONWriter
&
aWriter
,
const
TimeStamp
&
aProcessStartTime
,
UniqueStacks
&
aUniqueStacks
)
{
...
...
tools/profiler/public/GeckoProfiler.h
View file @
31eced36
...
...
@@ -160,7 +160,10 @@ class Vector;
MACRO(12, "jstracer", JSTracer, "Enable tracing of the JavaScript engine") \
\
MACRO(13, "jsallocations", JSAllocations, \
"Have the JavaScript engine track allocations")
"Have the JavaScript engine track allocations") \
\
MACRO(15, "preferencereads", PreferenceReads, \
"Track when preferences are read")
struct
ProfilerFeature
{
# define DECLARE(n_, str_, Name_, desc_) \
...
...
tools/profiler/public/ProfilerMarkerPayload.h
View file @
31eced36
...
...
@@ -12,6 +12,7 @@
#include
"mozilla/RefPtr.h"
#include
"mozilla/TimeStamp.h"
#include
"mozilla/UniquePtr.h"
#include
"mozilla/Preferences.h"
#include
"mozilla/UniquePtrExtensions.h"
#include
"mozilla/net/TimingStruct.h"
...
...
@@ -149,6 +150,35 @@ class DOMEventMarkerPayload : public TracingMarkerPayload {
nsString
mEventType
;
};
class
PrefMarkerPayload
:
public
ProfilerMarkerPayload
{
public:
PrefMarkerPayload
(
const
char
*
aPrefName
,
const
mozilla
::
Maybe
<
mozilla
::
PrefValueKind
>&
aPrefKind
,
const
mozilla
::
Maybe
<
mozilla
::
PrefType
>&
aPrefType
,
const
nsCString
&
aPrefValue
,
const
mozilla
::
TimeStamp
&
aPrefAccessTime
)
:
ProfilerMarkerPayload
(
aPrefAccessTime
,
aPrefAccessTime
),
mPrefAccessTime
(
aPrefAccessTime
),
mPrefName
(
aPrefName
),
mPrefKind
(
aPrefKind
),
mPrefType
(
aPrefType
),
mPrefValue
(
aPrefValue
)
{}
DECL_STREAM_PAYLOAD
private:
mozilla
::
TimeStamp
mPrefAccessTime
;
nsCString
mPrefName
;
// Nothing means this is a shared preference. Something, on the other hand,
// holds an actual PrefValueKind indicating either a Default or User
// preference.
mozilla
::
Maybe
<
mozilla
::
PrefValueKind
>
mPrefKind
;
// Nothing means that the mPrefName preference was not found. Something
// contains the type of the preference.
mozilla
::
Maybe
<
mozilla
::
PrefType
>
mPrefType
;
nsCString
mPrefValue
;
};
class
UserTimingMarkerPayload
:
public
ProfilerMarkerPayload
{
public:
UserTimingMarkerPayload
(
const
nsAString
&
aName
,
...
...
tools/profiler/tests/browser/browser.ini
View file @
31eced36
...
...
@@ -2,12 +2,14 @@
support-files
=
head.js
do_work_500ms.html
fixed_height.html
multi_frame.html
single_frame.html
single_frame_pushstate.html
single_frame_replacestate.html
[browser_test_feature_jsallocations.js]
[browser_test_feature_preferencereads.js]
[browser_test_profile_single_frame_page_info.js]
[browser_test_profile_multi_frame_page_info.js]
[browser_test_profile_pushstate_page_info.js]
...
...
tools/profiler/tests/browser/browser_test_feature_jsallocations.js
View file @
31eced36
...
...
@@ -80,48 +80,3 @@ add_task(async function test_profile_feature_jsallocations() {
}
});
});
/**
* Markers are collected only after a periodic sample. This function ensures that
* at least one periodic sample has been done.
*/
async
function
doAtLeastOnePeriodicSample
()
{
async
function
getProfileSampleCount
()
{
const
profile
=
await
Services
.
profiler
.
getProfileDataAsync
();
return
profile
.
threads
[
0
].
samples
.
data
.
length
;
}
const
sampleCount
=
await
getProfileSampleCount
();
// Create an infinite loop until a sample has been collected.
while
(
true
)
{
if
(
sampleCount
<
(
await
getProfileSampleCount
()))
{
return
;
}
}
}
async
function
stopProfilerAndGetThreads
(
contentPid
)
{
await
doAtLeastOnePeriodicSample
();
const
profile
=
await
Services
.
profiler
.
getProfileDataAsync
();
Services
.
profiler
.
StopProfiler
();
const
parentThread
=
profile
.
threads
[
0
];
const
contentProcess
=
profile
.
processes
.
find
(
p
=>
p
.
threads
[
0
].
pid
==
contentPid
);
if
(
!
contentProcess
)
{
throw
new
Error
(
"
Could not find the content process.
"
);
}
const
contentThread
=
contentProcess
.
threads
[
0
];
if
(
!
parentThread
)
{
throw
new
Error
(
"
The parent thread was not found in the profile.
"
);
}
if
(
!
contentThread
)
{
throw
new
Error
(
"
The content thread was not found in the profile.
"
);
}
return
{
parentThread
,
contentThread
};
}
tools/profiler/tests/browser/browser_test_feature_preferencereads.js
0 → 100644
View file @
31eced36
/* 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/. */
function
countDpiPrefReadsInThread
(
thread
)
{
let
count
=
0
;
for
(
let
payload
of
getPayloadsOfType
(
thread
,
"
PreferenceRead
"
))
{
if
(
payload
.
prefName
===
"
layout.css.dpi
"
)
{
count
++
;
}
}
return
count
;
}
/**
* Test the PreferenceRead feature.
*/
add_task
(
async
function
test_profile_feature_preferencereads
()
{
if
(
!
AppConstants
.
MOZ_GECKO_PROFILER
)
{
return
;
}
Assert
.
ok
(
!
Services
.
profiler
.
IsActive
(),
"
The profiler is not currently active
"
);
startProfiler
({
features
:
[
"
threads
"
,
"
preferencereads
"
]
});
const
url
=
BASE_URL
+
"
fixed_height.html
"
;
await
BrowserTestUtils
.
withNewTab
(
url
,
async
contentBrowser
=>
{
const
contentPid
=
await
ContentTask
.
spawn
(
contentBrowser
,
null
,
()
=>
Services
.
appinfo
.
processID
);
// Wait 100ms so that the tab finishes executing.
await
wait
(
100
);
// Check that some PreferenceRead profile markers were generated when the
// feature is enabled.
{
const
{
contentThread
}
=
await
stopProfilerAndGetThreads
(
contentPid
);
const
timesReadDpiInContent
=
countDpiPrefReadsInThread
(
contentThread
);
Assert
.
greater
(
timesReadDpiInContent
,
0
,
"
PreferenceRead profile markers for layout.css.dpi were recorded
"
+
"
when the PreferenceRead feature was turned on.
"
);
}
startProfiler
({
features
:
[
"
threads
"
]
});
// Now reload the tab with a clean run.
gBrowser
.
reload
();
await
wait
(
100
);
// Check that no PreferenceRead markers were recorded when the feature
// is turned off.
{
const
{
parentThread
,
contentThread
}
=
await
stopProfilerAndGetThreads
(
contentPid
);
Assert
.
equal
(
getPayloadsOfType
(
parentThread
,
"
PreferenceRead
"
).
length
,
0
,
"
No PreferenceRead profile markers for layout.css.dpi were recorded
"
+
"
when the PreferenceRead feature was turned on.
"
);
Assert
.
equal
(
getPayloadsOfType
(
contentThread
,
"
PreferenceRead
"
).
length
,
0
,
"
No PreferenceRead profile markers for layout.css.dpi were recorded
"
+
"
when the PreferenceRead feature was turned on.
"
);
}
});
});
tools/profiler/tests/browser/fixed_height.html
0 → 100644
View file @
31eced36
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"utf-8"
/>
<!--
Using an absolute value here should invoke Firefox to get
the layout.css.dpi preference.
-->
<style
type=
"text/css"
>
div
.fixed_height
{
height
:
15in
;
}
</style>
</head>
<body>
<div
class=
"fixed_height"
>
Testing
</div>
</body>
</html>
tools/profiler/tests/browser/head.js
View file @
31eced36
...
...
@@ -21,6 +21,60 @@ function startProfiler(callersSettings) {
settings
.
duration
);
}
/**
* This function spins on a while loop until at least one
* periodic sample is taken. Use this function to ensure
* that markers are properly collected for a test or that
* at least one sample in which we are interested is collected.
*/
async
function
doAtLeastOnePeriodicSample
()
{
async
function
getProfileSampleCount
()
{
const
profile
=
await
Services
.
profiler
.
getProfileDataAsync
();
return
profile
.
threads
[
0
].
samples
.
data
.
length
;
}
const
sampleCount
=
await
getProfileSampleCount
();
// Create an infinite loop until a sample has been collected.
while
(
true
)
{
if
(
sampleCount
<
(
await
getProfileSampleCount
()))
{
return
;
}
}
}
/**
* This is a helper function that will stop the profiler of the browser
* running with PID contentPid. The profiler in that PID
* will not stop until there is at least one periodic sample taken, though.
*
* @param {number} contentPid
* @returns {Promise}
*/
async
function
stopProfilerAndGetThreads
(
contentPid
)
{
await
doAtLeastOnePeriodicSample
();
const
profile
=
await
Services
.
profiler
.
getProfileDataAsync
();
Services
.
profiler
.
StopProfiler
();
const
parentThread
=
profile
.
threads
[
0
];
const
contentProcess
=
profile
.
processes
.
find
(
p
=>
p
.
threads
[
0
].
pid
==
contentPid
);
if
(
!
contentProcess
)
{
throw
new
Error
(
"
Could not find the content process.
"
);
}
const
contentThread
=
contentProcess
.
threads
[
0
];
if
(
!
parentThread
)
{
throw
new
Error
(
"
The parent thread was not found in the profile.
"
);
}
if
(
!
contentThread
)
{
throw
new
Error
(
"
The content thread was not found in the profile.
"
);
}
return
{
parentThread
,
contentThread
};
}
/**
* This is a helper function be able to run `await wait(500)`. Unfortunately this
...
...
Write
Preview