[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:
committed by
Commit Queue
parent
c0b423fbab
commit
2a437c54a0
@@ -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);
|
||||
|
||||
+66
-21
@@ -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');
|
||||
|
||||
+44
-6
@@ -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
|
||||
|
||||
+141
-13
@@ -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');
|
||||
|
||||
+28
-4
@@ -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=');
|
||||
|
||||
+14
-14
@@ -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
|
||||
|
||||
+206
-14
@@ -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');
|
||||
|
||||
+37
-8
@@ -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==');
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user