Bug 1387956 - Overhaul ComputedValues measurement, and add style structs measurement. r=bholley.

This patch moves measurement of ComputedValues objects from Rust to C++.
Measurement now happens (a) via DOM elements and (b) remaining elements via
the frame tree. Likewise for the style structs hanging off ComputedValues
objects.

Here is an example of the output.

> ├──27,600,448 B (26.49%) -- active/window(https://en.wikipedia.org/wiki/Barack_Obama)
> │  ├──12,772,544 B (12.26%) -- layout
> │  │  ├───4,483,744 B (04.30%) -- frames
> │  │  │   ├──1,653,552 B (01.59%) ── nsInlineFrame
> │  │  │   ├──1,415,760 B (01.36%) ── nsTextFrame
> │  │  │   ├────431,376 B (00.41%) ── nsBlockFrame
> │  │  │   ├────340,560 B (00.33%) ── nsHTMLScrollFrame
> │  │  │   ├────302,544 B (00.29%) ── nsContinuingTextFrame
> │  │  │   ├────156,408 B (00.15%) ── nsBulletFrame
> │  │  │   ├─────73,024 B (00.07%) ── nsPlaceholderFrame
> │  │  │   ├─────27,656 B (00.03%) ── sundries
> │  │  │   ├─────23,520 B (00.02%) ── nsTableCellFrame
> │  │  │   ├─────16,704 B (00.02%) ── nsImageFrame
> │  │  │   ├─────15,488 B (00.01%) ── nsTableRowFrame
> │  │  │   ├─────13,776 B (00.01%) ── nsTableColFrame
> │  │  │   └─────13,376 B (00.01%) ── nsTableFrame
> │  │  ├───3,412,192 B (03.28%) -- servo-style-structs
> │  │  │   ├──1,288,224 B (01.24%) ── Display
> │  │  │   ├────742,400 B (00.71%) ── Position
> │  │  │   ├────308,736 B (00.30%) ── Font
> │  │  │   ├────226,512 B (00.22%) ── Background
> │  │  │   ├────218,304 B (00.21%) ── TextReset
> │  │  │   ├────214,896 B (00.21%) ── Text
> │  │  │   ├────130,560 B (00.13%) ── Border
> │  │  │   ├─────81,408 B (00.08%) ── UIReset
> │  │  │   ├─────61,440 B (00.06%) ── Padding
> │  │  │   ├─────38,176 B (00.04%) ── UserInterface
> │  │  │   ├─────29,232 B (00.03%) ── Margin
> │  │  │   ├─────21,824 B (00.02%) ── sundries
> │  │  │   ├─────20,080 B (00.02%) ── Color
> │  │  │   ├─────20,080 B (00.02%) ── Column
> │  │  │   └─────10,320 B (00.01%) ── Effects
> │  │  ├───2,227,680 B (02.14%) -- computed-values
> │  │  │   ├──1,182,928 B (01.14%) ── non-dom
> │  │  │   └──1,044,752 B (01.00%) ── dom
> │  │  ├───1,500,016 B (01.44%) ── text-runs
> │  │  ├─────492,640 B (00.47%) ── line-boxes
> │  │  ├─────326,688 B (00.31%) ── frame-properties
> │  │  ├─────301,760 B (00.29%) ── pres-shell
> │  │  ├──────27,648 B (00.03%) ── pres-contexts
> │  │  └─────────176 B (00.00%) ── style-sets

The 'servo-style-structs' and 'computed-values' sub-trees are new. (Prior to
this patch, ComputedValues under DOM elements were tallied under the the
'dom/element-nodes' sub-tree, and ComputedValues not under DOM element were
ignored.) 'servo-style-structs/sundries' aggregates all the style structs that
are smaller than 8 KiB.

Other notable things done by the patch are as follows.

- It significantly changes the signatures of the methods measuring nsINode and
  its subclasses, in order to handle the tallying of style structs separately
  from element-nodes. Likewise for nsIFrame.

- It renames the 'layout/style-structs' sub-tree as
  'layout/gecko-style-structs', to clearly distinguish it from the new
  'layout/servo-style-structs' sub-tree.

- It adds some FFI functions to access various Rust-side data structures from
  C++ code.

- There is a nasty hack used twice to measure Arcs, by stepping backwards from
  an interior pointer to a base pointer. It works, but I want to replace it
  with something better eventually. The "XXX WARNING" comments have details.

- It makes DMD print a line to the console if it sees a pointer it doesn't
  recognise. This is useful for detecting when we are measuring an interior
  pointer instead of a base pointer, which is bad but easy to do when Arcs are
  involved.

- It removes the Rust code for measuring CVs, because it's now all done on the
  C++ side.

MozReview-Commit-ID: BKebACLKtCi

--HG--
extra : rebase_source : 4d9a8c6b198a0ff025b811759a6bfa9f33a260ba
This commit is contained in:
Nicholas Nethercote 2017-08-11 16:37:33 +10:00
Родитель cb12286e7a
Коммит 57c26c9834
30 изменённых файлов: 442 добавлений и 156 удалений

Просмотреть файл

@ -4143,19 +4143,40 @@ Element::SetCustomElementData(CustomElementData* aData)
MOZ_DEFINE_MALLOC_SIZE_OF(ServoElementMallocSizeOf)
size_t
Element::SizeOfExcludingThis(SizeOfState& aState) const
void
Element::AddSizeOfExcludingThis(SizeOfState& aState, nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
size_t n = FragmentOrElement::SizeOfExcludingThis(aState);
FragmentOrElement::AddSizeOfExcludingThis(aState, aSizes, aNodeSize);
// Measure mServoData. We use ServoElementMallocSizeOf rather than
// |aState.mMallocSizeOf| to distinguish in DMD's output the memory
// measured within Servo code.
if (mServoData.Get()) {
n += Servo_Element_SizeOfExcludingThis(ServoElementMallocSizeOf,
&aState.mSeenPtrs, this);
if (HasServoData()) {
// Measure mServoData, excluding the ComputedValues. This measurement
// counts towards the element's size. We use ServoElementMallocSizeOf
// rather thang |aState.mMallocSizeOf| to better distinguish in DMD's
// output the memory measured within Servo code.
*aNodeSize +=
Servo_Element_SizeOfExcludingThisAndCVs(ServoElementMallocSizeOf,
&aState.mSeenPtrs, this);
// Now measure just the ComputedValues (and style structs) under
// mServoData. This counts towards the relevant fields in |aSizes|.
RefPtr<ServoStyleContext> sc;
if (Servo_Element_HasPrimaryComputedValues(this)) {
sc = Servo_Element_GetPrimaryComputedValues(this).Consume();
if (!aState.HaveSeenPtr(sc.get())) {
sc->AddSizeOfIncludingThis(aState, aSizes, /* isDOM = */ true);
}
for (size_t i = 0; i < nsCSSPseudoElements::kEagerPseudoCount; i++) {
if (Servo_Element_HasPseudoComputedValues(this, i)) {
sc = Servo_Element_GetPseudoComputedValues(this, i).Consume();
if (!aState.HaveSeenPtr(sc.get())) {
sc->AddSizeOfIncludingThis(aState, aSizes, /* isDOM = */ true);
}
}
}
}
}
return n;
}
struct DirtyDescendantsBit {

Просмотреть файл

@ -205,7 +205,7 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ELEMENT_IID)
NS_DECL_SIZEOF_EXCLUDING_THIS
NS_DECL_ADDSIZEOFEXCLUDINGTHIS
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;

Просмотреть файл

@ -2502,19 +2502,18 @@ FragmentOrElement::FireNodeRemovedForChildren()
}
}
size_t
FragmentOrElement::SizeOfExcludingThis(SizeOfState& aState) const
void
FragmentOrElement::AddSizeOfExcludingThis(SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
size_t n = 0;
n += nsIContent::SizeOfExcludingThis(aState);
n += mAttrsAndChildren.SizeOfExcludingThis(aState.mMallocSizeOf);
nsIContent::AddSizeOfExcludingThis(aState, aSizes, aNodeSize);
*aNodeSize += mAttrsAndChildren.SizeOfExcludingThis(aState.mMallocSizeOf);
nsDOMSlots* slots = GetExistingDOMSlots();
if (slots) {
n += slots->SizeOfIncludingThis(aState.mMallocSizeOf);
*aNodeSize += slots->SizeOfIncludingThis(aState.mMallocSizeOf);
}
return n;
}
void

Просмотреть файл

@ -118,7 +118,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_SIZEOF_EXCLUDING_THIS
NS_DECL_ADDSIZEOFEXCLUDINGTHIS
// nsINode interface methods
virtual uint32_t GetChildCount() const override;

Просмотреть файл

@ -12390,26 +12390,25 @@ nsDocument::GetVisibilityState(nsAString& aState)
}
/* virtual */ void
nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const
nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aSizes) const
{
aWindowSizes.mDOMOtherSize +=
nsINode::SizeOfExcludingThis(aWindowSizes.mState);
nsINode::AddSizeOfExcludingThis(aSizes.mState, aSizes.mStyleSizes,
&aSizes.mDOMOtherSize);
if (mPresShell) {
mPresShell->AddSizeOfIncludingThis(aWindowSizes);
mPresShell->AddSizeOfIncludingThis(aSizes);
}
aWindowSizes.mPropertyTablesSize +=
mPropertyTable.SizeOfExcludingThis(aWindowSizes.mState.mMallocSizeOf);
aSizes.mPropertyTablesSize +=
mPropertyTable.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
for (uint32_t i = 0, count = mExtraPropertyTables.Length();
i < count; ++i) {
aWindowSizes.mPropertyTablesSize +=
mExtraPropertyTables[i]->SizeOfIncludingThis(
aWindowSizes.mState.mMallocSizeOf);
aSizes.mPropertyTablesSize +=
mExtraPropertyTables[i]->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
}
if (EventListenerManager* elm = GetExistingListenerManager()) {
aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
aSizes.mDOMEventListenersCount += elm->ListenerCount();
}
// Measurement of the following members may be added later if DMD finds it
@ -12440,10 +12439,12 @@ SizeOfOwnedSheetArrayExcludingThis(const nsTArray<RefPtr<StyleSheet>>& aSheets,
return n;
}
size_t
nsDocument::SizeOfExcludingThis(SizeOfState& aState) const
void
nsDocument::AddSizeOfExcludingThis(SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
// This SizeOfExcludingThis() overrides the one from nsINode. But
// This AddSizeOfExcludingThis() overrides the one from nsINode. But
// nsDocuments can only appear at the top of the DOM tree, and we use the
// specialized DocAddSizeOfExcludingThis() in that case. So this should never
// be called.
@ -12453,40 +12454,48 @@ nsDocument::SizeOfExcludingThis(SizeOfState& aState) const
void
nsDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const
{
nsIDocument::DocAddSizeOfExcludingThis(aWindowSizes);
for (nsIContent* node = nsINode::GetFirstChild();
node;
node = node->GetNextNode(this))
{
size_t nodeSize = node->SizeOfIncludingThis(aWindowSizes.mState);
size_t* p;
size_t nodeSize = 0;
node->AddSizeOfIncludingThis(aWindowSizes.mState, aWindowSizes.mStyleSizes,
&nodeSize);
// This is where we transfer the nodeSize obtained from
// nsINode::AddSizeOfIncludingThis() to a value in nsWindowSizes.
switch (node->NodeType()) {
case nsIDOMNode::ELEMENT_NODE:
p = &aWindowSizes.mDOMElementNodesSize;
aWindowSizes.mDOMElementNodesSize += nodeSize;
break;
case nsIDOMNode::TEXT_NODE:
p = &aWindowSizes.mDOMTextNodesSize;
aWindowSizes.mDOMTextNodesSize += nodeSize;
break;
case nsIDOMNode::CDATA_SECTION_NODE:
p = &aWindowSizes.mDOMCDATANodesSize;
aWindowSizes.mDOMCDATANodesSize += nodeSize;
break;
case nsIDOMNode::COMMENT_NODE:
p = &aWindowSizes.mDOMCommentNodesSize;
aWindowSizes.mDOMCommentNodesSize += nodeSize;
break;
default:
p = &aWindowSizes.mDOMOtherSize;
aWindowSizes.mDOMOtherSize += nodeSize;
break;
}
*p += nodeSize;
if (EventListenerManager* elm = node->GetExistingListenerManager()) {
aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
}
}
// IMPORTANT: for our ComputedValues measurements, we want to measure
// ComputedValues accessible from DOM elements before ComputedValues not
// accessible from DOM elements (i.e. accessible only from the frame tree).
//
// Therefore, the measurement of the nsIDocument superclass must happen after
// the measurement of DOM nodes (above), because nsIDocument contains the
// PresShell, which contains the frame tree.
nsIDocument::DocAddSizeOfExcludingThis(aWindowSizes);
aWindowSizes.mStyleSheetsSize +=
SizeOfOwnedSheetArrayExcludingThis(mStyleSheets,
aWindowSizes.mState.mMallocSizeOf);

Просмотреть файл

@ -367,7 +367,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_SIZEOF_EXCLUDING_THIS
NS_DECL_ADDSIZEOFEXCLUDINGTHIS
virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup) override;
virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,

Просмотреть файл

@ -1109,11 +1109,12 @@ nsGenericDOMDataNode::GetAttributeChangeHint(const nsIAtom* aAttribute,
return nsChangeHint(0);
}
size_t
nsGenericDOMDataNode::SizeOfExcludingThis(SizeOfState& aState) const
void
nsGenericDOMDataNode::AddSizeOfExcludingThis(SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
size_t n = nsIContent::SizeOfExcludingThis(aState);
n += mText.SizeOfExcludingThis(aState.mMallocSizeOf);
return n;
nsIContent::AddSizeOfExcludingThis(aState, aSizes, aNodeSize);
*aNodeSize += mText.SizeOfExcludingThis(aState.mMallocSizeOf);
}

Просмотреть файл

@ -67,7 +67,7 @@ class nsGenericDOMDataNode : public nsIContent
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_SIZEOF_EXCLUDING_THIS
NS_DECL_ADDSIZEOFEXCLUDINGTHIS
explicit nsGenericDOMDataNode(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
explicit nsGenericDOMDataNode(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);

Просмотреть файл

@ -2569,13 +2569,13 @@ nsINode::GetAccessibleNode()
return nullptr;
}
size_t
nsINode::SizeOfExcludingThis(SizeOfState& aState) const
void
nsINode::AddSizeOfExcludingThis(SizeOfState& aState, nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
size_t n = 0;
EventListenerManager* elm = GetExistingListenerManager();
if (elm) {
n += elm->SizeOfIncludingThis(aState.mMallocSizeOf);
*aNodeSize += elm->SizeOfIncludingThis(aState.mMallocSizeOf);
}
// Measurement of the following members may be added later if DMD finds it is
@ -2586,7 +2586,6 @@ nsINode::SizeOfExcludingThis(SizeOfState& aState) const
// The following members are not measured:
// - mParent, mNextSibling, mPreviousSibling, mFirstChild: because they're
// non-owning
return n;
}
#define EVENT(name_, id_, type_, struct_) \

Просмотреть файл

@ -17,9 +17,9 @@
#include "nsNodeInfoManager.h" // for use in NodePrincipal()
#include "nsPropertyTable.h" // for typedefs
#include "nsTObserverArray.h" // for member
#include "nsWindowSizes.h" // for nsStyleSizes
#include "mozilla/ErrorResult.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/SizeOfState.h" // for SizeOfState
#include "mozilla/dom/EventTarget.h" // for base class
#include "js/TypeDecls.h" // for Handle, Value, JSObject, JSContext
#include "mozilla/dom/DOMString.h"
@ -264,13 +264,13 @@ private:
};
// This should be used for any nsINode sub-class that has fields of its own
// that it needs to measure; any sub-class that doesn't use it will inherit
// SizeOfExcludingThis from its super-class. SizeOfIncludingThis() need not be
// defined, it is inherited from nsINode.
// This macro isn't actually specific to nodes, and bug 956400 will move it into MFBT.
#define NS_DECL_SIZEOF_EXCLUDING_THIS \
virtual size_t SizeOfExcludingThis(mozilla::SizeOfState& aState) \
const override;
// that it needs to measure; any sub-class that doesn't use it will inherit
// AddSizeOfExcludingThis from its super-class. AddSizeOfIncludingThis() need
// not be defined, it is inherited from nsINode.
#define NS_DECL_ADDSIZEOFEXCLUDINGTHIS \
virtual void AddSizeOfExcludingThis(mozilla::SizeOfState& aState, \
nsStyleSizes& aSizes, \
size_t* aNodeSize) const override;
// Categories of node properties
// 0 is global.
@ -305,6 +305,10 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)
// The |aNodeSize| outparam on this function is where the actual node size
// value is put. It gets added to the appropriate value within |aSizes| by
// nsDocument::DocAddSizeOfExcludingThis().
//
// Among the sub-classes that inherit (directly or indirectly) from nsINode,
// measurement of the following members may be added later if DMD finds it is
// worthwhile:
@ -328,15 +332,20 @@ public:
// The following members don't need to be measured:
// - nsIContent: mPrimaryFrame, because it's non-owning and measured elsewhere
//
virtual size_t SizeOfExcludingThis(mozilla::SizeOfState& aState) const;
virtual void AddSizeOfExcludingThis(mozilla::SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const;
// SizeOfIncludingThis doesn't need to be overridden by sub-classes because
// sub-classes of nsINode are guaranteed to be laid out in memory in such a
// way that |this| points to the start of the allocated object, even in
// methods of nsINode's sub-classes, so aState.mMallocSizeOf(this) is always
// safe to call no matter which object it was invoked on.
virtual size_t SizeOfIncludingThis(mozilla::SizeOfState& aState) const {
return aState.mMallocSizeOf(this) + SizeOfExcludingThis(aState);
virtual void AddSizeOfIncludingThis(mozilla::SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const {
*aNodeSize += aState.mMallocSizeOf(this);
AddSizeOfExcludingThis(aState, aSizes, aNodeSize);
}
friend class nsNodeUtils;

Просмотреть файл

@ -384,7 +384,7 @@ CollectWindowReports(nsGlobalWindow *aWindow,
aWindowTotalSizes->mArenaSizes.mStyleContexts
+= windowSizes.mArenaSizes.mStyleContexts;
REPORT_SIZE("/layout/style-structs", windowSizes.mArenaSizes.mStyleStructs,
REPORT_SIZE("/layout/gecko-style-structs", windowSizes.mArenaSizes.mStyleStructs,
"Memory used by style structs within a window.");
aWindowTotalSizes->mArenaSizes.mStyleStructs
+= windowSizes.mArenaSizes.mStyleStructs;
@ -429,19 +429,17 @@ CollectWindowReports(nsGlobalWindow *aWindow,
js::MemoryReportingSundriesThreshold();
size_t frameSundriesSize = 0;
#define FRAME_ID(classname, ...) \
{ \
size_t frameSize \
= windowSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(classname); \
if (frameSize < FRAME_SUNDRIES_THRESHOLD) { \
frameSundriesSize += frameSize; \
} else { \
REPORT_SIZE("/layout/frames/" # classname, frameSize, \
"Memory used by frames of " \
"type " #classname " within a window."); \
} \
aWindowTotalSizes->mArenaSizes.NS_ARENA_SIZES_FIELD(classname) \
+= frameSize; \
#define FRAME_ID(classname, ...) \
{ \
size_t size = windowSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(classname); \
if (size < FRAME_SUNDRIES_THRESHOLD) { \
frameSundriesSize += size; \
} else { \
REPORT_SIZE("/layout/frames/" # classname, size, \
"Memory used by frames of " \
"type " #classname " within a window."); \
} \
aWindowTotalSizes->mArenaSizes.NS_ARENA_SIZES_FIELD(classname) += size; \
}
#define ABSTRACT_FRAME_ID(...)
#include "nsFrameIdList.h"
@ -454,6 +452,50 @@ CollectWindowReports(nsGlobalWindow *aWindow,
"to be shown individually.");
}
// There are many different kinds of style structs, but it is likely that
// only a few matter. Implement a cutoff so we don't bloat about:memory with
// many uninteresting entries.
const size_t STYLE_SUNDRIES_THRESHOLD =
js::MemoryReportingSundriesThreshold();
size_t styleSundriesSize = 0;
#define STYLE_STRUCT(name_, cb_) \
{ \
size_t size = windowSizes.mStyleSizes.NS_STYLE_SIZES_FIELD(name_); \
if (size < STYLE_SUNDRIES_THRESHOLD) { \
styleSundriesSize += size; \
} else { \
REPORT_SIZE("/layout/servo-style-structs/" # name_, size, \
"Memory used by the " #name_ " Servo style structs " \
"within a window."); \
} \
aWindowTotalSizes->mStyleSizes.NS_STYLE_SIZES_FIELD(name_) += size; \
}
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
if (styleSundriesSize > 0) {
REPORT_SIZE("/layout/servo-style-structs/sundries", styleSundriesSize,
"The sum of all memory used by Servo style structs which were "
"too small to be shown individually.");
}
REPORT_SIZE("/layout/computed-values/dom",
windowSizes.mStyleSizes.mComputedValuesDom,
"Memory used by ComputedValues objects accessible from DOM "
"elements.");
aWindowTotalSizes->mStyleSizes.mComputedValuesDom +=
windowSizes.mStyleSizes.mComputedValuesDom;
REPORT_SIZE("/layout/computed-values/non-dom",
windowSizes.mStyleSizes.mComputedValuesNonDom,
"Memory used by ComputedValues objects not accessible from DOM "
"elements.");
aWindowTotalSizes->mStyleSizes.mComputedValuesNonDom +=
windowSizes.mStyleSizes.mComputedValuesNonDom;
#undef REPORT_SIZE
#undef REPORT_COUNT
}
@ -575,9 +617,9 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
windowTotalSizes.mArenaSizes.mStyleContexts,
"This is the sum of all windows' 'layout/style-contexts' numbers.");
REPORT("window-objects/layout/style-structs",
REPORT("window-objects/layout/gecko-style-structs",
windowTotalSizes.mArenaSizes.mStyleStructs,
"This is the sum of all windows' 'layout/style-structs' numbers.");
"This is the sum of all windows' 'layout/gecko-style-structs' numbers.");
REPORT("window-objects/layout/style-sets", windowTotalSizes.mLayoutStyleSetsSize,
"This is the sum of all windows' 'layout/style-sets' numbers.");
@ -603,6 +645,24 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
"Memory used for layout frames within windows. "
"This is the sum of all windows' 'layout/frames/' numbers.");
size_t styleTotal = 0;
#define STYLE_STRUCT(name_, cb_) \
styleTotal += windowTotalSizes.mStyleSizes.NS_STYLE_SIZES_FIELD(name_);
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
REPORT("window-objects/layout/servo-style-structs", styleTotal,
"Memory used for style structs within windows. This is the sum of "
"all windows' 'layout/servo-style-structs/' numbers.");
REPORT("window-objects/layout/computed-values",
windowTotalSizes.mStyleSizes.mComputedValuesDom +
windowTotalSizes.mStyleSizes.mComputedValuesNonDom,
"This is the sum of all windows' 'layout/computed-values/' "
"numbers.");
#undef REPORT
return NS_OK;

Просмотреть файл

@ -36,6 +36,11 @@ public:
size_t mOther;
};
#define ZERO_SIZE(kind, mSize) mSize(0),
#define ADD_TO_TAB_SIZES(kind, mSize) aSizes->add(nsTabSizes::kind, mSize);
#define ADD_TO_TOTAL_SIZE(kind, mSize) total += mSize;
#define DECL_SIZE(kind, mSize) size_t mSize;
#define NS_ARENA_SIZES_FIELD(classname) mArena##classname
struct nsArenaSizes {
@ -47,24 +52,24 @@ struct nsArenaSizes {
nsArenaSizes()
:
#define ZERO_SIZE(kind, mSize) mSize(0),
FOR_EACH_SIZE(ZERO_SIZE)
#undef ZERO_SIZE
#define FRAME_ID(classname, ...) NS_ARENA_SIZES_FIELD(classname)(),
#define FRAME_ID(classname, ...) \
NS_ARENA_SIZES_FIELD(classname)(0),
#define ABSTRACT_FRAME_ID(...)
#include "nsFrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
dummy()
{}
void addToTabSizes(nsTabSizes *sizes) const
void addToTabSizes(nsTabSizes* aSizes) const
{
#define ADD_TO_TAB_SIZES(kind, mSize) sizes->add(nsTabSizes::kind, mSize);
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
#undef ADD_TO_TAB_SIZES
#define FRAME_ID(classname, ...) \
sizes->add(nsTabSizes::Other, NS_ARENA_SIZES_FIELD(classname));
aSizes->add(nsTabSizes::Other, NS_ARENA_SIZES_FIELD(classname));
#define ABSTRACT_FRAME_ID(...)
#include "nsFrameIdList.h"
#undef FRAME_ID
@ -74,28 +79,95 @@ struct nsArenaSizes {
size_t getTotalSize() const
{
size_t total = 0;
#define ADD_TO_TOTAL_SIZE(kind, mSize) total += mSize;
FOR_EACH_SIZE(ADD_TO_TOTAL_SIZE)
#undef ADD_TO_TOTAL_SIZE
#define FRAME_ID(classname, ...) \
total += NS_ARENA_SIZES_FIELD(classname);
#define ABSTRACT_FRAME_ID(...)
#include "nsFrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
return total;
}
#define DECL_SIZE(kind, mSize) size_t mSize;
FOR_EACH_SIZE(DECL_SIZE)
#undef DECL_SIZE
#define FRAME_ID(classname, ...) size_t NS_ARENA_SIZES_FIELD(classname);
#define FRAME_ID(classname, ...) \
size_t NS_ARENA_SIZES_FIELD(classname);
#define ABSTRACT_FRAME_ID(...)
#include "nsFrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
int dummy; // present just to absorb the trailing comma from FRAME_ID in the
// constructor
// Present just to absorb the trailing comma in the constructor.
int dummy;
#undef FOR_EACH_SIZE
};
#define NS_STYLE_SIZES_FIELD(name_) mStyle##name_
struct nsStyleSizes
{
#define FOR_EACH_SIZE(macro) \
macro(Style, mComputedValuesDom) \
macro(Style, mComputedValuesNonDom)
nsStyleSizes()
:
FOR_EACH_SIZE(ZERO_SIZE)
#define STYLE_STRUCT(name_, cb_) \
NS_STYLE_SIZES_FIELD(name_)(0),
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
dummy()
{}
void addToTabSizes(nsTabSizes* aSizes) const
{
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
#define STYLE_STRUCT(name_, cb_) \
aSizes->add(nsTabSizes::Style, NS_STYLE_SIZES_FIELD(name_));
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
}
size_t getTotalSize() const
{
size_t total = 0;
FOR_EACH_SIZE(ADD_TO_TOTAL_SIZE)
#define STYLE_STRUCT(name_, cb_) \
total += NS_STYLE_SIZES_FIELD(name_);
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
return total;
}
FOR_EACH_SIZE(DECL_SIZE)
#define STYLE_STRUCT(name_, cb_) \
size_t NS_STYLE_SIZES_FIELD(name_);
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
// Present just to absorb the trailing comma in the constructor.
int dummy;
#undef FOR_EACH_SIZE
};
@ -122,43 +194,50 @@ class nsWindowSizes
public:
explicit nsWindowSizes(mozilla::SizeOfState& aState)
:
#define ZERO_SIZE(kind, mSize) mSize(0),
FOR_EACH_SIZE(ZERO_SIZE)
#undef ZERO_SIZE
mDOMEventTargetsCount(0),
mDOMEventListenersCount(0),
mArenaSizes(),
mStyleSizes(),
mState(aState)
{}
void addToTabSizes(nsTabSizes *sizes) const {
#define ADD_TO_TAB_SIZES(kind, mSize) sizes->add(nsTabSizes::kind, mSize);
void addToTabSizes(nsTabSizes* aSizes) const {
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
#undef ADD_TO_TAB_SIZES
mArenaSizes.addToTabSizes(sizes);
mArenaSizes.addToTabSizes(aSizes);
mStyleSizes.addToTabSizes(aSizes);
}
size_t getTotalSize() const
{
size_t total = 0;
#define ADD_TO_TOTAL_SIZE(kind, mSize) total += mSize;
FOR_EACH_SIZE(ADD_TO_TOTAL_SIZE)
#undef ADD_TO_TOTAL_SIZE
total += mArenaSizes.getTotalSize();
total += mStyleSizes.getTotalSize();
return total;
}
#define DECL_SIZE(kind, mSize) size_t mSize;
FOR_EACH_SIZE(DECL_SIZE);
#undef DECL_SIZE
uint32_t mDOMEventTargetsCount;
uint32_t mDOMEventListenersCount;
nsArenaSizes mArenaSizes;
// This is Stylo-only because in Gecko these style structs are stored in the
// nsPresArena, and so are measured as part of that.
nsStyleSizes mStyleSizes;
mozilla::SizeOfState& mState;
#undef FOR_EACH_SIZE
};
#undef ZERO_SIZE
#undef ADD_TO_TAB_SIZES
#undef ADD_TO_TOTAL_SIZE
#undef DECL_SIZE
#endif // nsWindowSizes_h

Просмотреть файл

@ -405,11 +405,13 @@ HTMLAnchorElement::IntrinsicState() const
return Link::LinkState() | nsGenericHTMLElement::IntrinsicState();
}
size_t
HTMLAnchorElement::SizeOfExcludingThis(mozilla::SizeOfState& aState) const
void
HTMLAnchorElement::AddSizeOfExcludingThis(SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
return nsGenericHTMLElement::SizeOfExcludingThis(aState) +
Link::SizeOfExcludingThis(aState);
nsGenericHTMLElement::AddSizeOfExcludingThis(aState, aSizes, aNodeSize);
*aNodeSize += Link::SizeOfExcludingThis(aState);
}
} // namespace dom

Просмотреть файл

@ -48,8 +48,7 @@ public:
// nsIDOMHTMLAnchorElement
NS_DECL_NSIDOMHTMLANCHORELEMENT
// DOM memory reporter participant
NS_DECL_SIZEOF_EXCLUDING_THIS
NS_DECL_ADDSIZEOFEXCLUDINGTHIS
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,

Просмотреть файл

@ -219,11 +219,13 @@ HTMLAreaElement::IntrinsicState() const
return Link::LinkState() | nsGenericHTMLElement::IntrinsicState();
}
size_t
HTMLAreaElement::SizeOfExcludingThis(mozilla::SizeOfState& aState) const
void
HTMLAreaElement::AddSizeOfExcludingThis(SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
return nsGenericHTMLElement::SizeOfExcludingThis(aState) +
Link::SizeOfExcludingThis(aState);
nsGenericHTMLElement::AddSizeOfExcludingThis(aState, aSizes, aNodeSize);
*aNodeSize += Link::SizeOfExcludingThis(aState);
}
JSObject*

Просмотреть файл

@ -36,8 +36,7 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLAreaElement,
nsGenericHTMLElement)
// DOM memory reporter participant
NS_DECL_SIZEOF_EXCLUDING_THIS
NS_DECL_ADDSIZEOFEXCLUDINGTHIS
virtual int32_t TabIndexDefault() override;

Просмотреть файл

@ -508,11 +508,13 @@ HTMLLinkElement::IntrinsicState() const
return Link::LinkState() | nsGenericHTMLElement::IntrinsicState();
}
size_t
HTMLLinkElement::SizeOfExcludingThis(mozilla::SizeOfState& aState) const
void
HTMLLinkElement::AddSizeOfExcludingThis(SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
return nsGenericHTMLElement::SizeOfExcludingThis(aState) +
Link::SizeOfExcludingThis(aState);
nsGenericHTMLElement::AddSizeOfExcludingThis(aState, aSizes, aNodeSize);
*aNodeSize += Link::SizeOfExcludingThis(aState);
}
JSObject*

Просмотреть файл

@ -36,8 +36,7 @@ public:
// nsIDOMHTMLLinkElement
NS_DECL_NSIDOMHTMLLINKELEMENT
// DOM memory reporter participant
NS_DECL_SIZEOF_EXCLUDING_THIS
NS_DECL_ADDSIZEOFEXCLUDINGTHIS
void LinkAdded();
void LinkRemoved();

Просмотреть файл

@ -45,11 +45,13 @@ SVGPathElement::SVGPathElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeIn
//----------------------------------------------------------------------
// memory reporting methods
size_t
SVGPathElement::SizeOfExcludingThis(mozilla::SizeOfState& aState) const
void
SVGPathElement::AddSizeOfExcludingThis(SizeOfState& aState,
nsStyleSizes& aSizes,
size_t* aNodeSize) const
{
return SVGPathElementBase::SizeOfExcludingThis(aState) +
mD.SizeOfExcludingThis(aState.mMallocSizeOf);
SVGPathElementBase::AddSizeOfExcludingThis(aState, aSizes, aNodeSize);
*aNodeSize += mD.SizeOfExcludingThis(aState.mMallocSizeOf);
}
//----------------------------------------------------------------------

Просмотреть файл

@ -35,8 +35,7 @@ protected:
explicit SVGPathElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
public:
// DOM memory reporter participant
NS_DECL_SIZEOF_EXCLUDING_THIS
NS_DECL_ADDSIZEOFEXCLUDINGTHIS
// nsIContent interface
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const override;

Просмотреть файл

@ -2121,16 +2121,6 @@ MOZ_DEFINE_MALLOC_SIZE_OF(OrphanMallocSizeOf)
namespace xpc {
static size_t
SizeOfTreeIncludingThis(nsINode* tree, SizeOfState& aState)
{
size_t n = tree->SizeOfIncludingThis(aState);
for (nsIContent* child = tree->GetFirstChild(); child; child = child->GetNextNode(tree))
n += child->SizeOfIncludingThis(aState);
return n;
}
class OrphanReporter : public JS::ObjectPrivateVisitor
{
public:
@ -2154,12 +2144,28 @@ class OrphanReporter : public JS::ObjectPrivateVisitor
// and then record its root so we don't measure it again.
nsCOMPtr<nsINode> orphanTree = node->SubtreeRoot();
if (orphanTree && !mState.HaveSeenPtr(orphanTree.get())) {
n += SizeOfTreeIncludingThis(orphanTree, mState);
n += SizeOfTreeIncludingThis(orphanTree);
}
}
return n;
}
size_t SizeOfTreeIncludingThis(nsINode* tree)
{
size_t nodeSize = 0;
nsStyleSizes sizes;
tree->AddSizeOfIncludingThis(mState, sizes, &nodeSize);
for (nsIContent* child = tree->GetFirstChild(); child; child = child->GetNextNode(tree))
child->AddSizeOfIncludingThis(mState, sizes, &nodeSize);
// We combine the node size with nsStyleSizes here. It's not ideal, but
// it's hard to get the style structs measurements out to
// nsWindowMemoryReporter. Also, we drop mServoData in
// UnbindFromTree(), so in theory any non-in-tree element won't have
// any style data to measure.
return nodeSize + sizes.getTotalSize();
}
private:
SizeOfState mState;
};

Просмотреть файл

@ -11045,8 +11045,7 @@ PresShell::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
if (rootFrame) {
aSizes.mLayoutFramePropertiesSize +=
rootFrame->SizeOfFramePropertiesForTree(mallocSizeOf);
rootFrame->AddSizeOfExcludingThisForTree(aSizes);
}
}

Просмотреть файл

@ -10701,22 +10701,29 @@ nsFrame::HasCSSTransitions()
return collection && collection->mAnimations.Length() > 0;
}
size_t
nsIFrame::SizeOfFramePropertiesForTree(MallocSizeOf aMallocSizeOf) const
void
nsIFrame::AddSizeOfExcludingThisForTree(nsWindowSizes& aSizes) const
{
size_t result = 0;
aSizes.mLayoutFramePropertiesSize +=
mProperties.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
result += mProperties.SizeOfExcludingThis(aMallocSizeOf);
// We don't do this for Gecko because this stuff is stored in the nsPresArena
// and so measured elsewhere.
if (mStyleContext->IsServo()) {
ServoStyleContext* sc = mStyleContext->AsServo();
if (!aSizes.mState.HaveSeenPtr(sc)) {
sc->AddSizeOfIncludingThis(aSizes.mState, aSizes.mStyleSizes,
/* isDOM = */ false);
}
}
FrameChildListIterator iter(this);
while (!iter.IsDone()) {
for (const nsIFrame* f : iter.CurrentList()) {
result += f->SizeOfFramePropertiesForTree(aMallocSizeOf);
f->AddSizeOfExcludingThisForTree(aSizes);
}
iter.Next();
}
return result;
}
// Box layout debugging

Просмотреть файл

@ -88,6 +88,7 @@ class nsIContent;
class nsContainerFrame;
class nsPlaceholderFrame;
class nsStyleChangeList;
class nsWindowSizes;
struct nsPeekOffsetStruct;
struct nsPoint;
@ -3541,8 +3542,10 @@ public:
mProperties.DeleteAll(this);
}
// Reports size of the FrameProperties for this frame and its descendants
size_t SizeOfFramePropertiesForTree(mozilla::MallocSizeOf aMallocSizeOf) const;
// nsIFrames themselves are in the nsPresArena, and so are not measured here.
// Instead, this measures heap-allocated things hanging off the nsIFrame, and
// likewise for its descendants.
void AddSizeOfExcludingThisForTree(nsWindowSizes& aWindowSizes) const;
/**
* Return true if and only if this frame obeys visibility:hidden.

Просмотреть файл

@ -20,8 +20,19 @@
// Element data
SERVO_BINDING_FUNC(Servo_Element_ClearData, void, RawGeckoElementBorrowed node)
SERVO_BINDING_FUNC(Servo_Element_SizeOfExcludingThis, size_t, mozilla::MallocSizeOf,
mozilla::SeenPtrs* seen_ptrs, RawGeckoElementBorrowed node)
SERVO_BINDING_FUNC(Servo_Element_SizeOfExcludingThisAndCVs, size_t,
mozilla::MallocSizeOf, mozilla::SeenPtrs* seen_ptrs,
RawGeckoElementBorrowed node)
SERVO_BINDING_FUNC(Servo_Element_HasPrimaryComputedValues, bool,
RawGeckoElementBorrowed node)
SERVO_BINDING_FUNC(Servo_Element_GetPrimaryComputedValues,
ServoStyleContextStrong,
RawGeckoElementBorrowed node)
SERVO_BINDING_FUNC(Servo_Element_HasPseudoComputedValues, bool,
RawGeckoElementBorrowed node, size_t index)
SERVO_BINDING_FUNC(Servo_Element_GetPseudoComputedValues,
ServoStyleContextStrong,
RawGeckoElementBorrowed node, size_t index)
// Styleset and Stylesheet management
SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetContentsStrong,

Просмотреть файл

@ -235,6 +235,46 @@ ServoComputedData::GetStyleVariables() const
"called");
}
MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleStructsMallocSizeOf)
void
ServoComputedData::AddSizeOfExcludingThis(SizeOfState& aState,
nsStyleSizes& aSizes) const
{
// XXX WARNING: GetStyleFoo() returns an nsStyleFoo pointer. This nsStyleFoo
// sits within a servo_arc::Arc, i.e. it is preceded by a word-sized
// refcount. So this pointer is an interior pointer. To get the start address
// of the heap block we move the pointer back by one word. For this to work,
// two things must be true.
//
// - The layout of servo_arc::Arc must stay the same.
//
// - The alignment of each nsStyleFoo must not be greater than the size of a
// word (otherwise padding might be inserted between the refcount and the
// struct in the servo_arc::Arc).
//
// In the long run a better solution here is for mozjemalloc to provide a
// function that converts an interior pointer to a start pointer (bug
// 1389305), but that's not available right now.
//
// Also, we use ServoStyleStructsMallocSizeOf rather than
// |aState.mMallocSizeOf| to better distinguish in DMD's output the memory
// measured here.
#define STYLE_STRUCT(name_, cb_) \
static_assert(alignof(nsStyle##name_) <= sizeof(size_t), \
"alignment will break AddSizeOfExcludingThis()"); \
const char* p##name_ = reinterpret_cast<const char*>(GetStyle##name_()); \
p##name_ -= sizeof(size_t); \
if (!aState.HaveSeenPtr(p##name_)) { \
aSizes.NS_STYLE_SIZES_FIELD(name_) += \
ServoStyleStructsMallocSizeOf(p##name_); \
}
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
}
void
Gecko_ServoStyleContext_Destroy(ServoStyleContext* aContext)
{

Просмотреть файл

@ -7,7 +7,10 @@
#ifndef mozilla_ServoStyleContext_h
#define mozilla_ServoStyleContext_h
#include "nsIMemoryReporter.h"
#include "nsStyleContext.h"
#include "nsWindowSizes.h"
#include <algorithm>
namespace mozilla {
@ -15,6 +18,8 @@ namespace dom {
class Element;
} // namespace dom
MOZ_DEFINE_MALLOC_SIZE_OF(ServoComputedValuesMallocSizeOf)
class ServoStyleContext final : public nsStyleContext
{
public:
@ -95,6 +100,29 @@ public:
*/
inline void ResolveSameStructsAs(const ServoStyleContext* aOther);
void AddSizeOfIncludingThis(SizeOfState& aState, nsStyleSizes& aSizes,
bool aIsDOM) const
{
// XXX WARNING: similar to ServoComputedData::AddSizeOfExcludingThis(),
// but here we need to step back 4 or 8 bytes to get past the servo_arc::Arc
// refcount to the base pointer.
static_assert(alignof(ServoStyleContext) == 4 ||
alignof(ServoStyleContext) == 8,
"alignment will break AddSizeOfExcludingThis()");
const char* p = reinterpret_cast<const char*>(this);
p -= std::max(sizeof(size_t), alignof(ServoStyleContext));
// We use ServoComputedValuesMallocSizeOf rather than
// |aState.mMallocSizeOf| to better distinguish in DMD's output the memory
// measured here.
if (aIsDOM) {
aSizes.mComputedValuesDom += ServoComputedValuesMallocSizeOf(p);
} else {
aSizes.mComputedValuesNonDom += ServoComputedValuesMallocSizeOf(p);
}
mSource.AddSizeOfExcludingThis(aState, aSizes);
}
private:
nsPresContext* mPresContext;
ServoComputedData mSource;

Просмотреть файл

@ -18,9 +18,12 @@
* so don't add significant include dependencies to this file.
*/
struct nsStyleSizes;
struct ServoNodeData;
namespace mozilla {
class SizeOfState;
/*
* Replaced types. These get mapped to associated Servo types in bindgen.
*/
@ -230,6 +233,9 @@ public:
#undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
const nsStyleVariables* GetStyleVariables() const;
void AddSizeOfExcludingThis(mozilla::SizeOfState& aState,
nsStyleSizes& aSizes) const;
private:
mozilla::ServoCustomPropertiesMap custom_properties;
mozilla::ServoWritingMode writing_mode;

Просмотреть файл

@ -87,6 +87,9 @@ public:
static bool IsCSS2PseudoElement(nsIAtom *aAtom);
// This must match EAGER_PSEUDO_COUNT in Rust code.
static const size_t kEagerPseudoCount = 4;
static bool IsEagerlyCascadedInServo(const Type aType)
{
return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_IS_CSS2);

Просмотреть файл

@ -1677,7 +1677,9 @@ ReportHelper(const void* aPtr, bool aReportedOnAlloc)
} else {
// We have no record of the block. It must be a bogus pointer. This should
// be extremely rare because Report() is almost always called in
// conjunction with a malloc_size_of-style function.
// conjunction with a malloc_size_of-style function. Print a message so
// that we get some feedback.
StatusMsg("Unknown pointer %p\n", aPtr);
}
}