[vm] Intern strings when writing Perfetto timeline

Intern the following fields:

* Category names
* Event labels
* Debug annotation keys and values

This significantly reduces the size of the timeline
(e.g. a timeline containing 60k slices goes from 15Mb
to 5Mb timeline)

This relands commit f2614d24f8
with a fix for Android build.

TEST=ci and manually

Cq-Include-Trybots: luci.dart.try:vm-ffi-android-release-arm64c-try
Change-Id: I88d4c5e1142ff66b270a22b82bacd1e9313fa953
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/418220
Reviewed-by: Derek Xu <derekx@google.com>
This commit is contained in:
Vyacheslav Egorov
2025-03-27 06:44:23 -07:00
committed by Commit Queue
parent c0b423fbab
commit 2a437c54a0
20 changed files with 1523 additions and 179 deletions
@@ -1,10 +1,14 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
// VMOptions=
// VMOptions=--intern_strings_when_writing_perfetto_timeline
import 'dart:collection';
import 'dart:convert';
import 'dart:developer';
import 'dart:io' show Platform;
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart' hide Timeline;
@@ -35,12 +39,108 @@ void primeTimeline() {
Timeline.finishSync();
}
Iterable<TrackEvent> extractTrackEventsFromTracePackets(
class Deinterner {
final bool stringsShouldBeInterned = Platform.executableArguments
.contains('--intern_strings_when_writing_perfetto_timeline');
final Map<int, String> debugAnnotationNames = {};
final Map<int, String> debugAnnotationStringValues = {};
final Map<int, String> eventNames = {};
final Map<int, String> eventCategories = {};
/// Update the state of the interning dictionaries using [InternedData]
/// from the given packet.
void update(TracePacket packet) {
// Clear the state if [TracePacket.sequenceFlags] instructs us to do so.
if (packet.sequenceFlags &
TracePacket_SequenceFlags.SEQ_INCREMENTAL_STATE_CLEARED.value !=
0) {
debugAnnotationNames.clear();
debugAnnotationStringValues.clear();
eventNames.clear();
eventCategories.clear();
}
if (!packet.hasInternedData()) {
return;
}
final internedData = packet.internedData;
for (var e in internedData.debugAnnotationNames) {
debugAnnotationNames[e.iid.toInt()] = e.name;
}
for (var e in internedData.debugAnnotationStringValues) {
debugAnnotationStringValues[e.iid.toInt()] = utf8.decode(e.str);
}
for (var e in internedData.eventNames) {
eventNames[e.iid.toInt()] = e.name;
}
for (var e in internedData.eventCategories) {
eventCategories[e.iid.toInt()] = e.name;
}
}
/// Deintern contents of the given [TrackEvent].
void deintern(TrackEvent event) {
if (event.hasName()) {
expect(stringsShouldBeInterned, isFalse);
}
if (event.hasNameIid()) {
expect(stringsShouldBeInterned, isTrue);
expect(event.hasName(), isFalse);
event.name = eventNames[event.nameIid.toInt()]!;
event.clearNameIid();
}
if (event.categories.isNotEmpty) {
expect(stringsShouldBeInterned, isFalse);
}
if (event.categoryIids.isNotEmpty) {
expect(stringsShouldBeInterned, isTrue);
expect(event.categories.isEmpty, isTrue);
for (var iid in event.categoryIids) {
event.categories.add(eventCategories[iid.toInt()]!);
}
event.categoryIids.clear();
}
for (var annotation in event.debugAnnotations) {
if (annotation.hasStringValue()) {
expect(stringsShouldBeInterned, isFalse);
}
if (annotation.hasStringValueIid()) {
expect(stringsShouldBeInterned, isTrue);
expect(annotation.hasStringValue(), isFalse);
annotation.stringValue =
debugAnnotationStringValues[annotation.stringValueIid.toInt()]!;
annotation.clearStringValueIid();
}
if (annotation.hasName()) {
expect(stringsShouldBeInterned, isFalse);
}
if (annotation.hasNameIid()) {
expect(stringsShouldBeInterned, isTrue);
expect(annotation.hasName(), isFalse);
annotation.name = debugAnnotationNames[annotation.nameIid.toInt()]!;
annotation.clearNameIid();
}
}
}
}
List<TrackEvent> extractTrackEventsFromTracePackets(
List<TracePacket> packets,
) {
return packets
.where((packet) => packet.hasTrackEvent())
.map((packet) => packet.trackEvent);
final result = <TrackEvent>[];
final deinterner = Deinterner();
for (var packet in packets) {
deinterner.update(packet);
if (packet.hasTrackEvent()) {
deinterner.deintern(packet.trackEvent);
result.add(packet.trackEvent);
}
}
return result;
}
Map<String, String> mapFromListOfDebugAnnotations(
@@ -60,7 +160,7 @@ Map<String, String> mapFromListOfDebugAnnotations(
}
void checkThatAllEventsHaveIsolateNumbers(Iterable<TrackEvent> events) {
for (TrackEvent event in events) {
for (final event in events) {
final debugAnnotations =
mapFromListOfDebugAnnotations(event.debugAnnotations);
expect(debugAnnotations['isolateGroupId'], isNotNull);
@@ -21,7 +21,9 @@ import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
import '../profiling/profile_common.pb.dart' as $2;
import '../profiling/profile_common.pb.dart' as $3;
import '../track_event/debug_annotation.pb.dart' as $1;
import '../track_event/track_event.pb.dart' as $2;
export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
@@ -36,13 +38,26 @@ export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
/// Next id: 29.
class InternedData extends $pb.GeneratedMessage {
factory InternedData({
$core.Iterable<$2.InternedString>? functionNames,
$core.Iterable<$2.Frame>? frames,
$core.Iterable<$2.Callstack>? callstacks,
$core.Iterable<$2.InternedString>? mappingPaths,
$core.Iterable<$2.Mapping>? mappings,
$core.Iterable<$2.EventCategory>? eventCategories,
$core.Iterable<$2.EventName>? eventNames,
$core.Iterable<$1.DebugAnnotationName>? debugAnnotationNames,
$core.Iterable<$3.InternedString>? functionNames,
$core.Iterable<$3.Frame>? frames,
$core.Iterable<$3.Callstack>? callstacks,
$core.Iterable<$3.InternedString>? mappingPaths,
$core.Iterable<$3.Mapping>? mappings,
$core.Iterable<$3.InternedString>? debugAnnotationStringValues,
}) {
final $result = create();
if (eventCategories != null) {
$result.eventCategories.addAll(eventCategories);
}
if (eventNames != null) {
$result.eventNames.addAll(eventNames);
}
if (debugAnnotationNames != null) {
$result.debugAnnotationNames.addAll(debugAnnotationNames);
}
if (functionNames != null) {
$result.functionNames.addAll(functionNames);
}
@@ -58,6 +73,9 @@ class InternedData extends $pb.GeneratedMessage {
if (mappings != null) {
$result.mappings.addAll(mappings);
}
if (debugAnnotationStringValues != null) {
$result.debugAnnotationStringValues.addAll(debugAnnotationStringValues);
}
return $result;
}
InternedData._() : super();
@@ -73,19 +91,33 @@ class InternedData extends $pb.GeneratedMessage {
package:
const $pb.PackageName(_omitMessageNames ? '' : 'perfetto.protos'),
createEmptyInstance: create)
..pc<$2.InternedString>(
..pc<$2.EventCategory>(
1, _omitFieldNames ? '' : 'eventCategories', $pb.PbFieldType.PM,
subBuilder: $2.EventCategory.create)
..pc<$2.EventName>(
2, _omitFieldNames ? '' : 'eventNames', $pb.PbFieldType.PM,
subBuilder: $2.EventName.create)
..pc<$1.DebugAnnotationName>(
3, _omitFieldNames ? '' : 'debugAnnotationNames', $pb.PbFieldType.PM,
subBuilder: $1.DebugAnnotationName.create)
..pc<$3.InternedString>(
5, _omitFieldNames ? '' : 'functionNames', $pb.PbFieldType.PM,
subBuilder: $2.InternedString.create)
..pc<$2.Frame>(6, _omitFieldNames ? '' : 'frames', $pb.PbFieldType.PM,
subBuilder: $2.Frame.create)
..pc<$2.Callstack>(
subBuilder: $3.InternedString.create)
..pc<$3.Frame>(6, _omitFieldNames ? '' : 'frames', $pb.PbFieldType.PM,
subBuilder: $3.Frame.create)
..pc<$3.Callstack>(
7, _omitFieldNames ? '' : 'callstacks', $pb.PbFieldType.PM,
subBuilder: $2.Callstack.create)
..pc<$2.InternedString>(
subBuilder: $3.Callstack.create)
..pc<$3.InternedString>(
17, _omitFieldNames ? '' : 'mappingPaths', $pb.PbFieldType.PM,
subBuilder: $2.InternedString.create)
..pc<$2.Mapping>(19, _omitFieldNames ? '' : 'mappings', $pb.PbFieldType.PM,
subBuilder: $2.Mapping.create)
subBuilder: $3.InternedString.create)
..pc<$3.Mapping>(19, _omitFieldNames ? '' : 'mappings', $pb.PbFieldType.PM,
subBuilder: $3.Mapping.create)
..pc<$3.InternedString>(
29,
_omitFieldNames ? '' : 'debugAnnotationStringValues',
$pb.PbFieldType.PM,
subBuilder: $3.InternedString.create)
..hasRequiredFields = false;
@$core.Deprecated('Using this can add significant overhead to your binary. '
@@ -111,25 +143,38 @@ class InternedData extends $pb.GeneratedMessage {
$pb.GeneratedMessage.$_defaultFor<InternedData>(create);
static InternedData? _defaultInstance;
@$pb.TagNumber(1)
$pb.PbList<$2.EventCategory> get eventCategories => $_getList(0);
@$pb.TagNumber(2)
$pb.PbList<$2.EventName> get eventNames => $_getList(1);
@$pb.TagNumber(3)
$pb.PbList<$1.DebugAnnotationName> get debugAnnotationNames => $_getList(2);
/// Names of functions used in frames below.
@$pb.TagNumber(5)
$pb.PbList<$2.InternedString> get functionNames => $_getList(0);
$pb.PbList<$3.InternedString> get functionNames => $_getList(3);
/// Frames of callstacks of a program.
@$pb.TagNumber(6)
$pb.PbList<$2.Frame> get frames => $_getList(1);
$pb.PbList<$3.Frame> get frames => $_getList(4);
/// A callstack of a program.
@$pb.TagNumber(7)
$pb.PbList<$2.Callstack> get callstacks => $_getList(2);
$pb.PbList<$3.Callstack> get callstacks => $_getList(5);
/// Paths to executable files.
@$pb.TagNumber(17)
$pb.PbList<$2.InternedString> get mappingPaths => $_getList(3);
$pb.PbList<$3.InternedString> get mappingPaths => $_getList(6);
/// Executable files mapped into processes.
@$pb.TagNumber(19)
$pb.PbList<$2.Mapping> get mappings => $_getList(4);
$pb.PbList<$3.Mapping> get mappings => $_getList(7);
/// Interned string values in the DebugAnnotation proto.
@$pb.TagNumber(29)
$pb.PbList<$3.InternedString> get debugAnnotationStringValues => $_getList(8);
}
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
@@ -25,6 +25,30 @@ import 'dart:typed_data' as $typed_data;
const InternedData$json = {
'1': 'InternedData',
'2': [
{
'1': 'event_categories',
'3': 1,
'4': 3,
'5': 11,
'6': '.perfetto.protos.EventCategory',
'10': 'eventCategories'
},
{
'1': 'event_names',
'3': 2,
'4': 3,
'5': 11,
'6': '.perfetto.protos.EventName',
'10': 'eventNames'
},
{
'1': 'debug_annotation_names',
'3': 3,
'4': 3,
'5': 11,
'6': '.perfetto.protos.DebugAnnotationName',
'10': 'debugAnnotationNames'
},
{
'1': 'mapping_paths',
'3': 17,
@@ -65,14 +89,28 @@ const InternedData$json = {
'6': '.perfetto.protos.Callstack',
'10': 'callstacks'
},
{
'1': 'debug_annotation_string_values',
'3': 29,
'4': 3,
'5': 11,
'6': '.perfetto.protos.InternedString',
'10': 'debugAnnotationStringValues'
},
],
};
/// Descriptor for `InternedData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List internedDataDescriptor = $convert.base64Decode(
'CgxJbnRlcm5lZERhdGESRAoNbWFwcGluZ19wYXRocxgRIAMoCzIfLnBlcmZldHRvLnByb3Rvcy'
'5JbnRlcm5lZFN0cmluZ1IMbWFwcGluZ1BhdGhzEkYKDmZ1bmN0aW9uX25hbWVzGAUgAygLMh8u'
'cGVyZmV0dG8ucHJvdG9zLkludGVybmVkU3RyaW5nUg1mdW5jdGlvbk5hbWVzEjQKCG1hcHBpbm'
'dzGBMgAygLMhgucGVyZmV0dG8ucHJvdG9zLk1hcHBpbmdSCG1hcHBpbmdzEi4KBmZyYW1lcxgG'
'IAMoCzIWLnBlcmZldHRvLnByb3Rvcy5GcmFtZVIGZnJhbWVzEjoKCmNhbGxzdGFja3MYByADKA'
'syGi5wZXJmZXR0by5wcm90b3MuQ2FsbHN0YWNrUgpjYWxsc3RhY2tz');
'CgxJbnRlcm5lZERhdGESSQoQZXZlbnRfY2F0ZWdvcmllcxgBIAMoCzIeLnBlcmZldHRvLnByb3'
'Rvcy5FdmVudENhdGVnb3J5Ug9ldmVudENhdGVnb3JpZXMSOwoLZXZlbnRfbmFtZXMYAiADKAsy'
'Gi5wZXJmZXR0by5wcm90b3MuRXZlbnROYW1lUgpldmVudE5hbWVzEloKFmRlYnVnX2Fubm90YX'
'Rpb25fbmFtZXMYAyADKAsyJC5wZXJmZXR0by5wcm90b3MuRGVidWdBbm5vdGF0aW9uTmFtZVIU'
'ZGVidWdBbm5vdGF0aW9uTmFtZXMSRAoNbWFwcGluZ19wYXRocxgRIAMoCzIfLnBlcmZldHRvLn'
'Byb3Rvcy5JbnRlcm5lZFN0cmluZ1IMbWFwcGluZ1BhdGhzEkYKDmZ1bmN0aW9uX25hbWVzGAUg'
'AygLMh8ucGVyZmV0dG8ucHJvdG9zLkludGVybmVkU3RyaW5nUg1mdW5jdGlvbk5hbWVzEjQKCG'
'1hcHBpbmdzGBMgAygLMhgucGVyZmV0dG8ucHJvdG9zLk1hcHBpbmdSCG1hcHBpbmdzEi4KBmZy'
'YW1lcxgGIAMoCzIWLnBlcmZldHRvLnByb3Rvcy5GcmFtZVIGZnJhbWVzEjoKCmNhbGxzdGFja3'
'MYByADKAsyGi5wZXJmZXR0by5wcm90b3MuQ2FsbHN0YWNrUgpjYWxsc3RhY2tzEmQKHmRlYnVn'
'X2Fubm90YXRpb25fc3RyaW5nX3ZhbHVlcxgdIAMoCzIfLnBlcmZldHRvLnByb3Rvcy5JbnRlcm'
'5lZFN0cmluZ1IbZGVidWdBbm5vdGF0aW9uU3RyaW5nVmFsdWVz');
@@ -22,11 +22,11 @@ import 'dart:core' as $core;
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb;
import 'clock_snapshot.pb.dart' as $5;
import 'clock_snapshot.pb.dart' as $6;
import 'interned_data/interned_data.pb.dart' as $7;
import 'profiling/profile_packet.pb.dart' as $9;
import 'track_event/track_descriptor.pb.dart' as $8;
import 'track_event/track_event.pb.dart' as $6;
import 'track_event/track_event.pb.dart' as $2;
export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
@@ -68,10 +68,10 @@ enum TracePacket_OptionalTrustedPacketSequenceId {
/// Next id: 88.
class TracePacket extends $pb.GeneratedMessage {
factory TracePacket({
$5.ClockSnapshot? clockSnapshot,
$6.ClockSnapshot? clockSnapshot,
$fixnum.Int64? timestamp,
$core.int? trustedPacketSequenceId,
$6.TrackEvent? trackEvent,
$2.TrackEvent? trackEvent,
$7.InternedData? internedData,
$core.int? sequenceFlags,
$core.int? timestampClockId,
@@ -135,15 +135,15 @@ class TracePacket extends $pb.GeneratedMessage {
createEmptyInstance: create)
..oo(0, [6, 11, 60, 66])
..oo(1, [10])
..aOM<$5.ClockSnapshot>(6, _omitFieldNames ? '' : 'clockSnapshot',
subBuilder: $5.ClockSnapshot.create)
..aOM<$6.ClockSnapshot>(6, _omitFieldNames ? '' : 'clockSnapshot',
subBuilder: $6.ClockSnapshot.create)
..a<$fixnum.Int64>(
8, _omitFieldNames ? '' : 'timestamp', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..a<$core.int>(10, _omitFieldNames ? '' : 'trustedPacketSequenceId',
$pb.PbFieldType.OU3)
..aOM<$6.TrackEvent>(11, _omitFieldNames ? '' : 'trackEvent',
subBuilder: $6.TrackEvent.create)
..aOM<$2.TrackEvent>(11, _omitFieldNames ? '' : 'trackEvent',
subBuilder: $2.TrackEvent.create)
..aOM<$7.InternedData>(12, _omitFieldNames ? '' : 'internedData',
subBuilder: $7.InternedData.create)
..a<$core.int>(
@@ -187,9 +187,9 @@ class TracePacket extends $pb.GeneratedMessage {
void clearOptionalTrustedPacketSequenceId() => $_clearField($_whichOneof(1));
@$pb.TagNumber(6)
$5.ClockSnapshot get clockSnapshot => $_getN(0);
$6.ClockSnapshot get clockSnapshot => $_getN(0);
@$pb.TagNumber(6)
set clockSnapshot($5.ClockSnapshot v) {
set clockSnapshot($6.ClockSnapshot v) {
$_setField(6, v);
}
@@ -198,7 +198,7 @@ class TracePacket extends $pb.GeneratedMessage {
@$pb.TagNumber(6)
void clearClockSnapshot() => $_clearField(6);
@$pb.TagNumber(6)
$5.ClockSnapshot ensureClockSnapshot() => $_ensure(0);
$6.ClockSnapshot ensureClockSnapshot() => $_ensure(0);
/// The timestamp of the TracePacket.
/// By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -231,9 +231,9 @@ class TracePacket extends $pb.GeneratedMessage {
void clearTrustedPacketSequenceId() => $_clearField(10);
@$pb.TagNumber(11)
$6.TrackEvent get trackEvent => $_getN(3);
$2.TrackEvent get trackEvent => $_getN(3);
@$pb.TagNumber(11)
set trackEvent($6.TrackEvent v) {
set trackEvent($2.TrackEvent v) {
$_setField(11, v);
}
@@ -242,7 +242,7 @@ class TracePacket extends $pb.GeneratedMessage {
@$pb.TagNumber(11)
void clearTrackEvent() => $_clearField(11);
@$pb.TagNumber(11)
$6.TrackEvent ensureTrackEvent() => $_ensure(3);
$2.TrackEvent ensureTrackEvent() => $_ensure(3);
/// Incrementally emitted interned data, valid only on the packet's sequence
/// (packets with the same |trusted_packet_sequence_id|). The writer will
@@ -19,13 +19,19 @@
import 'dart:core' as $core;
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb;
export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
enum DebugAnnotation_NameField { name, notSet }
enum DebugAnnotation_NameField { nameIid, name, notSet }
enum DebugAnnotation_Value { stringValue, legacyJsonValue, notSet }
enum DebugAnnotation_Value {
stringValue,
legacyJsonValue,
stringValueIid,
notSet
}
/// Proto representation of untyped key/value annotations provided in TRACE_EVENT
/// macros. Users of the Perfetto SDK should prefer to use the
@@ -70,11 +76,16 @@ enum DebugAnnotation_Value { stringValue, legacyJsonValue, notSet }
/// Reserved ID: 15
class DebugAnnotation extends $pb.GeneratedMessage {
factory DebugAnnotation({
$fixnum.Int64? nameIid,
$core.String? stringValue,
$core.String? legacyJsonValue,
$core.String? name,
$fixnum.Int64? stringValueIid,
}) {
final $result = create();
if (nameIid != null) {
$result.nameIid = nameIid;
}
if (stringValue != null) {
$result.stringValue = stringValue;
}
@@ -84,6 +95,9 @@ class DebugAnnotation extends $pb.GeneratedMessage {
if (name != null) {
$result.name = name;
}
if (stringValueIid != null) {
$result.stringValueIid = stringValueIid;
}
return $result;
}
DebugAnnotation._() : super();
@@ -96,6 +110,7 @@ class DebugAnnotation extends $pb.GeneratedMessage {
static const $core.Map<$core.int, DebugAnnotation_NameField>
_DebugAnnotation_NameFieldByTag = {
1: DebugAnnotation_NameField.nameIid,
10: DebugAnnotation_NameField.name,
0: DebugAnnotation_NameField.notSet
};
@@ -103,6 +118,7 @@ class DebugAnnotation extends $pb.GeneratedMessage {
_DebugAnnotation_ValueByTag = {
6: DebugAnnotation_Value.stringValue,
9: DebugAnnotation_Value.legacyJsonValue,
17: DebugAnnotation_Value.stringValueIid,
0: DebugAnnotation_Value.notSet
};
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
@@ -110,11 +126,16 @@ class DebugAnnotation extends $pb.GeneratedMessage {
package:
const $pb.PackageName(_omitMessageNames ? '' : 'perfetto.protos'),
createEmptyInstance: create)
..oo(0, [10])
..oo(1, [6, 9])
..oo(0, [1, 10])
..oo(1, [6, 9, 17])
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'nameIid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..aOS(6, _omitFieldNames ? '' : 'stringValue')
..aOS(9, _omitFieldNames ? '' : 'legacyJsonValue')
..aOS(10, _omitFieldNames ? '' : 'name')
..a<$fixnum.Int64>(
17, _omitFieldNames ? '' : 'stringValueIid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..hasRequiredFields = false;
@$core.Deprecated('Using this can add significant overhead to your binary. '
@@ -148,44 +169,151 @@ class DebugAnnotation extends $pb.GeneratedMessage {
_DebugAnnotation_ValueByTag[$_whichOneof(1)]!;
void clearValue() => $_clearField($_whichOneof(1));
/// interned DebugAnnotationName.
@$pb.TagNumber(1)
$fixnum.Int64 get nameIid => $_getI64(0);
@$pb.TagNumber(1)
set nameIid($fixnum.Int64 v) {
$_setInt64(0, v);
}
@$pb.TagNumber(1)
$core.bool hasNameIid() => $_has(0);
@$pb.TagNumber(1)
void clearNameIid() => $_clearField(1);
/// interned and non-interned variants of strings.
@$pb.TagNumber(6)
$core.String get stringValue => $_getSZ(0);
$core.String get stringValue => $_getSZ(1);
@$pb.TagNumber(6)
set stringValue($core.String v) {
$_setString(0, v);
$_setString(1, v);
}
@$pb.TagNumber(6)
$core.bool hasStringValue() => $_has(0);
$core.bool hasStringValue() => $_has(1);
@$pb.TagNumber(6)
void clearStringValue() => $_clearField(6);
/// Legacy instrumentation may not support conversion of nested data to
/// NestedValue yet.
@$pb.TagNumber(9)
$core.String get legacyJsonValue => $_getSZ(1);
$core.String get legacyJsonValue => $_getSZ(2);
@$pb.TagNumber(9)
set legacyJsonValue($core.String v) {
$_setString(1, v);
$_setString(2, v);
}
@$pb.TagNumber(9)
$core.bool hasLegacyJsonValue() => $_has(1);
$core.bool hasLegacyJsonValue() => $_has(2);
@$pb.TagNumber(9)
void clearLegacyJsonValue() => $_clearField(9);
/// non-interned variant.
@$pb.TagNumber(10)
$core.String get name => $_getSZ(2);
$core.String get name => $_getSZ(3);
@$pb.TagNumber(10)
set name($core.String v) {
$_setString(2, v);
$_setString(3, v);
}
@$pb.TagNumber(10)
$core.bool hasName() => $_has(2);
$core.bool hasName() => $_has(3);
@$pb.TagNumber(10)
void clearName() => $_clearField(10);
/// Corresponds to |debug_annotation_string_values| field in InternedData.
@$pb.TagNumber(17)
$fixnum.Int64 get stringValueIid => $_getI64(4);
@$pb.TagNumber(17)
set stringValueIid($fixnum.Int64 v) {
$_setInt64(4, v);
}
@$pb.TagNumber(17)
$core.bool hasStringValueIid() => $_has(4);
@$pb.TagNumber(17)
void clearStringValueIid() => $_clearField(17);
}
class DebugAnnotationName extends $pb.GeneratedMessage {
factory DebugAnnotationName({
$fixnum.Int64? iid,
$core.String? name,
}) {
final $result = create();
if (iid != null) {
$result.iid = iid;
}
if (name != null) {
$result.name = name;
}
return $result;
}
DebugAnnotationName._() : super();
factory DebugAnnotationName.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory DebugAnnotationName.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'DebugAnnotationName',
package:
const $pb.PackageName(_omitMessageNames ? '' : 'perfetto.protos'),
createEmptyInstance: create)
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'iid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..aOS(2, _omitFieldNames ? '' : 'name')
..hasRequiredFields = false;
@$core.Deprecated('Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
DebugAnnotationName clone() => DebugAnnotationName()..mergeFromMessage(this);
@$core.Deprecated('Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
DebugAnnotationName copyWith(void Function(DebugAnnotationName) updates) =>
super.copyWith((message) => updates(message as DebugAnnotationName))
as DebugAnnotationName;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static DebugAnnotationName create() => DebugAnnotationName._();
DebugAnnotationName createEmptyInstance() => create();
static $pb.PbList<DebugAnnotationName> createRepeated() =>
$pb.PbList<DebugAnnotationName>();
@$core.pragma('dart2js:noInline')
static DebugAnnotationName getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<DebugAnnotationName>(create);
static DebugAnnotationName? _defaultInstance;
@$pb.TagNumber(1)
$fixnum.Int64 get iid => $_getI64(0);
@$pb.TagNumber(1)
set iid($fixnum.Int64 v) {
$_setInt64(0, v);
}
@$pb.TagNumber(1)
$core.bool hasIid() => $_has(0);
@$pb.TagNumber(1)
void clearIid() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get name => $_getSZ(1);
@$pb.TagNumber(2)
set name($core.String v) {
$_setString(1, v);
}
@$pb.TagNumber(2)
$core.bool hasName() => $_has(1);
@$pb.TagNumber(2)
void clearName() => $_clearField(2);
}
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
@@ -25,8 +25,8 @@ import 'dart:typed_data' as $typed_data;
const DebugAnnotation$json = {
'1': 'DebugAnnotation',
'2': [
{'1': 'name_iid', '3': 1, '4': 1, '5': 4, '9': 0, '10': 'nameIid'},
{'1': 'name', '3': 10, '4': 1, '5': 9, '9': 0, '10': 'name'},
{'1': 'string_value', '3': 6, '4': 1, '5': 9, '9': 1, '10': 'stringValue'},
{
'1': 'legacy_json_value',
'3': 9,
@@ -35,6 +35,15 @@ const DebugAnnotation$json = {
'9': 1,
'10': 'legacyJsonValue'
},
{'1': 'string_value', '3': 6, '4': 1, '5': 9, '9': 1, '10': 'stringValue'},
{
'1': 'string_value_iid',
'3': 17,
'4': 1,
'5': 4,
'9': 1,
'10': 'stringValueIid'
},
],
'8': [
{'1': 'name_field'},
@@ -44,6 +53,21 @@ const DebugAnnotation$json = {
/// Descriptor for `DebugAnnotation`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List debugAnnotationDescriptor = $convert.base64Decode(
'Cg9EZWJ1Z0Fubm90YXRpb24SFAoEbmFtZRgKIAEoCUgAUgRuYW1lEiMKDHN0cmluZ192YWx1ZR'
'gGIAEoCUgBUgtzdHJpbmdWYWx1ZRIsChFsZWdhY3lfanNvbl92YWx1ZRgJIAEoCUgBUg9sZWdh'
'Y3lKc29uVmFsdWVCDAoKbmFtZV9maWVsZEIHCgV2YWx1ZQ==');
'Cg9EZWJ1Z0Fubm90YXRpb24SGwoIbmFtZV9paWQYASABKARIAFIHbmFtZUlpZBIUCgRuYW1lGA'
'ogASgJSABSBG5hbWUSLAoRbGVnYWN5X2pzb25fdmFsdWUYCSABKAlIAVIPbGVnYWN5SnNvblZh'
'bHVlEiMKDHN0cmluZ192YWx1ZRgGIAEoCUgBUgtzdHJpbmdWYWx1ZRIqChBzdHJpbmdfdmFsdW'
'VfaWlkGBEgASgESAFSDnN0cmluZ1ZhbHVlSWlkQgwKCm5hbWVfZmllbGRCBwoFdmFsdWU=');
@$core.Deprecated('Use debugAnnotationNameDescriptor instead')
const DebugAnnotationName$json = {
'1': 'DebugAnnotationName',
'2': [
{'1': 'iid', '3': 1, '4': 1, '5': 4, '10': 'iid'},
{'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
],
};
/// Descriptor for `DebugAnnotationName`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List debugAnnotationNameDescriptor = $convert.base64Decode(
'ChNEZWJ1Z0Fubm90YXRpb25OYW1lEhAKA2lpZBgBIAEoBFIDaWlkEhIKBG5hbWUYAiABKAlSBG'
'5hbWU=');
@@ -22,8 +22,8 @@ import 'dart:core' as $core;
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb;
import 'process_descriptor.pb.dart' as $3;
import 'thread_descriptor.pb.dart' as $4;
import 'process_descriptor.pb.dart' as $4;
import 'thread_descriptor.pb.dart' as $5;
export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
@@ -45,8 +45,8 @@ class TrackDescriptor extends $pb.GeneratedMessage {
factory TrackDescriptor({
$fixnum.Int64? uuid,
$core.String? name,
$3.ProcessDescriptor? process,
$4.ThreadDescriptor? thread,
$4.ProcessDescriptor? process,
$5.ThreadDescriptor? thread,
$fixnum.Int64? parentUuid,
}) {
final $result = create();
@@ -83,10 +83,10 @@ class TrackDescriptor extends $pb.GeneratedMessage {
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'uuid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..aOS(2, _omitFieldNames ? '' : 'name')
..aOM<$3.ProcessDescriptor>(3, _omitFieldNames ? '' : 'process',
subBuilder: $3.ProcessDescriptor.create)
..aOM<$4.ThreadDescriptor>(4, _omitFieldNames ? '' : 'thread',
subBuilder: $4.ThreadDescriptor.create)
..aOM<$4.ProcessDescriptor>(3, _omitFieldNames ? '' : 'process',
subBuilder: $4.ProcessDescriptor.create)
..aOM<$5.ThreadDescriptor>(4, _omitFieldNames ? '' : 'thread',
subBuilder: $5.ThreadDescriptor.create)
..a<$fixnum.Int64>(
5, _omitFieldNames ? '' : 'parentUuid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
@@ -157,9 +157,9 @@ class TrackDescriptor extends $pb.GeneratedMessage {
/// from other sources (e.g. ftrace) for the same process into a single
/// timeline view.
@$pb.TagNumber(3)
$3.ProcessDescriptor get process => $_getN(2);
$4.ProcessDescriptor get process => $_getN(2);
@$pb.TagNumber(3)
set process($3.ProcessDescriptor v) {
set process($4.ProcessDescriptor v) {
$_setField(3, v);
}
@@ -168,7 +168,7 @@ class TrackDescriptor extends $pb.GeneratedMessage {
@$pb.TagNumber(3)
void clearProcess() => $_clearField(3);
@$pb.TagNumber(3)
$3.ProcessDescriptor ensureProcess() => $_ensure(2);
$4.ProcessDescriptor ensureProcess() => $_ensure(2);
/// Associate the track with a thread, indicating that the track's events
/// describe synchronous code execution on the thread. There should only be one
@@ -178,9 +178,9 @@ class TrackDescriptor extends $pb.GeneratedMessage {
/// from other sources (e.g. ftrace) for the same thread into a single timeline
/// view.
@$pb.TagNumber(4)
$4.ThreadDescriptor get thread => $_getN(3);
$5.ThreadDescriptor get thread => $_getN(3);
@$pb.TagNumber(4)
set thread($4.ThreadDescriptor v) {
set thread($5.ThreadDescriptor v) {
$_setField(4, v);
}
@@ -189,7 +189,7 @@ class TrackDescriptor extends $pb.GeneratedMessage {
@$pb.TagNumber(4)
void clearThread() => $_clearField(4);
@$pb.TagNumber(4)
$4.ThreadDescriptor ensureThread() => $_ensure(3);
$5.ThreadDescriptor ensureThread() => $_ensure(3);
/// A parent track reference can be used to describe relationships between
/// tracks. For example, to define an asynchronous track which is scoped to a
@@ -29,7 +29,7 @@ export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
export 'track_event.pbenum.dart';
enum TrackEvent_NameField { name, notSet }
enum TrackEvent_NameField { nameIid, name, notSet }
/// Trace events emitted by client instrumentation library (TRACE_EVENT macros),
/// which describe activity on a track, such as a thread or asynchronous event
@@ -96,8 +96,10 @@ enum TrackEvent_NameField { name, notSet }
/// Next reserved id: 13 (up to 15). Next id: 50.
class TrackEvent extends $pb.GeneratedMessage {
factory TrackEvent({
$core.Iterable<$fixnum.Int64>? categoryIids,
$core.Iterable<$1.DebugAnnotation>? debugAnnotations,
TrackEvent_Type? type,
$fixnum.Int64? nameIid,
$fixnum.Int64? trackUuid,
$core.Iterable<$core.String>? categories,
$core.String? name,
@@ -105,12 +107,18 @@ class TrackEvent extends $pb.GeneratedMessage {
$core.Iterable<$fixnum.Int64>? terminatingFlowIds,
}) {
final $result = create();
if (categoryIids != null) {
$result.categoryIids.addAll(categoryIids);
}
if (debugAnnotations != null) {
$result.debugAnnotations.addAll(debugAnnotations);
}
if (type != null) {
$result.type = type;
}
if (nameIid != null) {
$result.nameIid = nameIid;
}
if (trackUuid != null) {
$result.trackUuid = trackUuid;
}
@@ -138,6 +146,7 @@ class TrackEvent extends $pb.GeneratedMessage {
static const $core.Map<$core.int, TrackEvent_NameField>
_TrackEvent_NameFieldByTag = {
10: TrackEvent_NameField.nameIid,
23: TrackEvent_NameField.name,
0: TrackEvent_NameField.notSet
};
@@ -146,7 +155,9 @@ class TrackEvent extends $pb.GeneratedMessage {
package:
const $pb.PackageName(_omitMessageNames ? '' : 'perfetto.protos'),
createEmptyInstance: create)
..oo(0, [23])
..oo(0, [10, 23])
..p<$fixnum.Int64>(
3, _omitFieldNames ? '' : 'categoryIids', $pb.PbFieldType.PU6)
..pc<$1.DebugAnnotation>(
4, _omitFieldNames ? '' : 'debugAnnotations', $pb.PbFieldType.PM,
subBuilder: $1.DebugAnnotation.create)
@@ -154,6 +165,9 @@ class TrackEvent extends $pb.GeneratedMessage {
defaultOrMaker: TrackEvent_Type.TYPE_UNSPECIFIED,
valueOf: TrackEvent_Type.valueOf,
enumValues: TrackEvent_Type.values)
..a<$fixnum.Int64>(
10, _omitFieldNames ? '' : 'nameIid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..a<$fixnum.Int64>(
11, _omitFieldNames ? '' : 'trackUuid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
@@ -190,53 +204,73 @@ class TrackEvent extends $pb.GeneratedMessage {
_TrackEvent_NameFieldByTag[$_whichOneof(0)]!;
void clearNameField() => $_clearField($_whichOneof(0));
/// Names of categories of the event. In the client library, categories are a
/// way to turn groups of individual events on or off.
/// interned EventCategoryName.
@$pb.TagNumber(3)
$pb.PbList<$fixnum.Int64> get categoryIids => $_getList(0);
/// Unstable key/value annotations shown in the trace viewer but not intended
/// for metrics use.
@$pb.TagNumber(4)
$pb.PbList<$1.DebugAnnotation> get debugAnnotations => $_getList(0);
$pb.PbList<$1.DebugAnnotation> get debugAnnotations => $_getList(1);
@$pb.TagNumber(9)
TrackEvent_Type get type => $_getN(1);
TrackEvent_Type get type => $_getN(2);
@$pb.TagNumber(9)
set type(TrackEvent_Type v) {
$_setField(9, v);
}
@$pb.TagNumber(9)
$core.bool hasType() => $_has(1);
$core.bool hasType() => $_has(2);
@$pb.TagNumber(9)
void clearType() => $_clearField(9);
/// interned EventName.
@$pb.TagNumber(10)
$fixnum.Int64 get nameIid => $_getI64(3);
@$pb.TagNumber(10)
set nameIid($fixnum.Int64 v) {
$_setInt64(3, v);
}
@$pb.TagNumber(10)
$core.bool hasNameIid() => $_has(3);
@$pb.TagNumber(10)
void clearNameIid() => $_clearField(10);
/// Identifies the track of the event. The default value may be overridden
/// using TrackEventDefaults, e.g., to specify the track of the TraceWriter's
/// sequence (in most cases sequence = one thread). If no value is specified
/// here or in TrackEventDefaults, the TrackEvent will be associated with an
/// implicit trace-global track (uuid 0). See TrackDescriptor::uuid.
@$pb.TagNumber(11)
$fixnum.Int64 get trackUuid => $_getI64(2);
$fixnum.Int64 get trackUuid => $_getI64(4);
@$pb.TagNumber(11)
set trackUuid($fixnum.Int64 v) {
$_setInt64(2, v);
$_setInt64(4, v);
}
@$pb.TagNumber(11)
$core.bool hasTrackUuid() => $_has(2);
$core.bool hasTrackUuid() => $_has(4);
@$pb.TagNumber(11)
void clearTrackUuid() => $_clearField(11);
/// non-interned variant.
@$pb.TagNumber(22)
$pb.PbList<$core.String> get categories => $_getList(3);
$pb.PbList<$core.String> get categories => $_getList(5);
/// non-interned variant.
@$pb.TagNumber(23)
$core.String get name => $_getSZ(4);
$core.String get name => $_getSZ(6);
@$pb.TagNumber(23)
set name($core.String v) {
$_setString(4, v);
$_setString(6, v);
}
@$pb.TagNumber(23)
$core.bool hasName() => $_has(4);
$core.bool hasName() => $_has(6);
@$pb.TagNumber(23)
void clearName() => $_clearField(23);
@@ -255,14 +289,172 @@ class TrackEvent extends $pb.GeneratedMessage {
/// Flows can also be explicitly terminated (see |terminating_flow_ids|), so
/// that the same ID can later be reused for another flow.
@$pb.TagNumber(47)
$pb.PbList<$fixnum.Int64> get flowIds => $_getList(5);
$pb.PbList<$fixnum.Int64> get flowIds => $_getList(7);
/// List of flow ids which should terminate on this event, otherwise same as
/// |flow_ids|.
/// Any one flow ID should be either listed as part of |flow_ids| OR
/// |terminating_flow_ids|, not both.
@$pb.TagNumber(48)
$pb.PbList<$fixnum.Int64> get terminatingFlowIds => $_getList(6);
$pb.PbList<$fixnum.Int64> get terminatingFlowIds => $_getList(8);
}
class EventCategory extends $pb.GeneratedMessage {
factory EventCategory({
$fixnum.Int64? iid,
$core.String? name,
}) {
final $result = create();
if (iid != null) {
$result.iid = iid;
}
if (name != null) {
$result.name = name;
}
return $result;
}
EventCategory._() : super();
factory EventCategory.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory EventCategory.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'EventCategory',
package:
const $pb.PackageName(_omitMessageNames ? '' : 'perfetto.protos'),
createEmptyInstance: create)
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'iid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..aOS(2, _omitFieldNames ? '' : 'name')
..hasRequiredFields = false;
@$core.Deprecated('Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
EventCategory clone() => EventCategory()..mergeFromMessage(this);
@$core.Deprecated('Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
EventCategory copyWith(void Function(EventCategory) updates) =>
super.copyWith((message) => updates(message as EventCategory))
as EventCategory;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static EventCategory create() => EventCategory._();
EventCategory createEmptyInstance() => create();
static $pb.PbList<EventCategory> createRepeated() =>
$pb.PbList<EventCategory>();
@$core.pragma('dart2js:noInline')
static EventCategory getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<EventCategory>(create);
static EventCategory? _defaultInstance;
@$pb.TagNumber(1)
$fixnum.Int64 get iid => $_getI64(0);
@$pb.TagNumber(1)
set iid($fixnum.Int64 v) {
$_setInt64(0, v);
}
@$pb.TagNumber(1)
$core.bool hasIid() => $_has(0);
@$pb.TagNumber(1)
void clearIid() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get name => $_getSZ(1);
@$pb.TagNumber(2)
set name($core.String v) {
$_setString(1, v);
}
@$pb.TagNumber(2)
$core.bool hasName() => $_has(1);
@$pb.TagNumber(2)
void clearName() => $_clearField(2);
}
class EventName extends $pb.GeneratedMessage {
factory EventName({
$fixnum.Int64? iid,
$core.String? name,
}) {
final $result = create();
if (iid != null) {
$result.iid = iid;
}
if (name != null) {
$result.name = name;
}
return $result;
}
EventName._() : super();
factory EventName.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory EventName.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'EventName',
package:
const $pb.PackageName(_omitMessageNames ? '' : 'perfetto.protos'),
createEmptyInstance: create)
..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'iid', $pb.PbFieldType.OU6,
defaultOrMaker: $fixnum.Int64.ZERO)
..aOS(2, _omitFieldNames ? '' : 'name')
..hasRequiredFields = false;
@$core.Deprecated('Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
EventName clone() => EventName()..mergeFromMessage(this);
@$core.Deprecated('Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
EventName copyWith(void Function(EventName) updates) =>
super.copyWith((message) => updates(message as EventName)) as EventName;
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static EventName create() => EventName._();
EventName createEmptyInstance() => create();
static $pb.PbList<EventName> createRepeated() => $pb.PbList<EventName>();
@$core.pragma('dart2js:noInline')
static EventName getDefault() =>
_defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<EventName>(create);
static EventName? _defaultInstance;
@$pb.TagNumber(1)
$fixnum.Int64 get iid => $_getI64(0);
@$pb.TagNumber(1)
set iid($fixnum.Int64 v) {
$_setInt64(0, v);
}
@$pb.TagNumber(1)
$core.bool hasIid() => $_has(0);
@$pb.TagNumber(1)
void clearIid() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get name => $_getSZ(1);
@$pb.TagNumber(2)
set name($core.String v) {
$_setString(1, v);
}
@$pb.TagNumber(2)
$core.bool hasName() => $_has(1);
@$pb.TagNumber(2)
void clearName() => $_clearField(2);
}
const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
@@ -25,7 +25,9 @@ import 'dart:typed_data' as $typed_data;
const TrackEvent$json = {
'1': 'TrackEvent',
'2': [
{'1': 'category_iids', '3': 3, '4': 3, '5': 4, '10': 'categoryIids'},
{'1': 'categories', '3': 22, '4': 3, '5': 9, '10': 'categories'},
{'1': 'name_iid', '3': 10, '4': 1, '5': 4, '9': 0, '10': 'nameIid'},
{'1': 'name', '3': 23, '4': 1, '5': 9, '9': 0, '10': 'name'},
{
'1': 'type',
@@ -72,11 +74,38 @@ const TrackEvent_Type$json = {
/// Descriptor for `TrackEvent`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List trackEventDescriptor = $convert.base64Decode(
'CgpUcmFja0V2ZW50Eh4KCmNhdGVnb3JpZXMYFiADKAlSCmNhdGVnb3JpZXMSFAoEbmFtZRgXIA'
'EoCUgAUgRuYW1lEjQKBHR5cGUYCSABKA4yIC5wZXJmZXR0by5wcm90b3MuVHJhY2tFdmVudC5U'
'eXBlUgR0eXBlEh0KCnRyYWNrX3V1aWQYCyABKARSCXRyYWNrVXVpZBIZCghmbG93X2lkcxgvIA'
'MoBlIHZmxvd0lkcxIwChR0ZXJtaW5hdGluZ19mbG93X2lkcxgwIAMoBlISdGVybWluYXRpbmdG'
'bG93SWRzEk0KEWRlYnVnX2Fubm90YXRpb25zGAQgAygLMiAucGVyZmV0dG8ucHJvdG9zLkRlYn'
'VnQW5ub3RhdGlvblIQZGVidWdBbm5vdGF0aW9ucyJYCgRUeXBlEhQKEFRZUEVfVU5TUEVDSUZJ'
'RUQQABIUChBUWVBFX1NMSUNFX0JFR0lOEAESEgoOVFlQRV9TTElDRV9FTkQQAhIQCgxUWVBFX0'
'lOU1RBTlQQA0IMCgpuYW1lX2ZpZWxk');
'CgpUcmFja0V2ZW50EiMKDWNhdGVnb3J5X2lpZHMYAyADKARSDGNhdGVnb3J5SWlkcxIeCgpjYX'
'RlZ29yaWVzGBYgAygJUgpjYXRlZ29yaWVzEhsKCG5hbWVfaWlkGAogASgESABSB25hbWVJaWQS'
'FAoEbmFtZRgXIAEoCUgAUgRuYW1lEjQKBHR5cGUYCSABKA4yIC5wZXJmZXR0by5wcm90b3MuVH'
'JhY2tFdmVudC5UeXBlUgR0eXBlEh0KCnRyYWNrX3V1aWQYCyABKARSCXRyYWNrVXVpZBIZCghm'
'bG93X2lkcxgvIAMoBlIHZmxvd0lkcxIwChR0ZXJtaW5hdGluZ19mbG93X2lkcxgwIAMoBlISdG'
'VybWluYXRpbmdGbG93SWRzEk0KEWRlYnVnX2Fubm90YXRpb25zGAQgAygLMiAucGVyZmV0dG8u'
'cHJvdG9zLkRlYnVnQW5ub3RhdGlvblIQZGVidWdBbm5vdGF0aW9ucyJYCgRUeXBlEhQKEFRZUE'
'VfVU5TUEVDSUZJRUQQABIUChBUWVBFX1NMSUNFX0JFR0lOEAESEgoOVFlQRV9TTElDRV9FTkQQ'
'AhIQCgxUWVBFX0lOU1RBTlQQA0IMCgpuYW1lX2ZpZWxk');
@$core.Deprecated('Use eventCategoryDescriptor instead')
const EventCategory$json = {
'1': 'EventCategory',
'2': [
{'1': 'iid', '3': 1, '4': 1, '5': 4, '10': 'iid'},
{'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
],
};
/// Descriptor for `EventCategory`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List eventCategoryDescriptor = $convert.base64Decode(
'Cg1FdmVudENhdGVnb3J5EhAKA2lpZBgBIAEoBFIDaWlkEhIKBG5hbWUYAiABKAlSBG5hbWU=');
@$core.Deprecated('Use eventNameDescriptor instead')
const EventName$json = {
'1': 'EventName',
'2': [
{'1': 'iid', '3': 1, '4': 1, '5': 4, '10': 'iid'},
{'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
],
};
/// Descriptor for `EventName`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List eventNameDescriptor = $convert.base64Decode(
'CglFdmVudE5hbWUSEAoDaWlkGAEgASgEUgNpaWQSEgoEbmFtZRgCIAEoCVIEbmFtZQ==');
+4
View File
@@ -268,6 +268,10 @@ class Malloc : public AllStatic {
static inline void Free(T* old_array, intptr_t old_len) {
free(old_array);
}
// Allow templated containers to check if this allocator supports
// freeing individual allocations.
static constexpr bool kSupportsFreeingIndividualAllocations = true;
};
template <typename T>
+138
View File
@@ -13,6 +13,7 @@
#include "perfetto/ext/tracing/core/trace_packet.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "vm/hash_map.h"
#include "vm/json_stream.h"
#include "vm/os.h"
#include "vm/protos/perfetto/common/builtin_clock.pbzero.h"
@@ -120,6 +121,143 @@ inline void AppendPacketToJSONBase64String(
}
}
// Sequence of elements which can be interned by |BytesInterner|.
//
// Equality and hash are defined in terms of raw byte content.
template <typename T>
struct InternedBytes {
InternedBytes(const T* data, intptr_t length)
: data(data),
length(length),
hash(HashBytes(reinterpret_cast<const uint8_t*>(data),
length * sizeof(T))),
iid(0) {}
InternedBytes(const T* data, intptr_t length, uword hash, uint64_t iid)
: data(data), length(length), hash(hash), iid(iid) {}
bool Equals(const InternedBytes& other) const {
if (length != other.length) {
return false;
}
return memcmp(data, other.data, length * sizeof(T)) == 0;
}
uword Hash() const { return hash; }
const T* const data;
const intptr_t length;
const uword hash;
// Interning id. Only set after interning and does not participate in
// equality or hash computations.
const uint64_t iid;
};
// Interning dictionary used to construct various parts of |InternedData|
// message.
template <typename T, typename Allocator>
class BytesInterner
: public BaseDirectChainedHashMap<PointerSetKeyValueTrait<InternedBytes<T>>,
ValueObject,
Allocator> {
using Base =
BaseDirectChainedHashMap<PointerSetKeyValueTrait<InternedBytes<T>>,
ValueObject,
Allocator>;
public:
explicit BytesInterner(Allocator* allocator = nullptr) : Base(allocator) {}
~BytesInterner() {
if constexpr (Allocator::kSupportsFreeingIndividualAllocations) {
auto it = Base::GetIterator();
while (auto pair = it.Next()) {
Dispose(*pair);
}
}
}
uint64_t Intern(const T* data, const intptr_t length) {
InternedBytes<T> key(data, length);
if (auto interned = Base::Lookup(&key)) {
return (*interned)->iid;
}
const uint64_t iid = Base::Size() + 1;
Base::Insert(Copy(key, iid));
return iid;
}
// Enumerate all entries added to this interner since the last call to this
// function.
template <typename F>
void FlushNewlyInternedTo(F&& callback) {
// Note: we never remove elements from this map so we can just iterate
// |pairs_| linearly.
for (uint32_t i = first_to_flush_; i < Base::next_pair_index_; i++) {
callback(*Base::pairs_[i]);
}
first_to_flush_ = Base::next_pair_index_;
}
// Returns |true| if there are entries added to this interner since the
// last call to |FlushNewlyInternedTo|
bool HasNewlyInternedEntries() const {
return first_to_flush_ < Base::next_pair_index_;
}
private:
Allocator* allocator() const { return Base::allocator_; }
InternedBytes<T>* Copy(const InternedBytes<T>& interned, uint64_t iid) const {
auto data_copy = allocator()->template Alloc<T>(interned.length);
memcpy(data_copy, interned.data, interned.length * sizeof(T)); // NOLINT
auto copy = allocator()->template Alloc<InternedBytes<T>>(1);
new (copy) InternedBytes<T>(data_copy, interned.length, interned.hash, iid);
return copy;
}
void Dispose(InternedBytes<T>* interned) {
if constexpr (Allocator::kSupportsFreeingIndividualAllocations) {
allocator()->Free(const_cast<T*>(interned->data),
interned->length * sizeof(T));
allocator()->Free(interned, 1);
}
}
// The index of the first entry which was not flushed via
// |FlushNewlyInternedTo|.
uint32_t first_to_flush_ = 0;
};
template <typename Allocator>
class StringInterner : public ValueObject {
public:
explicit StringInterner(Allocator* allocator = nullptr)
: bytes_interner_(allocator) {}
uint64_t Intern(const char* str) {
// +1 to include terminating NUL character.
return bytes_interner_.Intern(str, strlen(str) + 1);
}
bool HasNewlyInternedEntries() const {
return bytes_interner_.HasNewlyInternedEntries();
}
template <typename F>
void FlushNewlyInternedTo(F&& callback) {
bytes_interner_.FlushNewlyInternedTo(
[callback = std::move(callback)](const auto& interned_bytes) {
callback(interned_bytes.iid, interned_bytes.data);
});
}
private:
BytesInterner<char, Allocator> bytes_interner_;
};
} // namespace perfetto_utils
} // namespace dart
@@ -25,12 +25,15 @@ namespace protos {
namespace pbzero {
class Callstack;
class DebugAnnotationName;
class EventCategory;
class EventName;
class Frame;
class InternedString;
class Mapping;
class InternedData_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/19,
/*MAX_FIELD_ID=*/29,
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
public:
InternedData_Decoder(const uint8_t* data, size_t len)
@@ -40,6 +43,21 @@ class InternedData_Decoder : public ::protozero::TypedProtoDecoder<
raw.size()) {}
explicit InternedData_Decoder(const ::protozero::ConstBytes& raw)
: TypedProtoDecoder(raw.data, raw.size) {}
bool has_event_categories() const { return at<1>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstBytes> event_categories()
const {
return GetRepeated<::protozero::ConstBytes>(1);
}
bool has_event_names() const { return at<2>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstBytes> event_names()
const {
return GetRepeated<::protozero::ConstBytes>(2);
}
bool has_debug_annotation_names() const { return at<3>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstBytes>
debug_annotation_names() const {
return GetRepeated<::protozero::ConstBytes>(3);
}
bool has_mapping_paths() const { return at<17>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstBytes> mapping_paths()
const {
@@ -63,22 +81,71 @@ class InternedData_Decoder : public ::protozero::TypedProtoDecoder<
const {
return GetRepeated<::protozero::ConstBytes>(7);
}
bool has_debug_annotation_string_values() const { return at<29>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstBytes>
debug_annotation_string_values() const {
return GetRepeated<::protozero::ConstBytes>(29);
}
};
class InternedData : public ::protozero::Message {
public:
using Decoder = InternedData_Decoder;
enum : int32_t {
kEventCategoriesFieldNumber = 1,
kEventNamesFieldNumber = 2,
kDebugAnnotationNamesFieldNumber = 3,
kMappingPathsFieldNumber = 17,
kFunctionNamesFieldNumber = 5,
kMappingsFieldNumber = 19,
kFramesFieldNumber = 6,
kCallstacksFieldNumber = 7,
kDebugAnnotationStringValuesFieldNumber = 29,
};
static constexpr const char* GetName() {
return ".perfetto.protos.InternedData";
}
using FieldMetadata_EventCategories = ::protozero::proto_utils::FieldMetadata<
1,
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
::protozero::proto_utils::ProtoSchemaType::kMessage,
EventCategory,
InternedData>;
static constexpr FieldMetadata_EventCategories kEventCategories{};
template <typename T = EventCategory>
T* add_event_categories() {
return BeginNestedMessage<T>(1);
}
using FieldMetadata_EventNames = ::protozero::proto_utils::FieldMetadata<
2,
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
::protozero::proto_utils::ProtoSchemaType::kMessage,
EventName,
InternedData>;
static constexpr FieldMetadata_EventNames kEventNames{};
template <typename T = EventName>
T* add_event_names() {
return BeginNestedMessage<T>(2);
}
using FieldMetadata_DebugAnnotationNames =
::protozero::proto_utils::FieldMetadata<
3,
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
::protozero::proto_utils::ProtoSchemaType::kMessage,
DebugAnnotationName,
InternedData>;
static constexpr FieldMetadata_DebugAnnotationNames kDebugAnnotationNames{};
template <typename T = DebugAnnotationName>
T* add_debug_annotation_names() {
return BeginNestedMessage<T>(3);
}
using FieldMetadata_MappingPaths = ::protozero::proto_utils::FieldMetadata<
17,
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
@@ -143,6 +210,21 @@ class InternedData : public ::protozero::Message {
T* add_callstacks() {
return BeginNestedMessage<T>(7);
}
using FieldMetadata_DebugAnnotationStringValues =
::protozero::proto_utils::FieldMetadata<
29,
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
::protozero::proto_utils::ProtoSchemaType::kMessage,
InternedString,
InternedData>;
static constexpr FieldMetadata_DebugAnnotationStringValues
kDebugAnnotationStringValues{};
template <typename T = InternedString>
T* add_debug_annotation_string_values() {
return BeginNestedMessage<T>(29);
}
};
} // namespace pbzero
@@ -59,6 +59,10 @@ package perfetto.protos;
// Next reserved id: 8 (up to 15).
// Next id: 29.
message InternedData {
repeated EventCategory event_categories = 1;
repeated EventName event_names = 2;
repeated DebugAnnotationName debug_annotation_names = 3;
// Note: field IDs up to 15 should be used for frequent data only.
// Paths to executable files.
@@ -72,4 +76,6 @@ message InternedData {
repeated Frame frames = 6;
// A callstack of a program.
repeated Callstack callstacks = 7;
// Interned string values in the DebugAnnotation proto.
repeated InternedString debug_annotation_string_values = 29;
}
@@ -24,8 +24,80 @@ namespace perfetto {
namespace protos {
namespace pbzero {
class DebugAnnotationName_Decoder
: public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
public:
DebugAnnotationName_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
explicit DebugAnnotationName_Decoder(const std::string& raw)
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
raw.size()) {}
explicit DebugAnnotationName_Decoder(const ::protozero::ConstBytes& raw)
: TypedProtoDecoder(raw.data, raw.size) {}
bool has_iid() const { return at<1>().valid(); }
uint64_t iid() const { return at<1>().as_uint64(); }
bool has_name() const { return at<2>().valid(); }
::protozero::ConstChars name() const { return at<2>().as_string(); }
};
class DebugAnnotationName : public ::protozero::Message {
public:
using Decoder = DebugAnnotationName_Decoder;
enum : int32_t {
kIidFieldNumber = 1,
kNameFieldNumber = 2,
};
static constexpr const char* GetName() {
return ".perfetto.protos.DebugAnnotationName";
}
using FieldMetadata_Iid = ::protozero::proto_utils::FieldMetadata<
1,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
DebugAnnotationName>;
static constexpr FieldMetadata_Iid kIid{};
void set_iid(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_Iid::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_Name = ::protozero::proto_utils::FieldMetadata<
2,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kString,
std::string,
DebugAnnotationName>;
static constexpr FieldMetadata_Name kName{};
void set_name(const char* data, size_t size) {
AppendBytes(FieldMetadata_Name::kFieldId, data, size);
}
void set_name(::protozero::ConstChars chars) {
AppendBytes(FieldMetadata_Name::kFieldId, chars.data, chars.size);
}
void set_name(std::string value) {
static constexpr uint32_t field_id = FieldMetadata_Name::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kString>::Append(*this,
field_id,
value);
}
};
class DebugAnnotation_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/10,
/*MAX_FIELD_ID=*/17,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
public:
DebugAnnotation_Decoder(const uint8_t* data, size_t len)
@@ -35,28 +107,52 @@ class DebugAnnotation_Decoder : public ::protozero::TypedProtoDecoder<
raw.size()) {}
explicit DebugAnnotation_Decoder(const ::protozero::ConstBytes& raw)
: TypedProtoDecoder(raw.data, raw.size) {}
bool has_name_iid() const { return at<1>().valid(); }
uint64_t name_iid() const { return at<1>().as_uint64(); }
bool has_name() const { return at<10>().valid(); }
::protozero::ConstChars name() const { return at<10>().as_string(); }
bool has_string_value() const { return at<6>().valid(); }
::protozero::ConstChars string_value() const { return at<6>().as_string(); }
bool has_legacy_json_value() const { return at<9>().valid(); }
::protozero::ConstChars legacy_json_value() const {
return at<9>().as_string();
}
bool has_string_value() const { return at<6>().valid(); }
::protozero::ConstChars string_value() const { return at<6>().as_string(); }
bool has_string_value_iid() const { return at<17>().valid(); }
uint64_t string_value_iid() const { return at<17>().as_uint64(); }
};
class DebugAnnotation : public ::protozero::Message {
public:
using Decoder = DebugAnnotation_Decoder;
enum : int32_t {
kNameIidFieldNumber = 1,
kNameFieldNumber = 10,
kStringValueFieldNumber = 6,
kLegacyJsonValueFieldNumber = 9,
kStringValueFieldNumber = 6,
kStringValueIidFieldNumber = 17,
};
static constexpr const char* GetName() {
return ".perfetto.protos.DebugAnnotation";
}
using FieldMetadata_NameIid = ::protozero::proto_utils::FieldMetadata<
1,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
DebugAnnotation>;
static constexpr FieldMetadata_NameIid kNameIid{};
void set_name_iid(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_NameIid::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_Name = ::protozero::proto_utils::FieldMetadata<
10,
::protozero::proto_utils::RepetitionType::kNotRepeated,
@@ -81,30 +177,6 @@ class DebugAnnotation : public ::protozero::Message {
value);
}
using FieldMetadata_StringValue = ::protozero::proto_utils::FieldMetadata<
6,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kString,
std::string,
DebugAnnotation>;
static constexpr FieldMetadata_StringValue kStringValue{};
void set_string_value(const char* data, size_t size) {
AppendBytes(FieldMetadata_StringValue::kFieldId, data, size);
}
void set_string_value(::protozero::ConstChars chars) {
AppendBytes(FieldMetadata_StringValue::kFieldId, chars.data, chars.size);
}
void set_string_value(std::string value) {
static constexpr uint32_t field_id = FieldMetadata_StringValue::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kString>::Append(*this,
field_id,
value);
}
using FieldMetadata_LegacyJsonValue = ::protozero::proto_utils::FieldMetadata<
9,
::protozero::proto_utils::RepetitionType::kNotRepeated,
@@ -130,6 +202,48 @@ class DebugAnnotation : public ::protozero::Message {
field_id,
value);
}
using FieldMetadata_StringValue = ::protozero::proto_utils::FieldMetadata<
6,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kString,
std::string,
DebugAnnotation>;
static constexpr FieldMetadata_StringValue kStringValue{};
void set_string_value(const char* data, size_t size) {
AppendBytes(FieldMetadata_StringValue::kFieldId, data, size);
}
void set_string_value(::protozero::ConstChars chars) {
AppendBytes(FieldMetadata_StringValue::kFieldId, chars.data, chars.size);
}
void set_string_value(std::string value) {
static constexpr uint32_t field_id = FieldMetadata_StringValue::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kString>::Append(*this,
field_id,
value);
}
using FieldMetadata_StringValueIid = ::protozero::proto_utils::FieldMetadata<
17,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
DebugAnnotation>;
static constexpr FieldMetadata_StringValueIid kStringValueIid{};
void set_string_value_iid(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_StringValueIid::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
};
} // namespace pbzero
@@ -70,15 +70,29 @@ package perfetto.protos;
message DebugAnnotation {
// Name fields are set only for dictionary entries.
oneof name_field {
// interned DebugAnnotationName.
uint64 name_iid = 1;
// non-interned variant.
string name = 10;
}
oneof value {
string string_value = 6;
// Legacy instrumentation may not support conversion of nested data to
// NestedValue yet.
string legacy_json_value = 9;
// interned and non-interned variants of strings.
string string_value = 6;
// Corresponds to |debug_annotation_string_values| field in InternedData.
uint64 string_value_iid = 17;
}
}
// --------------------
// Interned data types:
// --------------------
message DebugAnnotationName {
optional uint64 iid = 1;
optional string name = 2;
}
@@ -63,6 +63,148 @@ const char* TrackEvent_Type_Name(
return "PBZERO_UNKNOWN_ENUM_VALUE";
}
class EventName_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
public:
EventName_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
explicit EventName_Decoder(const std::string& raw)
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
raw.size()) {}
explicit EventName_Decoder(const ::protozero::ConstBytes& raw)
: TypedProtoDecoder(raw.data, raw.size) {}
bool has_iid() const { return at<1>().valid(); }
uint64_t iid() const { return at<1>().as_uint64(); }
bool has_name() const { return at<2>().valid(); }
::protozero::ConstChars name() const { return at<2>().as_string(); }
};
class EventName : public ::protozero::Message {
public:
using Decoder = EventName_Decoder;
enum : int32_t {
kIidFieldNumber = 1,
kNameFieldNumber = 2,
};
static constexpr const char* GetName() {
return ".perfetto.protos.EventName";
}
using FieldMetadata_Iid = ::protozero::proto_utils::FieldMetadata<
1,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
EventName>;
static constexpr FieldMetadata_Iid kIid{};
void set_iid(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_Iid::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_Name = ::protozero::proto_utils::FieldMetadata<
2,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kString,
std::string,
EventName>;
static constexpr FieldMetadata_Name kName{};
void set_name(const char* data, size_t size) {
AppendBytes(FieldMetadata_Name::kFieldId, data, size);
}
void set_name(::protozero::ConstChars chars) {
AppendBytes(FieldMetadata_Name::kFieldId, chars.data, chars.size);
}
void set_name(std::string value) {
static constexpr uint32_t field_id = FieldMetadata_Name::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kString>::Append(*this,
field_id,
value);
}
};
class EventCategory_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/2,
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
public:
EventCategory_Decoder(const uint8_t* data, size_t len)
: TypedProtoDecoder(data, len) {}
explicit EventCategory_Decoder(const std::string& raw)
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
raw.size()) {}
explicit EventCategory_Decoder(const ::protozero::ConstBytes& raw)
: TypedProtoDecoder(raw.data, raw.size) {}
bool has_iid() const { return at<1>().valid(); }
uint64_t iid() const { return at<1>().as_uint64(); }
bool has_name() const { return at<2>().valid(); }
::protozero::ConstChars name() const { return at<2>().as_string(); }
};
class EventCategory : public ::protozero::Message {
public:
using Decoder = EventCategory_Decoder;
enum : int32_t {
kIidFieldNumber = 1,
kNameFieldNumber = 2,
};
static constexpr const char* GetName() {
return ".perfetto.protos.EventCategory";
}
using FieldMetadata_Iid = ::protozero::proto_utils::FieldMetadata<
1,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
EventCategory>;
static constexpr FieldMetadata_Iid kIid{};
void set_iid(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_Iid::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_Name = ::protozero::proto_utils::FieldMetadata<
2,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kString,
std::string,
EventCategory>;
static constexpr FieldMetadata_Name kName{};
void set_name(const char* data, size_t size) {
AppendBytes(FieldMetadata_Name::kFieldId, data, size);
}
void set_name(::protozero::ConstChars chars) {
AppendBytes(FieldMetadata_Name::kFieldId, chars.data, chars.size);
}
void set_name(std::string value) {
static constexpr uint32_t field_id = FieldMetadata_Name::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kString>::Append(*this,
field_id,
value);
}
};
class TrackEvent_Decoder : public ::protozero::TypedProtoDecoder<
/*MAX_FIELD_ID=*/48,
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
@@ -74,11 +216,17 @@ class TrackEvent_Decoder : public ::protozero::TypedProtoDecoder<
raw.size()) {}
explicit TrackEvent_Decoder(const ::protozero::ConstBytes& raw)
: TypedProtoDecoder(raw.data, raw.size) {}
bool has_category_iids() const { return at<3>().valid(); }
::protozero::RepeatedFieldIterator<uint64_t> category_iids() const {
return GetRepeated<uint64_t>(3);
}
bool has_categories() const { return at<22>().valid(); }
::protozero::RepeatedFieldIterator<::protozero::ConstChars> categories()
const {
return GetRepeated<::protozero::ConstChars>(22);
}
bool has_name_iid() const { return at<10>().valid(); }
uint64_t name_iid() const { return at<10>().as_uint64(); }
bool has_name() const { return at<23>().valid(); }
::protozero::ConstChars name() const { return at<23>().as_string(); }
bool has_type() const { return at<9>().valid(); }
@@ -104,7 +252,9 @@ class TrackEvent : public ::protozero::Message {
public:
using Decoder = TrackEvent_Decoder;
enum : int32_t {
kCategoryIidsFieldNumber = 3,
kCategoriesFieldNumber = 22,
kNameIidFieldNumber = 10,
kNameFieldNumber = 23,
kTypeFieldNumber = 9,
kTrackUuidFieldNumber = 11,
@@ -125,6 +275,24 @@ class TrackEvent : public ::protozero::Message {
static inline const Type TYPE_SLICE_END = Type::TYPE_SLICE_END;
static inline const Type TYPE_INSTANT = Type::TYPE_INSTANT;
using FieldMetadata_CategoryIids = ::protozero::proto_utils::FieldMetadata<
3,
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
TrackEvent>;
static constexpr FieldMetadata_CategoryIids kCategoryIids{};
void add_category_iids(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_CategoryIids::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_Categories = ::protozero::proto_utils::FieldMetadata<
22,
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
@@ -149,6 +317,24 @@ class TrackEvent : public ::protozero::Message {
value);
}
using FieldMetadata_NameIid = ::protozero::proto_utils::FieldMetadata<
10,
::protozero::proto_utils::RepetitionType::kNotRepeated,
::protozero::proto_utils::ProtoSchemaType::kUint64,
uint64_t,
TrackEvent>;
static constexpr FieldMetadata_NameIid kNameIid{};
void set_name_iid(uint64_t value) {
static constexpr uint32_t field_id = FieldMetadata_NameIid::kFieldId;
// Call the appropriate protozero::Message::Append(field_id, ...)
// method based on the type of the field.
::protozero::internal::FieldWriter<
::protozero::proto_utils::ProtoSchemaType::kUint64>::Append(*this,
field_id,
value);
}
using FieldMetadata_Name = ::protozero::proto_utils::FieldMetadata<
23,
::protozero::proto_utils::RepetitionType::kNotRepeated,
@@ -95,6 +95,11 @@ package perfetto.protos;
//
// Next reserved id: 13 (up to 15). Next id: 50.
message TrackEvent {
// Names of categories of the event. In the client library, categories are a
// way to turn groups of individual events on or off.
// interned EventCategoryName.
repeated uint64 category_iids = 3;
// non-interned variant.
repeated string categories = 22;
// Optional name of the event for its display in trace viewer. May be left
@@ -104,6 +109,8 @@ message TrackEvent {
// changing. Instead, they should use typed arguments to identify the events
// they are interested in.
oneof name_field {
// interned EventName.
uint64 name_iid = 10;
// non-interned variant.
string name = 23;
}
@@ -176,3 +183,17 @@ message TrackEvent {
// for metrics use.
repeated DebugAnnotation debug_annotations = 4;
}
// --------------------
// Interned data types:
// --------------------
message EventCategory {
optional uint64 iid = 1;
optional string name = 2;
}
message EventName {
optional uint64 iid = 1;
optional string name = 2;
}
+268 -47
View File
@@ -32,6 +32,7 @@
#include "vm/perfetto_utils.h"
#include "vm/protos/perfetto/common/builtin_clock.pbzero.h"
#include "vm/protos/perfetto/trace/clock_snapshot.pbzero.h"
#include "vm/protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "vm/protos/perfetto/trace/trace_packet.pbzero.h"
#include "vm/protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#include "vm/protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
@@ -82,6 +83,10 @@ DEFINE_FLAG(charp,
DEFAULT_TIMELINE_RECORDER,
"Select the timeline recorder used. "
"Valid values: none, " SUPPORTED_TIMELINE_RECORDERS)
DEFINE_FLAG(bool,
intern_strings_when_writing_perfetto_timeline,
false,
"Intern strings when writing timeline in perfetto format.")
// Implementation notes:
//
@@ -802,6 +807,156 @@ void TimelineEvent::PrintJSON(JSONWriter* writer) const {
#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
namespace {
// Trait used to map 64-bit ids (e.g. isolate or isolate group id) to
// interned id of a corresponding string representation.
//
// This way we only need to generate formatted string once, instead of
// repeatedly formatting it and then interning resulting string to get an
// iid.
class IdToIidTrait {
public:
struct Pair {
uint64_t id;
uint64_t formatted_iid;
};
using Key = uint64_t;
using Value = uint64_t;
static Key KeyOf(const Pair& kv) { return kv.id; }
static Value ValueOf(const Pair& kv) { return kv.formatted_iid; }
static uword Hash(Key key) {
return Utils::WordHash(static_cast<intptr_t>(key));
}
static bool IsKeyEqual(const Pair& kv, Key key) { return kv.id == key; }
};
using IdToIidMap = MallocDirectChainedHashMap<IdToIidTrait>;
class InternedDataBuilder : public ValueObject {
private:
using SequenceFlags = perfetto::protos::pbzero::TracePacket_SequenceFlags;
public:
// InternedData contains multiple independent interning dictionaries which
// are used for different attributes.
#define PERFETTO_INTERNED_STRINGS_FIELDS_LIST(V) \
V(event_categories, name) \
V(event_names, name) \
V(debug_annotation_names, name) \
V(debug_annotation_string_values, str)
// Direct access for known strings.
#define PERFETTO_COMMON_INTERNED_STRINGS_LIST(V) \
V(debug_annotation_names, isolateId) \
V(debug_annotation_names, isolateGroupId)
InternedDataBuilder() = default;
// Emit all strings added since the last invocation of |AttachInternedDataTo|
// into |interned_data| of the given |TracePacket|.
//
// Mark the packet as depending on incremental state.
void AttachInternedDataTo(perfetto::protos::pbzero::TracePacket* packet) {
if (!AnyInternerHasNewlyInternedEntries()) {
return;
}
packet->set_sequence_flags(sequence_flags_);
// The first packet will have SEQ_INCREMENTAL_STATE_CLEARED
// the rest will just have SEQ_NEEDS_INCREMENTAL_STATE.
sequence_flags_ &= ~SequenceFlags::SEQ_INCREMENTAL_STATE_CLEARED;
auto interned_data = packet->set_interned_data();
// Flush individual interning dictionaries.
#define FLUSH_FIELD(name, proto_field) \
name##_.FlushNewlyInternedTo([interned_data](auto& iid, auto& str) { \
auto entry = interned_data->add_##name(); \
entry->set_iid(iid); \
entry->set_##proto_field(str); \
});
PERFETTO_INTERNED_STRINGS_FIELDS_LIST(FLUSH_FIELD)
#undef FLUSH_FIELD
}
#define DEFINE_GETTER(name, proto_field) \
perfetto_utils::StringInterner<Malloc>& name() { return name##_; }
PERFETTO_INTERNED_STRINGS_FIELDS_LIST(DEFINE_GETTER)
#undef DEFINE_GETTER
#define DEFINE_GETTER_FOR_COMMON_STRING(category, str) \
uint64_t iid_##str() { \
if (iid_##str##_ == 0) { \
iid_##str##_ = category().Intern(#str); \
} \
return iid_##str##_; \
}
PERFETTO_COMMON_INTERNED_STRINGS_LIST(DEFINE_GETTER_FOR_COMMON_STRING)
#undef DEFINE_GETTER_FOR_COMMON_STRING
uint64_t InternFormattedIsolateId(uint64_t isolate_id) {
return InternFormattedIdForDebugAnnotation(
isolate_id_to_iid_of_formatted_string_,
ISOLATE_SERVICE_ID_FORMAT_STRING, isolate_id);
}
uint64_t InternFormattedIsolateGroupId(uint64_t isolate_group_id) {
return InternFormattedIdForDebugAnnotation(
isolate_group_id_to_iid_of_formatted_string_,
ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING, isolate_group_id);
}
private:
template <std::size_t kFormatLen>
uint64_t InternFormattedIdForDebugAnnotation(IdToIidMap& cache,
const char (&format)[kFormatLen],
uint64_t id) {
if (auto iid = cache.Lookup(id)) {
return iid->formatted_iid;
}
// 20 characters is enough to format any uint64_t (or int64_t) value.
char formatted[kFormatLen + 20];
Utils::SNPrint(formatted, ARRAY_SIZE(formatted), format, id);
auto formatted_iid = debug_annotation_string_values().Intern(formatted);
cache.Insert({id, formatted_iid});
return formatted_iid;
}
bool AnyInternerHasNewlyInternedEntries() const {
#define CHECK_FIELD(name, proto_field) \
if (name##_.HasNewlyInternedEntries()) return true;
PERFETTO_INTERNED_STRINGS_FIELDS_LIST(CHECK_FIELD)
#undef CHECK_FIELD
return false;
}
uint32_t sequence_flags_ = SequenceFlags::SEQ_INCREMENTAL_STATE_CLEARED |
SequenceFlags::SEQ_NEEDS_INCREMENTAL_STATE;
// These are interned in debug_annotation_string_values space.
IdToIidMap isolate_id_to_iid_of_formatted_string_;
IdToIidMap isolate_group_id_to_iid_of_formatted_string_;
#define DEFINE_FIELD_FOR_COMMON_STRING(category, str) uint64_t iid_##str##_ = 0;
PERFETTO_COMMON_INTERNED_STRINGS_LIST(DEFINE_FIELD_FOR_COMMON_STRING)
#undef DEFINE_FIELD_FOR_COMMON_STRING
#define DEFINE_FIELD(name, proto_field) \
perfetto_utils::StringInterner<Malloc> name##_;
PERFETTO_INTERNED_STRINGS_FIELDS_LIST(DEFINE_FIELD)
#undef DEFINE_FIELD
DISALLOW_COPY_AND_ASSIGN(InternedDataBuilder);
};
class TracePacketWriter : public ValueObject {
public:
using TracePacket = perfetto::protos::pbzero::TracePacket;
@@ -811,8 +966,11 @@ class TracePacketWriter : public ValueObject {
std::function<void(protozero::HeapBuffered<TracePacket>&)>;
TracePacketWriter(protozero::HeapBuffered<TracePacket>& packet,
WriteCallback&& write_callback)
: packet_(packet), write_callback_(std::move(write_callback)) {}
WriteCallback&& write_callback,
bool intern_strings)
: packet_(packet),
write_callback_(std::move(write_callback)),
intern_strings_(intern_strings) {}
// Converting contents of the given |TimelineEvent| into one or more
// Perfetto packets and write them out using |write_callback_| which
@@ -870,6 +1028,7 @@ class TracePacketWriter : public ValueObject {
int64_t timestamp,
const TimelineEvent& event) {
PopulatePacket(event_type, timestamp, event);
interned_data_builder_.AttachInternedDataTo(packet_.get());
write_callback_(packet_);
packet_.Reset();
}
@@ -884,7 +1043,7 @@ class TracePacketWriter : public ValueObject {
perfetto_utils::SetTimestampAndMonotonicClockId(packet_.get(), timestamp);
TrackEvent* track_event = packet_->set_track_event();
track_event->add_categories(event.stream()->name());
SetTrackEventCategory(track_event, event.stream()->name());
track_event->set_track_uuid(IsSync(event_type)
? OSThread::ThreadIdToIntPtr(event.thread())
@@ -892,7 +1051,7 @@ class TracePacketWriter : public ValueObject {
const auto perfetto_type = ToPerfettoType(event_type);
track_event->set_type(perfetto_type);
if (perfetto_type != TrackEvent::Type::TYPE_SLICE_END) {
track_event->set_name(event.label());
SetTrackEventName(track_event, event.label());
for (intptr_t i = 0; i < event.flow_id_count(); ++i) {
// TODO(derekx): |TrackEvent|s have a |terminating_flow_ids| field that
// we aren't able to populate right now because we aren't keeping track
@@ -911,37 +1070,120 @@ class TracePacketWriter : public ValueObject {
ASSERT(event.GetNumArguments() == 1);
perfetto::protos::pbzero::DebugAnnotation& debug_annotation =
*track_event->add_debug_annotations();
debug_annotation.set_name(event.arguments()[0].name);
SetDebugAnnotationName(debug_annotation, event.arguments()[0].name);
debug_annotation.set_legacy_json_value(event.arguments()[0].value);
} else {
for (intptr_t i = 0; i < event.GetNumArguments(); ++i) {
perfetto::protos::pbzero::DebugAnnotation& debug_annotation =
*track_event->add_debug_annotations();
debug_annotation.set_name(event.arguments()[i].name);
debug_annotation.set_string_value(event.arguments()[i].value);
SetDebugAnnotationName(debug_annotation, event.arguments()[0].name);
SetDebugAnnotationStringValue(debug_annotation,
event.arguments()[i].value);
}
}
}
if (event.HasIsolateId()) {
perfetto::protos::pbzero::DebugAnnotation& debug_annotation =
*track_event->add_debug_annotations();
debug_annotation.set_name("isolateId");
std::unique_ptr<const char[]> formatted_isolate_id =
event.GetFormattedIsolateId();
debug_annotation.set_string_value(formatted_isolate_id.get());
SetDebugAnnotationName(debug_annotation, "isolateId", [this](auto name) {
return interned_data_builder_.iid_isolateId();
});
SetDebugAnnotationStringValueFromFormattedId(
debug_annotation, ISOLATE_SERVICE_ID_FORMAT_STRING,
event.isolate_id(), [this](auto id) {
return interned_data_builder_.InternFormattedIsolateId(id);
});
}
if (event.HasIsolateGroupId()) {
perfetto::protos::pbzero::DebugAnnotation& debug_annotation =
*track_event->add_debug_annotations();
debug_annotation.set_name("isolateGroupId");
std::unique_ptr<const char[]> formatted_isolate_group =
event.GetFormattedIsolateGroupId();
debug_annotation.set_string_value(formatted_isolate_group.get());
SetDebugAnnotationName(
debug_annotation, "isolateGroupId", [this](auto name) {
return interned_data_builder_.iid_isolateGroupId();
});
SetDebugAnnotationStringValueFromFormattedId(
debug_annotation, ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING,
event.isolate_group_id(), [this](auto id) {
return interned_data_builder_.InternFormattedIsolateGroupId(id);
});
}
}
// Helpers for setting string valued properties on |TrackEvent| and
// |DebugAnnotation|, these can use interning if |intern_strings_| is
// |true|.
void SetTrackEventCategory(TrackEvent* track_event, const char* value) {
if (intern_strings_) {
track_event->add_category_iids(
interned_data_builder_.event_categories().Intern(value));
} else {
track_event->add_categories(value);
}
}
void SetTrackEventName(TrackEvent* track_event, const char* value) {
if (intern_strings_) {
track_event->set_name_iid(
interned_data_builder_.event_names().Intern(value));
} else {
track_event->set_name(value);
}
}
template <typename F>
void SetDebugAnnotationName(
perfetto::protos::pbzero::DebugAnnotation& debug_annotation,
const char* name,
F&& intern) {
if (intern_strings_) {
debug_annotation.set_name_iid(intern(name));
} else {
debug_annotation.set_name(name);
}
}
void SetDebugAnnotationName(
perfetto::protos::pbzero::DebugAnnotation& debug_annotation,
const char* name) {
SetDebugAnnotationName(debug_annotation, name, [this](auto name) {
return interned_data_builder_.debug_annotation_names().Intern(name);
});
}
void SetDebugAnnotationStringValue(
perfetto::protos::pbzero::DebugAnnotation& debug_annotation,
const char* value) {
if (intern_strings_) {
debug_annotation.set_string_value_iid(
interned_data_builder_.debug_annotation_string_values().Intern(
value));
} else {
debug_annotation.set_string_value(value);
}
}
template <std::size_t kFormatLen, typename F>
void SetDebugAnnotationStringValueFromFormattedId(
perfetto::protos::pbzero::DebugAnnotation& debug_annotation,
const char (&format)[kFormatLen],
uint64_t id,
F&& intern_id) {
if (intern_strings_) {
debug_annotation.set_string_value_iid(intern_id(id));
} else {
// 20 characters is enough to format any uint64_t (or int64_t) value.
char formatted[kFormatLen + 20];
Utils::SNPrint(formatted, ARRAY_SIZE(formatted), format, id);
debug_annotation.set_string_value(formatted);
}
}
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>& packet_;
WriteCallback write_callback_;
const bool intern_strings_;
InternedDataBuilder interned_data_builder_;
DISALLOW_COPY_AND_ASSIGN(TracePacketWriter);
};
@@ -978,34 +1220,6 @@ bool TimelineEvent::HasIsolateGroupId() const {
return isolate_group_id_ != ILLEGAL_ISOLATE_GROUP_ID;
}
std::unique_ptr<const char[]> TimelineEvent::GetFormattedIsolateId() const {
ASSERT(HasIsolateId());
intptr_t formatted_isolate_id_buffer_size =
Utils::SNPrint(nullptr, 0, ISOLATE_SERVICE_ID_FORMAT_STRING,
isolate_id_) +
1;
auto formatted_isolate_id =
std::make_unique<char[]>(formatted_isolate_id_buffer_size);
Utils::SNPrint(formatted_isolate_id.get(), formatted_isolate_id_buffer_size,
ISOLATE_SERVICE_ID_FORMAT_STRING, isolate_id_);
return formatted_isolate_id;
}
std::unique_ptr<const char[]> TimelineEvent::GetFormattedIsolateGroupId()
const {
ASSERT(HasIsolateGroupId());
intptr_t formatted_isolate_group_id_buffer_size =
Utils::SNPrint(nullptr, 0, ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING,
isolate_group_id_) +
1;
auto formatted_isolate_group_id =
std::make_unique<char[]>(formatted_isolate_group_id_buffer_size);
Utils::SNPrint(formatted_isolate_group_id.get(),
formatted_isolate_group_id_buffer_size,
ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING, isolate_group_id_);
return formatted_isolate_group_id;
}
TimelineTrackMetadata::TimelineTrackMetadata(intptr_t pid,
intptr_t tid,
CStringUniquePtr&& track_name)
@@ -1669,9 +1883,13 @@ void TimelineEventBufferedRecorder::PrintJSONEvents(
void TimelineEventBufferedRecorder::PrintPerfettoEvents(
JSONBase64String* jsonBase64String,
const TimelineEventFilter& filter) {
TracePacketWriter writer(packet(), [&jsonBase64String](auto& packet) {
perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String, &packet);
});
TracePacketWriter writer(
packet(),
[&jsonBase64String](auto& packet) {
perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
&packet);
},
FLAG_intern_strings_when_writing_perfetto_timeline);
PrintEventsCommon(filter, [&writer](const TimelineEvent& event) {
writer.WriteEvent(event);
@@ -2124,7 +2342,10 @@ static TimelineEventRecorder* CreateTimelineEventPerfettoFileRecorder(
TimelineEventPerfettoFileRecorder::TimelineEventPerfettoFileRecorder(
const char* path)
: TimelineEventFileRecorderBase(path),
writer_(packet(), [this](auto& packet) { this->WritePacket(&packet); }) {
writer_(
packet(),
[this](auto& packet) { this->WritePacket(&packet); },
FLAG_intern_strings_when_writing_perfetto_timeline) {
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>& packet =
this->packet();
-2
View File
@@ -456,8 +456,6 @@ class TimelineEvent {
bool HasIsolateId() const;
bool HasIsolateGroupId() const;
std::unique_ptr<const char[]> GetFormattedIsolateId() const;
std::unique_ptr<const char[]> GetFormattedIsolateGroupId() const;
// The lowest time value stored in this event.
int64_t LowTime() const;
+4
View File
@@ -93,6 +93,10 @@ class Zone {
static void ClearCache();
static intptr_t Size() { return total_size_; }
// Allow templated containers to check if this allocator supports
// freeing individual allocations.
static constexpr bool kSupportsFreeingIndividualAllocations = false;
private:
Zone();
~Zone(); // Delete all memory associated with the zone.