Skip to content

Commit

Permalink
Report memory size of performance.measure / performance.mark (#16094)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarred-Sumner authored Jan 2, 2025
1 parent ee95559 commit a8b3f73
Show file tree
Hide file tree
Showing 16 changed files with 121 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/bun.js/bindings/JSDOMExceptionHandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ JSValue createDOMException(JSGlobalObject* lexicalGlobalObject, ExceptionCode ec
return createRangeError(lexicalGlobalObject, "Bad value"_s);
return createRangeError(lexicalGlobalObject, message);

case ExceptionCode::SyntaxError:
case ExceptionCode::JSSyntaxError:
if (message.isEmpty())
return createSyntaxError(lexicalGlobalObject);
Expand Down
6 changes: 6 additions & 0 deletions src/bun.js/bindings/webcore/JSPerformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ JSPerformance::JSPerformance(Structure* structure, JSDOMGlobalObject& globalObje
{
}

size_t JSPerformance::estimatedSize(JSCell* cell, VM& vm)
{
JSPerformance* thisObject = jsCast<JSPerformance*>(cell);
return Base::estimatedSize(cell, vm) + thisObject->wrapped().memoryCost();
}

// static_assert(!std::is_base_of<ActiveDOMObject, Performance>::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject.");

void JSPerformance::finishCreation(VM& vm)
Expand Down
1 change: 1 addition & 0 deletions src/bun.js/bindings/webcore/JSPerformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class JSPerformance : public JSEventTarget {
}
static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm);
Performance& wrapped() const
{
return static_cast<Performance&>(Base::wrapped());
Expand Down
10 changes: 10 additions & 0 deletions src/bun.js/bindings/webcore/Performance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,16 @@ Vector<RefPtr<PerformanceEntry>> Performance::getEntriesByType(const String& ent
return entries;
}

size_t Performance::memoryCost() const
{
size_t size = sizeof(Performance);
size += m_resourceTimingBuffer.size() * sizeof(PerformanceResourceTiming);
if (m_userTiming) {
size += m_userTiming->memoryCost();
}
return size;
}

Vector<RefPtr<PerformanceEntry>> Performance::getEntriesByName(const String& name, const String& entryType) const
{
Vector<RefPtr<PerformanceEntry>> entries;
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/webcore/Performance.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ class Performance final : public RefCounted<Performance>, public ContextDestruct

// void reportFirstContentfulPaint();

size_t memoryCost() const;

void removeAllObservers();
void registerPerformanceObserver(PerformanceObserver&);
void unregisterPerformanceObserver(PerformanceObserver&);
Expand Down
26 changes: 26 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
#include "config.h"
#include "PerformanceEntry.h"

#include "PerformanceMark.h"
#include "PerformanceMeasure.h"
#include "PerformanceResourceTiming.h"

// #include "DeprecatedGlobalSettings.h"

namespace WebCore {
Expand All @@ -46,6 +50,28 @@ PerformanceEntry::PerformanceEntry(const String& name, double startTime, double

PerformanceEntry::~PerformanceEntry() = default;

size_t PerformanceEntry::memoryCost() const
{
size_t baseCost = this->m_name.sizeInBytes();
switch (performanceEntryType()) {
case Type::Mark: {
const PerformanceMark* mark = static_cast<const PerformanceMark*>(this);
return mark->memoryCost() + baseCost;
}
case Type::Measure: {
const PerformanceMeasure* measure = static_cast<const PerformanceMeasure*>(this);
return measure->memoryCost() + baseCost;
}
case Type::Resource: {
const PerformanceResourceTiming* resource = static_cast<const PerformanceResourceTiming*>(this);
return resource->memoryCost() + baseCost;
}
default: {
return sizeof(PerformanceEntry) + baseCost;
}
}
}

std::optional<PerformanceEntry::Type> PerformanceEntry::parseEntryTypeString(const String& entryType)
{
if (entryType == "navigation"_s)
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class PerformanceEntry : public RefCounted<PerformanceEntry> {
virtual Type performanceEntryType() const = 0;
virtual ASCIILiteral entryType() const = 0;

size_t memoryCost() const;

static std::optional<Type> parseEntryTypeString(const String& entryType);

static bool startTimeCompareLessThan(const RefPtr<PerformanceEntry>& a, const RefPtr<PerformanceEntry>& b)
Expand Down
9 changes: 9 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceMark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ PerformanceMark::PerformanceMark(const String& name, double startTime, RefPtr<Se

PerformanceMark::~PerformanceMark() = default;

size_t PerformanceMark::memoryCost() const
{
size_t size = sizeof(PerformanceMark);
if (m_serializedDetail) {
size += m_serializedDetail->memoryCost();
}
return size;
}

JSC::JSValue PerformanceMark::detail(JSC::JSGlobalObject& globalObject)
{
if (!m_serializedDetail) {
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceMark.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class PerformanceMark final : public PerformanceEntry {

JSC::JSValue detail(JSC::JSGlobalObject&);

size_t memoryCost() const;

private:
PerformanceMark(const String& name, double startTime, RefPtr<SerializedScriptValue>&&);
~PerformanceMark();
Expand Down
9 changes: 9 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceMeasure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@

namespace WebCore {

size_t PerformanceMeasure::memoryCost() const
{
size_t size = sizeof(PerformanceMeasure);
if (m_serializedDetail) {
size += m_serializedDetail->memoryCost();
}
return size;
}

ExceptionOr<Ref<PerformanceMeasure>> PerformanceMeasure::create(const String& name, double startTime, double endTime, RefPtr<SerializedScriptValue>&& serializedDetail)
{
return adoptRef(*new PerformanceMeasure(name, startTime, endTime, WTFMove(serializedDetail)));
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceMeasure.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class PerformanceMeasure final : public PerformanceEntry {

JSC::JSValue detail(JSC::JSGlobalObject&);

size_t memoryCost() const;

private:
PerformanceMeasure(const String& name, double startTime, double endTime, RefPtr<SerializedScriptValue>&& detail);
~PerformanceMeasure();
Expand Down
7 changes: 7 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceResourceTiming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ static double fetchStart(MonotonicTime timeOrigin, const ResourceTiming& resourc
return networkLoadTimeToDOMHighResTimeStamp(timeOrigin, startTime);
}

size_t PerformanceResourceTiming::memoryCost() const
{
size_t size = sizeof(PerformanceResourceTiming);
size += m_serverTiming.size() * sizeof(PerformanceServerTiming);
return size;
}

static double entryStartTime(MonotonicTime timeOrigin, const ResourceTiming& resourceTiming)
{
if (resourceTiming.networkLoadMetrics().failsTAOCheck
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceResourceTiming.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class PerformanceResourceTiming : public PerformanceEntry {
uint64_t encodedBodySize() const;
uint64_t decodedBodySize() const;

size_t memoryCost() const;

const Vector<Ref<PerformanceServerTiming>>& serverTiming() const { return m_serverTiming; }

Type performanceEntryType() const override { return Type::Resource; }
Expand Down
23 changes: 23 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceUserTiming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,29 @@ PerformanceUserTiming::PerformanceUserTiming(Performance& performance)
{
}

size_t PerformanceUserTiming::memoryCost() const
{
size_t size = sizeof(PerformanceUserTiming);
size += m_marksMap.byteSize();
size += m_measuresMap.byteSize();

for (const auto& entry : m_marksMap) {
size += entry.value.sizeInBytes();
for (const auto& entry : entry.value) {
size += entry->memoryCost();
}
}

for (const auto& entry : m_measuresMap) {
size += entry.value.sizeInBytes();
for (const auto& entry : entry.value) {
size += entry->memoryCost();
}
}

return size;
}

static void clearPerformanceEntries(PerformanceEntryMap& map, const String& name)
{
if (name.isNull())
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/webcore/PerformanceUserTiming.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class PerformanceUserTiming {

static bool isRestrictedMarkName(const String& markName);

size_t memoryCost() const;

private:
ExceptionOr<double> convertMarkToTimestamp(const std::variant<String, double>&) const;
ExceptionOr<double> convertMarkToTimestamp(const String& markName) const;
Expand Down
17 changes: 17 additions & 0 deletions test/js/web/timers/performance-entries.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { expect, test } from "bun:test";
import { estimateShallowMemoryUsageOf } from "bun:jsc";

test("memory usage of Performance", () => {
const initial = estimateShallowMemoryUsageOf(performance);
for (let i = 0; i < 1024; i++) {
performance.mark(`mark-${i}`);
}
const final = estimateShallowMemoryUsageOf(performance);

for (let i = 1; i < 1024; i++) {
performance.measure(`measure-${i}`, `mark-${i}`, `mark-${i - 1}`);
}
const final2 = estimateShallowMemoryUsageOf(performance);
expect(final2).toBeGreaterThan(final);
expect(final).toBeGreaterThan(initial);
});

0 comments on commit a8b3f73

Please sign in to comment.