Merge "Project import generated by Copybara."
diff --git a/Android.bp b/Android.bp
index 2de8862..687d3f5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -6744,6 +6744,7 @@
genrule {
name: "perfetto_protos_perfetto_trace_processor_zero_gen",
srcs: [
+ "protos/perfetto/trace_processor/cloud_trace_processor.proto",
"protos/perfetto/trace_processor/metatrace_categories.proto",
"protos/perfetto/trace_processor/trace_processor.proto",
],
@@ -6753,6 +6754,7 @@
],
cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location protozero_plugin) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/ $(in)",
out: [
+ "external/perfetto/protos/perfetto/trace_processor/cloud_trace_processor.pbzero.cc",
"external/perfetto/protos/perfetto/trace_processor/metatrace_categories.pbzero.cc",
"external/perfetto/protos/perfetto/trace_processor/trace_processor.pbzero.cc",
],
@@ -6762,6 +6764,7 @@
genrule {
name: "perfetto_protos_perfetto_trace_processor_zero_gen_headers",
srcs: [
+ "protos/perfetto/trace_processor/cloud_trace_processor.proto",
"protos/perfetto/trace_processor/metatrace_categories.proto",
"protos/perfetto/trace_processor/trace_processor.proto",
],
@@ -6771,6 +6774,7 @@
],
cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location protozero_plugin) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/ $(in)",
out: [
+ "external/perfetto/protos/perfetto/trace_processor/cloud_trace_processor.pbzero.h",
"external/perfetto/protos/perfetto/trace_processor/metatrace_categories.pbzero.h",
"external/perfetto/protos/perfetto/trace_processor/trace_processor.pbzero.h",
],
@@ -8139,6 +8143,7 @@
filegroup {
name: "perfetto_src_base_threading_unittests",
srcs: [
+ "src/base/threading/channel_unittest.cc",
"src/base/threading/thread_pool_unittest.cc",
],
}
diff --git a/BUILD b/BUILD
index 05a8baf..2232f30 100644
--- a/BUILD
+++ b/BUILD
@@ -4035,6 +4035,7 @@
perfetto_proto_library(
name = "protos_perfetto_trace_processor_protos",
srcs = [
+ "protos/perfetto/trace_processor/cloud_trace_processor.proto",
"protos/perfetto/trace_processor/metatrace_categories.proto",
"protos/perfetto/trace_processor/trace_processor.proto",
],
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index be78fcf..d1dc6c8 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -1473,6 +1473,11 @@
]
}
+ config("grpc_re2_config") {
+ visibility = _buildtools_visibility
+ include_dirs = [ "grpc/src/third_party/re2" ]
+ }
+
config("grpc_internal_config") {
visibility = _buildtools_visibility
include_dirs = [
@@ -1487,10 +1492,24 @@
cflags = [ "-DGRPC_ARES=0" ]
}
- source_set("grpc") {
- deps = [
- "grpc:grpc++",
- "//gn:default_deps",
+ config("grpc_gen_config") {
+ cflags = [
+ # Using -isystem instead of include_dirs (-I), so we don't need to
+ # suppress warnings coming from libprotobuf headers. Doing so would mask
+ # warnings in our own code.
+ perfetto_isystem_cflag,
+ rebase_path("grpc/src/include", root_build_dir),
+ perfetto_isystem_cflag,
+ rebase_path("grpc/src/third_party/abseil-cpp", root_build_dir),
]
+
+ # This issues appear in .grpc.pb.h files so we unfortunately need to leak
+ # the cflags outside of just compiling this code.
+ if (is_clang && !is_win) {
+ cflags += [
+ "-Wno-weak-vtables",
+ "-Wno-suggest-destructor-override",
+ ]
+ }
}
}
diff --git a/buildtools/grpc/BUILD.gn b/buildtools/grpc/BUILD.gn
index 4702dab..16ca941 100644
--- a/buildtools/grpc/BUILD.gn
+++ b/buildtools/grpc/BUILD.gn
@@ -5,9 +5,15 @@
# tools/gen_grpc_build_gn.py > buildtools/grpc/BUILD.gn
#
+import("../../gn/perfetto.gni")
+
# Prevent the gRPC from being depended upon without explicitly being opted in.
assert(enable_perfetto_grpc)
+# BoringSSL has assembly code which is tied to platform-specific. For now, we
+# only care about Linux x64 so assert this as the case.
+assert(is_linux && current_cpu == "x64")
+
source_set("absl_algorithm_algorithm") {
sources = [ "src/third_party/abseil-cpp/absl/algorithm/algorithm.h" ]
public_deps = [ ":absl_base_config" ]
@@ -2659,7 +2665,7 @@
configs -= [ "//gn/standalone:extra_warnings" ]
}
-source_set("upb") {
+static_library("upb") {
sources = [
"src/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c",
"src/src/core/ext/upb-generated/google/protobuf/descriptor.upb.h",
@@ -2722,9 +2728,85 @@
configs -= [ "//gn/standalone:extra_warnings" ]
}
-source_set("boringssl") {
+static_library("re2") {
+ sources = [
+ "src/third_party/re2/re2/bitmap256.h",
+ "src/third_party/re2/re2/bitstate.cc",
+ "src/third_party/re2/re2/compile.cc",
+ "src/third_party/re2/re2/dfa.cc",
+ "src/third_party/re2/re2/filtered_re2.cc",
+ "src/third_party/re2/re2/filtered_re2.h",
+ "src/third_party/re2/re2/mimics_pcre.cc",
+ "src/third_party/re2/re2/nfa.cc",
+ "src/third_party/re2/re2/onepass.cc",
+ "src/third_party/re2/re2/parse.cc",
+ "src/third_party/re2/re2/perl_groups.cc",
+ "src/third_party/re2/re2/pod_array.h",
+ "src/third_party/re2/re2/prefilter.cc",
+ "src/third_party/re2/re2/prefilter.h",
+ "src/third_party/re2/re2/prefilter_tree.cc",
+ "src/third_party/re2/re2/prefilter_tree.h",
+ "src/third_party/re2/re2/prog.cc",
+ "src/third_party/re2/re2/prog.h",
+ "src/third_party/re2/re2/re2.cc",
+ "src/third_party/re2/re2/re2.h",
+ "src/third_party/re2/re2/regexp.cc",
+ "src/third_party/re2/re2/regexp.h",
+ "src/third_party/re2/re2/set.cc",
+ "src/third_party/re2/re2/set.h",
+ "src/third_party/re2/re2/simplify.cc",
+ "src/third_party/re2/re2/sparse_array.h",
+ "src/third_party/re2/re2/sparse_set.h",
+ "src/third_party/re2/re2/stringpiece.cc",
+ "src/third_party/re2/re2/stringpiece.h",
+ "src/third_party/re2/re2/tostring.cc",
+ "src/third_party/re2/re2/unicode_casefold.cc",
+ "src/third_party/re2/re2/unicode_casefold.h",
+ "src/third_party/re2/re2/unicode_groups.cc",
+ "src/third_party/re2/re2/unicode_groups.h",
+ "src/third_party/re2/re2/walker-inl.h",
+ "src/third_party/re2/util/benchmark.h",
+ "src/third_party/re2/util/flags.h",
+ "src/third_party/re2/util/logging.h",
+ "src/third_party/re2/util/malloc_counter.h",
+ "src/third_party/re2/util/mix.h",
+ "src/third_party/re2/util/mutex.h",
+ "src/third_party/re2/util/pcre.cc",
+ "src/third_party/re2/util/pcre.h",
+ "src/third_party/re2/util/rune.cc",
+ "src/third_party/re2/util/strutil.cc",
+ "src/third_party/re2/util/strutil.h",
+ "src/third_party/re2/util/test.h",
+ "src/third_party/re2/util/utf.h",
+ "src/third_party/re2/util/util.h",
+ ]
+ public_deps = []
+ public_configs = [ "..:grpc_re2_config" ]
+ configs -= [ "//gn/standalone:extra_warnings" ]
+}
+
+static_library("boringssl") {
sources = [
"src/third_party/boringssl-with-bazel/err_data.c",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/chacha/chacha-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/cipher_extra/aes128gcmsiv-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/cipher_extra/chacha20_poly1305_x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/aesni-gcm-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/aesni-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/ghash-ssse3-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/ghash-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/md5-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/p256-x86_64-asm.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/p256_beeu-x86_64-asm.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/rdrand-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/rsaz-avx2.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/sha1-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/sha256-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/sha512-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/vpaes-x86_64.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/x86_64-mont.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/fipsmodule/x86_64-mont5.S",
+ "src/third_party/boringssl-with-bazel/linux-x86_64/crypto/test/trampoline-x86_64.S",
"src/third_party/boringssl-with-bazel/src/crypto/asn1/a_bitstr.c",
"src/third_party/boringssl-with-bazel/src/crypto/asn1/a_bool.c",
"src/third_party/boringssl-with-bazel/src/crypto/asn1/a_d2i_fp.c",
@@ -2943,6 +3025,7 @@
"src/third_party/boringssl-with-bazel/src/crypto/fipsmodule/tls/kdf.c",
"src/third_party/boringssl-with-bazel/src/crypto/hkdf/hkdf.c",
"src/third_party/boringssl-with-bazel/src/crypto/hpke/hpke.c",
+ "src/third_party/boringssl-with-bazel/src/crypto/hrss/asm/poly_rq_mul.S",
"src/third_party/boringssl-with-bazel/src/crypto/hrss/hrss.c",
"src/third_party/boringssl-with-bazel/src/crypto/hrss/internal.h",
"src/third_party/boringssl-with-bazel/src/crypto/internal.h",
@@ -5611,7 +5694,7 @@
configs -= [ "//gn/standalone:extra_warnings" ]
}
-source_set("grpc++") {
+static_library("grpc++") {
sources = [
"src/src/core/ext/transport/binder/client/binder_connector.cc",
"src/src/core/ext/transport/binder/client/binder_connector.h",
@@ -6318,3 +6401,48 @@
public_configs = [ "..:grpc_internal_config" ]
configs -= [ "//gn/standalone:extra_warnings" ]
}
+
+source_set("grpc_plugin_support") {
+ sources = [
+ "src/src/compiler/config.h",
+ "src/src/compiler/config_protobuf.h",
+ "src/src/compiler/cpp_generator.cc",
+ "src/src/compiler/cpp_generator.h",
+ "src/src/compiler/cpp_generator_helpers.h",
+ "src/src/compiler/cpp_plugin.h",
+ "src/src/compiler/csharp_generator.cc",
+ "src/src/compiler/csharp_generator.h",
+ "src/src/compiler/csharp_generator_helpers.h",
+ "src/src/compiler/generator_helpers.h",
+ "src/src/compiler/node_generator.cc",
+ "src/src/compiler/node_generator.h",
+ "src/src/compiler/node_generator_helpers.h",
+ "src/src/compiler/objective_c_generator.cc",
+ "src/src/compiler/objective_c_generator.h",
+ "src/src/compiler/objective_c_generator_helpers.h",
+ "src/src/compiler/php_generator.cc",
+ "src/src/compiler/php_generator.h",
+ "src/src/compiler/php_generator_helpers.h",
+ "src/src/compiler/protobuf_plugin.h",
+ "src/src/compiler/python_generator.cc",
+ "src/src/compiler/python_generator.h",
+ "src/src/compiler/python_generator_helpers.h",
+ "src/src/compiler/python_private_generator.h",
+ "src/src/compiler/ruby_generator.cc",
+ "src/src/compiler/ruby_generator.h",
+ "src/src/compiler/ruby_generator_helpers-inl.h",
+ "src/src/compiler/ruby_generator_map-inl.h",
+ "src/src/compiler/ruby_generator_string-inl.h",
+ "src/src/compiler/schema_interface.h",
+ ]
+ public_deps = [ "..:protoc_lib" ]
+ public_configs = [ "..:grpc_internal_config" ]
+ configs -= [ "//gn/standalone:extra_warnings" ]
+}
+
+executable("grpc_cpp_plugin") {
+ sources = [ "src/src/compiler/cpp_plugin.cc" ]
+ public_deps = [ ":grpc_plugin_support" ]
+ public_configs = [ "..:grpc_internal_config" ]
+ configs -= [ "//gn/standalone:extra_warnings" ]
+}
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index f41e959..b778d88 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -308,9 +308,10 @@
enable_perfetto_llvm_demangle =
enable_perfetto_trace_processor && perfetto_build_standalone
- # Enables gRPC support. This is used as the RPC framework for cloud trace
- # processor in open source but is disabled by default because of how
- # heavyweight gRPC is.
+ # Enables gRPC in the Perfetto codebase. gRPC significantly increases build
+ # times and the general footprint of Perfetto. As it only required for
+ # cloud trace processor and even then only to build the final ready-to-ship
+ # binary, don't enable this by default.
enable_perfetto_grpc = false
}
diff --git a/gn/proto_library.gni b/gn/proto_library.gni
index d1794d5..f69d3ce 100644
--- a/gn/proto_library.gni
+++ b/gn/proto_library.gni
@@ -204,6 +204,40 @@
}
}
+# Generates .grpc.{h,cc} stubs for services defined in .proto files.
+# We require explicit opt-in as gRPC is very heavyweight so we do not
+# want accidental dependencies on this.
+if (enable_perfetto_grpc) {
+ template("perfetto_grpc_library") {
+ proto_library(target_name) {
+ proto_in_dir = perfetto_root_path
+ proto_out_dir = perfetto_root_path
+ propagate_imports_configs = false
+
+ perfetto_root_path = perfetto_root_path
+ generate_cc = false
+ generate_python = false
+ generator_plugin_label =
+ "$perfetto_root_path/buildtools/grpc:grpc_cpp_plugin"
+ generator_plugin_suffix = ".grpc.pb"
+ deps = [ "$perfetto_root_path/buildtools/grpc:grpc++" ]
+ public_configs = [ "$perfetto_root_path/buildtools:grpc_gen_config" ]
+ if (defined(invoker.deps)) {
+ deps += invoker.deps
+ }
+ forward_variables_from(invoker,
+ [
+ "defines",
+ "extra_configs",
+ "include_dirs",
+ "sources",
+ "testonly",
+ "visibility",
+ ])
+ }
+ }
+}
+
# The template used everywhere in the codebase.
template("perfetto_proto_library") {
if (defined(invoker.proto_generators)) {
diff --git a/include/perfetto/ext/base/threading/BUILD.gn b/include/perfetto/ext/base/threading/BUILD.gn
index ab12670..cb11115 100644
--- a/include/perfetto/ext/base/threading/BUILD.gn
+++ b/include/perfetto/ext/base/threading/BUILD.gn
@@ -15,7 +15,10 @@
import("../../../../../gn/perfetto.gni")
source_set("threading") {
- sources = [ "thread_pool.h" ]
+ sources = [
+ "channel.h",
+ "thread_pool.h",
+ ]
deps = [
"..:base",
"../../../../../gn:default_deps",
diff --git a/include/perfetto/ext/base/threading/channel.h b/include/perfetto/ext/base/threading/channel.h
new file mode 100644
index 0000000..d117ff0
--- /dev/null
+++ b/include/perfetto/ext/base/threading/channel.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_BASE_THREADING_CHANNEL_H_
+#define INCLUDE_PERFETTO_EXT_BASE_THREADING_CHANNEL_H_
+
+#include <mutex>
+
+#include "perfetto/base/compiler.h"
+#include "perfetto/base/platform_handle.h"
+#include "perfetto/ext/base/circular_queue.h"
+#include "perfetto/ext/base/event_fd.h"
+#include "perfetto/ext/base/optional.h"
+
+namespace perfetto {
+namespace base {
+
+// Unidirectional conduit used to send values between threads with a fixed-sized
+// buffer in-between.
+//
+// When a channel is read from when empty or written to when full, the operation
+// will not succeed and the caller can choose to a) abandon the operation,
+// or b) use |read_fd| or |write_fd| (as appropriate) which will be become
+// "ready" (i.e. base::TaskRunner watches will fire) when the operation would
+// succeed.
+//
+// A channel is very similar to a Unix pipe except with the values being sent
+// a) not needing to be serializable b) data does not go through the kernel.
+template <typename T>
+class Channel {
+ public:
+ struct ReadResult {
+ ReadResult(base::Optional<T> _item, bool _is_closed)
+ : item(std::move(_item)), is_closed(_is_closed) {}
+
+ bool operator==(const ReadResult& res) const {
+ return item == res.item && is_closed == res.is_closed;
+ }
+
+ // The item read from the channel or base::nullopt if the channel is empty.
+ // If so, callers can use |read_fd| to be notified when a read operation
+ // would succeed.
+ base::Optional<T> item;
+
+ // Indicates the channel is closed. Readers can continue to read from the
+ // channel and any buffered elements will be correctly returned. Moreover,
+ // any future reads will also have |is_closed| == true and |read_fd| will be
+ // ready forever.
+ //
+ // Once a ReadResult is returned with |item| == base::nullopt and
+ // |is_closed| == true, no further values will ever be returned.
+ bool is_closed;
+ };
+ struct WriteResult {
+ WriteResult(bool _success, bool _is_closed)
+ : success(std::move(_success)), is_closed(_is_closed) {}
+
+ bool operator==(const WriteResult& res) const {
+ return success == res.success && is_closed == res.is_closed;
+ }
+
+ // Returns whether the write to the channel was successful. If this is
+ // false, callers can use |write_fd| to be notified when future writes
+ // would succeed. Note that callers should also check |is_closed| as another
+ // writer may have closed the channel.
+ bool success;
+
+ // Indicates that the channel is closed. If this value is true, |success|
+ // will be |false| Moreover, any further writes will continue to return
+ // |success| == false, |is_closed| == true and |write_fd| will be ready
+ // forever.
+ bool is_closed;
+ };
+
+ // Creates a channel with a capacity at least as large as |capacity_hint|. The
+ // capacity *must* be greater than zero.
+ //
+ // Note that it's possible that a capacity > |capacity_hint| will be chosen:
+ // it is implementation defined when this might happen.
+ explicit Channel(uint32_t capacity_hint) : elements_(capacity_hint) {
+ PERFETTO_DCHECK(capacity_hint > 0);
+
+ // It's very important that we make sure |write_fd| is ready to avoid
+ // deadlocks.
+ write_fd_.Notify();
+ }
+
+ // Attempts to read from the channel and returns the result of the attempt.
+ // See |ReadResult| for more information on the result.
+ PERFETTO_WARN_UNUSED_RESULT ReadResult ReadNonBlocking() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (elements_.empty()) {
+ return ReadResult(base::nullopt, is_closed_);
+ }
+ if (elements_.capacity() == elements_.size()) {
+ write_fd_.Notify();
+ }
+ T value = std::move(elements_.front());
+ elements_.pop_front();
+ if (!is_closed_ && elements_.empty()) {
+ read_fd_.Clear();
+ }
+ return ReadResult(std::move(value), is_closed_);
+ }
+
+ // Attempts to write to the channel and returns the result of the attempt.
+ // See |WriteResult| for more information on the result.
+ //
+ // IMPORTANT: if this function returns |success| == false, |element| *will
+ // not* be modified. This allows the caller to try again with the same value.
+ PERFETTO_WARN_UNUSED_RESULT WriteResult WriteNonBlocking(T&& element) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (is_closed_) {
+ return WriteResult{false, true};
+ }
+ if (elements_.size() == elements_.capacity()) {
+ return WriteResult{false, false};
+ }
+ if (elements_.empty()) {
+ read_fd_.Notify();
+ }
+ elements_.emplace_back(std::move(element));
+ if (elements_.size() == elements_.capacity()) {
+ write_fd_.Clear();
+ }
+ return WriteResult{true, false};
+ }
+
+ // Closes the channel for to any further writes.
+ //
+ // Note: this function will make both |read_fd| and |write_fd| ready to
+ // avoid deadlocks. Callers should correctly handle |is_closed| being
+ // false from |ReadNonBlocking| and |WriteNonBlocking| to stop watching the
+ // fds to avoid poll returning immediately.
+ //
+ // We prefer this behaviour as it's a lot more obvious something is wrong when
+ // it spins and takes 100% CPU rather than silently deadlocking.
+ void Close() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ is_closed_ = true;
+
+ // Make both fds ready to avoid deadlocks.
+ read_fd_.Notify();
+ write_fd_.Notify();
+ }
+
+ // Notification FD for when |ReadNonBlocking| would succeed. Can be useful to
+ // pass to AddFileDescriptorWatch to read data from the channel.
+ base::PlatformHandle read_fd() const { return read_fd_.fd(); }
+
+ // Notification FD for when |WriteNonBlocking| would succeed. Can be useful to
+ // pass to AddFileDescriptorWatch to send data through the channel.
+ base::PlatformHandle write_fd() const { return write_fd_.fd(); }
+
+ private:
+ std::mutex mutex_;
+ base::CircularQueue<T> elements_;
+ bool is_closed_ = false;
+
+ base::EventFd read_fd_;
+ base::EventFd write_fd_;
+};
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_BASE_THREADING_CHANNEL_H_
diff --git a/protos/perfetto/common/BUILD.gn b/protos/perfetto/common/BUILD.gn
index 5ecc0de..31d4842 100644
--- a/protos/perfetto/common/BUILD.gn
+++ b/protos/perfetto/common/BUILD.gn
@@ -36,4 +36,10 @@
"tracing_service_state.proto",
"track_event_descriptor.proto",
]
+ proto_generators = [
+ "lite",
+ "zero",
+ "cpp",
+ "source_set",
+ ]
}
diff --git a/protos/perfetto/trace_processor/BUILD.gn b/protos/perfetto/trace_processor/BUILD.gn
index c8671b1..4ba70c7 100644
--- a/protos/perfetto/trace_processor/BUILD.gn
+++ b/protos/perfetto/trace_processor/BUILD.gn
@@ -17,10 +17,11 @@
perfetto_proto_library("@TYPE@") {
proto_generators = [
+ "lite",
"zero",
"source_set",
]
- deps = [ "../common:zero" ] # ../common:zero needed for descriptor.proto.
+ deps = [ "../common:@TYPE@" ] # needed for descriptor.proto.
sources = []
foreach(source, trace_processor_protos) {
sources += [ "$source.proto" ]
@@ -34,3 +35,10 @@
]
sources = [ "metrics_impl.proto" ]
}
+
+if (enable_perfetto_grpc) {
+ perfetto_grpc_library("cloud_trace_processor_grpc") {
+ deps = [ ":lite" ]
+ sources = [ "cloud_trace_processor.proto" ]
+ }
+}
diff --git a/protos/perfetto/trace_processor/cloud_trace_processor.proto b/protos/perfetto/trace_processor/cloud_trace_processor.proto
new file mode 100644
index 0000000..b009fe3
--- /dev/null
+++ b/protos/perfetto/trace_processor/cloud_trace_processor.proto
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+syntax = "proto2";
+
+package perfetto.protos;
+
+service CloudTraceProcessorWorkerService {}
\ No newline at end of file
diff --git a/protos/perfetto/trace_processor/proto_files.gni b/protos/perfetto/trace_processor/proto_files.gni
index b46da47..4c9ae21 100644
--- a/protos/perfetto/trace_processor/proto_files.gni
+++ b/protos/perfetto/trace_processor/proto_files.gni
@@ -15,6 +15,7 @@
# This variable is used both by ./BUILD.gn (for the C++ proto codegen) and by
# //ui/BUIlD.gn (for the TypeScript/JS proto codegen).
trace_processor_protos = [
+ "cloud_trace_processor",
"trace_processor",
"metatrace_categories",
]
diff --git a/src/base/threading/BUILD.gn b/src/base/threading/BUILD.gn
index ba709e7..b1e01e3 100644
--- a/src/base/threading/BUILD.gn
+++ b/src/base/threading/BUILD.gn
@@ -28,6 +28,8 @@
"../../../gn:default_deps",
"../../../gn:gtest_and_gmock",
]
-
- sources = [ "thread_pool_unittest.cc" ]
+ sources = [
+ "channel_unittest.cc",
+ "thread_pool_unittest.cc",
+ ]
}
diff --git a/src/base/threading/channel_unittest.cc b/src/base/threading/channel_unittest.cc
new file mode 100644
index 0000000..21c5ce7
--- /dev/null
+++ b/src/base/threading/channel_unittest.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#include "perfetto/ext/base/threading/channel.h"
+#include <sys/poll.h>
+#include <memory>
+
+#include "perfetto/base/platform_handle.h"
+#include "perfetto/ext/base/file_utils.h"
+#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/utils.h"
+#include "test/gtest_and_gmock.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <Windows.h>
+#include <synchapi.h>
+#else
+#include <poll.h>
+#endif
+
+namespace perfetto {
+namespace base {
+namespace {
+
+using ReadResult = Channel<int>::ReadResult;
+using WriteResult = Channel<int>::WriteResult;
+
+bool IsReady(base::PlatformHandle fd) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ std::array<base::PlatformHandle, 1> poll_fds{fd};
+ DWORD ret =
+ WaitForMultipleObjects(static_cast<DWORD>(poll_fds.size()), &poll_fds[0],
+ /*bWaitAll=*/false, 0);
+ PERFETTO_CHECK(ret == WAIT_TIMEOUT || ret == 0);
+ return ret == 0;
+#else
+ std::array<struct pollfd, 1> poll_fds;
+ poll_fds[0].fd = fd;
+ poll_fds[0].events = POLLIN | POLLHUP;
+ poll_fds[0].revents = 0;
+
+ int ret = PERFETTO_EINTR(
+ poll(&poll_fds[0], static_cast<nfds_t>(poll_fds.size()), 0));
+ PERFETTO_CHECK(ret == 0 || ret == 1);
+ return ret == 1;
+#endif
+}
+
+TEST(ChannelUnittest, SingleElementBuffer) {
+ Channel<int> channel(1);
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_FALSE(IsReady(channel.read_fd()));
+
+ ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+ ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, false));
+
+ ASSERT_FALSE(IsReady(channel.write_fd()));
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, false));
+
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_FALSE(IsReady(channel.read_fd()));
+}
+
+TEST(ChannelUnittest, MultiElementBuffer) {
+ Channel<int> channel(2);
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_FALSE(IsReady(channel.read_fd()));
+
+ ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+
+ ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(true, false));
+ ASSERT_FALSE(IsReady(channel.write_fd()));
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(101, false));
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_FALSE(IsReady(channel.read_fd()));
+
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, false));
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_FALSE(IsReady(channel.read_fd()));
+}
+
+TEST(ChannelUnittest, CloseEmptyChannel) {
+ Channel<int> channel(1);
+
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, false));
+ ASSERT_FALSE(IsReady(channel.read_fd()));
+
+ channel.Close();
+
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, true));
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, true));
+
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+}
+
+TEST(ChannelUnittest, WriteDoesNotMoveIfFalse) {
+ Channel<std::unique_ptr<int>> channel(1);
+
+ std::unique_ptr<int> first(new int(100));
+ int* first_ptr = first.get();
+ ASSERT_EQ(channel.WriteNonBlocking(std::move(first)),
+ Channel<std::unique_ptr<int>>::WriteResult(true, false));
+ ASSERT_EQ(first.get(), nullptr);
+
+ std::unique_ptr<int> second(new int(101));
+ ASSERT_EQ(channel.WriteNonBlocking(std::move(second)),
+ Channel<std::unique_ptr<int>>::WriteResult(false, false));
+ ASSERT_NE(second.get(), nullptr);
+ ASSERT_EQ(*second, 101);
+
+ auto res = channel.ReadNonBlocking();
+ ASSERT_EQ(res.item->get(), first_ptr);
+}
+
+TEST(ChannelUnittest, ReadAfterClose) {
+ Channel<int> channel(1);
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, false));
+ ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+ channel.Close();
+
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, true));
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, true));
+}
+
+TEST(ChannelUnittest, WriteAfterClose) {
+ Channel<int> channel(1);
+ ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+ ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, false));
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, false));
+ channel.Close();
+
+ ASSERT_EQ(channel.WriteNonBlocking(101), WriteResult(false, true));
+}
+
+TEST(ChannelUnittest, EmptyClosedChannel) {
+ Channel<int> channel(1);
+ ASSERT_FALSE(IsReady(channel.read_fd()));
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ channel.Close();
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(base::nullopt, true));
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+}
+
+TEST(ChannelUnittest, FullClosedChannel) {
+ Channel<int> channel(1);
+ ASSERT_FALSE(IsReady(channel.read_fd()));
+ ASSERT_EQ(channel.WriteNonBlocking(100), WriteResult(true, false));
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+ ASSERT_FALSE(IsReady(channel.write_fd()));
+ channel.Close();
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+
+ ASSERT_EQ(channel.ReadNonBlocking(), ReadResult(100, true));
+ ASSERT_TRUE(IsReady(channel.write_fd()));
+ ASSERT_TRUE(IsReady(channel.read_fd()));
+}
+
+} // namespace
+} // namespace base
+} // namespace perfetto
diff --git a/tools/gen_grpc_build_gn.py b/tools/gen_grpc_build_gn.py
index 706e062..48993ca 100755
--- a/tools/gen_grpc_build_gn.py
+++ b/tools/gen_grpc_build_gn.py
@@ -1,4 +1,18 @@
#!/usr/bin/env python3
+# Copyright (C) 2023 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.
+
import json
import os
import subprocess
@@ -8,27 +22,6 @@
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-IGNORE_LIST = set([
- 'grpcpp_channelz',
- 'grpc++_reflection',
- 'benchmark_helpers',
- 'boringssl_test_util',
-])
-
-SOURCE_SET_TARGET = """
-source_set("{name}") {{
- sources = {srcs}
- public_deps = {deps}
- public_configs = ["..:{config_name}"]
- configs -= [ "//gn/standalone:extra_warnings" ]
-}}"""
-
-
-def grpc_relpath(*segments: str) -> str:
- '''From path segments to GRPC root, returns the absolute path.'''
- return os.path.join(ROOT_DIR, 'buildtools', 'grpc', 'src', *segments)
-
-
GRPC_GN_HEADER = '''
#
# DO NOT EDIT. AUTOGENERATED file
@@ -37,45 +30,117 @@
# tools/gen_grpc_build_gn.py > buildtools/grpc/BUILD.gn
#
+import("../../gn/perfetto.gni")
+
# Prevent the gRPC from being depended upon without explicitly being opted in.
assert(enable_perfetto_grpc)
+
+# BoringSSL has assembly code which is tied to platform-specific. For now, we
+# only care about Linux x64 so assert this as the case.
+assert(is_linux && current_cpu == "x64")
'''
+TARGET_TEMPLATE = """
+{target_type}("{name}") {{
+ sources = {srcs}
+ public_deps = {deps}
+ public_configs = ["..:{config_name}"]
+ configs -= [ "//gn/standalone:extra_warnings" ]
+}}"""
+
+LIBRARY_IGNORE_LIST = set([
+ 'grpcpp_channelz',
+ 'grpc++_reflection',
+ 'benchmark_helpers',
+ 'boringssl_test_util',
+])
+
+TARGET_ALLOW_LIST = set([
+ 'grpc_cpp_plugin',
+])
+
+STATIC_LIBRARY_TARGETS = set([
+ 'upb',
+ 're2',
+ 'boringssl',
+ 'grpc++',
+])
+
+
+def grpc_relpath(*segments: str) -> str:
+ '''From path segments to GRPC root, returns the absolute path.'''
+ return os.path.join(ROOT_DIR, 'buildtools', 'grpc', 'src', *segments)
+
+
GRPC_BUILD_YAML = grpc_relpath('build_autogenerated.yaml')
ABSL_GEN_BUILD_YAML = grpc_relpath('src', 'abseil-cpp', 'gen_build_yaml.py')
UPB_GEN_BUILD_YAML = grpc_relpath('src', 'upb', 'gen_build_yaml.py')
+RE2_GEN_BUILD_YAML = grpc_relpath('src', 're2', 'gen_build_yaml.py')
BSSL_GEN_BUILD_YAML = grpc_relpath('src', 'boringssl', 'gen_build_yaml.py')
-def bazel_label_to_gn_target(dep: str):
- '''Converts a Bazel label name into a gn target name.'''
- if dep == 'libssl':
- return 'boringssl'
- return dep.replace('/', '_').replace(':', '_')
-
-
def gen_grpc_dep_yaml(gen_path: str) -> Dict[str, Any]:
'''Invokes a gen_build_yaml.py file for creating YAML for gRPC deps.'''
return yaml.safe_load(subprocess.check_output(['python3', gen_path]))
-def yaml_to_gn_targets(desc: Dict[str, Any], build_type: str, config_name: str,
- out: List[str]):
+def bazel_label_to_gn_target(dep: str) -> str:
+ '''Converts a Bazel label name into a gn target name.'''
+ if dep == 'libssl':
+ return 'boringssl'
+ return dep.replace('/', '_').replace(':', '_')
+
+
+def get_deps_for_target(target: str) -> List[str]:
+ if target == 'grpc_plugin_support':
+ return ['..:protoc_lib']
+ return []
+
+
+def get_library_target_type(target: str) -> str:
+ if target in STATIC_LIBRARY_TARGETS:
+ return 'static_library'
+ return 'source_set'
+
+
+def yaml_to_gn_targets(desc: Dict[str, Any], build_types: list[str],
+ config_name: str) -> List[str]:
'''Given a gRPC YAML description of the build graph, generates GN targets.'''
+ out = []
for lib in desc['libs']:
- if lib['build'] != build_type:
+ if lib['build'] not in build_types:
continue
- if lib['name'] in IGNORE_LIST:
+ if lib['name'] in LIBRARY_IGNORE_LIST:
continue
- srcs = json.dumps([f'src/{file}' for file in lib['src'] + lib['headers']])
- deps = json.dumps(
- [f':{bazel_label_to_gn_target(dep)}' for dep in lib.get('deps', [])])
- source_set_target = SOURCE_SET_TARGET.format(
+ srcs = [f'src/{file}' for file in lib['src'] + lib['headers']]
+ if 'asm_src' in lib:
+ srcs += [f'src/{file}' for file in lib['asm_src']['crypto_linux_x86_64']]
+ deps = [f':{bazel_label_to_gn_target(dep)}' for dep in lib.get('deps', [])
+ ] + get_deps_for_target(lib['name'])
+ library_target = TARGET_TEMPLATE.format(
name=bazel_label_to_gn_target(lib['name']),
config_name=config_name,
+ srcs=json.dumps(srcs),
+ deps=json.dumps(deps),
+ target_type=get_library_target_type(lib['name']))
+ out.append(library_target)
+
+ for bin in desc.get('targets', []):
+ if bin['build'] not in build_types:
+ continue
+ if bin['name'] not in TARGET_ALLOW_LIST:
+ continue
+ srcs = json.dumps([f'src/{file}' for file in bin['src'] + bin['headers']])
+ deps = [f':{bazel_label_to_gn_target(dep)}' for dep in bin.get('deps', [])
+ ] + get_deps_for_target(bin['name'])
+ binary_target = TARGET_TEMPLATE.format(
+ name=bazel_label_to_gn_target(bin['name']),
+ config_name=config_name,
srcs=srcs,
- deps=deps)
- out.append(source_set_target)
+ deps=json.dumps(deps),
+ target_type='executable')
+ out.append(binary_target)
+ return out
def main():
@@ -83,20 +148,26 @@
# Generate absl rules
absl_yaml = gen_grpc_dep_yaml(ABSL_GEN_BUILD_YAML)
- yaml_to_gn_targets(absl_yaml, 'private', 'grpc_absl_config', out)
+ out.extend(yaml_to_gn_targets(absl_yaml, ['private'], 'grpc_absl_config'))
# Generate upb rules
upb_yaml = gen_grpc_dep_yaml(UPB_GEN_BUILD_YAML)
- yaml_to_gn_targets(upb_yaml, 'all', 'grpc_upb_config', out)
+ out.extend(yaml_to_gn_targets(upb_yaml, ['all'], 'grpc_upb_config'))
+
+ # Generate re2 rules
+ re2_yaml = gen_grpc_dep_yaml(RE2_GEN_BUILD_YAML)
+ out.extend(yaml_to_gn_targets(re2_yaml, ['private'], 'grpc_re2_config'))
# Generate boringssl rules
boringssl_yaml = gen_grpc_dep_yaml(BSSL_GEN_BUILD_YAML)
- yaml_to_gn_targets(boringssl_yaml, 'private', 'grpc_boringssl_config', out)
+ out.extend(
+ yaml_to_gn_targets(boringssl_yaml, ['private'], 'grpc_boringssl_config'))
# Generate grpc rules
with open(GRPC_BUILD_YAML, 'r', encoding='utf-8') as f:
grpc_yaml = yaml.safe_load(f.read())
- yaml_to_gn_targets(grpc_yaml, 'all', 'grpc_internal_config', out)
+ out.extend(
+ yaml_to_gn_targets(grpc_yaml, ['all', 'protoc'], 'grpc_internal_config'))
print(GRPC_GN_HEADER)
print('\n'.join(out))
diff --git a/tools/java_heap_dump b/tools/java_heap_dump
index eebf074..c14dde4 100755
--- a/tools/java_heap_dump
+++ b/tools/java_heap_dump
@@ -35,7 +35,7 @@
}
'''
-CFG_IDENT = ' '
+CFG_INDENT = ' '
CFG = '''buffers {{
size_kb: {size_kb}
fill_policy: DISCARD
@@ -63,6 +63,9 @@
data_sources: {{
config {{
name: "android.java_hprof.oom"
+ java_hprof_config {{
+{process_cfg}
+ }}
}}
}}
@@ -133,12 +136,12 @@
except ValueError:
print("FATAL: invalid PID %s" % pid, file=sys.stderr)
fail = True
- target_cfg += '{}pid: {}\n'.format(CFG_IDENT, pid)
+ target_cfg += '{}pid: {}\n'.format(CFG_INDENT, pid)
if args.name:
for name in args.name.split(','):
- target_cfg += '{}process_cmdline: "{}"\n'.format(CFG_IDENT, name)
+ target_cfg += '{}process_cmdline: "{}"\n'.format(CFG_INDENT, name)
if args.dump_smaps:
- target_cfg += '{}dump_smaps: true\n'.format(CFG_IDENT)
+ target_cfg += '{}dump_smaps: true\n'.format(CFG_INDENT)
if fail:
return None
@@ -168,8 +171,13 @@
file=sys.stderr)
return None
- if args.pid or args.name:
- print("FATAL: Specifying process not supported in OOM mode",
+ if args.pid:
+ print("FATAL: Specifying pid not supported in OOM mode",
+ file=sys.stderr)
+ return None
+
+ if not args.name:
+ print("FATAL: Must specify process in OOM mode (use --name '*' to match all)",
file=sys.stderr)
return None
@@ -183,9 +191,14 @@
file=sys.stderr)
return None
+ process_cfg = ''
+ for name in args.name.split(','):
+ process_cfg += '{}process_cmdline: "{}"\n'.format(CFG_INDENT, name)
+
return OOM_CFG.format(
size_kb=convert_size_to_kb(args.buffer_size),
- wait_duration_ms=args.oom_wait_seconds * 1000)
+ wait_duration_ms=args.oom_wait_seconds * 1000,
+ process_cfg=process_cfg)
def main(argv):