Add Instrumentation class (#22650)

This commit is contained in:
Yegor 2020-11-21 08:38:02 -08:00 committed by GitHub
parent 26c4ba074d
commit b249d568cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 133 additions and 1 deletions

View File

@ -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);
}
@ -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) {
@ -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

View File

@ -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 {
@ -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);
@ -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;
}
@ -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',
);
}
if (assertionsEnabled) {
debugReferrers.add(debugReferrer);
}
@ -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;
}
@ -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);
}
@ -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;

View File

@ -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;
},
);
}
}

View File

@ -292,6 +292,9 @@ class TestSkDeletable implements SkDeletable {
_isDeleted = true;
deleteCount++;
}
@override
JsConstructor get constructor => TestJsConstructor('TestSkDeletable');
}
class TestOneShotSkiaObject extends OneShotSkiaObject<SkPaint> implements SkDeletable {
@ -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> {