Bug 1158731 - Buffer for Performance APIs (Resource Timing, User Timing) should be separeted. r=baku

This commit is contained in:
Hiroyuki Ikezoe 2015-05-08 01:00:00 +02:00
parent 97a0be091d
commit 130bd87ffb
6 changed files with 217 additions and 59 deletions

View File

@ -400,7 +400,8 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsPerformance)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsPerformance, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow, mTiming,
mNavigation, mEntries,
mNavigation, mUserEntries,
mResourceEntries,
mParentPerformance)
tmp->mMozMemory = nullptr;
mozilla::DropJSObjects(this);
@ -408,7 +409,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsPerformance, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow, mTiming,
mNavigation, mEntries,
mNavigation, mUserEntries,
mResourceEntries,
mParentPerformance)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -429,7 +431,7 @@ nsPerformance::nsPerformance(nsPIDOMWindow* aWindow,
mDOMTiming(aDOMTiming),
mChannel(aChannel),
mParentPerformance(aParentPerformance),
mPrimaryBufferSize(kDefaultBufferSize)
mResourceTimingBufferSize(kDefaultResourceTimingBufferSize)
{
MOZ_ASSERT(aWindow, "Parent window object should be provided");
}
@ -509,24 +511,30 @@ nsPerformance::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
}
void
nsPerformance::GetEntries(nsTArray<nsRefPtr<PerformanceEntry> >& retval)
nsPerformance::GetEntries(nsTArray<nsRefPtr<PerformanceEntry>>& retval)
{
MOZ_ASSERT(NS_IsMainThread());
retval = mEntries;
retval = mResourceEntries;
retval.AppendElements(mUserEntries);
retval.Sort(PerformanceEntryComparator());
}
void
nsPerformance::GetEntriesByType(const nsAString& entryType,
nsTArray<nsRefPtr<PerformanceEntry> >& retval)
nsTArray<nsRefPtr<PerformanceEntry>>& retval)
{
MOZ_ASSERT(NS_IsMainThread());
retval.Clear();
uint32_t count = mEntries.Length();
for (uint32_t i = 0 ; i < count; i++) {
if (mEntries[i]->GetEntryType().Equals(entryType)) {
retval.AppendElement(mEntries[i]);
if (entryType.EqualsLiteral("resource")) {
retval = mResourceEntries;
} else if (entryType.EqualsLiteral("mark") ||
entryType.EqualsLiteral("measure")) {
for (PerformanceEntry* entry : mUserEntries) {
if (entry->GetEntryType().Equals(entryType)) {
retval.AppendElement(entry);
}
}
}
}
@ -534,31 +542,38 @@ nsPerformance::GetEntriesByType(const nsAString& entryType,
void
nsPerformance::GetEntriesByName(const nsAString& name,
const Optional<nsAString>& entryType,
nsTArray<nsRefPtr<PerformanceEntry> >& retval)
nsTArray<nsRefPtr<PerformanceEntry>>& retval)
{
MOZ_ASSERT(NS_IsMainThread());
retval.Clear();
uint32_t count = mEntries.Length();
for (uint32_t i = 0 ; i < count; i++) {
if (mEntries[i]->GetName().Equals(name) &&
for (PerformanceEntry* entry : mResourceEntries) {
if (entry->GetName().Equals(name) &&
(!entryType.WasPassed() ||
mEntries[i]->GetEntryType().Equals(entryType.Value()))) {
retval.AppendElement(mEntries[i]);
entry->GetEntryType().Equals(entryType.Value()))) {
retval.AppendElement(entry);
}
}
for (PerformanceEntry* entry : mUserEntries) {
if (entry->GetName().Equals(name) &&
(!entryType.WasPassed() ||
entry->GetEntryType().Equals(entryType.Value()))) {
retval.AppendElement(entry);
}
}
retval.Sort(PerformanceEntryComparator());
}
void
nsPerformance::ClearEntries(const Optional<nsAString>& aEntryName,
const nsAString& aEntryType)
nsPerformance::ClearUserEntries(const Optional<nsAString>& aEntryName,
const nsAString& aEntryType)
{
for (uint32_t i = 0; i < mEntries.Length();) {
for (uint32_t i = 0; i < mUserEntries.Length();) {
if ((!aEntryName.WasPassed() ||
mEntries[i]->GetName().Equals(aEntryName.Value())) &&
mUserEntries[i]->GetName().Equals(aEntryName.Value())) &&
(aEntryType.IsEmpty() ||
mEntries[i]->GetEntryType().Equals(aEntryType))) {
mEntries.RemoveElementAt(i);
mUserEntries[i]->GetEntryType().Equals(aEntryType))) {
mUserEntries.RemoveElementAt(i);
} else {
++i;
}
@ -569,15 +584,14 @@ void
nsPerformance::ClearResourceTimings()
{
MOZ_ASSERT(NS_IsMainThread());
ClearEntries(Optional<nsAString>(),
NS_LITERAL_STRING("resource"));
mResourceEntries.Clear();
}
void
nsPerformance::SetResourceTimingBufferSize(uint64_t maxSize)
{
MOZ_ASSERT(NS_IsMainThread());
mPrimaryBufferSize = maxSize;
mResourceTimingBufferSize = maxSize;
}
/**
@ -595,7 +609,7 @@ nsPerformance::AddEntry(nsIHttpChannel* channel,
}
// Don't add the entry if the buffer is full
if (mEntries.Length() >= mPrimaryBufferSize) {
if (mResourceEntries.Length() >= mResourceTimingBufferSize) {
return;
}
@ -634,7 +648,7 @@ nsPerformance::AddEntry(nsIHttpChannel* channel,
initiatorType = NS_LITERAL_STRING("other");
}
performanceEntry->SetInitiatorType(initiatorType);
InsertPerformanceEntry(performanceEntry, false);
InsertResourceEntry(performanceEntry);
}
}
@ -659,16 +673,25 @@ nsPerformance::PerformanceEntryComparator::LessThan(
}
void
nsPerformance::InsertPerformanceEntry(PerformanceEntry* aEntry,
bool aShouldPrint)
nsPerformance::InsertResourceEntry(PerformanceEntry* aEntry)
{
MOZ_ASSERT(aEntry);
MOZ_ASSERT(mEntries.Length() < mPrimaryBufferSize);
if (mEntries.Length() == mPrimaryBufferSize) {
NS_WARNING("Performance Entry buffer size maximum reached!");
MOZ_ASSERT(mResourceEntries.Length() < mResourceTimingBufferSize);
if (mResourceEntries.Length() >= mResourceTimingBufferSize) {
return;
}
if (aShouldPrint && nsContentUtils::IsUserTimingLoggingEnabled()) {
mResourceEntries.InsertElementSorted(aEntry,
PerformanceEntryComparator());
if (mResourceEntries.Length() == mResourceTimingBufferSize) {
// call onresourcetimingbufferfull
DispatchBufferFullEvent();
}
}
void
nsPerformance::InsertUserEntry(PerformanceEntry* aEntry)
{
if (nsContentUtils::IsUserTimingLoggingEnabled()) {
nsAutoCString uri;
nsresult rv = mWindow->GetDocumentURI()->GetHost(uri);
if(NS_FAILED(rv)) {
@ -683,21 +706,16 @@ nsPerformance::InsertPerformanceEntry(PerformanceEntry* aEntry,
aEntry->Duration(),
static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC));
}
mEntries.InsertElementSorted(aEntry,
PerformanceEntryComparator());
if (mEntries.Length() == mPrimaryBufferSize) {
// call onresourcetimingbufferfull
DispatchBufferFullEvent();
}
mUserEntries.InsertElementSorted(aEntry,
PerformanceEntryComparator());
}
void
nsPerformance::Mark(const nsAString& aName, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
// Don't add the entry if the buffer is full
if (mEntries.Length() >= mPrimaryBufferSize) {
NS_WARNING("Performance Entry buffer size maximum reached!");
// Don't add the entry if the buffer is full. XXX should be removed by bug 1159003.
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
return;
}
if (IsPerformanceTimingAttribute(aName)) {
@ -706,14 +724,14 @@ nsPerformance::Mark(const nsAString& aName, ErrorResult& aRv)
}
nsRefPtr<PerformanceMark> performanceMark =
new PerformanceMark(this, aName);
InsertPerformanceEntry(performanceMark, true);
InsertUserEntry(performanceMark);
}
void
nsPerformance::ClearMarks(const Optional<nsAString>& aName)
{
MOZ_ASSERT(NS_IsMainThread());
ClearEntries(aName, NS_LITERAL_STRING("mark"));
ClearUserEntries(aName, NS_LITERAL_STRING("mark"));
}
DOMHighResTimeStamp
@ -749,9 +767,8 @@ nsPerformance::Measure(const nsAString& aName,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
// Don't add the entry if the buffer is full
if (mEntries.Length() >= mPrimaryBufferSize) {
NS_WARNING("Performance Entry buffer size maximum reached!");
// Don't add the entry if the buffer is full. XXX should be removed by bug 1159003.
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
return;
}
DOMHighResTimeStamp startTime;
@ -783,14 +800,14 @@ nsPerformance::Measure(const nsAString& aName,
}
nsRefPtr<PerformanceMeasure> performanceMeasure =
new PerformanceMeasure(this, aName, startTime, endTime);
InsertPerformanceEntry(performanceMeasure, true);
InsertUserEntry(performanceMeasure);
}
void
nsPerformance::ClearMeasures(const Optional<nsAString>& aName)
{
MOZ_ASSERT(NS_IsMainThread());
ClearEntries(aName, NS_LITERAL_STRING("measure"));
ClearUserEntries(aName, NS_LITERAL_STRING("measure"));
}
DOMHighResTimeStamp

View File

@ -328,12 +328,12 @@ public:
nsPerformanceTiming* Timing();
nsPerformanceNavigation* Navigation();
void GetEntries(nsTArray<nsRefPtr<PerformanceEntry> >& retval);
void GetEntries(nsTArray<nsRefPtr<PerformanceEntry>>& retval);
void GetEntriesByType(const nsAString& entryType,
nsTArray<nsRefPtr<PerformanceEntry> >& retval);
nsTArray<nsRefPtr<PerformanceEntry>>& retval);
void GetEntriesByName(const nsAString& name,
const mozilla::dom::Optional< nsAString >& entryType,
nsTArray<nsRefPtr<PerformanceEntry> >& retval);
nsTArray<nsRefPtr<PerformanceEntry>>& retval);
void AddEntry(nsIHttpChannel* channel,
nsITimedChannel* timedChannel);
void ClearResourceTimings();
@ -357,20 +357,22 @@ private:
DOMTimeMilliSec GetPerformanceTimingFromString(const nsAString& aTimingName);
DOMHighResTimeStamp ConvertDOMMilliSecToHighRes(const DOMTimeMilliSec aTime);
void DispatchBufferFullEvent();
void InsertPerformanceEntry(PerformanceEntry* aEntry, bool aShouldPrint);
void ClearEntries(const mozilla::dom::Optional<nsAString>& aEntryName,
const nsAString& aEntryType);
void InsertUserEntry(PerformanceEntry* aEntry);
void ClearUserEntries(const mozilla::dom::Optional<nsAString>& aEntryName,
const nsAString& aEntryType);
void InsertResourceEntry(PerformanceEntry* aEntry);
nsCOMPtr<nsPIDOMWindow> mWindow;
nsRefPtr<nsDOMNavigationTiming> mDOMTiming;
nsCOMPtr<nsITimedChannel> mChannel;
nsRefPtr<nsPerformanceTiming> mTiming;
nsRefPtr<nsPerformanceNavigation> mNavigation;
nsTArray<nsRefPtr<PerformanceEntry> > mEntries;
nsTArray<nsRefPtr<PerformanceEntry>> mResourceEntries;
nsTArray<nsRefPtr<PerformanceEntry>> mUserEntries;
nsRefPtr<nsPerformance> mParentPerformance;
uint64_t mPrimaryBufferSize;
uint64_t mResourceTimingBufferSize;
JS::Heap<JSObject*> mMozMemory;
static const uint64_t kDefaultBufferSize = 150;
static const uint64_t kDefaultResourceTimingBufferSize = 150;
// Helper classes
class PerformanceEntryComparator {

View File

@ -14,6 +14,7 @@ support-files =
image_50.png
image_100.png
image_200.png
performance_timeline_main_test.html
resource_timing_iframe.html
resource_timing_main_test.html
resource_timing_cross_origin.html
@ -79,8 +80,10 @@ support-files = test_offsets.js
skip-if = buildapp == 'mulet'
[test_paste_selection.html]
skip-if = buildapp == 'mulet'
[test_performance_timeline.html]
[test_picture_mutations.html]
[test_picture_pref.html]
skip-if = buildapp == 'b2g' || buildapp == 'mulet'
[test_resource_timing.html]
skip-if = buildapp == 'b2g' || buildapp == 'mulet'
[test_resource_timing_cross_origin.html]

View File

@ -0,0 +1,100 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
function ok(cond, message) {
window.opener.ok(cond, message)
}
function is(received, expected, message) {
window.opener.is(received, expected, message);
}
function isnot(received, notExpected, message) {
window.opener.isnot(received, notExpected, message);
}
var receivedBufferFullEvents = 0;
window.performance.onresourcetimingbufferfull = () => {
receivedBufferFullEvents++;
}
window.onload = () => {
// Here, we should have 4 entries (1 css, 3 png) since the image was loaded.
is(window.performance.getEntries().length, 4, "Performance.getEntries() returned wrong number of entries.");
window.performance.setResourceTimingBufferSize(5);
window.performance.mark("test-start");
window.performance.mark("test-end");
// The URI should be the address of a resource will be loaded later to be used on getEntriesByName.
window.performance.measure("http://mochi.test:8888/tests/dom/tests/mochitest/general/test-data2.json",
"test-start", "test-end");
is(window.performance.getEntries().length, 7, "User Timing APIs should never be affected by setResourceTimingBufferSize.");
is(window.performance.getEntriesByType("resource").length, 4, "The number of PerformanceResourceTiming should be 4.");
is(window.performance.getEntriesByType("mark").length, 2, "The number of PerformanceMark entries should be 2.");
is(window.performance.getEntriesByType("measure").length, 1, "The number of PerformanceMeasure entries should be 1.");
is(receivedBufferFullEvents, 0, "onresourcetimingbufferfull should never be called.");
makeXhr("test-data2.json", firstCheck);
}
function makeXhr(aUrl, aCallback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = aCallback;
xmlhttp.open("get", aUrl, true);
xmlhttp.send();
}
function firstCheck() {
is(window.performance.getEntriesByType("resource").length, 5, "The number of PerformanceResourceTiming should be 5.");
is(receivedBufferFullEvents, 1, "onresourcetimingbufferfull should be called once.");
makeXhr("test-data2.json", secondCheck);
}
function secondCheck() {
is(window.performance.getEntriesByType("resource").length, 5, "The number of PerformanceResourceTiming should be 5.");
is(receivedBufferFullEvents, 1, "onresourcetimingbufferfull should never be called since the last call.");
checkOrder(window.performance.getEntries(), "All PerformanceEntry");
checkOrder(window.performance.getEntriesByType("resource"), "PerformanceResourceTiming");
checkOrder(window.performance.getEntriesByType("mark"), "PerformanceMark");
checkOrder(window.performance.getEntriesByType("measure"), "PerformanceMeasure");
is(window.performance.getEntriesByName("http://mochi.test:8888/tests/dom/tests/mochitest/general/test-data2.json").length, 2,
"Both PerformanceMeasure and XMLHttpRequest resource should be included.");
checkOrder(window.performance.getEntriesByName("http://mochi.test:8888/tests/dom/tests/mochitest/general/test-data2.json"),
"Entry with performance.getEntrieByName()");
window.opener.finishTests();
}
function checkOrder(entries, name) {
for (var i = 0; i < entries.length - 1; i++) {
ok(entries[i].startTime <= entries[i + 1].startTime, name + " should be sorted by startTime.");
}
}
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1158731"
title="Buffer for Performance APIs (Resource Timing, User Timing) should be separeted">
Bug #1158731 - Buffer for Performance APIs (Resource Timing, User Timing) should be separeted
</a>
<p id="display"></p>
<div id="content">
<img src="http://mochi.test:8888/tests/image/test/mochitest/over.png">
<object data="http://mochi.test:8888/tests/image/test/mochitest/clear.png" type="image/png"/>
<embed src="http://mochi.test:8888/tests/image/test/mochitest/green.png" type="image/png"/>
</div>
</body>
</html>

View File

@ -76,7 +76,7 @@ window.onload = function() {
bufferFullCounter += 1;
}
// Here, we should have 6 entries (1 css, 3 png, 1 html) since the image was loaded.
// Here, we should have 5 entries (1 css, 3 png, 1 html) since the image was loaded.
is(window.performance.getEntries().length, 5, "Performance.getEntries() returned wrong number of entries.");
checkStringify(window.performance.getEntries()[0]);

View File

@ -0,0 +1,36 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Resource timing is prefed off by default, so we had to use this workaround
SpecialPowers.pushPrefEnv({"set": [["dom.enable_resource_timing", true],
["dom.enable_user_timing", true]]}, start);
var subwindow = null;
function start() {
subwindow = window.open("performance_timeline_main_test.html");
}
function finishTests() {
subwindow.close();
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>