mirror of
https://github.com/dart-lang/sdk
synced 2024-09-04 16:03:44 +00:00
Reland "[VM] Begin supporting Perfetto file recorder"
This is a reland of commit 7424295ce9
The differences between this reland and the original CL are: now the
Perfetto file recorder does not get built in PRODUCT builds, and it does
not get built unless the SUPPORT_PERFETTO macro is defined.
TEST=Recorded traces with the Perfetto file recorder and explored them
in Perfetto's trace viewer, CI
Original change's description:
> [VM] Begin supporting Perfetto file recorder
>
> This CL adds the `TimelineEventPerfettoFileRecorder` class, which is a
> timeline recorder that writes a trace to file in Perfetto's proto
> format. This CL supports the recording of all types of timeline events
> except flow events. Support for flow events will be added in a future
> CL.
>
> TEST=Recorded traces with the Perfetto file recorder and explored them
> in Perfetto's trace viewer, CI
>
> Change-Id: Iaa2051e536589a473c5e15f9de9bb9c251f13d38
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278942
> Reviewed-by: Ben Konyi <bkonyi@google.com>
> Commit-Queue: Derek Xu <derekx@google.com>
Change-Id: I8713f704b5fbeed5f1231012bce8a32aaf566ae4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286020
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Derek Xu <derekx@google.com>
This commit is contained in:
parent
fa3a72fa7e
commit
4cd9c9c666
|
@ -146,7 +146,10 @@ config("dart_arch_config") {
|
|||
}
|
||||
|
||||
config("dart_config") {
|
||||
defines = []
|
||||
# We temporarily need to define this to exclude code that depends on Perfetto
|
||||
# from being built in google3, as there is currently a problem linking
|
||||
# Perfetto into google3 builds.
|
||||
defines = [ "SUPPORT_PERFETTO" ]
|
||||
|
||||
if (dart_debug) {
|
||||
defines += [ "DEBUG" ]
|
||||
|
@ -291,6 +294,7 @@ source_set("dart_api") {
|
|||
|
||||
library_for_all_configs("libdart") {
|
||||
target_type = dart_component_kind
|
||||
extra_nonproduct_deps = [ "vm:libprotozero" ]
|
||||
extra_deps = [
|
||||
":generate_version_cc_file",
|
||||
"third_party/double-conversion/src:libdouble_conversion",
|
||||
|
|
|
@ -39,7 +39,11 @@ def RunLint(input_api, output_api):
|
|||
# Find all .cc and .h files in the change list.
|
||||
for git_file in input_api.AffectedTextFiles():
|
||||
filename = git_file.AbsoluteLocalPath()
|
||||
if filename.endswith('.cc') or filename.endswith('.h'):
|
||||
if filename.endswith('.cc') or (
|
||||
# cpplint complains about the style of #ifndefs in our .pbzero.h
|
||||
# files, but they are generated by the protozero compiler, so we
|
||||
# can't fix this.
|
||||
not filename.endswith('.pbzero.h') and filename.endswith('.h')):
|
||||
# Run cpplint on the file.
|
||||
cpplint.ProcessFile(filename, 1)
|
||||
# Check for memcpy use.
|
||||
|
|
|
@ -957,6 +957,7 @@ executable("run_vm_tests") {
|
|||
":dart_snapshot_cc",
|
||||
":standalone_dart_io",
|
||||
"..:libdart_precompiler_testing",
|
||||
"../vm:libprotozero", # for timeline_test
|
||||
"//third_party/boringssl", # for secure_socket_utils_test
|
||||
"//third_party/zlib",
|
||||
]
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#endif
|
||||
|
||||
#if defined(USING_ADDRESS_SANITIZER)
|
||||
extern "C" void __asan_unpoison_memory_region(void*, size_t);
|
||||
extern "C" void __asan_unpoison_memory_region(void const volatile*, size_t);
|
||||
#define NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address")))
|
||||
#define ASAN_UNPOISON(ptr, len) __asan_unpoison_memory_region(ptr, len)
|
||||
#else // defined(USING_ADDRESS_SANITIZER)
|
||||
|
|
|
@ -8,6 +8,30 @@ import 'dart:math';
|
|||
|
||||
import 'package:pool/pool.dart';
|
||||
|
||||
// "perfetto_build_flags.h" is included by some Perfetto headers that we
|
||||
// include, but it is generated at build-time. We prevent clang-tidy from
|
||||
// reporting a "file not found" error by ensuring that this file exists in
|
||||
// Iout/DebugX64/gen and passing
|
||||
// -Iout/DebugX64/gen/third_party/perfetto/build_config to clang-tidy below.
|
||||
Future<void> generatePerfettoBuildFlags() async {
|
||||
final processResult = await Process.run(
|
||||
'./tools/build.py',
|
||||
['-mdebug', '-ax64', '--no-goma', 'third_party/perfetto/gn:gen_buildflags'],
|
||||
);
|
||||
|
||||
final int exitCode = processResult.exitCode;
|
||||
final String stdout = processResult.stdout.trim();
|
||||
final String stderr = processResult.stderr.trim();
|
||||
|
||||
if (exitCode != 0) {
|
||||
print('exit-code: $exitCode');
|
||||
print('stdout:');
|
||||
print('${stdout}');
|
||||
print('stderr:');
|
||||
print('${stderr}');
|
||||
}
|
||||
}
|
||||
|
||||
const String clangTidy = './buildtools/linux-x64/clang/bin/clang-tidy';
|
||||
|
||||
List<String> compilerFlagsForFile(String filepath) {
|
||||
|
@ -16,7 +40,9 @@ List<String> compilerFlagsForFile(String filepath) {
|
|||
'-Ithird_party',
|
||||
'-Iruntime/include',
|
||||
'-Ithird_party/boringssl/src/include',
|
||||
'-Ithird_party/perfetto/include',
|
||||
'-Ithird_party/zlib',
|
||||
'-Iout/DebugX64/gen/third_party/perfetto/build_config',
|
||||
'-DTARGET_ARCH_X64',
|
||||
'-DDEBUG',
|
||||
'-DDART_TARGET_OS_LINUX',
|
||||
|
@ -123,6 +149,8 @@ final Set<String> excludedFiles = Set<String>.from([
|
|||
]);
|
||||
|
||||
main(List<String> files) async {
|
||||
await generatePerfettoBuildFlags();
|
||||
|
||||
bool isFirstFailure = true;
|
||||
|
||||
files = files.where((filepath) => !excludedFiles.contains(filepath)).toList();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# 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.
|
||||
|
||||
import("//third_party/protobuf/proto_library.gni")
|
||||
import("../../build/executable_suffix.gni")
|
||||
import("../../sdk/lib/async/async_sources.gni")
|
||||
import("../../sdk/lib/collection/collection_sources.gni")
|
||||
|
@ -67,6 +68,79 @@ config("libdart_vm_config") {
|
|||
}
|
||||
}
|
||||
|
||||
# This is a modified copy of Perfetto's template of the same name defined in
|
||||
# //third_party/perfetto/gn/proto_library.gni.
|
||||
# This is equivalent to the proto_library template (generation of .h/.cc from
|
||||
# .proto files) but enables generation using the protozero plugin.
|
||||
# The generated files will have the .pbzero.{cc,h} suffix, as opposed to the
|
||||
# .pb.{cc,h} of the official proto library.
|
||||
template("protozero_library") {
|
||||
proto_library(target_name) {
|
||||
perfetto_root_path = "//third_party/perfetto/"
|
||||
|
||||
generate_cc = false
|
||||
generate_python = false
|
||||
generator_plugin_label =
|
||||
perfetto_root_path + "src/protozero/protoc_plugin:protozero_plugin"
|
||||
generator_plugin_suffix = ".pbzero"
|
||||
|
||||
if (defined(invoker.deps)) {
|
||||
deps = invoker.deps
|
||||
} else {
|
||||
deps = []
|
||||
}
|
||||
|
||||
forward_variables_from(invoker,
|
||||
[
|
||||
"defines",
|
||||
"generator_plugin_options",
|
||||
"include_dirs",
|
||||
"proto_in_dir",
|
||||
"proto_out_dir",
|
||||
"sources",
|
||||
"testonly",
|
||||
"visibility",
|
||||
"generate_descriptor",
|
||||
"propagate_imports_configs",
|
||||
"import_dirs",
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
# This target is not a dependency of any other GN target. It is required to make
|
||||
# ./protos/tools/compile_perfetto_protos.dart work though.
|
||||
protozero_library("perfetto_protos") {
|
||||
proto_in_dir = "."
|
||||
proto_out_dir = "//runtime/vm"
|
||||
generator_plugin_options = "wrapper_namespace=pbzero"
|
||||
sources = [
|
||||
"protos/perfetto/common/builtin_clock.proto",
|
||||
"protos/perfetto/trace/clock_snapshot.proto",
|
||||
"protos/perfetto/trace/trace_packet.proto",
|
||||
"protos/perfetto/trace/track_event/debug_annotation.proto",
|
||||
"protos/perfetto/trace/track_event/process_descriptor.proto",
|
||||
"protos/perfetto/trace/track_event/thread_descriptor.proto",
|
||||
"protos/perfetto/trace/track_event/track_descriptor.proto",
|
||||
"protos/perfetto/trace/track_event/track_event.proto",
|
||||
]
|
||||
}
|
||||
|
||||
# This config needs to be propagated to all targets that depend on
|
||||
# ":libprotozero".
|
||||
config("libprotozero_config") {
|
||||
include_dirs = [
|
||||
"//third_party/perfetto/include",
|
||||
"$root_gen_dir/third_party/perfetto/build_config",
|
||||
]
|
||||
}
|
||||
|
||||
# This target includes Perfetto's protozero target, which we need to serialize
|
||||
# proto messages. This target also propagates ":libprotozero_config".
|
||||
source_set("libprotozero") {
|
||||
public_configs = [ ":libprotozero_config" ]
|
||||
deps = [ "//third_party/perfetto/src/protozero:protozero" ]
|
||||
}
|
||||
|
||||
library_for_all_configs("libdart_vm") {
|
||||
target_type = "source_set"
|
||||
extra_product_deps = [
|
||||
|
@ -74,12 +148,14 @@ library_for_all_configs("libdart_vm") {
|
|||
"//third_party/icu:icuuc_hidden_visibility",
|
||||
]
|
||||
extra_nonproduct_deps = [
|
||||
":libprotozero",
|
||||
"//third_party/icu:icui18n",
|
||||
"//third_party/icu:icuuc",
|
||||
]
|
||||
extra_deps = []
|
||||
if (is_fuchsia) {
|
||||
if (using_fuchsia_gn_sdk) {
|
||||
extra_deps = [
|
||||
extra_deps += [
|
||||
"$fuchsia_sdk_root/fidl/fuchsia.intl",
|
||||
"$fuchsia_sdk_root/pkg/async",
|
||||
"$fuchsia_sdk_root/pkg/async-default",
|
||||
|
@ -92,7 +168,7 @@ library_for_all_configs("libdart_vm") {
|
|||
"$fuchsia_sdk_root/pkg/trace-engine",
|
||||
]
|
||||
} else if (using_fuchsia_sdk) {
|
||||
extra_deps = [
|
||||
extra_deps += [
|
||||
"$fuchsia_sdk_root/fidl:fuchsia.intl",
|
||||
"$fuchsia_sdk_root/pkg:async-loop",
|
||||
"$fuchsia_sdk_root/pkg:async-loop-default",
|
||||
|
@ -103,7 +179,7 @@ library_for_all_configs("libdart_vm") {
|
|||
"$fuchsia_sdk_root/pkg:trace-engine",
|
||||
]
|
||||
} else {
|
||||
extra_deps = [
|
||||
extra_deps += [
|
||||
"//sdk/fidl/fuchsia.intl",
|
||||
"//sdk/lib/sys/cpp",
|
||||
"//sdk/lib/sys/inspect/cpp",
|
||||
|
@ -131,13 +207,15 @@ library_for_all_configs_with_compiler("libdart_compiler") {
|
|||
public_configs = [ ":libdart_vm_config" ]
|
||||
sources = rebase_path(compiler_sources, ".", "./compiler/")
|
||||
include_dirs = [ ".." ]
|
||||
extra_nonproduct_deps = [ ":libprotozero" ]
|
||||
extra_deps = []
|
||||
if (is_fuchsia) {
|
||||
if (using_fuchsia_gn_sdk) {
|
||||
extra_deps = [ "$fuchsia_sdk_root/pkg/trace-engine" ]
|
||||
extra_deps += [ "$fuchsia_sdk_root/pkg/trace-engine" ]
|
||||
} else if (using_fuchsia_sdk) {
|
||||
extra_deps = [ "$fuchsia_sdk_root/pkg:trace-engine" ]
|
||||
extra_deps += [ "$fuchsia_sdk_root/pkg:trace-engine" ]
|
||||
} else {
|
||||
extra_deps = [
|
||||
extra_deps += [
|
||||
"//zircon/public/lib/fbl",
|
||||
"//zircon/system/ulib/trace-engine",
|
||||
]
|
||||
|
@ -147,13 +225,15 @@ library_for_all_configs_with_compiler("libdart_compiler") {
|
|||
|
||||
library_for_all_configs("libdart_lib") {
|
||||
target_type = "source_set"
|
||||
extra_nonproduct_deps = [ ":libprotozero" ]
|
||||
extra_deps = []
|
||||
if (is_fuchsia) {
|
||||
if (using_fuchsia_gn_sdk) {
|
||||
extra_deps = [ "$fuchsia_sdk_root/pkg/trace-engine" ]
|
||||
extra_deps += [ "$fuchsia_sdk_root/pkg/trace-engine" ]
|
||||
} else if (using_fuchsia_sdk) {
|
||||
extra_deps = [ "$fuchsia_sdk_root/pkg:trace-engine" ]
|
||||
extra_deps += [ "$fuchsia_sdk_root/pkg:trace-engine" ]
|
||||
} else {
|
||||
extra_deps = [
|
||||
extra_deps += [
|
||||
"//zircon/public/lib/fbl",
|
||||
"//zircon/system/ulib/trace-engine",
|
||||
]
|
||||
|
@ -232,6 +312,13 @@ group("kernel_platform_files") {
|
|||
}
|
||||
|
||||
executable("offsets_extractor") {
|
||||
# The timeline cannot be accessed from the generated executable, so we define
|
||||
# DART_DISABLE_TIMELINE to strip out the timeline source code. The precise
|
||||
# reason why we do this is to avoid missing header errors, as the Perfetto
|
||||
# proto headers are not built as a dependency of this target, but are
|
||||
# transitively included in this target when DART_DISABLE_TIMELINE is not
|
||||
# defined.
|
||||
defines = [ "DART_DISABLE_TIMELINE" ]
|
||||
configs += [
|
||||
"..:dart_arch_config",
|
||||
"..:dart_config",
|
||||
|
@ -243,6 +330,13 @@ executable("offsets_extractor") {
|
|||
}
|
||||
|
||||
executable("offsets_extractor_precompiled_runtime") {
|
||||
# The timeline cannot be accessed from the generated executable, so we define
|
||||
# DART_DISABLE_TIMELINE to strip out the timeline source code. The precise
|
||||
# reason why we do this is to avoid missing header errors, as the Perfetto
|
||||
# proto headers are not built as a dependency of this target, but are
|
||||
# transitively included in this target when DART_DISABLE_TIMELINE is not
|
||||
# defined.
|
||||
defines = [ "DART_DISABLE_TIMELINE" ]
|
||||
configs += [
|
||||
"..:dart_arch_config",
|
||||
"..:dart_config",
|
||||
|
|
|
@ -113,9 +113,10 @@ const intptr_t kDefaultNewGenSemiMaxSize = (kWordSize <= 4) ? 8 : 16;
|
|||
#define NOT_IN_PRECOMPILED_RUNTIME(code) code
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#if defined(DART_ENABLE_TIMELINE) || !defined(PRODUCT) || \
|
||||
defined(DART_HOST_OS_FUCHSIA) || defined(DART_TARGET_OS_FUCHSIA) || \
|
||||
defined(DART_TARGET_OS_ANDROID) || defined(DART_TARGET_OS_MACOS)
|
||||
#if !defined(DART_DISABLE_TIMELINE) && \
|
||||
(defined(DART_ENABLE_TIMELINE) || !defined(PRODUCT) || \
|
||||
defined(DART_HOST_OS_FUCHSIA) || defined(DART_TARGET_OS_FUCHSIA) || \
|
||||
defined(DART_TARGET_OS_ANDROID) || defined(DART_TARGET_OS_MACOS))
|
||||
#define SUPPORT_TIMELINE 1
|
||||
#endif
|
||||
|
||||
|
|
3
runtime/vm/protos/.gitignore
vendored
Normal file
3
runtime/vm/protos/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# The protozero compiler generates empty .pbzero.cc files for compatibility
|
||||
# reasons (crbug.com/998165). We can ignore them.
|
||||
*.pbzero.cc
|
46
runtime/vm/protos/perfetto/common/builtin_clock.pbzero.h
Normal file
46
runtime/vm/protos/perfetto/common/builtin_clock.pbzero.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
// 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.
|
||||
|
||||
// IMPORTANT: This file should only ever be modified by modifying the
|
||||
// corresponding .proto file and then running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root
|
||||
// directory.
|
||||
// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
|
||||
|
||||
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_COMMON_BUILTIN_CLOCK_PROTO_H_
|
||||
#define PERFETTO_PROTOS_PROTOS_PERFETTO_COMMON_BUILTIN_CLOCK_PROTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perfetto/protozero/field_writer.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/packed_repeated_fields.h"
|
||||
#include "perfetto/protozero/proto_decoder.h"
|
||||
#include "perfetto/protozero/proto_utils.h"
|
||||
|
||||
namespace perfetto {
|
||||
namespace protos {
|
||||
namespace pbzero {
|
||||
|
||||
enum BuiltinClock : int32_t {
|
||||
BUILTIN_CLOCK_MONOTONIC = 3,
|
||||
};
|
||||
|
||||
constexpr BuiltinClock BuiltinClock_MIN = BuiltinClock::BUILTIN_CLOCK_MONOTONIC;
|
||||
constexpr BuiltinClock BuiltinClock_MAX = BuiltinClock::BUILTIN_CLOCK_MONOTONIC;
|
||||
|
||||
PERFETTO_PROTOZERO_CONSTEXPR14_OR_INLINE
|
||||
const char* BuiltinClock_Name(::perfetto::protos::pbzero::BuiltinClock value) {
|
||||
switch (value) {
|
||||
case ::perfetto::protos::pbzero::BuiltinClock::BUILTIN_CLOCK_MONOTONIC:
|
||||
return "BUILTIN_CLOCK_MONOTONIC";
|
||||
}
|
||||
return "PBZERO_UNKNOWN_ENUM_VALUE";
|
||||
}
|
||||
|
||||
} // namespace pbzero
|
||||
} // namespace protos
|
||||
} // namespace perfetto
|
||||
#endif // Include guard.
|
31
runtime/vm/protos/perfetto/common/builtin_clock.proto
Normal file
31
runtime/vm/protos/perfetto/common/builtin_clock.proto
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: This is a manually minified version of Perfetto's
|
||||
// builtin_clock.proto.
|
||||
|
||||
// IMPORTANT: The coresponding .pbzero.h file must be regenerated after
|
||||
// any change is made to this file. This can be done by running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the
|
||||
// SDK root directory.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
enum BuiltinClock {
|
||||
BUILTIN_CLOCK_MONOTONIC = 3;
|
||||
}
|
195
runtime/vm/protos/perfetto/trace/clock_snapshot.pbzero.h
Normal file
195
runtime/vm/protos/perfetto/trace/clock_snapshot.pbzero.h
Normal file
|
@ -0,0 +1,195 @@
|
|||
// 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.
|
||||
|
||||
// IMPORTANT: This file should only ever be modified by modifying the
|
||||
// corresponding .proto file and then running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root
|
||||
// directory.
|
||||
// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
|
||||
|
||||
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_CLOCK_SNAPSHOT_PROTO_H_
|
||||
#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_CLOCK_SNAPSHOT_PROTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perfetto/protozero/field_writer.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/packed_repeated_fields.h"
|
||||
#include "perfetto/protozero/proto_decoder.h"
|
||||
#include "perfetto/protozero/proto_utils.h"
|
||||
|
||||
namespace perfetto {
|
||||
namespace protos {
|
||||
namespace pbzero {
|
||||
|
||||
class ClockSnapshot_Clock;
|
||||
enum BuiltinClock : int32_t;
|
||||
|
||||
class ClockSnapshot_Decoder : public ::protozero::TypedProtoDecoder<
|
||||
/*MAX_FIELD_ID=*/2,
|
||||
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
|
||||
public:
|
||||
ClockSnapshot_Decoder(const uint8_t* data, size_t len)
|
||||
: TypedProtoDecoder(data, len) {}
|
||||
explicit ClockSnapshot_Decoder(const std::string& raw)
|
||||
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
|
||||
raw.size()) {}
|
||||
explicit ClockSnapshot_Decoder(const ::protozero::ConstBytes& raw)
|
||||
: TypedProtoDecoder(raw.data, raw.size) {}
|
||||
bool has_clocks() const { return at<1>().valid(); }
|
||||
::protozero::RepeatedFieldIterator<::protozero::ConstBytes> clocks() const {
|
||||
return GetRepeated<::protozero::ConstBytes>(1);
|
||||
}
|
||||
bool has_primary_trace_clock() const { return at<2>().valid(); }
|
||||
int32_t primary_trace_clock() const { return at<2>().as_int32(); }
|
||||
};
|
||||
|
||||
class ClockSnapshot : public ::protozero::Message {
|
||||
public:
|
||||
using Decoder = ClockSnapshot_Decoder;
|
||||
enum : int32_t {
|
||||
kClocksFieldNumber = 1,
|
||||
kPrimaryTraceClockFieldNumber = 2,
|
||||
};
|
||||
static constexpr const char* GetName() {
|
||||
return ".perfetto.protos.ClockSnapshot";
|
||||
}
|
||||
|
||||
using Clock = ::perfetto::protos::pbzero::ClockSnapshot_Clock;
|
||||
|
||||
using FieldMetadata_Clocks = ::protozero::proto_utils::FieldMetadata<
|
||||
1,
|
||||
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
|
||||
::protozero::proto_utils::ProtoSchemaType::kMessage,
|
||||
ClockSnapshot_Clock,
|
||||
ClockSnapshot>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Clocks kClocks() { return {}; }
|
||||
template <typename T = ClockSnapshot_Clock>
|
||||
T* add_clocks() {
|
||||
return BeginNestedMessage<T>(1);
|
||||
}
|
||||
|
||||
using FieldMetadata_PrimaryTraceClock =
|
||||
::protozero::proto_utils::FieldMetadata<
|
||||
2,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kEnum,
|
||||
::perfetto::protos::pbzero::BuiltinClock,
|
||||
ClockSnapshot>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_PrimaryTraceClock kPrimaryTraceClock() {
|
||||
return {};
|
||||
}
|
||||
void set_primary_trace_clock(::perfetto::protos::pbzero::BuiltinClock value) {
|
||||
static constexpr uint32_t field_id =
|
||||
FieldMetadata_PrimaryTraceClock::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kEnum>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
};
|
||||
|
||||
class ClockSnapshot_Clock_Decoder
|
||||
: public ::protozero::TypedProtoDecoder<
|
||||
/*MAX_FIELD_ID=*/2,
|
||||
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
|
||||
public:
|
||||
ClockSnapshot_Clock_Decoder(const uint8_t* data, size_t len)
|
||||
: TypedProtoDecoder(data, len) {}
|
||||
explicit ClockSnapshot_Clock_Decoder(const std::string& raw)
|
||||
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
|
||||
raw.size()) {}
|
||||
explicit ClockSnapshot_Clock_Decoder(const ::protozero::ConstBytes& raw)
|
||||
: TypedProtoDecoder(raw.data, raw.size) {}
|
||||
bool has_clock_id() const { return at<1>().valid(); }
|
||||
uint32_t clock_id() const { return at<1>().as_uint32(); }
|
||||
bool has_timestamp() const { return at<2>().valid(); }
|
||||
uint64_t timestamp() const { return at<2>().as_uint64(); }
|
||||
};
|
||||
|
||||
class ClockSnapshot_Clock : public ::protozero::Message {
|
||||
public:
|
||||
using Decoder = ClockSnapshot_Clock_Decoder;
|
||||
enum : int32_t {
|
||||
kClockIdFieldNumber = 1,
|
||||
kTimestampFieldNumber = 2,
|
||||
};
|
||||
static constexpr const char* GetName() {
|
||||
return ".perfetto.protos.ClockSnapshot.Clock";
|
||||
}
|
||||
|
||||
using FieldMetadata_ClockId = ::protozero::proto_utils::FieldMetadata<
|
||||
1,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint32,
|
||||
uint32_t,
|
||||
ClockSnapshot_Clock>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_ClockId kClockId() { return {}; }
|
||||
void set_clock_id(uint32_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_ClockId::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint32>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
|
||||
using FieldMetadata_Timestamp = ::protozero::proto_utils::FieldMetadata<
|
||||
2,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint64,
|
||||
uint64_t,
|
||||
ClockSnapshot_Clock>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Timestamp kTimestamp() { return {}; }
|
||||
void set_timestamp(uint64_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_Timestamp::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
|
||||
} // namespace protos
|
||||
} // namespace perfetto
|
||||
#endif // Include guard.
|
56
runtime/vm/protos/perfetto/trace/clock_snapshot.proto
Normal file
56
runtime/vm/protos/perfetto/trace/clock_snapshot.proto
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: This is a manually minified version of Perfetto's
|
||||
// clock_snapshot.proto.
|
||||
|
||||
// IMPORTANT: The coresponding .pbzero.h file must be regenerated after
|
||||
// any change is made to this file. This can be done by running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the
|
||||
// SDK root directory.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
import "protos/perfetto/common/builtin_clock.proto";
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
// A snapshot of clock readings to allow for trace alignment.
|
||||
message ClockSnapshot {
|
||||
message Clock {
|
||||
// Clock IDs have the following semantic:
|
||||
// [1, 63]: Builtin types, see BuiltinClock from
|
||||
// ../common/builtin_clock.proto.
|
||||
// [64, 127]: User-defined clocks. These clocks are sequence-scoped. They
|
||||
// are only valid within the same |trusted_packet_sequence_id|
|
||||
// (i.e. only for TracePacket(s) emitted by the same TraceWriter
|
||||
// that emitted the clock snapshot).
|
||||
// [128, MAX]: Reserved for future use. The idea is to allow global clock
|
||||
// IDs and setting this ID to hash(full_clock_name) & ~127.
|
||||
optional uint32 clock_id = 1;
|
||||
|
||||
// Absolute timestamp. Unit is ns unless specified otherwise by the
|
||||
// unit_multiplier_ns field below.
|
||||
optional uint64 timestamp = 2;
|
||||
}
|
||||
repeated Clock clocks = 1;
|
||||
|
||||
// The authoritative clock domain for the trace. Defaults to BOOTTIME, but can
|
||||
// be overridden in TraceConfig's builtin_data_sources. Trace processor will
|
||||
// attempt to translate packet/event timestamps from various data sources (and
|
||||
// their chosen clock domains) to this domain during import.
|
||||
optional BuiltinClock primary_trace_clock = 2;
|
||||
}
|
223
runtime/vm/protos/perfetto/trace/trace_packet.pbzero.h
Normal file
223
runtime/vm/protos/perfetto/trace/trace_packet.pbzero.h
Normal file
|
@ -0,0 +1,223 @@
|
|||
// 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.
|
||||
|
||||
// IMPORTANT: This file should only ever be modified by modifying the
|
||||
// corresponding .proto file and then running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root
|
||||
// directory.
|
||||
// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
|
||||
|
||||
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACE_PACKET_PROTO_H_
|
||||
#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACE_PACKET_PROTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perfetto/protozero/field_writer.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/packed_repeated_fields.h"
|
||||
#include "perfetto/protozero/proto_decoder.h"
|
||||
#include "perfetto/protozero/proto_utils.h"
|
||||
|
||||
namespace perfetto {
|
||||
namespace protos {
|
||||
namespace pbzero {
|
||||
|
||||
class ClockSnapshot;
|
||||
class TrackDescriptor;
|
||||
class TrackEvent;
|
||||
|
||||
class TracePacket_Decoder : public ::protozero::TypedProtoDecoder<
|
||||
/*MAX_FIELD_ID=*/60,
|
||||
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
|
||||
public:
|
||||
TracePacket_Decoder(const uint8_t* data, size_t len)
|
||||
: TypedProtoDecoder(data, len) {}
|
||||
explicit TracePacket_Decoder(const std::string& raw)
|
||||
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
|
||||
raw.size()) {}
|
||||
explicit TracePacket_Decoder(const ::protozero::ConstBytes& raw)
|
||||
: TypedProtoDecoder(raw.data, raw.size) {}
|
||||
bool has_timestamp() const { return at<8>().valid(); }
|
||||
uint64_t timestamp() const { return at<8>().as_uint64(); }
|
||||
bool has_timestamp_clock_id() const { return at<58>().valid(); }
|
||||
uint32_t timestamp_clock_id() const { return at<58>().as_uint32(); }
|
||||
bool has_clock_snapshot() const { return at<6>().valid(); }
|
||||
::protozero::ConstBytes clock_snapshot() const { return at<6>().as_bytes(); }
|
||||
bool has_track_event() const { return at<11>().valid(); }
|
||||
::protozero::ConstBytes track_event() const { return at<11>().as_bytes(); }
|
||||
bool has_track_descriptor() const { return at<60>().valid(); }
|
||||
::protozero::ConstBytes track_descriptor() const {
|
||||
return at<60>().as_bytes();
|
||||
}
|
||||
bool has_trusted_packet_sequence_id() const { return at<10>().valid(); }
|
||||
uint32_t trusted_packet_sequence_id() const { return at<10>().as_uint32(); }
|
||||
};
|
||||
|
||||
class TracePacket : public ::protozero::Message {
|
||||
public:
|
||||
using Decoder = TracePacket_Decoder;
|
||||
enum : int32_t {
|
||||
kTimestampFieldNumber = 8,
|
||||
kTimestampClockIdFieldNumber = 58,
|
||||
kClockSnapshotFieldNumber = 6,
|
||||
kTrackEventFieldNumber = 11,
|
||||
kTrackDescriptorFieldNumber = 60,
|
||||
kTrustedPacketSequenceIdFieldNumber = 10,
|
||||
};
|
||||
static constexpr const char* GetName() {
|
||||
return ".perfetto.protos.TracePacket";
|
||||
}
|
||||
|
||||
using FieldMetadata_Timestamp = ::protozero::proto_utils::FieldMetadata<
|
||||
8,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint64,
|
||||
uint64_t,
|
||||
TracePacket>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Timestamp kTimestamp() { return {}; }
|
||||
void set_timestamp(uint64_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_Timestamp::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_TimestampClockId =
|
||||
::protozero::proto_utils::FieldMetadata<
|
||||
58,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint32,
|
||||
uint32_t,
|
||||
TracePacket>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_TimestampClockId kTimestampClockId() {
|
||||
return {};
|
||||
}
|
||||
void set_timestamp_clock_id(uint32_t value) {
|
||||
static constexpr uint32_t field_id =
|
||||
FieldMetadata_TimestampClockId::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint32>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
|
||||
using FieldMetadata_ClockSnapshot = ::protozero::proto_utils::FieldMetadata<
|
||||
6,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kMessage,
|
||||
ClockSnapshot,
|
||||
TracePacket>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_ClockSnapshot kClockSnapshot() { return {}; }
|
||||
template <typename T = ClockSnapshot>
|
||||
T* set_clock_snapshot() {
|
||||
return BeginNestedMessage<T>(6);
|
||||
}
|
||||
|
||||
using FieldMetadata_TrackEvent = ::protozero::proto_utils::FieldMetadata<
|
||||
11,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kMessage,
|
||||
TrackEvent,
|
||||
TracePacket>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_TrackEvent kTrackEvent() { return {}; }
|
||||
template <typename T = TrackEvent>
|
||||
T* set_track_event() {
|
||||
return BeginNestedMessage<T>(11);
|
||||
}
|
||||
|
||||
using FieldMetadata_TrackDescriptor = ::protozero::proto_utils::FieldMetadata<
|
||||
60,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kMessage,
|
||||
TrackDescriptor,
|
||||
TracePacket>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_TrackDescriptor kTrackDescriptor() {
|
||||
return {};
|
||||
}
|
||||
template <typename T = TrackDescriptor>
|
||||
T* set_track_descriptor() {
|
||||
return BeginNestedMessage<T>(60);
|
||||
}
|
||||
|
||||
using FieldMetadata_TrustedPacketSequenceId =
|
||||
::protozero::proto_utils::FieldMetadata<
|
||||
10,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint32,
|
||||
uint32_t,
|
||||
TracePacket>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_TrustedPacketSequenceId
|
||||
kTrustedPacketSequenceId() {
|
||||
return {};
|
||||
}
|
||||
void set_trusted_packet_sequence_id(uint32_t value) {
|
||||
static constexpr uint32_t field_id =
|
||||
FieldMetadata_TrustedPacketSequenceId::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint32>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pbzero
|
||||
} // namespace protos
|
||||
} // namespace perfetto
|
||||
#endif // Include guard.
|
88
runtime/vm/protos/perfetto/trace/trace_packet.proto
Normal file
88
runtime/vm/protos/perfetto/trace/trace_packet.proto
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: This is a manually minified version of Perfetto's
|
||||
// trace_packet.proto.
|
||||
|
||||
// IMPORTANT: The coresponding .pbzero.h file must be regenerated after
|
||||
// any change is made to this file. This can be done by running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the
|
||||
// SDK root directory.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
import "protos/perfetto/trace/clock_snapshot.proto";
|
||||
import "protos/perfetto/trace/track_event/track_descriptor.proto";
|
||||
import "protos/perfetto/trace/track_event/track_event.proto";
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
// TracePacket is the root object of a Perfetto trace.
|
||||
// A Perfetto trace is a linear sequence of TracePacket(s).
|
||||
//
|
||||
// The tracing service guarantees that all TracePacket(s) written by a given
|
||||
// TraceWriter are seen in-order, without gaps or duplicates. If, for any
|
||||
// reason, a TraceWriter sequence becomes invalid, no more packets are returned
|
||||
// to the Consumer (or written into the trace file).
|
||||
// TracePacket(s) written by different TraceWriter(s), hence even different
|
||||
// data sources, can be seen in arbitrary order.
|
||||
// The consumer can re-establish a total order, if interested, using the packet
|
||||
// timestamps, after having synchronized the different clocks onto a global
|
||||
// clock.
|
||||
//
|
||||
// The tracing service is agnostic of the content of TracePacket, with the
|
||||
// exception of few fields (e.g.. trusted_*, trace_config) that are written by
|
||||
// the service itself.
|
||||
//
|
||||
// See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
|
||||
//
|
||||
// Next reserved id: 14 (up to 15).
|
||||
// Next id: 88.
|
||||
message TracePacket {
|
||||
// The timestamp of the TracePacket.
|
||||
// By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
|
||||
// Android). It can be overridden using a different timestamp_clock_id.
|
||||
// The clock domain definition in ClockSnapshot can also override:
|
||||
// - The unit (default: 1ns).
|
||||
// - The absolute vs delta encoding (default: absolute timestamp).
|
||||
optional uint64 timestamp = 8;
|
||||
|
||||
// Specifies the ID of the clock used for the TracePacket |timestamp|. Can be
|
||||
// one of the built-in types from ClockSnapshot::BuiltinClocks, or a
|
||||
// producer-defined clock id.
|
||||
// If unspecified and if no default per-sequence value has been provided via
|
||||
// TracePacketDefaults, it defaults to BuiltinClocks::BOOTTIME.
|
||||
optional uint32 timestamp_clock_id = 58;
|
||||
|
||||
oneof data {
|
||||
ClockSnapshot clock_snapshot = 6;
|
||||
TrackEvent track_event = 11;
|
||||
|
||||
// IDs up to 15 are reserved. They take only one byte to encode their
|
||||
// preamble so should be used for frequent events.
|
||||
|
||||
// Only used by TrackEvent.
|
||||
TrackDescriptor track_descriptor = 60;
|
||||
}
|
||||
|
||||
// Service-assigned identifier of the packet sequence this packet belongs to.
|
||||
// Uniquely identifies a producer + writer pair within the tracing session. A
|
||||
// value of zero denotes an invalid ID. Keep in sync with
|
||||
// TrustedPacket.trusted_packet_sequence_id.
|
||||
oneof optional_trusted_packet_sequence_id {
|
||||
uint32 trusted_packet_sequence_id = 10;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
// 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.
|
||||
|
||||
// IMPORTANT: This file should only ever be modified by modifying the
|
||||
// corresponding .proto file and then running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root
|
||||
// directory.
|
||||
// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
|
||||
|
||||
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_DEBUG_ANNOTATION_PROTO_H_
|
||||
#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_DEBUG_ANNOTATION_PROTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perfetto/protozero/field_writer.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/packed_repeated_fields.h"
|
||||
#include "perfetto/protozero/proto_decoder.h"
|
||||
#include "perfetto/protozero/proto_utils.h"
|
||||
|
||||
namespace perfetto {
|
||||
namespace protos {
|
||||
namespace pbzero {
|
||||
|
||||
class DebugAnnotation_Decoder : public ::protozero::TypedProtoDecoder<
|
||||
/*MAX_FIELD_ID=*/10,
|
||||
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
|
||||
public:
|
||||
DebugAnnotation_Decoder(const uint8_t* data, size_t len)
|
||||
: TypedProtoDecoder(data, len) {}
|
||||
explicit DebugAnnotation_Decoder(const std::string& raw)
|
||||
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
|
||||
raw.size()) {}
|
||||
explicit DebugAnnotation_Decoder(const ::protozero::ConstBytes& raw)
|
||||
: TypedProtoDecoder(raw.data, raw.size) {}
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
class DebugAnnotation : public ::protozero::Message {
|
||||
public:
|
||||
using Decoder = DebugAnnotation_Decoder;
|
||||
enum : int32_t {
|
||||
kNameFieldNumber = 10,
|
||||
kStringValueFieldNumber = 6,
|
||||
kLegacyJsonValueFieldNumber = 9,
|
||||
};
|
||||
static constexpr const char* GetName() {
|
||||
return ".perfetto.protos.DebugAnnotation";
|
||||
}
|
||||
|
||||
using FieldMetadata_Name = ::protozero::proto_utils::FieldMetadata<
|
||||
10,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kString,
|
||||
std::string,
|
||||
DebugAnnotation>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Name kName() { return {}; }
|
||||
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);
|
||||
}
|
||||
|
||||
using FieldMetadata_StringValue = ::protozero::proto_utils::FieldMetadata<
|
||||
6,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kString,
|
||||
std::string,
|
||||
DebugAnnotation>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_StringValue kStringValue() { return {}; }
|
||||
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,
|
||||
::protozero::proto_utils::ProtoSchemaType::kString,
|
||||
std::string,
|
||||
DebugAnnotation>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_LegacyJsonValue kLegacyJsonValue() {
|
||||
return {};
|
||||
}
|
||||
void set_legacy_json_value(const char* data, size_t size) {
|
||||
AppendBytes(FieldMetadata_LegacyJsonValue::kFieldId, data, size);
|
||||
}
|
||||
void set_legacy_json_value(::protozero::ConstChars chars) {
|
||||
AppendBytes(FieldMetadata_LegacyJsonValue::kFieldId, chars.data,
|
||||
chars.size);
|
||||
}
|
||||
void set_legacy_json_value(std::string value) {
|
||||
static constexpr uint32_t field_id =
|
||||
FieldMetadata_LegacyJsonValue::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);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pbzero
|
||||
} // namespace protos
|
||||
} // namespace perfetto
|
||||
#endif // Include guard.
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: This is a manually minified version of Perfetto's
|
||||
// debug_annotation.proto.
|
||||
|
||||
// IMPORTANT: The coresponding .pbzero.h file must be regenerated after
|
||||
// any change is made to this file. This can be done by running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the
|
||||
// SDK root directory.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
// Proto representation of untyped key/value annotations provided in TRACE_EVENT
|
||||
// macros. Users of the Perfetto SDK should prefer to use the
|
||||
// perfetto::TracedValue API to fill these protos, rather than filling them
|
||||
// manually.
|
||||
//
|
||||
// Debug annotations are intended for debug use and are not considered a stable
|
||||
// API of the trace contents. Trace-based metrics that use debug annotation
|
||||
// values are prone to breakage, so please rely on typed TrackEvent fields for
|
||||
// these instead.
|
||||
//
|
||||
// DebugAnnotations support nested arrays and dictionaries. Each entry is
|
||||
// encoded as a single DebugAnnotation message. Only dictionary entries
|
||||
// set the "name" field. The TrackEvent message forms an implicit root
|
||||
// dictionary.
|
||||
//
|
||||
// Example TrackEvent with nested annotations:
|
||||
// track_event {
|
||||
// debug_annotations {
|
||||
// name: "foo"
|
||||
// dict_entries {
|
||||
// name: "a"
|
||||
// bool_value: true
|
||||
// }
|
||||
// dict_entries {
|
||||
// name: "b"
|
||||
// int_value: 123
|
||||
// }
|
||||
// }
|
||||
// debug_annotations {
|
||||
// name: "bar"
|
||||
// array_values {
|
||||
// string_value: "hello"
|
||||
// }
|
||||
// array_values {
|
||||
// string_value: "world"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Next ID: 17.
|
||||
// Reserved ID: 15
|
||||
message DebugAnnotation {
|
||||
// Name fields are set only for dictionary entries.
|
||||
oneof name_field {
|
||||
// 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
// 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.
|
||||
|
||||
// IMPORTANT: This file should only ever be modified by modifying the
|
||||
// corresponding .proto file and then running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root
|
||||
// directory.
|
||||
// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
|
||||
|
||||
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_PROCESS_DESCRIPTOR_PROTO_H_
|
||||
#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_PROCESS_DESCRIPTOR_PROTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perfetto/protozero/field_writer.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/packed_repeated_fields.h"
|
||||
#include "perfetto/protozero/proto_decoder.h"
|
||||
#include "perfetto/protozero/proto_utils.h"
|
||||
|
||||
namespace perfetto {
|
||||
namespace protos {
|
||||
namespace pbzero {
|
||||
|
||||
class ProcessDescriptor_Decoder : public ::protozero::TypedProtoDecoder<
|
||||
/*MAX_FIELD_ID=*/6,
|
||||
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
|
||||
public:
|
||||
ProcessDescriptor_Decoder(const uint8_t* data, size_t len)
|
||||
: TypedProtoDecoder(data, len) {}
|
||||
explicit ProcessDescriptor_Decoder(const std::string& raw)
|
||||
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
|
||||
raw.size()) {}
|
||||
explicit ProcessDescriptor_Decoder(const ::protozero::ConstBytes& raw)
|
||||
: TypedProtoDecoder(raw.data, raw.size) {}
|
||||
bool has_pid() const { return at<1>().valid(); }
|
||||
int32_t pid() const { return at<1>().as_int32(); }
|
||||
bool has_process_name() const { return at<6>().valid(); }
|
||||
::protozero::ConstChars process_name() const { return at<6>().as_string(); }
|
||||
};
|
||||
|
||||
class ProcessDescriptor : public ::protozero::Message {
|
||||
public:
|
||||
using Decoder = ProcessDescriptor_Decoder;
|
||||
enum : int32_t {
|
||||
kPidFieldNumber = 1,
|
||||
kProcessNameFieldNumber = 6,
|
||||
};
|
||||
static constexpr const char* GetName() {
|
||||
return ".perfetto.protos.ProcessDescriptor";
|
||||
}
|
||||
|
||||
using FieldMetadata_Pid = ::protozero::proto_utils::FieldMetadata<
|
||||
1,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kInt32,
|
||||
int32_t,
|
||||
ProcessDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Pid kPid() { return {}; }
|
||||
void set_pid(int32_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_Pid::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kInt32>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
|
||||
using FieldMetadata_ProcessName = ::protozero::proto_utils::FieldMetadata<
|
||||
6,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kString,
|
||||
std::string,
|
||||
ProcessDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_ProcessName kProcessName() { return {}; }
|
||||
void set_process_name(const char* data, size_t size) {
|
||||
AppendBytes(FieldMetadata_ProcessName::kFieldId, data, size);
|
||||
}
|
||||
void set_process_name(::protozero::ConstChars chars) {
|
||||
AppendBytes(FieldMetadata_ProcessName::kFieldId, chars.data, chars.size);
|
||||
}
|
||||
void set_process_name(std::string value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_ProcessName::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);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pbzero
|
||||
} // namespace protos
|
||||
} // namespace perfetto
|
||||
#endif // Include guard.
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: This is a manually minified version of Perfetto's
|
||||
// process_descriptor.proto.
|
||||
|
||||
// IMPORTANT: The coresponding .pbzero.h file must be regenerated after
|
||||
// any change is made to this file. This can be done by running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the
|
||||
// SDK root directory.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
// Describes a process's attributes. Emitted as part of a TrackDescriptor,
|
||||
// usually by the process's main thread.
|
||||
//
|
||||
// Next id: 9.
|
||||
message ProcessDescriptor {
|
||||
optional int32 pid = 1;
|
||||
optional string process_name = 6;
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
// 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.
|
||||
|
||||
// IMPORTANT: This file should only ever be modified by modifying the
|
||||
// corresponding .proto file and then running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root
|
||||
// directory.
|
||||
// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
|
||||
|
||||
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_THREAD_DESCRIPTOR_PROTO_H_
|
||||
#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_THREAD_DESCRIPTOR_PROTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perfetto/protozero/field_writer.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/packed_repeated_fields.h"
|
||||
#include "perfetto/protozero/proto_decoder.h"
|
||||
#include "perfetto/protozero/proto_utils.h"
|
||||
|
||||
namespace perfetto {
|
||||
namespace protos {
|
||||
namespace pbzero {
|
||||
|
||||
class ThreadDescriptor_Decoder : public ::protozero::TypedProtoDecoder<
|
||||
/*MAX_FIELD_ID=*/5,
|
||||
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
|
||||
public:
|
||||
ThreadDescriptor_Decoder(const uint8_t* data, size_t len)
|
||||
: TypedProtoDecoder(data, len) {}
|
||||
explicit ThreadDescriptor_Decoder(const std::string& raw)
|
||||
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
|
||||
raw.size()) {}
|
||||
explicit ThreadDescriptor_Decoder(const ::protozero::ConstBytes& raw)
|
||||
: TypedProtoDecoder(raw.data, raw.size) {}
|
||||
bool has_pid() const { return at<1>().valid(); }
|
||||
int32_t pid() const { return at<1>().as_int32(); }
|
||||
bool has_tid() const { return at<2>().valid(); }
|
||||
int32_t tid() const { return at<2>().as_int32(); }
|
||||
bool has_thread_name() const { return at<5>().valid(); }
|
||||
::protozero::ConstChars thread_name() const { return at<5>().as_string(); }
|
||||
};
|
||||
|
||||
class ThreadDescriptor : public ::protozero::Message {
|
||||
public:
|
||||
using Decoder = ThreadDescriptor_Decoder;
|
||||
enum : int32_t {
|
||||
kPidFieldNumber = 1,
|
||||
kTidFieldNumber = 2,
|
||||
kThreadNameFieldNumber = 5,
|
||||
};
|
||||
static constexpr const char* GetName() {
|
||||
return ".perfetto.protos.ThreadDescriptor";
|
||||
}
|
||||
|
||||
using FieldMetadata_Pid = ::protozero::proto_utils::FieldMetadata<
|
||||
1,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kInt32,
|
||||
int32_t,
|
||||
ThreadDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Pid kPid() { return {}; }
|
||||
void set_pid(int32_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_Pid::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kInt32>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
|
||||
using FieldMetadata_Tid = ::protozero::proto_utils::FieldMetadata<
|
||||
2,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kInt32,
|
||||
int32_t,
|
||||
ThreadDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Tid kTid() { return {}; }
|
||||
void set_tid(int32_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_Tid::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kInt32>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
|
||||
using FieldMetadata_ThreadName = ::protozero::proto_utils::FieldMetadata<
|
||||
5,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kString,
|
||||
std::string,
|
||||
ThreadDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_ThreadName kThreadName() { return {}; }
|
||||
void set_thread_name(const char* data, size_t size) {
|
||||
AppendBytes(FieldMetadata_ThreadName::kFieldId, data, size);
|
||||
}
|
||||
void set_thread_name(::protozero::ConstChars chars) {
|
||||
AppendBytes(FieldMetadata_ThreadName::kFieldId, chars.data, chars.size);
|
||||
}
|
||||
void set_thread_name(std::string value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_ThreadName::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);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pbzero
|
||||
} // namespace protos
|
||||
} // namespace perfetto
|
||||
#endif // Include guard.
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: This is a manually minified version of Perfetto's
|
||||
// thread_descriptor.proto.
|
||||
|
||||
// IMPORTANT: The coresponding .pbzero.h file must be regenerated after
|
||||
// any change is made to this file. This can be done by running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the
|
||||
// SDK root directory.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
// Describes a thread's attributes. Emitted as part of a TrackDescriptor,
|
||||
// usually by the thread's trace writer.
|
||||
//
|
||||
// Next id: 9.
|
||||
message ThreadDescriptor {
|
||||
optional int32 pid = 1;
|
||||
optional int32 tid = 2;
|
||||
|
||||
optional string thread_name = 5;
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
// 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.
|
||||
|
||||
// IMPORTANT: This file should only ever be modified by modifying the
|
||||
// corresponding .proto file and then running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root
|
||||
// directory.
|
||||
// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
|
||||
|
||||
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_TRACK_DESCRIPTOR_PROTO_H_
|
||||
#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_TRACK_DESCRIPTOR_PROTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perfetto/protozero/field_writer.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/packed_repeated_fields.h"
|
||||
#include "perfetto/protozero/proto_decoder.h"
|
||||
#include "perfetto/protozero/proto_utils.h"
|
||||
|
||||
namespace perfetto {
|
||||
namespace protos {
|
||||
namespace pbzero {
|
||||
|
||||
class ProcessDescriptor;
|
||||
class ThreadDescriptor;
|
||||
|
||||
class TrackDescriptor_Decoder : public ::protozero::TypedProtoDecoder<
|
||||
/*MAX_FIELD_ID=*/5,
|
||||
/*HAS_NONPACKED_REPEATED_FIELDS=*/false> {
|
||||
public:
|
||||
TrackDescriptor_Decoder(const uint8_t* data, size_t len)
|
||||
: TypedProtoDecoder(data, len) {}
|
||||
explicit TrackDescriptor_Decoder(const std::string& raw)
|
||||
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
|
||||
raw.size()) {}
|
||||
explicit TrackDescriptor_Decoder(const ::protozero::ConstBytes& raw)
|
||||
: TypedProtoDecoder(raw.data, raw.size) {}
|
||||
bool has_uuid() const { return at<1>().valid(); }
|
||||
uint64_t uuid() const { return at<1>().as_uint64(); }
|
||||
bool has_parent_uuid() const { return at<5>().valid(); }
|
||||
uint64_t parent_uuid() const { return at<5>().as_uint64(); }
|
||||
bool has_name() const { return at<2>().valid(); }
|
||||
::protozero::ConstChars name() const { return at<2>().as_string(); }
|
||||
bool has_process() const { return at<3>().valid(); }
|
||||
::protozero::ConstBytes process() const { return at<3>().as_bytes(); }
|
||||
bool has_thread() const { return at<4>().valid(); }
|
||||
::protozero::ConstBytes thread() const { return at<4>().as_bytes(); }
|
||||
};
|
||||
|
||||
class TrackDescriptor : public ::protozero::Message {
|
||||
public:
|
||||
using Decoder = TrackDescriptor_Decoder;
|
||||
enum : int32_t {
|
||||
kUuidFieldNumber = 1,
|
||||
kParentUuidFieldNumber = 5,
|
||||
kNameFieldNumber = 2,
|
||||
kProcessFieldNumber = 3,
|
||||
kThreadFieldNumber = 4,
|
||||
};
|
||||
static constexpr const char* GetName() {
|
||||
return ".perfetto.protos.TrackDescriptor";
|
||||
}
|
||||
|
||||
using FieldMetadata_Uuid = ::protozero::proto_utils::FieldMetadata<
|
||||
1,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint64,
|
||||
uint64_t,
|
||||
TrackDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Uuid kUuid() { return {}; }
|
||||
void set_uuid(uint64_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_Uuid::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_ParentUuid = ::protozero::proto_utils::FieldMetadata<
|
||||
5,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint64,
|
||||
uint64_t,
|
||||
TrackDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_ParentUuid kParentUuid() { return {}; }
|
||||
void set_parent_uuid(uint64_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_ParentUuid::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,
|
||||
TrackDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Name kName() { return {}; }
|
||||
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);
|
||||
}
|
||||
|
||||
using FieldMetadata_Process = ::protozero::proto_utils::FieldMetadata<
|
||||
3,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kMessage,
|
||||
ProcessDescriptor,
|
||||
TrackDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Process kProcess() { return {}; }
|
||||
template <typename T = ProcessDescriptor>
|
||||
T* set_process() {
|
||||
return BeginNestedMessage<T>(3);
|
||||
}
|
||||
|
||||
using FieldMetadata_Thread = ::protozero::proto_utils::FieldMetadata<
|
||||
4,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kMessage,
|
||||
ThreadDescriptor,
|
||||
TrackDescriptor>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Thread kThread() { return {}; }
|
||||
template <typename T = ThreadDescriptor>
|
||||
T* set_thread() {
|
||||
return BeginNestedMessage<T>(4);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pbzero
|
||||
} // namespace protos
|
||||
} // namespace perfetto
|
||||
#endif // Include guard.
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: This is a manually minified version of Perfetto's
|
||||
// track_descriptor.proto.
|
||||
|
||||
// IMPORTANT: The coresponding .pbzero.h file must be regenerated after
|
||||
// any change is made to this file. This can be done by running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the
|
||||
// SDK root directory.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
import "protos/perfetto/trace/track_event/process_descriptor.proto";
|
||||
import "protos/perfetto/trace/track_event/thread_descriptor.proto";
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
// Defines a track for TrackEvents. Slices and instant events on the same track
|
||||
// will be nested based on their timestamps, see TrackEvent::Type.
|
||||
//
|
||||
// A TrackDescriptor only needs to be emitted by one trace writer / producer and
|
||||
// is valid for the entirety of the trace. To ensure the descriptor isn't lost
|
||||
// when the ring buffer wraps, it should be reemitted whenever incremental state
|
||||
// is cleared.
|
||||
//
|
||||
// As a fallback, TrackEvents emitted without an explicit track association will
|
||||
// be associated with an implicit trace-global track (uuid = 0), see also
|
||||
// |TrackEvent::track_uuid|. It is possible but not necessary to emit a
|
||||
// TrackDescriptor for this implicit track.
|
||||
//
|
||||
// Next id: 9.
|
||||
message TrackDescriptor {
|
||||
// Unique ID that identifies this track. This ID is global to the whole trace.
|
||||
// Producers should ensure that it is unlikely to clash with IDs emitted by
|
||||
// other producers. A value of 0 denotes the implicit trace-global track.
|
||||
//
|
||||
// For example, legacy TRACE_EVENT macros may use a hash involving the async
|
||||
// event id + id_scope, pid, and/or tid to compute this ID.
|
||||
optional uint64 uuid = 1;
|
||||
|
||||
// A parent track reference can be used to describe relationships between
|
||||
// tracks. For example, to define an asynchronous track which is scoped to a
|
||||
// specific process, specify the uuid for that process's process track here.
|
||||
// Similarly, to associate a COUNTER_THREAD_TIME_NS counter track with a
|
||||
// thread, specify the uuid for that thread's thread track here.
|
||||
optional uint64 parent_uuid = 5;
|
||||
|
||||
// Name of the track. Optional - if unspecified, it may be derived from the
|
||||
// process/thread name (process/thread tracks), the first event's name (async
|
||||
// tracks), or counter name (counter tracks).
|
||||
optional string name = 2;
|
||||
|
||||
// Associate the track with a process, making it the process-global track.
|
||||
// There should only be one such track per process (usually for instant
|
||||
// events; trace processor uses this fact to detect pid reuse). If you need
|
||||
// more (e.g. for asynchronous events), create child tracks using parent_uuid.
|
||||
//
|
||||
// Trace processor will merge events on a process track with slice-type events
|
||||
// from other sources (e.g. ftrace) for the same process into a single
|
||||
// timeline view.
|
||||
optional ProcessDescriptor process = 3;
|
||||
|
||||
// Associate the track with a thread, indicating that the track's events
|
||||
// describe synchronous code execution on the thread. There should only be one
|
||||
// such track per thread (trace processor uses this fact to detect tid reuse).
|
||||
//
|
||||
// Trace processor will merge events on a thread track with slice-type events
|
||||
// from other sources (e.g. ftrace) for the same thread into a single timeline
|
||||
// view.
|
||||
optional ThreadDescriptor thread = 4;
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
// 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.
|
||||
|
||||
// IMPORTANT: This file should only ever be modified by modifying the
|
||||
// corresponding .proto file and then running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root
|
||||
// directory.
|
||||
// Autogenerated by the ProtoZero compiler plugin. DO NOT EDIT.
|
||||
|
||||
#ifndef PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_TRACK_EVENT_PROTO_H_
|
||||
#define PERFETTO_PROTOS_PROTOS_PERFETTO_TRACE_TRACK_EVENT_TRACK_EVENT_PROTO_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perfetto/protozero/field_writer.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/packed_repeated_fields.h"
|
||||
#include "perfetto/protozero/proto_decoder.h"
|
||||
#include "perfetto/protozero/proto_utils.h"
|
||||
|
||||
namespace perfetto {
|
||||
namespace protos {
|
||||
namespace pbzero {
|
||||
|
||||
class DebugAnnotation;
|
||||
namespace perfetto_pbzero_enum_TrackEvent {
|
||||
enum Type : int32_t;
|
||||
} // namespace perfetto_pbzero_enum_TrackEvent
|
||||
using TrackEvent_Type = perfetto_pbzero_enum_TrackEvent::Type;
|
||||
|
||||
namespace perfetto_pbzero_enum_TrackEvent {
|
||||
enum Type : int32_t {
|
||||
TYPE_SLICE_BEGIN = 1,
|
||||
TYPE_SLICE_END = 2,
|
||||
TYPE_INSTANT = 3,
|
||||
};
|
||||
} // namespace perfetto_pbzero_enum_TrackEvent
|
||||
using TrackEvent_Type = perfetto_pbzero_enum_TrackEvent::Type;
|
||||
|
||||
constexpr TrackEvent_Type TrackEvent_Type_MIN =
|
||||
TrackEvent_Type::TYPE_SLICE_BEGIN;
|
||||
constexpr TrackEvent_Type TrackEvent_Type_MAX = TrackEvent_Type::TYPE_INSTANT;
|
||||
|
||||
PERFETTO_PROTOZERO_CONSTEXPR14_OR_INLINE
|
||||
const char* TrackEvent_Type_Name(
|
||||
::perfetto::protos::pbzero::TrackEvent_Type value) {
|
||||
switch (value) {
|
||||
case ::perfetto::protos::pbzero::TrackEvent_Type::TYPE_SLICE_BEGIN:
|
||||
return "TYPE_SLICE_BEGIN";
|
||||
|
||||
case ::perfetto::protos::pbzero::TrackEvent_Type::TYPE_SLICE_END:
|
||||
return "TYPE_SLICE_END";
|
||||
|
||||
case ::perfetto::protos::pbzero::TrackEvent_Type::TYPE_INSTANT:
|
||||
return "TYPE_INSTANT";
|
||||
}
|
||||
return "PBZERO_UNKNOWN_ENUM_VALUE";
|
||||
}
|
||||
|
||||
class TrackEvent_Decoder : public ::protozero::TypedProtoDecoder<
|
||||
/*MAX_FIELD_ID=*/48,
|
||||
/*HAS_NONPACKED_REPEATED_FIELDS=*/true> {
|
||||
public:
|
||||
TrackEvent_Decoder(const uint8_t* data, size_t len)
|
||||
: TypedProtoDecoder(data, len) {}
|
||||
explicit TrackEvent_Decoder(const std::string& raw)
|
||||
: TypedProtoDecoder(reinterpret_cast<const uint8_t*>(raw.data()),
|
||||
raw.size()) {}
|
||||
explicit TrackEvent_Decoder(const ::protozero::ConstBytes& raw)
|
||||
: TypedProtoDecoder(raw.data, raw.size) {}
|
||||
bool has_categories() const { return at<22>().valid(); }
|
||||
::protozero::RepeatedFieldIterator<::protozero::ConstChars> categories()
|
||||
const {
|
||||
return GetRepeated<::protozero::ConstChars>(22);
|
||||
}
|
||||
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(); }
|
||||
int32_t type() const { return at<9>().as_int32(); }
|
||||
bool has_track_uuid() const { return at<11>().valid(); }
|
||||
uint64_t track_uuid() const { return at<11>().as_uint64(); }
|
||||
bool has_flow_ids() const { return at<47>().valid(); }
|
||||
::protozero::RepeatedFieldIterator<uint64_t> flow_ids() const {
|
||||
return GetRepeated<uint64_t>(47);
|
||||
}
|
||||
bool has_terminating_flow_ids() const { return at<48>().valid(); }
|
||||
::protozero::RepeatedFieldIterator<uint64_t> terminating_flow_ids() const {
|
||||
return GetRepeated<uint64_t>(48);
|
||||
}
|
||||
bool has_debug_annotations() const { return at<4>().valid(); }
|
||||
::protozero::RepeatedFieldIterator<::protozero::ConstBytes>
|
||||
debug_annotations() const {
|
||||
return GetRepeated<::protozero::ConstBytes>(4);
|
||||
}
|
||||
};
|
||||
|
||||
class TrackEvent : public ::protozero::Message {
|
||||
public:
|
||||
using Decoder = TrackEvent_Decoder;
|
||||
enum : int32_t {
|
||||
kCategoriesFieldNumber = 22,
|
||||
kNameFieldNumber = 23,
|
||||
kTypeFieldNumber = 9,
|
||||
kTrackUuidFieldNumber = 11,
|
||||
kFlowIdsFieldNumber = 47,
|
||||
kTerminatingFlowIdsFieldNumber = 48,
|
||||
kDebugAnnotationsFieldNumber = 4,
|
||||
};
|
||||
static constexpr const char* GetName() {
|
||||
return ".perfetto.protos.TrackEvent";
|
||||
}
|
||||
|
||||
using Type = ::perfetto::protos::pbzero::TrackEvent_Type;
|
||||
static inline const char* Type_Name(Type value) {
|
||||
return ::perfetto::protos::pbzero::TrackEvent_Type_Name(value);
|
||||
}
|
||||
static const Type TYPE_SLICE_BEGIN = Type::TYPE_SLICE_BEGIN;
|
||||
static const Type TYPE_SLICE_END = Type::TYPE_SLICE_END;
|
||||
static const Type TYPE_INSTANT = Type::TYPE_INSTANT;
|
||||
|
||||
using FieldMetadata_Categories = ::protozero::proto_utils::FieldMetadata<
|
||||
22,
|
||||
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
|
||||
::protozero::proto_utils::ProtoSchemaType::kString,
|
||||
std::string,
|
||||
TrackEvent>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Categories kCategories() { return {}; }
|
||||
void add_categories(const char* data, size_t size) {
|
||||
AppendBytes(FieldMetadata_Categories::kFieldId, data, size);
|
||||
}
|
||||
void add_categories(::protozero::ConstChars chars) {
|
||||
AppendBytes(FieldMetadata_Categories::kFieldId, chars.data, chars.size);
|
||||
}
|
||||
void add_categories(std::string value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_Categories::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_Name = ::protozero::proto_utils::FieldMetadata<
|
||||
23,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kString,
|
||||
std::string,
|
||||
TrackEvent>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Name kName() { return {}; }
|
||||
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);
|
||||
}
|
||||
|
||||
using FieldMetadata_Type = ::protozero::proto_utils::FieldMetadata<
|
||||
9,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kEnum,
|
||||
::perfetto::protos::pbzero::TrackEvent_Type,
|
||||
TrackEvent>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_Type kType() { return {}; }
|
||||
void set_type(::perfetto::protos::pbzero::TrackEvent_Type value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_Type::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kEnum>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
|
||||
using FieldMetadata_TrackUuid = ::protozero::proto_utils::FieldMetadata<
|
||||
11,
|
||||
::protozero::proto_utils::RepetitionType::kNotRepeated,
|
||||
::protozero::proto_utils::ProtoSchemaType::kUint64,
|
||||
uint64_t,
|
||||
TrackEvent>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_TrackUuid kTrackUuid() { return {}; }
|
||||
void set_track_uuid(uint64_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_TrackUuid::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_FlowIds = ::protozero::proto_utils::FieldMetadata<
|
||||
47,
|
||||
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
|
||||
::protozero::proto_utils::ProtoSchemaType::kFixed64,
|
||||
uint64_t,
|
||||
TrackEvent>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_FlowIds kFlowIds() { return {}; }
|
||||
void add_flow_ids(uint64_t value) {
|
||||
static constexpr uint32_t field_id = FieldMetadata_FlowIds::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kFixed64>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
|
||||
using FieldMetadata_TerminatingFlowIds =
|
||||
::protozero::proto_utils::FieldMetadata<
|
||||
48,
|
||||
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
|
||||
::protozero::proto_utils::ProtoSchemaType::kFixed64,
|
||||
uint64_t,
|
||||
TrackEvent>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_TerminatingFlowIds kTerminatingFlowIds() {
|
||||
return {};
|
||||
}
|
||||
void add_terminating_flow_ids(uint64_t value) {
|
||||
static constexpr uint32_t field_id =
|
||||
FieldMetadata_TerminatingFlowIds::kFieldId;
|
||||
// Call the appropriate protozero::Message::Append(field_id, ...)
|
||||
// method based on the type of the field.
|
||||
::protozero::internal::FieldWriter<
|
||||
::protozero::proto_utils::ProtoSchemaType::kFixed64>::Append(*this,
|
||||
field_id,
|
||||
value);
|
||||
}
|
||||
|
||||
using FieldMetadata_DebugAnnotations =
|
||||
::protozero::proto_utils::FieldMetadata<
|
||||
4,
|
||||
::protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
|
||||
::protozero::proto_utils::ProtoSchemaType::kMessage,
|
||||
DebugAnnotation,
|
||||
TrackEvent>;
|
||||
|
||||
// Ceci n'est pas une pipe.
|
||||
// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
|
||||
// type (and users are expected to use it as such, hence kCamelCase name).
|
||||
// It is declared as a function to keep protozero bindings header-only as
|
||||
// inline constexpr variables are not available until C++17 (while inline
|
||||
// functions are).
|
||||
// TODO(altimin): Use inline variable instead after adopting C++17.
|
||||
static constexpr FieldMetadata_DebugAnnotations kDebugAnnotations() {
|
||||
return {};
|
||||
}
|
||||
template <typename T = DebugAnnotation>
|
||||
T* add_debug_annotations() {
|
||||
return BeginNestedMessage<T>(4);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pbzero
|
||||
} // namespace protos
|
||||
} // namespace perfetto
|
||||
#endif // Include guard.
|
176
runtime/vm/protos/perfetto/trace/track_event/track_event.proto
Normal file
176
runtime/vm/protos/perfetto/trace/track_event/track_event.proto
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOTE: This is a manually minified version of Perfetto's
|
||||
// track_event.proto.
|
||||
|
||||
// IMPORTANT: The coresponding .pbzero.h file must be regenerated after
|
||||
// any change is made to this file. This can be done by running
|
||||
// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the
|
||||
// SDK root directory.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
import "protos/perfetto/trace/track_event/debug_annotation.proto";
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
// NOTE: Full TrackEvent support in the client lib and chrome is WIP, thus these
|
||||
// protos are still subject to change. Don't depend on them staying as they are.
|
||||
|
||||
// Trace events emitted by client instrumentation library (TRACE_EVENT macros),
|
||||
// which describe activity on a track, such as a thread or asynchronous event
|
||||
// track. The track is specified using separate TrackDescriptor messages and
|
||||
// referred to via the track's UUID.
|
||||
//
|
||||
// A simple TrackEvent packet specifies a timestamp, category, name and type:
|
||||
// ```protobuf
|
||||
// trace_packet {
|
||||
// timestamp: 1000
|
||||
// track_event {
|
||||
// categories: ["my_cat"]
|
||||
// name: "my_event"
|
||||
// type: TYPE_INSTANT
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// To associate an event with a custom track (e.g. a thread), the track is
|
||||
// defined in a separate packet and referred to from the TrackEvent by its UUID:
|
||||
// ```protobuf
|
||||
// trace_packet {
|
||||
// track_descriptor {
|
||||
// track_uuid: 1234
|
||||
// name: "my_track"
|
||||
//
|
||||
// // Optionally, associate the track with a thread.
|
||||
// thread_descriptor {
|
||||
// pid: 10
|
||||
// tid: 10
|
||||
// ..
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// A pair of TYPE_SLICE_BEGIN and _END events form a slice on the track:
|
||||
//
|
||||
// ```protobuf
|
||||
// trace_packet {
|
||||
// timestamp: 1200
|
||||
// track_event {
|
||||
// track_uuid: 1234
|
||||
// categories: ["my_cat"]
|
||||
// name: "my_slice"
|
||||
// type: TYPE_SLICE_BEGIN
|
||||
// }
|
||||
// }
|
||||
// trace_packet {
|
||||
// timestamp: 1400
|
||||
// track_event {
|
||||
// track_uuid: 1234
|
||||
// type: TYPE_SLICE_END
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
// TrackEvents also support optimizations to reduce data repetition and encoded
|
||||
// data size, e.g. through data interning (names, categories, ...) and delta
|
||||
// encoding of timestamps/counters. For details, see the InternedData message.
|
||||
// Further, default values for attributes of events on the same sequence (e.g.
|
||||
// their default track association) can be emitted as part of a
|
||||
// TrackEventDefaults message.
|
||||
//
|
||||
// Next reserved id: 13 (up to 15). Next id: 50.
|
||||
message TrackEvent {
|
||||
repeated string categories = 22;
|
||||
|
||||
// Optional name of the event for its display in trace viewer. May be left
|
||||
// unspecified for events with typed arguments.
|
||||
//
|
||||
// Note that metrics should not rely on event names, as they are prone to
|
||||
// changing. Instead, they should use typed arguments to identify the events
|
||||
// they are interested in.
|
||||
oneof name_field {
|
||||
// non-interned variant.
|
||||
string name = 23;
|
||||
}
|
||||
|
||||
// TODO(eseckler): Support using binary symbols for category/event names.
|
||||
|
||||
// Type of the TrackEvent (required if |phase| in LegacyEvent is not set).
|
||||
enum Type {
|
||||
// Slice events are events that have a begin and end timestamp, i.e. a
|
||||
// duration. They can be nested similar to a callstack: If, on the same
|
||||
// track, event B begins after event A, but before A ends, B is a child
|
||||
// event of A and will be drawn as a nested event underneath A in the UI.
|
||||
// Note that child events should always end before their parents (e.g. B
|
||||
// before A).
|
||||
//
|
||||
// Each slice event is formed by a pair of BEGIN + END events. The END event
|
||||
// does not need to repeat any TrackEvent fields it has in common with its
|
||||
// corresponding BEGIN event. Arguments and debug annotations of the BEGIN +
|
||||
// END pair will be merged during trace import.
|
||||
//
|
||||
// Note that we deliberately chose not to support COMPLETE events (which
|
||||
// would specify a duration directly) since clients would need to delay
|
||||
// writing them until the slice is completed, which can result in reordered
|
||||
// events in the trace and loss of unfinished events at the end of a trace.
|
||||
TYPE_SLICE_BEGIN = 1;
|
||||
TYPE_SLICE_END = 2;
|
||||
|
||||
// Instant events are nestable events without duration. They can be children
|
||||
// of slice events on the same track.
|
||||
TYPE_INSTANT = 3;
|
||||
}
|
||||
optional Type type = 9;
|
||||
|
||||
// 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.
|
||||
optional uint64 track_uuid = 11;
|
||||
|
||||
// IDs of flows originating, passing through, or ending at this event.
|
||||
// Flow IDs are global within a trace.
|
||||
//
|
||||
// A flow connects a sequence of TrackEvents within or across tracks, e.g.
|
||||
// an input event may be handled on one thread but cause another event on
|
||||
// a different thread - a flow between the two events can associate them.
|
||||
//
|
||||
// The direction of the flows between events is inferred from the events'
|
||||
// timestamps. The earliest event with the same flow ID becomes the source
|
||||
// of the flow. Any events thereafter are intermediate steps of the flow,
|
||||
// until the flow terminates at the last event with the flow ID.
|
||||
//
|
||||
// Flows can also be explicitly terminated (see |terminating_flow_ids|), so
|
||||
// that the same ID can later be reused for another flow.
|
||||
repeated fixed64 flow_ids = 47;
|
||||
|
||||
// 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.
|
||||
repeated fixed64 terminating_flow_ids = 48;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TrackEvent arguments:
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Unstable key/value annotations shown in the trace viewer but not intended
|
||||
// for metrics use.
|
||||
repeated DebugAnnotation debug_annotations = 4;
|
||||
}
|
77
runtime/vm/protos/tools/compile_perfetto_protos.dart
Normal file
77
runtime/vm/protos/tools/compile_perfetto_protos.dart
Normal file
|
@ -0,0 +1,77 @@
|
|||
// 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.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
Future<void> compilePerfettoProtos() async {
|
||||
final processResult = await Process.run(
|
||||
'./tools/build.py',
|
||||
['-mdebug', '-ax64', '--no-goma', 'runtime/vm:perfetto_protos'],
|
||||
);
|
||||
|
||||
final int exitCode = processResult.exitCode;
|
||||
final String stdout = processResult.stdout.trim();
|
||||
final String stderr = processResult.stderr.trim();
|
||||
if (exitCode != 0) {
|
||||
print('exit-code: $exitCode');
|
||||
print('stdout:');
|
||||
print('${stdout}');
|
||||
print('stderr:');
|
||||
print('${stderr}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> copyPerfettoProtoHeaders() async {
|
||||
final copySource = Directory('./out/DebugX64/gen/runtime/vm/protos').path;
|
||||
final copyDestination = Directory('./runtime/vm').path;
|
||||
|
||||
late final executable;
|
||||
late final args;
|
||||
if (Platform.operatingSystem == 'windows') {
|
||||
executable = 'xcopy';
|
||||
args = [copySource, copyDestination, '/e', '/i'];
|
||||
} else {
|
||||
executable = 'cp';
|
||||
args = ['-R', copySource, copyDestination];
|
||||
}
|
||||
final processResult = await Process.run(executable, args);
|
||||
|
||||
final int exitCode = processResult.exitCode;
|
||||
final String stdout = processResult.stdout.trim();
|
||||
final String stderr = processResult.stderr.trim();
|
||||
if (exitCode != 0) {
|
||||
print('exit-code: $exitCode');
|
||||
print('stdout:');
|
||||
print('${stdout}');
|
||||
print('stderr:');
|
||||
print('${stderr}');
|
||||
}
|
||||
|
||||
for (final file
|
||||
in Directory('./runtime/vm/protos').listSync(recursive: true)) {
|
||||
if (!(file is File) || !file.path.endsWith('.pbzero.h')) {
|
||||
continue;
|
||||
}
|
||||
final contentsIncludingPrependedNotices =
|
||||
'// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file\n' +
|
||||
'// for details. All rights reserved. Use of this source code is governed by a\n' +
|
||||
'// BSD-style license that can be found in the LICENSE file.\n\n' +
|
||||
'// IMPORTANT: This file should only ever be modified by modifying the\n' +
|
||||
'// corresponding .proto file and then running\n' +
|
||||
'// `dart runtime/vm/protos/tools/compile_perfetto_protos.dart` from the SDK root\n' +
|
||||
'// directory.\n' +
|
||||
file.readAsStringSync();
|
||||
file.writeAsStringSync(contentsIncludingPrependedNotices, flush: true);
|
||||
}
|
||||
}
|
||||
|
||||
main(List<String> files) async {
|
||||
if (!Directory('./runtime/vm').existsSync()) {
|
||||
print('Error: this tool must be run from the root directory of the SDK.');
|
||||
return;
|
||||
}
|
||||
await compilePerfettoProtos();
|
||||
await copyPerfettoProtoHeaders();
|
||||
}
|
|
@ -11,6 +11,8 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "platform/atomic.h"
|
||||
|
@ -24,6 +26,18 @@
|
|||
#include "vm/service_event.h"
|
||||
#include "vm/thread.h"
|
||||
|
||||
#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
#include "perfetto/ext/tracing/core/trace_packet.h"
|
||||
#include "vm/protos/perfetto/common/builtin_clock.pbzero.h"
|
||||
#include "vm/protos/perfetto/trace/clock_snapshot.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"
|
||||
#include "vm/protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
|
||||
#include "vm/protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
|
||||
#include "vm/protos/perfetto/trace/track_event/track_event.pbzero.h"
|
||||
#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
|
||||
namespace dart {
|
||||
|
||||
#if defined(PRODUCT)
|
||||
|
@ -31,9 +45,14 @@ namespace dart {
|
|||
#define SUPPORTED_TIMELINE_RECORDERS "systrace, file, callback"
|
||||
#else
|
||||
#define DEFAULT_TIMELINE_RECORDER "ring"
|
||||
#if defined(SUPPORT_PERFETTO)
|
||||
#define SUPPORTED_TIMELINE_RECORDERS \
|
||||
"ring, endless, startup, systrace, file, callback, perfetto"
|
||||
#else
|
||||
#define SUPPORTED_TIMELINE_RECORDERS \
|
||||
"ring, endless, startup, systrace, file, callback"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline");
|
||||
DEFINE_FLAG(bool, startup_timeline, false, "Record the startup timeline");
|
||||
|
@ -43,12 +62,12 @@ DEFINE_FLAG(
|
|||
false,
|
||||
"Record the timeline to the platform's tracing service if there is one");
|
||||
DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend");
|
||||
DEFINE_FLAG(
|
||||
charp,
|
||||
timeline_dir,
|
||||
nullptr,
|
||||
"Enable all timeline trace streams and output VM global trace "
|
||||
"into specified directory. This flag is ignored by the file recorder.");
|
||||
DEFINE_FLAG(charp,
|
||||
timeline_dir,
|
||||
nullptr,
|
||||
"Enable all timeline trace streams and output VM global trace "
|
||||
"into specified directory. This flag is ignored by the file and "
|
||||
"perfetto recorders.");
|
||||
DEFINE_FLAG(charp,
|
||||
timeline_streams,
|
||||
nullptr,
|
||||
|
@ -153,6 +172,7 @@ static TimelineEventRecorder* CreateTimelineRecorder() {
|
|||
if (Utils::StrStartsWith(flag, "file") &&
|
||||
(flag[4] == '\0' || flag[4] == ':' || flag[4] == '=')) {
|
||||
const char* filename = flag[4] == '\0' ? "dart-timeline.json" : &flag[5];
|
||||
free(const_cast<char*>(FLAG_timeline_dir));
|
||||
FLAG_timeline_dir = nullptr;
|
||||
return new TimelineEventFileRecorder(filename);
|
||||
}
|
||||
|
@ -162,6 +182,25 @@ static TimelineEventRecorder* CreateTimelineRecorder() {
|
|||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
#if defined(SUPPORT_PERFETTO)
|
||||
// The Perfetto file recorder is disabled in PRODUCT mode to avoid the large
|
||||
// binary size increase that it brings.
|
||||
{
|
||||
const intptr_t kLengthOfWordPerfetto = 8;
|
||||
if (Utils::StrStartsWith(flag, "perfetto") &&
|
||||
(flag[kLengthOfWordPerfetto] == '\0' ||
|
||||
flag[kLengthOfWordPerfetto] == ':' ||
|
||||
flag[kLengthOfWordPerfetto] == '=')) {
|
||||
const char* filename = flag[kLengthOfWordPerfetto] == '\0'
|
||||
? "dart.perfetto-trace"
|
||||
: &flag[kLengthOfWordPerfetto + 1];
|
||||
free(const_cast<char*>(FLAG_timeline_dir));
|
||||
FLAG_timeline_dir = nullptr;
|
||||
return new TimelineEventPerfettoFileRecorder(filename);
|
||||
}
|
||||
}
|
||||
#endif // defined(SUPPORT_PERFETTO)
|
||||
|
||||
// Recorders below do nothing useful in PRODUCT mode. You can't extract
|
||||
// information available in them without vm-service.
|
||||
if (strcmp("endless", flag) == 0) {
|
||||
|
@ -175,7 +214,7 @@ static TimelineEventRecorder* CreateTimelineRecorder() {
|
|||
if (strcmp("ring", flag) == 0) {
|
||||
return new TimelineEventRingRecorder();
|
||||
}
|
||||
#endif
|
||||
#endif // !defined(PRODUCT)
|
||||
|
||||
if (strlen(flag) > 0 && strcmp(flag, DEFAULT_TIMELINE_RECORDER) != 0) {
|
||||
OS::PrintErr(
|
||||
|
@ -792,7 +831,7 @@ bool TimelineEvent::HasIsolateGroupId() const {
|
|||
return isolate_group_id_ != ILLEGAL_ISOLATE_GROUP_ID;
|
||||
}
|
||||
|
||||
const char* TimelineEvent::GetFormattedIsolateId() const {
|
||||
char* TimelineEvent::GetFormattedIsolateId() const {
|
||||
ASSERT(HasIsolateId());
|
||||
intptr_t formatted_isolate_id_len =
|
||||
Utils::SNPrint(nullptr, 0, ISOLATE_SERVICE_ID_FORMAT_STRING, isolate_id_);
|
||||
|
@ -803,7 +842,7 @@ const char* TimelineEvent::GetFormattedIsolateId() const {
|
|||
return formatted_isolate_id;
|
||||
}
|
||||
|
||||
const char* TimelineEvent::GetFormattedIsolateGroupId() const {
|
||||
char* TimelineEvent::GetFormattedIsolateGroupId() const {
|
||||
ASSERT(HasIsolateGroupId());
|
||||
intptr_t formatted_isolate_group_id_len = Utils::SNPrint(
|
||||
nullptr, 0, ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING, isolate_group_id_);
|
||||
|
@ -838,6 +877,32 @@ void TimelineTrackMetadata::PrintJSON(const JSONArray& jsarr_events) const {
|
|||
jsobj_args.AddProperty("mode", "basic");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SUPPORT_PERFETTO)
|
||||
inline void SetTrustedPacketSequenceId(
|
||||
perfetto::protos::pbzero::TracePacket* packet) {
|
||||
// trusted_packet_sequence_id uniquely identifies a trace producer + writer
|
||||
// pair. We set the trusted_packet_sequence_id of all packets written by the
|
||||
// Perfetto file recorder to the arbitrary value of 1.
|
||||
packet->set_trusted_packet_sequence_id(1);
|
||||
}
|
||||
|
||||
void TimelineTrackMetadata::PopulateTracePacket(
|
||||
perfetto::protos::pbzero::TracePacket* track_descriptor_packet) {
|
||||
SetTrustedPacketSequenceId(track_descriptor_packet);
|
||||
|
||||
perfetto::protos::pbzero::TrackDescriptor& track_descriptor =
|
||||
*track_descriptor_packet->set_track_descriptor();
|
||||
track_descriptor.set_parent_uuid(pid());
|
||||
track_descriptor.set_uuid(tid());
|
||||
|
||||
perfetto::protos::pbzero::ThreadDescriptor& thread_descriptor =
|
||||
*track_descriptor.set_thread();
|
||||
thread_descriptor.set_pid(pid());
|
||||
thread_descriptor.set_tid(tid());
|
||||
thread_descriptor.set_thread_name(track_name());
|
||||
}
|
||||
#endif // defined(SUPPORT_PERFETTO)
|
||||
#endif // !defined(PRODUCT)
|
||||
|
||||
TimelineStream::TimelineStream(const char* name,
|
||||
|
@ -1664,6 +1729,258 @@ void TimelineEventFileRecorder::DrainImpl(const TimelineEvent& event) {
|
|||
free(output);
|
||||
}
|
||||
|
||||
#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
TimelineEventPerfettoFileRecorder::TimelineEventPerfettoFileRecorder(
|
||||
const char* path)
|
||||
: TimelineEventFileRecorderBase(path),
|
||||
async_track_uuid_to_track_descriptor_(
|
||||
&SimpleHashMap::SamePointerValue,
|
||||
TimelineEventPerfettoFileRecorder::
|
||||
kAsyncTrackUuidToTrackDescriptorInitialCapacity) {
|
||||
SetTrustedPacketSequenceId(packet_.get());
|
||||
|
||||
perfetto::protos::pbzero::ClockSnapshot& clock_snapshot =
|
||||
*packet_->set_clock_snapshot();
|
||||
clock_snapshot.set_primary_trace_clock(
|
||||
perfetto::protos::pbzero::BuiltinClock::BUILTIN_CLOCK_MONOTONIC);
|
||||
|
||||
perfetto::protos::pbzero::ClockSnapshot_Clock& clock =
|
||||
*clock_snapshot.add_clocks();
|
||||
clock.set_clock_id(
|
||||
perfetto::protos::pbzero::BuiltinClock::BUILTIN_CLOCK_MONOTONIC);
|
||||
clock.set_timestamp(OS::GetCurrentMonotonicMicrosForTimeline() * 1000);
|
||||
|
||||
WritePacket(&packet_);
|
||||
packet_.Reset();
|
||||
|
||||
SetTrustedPacketSequenceId(packet_.get());
|
||||
|
||||
perfetto::protos::pbzero::TrackDescriptor& track_descriptor =
|
||||
*packet_->set_track_descriptor();
|
||||
const int64_t pid = OS::ProcessId();
|
||||
track_descriptor.set_uuid(pid);
|
||||
|
||||
perfetto::protos::pbzero::ProcessDescriptor& process_descriptor =
|
||||
*track_descriptor.set_process();
|
||||
process_descriptor.set_pid(pid);
|
||||
// TODO(derekx): Add the process name.
|
||||
|
||||
WritePacket(&packet_);
|
||||
packet_.Reset();
|
||||
|
||||
OSThread::Start("TimelineEventPerfettoFileRecorder",
|
||||
TimelineEventFileRecorderBaseStart,
|
||||
reinterpret_cast<uword>(this));
|
||||
}
|
||||
|
||||
TimelineEventPerfettoFileRecorder::~TimelineEventPerfettoFileRecorder() {
|
||||
ShutDown();
|
||||
for (SimpleHashMap::Entry* entry = track_uuid_to_track_metadata().Start();
|
||||
entry != nullptr; entry = track_uuid_to_track_metadata().Next(entry)) {
|
||||
TimelineTrackMetadata* value =
|
||||
static_cast<TimelineTrackMetadata*>(entry->value);
|
||||
packet_.Reset();
|
||||
value->PopulateTracePacket(packet_.get());
|
||||
WritePacket(&packet_);
|
||||
}
|
||||
for (SimpleHashMap::Entry* entry =
|
||||
async_track_uuid_to_track_descriptor_.Start();
|
||||
entry != nullptr;
|
||||
entry = async_track_uuid_to_track_descriptor_.Next(entry)) {
|
||||
auto* value = static_cast<
|
||||
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*>(
|
||||
entry->value);
|
||||
WritePacket(value);
|
||||
delete value;
|
||||
}
|
||||
}
|
||||
|
||||
inline const std::tuple<std::unique_ptr<char[]>, intptr_t> GetProtoPreamble(
|
||||
const intptr_t size) {
|
||||
auto preamble =
|
||||
std::make_unique<char[]>(perfetto::TracePacket::kMaxPreambleBytes);
|
||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(&preamble[0]);
|
||||
|
||||
const uint8_t tag = protozero::proto_utils::MakeTagLengthDelimited(
|
||||
perfetto::TracePacket::kPacketFieldNumber);
|
||||
static_assert(tag < 0x80, "TracePacket tag should fit in one byte");
|
||||
*(ptr++) = tag;
|
||||
|
||||
ptr = protozero::proto_utils::WriteVarInt(size, ptr);
|
||||
intptr_t preamble_size = reinterpret_cast<intptr_t>(ptr) -
|
||||
reinterpret_cast<intptr_t>(&preamble[0]);
|
||||
return std::make_tuple(std::move(preamble), preamble_size);
|
||||
}
|
||||
|
||||
void TimelineEventPerfettoFileRecorder::WritePacket(
|
||||
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet)
|
||||
const {
|
||||
intptr_t size = 0;
|
||||
for (const protozero::ScatteredHeapBuffer::Slice& slice :
|
||||
packet->GetSlices()) {
|
||||
size += slice.size() - slice.unused_bytes();
|
||||
}
|
||||
const std::tuple<std::unique_ptr<char[]>, intptr_t>& response =
|
||||
GetProtoPreamble(size);
|
||||
Write(std::get<0>(response).get(), std::get<1>(response));
|
||||
for (const protozero::ScatteredHeapBuffer::Slice& slice :
|
||||
packet->GetSlices()) {
|
||||
Write(reinterpret_cast<char*>(slice.start()),
|
||||
slice.size() - slice.unused_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
inline void AddSyncEventFields(
|
||||
perfetto::protos::pbzero::TrackEvent* track_event,
|
||||
const TimelineEvent& event) {
|
||||
track_event->set_track_uuid(OSThread::ThreadIdToIntPtr(event.thread()));
|
||||
}
|
||||
|
||||
inline void AddAsyncEventFields(
|
||||
perfetto::protos::pbzero::TrackEvent* track_event,
|
||||
const TimelineEvent& event) {
|
||||
track_event->set_track_uuid(event.Id());
|
||||
}
|
||||
|
||||
inline void AddBeginAndInstantEventCommonFields(
|
||||
perfetto::protos::pbzero::TrackEvent* track_event,
|
||||
const TimelineEvent& event) {
|
||||
track_event->set_name(event.label());
|
||||
}
|
||||
|
||||
inline void AddBeginEventFields(
|
||||
perfetto::protos::pbzero::TrackEvent* track_event,
|
||||
const TimelineEvent& event) {
|
||||
AddBeginAndInstantEventCommonFields(track_event, event);
|
||||
track_event->set_type(
|
||||
perfetto::protos::pbzero::TrackEvent::Type::TYPE_SLICE_BEGIN);
|
||||
}
|
||||
|
||||
inline void AddInstantEventFields(
|
||||
perfetto::protos::pbzero::TrackEvent* track_event,
|
||||
const TimelineEvent& event) {
|
||||
AddBeginAndInstantEventCommonFields(track_event, event);
|
||||
track_event->set_type(
|
||||
perfetto::protos::pbzero::TrackEvent::Type::TYPE_INSTANT);
|
||||
}
|
||||
|
||||
inline void AddEndEventFields(
|
||||
perfetto::protos::pbzero::TrackEvent* track_event) {
|
||||
track_event->set_type(
|
||||
perfetto::protos::pbzero::TrackEvent::Type::TYPE_SLICE_END);
|
||||
}
|
||||
|
||||
inline void AddTrackDescriptorForAsyncTrack(
|
||||
SimpleHashMap* async_track_uuid_to_track_descriptor,
|
||||
const TimelineEvent& event) {
|
||||
void* key = reinterpret_cast<void*>(event.Id());
|
||||
const intptr_t hash = Utils::WordHash(event.Id());
|
||||
SimpleHashMap::Entry* entry =
|
||||
async_track_uuid_to_track_descriptor->Lookup(key, hash, true);
|
||||
if (entry->value == nullptr) {
|
||||
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>&
|
||||
track_descriptor_packet = *(
|
||||
new protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>);
|
||||
SetTrustedPacketSequenceId(track_descriptor_packet.get());
|
||||
|
||||
perfetto::protos::pbzero::TrackDescriptor& track_descriptor =
|
||||
*track_descriptor_packet->set_track_descriptor();
|
||||
track_descriptor.set_parent_uuid(OS::ProcessId());
|
||||
track_descriptor.set_uuid(event.Id());
|
||||
|
||||
entry->value = &track_descriptor_packet;
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineEventPerfettoFileRecorder::DrainImpl(const TimelineEvent& event) {
|
||||
SetTrustedPacketSequenceId(packet_.get());
|
||||
// TODO(derekx): We should be able to set the unit_multiplier_ns field in a
|
||||
// ClockSnapshot to avoid manually converting from microseconds to
|
||||
// nanoseconds, but I haven't been able to get it to work.
|
||||
packet_->set_timestamp(event.TimeOrigin() * 1000);
|
||||
packet_->set_timestamp_clock_id(
|
||||
perfetto::protos::pbzero::BuiltinClock::BUILTIN_CLOCK_MONOTONIC);
|
||||
|
||||
perfetto::protos::pbzero::TrackEvent* track_event =
|
||||
packet_->set_track_event();
|
||||
track_event->add_categories(event.stream()->name());
|
||||
|
||||
switch (event.event_type()) {
|
||||
case TimelineEvent::kBegin: {
|
||||
AddSyncEventFields(track_event, event);
|
||||
AddBeginEventFields(track_event, event);
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kEnd: {
|
||||
AddSyncEventFields(track_event, event);
|
||||
AddEndEventFields(track_event);
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kInstant: {
|
||||
AddSyncEventFields(track_event, event);
|
||||
AddInstantEventFields(track_event, event);
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kAsyncBegin: {
|
||||
AddTrackDescriptorForAsyncTrack(&async_track_uuid_to_track_descriptor_,
|
||||
event);
|
||||
AddAsyncEventFields(track_event, event);
|
||||
AddBeginEventFields(track_event, event);
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kAsyncEnd: {
|
||||
AddAsyncEventFields(track_event, event);
|
||||
AddEndEventFields(track_event);
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kAsyncInstant: {
|
||||
AddTrackDescriptorForAsyncTrack(&async_track_uuid_to_track_descriptor_,
|
||||
event);
|
||||
AddAsyncEventFields(track_event, event);
|
||||
AddInstantEventFields(track_event, event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (event.GetNumArguments() > 0) {
|
||||
if (event.pre_serialized_args()) {
|
||||
ASSERT(event.GetNumArguments() == 1);
|
||||
perfetto::protos::pbzero::DebugAnnotation& debug_annotation =
|
||||
*track_event->add_debug_annotations();
|
||||
debug_annotation.set_name(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.HasIsolateId()) {
|
||||
perfetto::protos::pbzero::DebugAnnotation& debug_annotation =
|
||||
*track_event->add_debug_annotations();
|
||||
debug_annotation.set_name("isolateId");
|
||||
char* formatted_isolate_id = event.GetFormattedIsolateId();
|
||||
debug_annotation.set_string_value(formatted_isolate_id);
|
||||
free(formatted_isolate_id);
|
||||
}
|
||||
if (event.HasIsolateGroupId()) {
|
||||
perfetto::protos::pbzero::DebugAnnotation& debug_annotation =
|
||||
*track_event->add_debug_annotations();
|
||||
debug_annotation.set_name("isolateGroupId");
|
||||
char* formatted_isolate_group = event.GetFormattedIsolateGroupId();
|
||||
debug_annotation.set_string_value(formatted_isolate_group);
|
||||
free(formatted_isolate_group);
|
||||
}
|
||||
|
||||
WritePacket(&packet_);
|
||||
packet_.Reset();
|
||||
}
|
||||
#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
|
||||
TimelineEventEndlessRecorder::TimelineEventEndlessRecorder()
|
||||
: head_(nullptr), tail_(nullptr), block_index_(0) {}
|
||||
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
#include "vm/os.h"
|
||||
#include "vm/os_thread.h"
|
||||
|
||||
#if defined(SUPPORT_TIMELINE) && defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
#include "perfetto/protozero/scattered_heap_buffer.h"
|
||||
#include "vm/protos/perfetto/trace/trace_packet.pbzero.h"
|
||||
#endif // defined(SUPPORT_TIMELINE) && defined(SUPPORT_PERFETTO) && \
|
||||
// !defined(PRODUCT)
|
||||
|
||||
#if defined(FUCHSIA_SDK) || defined(DART_HOST_OS_FUCHSIA)
|
||||
#include <lib/trace-engine/context.h>
|
||||
#include <lib/trace-engine/instrumentation.h>
|
||||
|
@ -34,6 +40,12 @@
|
|||
|
||||
namespace dart {
|
||||
|
||||
#if !defined(SUPPORT_TIMELINE)
|
||||
#define TIMELINE_DURATION(thread, stream, name)
|
||||
#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function)
|
||||
#define TIMELINE_FUNCTION_GC_DURATION(thread, name)
|
||||
#endif // !defined(SUPPORT_TIMELINE)
|
||||
|
||||
class JSONArray;
|
||||
class JSONObject;
|
||||
class JSONStream;
|
||||
|
@ -49,11 +61,13 @@ class TimelineStream;
|
|||
class VirtualMemory;
|
||||
class Zone;
|
||||
|
||||
#if defined(SUPPORT_TIMELINE)
|
||||
#define CALLBACK_RECORDER_NAME "Callback"
|
||||
#define ENDLESS_RECORDER_NAME "Endless"
|
||||
#define FILE_RECORDER_NAME "File"
|
||||
#define FUCHSIA_RECORDER_NAME "Fuchsia"
|
||||
#define MACOS_RECORDER_NAME "Macos"
|
||||
#define PERFETTO_RECORDER_NAME "Perfetto"
|
||||
#define RING_RECORDER_NAME "Ring"
|
||||
#define STARTUP_RECORDER_NAME "Startup"
|
||||
#define SYSTRACE_RECORDER_NAME "Systrace"
|
||||
|
@ -69,6 +83,7 @@ class Zone;
|
|||
V(GC, "dart:gc", true) \
|
||||
V(Isolate, "dart:isolate", true) \
|
||||
V(VM, "dart:vm", true)
|
||||
#endif // defined(SUPPORT_TIMELINE)
|
||||
|
||||
// A stream of timeline events. A stream has a name and can be enabled or
|
||||
// disabled (globally and per isolate).
|
||||
|
@ -129,6 +144,7 @@ class TimelineStream {
|
|||
#endif
|
||||
};
|
||||
|
||||
#if defined(SUPPORT_TIMELINE)
|
||||
class RecorderSynchronizationLock : public AllStatic {
|
||||
public:
|
||||
static void Init() {
|
||||
|
@ -376,7 +392,7 @@ class TimelineEvent {
|
|||
void CompleteWithPreSerializedArgs(char* args_json);
|
||||
|
||||
// Get/Set the number of arguments in the event.
|
||||
intptr_t GetNumArguments() { return arguments_.length(); }
|
||||
intptr_t GetNumArguments() const { return arguments_.length(); }
|
||||
void SetNumArguments(intptr_t length) { arguments_.SetNumArguments(length); }
|
||||
// |name| must be a compile time constant. Takes ownership of |argument|.
|
||||
void SetArgument(intptr_t i, const char* name, char* argument) {
|
||||
|
@ -420,8 +436,8 @@ class TimelineEvent {
|
|||
|
||||
bool HasIsolateId() const;
|
||||
bool HasIsolateGroupId() const;
|
||||
const char* GetFormattedIsolateId() const;
|
||||
const char* GetFormattedIsolateGroupId() const;
|
||||
char* GetFormattedIsolateId() const;
|
||||
char* GetFormattedIsolateGroupId() const;
|
||||
|
||||
// The lowest time value stored in this event.
|
||||
int64_t LowTime() const;
|
||||
|
@ -562,6 +578,9 @@ class TimelineEvent {
|
|||
friend class TimelineEventPlatformRecorder;
|
||||
friend class TimelineEventFuchsiaRecorder;
|
||||
friend class TimelineEventMacosRecorder;
|
||||
#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
friend class TimelineEventPerfettoFileRecorder;
|
||||
#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
friend class TimelineStream;
|
||||
friend class TimelineTestHelper;
|
||||
DISALLOW_COPY_AND_ASSIGN(TimelineEvent);
|
||||
|
@ -582,6 +601,14 @@ class TimelineTrackMetadata {
|
|||
* object into |jsarr_events|.
|
||||
*/
|
||||
void PrintJSON(const JSONArray& jsarr_events) const;
|
||||
#if defined(SUPPORT_PERFETTO)
|
||||
/*
|
||||
* Populates the fields of a |perfetto::protos::pbzero::TracePacket| with the
|
||||
* metadata stored by this object.
|
||||
*/
|
||||
void PopulateTracePacket(
|
||||
perfetto::protos::pbzero::TracePacket* track_descriptor_packet);
|
||||
#endif // defined(SUPPORT_PERFETTO)
|
||||
#endif // !defined(PRODUCT)
|
||||
|
||||
private:
|
||||
|
@ -593,7 +620,6 @@ class TimelineTrackMetadata {
|
|||
Utils::CStringUniquePtr track_name_;
|
||||
};
|
||||
|
||||
#ifdef SUPPORT_TIMELINE
|
||||
#define TIMELINE_DURATION(thread, stream, name) \
|
||||
TimelineBeginEndScope tbes(thread, Timeline::Get##stream##Stream(), name);
|
||||
#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function) \
|
||||
|
@ -605,11 +631,6 @@ class TimelineTrackMetadata {
|
|||
|
||||
#define TIMELINE_FUNCTION_GC_DURATION(thread, name) \
|
||||
TimelineBeginEndScope tbes(thread, Timeline::GetGCStream(), name);
|
||||
#else
|
||||
#define TIMELINE_DURATION(thread, stream, name)
|
||||
#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function)
|
||||
#define TIMELINE_FUNCTION_GC_DURATION(thread, name)
|
||||
#endif // SUPPORT_TIMELINE
|
||||
|
||||
// See |TimelineBeginEndScope|.
|
||||
class TimelineEventScope : public StackResource {
|
||||
|
@ -833,6 +854,10 @@ class TimelineEventRecorder : public MallocAllocated {
|
|||
const char* thread_name);
|
||||
|
||||
protected:
|
||||
SimpleHashMap& track_uuid_to_track_metadata() {
|
||||
return track_uuid_to_track_metadata_;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void WriteTo(const char* directory);
|
||||
#endif
|
||||
|
@ -1137,6 +1162,30 @@ class TimelineEventFileRecorder : public TimelineEventFileRecorderBase {
|
|||
bool first_;
|
||||
};
|
||||
|
||||
#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
class TimelineEventPerfettoFileRecorder : public TimelineEventFileRecorderBase {
|
||||
public:
|
||||
explicit TimelineEventPerfettoFileRecorder(const char* path);
|
||||
virtual ~TimelineEventPerfettoFileRecorder();
|
||||
|
||||
const char* name() const final { return PERFETTO_RECORDER_NAME; }
|
||||
|
||||
private:
|
||||
void WritePacket(
|
||||
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet)
|
||||
const;
|
||||
void DrainImpl(const TimelineEvent& event) final;
|
||||
|
||||
static const intptr_t kAsyncTrackUuidToTrackDescriptorInitialCapacity = 1
|
||||
<< 4;
|
||||
SimpleHashMap async_track_uuid_to_track_descriptor_;
|
||||
// We allocate one heap-buffered packet as a class member, because it lets us
|
||||
// continuously follow a cycle of resetting the buffer and writing its to
|
||||
// contents to the file.
|
||||
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket> packet_;
|
||||
};
|
||||
#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
||||
|
||||
class DartTimelineEventHelpers : public AllStatic {
|
||||
public:
|
||||
static void ReportTaskEvent(TimelineEvent* event,
|
||||
|
@ -1145,6 +1194,7 @@ class DartTimelineEventHelpers : public AllStatic {
|
|||
char* name,
|
||||
char* args);
|
||||
};
|
||||
#endif // defined(SUPPORT_TIMELINE)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
|
|
|
@ -233,6 +233,14 @@ vm_sources = [
|
|||
"profiler_service.h",
|
||||
"program_visitor.cc",
|
||||
"program_visitor.h",
|
||||
"protos/perfetto/common/builtin_clock.pbzero.h",
|
||||
"protos/perfetto/trace/clock_snapshot.pbzero.h",
|
||||
"protos/perfetto/trace/trace_packet.pbzero.h",
|
||||
"protos/perfetto/trace/track_event/debug_annotation.pbzero.h",
|
||||
"protos/perfetto/trace/track_event/process_descriptor.pbzero.h",
|
||||
"protos/perfetto/trace/track_event/thread_descriptor.pbzero.h",
|
||||
"protos/perfetto/trace/track_event/track_descriptor.pbzero.h",
|
||||
"protos/perfetto/trace/track_event/track_event.pbzero.h",
|
||||
"random.cc",
|
||||
"random.h",
|
||||
"raw_object.cc",
|
||||
|
|
Loading…
Reference in a new issue