Global Metrics
path: .metrics.mi.mi_sei
old: 22.890477867599735
new: -20.106512789302787
path: .metrics.mi.mi_original
old: 36.4251273767445
new: 25.011851586450845
path: .metrics.mi.mi_visual_studio
old: 21.301244079967542
new: 14.626813793246107
path: .metrics.halstead.volume
old: 3231.3909820522326
new: 7795.941977063929
path: .metrics.halstead.length
old: 499.0
new: 1033.0
path: .metrics.halstead.time
old: 8130.596664518521
new: 16614.347511597916
path: .metrics.halstead.n1
old: 27.0
new: 29.0
path: .metrics.halstead.vocabulary
old: 89.0
new: 187.0
path: .metrics.halstead.effort
old: 146350.73996133337
new: 299058.2552087625
path: .metrics.halstead.N1
old: 291.0
new: 615.0
path: .metrics.halstead.purity_ratio
old: 0.9970784244537072
new: 1.25351288196581
path: .metrics.halstead.N2
old: 208.0
new: 418.0
path: .metrics.halstead.difficulty
old: 45.29032258064516
new: 38.36075949367088
path: .metrics.halstead.bugs
old: 0.9257108635252772
new: 1.4906737668451473
path: .metrics.halstead.estimated_program_length
old: 497.5421338023999
new: 1294.878807070682
path: .metrics.halstead.level
old: 0.02207977207977208
new: 0.02606830556013859
path: .metrics.halstead.n2
old: 62.0
new: 158.0
path: .metrics.nom.functions
old: 6.0
new: 14.0
path: .metrics.nom.total
old: 6.0
new: 18.0
path: .metrics.nom.closures
old: 0.0
new: 4.0
path: .metrics.cyclomatic.average
old: 2.857142857142857
new: 2.0
path: .metrics.cyclomatic.sum
old: 20.0
new: 36.0
path: .metrics.loc.ploc
old: 106.0
new: 215.0
path: .metrics.loc.sloc
old: 228.0
new: 277.0
path: .metrics.loc.cloc
old: 110.0
new: 12.0
path: .metrics.loc.blank
old: 12.0
new: 50.0
path: .metrics.loc.lloc
old: 31.0
new: 82.0
path: .metrics.nargs.sum
old: 33.0
new: 14.0
path: .metrics.nargs.average
old: 5.5
new: 0.7777777777777778
path: .metrics.cognitive.average
old: 3.1666666666666665
new: 1.2222222222222223
path: .metrics.cognitive.sum
old: 19.0
new: 22.0
path: .metrics.nexits.average
old: 1.3333333333333333
new: 0.3333333333333333
path: .metrics.nexits.sum
old: 8.0
new: 6.0
Spaces Data
Minimal test - lines (21, 277)
path: .spaces[0].metrics.nom.closures
old: 0.0
new: 4.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 14.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 18.0
path: .spaces[0].metrics.mi.mi_original
old: 109.32690234865424
new: 26.603424725710894
path: .spaces[0].metrics.mi.mi_visual_studio
old: 63.933861022604816
new: 15.557558319129177
path: .spaces[0].metrics.mi.mi_sei
old: 108.26538255658764
new: -22.031296693380508
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 14.0
path: .spaces[0].metrics.nargs.average
old: 0.0
new: 0.7777777777777778
path: .spaces[0].metrics.cyclomatic.sum
old: 2.0
new: 35.0
path: .spaces[0].metrics.cyclomatic.average
old: 2.0
new: 2.0588235294117645
path: .spaces[0].metrics.loc.cloc
old: 1.0
new: 6.0
path: .spaces[0].metrics.loc.lloc
old: 3.0
new: 82.0
path: .spaces[0].metrics.loc.sloc
old: 8.0
new: 257.0
path: .spaces[0].metrics.loc.ploc
old: 8.0
new: 203.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 48.0
path: .spaces[0].metrics.cognitive.average
old: 1.0
new: 1.2222222222222223
path: .spaces[0].metrics.cognitive.sum
old: 1.0
new: 22.0
path: .spaces[0].metrics.nexits.average
old: 1.0
new: 0.3333333333333333
path: .spaces[0].metrics.nexits.sum
old: 1.0
new: 6.0
path: .spaces[0].metrics.halstead.n2
old: 10.0
new: 146.0
path: .spaces[0].metrics.halstead.time
old: 129.37387194323057
new: 16975.26239429908
path: .spaces[0].metrics.halstead.volume
old: 199.03672606650855
new: 7577.881700733478
path: .spaces[0].metrics.halstead.estimated_program_length
old: 81.32499728470782
new: 1190.595834455182
path: .spaces[0].metrics.halstead.n1
old: 13.0
new: 29.0
path: .spaces[0].metrics.halstead.N1
old: 26.0
new: 611.0
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.8482953928342687
new: 1.1706940358458031
path: .spaces[0].metrics.halstead.length
old: 44.0
new: 1017.0
path: .spaces[0].metrics.halstead.vocabulary
old: 23.0
new: 175.0
path: .spaces[0].metrics.halstead.bugs
old: 0.058563200005583176
new: 1.5121843742215806
path: .spaces[0].metrics.halstead.difficulty
old: 11.7
new: 40.321917808219176
path: .spaces[0].metrics.halstead.level
old: 0.08547008547008547
new: 0.02480040767793443
path: .spaces[0].metrics.halstead.N2
old: 18.0
new: 406.0
path: .spaces[0].metrics.halstead.effort
old: 2328.7296949781503
new: 305554.72309738345
Code
namespace mozilla {
static const char* const sMetricNames[] = {"DisplayList Building",
"Rasterizing",
"LayerBuilding",
"Layer Transactions",
"Compositing",
"Reflowing",
"Styling",
"HttpChannelCompletion_Network",
"HttpChannelCompletion_Cache"};
static_assert(sizeof(sMetricNames) / sizeof(sMetricNames[0]) ==
static_cast(PerfStats::Metric::Max));
PerfStats::MetricMask PerfStats::sCollectionMask = 0;
StaticMutex PerfStats::sMutex;
StaticAutoPtr PerfStats::sSingleton;
void PerfStats::SetCollectionMask(MetricMask aMask) {
sCollectionMask = aMask;
for (uint64_t i = 0; i < static_cast(Metric::Max); i++) {
if (!(sCollectionMask & 1 << i)) {
continue;
}
GetSingleton()->mRecordedTimes[i] = 0;
}
if (!XRE_IsParentProcess()) {
return;
}
GPUProcessManager* gpuManager = GPUProcessManager::Get();
GPUChild* gpuChild = nullptr;
if (gpuManager) {
gpuChild = gpuManager->GetGPUChild();
if (gpuChild) {
gpuChild->SendUpdatePerfStatsCollectionMask(aMask);
}
}
nsTArray contentParents;
ContentParent::GetAll(contentParents);
for (ContentParent* parent : contentParents) {
Unused << parent->SendUpdatePerfStatsCollectionMask(aMask);
}
}
PerfStats* PerfStats::GetSingleton() {
if (!sSingleton) {
sSingleton = new PerfStats;
}
return sSingleton.get();
}
void PerfStats::RecordMeasurementStartInternal(Metric aMetric) {
StaticMutexAutoLock lock(sMutex);
GetSingleton()->mRecordedStarts[static_cast(aMetric)] =
TimeStamp::Now();
}
void PerfStats::RecordMeasurementEndInternal(Metric aMetric) {
StaticMutexAutoLock lock(sMutex);
MOZ_ASSERT(sSingleton);
sSingleton->mRecordedTimes[static_cast(aMetric)] +=
(TimeStamp::Now() -
sSingleton->mRecordedStarts[static_cast(aMetric)])
.ToMilliseconds();
}
void PerfStats::RecordMeasurementInternal(Metric aMetric,
TimeDuration aDuration) {
StaticMutexAutoLock lock(sMutex);
MOZ_ASSERT(sSingleton);
sSingleton->mRecordedTimes[static_cast(aMetric)] +=
aDuration.ToMilliseconds();
}
struct StringWriteFunc : public JSONWriteFunc {
nsCString& mString;
explicit StringWriteFunc(nsCString& aString) : mString(aString) {}
virtual void Write(const Span& aStr) override {
mString.Append(aStr);
}
};
void AppendJSONStringAsProperty(nsCString& aDest, const char* aPropertyName,
const nsCString& aJSON) {
// We need to manually append into the string here, since JSONWriter has no
// way to allow us to write an existing JSON object into a property.
aDest.Append(",\n\"");
aDest.Append(aPropertyName);
aDest.Append("\": ");
aDest.Append(aJSON);
}
struct PerfStatsCollector {
PerfStatsCollector() : writer(MakeUnique(string)) {}
void AppendPerfStats(const nsCString& aString, ContentParent* aParent) {
writer.StartObjectElement();
writer.StringProperty("type", "content");
writer.IntProperty("id", aParent->ChildID());
const ManagedContainer& browsers =
aParent->ManagedPBrowserParent();
writer.StartArrayProperty("urls");
for (auto iter = browsers.ConstIter(); !iter.Done(); iter.Next()) {
RefPtr parent =
BrowserParent::GetFrom(iter.Get()->GetKey());
CanonicalBrowsingContext* ctx = parent->GetBrowsingContext();
if (!ctx) {
continue;
}
WindowGlobalParent* windowGlobal = ctx->GetCurrentWindowGlobal();
if (!windowGlobal) {
continue;
}
RefPtr uri = windowGlobal->GetDocumentURI();
if (!uri) {
continue;
}
nsAutoCString url;
uri->GetSpec(url);
writer.StringElement(url);
}
writer.EndArray();
AppendJSONStringAsProperty(string, "perfstats", aString);
writer.EndObject();
}
void AppendPerfStats(const nsCString& aString, GPUChild* aChild) {
writer.StartObjectElement();
writer.StringProperty("type", "gpu");
writer.IntProperty("id", aChild->Id());
AppendJSONStringAsProperty(string, "perfstats", aString);
writer.EndObject();
}
~PerfStatsCollector() {
writer.EndArray();
writer.End();
promise.Resolve(string, __func__);
}
nsCString string;
JSONWriter writer;
MozPromiseHolder promise;
};
auto PerfStats::CollectPerfStatsJSONInternal() -> RefPtr {
if (!PerfStats::sCollectionMask) {
return PerfStatsPromise::CreateAndReject(false, __func__);
}
if (!XRE_IsParentProcess()) {
return PerfStatsPromise::CreateAndResolve(
CollectLocalPerfStatsJSONInternal(), __func__);
}
std::shared_ptr collector =
std::make_shared();
JSONWriter& w = collector->writer;
w.Start();
{
w.StartArrayProperty("processes");
{
w.StartObjectElement();
{
w.StringProperty("type", "parent");
AppendJSONStringAsProperty(collector->string, "perfstats",
CollectLocalPerfStatsJSONInternal());
}
w.EndObject();
GPUProcessManager* gpuManager = GPUProcessManager::Get();
GPUChild* gpuChild = nullptr;
if (gpuManager) {
gpuChild = gpuManager->GetGPUChild();
}
nsTArray contentParents;
ContentParent::GetAll(contentParents);
if (gpuChild) {
gpuChild->SendCollectPerfStatsJSON(
[collector, gpuChild](const nsCString& aString) {
collector->AppendPerfStats(aString, gpuChild);
},
// The only feasible errors here are if something goes wrong in the
// the bridge, we choose to ignore those.
[](mozilla::ipc::ResponseRejectReason) {});
}
for (ContentParent* parent : contentParents) {
RefPtr parentRef = parent;
parent->SendCollectPerfStatsJSON(
[collector, parentRef](const nsCString& aString) {
collector->AppendPerfStats(aString, parentRef.get());
},
// The only feasible errors here are if something goes wrong in the
// the bridge, we choose to ignore those.
[](mozilla::ipc::ResponseRejectReason) {});
}
}
}
return collector->promise.Ensure(__func__);
}
nsCString PerfStats::CollectLocalPerfStatsJSONInternal() {
StaticMutexAutoLock lock(PerfStats::sMutex);
nsCString jsonString;
JSONWriter w(MakeUnique(jsonString));
w.Start();
{
w.StartArrayProperty("metrics");
{
for (uint64_t i = 0; i < static_cast(Metric::Max); i++) {
if (!(sCollectionMask & (1 << i))) {
continue;
}
w.StartObjectElement();
{
w.IntProperty("id", i);
w.StringProperty("metric", MakeStringSpan(sMetricNames[i]));
w.DoubleProperty("time", mRecordedTimes[i]);
}
w.EndObject();
}
}
w.EndArray();
}
w.End();
return jsonString;
}
} // namespace mozilla