Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1801,6 +1801,11 @@ class ProductionCollector implements Collector {

@override
void register(Object wrapper, SkDeletable deletable) {
if (Instrumentation.enabled) {
Instrumentation.instance.incrementCounter(
'${deletable.constructor.name} registered',
);
}
_skObjectFinalizationRegistry.register(wrapper, deletable);
}

Expand Down Expand Up @@ -1859,6 +1864,11 @@ class ProductionCollector implements Collector {
// again if the objects is worth collecting.
continue;
}
if (Instrumentation.enabled) {
Instrumentation.instance.incrementCounter(
'${deletable.constructor.name} deleted',
);
}
try {
deletable.delete();
} catch (error, stackTrace) {
Expand Down Expand Up @@ -1907,6 +1917,21 @@ class SkDeletable {

/// Returns whether the correcponding C++ object has been deleted.
external bool isDeleted();

/// Returns the JavaScript constructor for this object.
///
/// This is useful for debugging.
external JsConstructor get constructor;
}

@JS()
@anonymous
class JsConstructor {
/// The name of the "constructor", typically the function name called with
/// the `new` keyword, or the ES6 class name.
///
/// This is useful for debugging.
external String get name;
}

/// Attaches a weakly referenced object to another object and calls a finalizer
Expand Down
33 changes: 32 additions & 1 deletion lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ abstract class ManagedSkiaObject<T extends Object> extends SkiaObject<T> {
} else {
// If FinalizationRegistry is _not_ supported we may need to delete
// and resurrect the object multiple times before deleting it forever.
if (Instrumentation.enabled) {
Instrumentation.instance.incrementCounter(
'${(defaultObject as SkDeletable).constructor.name} created',
);
}
if (isResurrectionExpensive) {
SkiaObjects.manageExpensive(this);
} else {
Expand All @@ -161,6 +166,11 @@ abstract class ManagedSkiaObject<T extends Object> extends SkiaObject<T> {
T _doResurrect() {
assert(!browserSupportsFinalizationRegistry);
final T skiaObject = resurrect();
if (Instrumentation.enabled) {
Instrumentation.instance.incrementCounter(
'${(skiaObject as SkDeletable).constructor.name} resurrected',
);
}
rawSkiaObject = skiaObject;
if (isResurrectionExpensive) {
SkiaObjects.manageExpensive(this);
Expand All @@ -173,6 +183,11 @@ abstract class ManagedSkiaObject<T extends Object> extends SkiaObject<T> {
@override
void didDelete() {
assert(!browserSupportsFinalizationRegistry);
if (Instrumentation.enabled) {
Instrumentation.instance.incrementCounter(
'${(rawSkiaObject as SkDeletable).constructor.name} deleted',
);
}
rawSkiaObject = null;
}

Expand Down Expand Up @@ -303,6 +318,11 @@ class SkiaObjectBox<R extends StackTraceDebugger, T extends Object> extends Skia

void _initialize(R debugReferrer, T initialValue) {
_update(initialValue);
if (Instrumentation.enabled) {
Instrumentation.instance.incrementCounter(
'${_skDeletable?.constructor.name} created',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we get 'null created' and 'null deleted'? How should we make sense of those?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not seen any nulls yet. I'm not sure how to make sense of that situation. I think let's wait until we get a null and find a solution then.

);
}
if (assertionsEnabled) {
debugReferrers.add(debugReferrer);
}
Expand Down Expand Up @@ -355,6 +375,11 @@ class SkiaObjectBox<R extends StackTraceDebugger, T extends Object> extends Skia
assert(_resurrector != null);
assert(!_isDeletedPermanently, 'Cannot use deleted object.');
_update(_resurrector!());
if (Instrumentation.enabled) {
Instrumentation.instance.incrementCounter(
'${_skDeletable?.constructor.name} resurrected',
);
}
SkiaObjects.manageExpensive(this);
return skiaObject;
}
Expand All @@ -366,6 +391,11 @@ class SkiaObjectBox<R extends StackTraceDebugger, T extends Object> extends Skia

@override
void didDelete() {
if (Instrumentation.enabled) {
Instrumentation.instance.incrementCounter(
'${_skDeletable?.constructor.name} deleted',
);
}
assert(!browserSupportsFinalizationRegistry);
_update(null);
}
Expand Down Expand Up @@ -419,7 +449,8 @@ class SkiaObjectBox<R extends StackTraceDebugger, T extends Object> extends Skia
if (browserSupportsFinalizationRegistry) {
Collector.instance.collect(_skDeletable!);
} else {
_skDeletable!.delete();
delete();
didDelete();
}
}
rawSkiaObject = null;
Expand Down
63 changes: 63 additions & 0 deletions lib/web_ui/lib/src/engine/profiler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,66 @@ void _frameTimingsOnRasterFinish() {
int _nowMicros() {
return (html.window.performance.now() * 1000).toInt();
}

/// Counts various events that take place while the app is running.
///
/// This class will slow down the app, and therefore should be disabled while
/// benchmarking. For example, avoid using it in conjunction with [Profiler].
class Instrumentation {
Instrumentation._() {
_checkInstrumentationEnabled();
}

/// Whether instrumentation is enabled.
///
/// Check this value before calling any other methods in this class.
static const bool enabled = const bool.fromEnvironment(
'FLUTTER_WEB_ENABLE_INSTRUMENTATION',
defaultValue: false,
);

/// Returns the singleton that provides instrumentation API.
static Instrumentation get instance {
_checkInstrumentationEnabled();
return _instance;
}

static late final Instrumentation _instance = Instrumentation._();

static void _checkInstrumentationEnabled() {
if (!enabled) {
throw Exception(
'Cannot use Instrumentation unless it is enabled. '
'You can enable it by setting the `FLUTTER_WEB_ENABLE_INSTRUMENTATION` '
'environment variable to true, or by passing '
'--dart-define=FLUTTER_WEB_ENABLE_INSTRUMENTATION=true to the flutter '
'tool.',
);
}
}

final Map<String, int> _counters = <String, int>{};
Timer? _printTimer;

/// Increments the count of a particular event by one.
void incrementCounter(String event) {
_checkInstrumentationEnabled();
final int currentCount = _counters[event] ?? 0;
_counters[event] = currentCount + 1;
_printTimer ??= Timer(
const Duration(seconds: 2),
() {
final StringBuffer message = StringBuffer('Engine counters:\n');
final List<MapEntry<String, int>> entries = _counters.entries.toList()
..sort((MapEntry<String, int> a, MapEntry<String, int> b) {
return a.key.compareTo(b.key);
});
for (MapEntry<String, int> entry in entries) {
message.writeln(' ${entry.key}: ${entry.value}');
}
print(message);
_printTimer = null;
},
);
}
}
13 changes: 13 additions & 0 deletions lib/web_ui/test/canvaskit/skia_objects_cache_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ class TestSkDeletable implements SkDeletable {
_isDeleted = true;
deleteCount++;
}

@override
JsConstructor get constructor => TestJsConstructor('TestSkDeletable');
}

class TestOneShotSkiaObject extends OneShotSkiaObject<SkPaint> implements SkDeletable {
Expand All @@ -310,6 +313,16 @@ class TestOneShotSkiaObject extends OneShotSkiaObject<SkPaint> implements SkDele
rawSkiaObject?.delete();
deleteCount++;
}

@override
JsConstructor get constructor => TestJsConstructor('TestOneShotSkiaObject');
}

class TestJsConstructor implements JsConstructor{
TestJsConstructor(this.name);

@override
final String name;
}

class TestSkiaObject extends ManagedSkiaObject<SkPaint> {
Expand Down